1
1
Fork 0
mirror of https://github.com/QB64-Phoenix-Edition/QB64pe.git synced 2024-07-10 00:45:13 +00:00

Merge pull request #334 from mkilgore/fix-keyboard-input-windows

Fix keyboard _Device on Windows
This commit is contained in:
Matt Kilgore 2023-04-26 21:20:44 -04:00 committed by GitHub
commit 17b8fe4ac4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 517 additions and 66 deletions

View file

@ -34267,7 +34267,6 @@ void GLUT_KEYBOARD_FUNC(unsigned char key, int x, int y) {
void GLUT_KEYBOARDUP_FUNC(unsigned char key, int x, int y) { GLUT_key_ascii(key, 0); }
void GLUT_key_special(int32 key, int32 down) {
#ifdef QB64_GLUT
# ifndef CORE_FREEGLUT
/*
@ -39236,78 +39235,64 @@ void scancodeup(uint8 scancode) {
#define OS_EVENT_POST_PROCESSING 2
#define OS_EVENT_RETURN_IMMEDIATELY 3
static void reportKeyState(int code, int down) {
static device_struct *d;
d = &devices[1]; // keyboard
// don't add message if state already matches what we're reporting
if (getDeviceEventButtonValue(d, d->queued_events - 1, code) != down) {
int32 eventIndex = createDeviceEvent(d);
setDeviceEventButtonValue(d, eventIndex, code, down);
commitDeviceEvent(d);
}
}
#ifdef QB64_WINDOWS
// Windows only reports one WM_KEYUP event when both shift keys are held. To
// fix that somewhat we're manually check on each window message and reporting
// the keyup ourselves.
static void checkShiftKeys() {
static int rightShift = 0, leftShift = 0;
// GetAsyncKeyState() indicates the key state in the most significant bit
if (rightShift != !!(GetAsyncKeyState(VK_RSHIFT) & 0x8000)) {
rightShift = !rightShift;
reportKeyState(0x36, rightShift);
}
if (leftShift != !!(GetAsyncKeyState(VK_LSHIFT) & 0x8000)) {
leftShift = !leftShift;
reportKeyState(0x2A, leftShift);
}
}
extern "C" LRESULT qb64_os_event_windows(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, int *qb64_os_event_info) {
if (*qb64_os_event_info == OS_EVENT_PRE_PROCESSING) {
// example usage
/*
if (uMsg==WM_CLOSE){
alert("goodbye");
*qb64_os_event_info=OS_EVENT_RETURN_IMMEDIATELY;
if (func__hasfocus())
checkShiftKeys();
if (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN) {
if (device_last) { // core devices required?
/*
16-23 The scan code. The value depends on the OEM.
24 Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key
keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
*/
uint32_t code = (lParam >> 16) & 0x1FF;
reportKeyState(code, 1);
}
*/
if (uMsg == WM_KEYDOWN) {
}
if (uMsg == WM_KEYUP || uMsg == WM_SYSKEYUP) {
if (device_last) { // core devices required?
uint32_t code = (lParam >> 16) & 0x1FF;
/*
16-23 The scan code. The value depends on the OEM.
24 Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key
keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
*/
static int32 code, special;
special = 0; // set to 2 for keys which we cannot detect a release for
code = (lParam >> 16) & 511;
keydown_special:
static device_struct *d;
d = &devices[1]; // keyboard
if (getDeviceEventButtonValue(d, d->queued_events - 1, code) != 1) { // don't add message if already on
int32 eventIndex = createDeviceEvent(d);
setDeviceEventButtonValue(d, eventIndex, code, 1);
if (special == 2) {
special = 1;
commitDeviceEvent(d);
goto keydown_special;
} // jump to ~5 lines above to add a 2nd key event
if (special == 1)
setDeviceEventButtonValue(d, eventIndex, code, 0);
commitDeviceEvent(d);
} // not 1
} // core devices required
} // WM_KEYDOWN
if (uMsg == WM_KEYUP) {
if (device_last) { // core devices required?
/*
16-23 The scan code. The value depends on the OEM.
24 Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key
keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
*/
static int32 code;
code = (lParam >> 16) & 511;
static device_struct *d;
d = &devices[1]; // keyboard
if (getDeviceEventButtonValue(d, d->queued_events - 1, code) != 0) { // don't add message if already off
int32 eventIndex = createDeviceEvent(d);
setDeviceEventButtonValue(d, eventIndex, code, 0);
commitDeviceEvent(d);
} // not 1
} // core devices required
} // WM_KEYUP
reportKeyState(code, 0);
}
}
}
if (*qb64_os_event_info == OS_EVENT_POST_PROCESSING) {
}

View file

@ -0,0 +1,187 @@
$Console
_Dest _Console
ChDir _StartDir$
$IF LNX THEN
'$include:'keyconsts.bi'
'$include:'sendinput.bi'
Dim Shared testCount As Long
deviceCount& = _Devices
AssertPress EscScanCode
AssertPress EnterScancode
AssertPress TabScancode
AssertPress OneScancode
AssertPress AScanCode
AssertPress WScanCode
AssertPress SpaceScanCode
AssertPress PgUpScanCode
AssertPress PgDownScanCode
AssertPress HomeScanCode
AssertPress InsertScanCode
AssertPress DeleteScanCode
AssertPress EndScanCode
AssertPress LCtrlScancode
AssertPress LShiftScancode
AssertPress LAltScancode
AssertPress RCtrlScancode
AssertPress RShiftScancode
AssertPress RAltScancode
AssertPress NumLockScancode
AssertPress ScrollLockScancode
AssertPress KeypadUpScancode
AssertPress F1Scancode
AssertPress F2Scancode
AssertPress F3Scancode
AssertPress F4Scancode
AssertPress F5Scancode
AssertPress F6Scancode
AssertPress F7Scancode
AssertPress F8Scancode
AssertPress F9Scancode
AssertPress F10Scancode
AssertPress F11Scancode
AssertPress F12Scancode
' Test multiple keys at the same time
' Modifiers in paticular are important to test
emulateScancode LShiftScancode, Down
emulateScancode LCtrlScancode, Down
emulateScancode LAltScancode, Down
emulateScancode AScanCode, Down
AssertDown LShiftScancode
AssertDown LCtrlScancode
AssertDown LAltScancode
AssertDown AScanCode
' These keys are released in same order they were pressed
emulateScancode LShiftScancode, Up
AssertUp LShiftScancode
emulateScancode LCtrlScancode, Up
AssertUp LCtrlScancode
emulateScancode LAltScancode, Up
AssertUp LAltScancode
emulateScancode AScanCode, Up
AssertUp AScanCode
' Same test, but release keys in opposite order they were pressed
emulateScancode LShiftScancode, Down
emulateScancode LCtrlScancode, Down
emulateScancode LAltScancode, Down
emulateScancode AScanCode, Down
AssertDown LShiftScancode
AssertDown LCtrlScancode
AssertDown LAltScancode
AssertDown AScanCode
emulateScancode AScanCode, Up
AssertUp AScanCode
emulateScancode LAltScancode, Up
AssertUp LAltScancode
emulateScancode LCtrlScancode, Up
AssertUp LCtrlScancode
emulateScancode LShiftScancode, Up
AssertUp LShiftScancode
' Test holding and releasing both left/right modifiers
' Shift
emulateScancode LShiftScancode, Down
AssertDown LShiftScancode
emulateScancode RShiftScancode, Down
AssertDown RShiftScancode
emulateScancode LShiftScancode, Up
AssertUp LShiftScancode
emulateScancode RShiftScancode, Up
AssertUp RShiftScancode
' Control
emulateScancode LCtrlScancode, Down
AssertDown LCtrlScancode
emulateScancode RCtrlScancode, Down
AssertDown RCtrlScancode
emulateScancode LCtrlScancode, Up
AssertUp LCtrlScancode
emulateScancode RCtrlScancode, Up
AssertUp RCtrlScancode
' Alt
emulateScancode LAltScancode, Down
AssertDown LAltScancode
emulateScancode RAltScancode, Down
AssertDown RAltScancode
emulateScancode LAltScancode, Up
AssertUp LAltScancode
emulateScancode RAltScancode, Up
AssertUp RAltScancode
System
'$include:'sendinput.bm'
' Convert scan code into the device button number
Function GetDeviceCode&(scan As Long)
Dim deviceCode As Long
' "Extended" keys will have the 9th bit set, so add 256
deviceCode = (scan And &H7FFF) + 1
If scan And &H8000 Then deviceCode = deviceCode + 256
GetDeviceCode& = deviceCode
End Function
Sub AssertPress(scan As Long)
testCount = testCount + 1
emulateScancode scan, Down
AssertDown scan
emulateScancode scan, Up
AssertUp scan
End Sub
Sub AssertDown(scan As Long)
testCount = testCount + 1
deviceCode = GetDeviceCode&(scan)
While _DeviceInput(1): Wend
Print "Test button down:"; testCount; ": ";
If _Button(deviceCode) Then Print "PASS!" Else Print "FAIL! Key="; scan And &H7FFF; ", state="; _Button(deviceCode)
End Sub
Sub AssertUp(scan As Long)
testCount = testCount + 1
deviceCode = GetDeviceCode&(scan)
While _DeviceInput(1): Wend
Print "Test button up :"; testCount; ": ";
If Not _Button(deviceCode) Then Print "PASS!" Else Print "FAIL! Key="; scan And &H7FFF; ", state="; _Button(deviceCode)
End Sub
$Else
' Not supported for other platforms at the moment, output is simulated
Open "devices_windows.output" For Input As #1
While Not Eof(1)
Line Input #1, l$
Print l$
Wend
System
$End If

View file

@ -0,0 +1,96 @@
Test button down: 2 : PASS!
Test button up : 3 : PASS!
Test button down: 5 : PASS!
Test button up : 6 : PASS!
Test button down: 8 : PASS!
Test button up : 9 : PASS!
Test button down: 11 : PASS!
Test button up : 12 : PASS!
Test button down: 14 : PASS!
Test button up : 15 : PASS!
Test button down: 17 : PASS!
Test button up : 18 : PASS!
Test button down: 20 : PASS!
Test button up : 21 : PASS!
Test button down: 23 : PASS!
Test button up : 24 : PASS!
Test button down: 26 : PASS!
Test button up : 27 : PASS!
Test button down: 29 : PASS!
Test button up : 30 : PASS!
Test button down: 32 : PASS!
Test button up : 33 : PASS!
Test button down: 35 : PASS!
Test button up : 36 : PASS!
Test button down: 38 : PASS!
Test button up : 39 : PASS!
Test button down: 41 : PASS!
Test button up : 42 : PASS!
Test button down: 44 : PASS!
Test button up : 45 : PASS!
Test button down: 47 : PASS!
Test button up : 48 : PASS!
Test button down: 50 : PASS!
Test button up : 51 : PASS!
Test button down: 53 : PASS!
Test button up : 54 : PASS!
Test button down: 56 : PASS!
Test button up : 57 : PASS!
Test button down: 59 : PASS!
Test button up : 60 : PASS!
Test button down: 62 : PASS!
Test button up : 63 : PASS!
Test button down: 65 : PASS!
Test button up : 66 : PASS!
Test button down: 68 : PASS!
Test button up : 69 : PASS!
Test button down: 71 : PASS!
Test button up : 72 : PASS!
Test button down: 74 : PASS!
Test button up : 75 : PASS!
Test button down: 77 : PASS!
Test button up : 78 : PASS!
Test button down: 80 : PASS!
Test button up : 81 : PASS!
Test button down: 83 : PASS!
Test button up : 84 : PASS!
Test button down: 86 : PASS!
Test button up : 87 : PASS!
Test button down: 89 : PASS!
Test button up : 90 : PASS!
Test button down: 92 : PASS!
Test button up : 93 : PASS!
Test button down: 95 : PASS!
Test button up : 96 : PASS!
Test button down: 98 : PASS!
Test button up : 99 : PASS!
Test button down: 101 : PASS!
Test button up : 102 : PASS!
Test button down: 103 : PASS!
Test button down: 104 : PASS!
Test button down: 105 : PASS!
Test button down: 106 : PASS!
Test button up : 107 : PASS!
Test button up : 108 : PASS!
Test button up : 109 : PASS!
Test button up : 110 : PASS!
Test button down: 111 : PASS!
Test button down: 112 : PASS!
Test button down: 113 : PASS!
Test button down: 114 : PASS!
Test button up : 115 : PASS!
Test button up : 116 : PASS!
Test button up : 117 : PASS!
Test button up : 118 : PASS!
Test button down: 119 : PASS!
Test button down: 120 : PASS!
Test button up : 121 : PASS!
Test button up : 122 : PASS!
Test button down: 123 : PASS!
Test button down: 124 : PASS!
Test button up : 125 : PASS!
Test button up : 126 : PASS!
Test button down: 127 : PASS!
Test button down: 128 : PASS!
Test button up : 129 : PASS!
Test button up : 130 : PASS!

View file

@ -0,0 +1,126 @@
' _KEYDOWN Keyboard Values
'
'Esc F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 Sys ScL Pause
' 27 15104 15360 15616 15872 16128 16384 16640 16896 17152 17408 34048 34304 +316 +302 +019
'`~ 1! 2@ 3# 4$ 5% 6^ 7& 8* 9( 0) -_ =+ BkSp Ins Hme PUp NumL / * -
'126 33 64 35 36 37 94 38 42 40 41 95 43 8 20992 18176 18688 +300 47 42 45
' 96 49 50 51 52 53 54 55 56 57 48 45 61
'Tab Q W E R T Y U I O P [{ ]} \| Del End PDn 7Hme 8/^ 9PU +
' 9 81 87 69 82 84 89 85 73 79 80 123 125 124 21248 20224 20736 18176 18432 18688 43
' 113 119 101 114 116 121 117 105 111 112 91 93 92 55 56 57
'CapL A S D F G H J K L ;: '" Enter 4/<- 5 6/->
'+301 65 83 68 70 71 72 74 75 76 58 34 13 19200 19456 19712 E
' 97 115 100 102 103 104 106 107 108 59 39 52 53 54 n
'Shift Z X C V B N M ,< .> /? Shift ^ 1End 2/V 3PD t
'+304 90 88 67 86 66 78 77 60 62 63 +303 18432 20224 20480 20736 e
' 122 120 99 118 98 110 109 44 46 47 49 50 51 r
'Ctrl Win Alt Spacebar Alt Win Menu Ctrl <- V -> 0Ins .Del
'+306 +311 +308 32 +307 +312 +319 +305 19200 20480 19712 20992 21248 13
' 48 46
'
' Lower value = LCase/NumLock On __________________ + = add 100000
CONST KEY_TAB = 9
CONST KEY_ENTER = 13
CONST KEY_EXCLAIM = 33
CONST KEY_ONE = 49
CONST KEY_F1 = 15104
CONST KEY_F10 = 17408
CONST KEY_SHIFT = 16
CONST KEY_CTRL = 17
CONST KEY_ALT = 18
CONST KEY_PAUSE& = 100019
CONST KEY_NUMLOCK& = 100300
CONST KEY_CAPSLOCK& = 100301
CONST KEY_SCROLLOCK& = 100302
CONST KEY_RSHIFT& = 100303
CONST KEY_LSHIFT& = 100304
CONST KEY_RCTRL& = 100305
CONST KEY_LCTRL& = 100306
CONST KEY_RALT& = 100307
CONST KEY_LALT& = 100308
CONST KEY_RMETA& = 100309 'Left 'Apple' key (macOS)
CONST KEY_LMETA& = 100310 'Right 'Apple' key (macOS)
CONST KEY_LSUPER& = 100311 'Left "Windows" key
CONST KEY_RSUPER& = 100312 'Right "Windows"key
CONST KEY_MODE& = 100313 '"AltGr" key
CONST KEY_COMPOSE& = 100314
CONST KEY_HELP& = 100315
CONST KEY_PRINT& = 100316
CONST KEY_SYSREQ& = 100317
CONST KEY_BREAK& = 100318
CONST KEY_MENU& = 100319
CONST KEY_POWER& = 100320
CONST KEY_EURO& = 100321
CONST KEY_UNDO& = 100322
CONST KEY_KP0& = 100256
CONST KEY_KP1& = 100257
CONST KEY_KP2& = 100258
CONST KEY_KP3& = 100259
CONST KEY_KP4& = 100260
CONST KEY_KP5& = 100261
CONST KEY_KP6& = 100262
CONST KEY_KP7& = 100263
CONST KEY_KP8& = 100264
CONST KEY_KP9& = 100265
CONST KEY_KP_PERIOD& = 100266
CONST KEY_KP_DIVIDE& = 100267
CONST KEY_KP_MULTIPLY& = 100268
CONST KEY_KP_MINUS& = 100269
CONST KEY_KP_PLUS& = 100270
CONST KEY_KP_ENTER& = 100271
CONST KEY_KP_INSERT& = 200000
CONST KEY_KP_END& = 200001
CONST KEY_KP_DOWN& = 200002
CONST KEY_KP_PAGE_DOWN& = 200003
CONST KEY_KP_LEFT& = 200004
CONST KEY_KP_MIDDLE& = 200005
CONST KEY_KP_RIGHT& = 200006
CONST KEY_KP_HOME& = 200007
CONST KEY_KP_UP& = 200008
CONST KEY_KP_PAGE_UP& = 200009
CONST KEY_KP_DELETE& = 200010
CONST KEY_SCROLL_LOCK_MODE& = 200011
CONST KEY_INSERT_MODE& = 200012
Const EscScanCode = &H01
Const EnterScancode = &H1C
Const TabScancode = &H0F
Const OneScancode = &H02
Const AScanCode = &H1E ' A key
Const WScanCode = &H11
Const SpaceScanCode = &H39
Const PgUpScanCode = &H49 Or &H8000
Const PgDownScanCode = &H51 Or &H8000
Const HomeScanCode = &H47 Or &H8000
Const InsertScanCode = &H52 Or &H8000
Const DeleteScanCode = &H53 Or &H8000
Const EndScanCode = &H4F Or &H8000
Const LCtrlScancode = &H1D
Const LShiftScancode = &H2A
Const LAltScancode = &H38
Const RCtrlScancode = &H1D Or &H8000 ' Extended
Const RShiftScancode = &H36
Const RAltScancode = &H38 Or &H8000
Const NumLockScancode = &H45
Const ScrollLockScancode = &H45
Const KeypadUpScancode = &H48
Const F1Scancode = &H3B
Const F2Scancode = &H3C
Const F3Scancode = &H3D
Const F4Scancode = &H3E
Const F5Scancode = &H3F
Const F6Scancode = &H40
Const F7Scancode = &H41
Const F8Scancode = &H42
Const F9Scancode = &H43
Const F10Scancode = &H44
Const F11Scancode = &H57
Const F12Scancode = &H58

View file

@ -0,0 +1,28 @@
Const INPUT_TYPE_KEYBOARD = 1
Const KBD_FLAG_EXTENDED = 1
Const KBD_FLAG_UP = 2
Const KBD_FLAG_UNICODE = 4
Const KBD_FLAG_SCANCODE = 8
Const Down = 1
Const Up = 0
Type KbdInput
typ As Long
pad As Long
vk As Integer
scancode As Integer
flags As _Unsigned Long
tim As _Unsigned Long
pad2 As Long
extraInfo As _Offset
padding As String * 8
End Type
Declare CustomType Library
Function SendInput~&(ByVal inputCount As _Unsigned Long, ByVal inputArray As _Offset, ByVal inputTypeSize As _Unsigned Long)
Function GetLastError&()
End Declare

View file

@ -0,0 +1,29 @@
Sub emulateScancode(scancode As Integer, isDown As Long)
Dim kbd As KbdInput
kbd.typ = INPUT_TYPE_KEYBOARD
kbd.scancode = scancode And &H7FFF ' Strip off extended flag
kbd.flags = KBD_FLAG_SCANCODE
If isDown = 0 Then kbd.flags = kbd.flags Or KBD_FLAG_UP
If scancode And &H8000 Then kbd.flags = kbd.flags Or KBD_FLAG_EXTENDED
e& = SendInput~&(1, _Offset(kbd), LEN(kbd))
If e& <> 1 Then Print "ERROR: e:"; e&; ", GetLastError:"; GetLastError
_Delay .05
End Sub
Sub emulateVirtualKey(vk As Integer, isDown As Long)
Dim kbd As KbdInput
kbd.typ = INPUT_TYPE_KEYBOARD
kbd.vk = vk
If isDown = 0 Then kbd.flags = kbd.flags Or KBD_FLAG_UP
e& = SendInput~&(1, _Offset(kbd), LEN(kbd))
If e& <> 1 Then Print "ERROR: e:"; e&; ", GetLastError:"; GetLastError
_Delay .05
End Sub