9c0678a291
The original code is perfectly valid standard C. However, some compilers (especially GCC) complain about duplicate const specifiers anyway. At this point we cave in as there doesn't seem to be any efforts to fix this problem by the corresponding compiler vendors. uGFX v3 will no longer suffer from this problem as the driver interface works differently in this area.
1665 lines
48 KiB
C
1665 lines
48 KiB
C
/*
|
|
* This file is subject to the terms of the GFX License. If a copy of
|
|
* the license was not distributed with this file, you can obtain one at:
|
|
*
|
|
* http://ugfx.io/license.html
|
|
*/
|
|
|
|
// We need to include stdio.h below. Turn off GFILE_NEED_STDIO just for this file to prevent conflicts
|
|
#define GFILE_NEED_STDIO_MUST_BE_OFF
|
|
|
|
#include "gfx.h"
|
|
|
|
#if GFX_USE_GDISP
|
|
|
|
#define GDISP_DRIVER_VMT GDISPVMT_Win32
|
|
#include "gdisp_lld_config.h"
|
|
#include "../../../src/gdisp/gdisp_driver.h"
|
|
|
|
// Configuration parameters for this driver
|
|
#ifndef GDISP_SCREEN_WIDTH
|
|
#define GDISP_SCREEN_WIDTH 640
|
|
#endif
|
|
#ifndef GDISP_SCREEN_HEIGHT
|
|
#define GDISP_SCREEN_HEIGHT 480
|
|
#endif
|
|
#ifndef GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
/**
|
|
* Setting this to GFXON delays updating the screen
|
|
* to the windows paint routine. Due to the
|
|
* drawing lock this does not add as much speed
|
|
* as might be expected but it is still faster in
|
|
* all tested circumstances and for all operations
|
|
* even draw_pixel().
|
|
* This is probably due to drawing operations being
|
|
* combined as the update regions are merged.
|
|
* The only time you might want to turn this off is
|
|
* if you are debugging drawing and want to see each
|
|
* pixel as it is set.
|
|
*/
|
|
#define GDISP_WIN32_USE_INDIRECT_UPDATE GFXON
|
|
#endif
|
|
#ifndef GKEYBOARD_WIN32_NO_LAYOUT
|
|
/**
|
|
* Setting this to GFXON turns off the layout engine.
|
|
* In this situation "cooked" characters are returned but
|
|
* shift states etc are lost.
|
|
* As only a limited number of keyboard layouts are currently
|
|
* defined for Win32 in uGFX (currently only US English), setting this
|
|
* to GFXON enables the windows keyboard mapping to be pass non-English
|
|
* characters to uGFX or to handle non-standard keyboard layouts at
|
|
* the expense of losing special function keys etc.
|
|
*/
|
|
#define GKEYBOARD_WIN32_NO_LAYOUT GFXOFF
|
|
#endif
|
|
#ifndef GKEYBOARD_WIN32_DEFAULT_LAYOUT
|
|
#define GKEYBOARD_WIN32_DEFAULT_LAYOUT KeyboardLayout_Win32_US
|
|
#endif
|
|
|
|
// How far extra windows (multiple displays) should be offset from the first.
|
|
#define DISPLAY_X_OFFSET 50
|
|
#define DISPLAY_Y_OFFSET 50
|
|
|
|
// Oops - name clashes with Win32 symbols
|
|
#if GFX_COMPAT_V2 && GFX_COMPAT_OLDCOLORS
|
|
#undef Red
|
|
#undef Green
|
|
#undef Blue
|
|
#endif
|
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <wingdi.h>
|
|
#include <assert.h>
|
|
|
|
#define GDISP_FLG_READY (GDISP_FLG_DRIVER<<0)
|
|
#define GDISP_FLG_HASTOGGLE (GDISP_FLG_DRIVER<<1)
|
|
#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
|
|
#define GDISP_FLG_WSTREAM (GDISP_FLG_DRIVER<<3)
|
|
#define GDISP_FLG_WRAPPED (GDISP_FLG_DRIVER<<4)
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
/* Include toggle support code */
|
|
#include "../../../src/ginput/ginput_driver_toggle.h"
|
|
|
|
// Hack until toggle use gdriver.
|
|
static GDisplay *toggleWindow;
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
// Include mouse support code
|
|
#define GMOUSE_DRIVER_VMT GMOUSEVMT_Win32
|
|
#include "../../../src/ginput/ginput_driver_mouse.h"
|
|
|
|
// Forward definitions
|
|
static gBool Win32MouseInit(GMouse *m, unsigned driverinstance);
|
|
static gBool Win32MouseRead(GMouse *m, GMouseReading *prd);
|
|
|
|
/**
|
|
* This should be: const GMouseVMT const GMOUSE_DRIVER_VMT[1] = {{
|
|
* However, some major compilers complain about the duplicate const specifier even though this is perfectly valid standard C.
|
|
*/
|
|
const GMouseVMT GMOUSE_DRIVER_VMT[1] = {{
|
|
{
|
|
GDRIVER_TYPE_MOUSE,
|
|
GMOUSE_VFLG_NOPOLL|GMOUSE_VFLG_DYNAMICONLY,
|
|
// Extra flags for testing only
|
|
//GMOUSE_VFLG_TOUCH|GMOUSE_VFLG_SELFROTATION|GMOUSE_VFLG_DEFAULTFINGER
|
|
//GMOUSE_VFLG_CALIBRATE|GMOUSE_VFLG_CAL_EXTREMES|GMOUSE_VFLG_CAL_TEST|GMOUSE_VFLG_CAL_LOADFREE
|
|
//GMOUSE_VFLG_ONLY_DOWN|GMOUSE_VFLG_POORUPDOWN
|
|
sizeof(GMouse),
|
|
_gmouseInitDriver, _gmousePostInitDriver, _gmouseDeInitDriver
|
|
},
|
|
1, // z_max
|
|
0, // z_min
|
|
1, // z_touchon
|
|
0, // z_touchoff
|
|
{ // pen_jitter
|
|
0, // calibrate
|
|
0, // click
|
|
0 // move
|
|
},
|
|
{ // finger_jitter
|
|
0, // calibrate
|
|
2, // click
|
|
2 // move
|
|
},
|
|
Win32MouseInit, // init
|
|
0, // deinit
|
|
Win32MouseRead, // get
|
|
0, // calsave
|
|
0 // calload
|
|
}};
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
|
|
#define GKEYBOARD_DRIVER_VMT GKEYBOARDVMT_Win32
|
|
#include "../../../src/ginput/ginput_driver_keyboard.h"
|
|
|
|
#if !GKEYBOARD_WIN32_NO_LAYOUT
|
|
#if GKEYBOARD_LAYOUT_OFF
|
|
#error "The Win32 keyboard driver is using the layout engine. Please set GKEYBOARD_LAYOUT_OFF=GFXOFF or GKEYBOARD_WIN32_NO_LAYOUT=GFXON."
|
|
#endif
|
|
|
|
#include "../../../src/ginput/ginput_keyboard_microcode.h"
|
|
|
|
// Forward definitions
|
|
extern gU8 GKEYBOARD_WIN32_DEFAULT_LAYOUT[];
|
|
|
|
// This is the layout code for the English US keyboard.
|
|
// We make it public so that a user can switch to a different layout if required.
|
|
gU8 KeyboardLayout_Win32_US[] = {
|
|
KMC_HEADERSTART, KMC_HEADER_ID1, KMC_HEADER_ID2, KMC_HEADER_VER_1,
|
|
|
|
// Transient Shifters: SHIFT, CTRL, ALT, WINKEY
|
|
/* 1 */KMC_RECORDSTART, 9, // SHIFT (left & Right)
|
|
KMC_TEST_CODETABLE, 2, VK_SHIFT, VK_LSHIFT,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SHIFT_L_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 2 */KMC_RECORDSTART, 9,
|
|
KMC_TEST_CODETABLE, 2, VK_SHIFT, VK_LSHIFT,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_SHIFT_L_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SHIFT_L_BIT,
|
|
KMC_ACT_DONE,
|
|
/* 3 */KMC_RECORDSTART, 7,
|
|
KMC_TEST_CODE, VK_RSHIFT,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SHIFT_R_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 4 */KMC_RECORDSTART, 7,
|
|
KMC_TEST_CODE, VK_RSHIFT,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_SHIFT_R_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SHIFT_R_BIT,
|
|
KMC_ACT_DONE,
|
|
/* 5 */KMC_RECORDSTART, 9, // CONTROL (left & Right)
|
|
KMC_TEST_CODETABLE, 2, VK_CONTROL, VK_LCONTROL,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_CTRL_L_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 6 */KMC_RECORDSTART, 9,
|
|
KMC_TEST_CODETABLE, 2, VK_CONTROL, VK_LCONTROL,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_CTRL_L_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_CTRL_L_BIT,
|
|
KMC_ACT_DONE,
|
|
/* 7 */KMC_RECORDSTART, 7,
|
|
KMC_TEST_CODE, VK_RCONTROL,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_CTRL_R_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 8 */KMC_RECORDSTART, 7,
|
|
KMC_TEST_CODE, VK_RCONTROL,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_CTRL_R_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_CTRL_R_BIT,
|
|
KMC_ACT_DONE,
|
|
/* 9 */KMC_RECORDSTART, 9, // ALT (left & Right)
|
|
KMC_TEST_CODETABLE, 2, VK_MENU, VK_LMENU,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_ALT_L_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 10 */KMC_RECORDSTART, 9,
|
|
KMC_TEST_CODETABLE, 2, VK_MENU, VK_LMENU,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_ALT_L_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_ALT_L_BIT,
|
|
KMC_ACT_DONE,
|
|
/* 11 */KMC_RECORDSTART, 7,
|
|
KMC_TEST_CODE, VK_RMENU,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_ALT_R_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 12 */KMC_RECORDSTART, 7,
|
|
KMC_TEST_CODE, VK_RMENU,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_ALT_R_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_ALT_R_BIT,
|
|
KMC_ACT_DONE,
|
|
/* 13 */KMC_RECORDSTART, 9, // WinKey (left or right)
|
|
KMC_TEST_CODETABLE, 2, VK_LWIN, VK_RWIN,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_WINKEY_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_DONE,
|
|
/* 14 */KMC_RECORDSTART, 9,
|
|
KMC_TEST_CODETABLE, 2, VK_LWIN, VK_RWIN,
|
|
KMC_TEST_STATEBIT, GKEYSTATE_WINKEY_BIT|KMC_BIT_CLEAR,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_WINKEY_BIT,
|
|
KMC_ACT_DONE,
|
|
|
|
// Locking Shifters: CAPSLOCK, NUMLOCK and SCROLLLOCK
|
|
/* 15 */KMC_RECORDSTART, 7, // CAPSLOCK (keyup only)
|
|
KMC_TEST_CODE, VK_CAPITAL,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_CAPSLOCK_BIT|KMC_BIT_INVERT,
|
|
KMC_ACT_DONE,
|
|
/* 16 */KMC_RECORDSTART, 7, // NUMLOCK (keyup only)
|
|
KMC_TEST_CODE, VK_NUMLOCK,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_NUMLOCK_BIT|KMC_BIT_INVERT,
|
|
KMC_ACT_DONE,
|
|
/* 17 */KMC_RECORDSTART, 7, // SCROLLLOCK (keyup only)
|
|
KMC_TEST_CODE, VK_SCROLL,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SCROLLLOCK_BIT|KMC_BIT_INVERT,
|
|
KMC_ACT_DONE,
|
|
|
|
// Keyup, Repeat
|
|
/* 18 */KMC_RECORDSTART, 18, // Clear any shifter keys that got through
|
|
KMC_TEST_CODETABLE, 14, VK_SHIFT, VK_LSHIFT, VK_RSHIFT,
|
|
VK_CONTROL, VK_LCONTROL, VK_RCONTROL,
|
|
VK_MENU, VK_LMENU, VK_RMENU,
|
|
VK_LWIN, VK_RWIN,
|
|
VK_CAPITAL, VK_NUMLOCK, VK_SCROLL,
|
|
KMC_ACT_RESET,
|
|
KMC_ACT_STOP,
|
|
/* 19 */KMC_RECORDSTART, 4, // Skip special codes 0x00 (Keyup) & 0x01 (Repeat)
|
|
KMC_TEST_CODERANGE, 0x00, 0x01,
|
|
KMC_ACT_STOP,
|
|
/* 20 */KMC_RECORDSTART, 6, // Keyup
|
|
KMC_ACT_STATEBIT, GKEYSTATE_KEYUP_BIT|KMC_BIT_CLEAR,
|
|
KMC_TEST_LASTCODE, 0x00,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_KEYUP_BIT,
|
|
/* 21 */KMC_RECORDSTART, 6, // Repeat
|
|
KMC_ACT_STATEBIT, GKEYSTATE_REPEAT_BIT|KMC_BIT_CLEAR,
|
|
KMC_TEST_LASTCODE, 0x01,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_REPEAT_BIT,
|
|
|
|
// 0 - 9
|
|
/* 22 */KMC_RECORDSTART, 7, // Alt 0-9
|
|
KMC_TEST_ALT,
|
|
KMC_TEST_CODERANGE, '0', '9',
|
|
KMC_ACT_CHARADD, 10,
|
|
KMC_ACT_STOP,
|
|
/* 23 */KMC_RECORDSTART, 17, // Shifted 0-9
|
|
KMC_TEST_SHIFT,
|
|
KMC_TEST_CODERANGE, '0', '9',
|
|
KMC_ACT_CHARTABLE, 10, ')', '!', '@', '#', '$', '%', '^', '&', '*', '(',
|
|
KMC_ACT_DONE,
|
|
/* 24 */KMC_RECORDSTART, 5, // 0 - 9
|
|
KMC_TEST_CODERANGE, '0', '9',
|
|
KMC_ACT_CHARCODE,
|
|
KMC_ACT_DONE,
|
|
|
|
// A - Z
|
|
/* 25 */KMC_RECORDSTART, 7, // Control A-Z
|
|
KMC_TEST_CTRL,
|
|
KMC_TEST_CODERANGE, 'A', 'Z',
|
|
KMC_ACT_CHARRANGE, 1,
|
|
KMC_ACT_DONE,
|
|
/* 26 */KMC_RECORDSTART, 7, // No Caps A-Z
|
|
KMC_TEST_NOCAPS,
|
|
KMC_TEST_CODERANGE, 'A', 'Z',
|
|
KMC_ACT_CHARRANGE, 'a',
|
|
KMC_ACT_DONE,
|
|
/* 27 */KMC_RECORDSTART, 5, // Caps A-Z
|
|
KMC_TEST_CODERANGE, 'A', 'Z',
|
|
KMC_ACT_CHARCODE,
|
|
KMC_ACT_DONE,
|
|
|
|
// Number pad
|
|
/* 28 */KMC_RECORDSTART, 7, // Alt Number pad
|
|
KMC_TEST_ALT,
|
|
KMC_TEST_CODERANGE, VK_NUMPAD0, VK_NUMPAD9,
|
|
KMC_ACT_CHARADD, 10,
|
|
KMC_ACT_STOP,
|
|
/* 29 */KMC_RECORDSTART, 5,
|
|
KMC_TEST_ALT,
|
|
KMC_TEST_CODERANGE, VK_MULTIPLY, VK_DIVIDE,
|
|
KMC_ACT_STOP,
|
|
/* 30 */KMC_RECORDSTART, 7, // Number pad with Numlock
|
|
KMC_TEST_NUMLOCK,
|
|
KMC_TEST_CODERANGE, VK_NUMPAD0, VK_NUMPAD9,
|
|
KMC_ACT_CHARRANGE, '0',
|
|
KMC_ACT_DONE,
|
|
/* 31 */KMC_RECORDSTART, 13,
|
|
KMC_TEST_NUMLOCK,
|
|
KMC_TEST_CODERANGE, VK_MULTIPLY, VK_DIVIDE,
|
|
KMC_ACT_CHARTABLE, 6, '*', '+', GKEY_ENTER, '-', '.', '/',
|
|
KMC_ACT_DONE,
|
|
/* 32 */KMC_RECORDSTART, 4, // Number pad with no Numlock
|
|
KMC_TEST_CODE, VK_NUMPAD5,
|
|
KMC_ACT_RESET,
|
|
KMC_ACT_STOP,
|
|
/* 33 */KMC_RECORDSTART, 12,
|
|
KMC_TEST_CODERANGE, VK_MULTIPLY, VK_DIVIDE,
|
|
KMC_ACT_CHARTABLE, 6, '*', '+', GKEY_ENTER, '-', GKEY_DEL, '/',
|
|
KMC_ACT_DONE,
|
|
/* 34 */KMC_RECORDSTART, 18,
|
|
KMC_TEST_CODERANGE, VK_NUMPAD0, VK_NUMPAD9,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SPECIAL_BIT,
|
|
KMC_ACT_CHARTABLE, 10, GKEY_INSERT, GKEY_END, GKEY_DOWN, GKEY_PAGEDOWN, GKEY_LEFT, '5', GKEY_RIGHT, GKEY_HOME, GKEY_UP, GKEY_PAGEUP,
|
|
KMC_ACT_DONE,
|
|
|
|
// Symbols
|
|
/* 35 */KMC_RECORDSTART, 14, // Shifted Symbols
|
|
KMC_TEST_SHIFT,
|
|
KMC_TEST_CODERANGE, VK_OEM_1, VK_OEM_3,
|
|
KMC_ACT_CHARTABLE, 7, ':', '+', '<', '_', '>', '?', '~',
|
|
KMC_ACT_DONE,
|
|
/* 36 */KMC_RECORDSTART, 11,
|
|
KMC_TEST_SHIFT,
|
|
KMC_TEST_CODERANGE, VK_OEM_4, VK_OEM_7,
|
|
KMC_ACT_CHARTABLE, 4, '{', '|', '}', '"',
|
|
KMC_ACT_DONE,
|
|
/* 37 */KMC_RECORDSTART, 13, // Non-shifted Symbols
|
|
KMC_TEST_CODERANGE, VK_OEM_1, VK_OEM_3,
|
|
KMC_ACT_CHARTABLE, 7, ';', '=', ',', '-', '.', '/', '`',
|
|
KMC_ACT_DONE,
|
|
/* 38 */KMC_RECORDSTART, 10,
|
|
KMC_TEST_CODERANGE, VK_OEM_4, VK_OEM_7,
|
|
KMC_ACT_CHARTABLE, 4, '[', '\\', ']', '\'',
|
|
KMC_ACT_DONE,
|
|
|
|
// Special Keys
|
|
// Extra special keys like Media and Browser keys are still to be implemented.
|
|
/* 39 */KMC_RECORDSTART, 17, // Normal Control Type Keys
|
|
KMC_TEST_CODETABLE, 6, VK_BACK, VK_TAB, VK_RETURN, VK_ESCAPE, VK_SPACE, VK_DELETE,
|
|
KMC_ACT_CHARTABLE, 6, GKEY_BACKSPACE, GKEY_TAB, GKEY_ENTER, GKEY_ESC, GKEY_SPACE, GKEY_DEL,
|
|
KMC_ACT_DONE,
|
|
/* 40 */KMC_RECORDSTART, 35, // Special Keys
|
|
KMC_TEST_CODETABLE, 14, VK_PRIOR, VK_NEXT,
|
|
VK_HOME, VK_END,
|
|
VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN,
|
|
VK_INSERT,
|
|
VK_SNAPSHOT, VK_SLEEP, VK_PAUSE, VK_CANCEL,
|
|
VK_APPS,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SPECIAL_BIT,
|
|
KMC_ACT_CHARTABLE, 14, GKEY_PAGEUP, GKEY_PAGEDOWN,
|
|
GKEY_HOME, GKEY_END,
|
|
GKEY_LEFT, GKEY_RIGHT, GKEY_UP, GKEY_DOWN,
|
|
GKEY_INSERT,
|
|
GKEY_PRINTSCREEN, GKEY_SLEEP, GKEY_CTRLPAUSE, GKEY_CTRLBREAK,
|
|
GKEY_RIGHTCLICKKEY,
|
|
KMC_ACT_DONE,
|
|
/* 41 */KMC_RECORDSTART, 8, // F1 .. F15
|
|
KMC_TEST_CODERANGE, VK_F1, VK_F15,
|
|
KMC_ACT_STATEBIT, GKEYSTATE_SPECIAL_BIT,
|
|
KMC_ACT_CHARRANGE, GKEY_FN1,
|
|
KMC_ACT_DONE,
|
|
|
|
// Anything else
|
|
/* 40 */KMC_RECORDSTART, 1, // Just send the scan code to the user
|
|
KMC_ACT_DONE,
|
|
|
|
// EOF
|
|
KMC_RECORDSTART, 0
|
|
};
|
|
#elif !GKEYBOARD_LAYOUT_OFF
|
|
#if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
|
|
#warning "The WIN32 keyboard driver is not using the layout engine. If no other keyboard is using it consider defining GKEYBOARD_LAYOUT_OFF=GFXON to save code size."
|
|
#elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
|
|
COMPILER_WARNING("The WIN32 keyboard driver is not using the layout engine. If no other keyboard is using it consider defining GKEYBOARD_LAYOUT_OFF=GFXON to save code size.")
|
|
#endif
|
|
#endif
|
|
|
|
// Forward definitions
|
|
static gBool Win32KeyboardInit(GKeyboard *k, unsigned driverinstance);
|
|
static int Win32KeyboardGetData(GKeyboard *k, gU8 *pch, int sz);
|
|
|
|
const GKeyboardVMT const GKEYBOARD_DRIVER_VMT[1] = {{
|
|
{
|
|
GDRIVER_TYPE_KEYBOARD,
|
|
GKEYBOARD_VFLG_NOPOLL, // GKEYBOARD_VFLG_DYNAMICONLY
|
|
sizeof(GKeyboard),
|
|
_gkeyboardInitDriver, _gkeyboardPostInitDriver, _gkeyboardDeInitDriver
|
|
},
|
|
|
|
// The Win32 keyboard layout
|
|
#if GKEYBOARD_WIN32_NO_LAYOUT
|
|
0,
|
|
#else
|
|
GKEYBOARD_WIN32_DEFAULT_LAYOUT,
|
|
#endif
|
|
|
|
Win32KeyboardInit, // init
|
|
0, // deinit
|
|
Win32KeyboardGetData, // getdata
|
|
0 // putdata void (*putdata)(GKeyboard *k, char ch); Optional
|
|
}};
|
|
|
|
static int keypos;
|
|
static gU8 keybuffer[8];
|
|
static GKeyboard *keyboard;
|
|
#endif
|
|
|
|
static DWORD winThreadId;
|
|
static volatile gBool QReady;
|
|
static HANDLE drawMutex;
|
|
static HWND hWndParent = 0;
|
|
|
|
/*===========================================================================*/
|
|
/* Driver local routines . */
|
|
/*===========================================================================*/
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
#define WIN32_BUTTON_AREA 16
|
|
#else
|
|
#define WIN32_BUTTON_AREA 0
|
|
#endif
|
|
|
|
#define APP_NAME "uGFX"
|
|
|
|
typedef struct winPriv {
|
|
HWND hwnd;
|
|
HDC dcBuffer;
|
|
HBITMAP dcBitmap;
|
|
HBITMAP dcOldBitmap;
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
gCoord mousex, mousey;
|
|
gU16 mousebuttons;
|
|
GMouse *mouse;
|
|
gBool mouseenabled;
|
|
void (*capfn)(void * hWnd, GDisplay *g, gU16 buttons, gCoord x, gCoord y);
|
|
#endif
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
gU8 toggles;
|
|
#endif
|
|
#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
|
|
gCoord x0, y0, x1, y1;
|
|
gCoord x, y;
|
|
#endif
|
|
} winPriv;
|
|
|
|
void gfxEmulatorSetParentWindow(void *hwnd) {
|
|
hWndParent = (HWND)hwnd;
|
|
}
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
void gfxEmulatorMouseInject(GDisplay *g, gU16 buttons, gCoord x, gCoord y) {
|
|
winPriv * priv;
|
|
|
|
priv = (winPriv *)g->priv;
|
|
priv->mousebuttons = buttons;
|
|
priv->mousex = x;
|
|
priv->mousey = y;
|
|
if ((gmvmt(priv->mouse)->d.flags & GMOUSE_VFLG_NOPOLL)) // For normal setup this is always true
|
|
_gmouseWakeup(priv->mouse);
|
|
}
|
|
void gfxEmulatorMouseEnable(GDisplay *g, gBool enabled) {
|
|
((winPriv *)g->priv)->mouseenabled = enabled;
|
|
}
|
|
void gfxEmulatorMouseCapture(GDisplay *g, void (*capfn)(void * hWnd, GDisplay *g, gU16 buttons, gCoord x, gCoord y)) {
|
|
((winPriv *)g->priv)->capfn = capfn;
|
|
}
|
|
#endif
|
|
|
|
static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HDC dc;
|
|
PAINTSTRUCT ps;
|
|
GDisplay * g;
|
|
winPriv * priv;
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
gU16 btns;
|
|
#endif
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
HBRUSH hbrOn, hbrOff;
|
|
HPEN pen;
|
|
RECT rect;
|
|
HGDIOBJ old;
|
|
POINT p;
|
|
gCoord pos;
|
|
gU8 bit;
|
|
#endif
|
|
|
|
switch (Msg) {
|
|
case WM_CREATE:
|
|
// Get our GDisplay structure and attach it to the window
|
|
g = (GDisplay *)((LPCREATESTRUCT)lParam)->lpCreateParams;
|
|
priv = (winPriv *)g->priv;
|
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)g);
|
|
|
|
// Fill in the private area
|
|
priv->hwnd = hWnd;
|
|
dc = GetDC(hWnd);
|
|
priv->dcBitmap = CreateCompatibleBitmap(dc, g->g.Width, g->g.Height);
|
|
priv->dcBuffer = CreateCompatibleDC(dc);
|
|
ReleaseDC(hWnd, dc);
|
|
priv->dcOldBitmap = SelectObject(priv->dcBuffer, priv->dcBitmap);
|
|
|
|
// Mark the window as ready to go
|
|
g->flags |= GDISP_FLG_READY;
|
|
break;
|
|
|
|
#if GFX_USE_GINPUT && (GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE)
|
|
case WM_LBUTTONDOWN:
|
|
// Get our GDisplay structure
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
|
|
// Handle mouse down on the window
|
|
#if GINPUT_NEED_MOUSE
|
|
if ((gCoord)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) {
|
|
btns = priv->mousebuttons;
|
|
btns |= GINPUT_MOUSE_BTN_LEFT;
|
|
goto mousemove;
|
|
}
|
|
#endif
|
|
|
|
// Handle mouse down on the toggle area
|
|
#if GINPUT_NEED_TOGGLE
|
|
if ((gCoord)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) {
|
|
bit = 1 << ((gCoord)LOWORD(lParam)*8/g->g.Width);
|
|
priv->toggles ^= bit;
|
|
rect.left = 0;
|
|
rect.right = GDISP_SCREEN_WIDTH;
|
|
rect.top = GDISP_SCREEN_HEIGHT;
|
|
rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA;
|
|
InvalidateRect(hWnd, &rect, FALSE);
|
|
UpdateWindow(hWnd);
|
|
#if GINPUT_TOGGLE_POLL_PERIOD == gDelayForever
|
|
ginputToggleWakeup();
|
|
#endif
|
|
}
|
|
#endif
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
// Get our GDisplay structure
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
|
|
// Handle mouse up on the toggle area
|
|
#if GINPUT_NEED_TOGGLE
|
|
if ((g->flags & GDISP_FLG_HASTOGGLE)) {
|
|
if ((priv->toggles & 0x0F)) {
|
|
priv->toggles &= ~0x0F;
|
|
rect.left = 0;
|
|
rect.right = GDISP_SCREEN_WIDTH;
|
|
rect.top = GDISP_SCREEN_HEIGHT;
|
|
rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA;
|
|
InvalidateRect(hWnd, &rect, FALSE);
|
|
UpdateWindow(hWnd);
|
|
#if GINPUT_TOGGLE_POLL_PERIOD == gDelayForever
|
|
ginputToggleWakeup();
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Handle mouse up on the window
|
|
#if GINPUT_NEED_MOUSE
|
|
if ((gCoord)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) {
|
|
btns = priv->mousebuttons;
|
|
btns &= ~GINPUT_MOUSE_BTN_LEFT;
|
|
goto mousemove;
|
|
}
|
|
#endif
|
|
break;
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
case WM_MBUTTONDOWN:
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
if ((gCoord)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) {
|
|
btns = priv->mousebuttons;
|
|
btns |= GINPUT_MOUSE_BTN_MIDDLE;
|
|
goto mousemove;
|
|
}
|
|
break;
|
|
case WM_MBUTTONUP:
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
if ((gCoord)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) {
|
|
btns = priv->mousebuttons;
|
|
btns &= ~GINPUT_MOUSE_BTN_MIDDLE;
|
|
goto mousemove;
|
|
}
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
if ((gCoord)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) {
|
|
btns = priv->mousebuttons;
|
|
btns |= GINPUT_MOUSE_BTN_RIGHT;
|
|
goto mousemove;
|
|
}
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
if ((gCoord)HIWORD(lParam) < GDISP_SCREEN_HEIGHT) {
|
|
btns = priv->mousebuttons;
|
|
btns &= ~GINPUT_MOUSE_BTN_RIGHT;
|
|
goto mousemove;
|
|
}
|
|
break;
|
|
case WM_MOUSEMOVE:
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
if ((gCoord)HIWORD(lParam) >= GDISP_SCREEN_HEIGHT)
|
|
break;
|
|
btns = priv->mousebuttons;
|
|
|
|
mousemove:
|
|
if (priv->capfn)
|
|
priv->capfn(hWnd, g, btns, (gCoord)LOWORD(lParam), (gCoord)HIWORD(lParam));
|
|
if (priv->mouseenabled) {
|
|
priv->mousebuttons = btns;
|
|
priv->mousex = (gCoord)LOWORD(lParam);
|
|
priv->mousey = (gCoord)HIWORD(lParam);
|
|
if ((gmvmt(priv->mouse)->d.flags & GMOUSE_VFLG_NOPOLL)) // For normal setup this is always true
|
|
_gmouseWakeup(priv->mouse);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
|
|
case WM_SYSKEYDOWN:
|
|
case WM_SYSKEYUP:
|
|
case WM_KEYDOWN:
|
|
case WM_KEYUP:
|
|
// A layout is being used: Send scan codes to the keyboard buffer
|
|
if (keyboard && keyboard->pLayout && keypos < (int)sizeof(keybuffer)-1 && (wParam & 0xFF) > 0x01) {
|
|
if (Msg == WM_KEYUP || Msg == WM_SYSKEYUP)
|
|
keybuffer[keypos++] = 0x00; // Keyup
|
|
else if (HIWORD(lParam) & KF_REPEAT)
|
|
keybuffer[keypos++] = 0x01; // Repeat
|
|
keybuffer[keypos++] = wParam;
|
|
if ((gkvmt(keyboard)->d.flags & GKEYBOARD_VFLG_NOPOLL)) // For normal setup this is always true
|
|
_gkeyboardWakeup(keyboard);
|
|
}
|
|
return 0;
|
|
case WM_CHAR:
|
|
// A layout is not being used: Send character codes to the keyboard buffer
|
|
if (keyboard && !keyboard->pLayout && keypos < (int)sizeof(keybuffer)) {
|
|
wchar_t w;
|
|
int len;
|
|
|
|
// Convert from a UTF16 character to a UTF8 string.
|
|
w = wParam;
|
|
len = WideCharToMultiByte(CP_UTF8, 0, &w, 1, (char *)(keybuffer+keypos), sizeof(keybuffer)-keypos, 0, 0);
|
|
keypos += len;
|
|
if (len && (gkvmt(keyboard)->d.flags & GKEYBOARD_VFLG_NOPOLL)) // For normal setup this is always true
|
|
_gkeyboardWakeup(keyboard);
|
|
}
|
|
return 0;
|
|
/*
|
|
case WM_DEADCHAR:
|
|
case WM_SYSCHAR:
|
|
case WM_SYSDEADCHAR:
|
|
break;
|
|
*/
|
|
#endif
|
|
|
|
case WM_ERASEBKGND:
|
|
// Pretend we have erased the background.
|
|
// We know we don't really need to do this as we
|
|
// redraw the entire surface in the WM_PAINT handler.
|
|
return TRUE;
|
|
|
|
case WM_PAINT:
|
|
// Get our GDisplay structure
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
|
|
// Paint the main window area
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
dc = BeginPaint(hWnd, &ps);
|
|
BitBlt(dc, ps.rcPaint.left, ps.rcPaint.top,
|
|
ps.rcPaint.right - ps.rcPaint.left,
|
|
(ps.rcPaint.bottom > GDISP_SCREEN_HEIGHT ? GDISP_SCREEN_HEIGHT : ps.rcPaint.bottom) - ps.rcPaint.top,
|
|
priv->dcBuffer, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
|
|
|
|
// Paint the toggle area
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
if (ps.rcPaint.bottom >= GDISP_SCREEN_HEIGHT && (g->flags & GDISP_FLG_HASTOGGLE)) {
|
|
pen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
|
|
hbrOn = CreateSolidBrush(RGB(0, 0, 255));
|
|
hbrOff = CreateSolidBrush(RGB(128, 128, 128));
|
|
old = SelectObject(dc, pen);
|
|
MoveToEx(dc, 0, GDISP_SCREEN_HEIGHT, &p);
|
|
LineTo(dc, GDISP_SCREEN_WIDTH, GDISP_SCREEN_HEIGHT);
|
|
for(pos = 0, bit=1; pos < GDISP_SCREEN_WIDTH; pos=rect.right, bit <<= 1) {
|
|
rect.left = pos;
|
|
rect.right = pos + GDISP_SCREEN_WIDTH/8;
|
|
rect.top = GDISP_SCREEN_HEIGHT;
|
|
rect.bottom = GDISP_SCREEN_HEIGHT + WIN32_BUTTON_AREA;
|
|
FillRect(dc, &rect, (priv->toggles & bit) ? hbrOn : hbrOff);
|
|
if (pos > 0) {
|
|
MoveToEx(dc, rect.left, rect.top, &p);
|
|
LineTo(dc, rect.left, rect.bottom);
|
|
}
|
|
}
|
|
DeleteObject(hbrOn);
|
|
DeleteObject(hbrOff);
|
|
SelectObject(dc, old);
|
|
}
|
|
#endif
|
|
EndPaint(hWnd, &ps);
|
|
ReleaseMutex(drawMutex);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
// Get our GDisplay structure
|
|
g = (GDisplay *)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
priv = (winPriv *)g->priv;
|
|
|
|
// Restore the window and free our bitmaps
|
|
SelectObject(priv->dcBuffer, priv->dcOldBitmap);
|
|
DeleteDC(priv->dcBuffer);
|
|
DeleteObject(priv->dcBitmap);
|
|
|
|
// Cleanup the private area
|
|
gfxFree(priv);
|
|
|
|
// Quit the application
|
|
PostQuitMessage(0);
|
|
|
|
// Actually the above doesn't work (who knows why)
|
|
ExitProcess(0);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, Msg, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static DWORD WINAPI WindowThread(void *param) {
|
|
(void)param;
|
|
MSG msg;
|
|
|
|
// Establish this thread as a message queue thread
|
|
winThreadId = GetCurrentThreadId();
|
|
PeekMessage(&msg, 0, WM_USER, WM_USER, PM_NOREMOVE);
|
|
QReady = gTrue;
|
|
|
|
// Create the window class
|
|
{
|
|
WNDCLASS wc;
|
|
ATOM winClass;
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW; // | CS_OWNDC;
|
|
wc.lpfnWndProc = (WNDPROC)myWindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = GetModuleHandle(0);
|
|
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
|
wc.hCursor = LoadCursor(0, IDC_ARROW);
|
|
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
|
|
wc.lpszMenuName = 0;
|
|
wc.lpszClassName = APP_NAME;
|
|
winClass = RegisterClass(&wc);
|
|
assert(winClass != 0);
|
|
}
|
|
|
|
do {
|
|
// This is a high priority task - make sure other tasks get a go.
|
|
Sleep(1);
|
|
|
|
while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
|
// Is this our special thread message to create a new window?
|
|
if (!msg.hwnd && msg.message == WM_USER) {
|
|
RECT rect;
|
|
GDisplay *g;
|
|
|
|
g = (GDisplay *)msg.lParam;
|
|
|
|
// Set the window rectangle
|
|
rect.top = 0; rect.bottom = g->g.Height;
|
|
rect.left = 0; rect.right = g->g.Width;
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
if ((g->flags & GDISP_FLG_HASTOGGLE))
|
|
rect.bottom += WIN32_BUTTON_AREA;
|
|
#endif
|
|
AdjustWindowRect(&rect, WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU, 0);
|
|
|
|
// Create the window
|
|
msg.hwnd = CreateWindow(APP_NAME, "", WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_BORDER, msg.wParam*DISPLAY_X_OFFSET, msg.wParam*DISPLAY_Y_OFFSET,
|
|
rect.right-rect.left, rect.bottom-rect.top,
|
|
hWndParent, 0,
|
|
GetModuleHandle(0), g);
|
|
assert(msg.hwnd != 0);
|
|
|
|
// Or just a normal window message
|
|
} else {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
} while (msg.message != WM_QUIT);
|
|
ExitProcess(0);
|
|
return msg.wParam;
|
|
}
|
|
|
|
/*===========================================================================*/
|
|
/* Driver exported functions. */
|
|
/*===========================================================================*/
|
|
|
|
LLDSPEC gBool gdisp_lld_init(GDisplay *g) {
|
|
winPriv * priv;
|
|
char buf[132];
|
|
|
|
// Initialise the window thread and the window class (if it hasn't been done already)
|
|
if (!QReady) {
|
|
HANDLE hth;
|
|
|
|
// Create the draw mutex
|
|
drawMutex = CreateMutex(0, FALSE, 0);
|
|
|
|
// Create the thread
|
|
if (!(hth = CreateThread(0, 0, WindowThread, 0, CREATE_SUSPENDED, 0)))
|
|
return gFalse;
|
|
SetThreadPriority(hth, THREAD_PRIORITY_ABOVE_NORMAL);
|
|
ResumeThread(hth);
|
|
CloseHandle(hth);
|
|
|
|
// Wait for our thread to be ready
|
|
while (!QReady)
|
|
Sleep(1);
|
|
}
|
|
|
|
// Initialise the GDISP structure
|
|
g->g.Orientation = gOrientation0;
|
|
g->g.Powermode = gPowerOn;
|
|
g->g.Backlight = 100;
|
|
g->g.Contrast = 50;
|
|
g->g.Width = GDISP_SCREEN_WIDTH;
|
|
g->g.Height = GDISP_SCREEN_HEIGHT;
|
|
|
|
// Turn on toggles for the first GINPUT_TOGGLE_CONFIG_ENTRIES windows
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
if (g->controllerdisplay < GINPUT_TOGGLE_CONFIG_ENTRIES) {
|
|
g->flags |= GDISP_FLG_HASTOGGLE;
|
|
toggleWindow = g;
|
|
}
|
|
#endif
|
|
|
|
// Create a private area for this window
|
|
priv = gfxAlloc(sizeof(winPriv));
|
|
assert(priv != 0);
|
|
memset(priv, 0, sizeof(winPriv));
|
|
g->priv = priv;
|
|
#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
|
|
// Initialise with an invalid window
|
|
g->flags &= ~GDISP_FLG_WSTREAM;
|
|
#endif
|
|
g->board = 0; // no board interface for this controller
|
|
|
|
// Create the window in the message thread
|
|
PostThreadMessage(winThreadId, WM_USER, (WPARAM)g->controllerdisplay, (LPARAM)g);
|
|
|
|
// Wait for the window creation to complete (for safety)
|
|
while(!(((volatile GDisplay *)g)->flags & GDISP_FLG_READY))
|
|
Sleep(1);
|
|
|
|
// Create the associated mouse
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
priv->mouseenabled = hWndParent ? gFalse : gTrue;
|
|
priv->mouse = (GMouse *)gdriverRegister((const GDriverVMT*)GMOUSE_DRIVER_VMT, g);
|
|
#endif
|
|
|
|
sprintf(buf, APP_NAME " - %u", g->systemdisplay+1);
|
|
SetWindowTextA(priv->hwnd, buf);
|
|
ShowWindow(priv->hwnd, SW_SHOW);
|
|
UpdateWindow(priv->hwnd);
|
|
|
|
return gTrue;
|
|
}
|
|
|
|
#if GDISP_HARDWARE_FLUSH
|
|
LLDSPEC void gdisp_lld_flush(GDisplay *g) {
|
|
winPriv * priv;
|
|
|
|
priv = g->priv;
|
|
UpdateWindow(priv->hwnd);
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
|
|
void BAD_PARAMETER(const char *msg) {
|
|
fprintf(stderr, "%s\n", msg);
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_STREAM_WRITE
|
|
LLDSPEC void gdisp_lld_write_start(GDisplay *g) {
|
|
winPriv * priv;
|
|
|
|
if (g->flags & GDISP_FLG_WSTREAM)
|
|
BAD_PARAMETER("write_start: already in streaming mode");
|
|
if (g->p.cx <= 0 || g->p.cy <= 0 || g->p.x < 0 || g->p.y < 0 || g->p.x+g->p.cx > g->g.Width || g->p.y+g->p.cy > g->g.Height)
|
|
BAD_PARAMETER("write_start: bad window parameter");
|
|
|
|
priv = g->priv;
|
|
priv->x0 = g->p.x; priv->x1 = g->p.x + g->p.cx - 1;
|
|
priv->y0 = g->p.y; priv->y1 = g->p.y + g->p.cy - 1;
|
|
#if GDISP_HARDWARE_STREAM_POS
|
|
priv->x = g->p.x-1; // Make sure these values are invalid (for testing)
|
|
priv->y = g->p.y-1;
|
|
#else
|
|
priv->x = g->p.x;
|
|
priv->y = g->p.y;
|
|
#endif
|
|
g->flags |= GDISP_FLG_WSTREAM;
|
|
g->flags &= ~GDISP_FLG_WRAPPED;
|
|
}
|
|
LLDSPEC void gdisp_lld_write_color(GDisplay *g) {
|
|
winPriv * priv;
|
|
int x, y;
|
|
COLORREF color;
|
|
|
|
priv = g->priv;
|
|
color = gdispColor2Native(g->p.color);
|
|
|
|
if (!(g->flags & GDISP_FLG_WSTREAM))
|
|
BAD_PARAMETER("write_color: not in streaming mode");
|
|
if (priv->x < priv->x0 || priv->x > priv->x1 || priv->y < priv->y0 || priv->y > priv->y1)
|
|
BAD_PARAMETER("write_color: cursor outside streaming area");
|
|
if (g->flags & GDISP_FLG_WRAPPED) {
|
|
BAD_PARAMETER("write_color: Warning - Area wrapped.");
|
|
g->flags &= ~GDISP_FLG_WRAPPED;
|
|
}
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
x = priv->x;
|
|
y = priv->y;
|
|
break;
|
|
case gOrientation90:
|
|
x = priv->y;
|
|
y = g->g.Width - 1 - priv->x;
|
|
break;
|
|
case gOrientation180:
|
|
x = g->g.Width - 1 - priv->x;
|
|
y = g->g.Height - 1 - priv->y;
|
|
break;
|
|
case gOrientation270:
|
|
x = g->g.Height - 1 - priv->y;
|
|
y = priv->x;
|
|
break;
|
|
}
|
|
#else
|
|
x = priv->x;
|
|
y = priv->y;
|
|
#endif
|
|
|
|
// Draw the pixel on the screen and in the buffer.
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
SetPixel(priv->dcBuffer, x, y, color);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
{
|
|
RECT r;
|
|
r.left = x; r.right = x+1;
|
|
r.top = y; r.bottom = y+1;
|
|
InvalidateRect(priv->hwnd, &r, FALSE);
|
|
}
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
SetPixel(dc, x, y, color);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
|
|
// Update the cursor
|
|
if (++priv->x > priv->x1) {
|
|
priv->x = priv->x0;
|
|
if (++priv->y > priv->y1) {
|
|
g->flags |= GDISP_FLG_WRAPPED;
|
|
priv->y = priv->y0;
|
|
}
|
|
}
|
|
}
|
|
LLDSPEC void gdisp_lld_write_stop(GDisplay *g) {
|
|
if (!(g->flags & GDISP_FLG_WSTREAM))
|
|
BAD_PARAMETER("write_stop: not in streaming mode");
|
|
g->flags &= ~GDISP_FLG_WSTREAM;
|
|
}
|
|
#if GDISP_HARDWARE_STREAM_POS
|
|
LLDSPEC void gdisp_lld_write_pos(GDisplay *g) {
|
|
winPriv * priv;
|
|
|
|
priv = g->priv;
|
|
|
|
if (!(g->flags & GDISP_FLG_WSTREAM))
|
|
BAD_PARAMETER("write_pos: not in streaming mode");
|
|
if (g->p.x < priv->x0 || g->p.x > priv->x1 || g->p.y < priv->y0 || g->p.y > priv->y1)
|
|
BAD_PARAMETER("write_color: new cursor outside streaming area");
|
|
priv->x = g->p.x;
|
|
priv->y = g->p.y;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_STREAM_READ
|
|
LLDSPEC void gdisp_lld_read_start(GDisplay *g) {
|
|
winPriv * priv;
|
|
|
|
if (g->flags & GDISP_FLG_WSTREAM)
|
|
BAD_PARAMETER("read_start: already in streaming mode");
|
|
if (g->p.cx <= 0 || g->p.cy <= 0 || g->p.x < 0 || g->p.y < 0 || g->p.x+g->p.cx > g->g.Width || g->p.y+g->p.cy > g->g.Height)
|
|
BAD_PARAMETER("read_start: bad window parameter");
|
|
|
|
priv = g->priv;
|
|
priv->x0 = g->p.x; priv->x1 = g->p.x + g->p.cx - 1;
|
|
priv->y0 = g->p.y; priv->y1 = g->p.y + g->p.cy - 1;
|
|
priv->x = g->p.x;
|
|
priv->y = g->p.y;
|
|
g->flags |= GDISP_FLG_WSTREAM;
|
|
g->flags &= ~GDISP_FLG_WRAPPED;
|
|
}
|
|
LLDSPEC gColor gdisp_lld_read_color(GDisplay *g) {
|
|
winPriv * priv;
|
|
COLORREF color;
|
|
|
|
priv = g->priv;
|
|
|
|
if (!(g->flags & GDISP_FLG_WSTREAM))
|
|
BAD_PARAMETER("read_color: not in streaming mode");
|
|
if (priv->x < priv->x0 || priv->x > priv->x1 || priv->y < priv->y0 || priv->y > priv->y1)
|
|
BAD_PARAMETER("read_color: cursor outside streaming area");
|
|
if (g->flags & GDISP_FLG_WRAPPED) {
|
|
BAD_PARAMETER("read_color: Warning - Area wrapped.");
|
|
g->flags &= ~GDISP_FLG_WRAPPED;
|
|
}
|
|
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
color = GetPixel(priv->dcBuffer, priv->x, priv->y);
|
|
break;
|
|
case gOrientation90:
|
|
color = GetPixel(priv->dcBuffer, priv->y, g->g.Width - 1 - priv->x);
|
|
break;
|
|
case gOrientation180:
|
|
color = GetPixel(priv->dcBuffer, g->g.Width - 1 - priv->x, g->g.Height - 1 - priv->y);
|
|
break;
|
|
case gOrientation270:
|
|
color = GetPixel(priv->dcBuffer, g->g.Height - 1 - priv->y, priv->x);
|
|
break;
|
|
}
|
|
#else
|
|
color = GetPixel(priv->dcBuffer, priv->x, priv->y);
|
|
#endif
|
|
ReleaseMutex(drawMutex);
|
|
|
|
// Update the cursor
|
|
if (++priv->x > priv->x1) {
|
|
priv->x = priv->x0;
|
|
if (++priv->y > priv->y1) {
|
|
g->flags |= GDISP_FLG_WRAPPED;
|
|
priv->y = priv->y0;
|
|
}
|
|
}
|
|
|
|
return gdispNative2Color(color);
|
|
}
|
|
LLDSPEC void gdisp_lld_read_stop(GDisplay *g) {
|
|
if (!(g->flags & GDISP_FLG_WSTREAM))
|
|
BAD_PARAMETER("write_stop: not in streaming mode");
|
|
g->flags &= ~GDISP_FLG_WSTREAM;
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_DRAWPIXEL
|
|
LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g) {
|
|
winPriv * priv;
|
|
int x, y;
|
|
COLORREF color;
|
|
|
|
priv = g->priv;
|
|
color = gdispColor2Native(g->p.color);
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
x = g->p.x;
|
|
y = g->p.y;
|
|
break;
|
|
case gOrientation90:
|
|
x = g->p.y;
|
|
y = g->g.Width - 1 - g->p.x;
|
|
break;
|
|
case gOrientation180:
|
|
x = g->g.Width - 1 - g->p.x;
|
|
y = g->g.Height - 1 - g->p.y;
|
|
break;
|
|
case gOrientation270:
|
|
x = g->g.Height - 1 - g->p.y;
|
|
y = g->p.x;
|
|
break;
|
|
}
|
|
#else
|
|
x = g->p.x;
|
|
y = g->p.y;
|
|
#endif
|
|
|
|
// Draw the pixel on the screen and in the buffer.
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
SetPixel(priv->dcBuffer, x, y, color);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
{
|
|
RECT r;
|
|
r.left = x; r.right = x+1;
|
|
r.top = y; r.bottom = y+1;
|
|
InvalidateRect(priv->hwnd, &r, FALSE);
|
|
}
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
SetPixel(dc, x, y, color);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/* ---- Optional Routines ---- */
|
|
|
|
#if GDISP_HARDWARE_FILLS
|
|
LLDSPEC void gdisp_lld_fill_area(GDisplay *g) {
|
|
winPriv * priv;
|
|
RECT rect;
|
|
HBRUSH hbr;
|
|
COLORREF color;
|
|
|
|
priv = g->priv;
|
|
color = gdispColor2Native(g->p.color);
|
|
hbr = CreateSolidBrush(color);
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
rect.top = g->p.y;
|
|
rect.bottom = rect.top + g->p.cy;
|
|
rect.left = g->p.x;
|
|
rect.right = rect.left + g->p.cx;
|
|
break;
|
|
case gOrientation90:
|
|
rect.bottom = g->g.Width - g->p.x;
|
|
rect.top = rect.bottom - g->p.cx;
|
|
rect.left = g->p.y;
|
|
rect.right = rect.left + g->p.cy;
|
|
break;
|
|
case gOrientation180:
|
|
rect.bottom = g->g.Height - g->p.y;
|
|
rect.top = rect.bottom - g->p.cy;
|
|
rect.right = g->g.Width - g->p.x;
|
|
rect.left = rect.right - g->p.cx;
|
|
break;
|
|
case gOrientation270:
|
|
rect.top = g->p.x;
|
|
rect.bottom = rect.top + g->p.cx;
|
|
rect.right = g->g.Height - g->p.y;
|
|
rect.left = rect.right - g->p.cy;
|
|
break;
|
|
}
|
|
#else
|
|
rect.top = g->p.y;
|
|
rect.bottom = rect.top + g->p.cy;
|
|
rect.left = g->p.x;
|
|
rect.right = rect.left + g->p.cx;
|
|
#endif
|
|
|
|
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
FillRect(priv->dcBuffer, &rect, hbr);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
InvalidateRect(priv->hwnd, &rect, FALSE);
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
FillRect(dc, &rect, hbr);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
|
|
DeleteObject(hbr);
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL
|
|
static gPixel *rotateimg(GDisplay *g, const gPixel *buffer) {
|
|
gPixel *dstbuf;
|
|
gPixel *dst;
|
|
const gPixel *src;
|
|
size_t sz;
|
|
gCoord i, j;
|
|
|
|
// Allocate the destination buffer
|
|
sz = (size_t)g->p.cx * (size_t)g->p.cy;
|
|
if (!(dstbuf = (gPixel *)malloc(sz * sizeof(gPixel))))
|
|
return 0;
|
|
|
|
// Copy the bits we need
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
return 0; // not handled as it doesn't need to be.
|
|
case gOrientation90:
|
|
for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) {
|
|
dst = dstbuf+sz-g->p.cy+j;
|
|
for(i = 0; i < g->p.cx; i++, dst -= g->p.cy)
|
|
*dst = *src++;
|
|
}
|
|
break;
|
|
case gOrientation180:
|
|
for(dst = dstbuf+sz, src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx)
|
|
for(i = 0; i < g->p.cx; i++)
|
|
*--dst = *src++;
|
|
break;
|
|
case gOrientation270:
|
|
for(src = buffer+g->p.x1, j = 0; j < g->p.cy; j++, src += g->p.x2 - g->p.cx) {
|
|
dst = dstbuf+g->p.cy-j-1;
|
|
for(i = 0; i < g->p.cx; i++, dst += g->p.cy)
|
|
*dst = *src++;
|
|
}
|
|
break;
|
|
}
|
|
return dstbuf;
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_BITFILLS
|
|
#if COLOR_SYSTEM != GDISP_COLORSYSTEM_TRUECOLOR || COLOR_TYPE_BITS <= 8
|
|
#error "GDISP Win32: This driver's bitblit currently only supports true-color with bit depths > 8 bits."
|
|
#endif
|
|
|
|
LLDSPEC void gdisp_lld_blit_area(GDisplay *g) {
|
|
winPriv * priv;
|
|
gPixel * buffer;
|
|
RECT rect;
|
|
BITMAPV4HEADER bmpInfo;
|
|
|
|
// Make everything relative to the start of the line
|
|
priv = g->priv;
|
|
buffer = g->p.ptr;
|
|
buffer += g->p.x2*g->p.y1;
|
|
|
|
memset(&bmpInfo, 0, sizeof(bmpInfo));
|
|
bmpInfo.bV4Size = sizeof(bmpInfo);
|
|
bmpInfo.bV4Planes = 1;
|
|
bmpInfo.bV4BitCount = COLOR_TYPE_BITS;
|
|
bmpInfo.bV4AlphaMask = 0;
|
|
bmpInfo.bV4RedMask = RGB2COLOR(255,0,0);
|
|
bmpInfo.bV4GreenMask = RGB2COLOR(0,255,0);
|
|
bmpInfo.bV4BlueMask = RGB2COLOR(0,0,255);
|
|
bmpInfo.bV4V4Compression = BI_BITFIELDS;
|
|
bmpInfo.bV4XPelsPerMeter = 3078;
|
|
bmpInfo.bV4YPelsPerMeter = 3078;
|
|
bmpInfo.bV4ClrUsed = 0;
|
|
bmpInfo.bV4ClrImportant = 0;
|
|
bmpInfo.bV4CSType = 0; //LCS_sRGB;
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(gPixel);
|
|
bmpInfo.bV4Width = g->p.x2;
|
|
bmpInfo.bV4Height = -g->p.cy; /* top-down image */
|
|
rect.top = g->p.y;
|
|
rect.bottom = rect.top+g->p.cy;
|
|
rect.left = g->p.x;
|
|
rect.right = rect.left+g->p.cx;
|
|
break;
|
|
case gOrientation90:
|
|
if (!(buffer = rotateimg(g, buffer))) return;
|
|
bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(gPixel);
|
|
bmpInfo.bV4Width = g->p.cy;
|
|
bmpInfo.bV4Height = -g->p.cx; /* top-down image */
|
|
rect.bottom = g->g.Width - g->p.x;
|
|
rect.top = rect.bottom-g->p.cx;
|
|
rect.left = g->p.y;
|
|
rect.right = rect.left+g->p.cy;
|
|
break;
|
|
case gOrientation180:
|
|
if (!(buffer = rotateimg(g, buffer))) return;
|
|
bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(gPixel);
|
|
bmpInfo.bV4Width = g->p.cx;
|
|
bmpInfo.bV4Height = -g->p.cy; /* top-down image */
|
|
rect.bottom = g->g.Height-1 - g->p.y;
|
|
rect.top = rect.bottom-g->p.cy;
|
|
rect.right = g->g.Width - g->p.x;
|
|
rect.left = rect.right-g->p.cx;
|
|
break;
|
|
case gOrientation270:
|
|
if (!(buffer = rotateimg(g, buffer))) return;
|
|
bmpInfo.bV4SizeImage = (g->p.cy*g->p.cx) * sizeof(gPixel);
|
|
bmpInfo.bV4Width = g->p.cy;
|
|
bmpInfo.bV4Height = -g->p.cx; /* top-down image */
|
|
rect.top = g->p.x;
|
|
rect.bottom = rect.top+g->p.cx;
|
|
rect.right = g->g.Height - g->p.y;
|
|
rect.left = rect.right-g->p.cy;
|
|
break;
|
|
}
|
|
#else
|
|
bmpInfo.bV4SizeImage = (g->p.cy*g->p.x2) * sizeof(gPixel);
|
|
bmpInfo.bV4Width = g->p.x2;
|
|
bmpInfo.bV4Height = -g->p.cy; /* top-down image */
|
|
rect.top = g->p.y;
|
|
rect.bottom = rect.top+g->p.cy;
|
|
rect.left = g->p.x;
|
|
rect.right = rect.left+g->p.cx;
|
|
#endif
|
|
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
SetDIBitsToDevice(priv->dcBuffer, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
InvalidateRect(priv->hwnd, &rect, FALSE);
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
SetDIBitsToDevice(dc, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, rect.bottom-rect.top, buffer, (BITMAPINFO*)&bmpInfo, DIB_RGB_COLORS);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
if (buffer != (gPixel *)g->p.ptr)
|
|
free(buffer);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_HARDWARE_PIXELREAD
|
|
LLDSPEC gColor gdisp_lld_get_pixel_color(GDisplay *g) {
|
|
winPriv * priv;
|
|
COLORREF color;
|
|
|
|
priv = g->priv;
|
|
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
color = GetPixel(priv->dcBuffer, g->p.x, g->p.y);
|
|
break;
|
|
case gOrientation90:
|
|
color = GetPixel(priv->dcBuffer, g->p.y, g->g.Width - 1 - g->p.x);
|
|
break;
|
|
case gOrientation180:
|
|
color = GetPixel(priv->dcBuffer, g->g.Width - 1 - g->p.x, g->g.Height - 1 - g->p.y);
|
|
break;
|
|
case gOrientation270:
|
|
color = GetPixel(priv->dcBuffer, g->g.Height - 1 - g->p.y, g->p.x);
|
|
break;
|
|
}
|
|
#else
|
|
color = GetPixel(priv->dcBuffer, g->p.x, g->p.y);
|
|
#endif
|
|
ReleaseMutex(drawMutex);
|
|
|
|
return gdispNative2Color(color);
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL
|
|
LLDSPEC void gdisp_lld_vertical_scroll(GDisplay *g) {
|
|
winPriv * priv;
|
|
RECT rect;
|
|
gCoord lines;
|
|
|
|
priv = g->priv;
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
switch(g->g.Orientation) {
|
|
case gOrientation0:
|
|
default:
|
|
rect.top = g->p.y;
|
|
rect.bottom = rect.top+g->p.cy;
|
|
rect.left = g->p.x;
|
|
rect.right = rect.left+g->p.cx;
|
|
lines = -g->p.y1;
|
|
goto vertical_scroll;
|
|
case gOrientation90:
|
|
rect.bottom = g->g.Width - g->p.x;
|
|
rect.top = rect.bottom-g->p.cx;
|
|
rect.left = g->p.y;
|
|
rect.right = rect.left+g->p.cy;
|
|
lines = -g->p.y1;
|
|
goto horizontal_scroll;
|
|
case gOrientation180:
|
|
rect.bottom = g->g.Height - g->p.y;
|
|
rect.top = rect.bottom-g->p.cy;
|
|
rect.right = g->g.Width - g->p.x;
|
|
rect.left = rect.right-g->p.cx;
|
|
lines = g->p.y1;
|
|
vertical_scroll:
|
|
if (lines > 0) {
|
|
rect.bottom -= lines;
|
|
} else {
|
|
rect.top -= lines;
|
|
}
|
|
if (g->p.cy >= lines && g->p.cy >= -lines) {
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
ScrollDC(priv->dcBuffer, 0, lines, &rect, 0, 0, 0);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
InvalidateRect(priv->hwnd, &rect, FALSE);
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
ScrollDC(dc, 0, lines, &rect, 0, 0, 0);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
case gOrientation270:
|
|
rect.top = g->p.x;
|
|
rect.bottom = rect.top+g->p.cx;
|
|
rect.right = g->g.Height - g->p.y;
|
|
rect.left = rect.right-g->p.cy;
|
|
lines = g->p.y1;
|
|
horizontal_scroll:
|
|
if (lines > 0) {
|
|
rect.right -= lines;
|
|
} else {
|
|
rect.left -= lines;
|
|
}
|
|
if (g->p.cy >= lines && g->p.cy >= -lines) {
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
ScrollDC(priv->dcBuffer, lines, 0, &rect, 0, 0, 0);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
InvalidateRect(priv->hwnd, &rect, FALSE);
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
ScrollDC(dc, lines, 0, &rect, 0, 0, 0);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
#else
|
|
rect.top = g->p.y;
|
|
rect.bottom = rect.top+g->p.cy;
|
|
rect.left = g->p.x;
|
|
rect.right = rect.left+g->p.cx;
|
|
lines = -g->p.y1;
|
|
if (lines > 0) {
|
|
rect.bottom -= lines;
|
|
} else {
|
|
rect.top -= lines;
|
|
}
|
|
if (g->p.cy >= lines && g->p.cy >= -lines) {
|
|
WaitForSingleObject(drawMutex, INFINITE);
|
|
ScrollDC(priv->dcBuffer, 0, lines, &rect, 0, 0, 0);
|
|
#if GDISP_WIN32_USE_INDIRECT_UPDATE
|
|
ReleaseMutex(drawMutex);
|
|
InvalidateRect(priv->hwnd, &rect, FALSE);
|
|
#else
|
|
{
|
|
HDC dc;
|
|
dc = GetDC(priv->hwnd);
|
|
ScrollDC(dc, 0, lines, &rect, 0, 0, 0);
|
|
ReleaseDC(priv->hwnd, dc);
|
|
ReleaseMutex(drawMutex);
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
#if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
|
|
LLDSPEC void gdisp_lld_control(GDisplay *g) {
|
|
switch(g->p.x) {
|
|
case GDISP_CONTROL_ORIENTATION:
|
|
if (g->g.Orientation == (gOrientation)g->p.ptr)
|
|
return;
|
|
switch((gOrientation)g->p.ptr) {
|
|
case gOrientation0:
|
|
case gOrientation180:
|
|
g->g.Width = GDISP_SCREEN_WIDTH;
|
|
g->g.Height = GDISP_SCREEN_HEIGHT;
|
|
break;
|
|
case gOrientation90:
|
|
case gOrientation270:
|
|
g->g.Height = GDISP_SCREEN_WIDTH;
|
|
g->g.Width = GDISP_SCREEN_HEIGHT;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
g->g.Orientation = (gOrientation)g->p.ptr;
|
|
return;
|
|
/*
|
|
case GDISP_CONTROL_POWER:
|
|
case GDISP_CONTROL_BACKLIGHT:
|
|
case GDISP_CONTROL_CONTRAST:
|
|
*/
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
|
|
static gBool Win32MouseInit(GMouse *m, unsigned driverinstance) {
|
|
(void) m;
|
|
(void) driverinstance;
|
|
return gTrue;
|
|
}
|
|
static gBool Win32MouseRead(GMouse *m, GMouseReading *pt) {
|
|
GDisplay * g;
|
|
winPriv * priv;
|
|
|
|
g = m->display;
|
|
priv = g->priv;
|
|
|
|
pt->x = priv->mousex;
|
|
pt->y = priv->mousey;
|
|
pt->z = (priv->mousebuttons & GINPUT_MOUSE_BTN_LEFT) ? 1 : 0;
|
|
pt->buttons = priv->mousebuttons;
|
|
|
|
#if GDISP_NEED_CONTROL
|
|
// If the self-rotation has been set in the VMT then do that here (TESTING ONLY)
|
|
if ((gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { // For normal setup this is always False
|
|
gCoord t;
|
|
|
|
switch(gdispGGetOrientation(m->display)) {
|
|
case gOrientation0:
|
|
default:
|
|
break;
|
|
case gOrientation90:
|
|
t = pt->x;
|
|
pt->x = g->g.Width - 1 - pt->y;
|
|
pt->y = t;
|
|
break;
|
|
case gOrientation180:
|
|
pt->x = g->g.Width - 1 - pt->x;
|
|
pt->y = g->g.Height - 1 - pt->y;
|
|
break;
|
|
case gOrientation270:
|
|
t = pt->y;
|
|
pt->y = g->g.Height - 1 - pt->x;
|
|
pt->x = t;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return gTrue;
|
|
}
|
|
#endif /* GINPUT_NEED_MOUSE */
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
|
|
static gBool Win32KeyboardInit(GKeyboard *k, unsigned driverinstance) {
|
|
(void) driverinstance;
|
|
|
|
// Only one please
|
|
if (keyboard)
|
|
return gFalse;
|
|
|
|
keyboard = k;
|
|
return gTrue;
|
|
}
|
|
|
|
static int Win32KeyboardGetData(GKeyboard *k, gU8 *pch, int sz) {
|
|
int i, j;
|
|
(void) k;
|
|
|
|
if (!keypos)
|
|
return 0;
|
|
|
|
for(i = 0; i < keypos && i < sz; i++)
|
|
pch[i] = keybuffer[i];
|
|
keypos -= i;
|
|
for(j=0; j < keypos; j++)
|
|
keybuffer[j] = keybuffer[i+j];
|
|
return i;
|
|
}
|
|
#endif
|
|
|
|
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
|
#if GINPUT_TOGGLE_CONFIG_ENTRIES > 1
|
|
#error "GDISP Win32: GINPUT_TOGGLE_CONFIG_ENTRIES must be 1 until Toggles can use GDriver"
|
|
#endif
|
|
|
|
const GToggleConfig GInputToggleConfigTable[GINPUT_TOGGLE_CONFIG_ENTRIES];
|
|
|
|
void ginput_lld_toggle_init(const GToggleConfig *ptc) {
|
|
// Save the associated window struct
|
|
//ptc->id = &GDISP_WIN32[ptc - GInputToggleConfigTable];
|
|
((GToggleConfig *)ptc)->id = 0;
|
|
|
|
// We have 8 buttons per window.
|
|
((GToggleConfig *)ptc)->mask = 0xFF;
|
|
|
|
// No inverse or special mode
|
|
((GToggleConfig *)ptc)->invert = 0x00;
|
|
((GToggleConfig *)ptc)->mode = 0;
|
|
}
|
|
unsigned ginput_lld_toggle_getbits(const GToggleConfig *ptc) {
|
|
(void) ptc;
|
|
|
|
// This should use ID
|
|
if (!toggleWindow)
|
|
return 0;
|
|
return ((winPriv *)toggleWindow->priv)->toggles;
|
|
//return ((winPriv *)((GDisplay *)(ptc->id))->priv)->toggles;
|
|
}
|
|
#endif /* GINPUT_NEED_TOGGLE */
|
|
|
|
#endif /* GFX_USE_GDISP */
|