2013-05-01 23:53:28 +00:00
/*
2013-06-15 11:09:02 +00:00
* This file is subject to the terms of the GFX License . If a copy of
2013-05-03 14:36:17 +00:00
* the license was not distributed with this file , you can obtain one at :
*
2018-10-01 15:32:39 +00:00
* http : //ugfx.io/license.html
2013-05-03 14:36:17 +00:00
*/
2013-02-18 07:29:08 +00:00
2015-02-20 23:23:33 +00:00
// 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
2013-02-18 07:29:08 +00:00
# include "gfx.h"
2013-09-18 13:46:37 +00:00
# if GFX_USE_GDISP
2013-02-18 07:29:08 +00:00
2013-10-12 03:24:40 +00:00
# define GDISP_DRIVER_VMT GDISPVMT_Win32
2014-09-26 06:32:34 +00:00
# include "gdisp_lld_config.h"
2015-11-21 09:27:08 +00:00
# include "../../../src/gdisp/gdisp_driver.h"
2013-09-06 02:29:06 +00:00
2015-01-08 09:53:08 +00:00
// Configuration parameters for this driver
2013-02-18 07:29:08 +00:00
# ifndef GDISP_SCREEN_WIDTH
# define GDISP_SCREEN_WIDTH 640
# endif
# ifndef GDISP_SCREEN_HEIGHT
# define GDISP_SCREEN_HEIGHT 480
# endif
2015-01-03 08:40:38 +00:00
# ifndef GDISP_WIN32_USE_INDIRECT_UPDATE
2015-01-08 09:53:08 +00:00
/**
2018-02-27 07:44:21 +00:00
* Setting this to GFXON delays updating the screen
2015-01-08 09:53:08 +00:00
* 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 .
*/
2018-02-27 07:44:21 +00:00
# define GDISP_WIN32_USE_INDIRECT_UPDATE GFXON
2015-01-03 08:40:38 +00:00
# endif
2015-01-08 09:53:08 +00:00
# ifndef GKEYBOARD_WIN32_NO_LAYOUT
/**
2018-02-27 07:44:21 +00:00
* Setting this to GFXON turns off the layout engine .
2015-01-08 09:53:08 +00:00
* 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
2018-02-27 07:44:21 +00:00
* to GFXON enables the windows keyboard mapping to be pass non - English
2015-01-08 09:53:08 +00:00
* characters to uGFX or to handle non - standard keyboard layouts at
* the expense of losing special function keys etc .
*/
2018-02-27 07:44:21 +00:00
# define GKEYBOARD_WIN32_NO_LAYOUT GFXOFF
2015-01-08 09:53:08 +00:00
# endif
# ifndef GKEYBOARD_WIN32_DEFAULT_LAYOUT
# define GKEYBOARD_WIN32_DEFAULT_LAYOUT KeyboardLayout_Win32_US
# endif
2013-10-12 03:24:40 +00:00
2013-10-24 01:30:17 +00:00
// How far extra windows (multiple displays) should be offset from the first.
2013-10-12 03:24:40 +00:00
# define DISPLAY_X_OFFSET 50
# define DISPLAY_Y_OFFSET 50
2015-01-08 09:53:08 +00:00
// Oops - name clashes with Win32 symbols
2018-03-10 10:36:12 +00:00
# if GFX_COMPAT_V2 && GFX_COMPAT_OLDCOLORS
# undef Red
# undef Green
# undef Blue
# endif
2013-12-10 14:38:42 +00:00
# define WIN32_LEAN_AND_MEAN
2013-10-24 01:30:17 +00:00
# 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
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2013-10-24 01:30:17 +00:00
/* Include toggle support code */
2015-11-21 09:27:08 +00:00
# include "../../../src/ginput/ginput_driver_toggle.h"
2015-02-13 23:16:28 +00:00
// Hack until toggle use gdriver.
static GDisplay * toggleWindow ;
2013-10-24 01:30:17 +00:00
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2014-09-26 06:32:34 +00:00
// Include mouse support code
# define GMOUSE_DRIVER_VMT GMOUSEVMT_Win32
2015-11-21 09:27:08 +00:00
# include "../../../src/ginput/ginput_driver_mouse.h"
2014-09-26 06:32:34 +00:00
// Forward definitions
2018-06-23 03:02:07 +00:00
static gBool Win32MouseInit ( GMouse * m , unsigned driverinstance ) ;
static gBool Win32MouseRead ( GMouse * m , GMouseReading * prd ) ;
2014-09-26 06:32:34 +00:00
2021-08-12 10:20:07 +00:00
/**
* 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 ] = { {
2014-09-26 06:32:34 +00:00
{
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
2014-09-26 07:29:06 +00:00
0 , // calsave
0 // calload
2014-09-26 06:32:34 +00:00
} } ;
2013-10-24 01:30:17 +00:00
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
2015-01-07 03:21:23 +00:00
# define GKEYBOARD_DRIVER_VMT GKEYBOARDVMT_Win32
2015-11-21 09:27:08 +00:00
# include "../../../src/ginput/ginput_driver_keyboard.h"
2015-01-08 09:53:08 +00:00
# if !GKEYBOARD_WIN32_NO_LAYOUT
# if GKEYBOARD_LAYOUT_OFF
2018-02-27 07:44:21 +00:00
# error "The Win32 keyboard driver is using the layout engine. Please set GKEYBOARD_LAYOUT_OFF=GFXOFF or GKEYBOARD_WIN32_NO_LAYOUT=GFXON."
2015-01-08 09:53:08 +00:00
# endif
2015-11-21 09:27:08 +00:00
# include "../../../src/ginput/ginput_keyboard_microcode.h"
2015-01-08 09:53:08 +00:00
// Forward definitions
2018-11-03 00:51:23 +00:00
extern gU8 GKEYBOARD_WIN32_DEFAULT_LAYOUT [ ] ;
2015-01-08 09:53:08 +00:00
// 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.
2018-11-03 00:51:23 +00:00
gU8 KeyboardLayout_Win32_US [ ] = {
2015-01-08 09:53:08 +00:00
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
2017-06-30 09:43:51 +00:00
# if GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_DIRECT
2018-02-27 07:44:21 +00:00
# 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."
2017-06-30 09:43:51 +00:00
# elif GFX_COMPILER_WARNING_TYPE == GFX_COMPILER_WARNING_MACRO
2018-02-27 07:44:21 +00:00
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. " )
2017-06-30 09:43:51 +00:00
# endif
2015-01-08 09:53:08 +00:00
# endif
2015-01-07 03:21:23 +00:00
// Forward definitions
2018-06-23 03:02:07 +00:00
static gBool Win32KeyboardInit ( GKeyboard * k , unsigned driverinstance ) ;
2018-11-03 00:51:23 +00:00
static int Win32KeyboardGetData ( GKeyboard * k , gU8 * pch , int sz ) ;
2015-01-07 03:21:23 +00:00
const GKeyboardVMT const GKEYBOARD_DRIVER_VMT [ 1 ] = { {
{
GDRIVER_TYPE_KEYBOARD ,
GKEYBOARD_VFLG_NOPOLL , // GKEYBOARD_VFLG_DYNAMICONLY
sizeof ( GKeyboard ) ,
_gkeyboardInitDriver , _gkeyboardPostInitDriver , _gkeyboardDeInitDriver
} ,
2015-01-08 09:53:08 +00:00
// The Win32 keyboard layout
# if GKEYBOARD_WIN32_NO_LAYOUT
0 ,
# else
GKEYBOARD_WIN32_DEFAULT_LAYOUT ,
# endif
2015-01-07 03:21:23 +00:00
Win32KeyboardInit , // init
0 , // deinit
Win32KeyboardGetData , // getdata
0 // putdata void (*putdata)(GKeyboard *k, char ch); Optional
} } ;
static int keypos ;
2018-11-03 00:51:23 +00:00
static gU8 keybuffer [ 8 ] ;
2015-01-07 03:21:23 +00:00
static GKeyboard * keyboard ;
# endif
2013-10-12 03:24:40 +00:00
static DWORD winThreadId ;
2018-06-23 03:02:07 +00:00
static volatile gBool QReady ;
2013-10-12 03:24:40 +00:00
static HANDLE drawMutex ;
2016-07-19 08:54:17 +00:00
static HWND hWndParent = 0 ;
2013-10-12 03:24:40 +00:00
2013-02-18 07:29:08 +00:00
/*===========================================================================*/
/* Driver local routines . */
/*===========================================================================*/
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2013-02-18 07:29:08 +00:00
# define WIN32_BUTTON_AREA 16
# else
# define WIN32_BUTTON_AREA 0
# endif
2014-05-09 15:11:30 +00:00
# define APP_NAME "uGFX"
2013-02-18 07:29:08 +00:00
2013-10-12 03:24:40 +00:00
typedef struct winPriv {
HWND hwnd ;
HDC dcBuffer ;
HBITMAP dcBitmap ;
HBITMAP dcOldBitmap ;
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2018-07-08 00:54:19 +00:00
gCoord mousex , mousey ;
2018-11-03 00:51:23 +00:00
gU16 mousebuttons ;
2014-09-26 06:32:34 +00:00
GMouse * mouse ;
2018-06-23 03:02:07 +00:00
gBool mouseenabled ;
2018-11-03 00:51:23 +00:00
void ( * capfn ) ( void * hWnd , GDisplay * g , gU16 buttons , gCoord x , gCoord y ) ;
2013-10-12 03:24:40 +00:00
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2018-11-03 00:51:23 +00:00
gU8 toggles ;
2013-10-12 03:24:40 +00:00
# endif
2013-10-24 01:30:17 +00:00
# if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
2018-07-08 00:54:19 +00:00
gCoord x0 , y0 , x1 , y1 ;
gCoord x , y ;
2013-10-24 01:30:17 +00:00
# endif
2013-10-12 03:24:40 +00:00
} winPriv ;
2013-02-18 07:29:08 +00:00
2016-12-12 09:58:46 +00:00
void gfxEmulatorSetParentWindow ( void * hwnd ) {
hWndParent = ( HWND ) hwnd ;
2016-07-19 08:54:17 +00:00
}
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2018-11-03 00:51:23 +00:00
void gfxEmulatorMouseInject ( GDisplay * g , gU16 buttons , gCoord x , gCoord y ) {
2016-07-19 08:54:17 +00:00
winPriv * priv ;
priv = ( winPriv * ) g - > priv ;
2016-07-25 09:25:55 +00:00
priv - > mousebuttons = buttons ;
2016-07-19 08:54:17 +00:00
priv - > mousex = x ;
priv - > mousey = y ;
2018-02-27 07:44:21 +00:00
if ( ( gmvmt ( priv - > mouse ) - > d . flags & GMOUSE_VFLG_NOPOLL ) ) // For normal setup this is always true
2016-07-19 08:54:17 +00:00
_gmouseWakeup ( priv - > mouse ) ;
}
2018-06-23 03:02:07 +00:00
void gfxEmulatorMouseEnable ( GDisplay * g , gBool enabled ) {
2016-07-19 08:54:17 +00:00
( ( winPriv * ) g - > priv ) - > mouseenabled = enabled ;
}
2018-11-03 00:51:23 +00:00
void gfxEmulatorMouseCapture ( GDisplay * g , void ( * capfn ) ( void * hWnd , GDisplay * g , gU16 buttons , gCoord x , gCoord y ) ) {
2016-07-19 08:54:17 +00:00
( ( winPriv * ) g - > priv ) - > capfn = capfn ;
}
# endif
2013-02-18 07:29:08 +00:00
static LRESULT myWindowProc ( HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam )
{
2013-10-12 03:24:40 +00:00
HDC dc ;
PAINTSTRUCT ps ;
GDisplay * g ;
winPriv * priv ;
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2018-11-03 00:51:23 +00:00
gU16 btns ;
2016-07-19 08:54:17 +00:00
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2013-02-18 07:29:08 +00:00
HBRUSH hbrOn , hbrOff ;
HPEN pen ;
RECT rect ;
HGDIOBJ old ;
POINT p ;
2018-07-08 00:54:19 +00:00
gCoord pos ;
2018-11-03 00:51:23 +00:00
gU8 bit ;
2013-02-18 07:29:08 +00:00
# endif
switch ( Msg ) {
case WM_CREATE :
2013-10-12 03:24:40 +00:00
// 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 ;
2013-02-18 07:29:08 +00:00
break ;
2013-10-12 03:24:40 +00:00
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && (GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE)
2013-10-12 03:24:40 +00:00
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
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) < GDISP_SCREEN_HEIGHT ) {
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
btns | = GINPUT_MOUSE_BTN_LEFT ;
2013-10-12 03:24:40 +00:00
goto mousemove ;
}
# endif
// Handle mouse down on the toggle area
# if GINPUT_NEED_TOGGLE
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) > = GDISP_SCREEN_HEIGHT & & ( g - > flags & GDISP_FLG_HASTOGGLE ) ) {
bit = 1 < < ( ( gCoord ) LOWORD ( lParam ) * 8 / g - > g . Width ) ;
2013-10-12 03:24:40 +00:00
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 ) ;
2018-07-08 05:15:15 +00:00
# if GINPUT_TOGGLE_POLL_PERIOD == gDelayForever
2013-10-12 03:24:40 +00:00
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 ) ;
2018-07-08 05:15:15 +00:00
# if GINPUT_TOGGLE_POLL_PERIOD == gDelayForever
2013-10-12 03:24:40 +00:00
ginputToggleWakeup ( ) ;
# endif
}
}
# endif
// Handle mouse up on the window
# if GINPUT_NEED_MOUSE
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) < GDISP_SCREEN_HEIGHT ) {
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
btns & = ~ GINPUT_MOUSE_BTN_LEFT ;
2013-10-12 03:24:40 +00:00
goto mousemove ;
}
# endif
break ;
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2013-10-12 03:24:40 +00:00
case WM_MBUTTONDOWN :
g = ( GDisplay * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
priv = ( winPriv * ) g - > priv ;
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) < GDISP_SCREEN_HEIGHT ) {
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
btns | = GINPUT_MOUSE_BTN_MIDDLE ;
2013-02-18 07:29:08 +00:00
goto mousemove ;
}
2013-10-12 03:24:40 +00:00
break ;
case WM_MBUTTONUP :
g = ( GDisplay * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
priv = ( winPriv * ) g - > priv ;
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) < GDISP_SCREEN_HEIGHT ) {
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
btns & = ~ GINPUT_MOUSE_BTN_MIDDLE ;
2013-10-12 03:24:40 +00:00
goto mousemove ;
2013-02-18 07:29:08 +00:00
}
2013-10-12 03:24:40 +00:00
break ;
case WM_RBUTTONDOWN :
g = ( GDisplay * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
priv = ( winPriv * ) g - > priv ;
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) < GDISP_SCREEN_HEIGHT ) {
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
btns | = GINPUT_MOUSE_BTN_RIGHT ;
2013-02-18 07:29:08 +00:00
goto mousemove ;
}
break ;
2013-10-12 03:24:40 +00:00
case WM_RBUTTONUP :
g = ( GDisplay * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
priv = ( winPriv * ) g - > priv ;
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) < GDISP_SCREEN_HEIGHT ) {
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
btns & = ~ GINPUT_MOUSE_BTN_RIGHT ;
2013-10-12 03:24:40 +00:00
goto mousemove ;
}
break ;
case WM_MOUSEMOVE :
g = ( GDisplay * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
priv = ( winPriv * ) g - > priv ;
2018-07-08 00:54:19 +00:00
if ( ( gCoord ) HIWORD ( lParam ) > = GDISP_SCREEN_HEIGHT )
2013-10-12 03:24:40 +00:00
break ;
2016-07-19 08:54:17 +00:00
btns = priv - > mousebuttons ;
2013-10-12 03:24:40 +00:00
mousemove :
2016-07-19 08:54:17 +00:00
if ( priv - > capfn )
2018-07-08 00:54:19 +00:00
priv - > capfn ( hWnd , g , btns , ( gCoord ) LOWORD ( lParam ) , ( gCoord ) HIWORD ( lParam ) ) ;
2016-07-19 08:54:17 +00:00
if ( priv - > mouseenabled ) {
priv - > mousebuttons = btns ;
2018-07-08 00:54:19 +00:00
priv - > mousex = ( gCoord ) LOWORD ( lParam ) ;
priv - > mousey = ( gCoord ) HIWORD ( lParam ) ;
2018-02-27 07:44:21 +00:00
if ( ( gmvmt ( priv - > mouse ) - > d . flags & GMOUSE_VFLG_NOPOLL ) ) // For normal setup this is always true
2016-07-19 08:54:17 +00:00
_gmouseWakeup ( priv - > mouse ) ;
}
2013-10-12 03:24:40 +00:00
break ;
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
2015-01-07 03:21:23 +00:00
case WM_SYSKEYDOWN :
case WM_SYSKEYUP :
case WM_KEYDOWN :
case WM_KEYUP :
2015-01-08 09:53:08 +00:00
// A layout is being used: Send scan codes to the keyboard buffer
if ( keyboard & & keyboard - > pLayout & & keypos < ( int ) sizeof ( keybuffer ) - 1 & & ( wParam & 0xFF ) > 0x01 ) {
2015-01-07 03:21:23 +00:00
if ( Msg = = WM_KEYUP | | Msg = = WM_SYSKEYUP )
keybuffer [ keypos + + ] = 0x00 ; // Keyup
else if ( HIWORD ( lParam ) & KF_REPEAT )
keybuffer [ keypos + + ] = 0x01 ; // Repeat
keybuffer [ keypos + + ] = wParam ;
2018-02-27 07:44:21 +00:00
if ( ( gkvmt ( keyboard ) - > d . flags & GKEYBOARD_VFLG_NOPOLL ) ) // For normal setup this is always true
2015-01-07 03:21:23 +00:00
_gkeyboardWakeup ( keyboard ) ;
}
return 0 ;
case WM_CHAR :
2015-01-08 09:53:08 +00:00
// 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 ;
2018-02-27 07:44:21 +00:00
if ( len & & ( gkvmt ( keyboard ) - > d . flags & GKEYBOARD_VFLG_NOPOLL ) ) // For normal setup this is always true
2015-01-08 09:53:08 +00:00
_gkeyboardWakeup ( keyboard ) ;
}
return 0 ;
/*
2015-01-07 03:21:23 +00:00
case WM_DEADCHAR :
case WM_SYSCHAR :
case WM_SYSDEADCHAR :
break ;
*/
# endif
2013-10-12 03:24:40 +00:00
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 ;
2013-02-18 07:29:08 +00:00
case WM_PAINT :
2013-10-12 03:24:40 +00:00
// Get our GDisplay structure
g = ( GDisplay * ) GetWindowLongPtr ( hWnd , GWLP_USERDATA ) ;
priv = ( winPriv * ) g - > priv ;
// Paint the main window area
WaitForSingleObject ( drawMutex , INFINITE ) ;
2013-02-18 07:29:08 +00:00
dc = BeginPaint ( hWnd , & ps ) ;
BitBlt ( dc , ps . rcPaint . left , ps . rcPaint . top ,
ps . rcPaint . right - ps . rcPaint . left ,
2013-10-12 03:24:40 +00:00
( 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
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2013-10-12 03:24:40 +00:00
if ( ps . rcPaint . bottom > = GDISP_SCREEN_HEIGHT & & ( g - > flags & GDISP_FLG_HASTOGGLE ) ) {
2015-02-13 23:16:28 +00:00
pen = CreatePen ( PS_SOLID , 1 , RGB ( 0 , 0 , 0 ) ) ;
hbrOn = CreateSolidBrush ( RGB ( 0 , 0 , 255 ) ) ;
hbrOff = CreateSolidBrush ( RGB ( 128 , 128 , 128 ) ) ;
2013-02-18 07:29:08 +00:00
old = SelectObject ( dc , pen ) ;
2013-10-12 03:24:40 +00:00
MoveToEx ( dc , 0 , GDISP_SCREEN_HEIGHT , & p ) ;
LineTo ( dc , GDISP_SCREEN_WIDTH , GDISP_SCREEN_HEIGHT ) ;
2015-02-13 23:16:28 +00:00
for ( pos = 0 , bit = 1 ; pos < GDISP_SCREEN_WIDTH ; pos = rect . right , bit < < = 1 ) {
2013-02-18 07:29:08 +00:00
rect . left = pos ;
2013-10-12 03:24:40 +00:00
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 ) ;
2013-02-18 07:29:08 +00:00
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 ) ;
2013-10-12 03:24:40 +00:00
ReleaseMutex ( drawMutex ) ;
2013-02-18 07:29:08 +00:00
break ;
2013-10-12 03:24:40 +00:00
2013-02-18 07:29:08 +00:00
case WM_DESTROY :
2013-10-12 03:24:40 +00:00
// 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
2013-02-18 07:29:08 +00:00
PostQuitMessage ( 0 ) ;
2013-10-12 03:24:40 +00:00
// Actually the above doesn't work (who knows why)
ExitProcess ( 0 ) ;
2013-02-18 07:29:08 +00:00
break ;
2013-10-12 03:24:40 +00:00
2013-02-18 07:29:08 +00:00
default :
return DefWindowProc ( hWnd , Msg , wParam , lParam ) ;
}
return 0 ;
}
2013-12-21 01:20:30 +00:00
static DWORD WINAPI WindowThread ( void * param ) {
2013-06-02 08:57:22 +00:00
( void ) param ;
MSG msg ;
2013-05-25 16:06:55 +00:00
2013-10-12 03:24:40 +00:00
// Establish this thread as a message queue thread
winThreadId = GetCurrentThreadId ( ) ;
2013-12-21 03:23:16 +00:00
PeekMessage ( & msg , 0 , WM_USER , WM_USER , PM_NOREMOVE ) ;
2018-06-23 03:02:07 +00:00
QReady = gTrue ;
2013-10-12 03:24:40 +00:00
2013-12-21 03:23:16 +00:00
// 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 ) ;
}
2013-06-02 08:57:22 +00:00
do {
2013-12-21 03:23:16 +00:00
// This is a high priority task - make sure other tasks get a go.
Sleep ( 1 ) ;
while ( PeekMessage ( & msg , 0 , 0 , 0 , PM_REMOVE ) ) {
2013-10-12 03:24:40 +00:00
// 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 ;
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2013-10-12 03:24:40 +00:00
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 ,
2016-07-19 08:54:17 +00:00
rect . right - rect . left , rect . bottom - rect . top ,
hWndParent , 0 ,
2013-12-21 03:23:16 +00:00
GetModuleHandle ( 0 ) , g ) ;
assert ( msg . hwnd ! = 0 ) ;
2013-10-12 03:24:40 +00:00
// Or just a normal window message
} else {
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
2013-05-25 16:06:55 +00:00
}
2013-06-02 08:57:22 +00:00
} while ( msg . message ! = WM_QUIT ) ;
ExitProcess ( 0 ) ;
return msg . wParam ;
}
2013-02-18 07:29:08 +00:00
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
2018-06-23 03:02:07 +00:00
LLDSPEC gBool gdisp_lld_init ( GDisplay * g ) {
2013-10-12 03:24:40 +00:00
winPriv * priv ;
char buf [ 132 ] ;
// Initialise the window thread and the window class (if it hasn't been done already)
if ( ! QReady ) {
2013-12-21 01:20:30 +00:00
HANDLE hth ;
2013-10-12 03:24:40 +00:00
// Create the draw mutex
2013-12-21 03:23:16 +00:00
drawMutex = CreateMutex ( 0 , FALSE , 0 ) ;
2013-10-12 03:24:40 +00:00
// Create the thread
2013-12-21 03:23:16 +00:00
if ( ! ( hth = CreateThread ( 0 , 0 , WindowThread , 0 , CREATE_SUSPENDED , 0 ) ) )
2018-06-23 03:02:07 +00:00
return gFalse ;
2013-12-21 01:20:30 +00:00
SetThreadPriority ( hth , THREAD_PRIORITY_ABOVE_NORMAL ) ;
ResumeThread ( hth ) ;
CloseHandle ( hth ) ;
2013-10-12 03:24:40 +00:00
// Wait for our thread to be ready
while ( ! QReady )
2013-12-21 01:20:30 +00:00
Sleep ( 1 ) ;
2013-06-02 08:57:22 +00:00
}
2013-02-18 07:29:08 +00:00
2013-10-12 03:24:40 +00:00
// Initialise the GDISP structure
2018-07-08 03:51:20 +00:00
g - > g . Orientation = gOrientation0 ;
2018-07-08 01:47:36 +00:00
g - > g . Powermode = gPowerOn ;
2013-09-18 13:46:37 +00:00
g - > g . Backlight = 100 ;
g - > g . Contrast = 50 ;
2013-10-12 03:24:40 +00:00
g - > g . Width = GDISP_SCREEN_WIDTH ;
g - > g . Height = GDISP_SCREEN_HEIGHT ;
// Turn on toggles for the first GINPUT_TOGGLE_CONFIG_ENTRIES windows
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2015-02-13 23:16:28 +00:00
if ( g - > controllerdisplay < GINPUT_TOGGLE_CONFIG_ENTRIES ) {
2013-10-12 03:24:40 +00:00
g - > flags | = GDISP_FLG_HASTOGGLE ;
2015-02-13 23:16:28 +00:00
toggleWindow = g ;
}
2013-10-12 03:24:40 +00:00
# endif
// Create a private area for this window
2014-02-02 11:59:36 +00:00
priv = gfxAlloc ( sizeof ( winPriv ) ) ;
2013-12-21 03:23:16 +00:00
assert ( priv ! = 0 ) ;
2013-10-12 03:24:40 +00:00
memset ( priv , 0 , sizeof ( winPriv ) ) ;
g - > priv = priv ;
2013-10-24 01:30:17 +00:00
# if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
// Initialise with an invalid window
g - > flags & = ~ GDISP_FLG_WSTREAM ;
# endif
2013-10-21 05:13:10 +00:00
g - > board = 0 ; // no board interface for this controller
2013-10-12 03:24:40 +00:00
// Create the window in the message thread
2013-10-19 05:36:05 +00:00
PostThreadMessage ( winThreadId , WM_USER , ( WPARAM ) g - > controllerdisplay , ( LPARAM ) g ) ;
2013-10-12 03:24:40 +00:00
// Wait for the window creation to complete (for safety)
while ( ! ( ( ( volatile GDisplay * ) g ) - > flags & GDISP_FLG_READY ) )
2013-12-21 01:20:30 +00:00
Sleep ( 1 ) ;
2013-10-12 03:24:40 +00:00
2014-09-26 06:32:34 +00:00
// Create the associated mouse
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2018-06-23 03:02:07 +00:00
priv - > mouseenabled = hWndParent ? gFalse : gTrue ;
2021-08-12 10:20:07 +00:00
priv - > mouse = ( GMouse * ) gdriverRegister ( ( const GDriverVMT * ) GMOUSE_DRIVER_VMT , g ) ;
2014-09-26 06:32:34 +00:00
# endif
2014-09-27 15:44:24 +00:00
sprintf ( buf , APP_NAME " - %u " , g - > systemdisplay + 1 ) ;
2017-06-30 09:44:38 +00:00
SetWindowTextA ( priv - > hwnd , buf ) ;
2014-09-27 15:44:24 +00:00
ShowWindow ( priv - > hwnd , SW_SHOW ) ;
UpdateWindow ( priv - > hwnd ) ;
2018-06-23 03:02:07 +00:00
return gTrue ;
2013-02-18 07:29:08 +00:00
}
2013-10-21 03:34:55 +00:00
# if GDISP_HARDWARE_FLUSH
LLDSPEC void gdisp_lld_flush ( GDisplay * g ) {
winPriv * priv ;
priv = g - > priv ;
UpdateWindow ( priv - > hwnd ) ;
}
# endif
2013-10-24 01:30:17 +00:00
# if GDISP_HARDWARE_STREAM_WRITE || GDISP_HARDWARE_STREAM_READ
void BAD_PARAMETER ( const char * msg ) {
2013-10-29 10:25:41 +00:00
fprintf ( stderr , " %s \n " , msg ) ;
2013-10-24 01:30:17 +00:00
}
# 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 ;
2013-11-17 13:32:19 +00:00
color = gdispColor2Native ( g - > p . color ) ;
2013-10-24 01:30:17 +00:00
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 ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-10-24 01:30:17 +00:00
x = priv - > x ;
y = priv - > y ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-10-24 01:30:17 +00:00
x = priv - > y ;
y = g - > g . Width - 1 - priv - > x ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-10-24 01:30:17 +00:00
x = g - > g . Width - 1 - priv - > x ;
y = g - > g . Height - 1 - priv - > y ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-10-24 01:30:17 +00:00
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 ;
}
2018-07-08 01:19:43 +00:00
LLDSPEC gColor gdisp_lld_read_color ( GDisplay * g ) {
2013-10-24 01:30:17 +00:00
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 ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-11-05 03:43:28 +00:00
color = GetPixel ( priv - > dcBuffer , priv - > x , priv - > y ) ;
2013-10-24 01:30:17 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-11-05 03:43:28 +00:00
color = GetPixel ( priv - > dcBuffer , priv - > y , g - > g . Width - 1 - priv - > x ) ;
2013-10-24 01:30:17 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-11-05 03:43:28 +00:00
color = GetPixel ( priv - > dcBuffer , g - > g . Width - 1 - priv - > x , g - > g . Height - 1 - priv - > y ) ;
2013-10-24 01:30:17 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-11-05 03:43:28 +00:00
color = GetPixel ( priv - > dcBuffer , g - > g . Height - 1 - priv - > y , priv - > x ) ;
2013-10-24 01:30:17 +00:00
break ;
}
# else
2013-11-05 03:43:28 +00:00
color = GetPixel ( priv - > dcBuffer , priv - > x , priv - > y ) ;
2013-10-24 01:30:17 +00:00
# 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 ;
}
}
2013-11-17 13:32:19 +00:00
return gdispNative2Color ( color ) ;
2013-10-24 01:30:17 +00:00
}
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
2013-09-06 02:29:06 +00:00
# if GDISP_HARDWARE_DRAWPIXEL
2013-10-12 03:24:40 +00:00
LLDSPEC void gdisp_lld_draw_pixel ( GDisplay * g ) {
winPriv * priv ;
2013-09-06 02:29:06 +00:00
int x , y ;
COLORREF color ;
2014-09-26 06:32:34 +00:00
2013-10-12 03:24:40 +00:00
priv = g - > priv ;
2013-11-17 13:32:19 +00:00
color = gdispColor2Native ( g - > p . color ) ;
2014-09-26 06:32:34 +00:00
2013-09-06 02:29:06 +00:00
# if GDISP_NEED_CONTROL
2013-09-18 13:46:37 +00:00
switch ( g - > g . Orientation ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-09-18 13:46:37 +00:00
x = g - > p . x ;
y = g - > p . y ;
2013-09-06 02:29:06 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-09-24 06:10:15 +00:00
x = g - > p . y ;
y = g - > g . Width - 1 - g - > p . x ;
2013-09-06 02:29:06 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-09-18 13:46:37 +00:00
x = g - > g . Width - 1 - g - > p . x ;
y = g - > g . Height - 1 - g - > p . y ;
2013-09-06 02:29:06 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-09-24 06:10:15 +00:00
x = g - > g . Height - 1 - g - > p . y ;
y = g - > p . x ;
2013-09-06 02:29:06 +00:00
break ;
}
# else
2013-09-18 13:46:37 +00:00
x = g - > p . x ;
y = g - > p . y ;
2013-09-06 02:29:06 +00:00
# endif
// Draw the pixel on the screen and in the buffer.
2013-10-12 03:24:40 +00:00
WaitForSingleObject ( drawMutex , INFINITE ) ;
SetPixel ( priv - > dcBuffer , x , y , color ) ;
# if GDISP_WIN32_USE_INDIRECT_UPDATE
ReleaseMutex ( drawMutex ) ;
{
RECT r ;
2013-10-24 01:30:17 +00:00
r . left = x ; r . right = x + 1 ;
r . top = y ; r . bottom = y + 1 ;
2013-10-12 03:24:40 +00:00
InvalidateRect ( priv - > hwnd , & r , FALSE ) ;
}
# else
{
HDC dc ;
dc = GetDC ( priv - > hwnd ) ;
SetPixel ( dc , x , y , color ) ;
ReleaseDC ( priv - > hwnd , dc ) ;
ReleaseMutex ( drawMutex ) ;
}
# endif
2013-09-06 02:29:06 +00:00
}
# endif
2013-02-18 07:29:08 +00:00
/* ---- Optional Routines ---- */
2013-09-06 02:29:06 +00:00
# if GDISP_HARDWARE_FILLS
2013-10-12 03:24:40 +00:00
LLDSPEC void gdisp_lld_fill_area ( GDisplay * g ) {
winPriv * priv ;
2013-09-06 02:29:06 +00:00
RECT rect ;
HBRUSH hbr ;
COLORREF color ;
2013-02-18 07:29:08 +00:00
2013-10-12 03:24:40 +00:00
priv = g - > priv ;
2013-11-17 13:32:19 +00:00
color = gdispColor2Native ( g - > p . color ) ;
2013-10-12 03:24:40 +00:00
hbr = CreateSolidBrush ( color ) ;
2013-02-18 07:29:08 +00:00
# if GDISP_NEED_CONTROL
2013-09-18 13:46:37 +00:00
switch ( g - > g . Orientation ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-09-18 13:46:37 +00:00
rect . top = g - > p . y ;
rect . bottom = rect . top + g - > p . cy ;
rect . left = g - > p . x ;
rect . right = rect . left + g - > p . cx ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-09-18 13:46:37 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
}
# else
2013-09-18 13:46:37 +00:00
rect . top = g - > p . y ;
rect . bottom = rect . top + g - > p . cy ;
rect . left = g - > p . x ;
rect . right = rect . left + g - > p . cx ;
2013-02-18 07:29:08 +00:00
# endif
2013-10-12 03:24:40 +00:00
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
2013-02-18 07:29:08 +00:00
2013-09-06 02:29:06 +00:00
DeleteObject ( hbr ) ;
2013-02-18 07:29:08 +00:00
}
# endif
2013-09-24 06:10:15 +00:00
# if GDISP_HARDWARE_BITFILLS && GDISP_NEED_CONTROL
2018-07-08 01:08:55 +00:00
static gPixel * rotateimg ( GDisplay * g , const gPixel * buffer ) {
gPixel * dstbuf ;
gPixel * dst ;
const gPixel * src ;
2013-02-18 07:29:08 +00:00
size_t sz ;
2018-07-08 00:54:19 +00:00
gCoord i , j ;
2013-02-18 07:29:08 +00:00
// Allocate the destination buffer
2013-09-24 06:10:15 +00:00
sz = ( size_t ) g - > p . cx * ( size_t ) g - > p . cy ;
2018-07-08 01:08:55 +00:00
if ( ! ( dstbuf = ( gPixel * ) malloc ( sz * sizeof ( gPixel ) ) ) )
2013-02-18 07:29:08 +00:00
return 0 ;
2014-09-26 06:32:34 +00:00
2013-02-18 07:29:08 +00:00
// Copy the bits we need
2013-09-24 06:10:15 +00:00
switch ( g - > g . Orientation ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-10-24 06:53:07 +00:00
return 0 ; // not handled as it doesn't need to be.
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-09-24 06:10:15 +00:00
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 )
2013-02-18 07:29:08 +00:00
* dst = * src + + ;
}
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-09-24 06:10:15 +00:00
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 + + )
2013-02-18 07:29:08 +00:00
* - - dst = * src + + ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-09-24 06:10:15 +00:00
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 )
2013-02-18 07:29:08 +00:00
* dst = * src + + ;
}
break ;
}
return dstbuf ;
}
# endif
2014-09-26 06:32:34 +00:00
2013-09-24 06:10:15 +00:00
# if GDISP_HARDWARE_BITFILLS
2013-11-05 09:34:12 +00:00
# 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
2013-10-12 03:24:40 +00:00
LLDSPEC void gdisp_lld_blit_area ( GDisplay * g ) {
winPriv * priv ;
2018-07-08 01:08:55 +00:00
gPixel * buffer ;
2013-10-12 03:24:40 +00:00
RECT rect ;
BITMAPV4HEADER bmpInfo ;
2021-08-25 22:22:19 +00:00
# if GDISP_NEED_CONTROL
gPixel * bufferBase ;
# endif
2013-02-18 07:29:08 +00:00
// Make everything relative to the start of the line
2013-10-12 03:24:40 +00:00
priv = g - > priv ;
2013-09-24 06:10:15 +00:00
buffer = g - > p . ptr ;
2021-08-25 22:04:47 +00:00
buffer + = g - > p . x2 * g - > p . y1 + g - > p . x1 ;
2021-08-25 22:22:19 +00:00
# if GDISP_NEED_CONTROL
bufferBase = buffer ; // Keep pointer to original buffer for correct free()-ing later on
# endif
2014-09-26 06:32:34 +00:00
2013-02-18 07:29:08 +00:00
memset ( & bmpInfo , 0 , sizeof ( bmpInfo ) ) ;
bmpInfo . bV4Size = sizeof ( bmpInfo ) ;
bmpInfo . bV4Planes = 1 ;
2013-11-05 09:34:12 +00:00
bmpInfo . bV4BitCount = COLOR_TYPE_BITS ;
2013-02-18 07:29:08 +00:00
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
2013-09-24 06:10:15 +00:00
switch ( g - > g . Orientation ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2018-07-08 01:08:55 +00:00
bmpInfo . bV4SizeImage = ( g - > p . cy * g - > p . x2 ) * sizeof ( gPixel ) ;
2013-10-12 03:24:40 +00:00
bmpInfo . bV4Width = g - > p . x2 ;
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-10-12 03:24:40 +00:00
if ( ! ( buffer = rotateimg ( g , buffer ) ) ) return ;
2018-07-08 01:08:55 +00:00
bmpInfo . bV4SizeImage = ( g - > p . cy * g - > p . cx ) * sizeof ( gPixel ) ;
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-10-12 03:24:40 +00:00
if ( ! ( buffer = rotateimg ( g , buffer ) ) ) return ;
2018-07-08 01:08:55 +00:00
bmpInfo . bV4SizeImage = ( g - > p . cy * g - > p . cx ) * sizeof ( gPixel ) ;
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-10-12 03:24:40 +00:00
if ( ! ( buffer = rotateimg ( g , buffer ) ) ) return ;
2018-07-08 01:08:55 +00:00
bmpInfo . bV4SizeImage = ( g - > p . cy * g - > p . cx ) * sizeof ( gPixel ) ;
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
break ;
}
# else
2018-07-08 01:08:55 +00:00
bmpInfo . bV4SizeImage = ( g - > p . cy * g - > p . x2 ) * sizeof ( gPixel ) ;
2013-09-24 06:10:15 +00:00
bmpInfo . bV4Width = g - > p . x2 ;
bmpInfo . bV4Height = - g - > p . cy ; /* top-down image */
2013-10-12 03:24:40 +00:00
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
2021-08-25 22:22:19 +00:00
if ( bufferBase ! = buffer )
2013-10-24 06:53:07 +00:00
free ( buffer ) ;
2013-02-18 07:29:08 +00:00
# endif
}
# endif
2013-09-18 13:46:37 +00:00
# if GDISP_HARDWARE_PIXELREAD
2018-07-08 01:19:43 +00:00
LLDSPEC gColor gdisp_lld_get_pixel_color ( GDisplay * g ) {
2013-10-12 03:24:40 +00:00
winPriv * priv ;
2013-09-18 13:46:37 +00:00
COLORREF color ;
2013-02-18 07:29:08 +00:00
2013-10-12 03:24:40 +00:00
priv = g - > priv ;
WaitForSingleObject ( drawMutex , INFINITE ) ;
2013-02-18 07:29:08 +00:00
# if GDISP_NEED_CONTROL
2013-09-18 13:46:37 +00:00
switch ( g - > g . Orientation ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-10-12 03:24:40 +00:00
color = GetPixel ( priv - > dcBuffer , g - > p . x , g - > p . y ) ;
2013-06-02 08:57:22 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-10-12 03:24:40 +00:00
color = GetPixel ( priv - > dcBuffer , g - > p . y , g - > g . Width - 1 - g - > p . x ) ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-10-12 03:24:40 +00:00
color = GetPixel ( priv - > dcBuffer , g - > g . Width - 1 - g - > p . x , g - > g . Height - 1 - g - > p . y ) ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-10-12 03:24:40 +00:00
color = GetPixel ( priv - > dcBuffer , g - > g . Height - 1 - g - > p . y , g - > p . x ) ;
2013-02-18 07:29:08 +00:00
break ;
}
2013-09-18 13:46:37 +00:00
# else
2013-10-12 03:24:40 +00:00
color = GetPixel ( priv - > dcBuffer , g - > p . x , g - > p . y ) ;
2013-02-18 07:29:08 +00:00
# endif
2013-10-12 03:24:40 +00:00
ReleaseMutex ( drawMutex ) ;
2014-09-26 06:32:34 +00:00
2013-11-17 13:32:19 +00:00
return gdispNative2Color ( color ) ;
2013-02-18 07:29:08 +00:00
}
# endif
2013-09-18 13:46:37 +00:00
# if GDISP_NEED_SCROLL && GDISP_HARDWARE_SCROLL
2013-10-12 03:24:40 +00:00
LLDSPEC void gdisp_lld_vertical_scroll ( GDisplay * g ) {
winPriv * priv ;
2013-09-18 13:46:37 +00:00
RECT rect ;
2018-07-08 00:54:19 +00:00
gCoord lines ;
2014-09-26 06:32:34 +00:00
2013-10-12 03:24:40 +00:00
priv = g - > priv ;
2013-02-18 07:29:08 +00:00
# if GDISP_NEED_CONTROL
2013-10-24 06:53:07 +00:00
switch ( g - > g . Orientation ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2013-11-15 15:56:34 +00:00
default :
2013-09-18 13:46:37 +00:00
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 ;
2013-02-18 07:29:08 +00:00
goto vertical_scroll ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
goto horizontal_scroll ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2013-09-18 13:46:37 +00:00
rect . bottom = g - > g . Height - g - > p . y ;
rect . top = rect . bottom - g - > p . cy ;
2013-10-24 06:53:07 +00:00
rect . right = g - > g . Width - g - > p . x ;
2013-09-18 13:46:37 +00:00
rect . left = rect . right - g - > p . cx ;
lines = g - > p . y1 ;
2013-02-18 07:29:08 +00:00
vertical_scroll :
if ( lines > 0 ) {
2013-09-18 13:46:37 +00:00
rect . bottom - = lines ;
2013-02-18 07:29:08 +00:00
} else {
2013-09-18 13:46:37 +00:00
rect . top - = lines ;
}
if ( g - > p . cy > = lines & & g - > p . cy > = - lines ) {
2013-10-12 03:24:40 +00:00
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
2013-02-18 07:29:08 +00:00
}
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2013-09-24 06:10:15 +00:00
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 ;
2013-02-18 07:29:08 +00:00
horizontal_scroll :
if ( lines > 0 ) {
2013-09-18 13:46:37 +00:00
rect . right - = lines ;
2013-02-18 07:29:08 +00:00
} else {
2013-09-18 13:46:37 +00:00
rect . left - = lines ;
}
if ( g - > p . cy > = lines & & g - > p . cy > = - lines ) {
2013-10-12 03:24:40 +00:00
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
2013-02-18 07:29:08 +00:00
}
break ;
}
# else
2013-09-18 13:46:37 +00:00
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 ;
2013-02-18 07:29:08 +00:00
if ( lines > 0 ) {
2013-09-18 13:46:37 +00:00
rect . bottom - = lines ;
2013-02-18 07:29:08 +00:00
} else {
2013-09-18 13:46:37 +00:00
rect . top - = lines ;
}
if ( g - > p . cy > = lines & & g - > p . cy > = - lines ) {
2013-10-12 03:24:40 +00:00
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
2013-02-18 07:29:08 +00:00
}
# endif
}
# endif
2013-09-18 13:46:37 +00:00
# if GDISP_NEED_CONTROL && GDISP_HARDWARE_CONTROL
2013-10-12 03:24:40 +00:00
LLDSPEC void gdisp_lld_control ( GDisplay * g ) {
2013-09-18 13:46:37 +00:00
switch ( g - > p . x ) {
2013-02-18 07:29:08 +00:00
case GDISP_CONTROL_ORIENTATION :
2018-07-08 03:51:20 +00:00
if ( g - > g . Orientation = = ( gOrientation ) g - > p . ptr )
2013-02-18 07:29:08 +00:00
return ;
2018-07-08 03:51:20 +00:00
switch ( ( gOrientation ) g - > p . ptr ) {
case gOrientation0 :
case gOrientation180 :
2013-10-12 03:24:40 +00:00
g - > g . Width = GDISP_SCREEN_WIDTH ;
g - > g . Height = GDISP_SCREEN_HEIGHT ;
2013-02-18 07:29:08 +00:00
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
case gOrientation270 :
2013-10-12 03:24:40 +00:00
g - > g . Height = GDISP_SCREEN_WIDTH ;
g - > g . Width = GDISP_SCREEN_HEIGHT ;
2013-02-18 07:29:08 +00:00
break ;
default :
return ;
}
2018-07-08 03:51:20 +00:00
g - > g . Orientation = ( gOrientation ) g - > p . ptr ;
2013-02-18 07:29:08 +00:00
return ;
/*
case GDISP_CONTROL_POWER :
case GDISP_CONTROL_BACKLIGHT :
case GDISP_CONTROL_CONTRAST :
*/
}
}
# endif
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
2018-06-23 03:02:07 +00:00
static gBool Win32MouseInit ( GMouse * m , unsigned driverinstance ) {
2014-09-26 06:32:34 +00:00
( void ) m ;
( void ) driverinstance ;
2018-06-23 03:02:07 +00:00
return gTrue ;
2014-09-26 06:32:34 +00:00
}
2018-06-23 03:02:07 +00:00
static gBool Win32MouseRead ( GMouse * m , GMouseReading * pt ) {
2013-10-24 06:53:07 +00:00
GDisplay * g ;
winPriv * priv ;
2014-09-26 06:32:34 +00:00
g = m - > display ;
2013-10-24 06:53:07 +00:00
priv = g - > priv ;
2013-10-12 03:24:40 +00:00
2013-10-24 06:53:07 +00:00
pt - > x = priv - > mousex ;
2014-09-26 06:32:34 +00:00
pt - > y = priv - > mousey ;
pt - > z = ( priv - > mousebuttons & GINPUT_MOUSE_BTN_LEFT ) ? 1 : 0 ;
2013-10-24 06:53:07 +00:00
pt - > buttons = priv - > mousebuttons ;
2014-09-26 06:32:34 +00:00
# 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
2018-07-08 00:54:19 +00:00
gCoord t ;
2014-09-26 06:32:34 +00:00
switch ( gdispGGetOrientation ( m - > display ) ) {
2018-07-08 03:51:20 +00:00
case gOrientation0 :
2014-09-26 06:32:34 +00:00
default :
break ;
2018-07-08 03:51:20 +00:00
case gOrientation90 :
2014-09-26 06:32:34 +00:00
t = pt - > x ;
pt - > x = g - > g . Width - 1 - pt - > y ;
pt - > y = t ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation180 :
2014-09-26 06:32:34 +00:00
pt - > x = g - > g . Width - 1 - pt - > x ;
pt - > y = g - > g . Height - 1 - pt - > y ;
break ;
2018-07-08 03:51:20 +00:00
case gOrientation270 :
2014-09-26 06:32:34 +00:00
t = pt - > y ;
pt - > y = g - > g . Height - 1 - pt - > x ;
pt - > x = t ;
break ;
}
}
# endif
2014-11-07 02:02:41 +00:00
2018-06-23 03:02:07 +00:00
return gTrue ;
2013-02-18 07:29:08 +00:00
}
# endif /* GINPUT_NEED_MOUSE */
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD
2018-06-23 03:02:07 +00:00
static gBool Win32KeyboardInit ( GKeyboard * k , unsigned driverinstance ) {
2015-01-07 03:21:23 +00:00
( void ) driverinstance ;
// Only one please
if ( keyboard )
2018-06-23 03:02:07 +00:00
return gFalse ;
2015-01-07 03:21:23 +00:00
keyboard = k ;
2018-06-23 03:02:07 +00:00
return gTrue ;
2015-01-07 03:21:23 +00:00
}
2018-11-03 00:51:23 +00:00
static int Win32KeyboardGetData ( GKeyboard * k , gU8 * pch , int sz ) {
2015-01-07 03:21:23 +00:00
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
2016-10-01 08:11:12 +00:00
# if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
2015-02-13 23:16:28 +00:00
# if GINPUT_TOGGLE_CONFIG_ENTRIES > 1
# error "GDISP Win32: GINPUT_TOGGLE_CONFIG_ENTRIES must be 1 until Toggles can use GDriver"
2013-10-12 03:24:40 +00:00
# endif
2015-02-13 23:16:28 +00:00
const GToggleConfig GInputToggleConfigTable [ GINPUT_TOGGLE_CONFIG_ENTRIES ] ;
2013-10-12 03:24:40 +00:00
void ginput_lld_toggle_init ( const GToggleConfig * ptc ) {
// Save the associated window struct
2015-02-13 23:16:28 +00:00
//ptc->id = &GDISP_WIN32[ptc - GInputToggleConfigTable];
( ( GToggleConfig * ) ptc ) - > id = 0 ;
2013-10-12 03:24:40 +00:00
// We have 8 buttons per window.
2015-02-13 23:16:28 +00:00
( ( GToggleConfig * ) ptc ) - > mask = 0xFF ;
2013-10-12 03:24:40 +00:00
// No inverse or special mode
2015-02-13 23:16:28 +00:00
( ( GToggleConfig * ) ptc ) - > invert = 0x00 ;
( ( GToggleConfig * ) ptc ) - > mode = 0 ;
2013-10-12 03:24:40 +00:00
}
unsigned ginput_lld_toggle_getbits ( const GToggleConfig * ptc ) {
2015-02-13 23:16:28 +00:00
( void ) ptc ;
// This should use ID
if ( ! toggleWindow )
return 0 ;
return ( ( winPriv * ) toggleWindow - > priv ) - > toggles ;
//return ((winPriv *)((GDisplay *)(ptc->id))->priv)->toggles;
2013-10-12 03:24:40 +00:00
}
# endif /* GINPUT_NEED_TOGGLE */
2013-02-18 07:29:08 +00:00
# endif /* GFX_USE_GDISP */