Author Topic: Programmable Keyboard Input  (Read 4573 times)

0 Members and 1 Guest are viewing this topic.

This topic contains a post which is marked as Best Answer. Press here if you would like to see it.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Programmable Keyboard Input
« on: December 29, 2019, 12:06:32 am »
As you guys probably know from my posts in the last few days, I haven't been very happy with the performance of QB64's input routines.  None of them seem to work 100% as they should -- _KEYHIT, INKEY$, _DEVICES, INP(&H60)...

I was working up a patch for the problem, but then Tempodi asked a rather poignant question: "Will this patch work for other keyboards, or just yours?"

And, to be honest, I don't really know.  I've got several PCs around here, but I'm a 100% English speaking idiot...  None of my keyboards support extra characters, or international letters, or AltGr keys, or anything all fancy pancy like that...

So, I thought about it for a moment, and then I decided, "What we really need is a command similar to _MAPUNICODE to use with keyboard input, and not just displaying fonts properly on the screen."

And thus, I've came up with this little concept (which is still a work-in-progress, but since I'm going to bed here in a few moments, I thought I'd go ahead and share to see if anybody notices any issues with the process):

Code: QB64: [Select]
  1. DECLARE LIBRARY 'function is already used by QB64 so "User32" is not required
  2.     FUNCTION GetKeyState% (BYVAL vkey AS LONG)
  3.  
  4.  
  5. TYPE KeyboardInfo_Type
  6.     Index AS LONG
  7.     KeyCodeReturn AS LONG
  8.     ASCII AS STRING
  9.     Modifiers AS LONG
  10.     Repeat AS _FLOAT
  11.     LastHit AS _FLOAT
  12.     Down AS INTEGER
  13. DIM SHARED Keys(1000) AS KeyboardInfo_Type
  14. CONST NONE = 0, KEY_CTRL = 1, KEY_SHIFT = 2, KEY_ALT = 4, ALTGR = 8, CASECHANGE = 16, TOGGLE = 32
  15.  
  16. l = -128
  17.  
  18. SetNextKey 1, 100001, "LMB", NONE, 0.2 'Left Mouse Button
  19. SetNextKey 2, 100002, "RMB", NONE, 0.2 'Right Mouse Button
  20. SetNextKey 3, 900001, "CANCEL", NONE, 0.2 'VK_Cancel
  21. SetNextKey 4, 100003, "MMB", NONE, 0.2 'Middle Mouse Button
  22. SetNextKey 5, 100004, "MB4", NONE, 0.2 'Mouse Button 4
  23. SetNextKey 6, 100005, "MB5", NONE, 0.2 'Mouse Button 5
  24. SetNextKey 7, 0, "UNDEFINED", NONE, 0 'Undefined
  25. SetNextKey 8, 8, CHR$(8), NONE, 0.2 'BackSpace
  26. SetNextKey 9, 9, CHR$(9), NONE, 0.2 'Tab
  27. SetNextKey 10, 0, "RESERVED", NONE, 0 'Reserved
  28. SetNextKey 11, 0, "RESERVED", NONE, 0 'Reserved
  29. SetNextKey 12, 900002, "CLEAR", NONE, 0.2 'Clear
  30. SetNextKey 13, 13, CHR$(13), NONE, 0.2 'Enter
  31. SetNextKey 14, 0, "UNDEFINED", NONE, 0 'Undefined
  32. SetNextKey 15, 0, "UNDEFINED", NONE, 0 'Undefined
  33. SetNextKey 16, 100016, "SHIFT", TOGGLE, 0 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  34. SetNextKey 17, 100017, "CTRL", TOGGLE, 0 'Ctrl   (Same)
  35. SetNextKey 18, 100018, "ALT", TOGGLE, 0 'Alt     (Same)
  36. SetNextKey 19, 100019, "PAUSE", NONE, 0 'Pause
  37. SetNextKey 20, 100301, "CAPS", TOGGLE, 0 'Caps Lock
  38. SetNextKey 21, 900021, "VK_HANGUL", NONE, 0 'VK_Hangul
  39. SetNextKey 22, 0, "UNDEFINED", NONE, 0 'Undefined
  40. SetNextKey 23, 900023, "VK_JUNJA", NONE, 0 'VK_Junja
  41. SetNextKey 24, 900024, "VK_FINAL", NONE, 0 'VK_Final
  42. SetNextKey 25, 900026, "VK_HANJA/VK_KANJI", NONE, 0 'VK_HANGA and VK_Kanji
  43. SetNextKey 26, 0, "UNDEFINED", NONE, 0 'Undefined
  44. SetNextKey 27, 27, CHR$(27), NONE, 0.2 'ESC
  45. SetNextKey 28, 900028, "VK_CONVERT", NONE, 0 'VK_Convert
  46. SetNextKey 29, 900029, "VK_NONCONVERT", NONE, 0 'VK_NonConvery
  47. SetNextKey 30, 900030, "VK_ACCEPT", NONE, 0 'VK_Accept
  48. SetNextKey 31, 900031, "VK_MODECHANGE", NONE, 0 'VK_ModeChange
  49. SetNextKey 32, 32, " ", NONE, 0.2 'Space
  50. SetNextKey 33, 18688, CHR$(0) + CHR$(73), NONE, 0.2 'Page Up
  51. SetNextKey 34, 20736, CHR$(0) + CHR$(81), NONE, 0.2 'Page Down
  52. SetNextKey 35, 20224, CHR$(0) + CHR$(79), NONE, 0.2 'END
  53. SetNextKey 36, 18176, CHR$(0) + CHR$(71), NONE, 0.2 'HOME
  54. SetNextKey 37, 19200, CHR$(0) + CHR$(75), NONE, 0.2 'Left Arrow
  55. SetNextKey 38, 18432, CHR$(0) + CHR$(72), NONE, 0.2 'Up Arrow
  56. SetNextKey 39, 19712, CHR$(0) + CHR$(77), NONE, 0.2 'Right Arrow
  57. SetNextKey 40, 20480, CHR$(0) + CHR$(80), NONE, 0.2 'Down Arrow
  58. SetNextKey 41, 900041, "VK_SELECT", NONE, 0 'VK_SELECT
  59. SetNextKey 42, 900042, "VK_PRINT", NONE, 0 'VK_PRINT
  60. SetNextKey 43, 900043, "VK_EXECUTE", NONE, 0 'VK_EXECUTE
  61. SetNextKey 44, 900044, "VK_SNAPSHOT", NONE, 0 'VK_SNAPSHOT
  62. SetNextKey 45, 20992, CHR$(0) + CHR$(82), NONE, 0 'INS
  63. SetNextKey 46, 21248, CHR$(0) + CHR$(83), NONE, 0 'DEL
  64. SetNextKey 47, 900047, "VK_HELP", NONE, 0 'VK_HELP
  65.  
  66.  
  67. SetNextKey 48, 48, "0", NONE, 0.2 '0
  68. SetNextKey 49, 49, "1", NONE, 0.2 '1
  69. SetNextKey 50, 50, "2", NONE, 0.2 '2
  70. SetNextKey 51, 51, "3", NONE, 0.2 '3
  71. SetNextKey 52, 52, "4", NONE, 0.2 '4
  72. SetNextKey 53, 53, "5", NONE, 0.2 '5
  73. SetNextKey 54, 54, "6", NONE, 0.2 '6
  74. SetNextKey 55, 55, "7", NONE, 0.2 '7
  75. SetNextKey 56, 56, "8", NONE, 0.2 '8
  76. SetNextKey 57, 57, "9", NONE, 0.2 '9
  77.  
  78. SetNextKey 48, 41, ")", KEY_SHIFT, 0.2 '0
  79. SetNextKey 49, 33, "!", KEY_SHIFT, 0.2 '1
  80. SetNextKey 50, 64, "@", KEY_SHIFT, 0.2 '2
  81. SetNextKey 51, 35, "#", KEY_SHIFT, 0.2 '3
  82. SetNextKey 52, 36, "$", KEY_SHIFT, 0.2 '4
  83. SetNextKey 53, 37, "%", KEY_SHIFT, 0.2 '5
  84. SetNextKey 54, 94, "^", KEY_SHIFT, 0.2 '6
  85. SetNextKey 55, 38, "&", KEY_SHIFT, 0.2 '7
  86. SetNextKey 56, 42, "*", KEY_SHIFT, 0.2 '8
  87. SetNextKey 57, 40, "(", KEY_SHIFT, 0.2 '9
  88.  
  89. SetNextKey 58, 0, "UNDEFINED", NONE, 0 'Undefined
  90. SetNextKey 59, 0, "UNDEFINED", NONE, 0 'Undefined
  91. SetNextKey 60, 0, "UNDEFINED", NONE, 0 'Undefined
  92. SetNextKey 61, 0, "UNDEFINED", NONE, 0 'Undefined
  93. SetNextKey 62, 0, "UNDEFINED", NONE, 0 'Undefined
  94. SetNextKey 63, 0, "UNDEFINED", NONE, 0 'Undefined
  95. SetNextKey 64, 0, "UNDEFINED", NONE, 0 'Undefined
  96.  
  97. SetNextKey 65, 65, "A", CASECHANGE + KEY_SHIFT, 0.2 'A
  98. SetNextKey 66, 66, "B", CASECHANGE + KEY_SHIFT, 0.2 'B
  99. SetNextKey 67, 67, "C", CASECHANGE + KEY_SHIFT, 0.2 'C
  100. SetNextKey 68, 68, "D", CASECHANGE + KEY_SHIFT, 0.2 'D
  101. SetNextKey 69, 69, "E", CASECHANGE + KEY_SHIFT, 0.2 'E
  102. SetNextKey 70, 70, "F", CASECHANGE + KEY_SHIFT, 0.2 'F
  103. SetNextKey 71, 71, "G", CASECHANGE + KEY_SHIFT, 0.2 'G
  104. SetNextKey 72, 72, "H", CASECHANGE + KEY_SHIFT, 0.2 'H
  105. SetNextKey 73, 73, "I", CASECHANGE + KEY_SHIFT, 0.2 'I
  106. SetNextKey 74, 74, "J", CASECHANGE + KEY_SHIFT, 0.2 'J
  107. SetNextKey 75, 75, "K", CASECHANGE + KEY_SHIFT, 0.2 'K
  108. SetNextKey 76, 76, "L", CASECHANGE + KEY_SHIFT, 0.2 'L
  109. SetNextKey 77, 77, "M", CASECHANGE + KEY_SHIFT, 0.2 'M
  110. SetNextKey 78, 78, "N", CASECHANGE + KEY_SHIFT, 0.2 'N
  111. SetNextKey 79, 79, "O", CASECHANGE + KEY_SHIFT, 0.2 'O
  112. SetNextKey 80, 80, "P", CASECHANGE + KEY_SHIFT, 0.2 'P
  113. SetNextKey 81, 81, "Q", CASECHANGE + KEY_SHIFT, 0.2 'Q
  114. SetNextKey 82, 82, "R", CASECHANGE + KEY_SHIFT, 0.2 'R
  115. SetNextKey 83, 83, "S", CASECHANGE + KEY_SHIFT, 0.2 'S
  116. SetNextKey 84, 84, "T", CASECHANGE + KEY_SHIFT, 0.2 'T
  117. SetNextKey 81, 85, "U", CASECHANGE + KEY_SHIFT, 0.2 'U
  118. SetNextKey 81, 86, "V", CASECHANGE + KEY_SHIFT, 0.2 'V
  119. SetNextKey 82, 87, "W", CASECHANGE + KEY_SHIFT, 0.2 'W
  120. SetNextKey 83, 88, "X", CASECHANGE + KEY_SHIFT, 0.2 'X
  121. SetNextKey 84, 89, "Y", CASECHANGE + KEY_SHIFT, 0.2 'Y
  122. SetNextKey 81, 90, "Z", CASECHANGE + KEY_SHIFT, 0.2 'Z
  123.  
  124. SetNextKey 65, 97, "a", CASECHANGE, 0.2 'a
  125. SetNextKey 66, 98, "b", CASECHANGE, 0.2 'b
  126. SetNextKey 67, 99, "c", CASECHANGE, 0.2 'c
  127. SetNextKey 68, 100, "d", CASECHANGE, 0.2 'd
  128. SetNextKey 69, 101, "e", CASECHANGE, 0.2 'e
  129. SetNextKey 70, 102, "f", CASECHANGE, 0.2 'f
  130. SetNextKey 71, 103, "g", CASECHANGE, 0.2 'g
  131. SetNextKey 72, 104, "h", CASECHANGE, 0.2 'h
  132. SetNextKey 73, 105, "i", CASECHANGE, 0.2 'i
  133. SetNextKey 74, 106, "j", CASECHANGE, 0.2 'j
  134. SetNextKey 75, 107, "k", CASECHANGE, 0.2 'k
  135. SetNextKey 76, 108, "l", CASECHANGE, 0.2 'l
  136. SetNextKey 77, 109, "m", CASECHANGE, 0.2 'm
  137. SetNextKey 78, 110, "n", CASECHANGE, 0.2 'n
  138. SetNextKey 79, 111, "o", CASECHANGE, 0.2 'o
  139. SetNextKey 80, 112, "p", CASECHANGE, 0.2 'p
  140. SetNextKey 81, 113, "q", CASECHANGE, 0.2 'q
  141. SetNextKey 82, 114, "r", CASECHANGE, 0.2 'r
  142. SetNextKey 83, 115, "s", CASECHANGE, 0.2 's
  143. SetNextKey 84, 116, "t", CASECHANGE, 0.2 't
  144. SetNextKey 81, 117, "u", CASECHANGE, 0.2 'u
  145. SetNextKey 81, 118, "v", CASECHANGE, 0.2 'v
  146. SetNextKey 82, 119, "w", CASECHANGE, 0.2 'w
  147. SetNextKey 83, 120, "x", CASECHANGE, 0.2 'x
  148. SetNextKey 84, 121, "y", CASECHANGE, 0.2 'y
  149. SetNextKey 81, 122, "z", CASECHANGE, 0.2 'z
  150.  
  151.  
  152. COLOR 15, 2
  153.     k = GetKeyHit(s$)
  154.     IF k <> 0 THEN PRINT k, s$
  155.  
  156.     _LIMIT 30
  157.  
  158.  
  159. FUNCTION GetKeyHit (s$)
  160.         FOR i = 0 TO 1000
  161.             SELECT CASE Keys(i).Index
  162.                 CASE 0: r = 0
  163.                 CASE ELSE: r = GetKeyState(Keys(i).Index)
  164.             END SELECT
  165.  
  166.             IF r AND &H8000 THEN 'the key is down
  167.  
  168.                 IF Keys(16).Down THEN CaseShift = -1 ELSE CaseShift = 0
  169.                 IF Keys(i).Modifiers AND CASECHANGE THEN
  170.                     IF _CAPSLOCK THEN CaseShift = NOT CaseShift
  171.                 END IF
  172.  
  173.                 IF Keys(i).Down = 0 THEN
  174.                     IF CaseShift = 0 THEN 'If shift is down
  175.                         IF (Keys(i).Modifiers AND KEY_SHIFT) = 0 THEN 'and we have a shift-modifer for out key
  176.                             GetKeyHit = Keys(i).KeyCodeReturn 'return it's value
  177.                             s$ = Keys(i).ASCII
  178.                             Keys(i).Down = -1
  179.                             Keys(i).LastHit = TIMER + Keys(i).Repeat
  180.                         END IF
  181.                     ELSE 'shift is up
  182.                         IF (Keys(i).Modifiers AND KEY_SHIFT) THEN
  183.                             GetKeyHit = Keys(i).KeyCodeReturn
  184.                             s$ = Keys(i).ASCII
  185.                             Keys(i).Down = -1
  186.                             Keys(i).LastHit = TIMER + Keys(i).Repeat
  187.                         END IF
  188.                     END IF
  189.  
  190.                 ELSE
  191.                     'if the key is already down, we check to see if the repeat time has passed and then repeat the down call
  192.                     IF TIMER <= Keys(i).LastHit THEN
  193.                         GetKeyHit = 0
  194.                     ELSE
  195.                         IF (Keys(i).Modifiers AND TOGGLE) = 0 THEN Keys(i).Down = 0
  196.                     END IF
  197.                 END IF
  198.             ELSE
  199.                 IF Keys(i).Down THEN
  200.                     GetKeyHit = -Keys(i).KeyCodeReturn
  201.                     Keys(i).Down = 0
  202.                     Keys(i).LastHit = 0
  203.                 END IF
  204.             END IF
  205.         NEXT
  206.  
  207.     END IF
  208.  
  209.  
  210. SUB SetNextKey (Index AS LONG, KeyCodeReturn AS LONG, ASCII AS STRING, Modifiers AS LONG, Repeat AS _FLOAT)
  211.     STATIC Which AS INTEGER
  212.     Which = Which + 1
  213.     Keys(Which).Index = Index
  214.     Keys(Which).KeyCodeReturn = KeyCodeReturn
  215.     Keys(Which).ASCII = ASCII
  216.     Keys(Which).Modifiers = Modifiers
  217.     Keys(Which).Repeat = Repeat
  218.     Keys(Which).LastHit = 0
  219.  
  220. SUB SetKey (Which AS LONG, Index AS LONG, KeyCodeReturn AS LONG, ASCII AS STRING, Modifiers AS LONG, Repeat AS _FLOAT)
  221.     Keys(Which).Index = Index
  222.     Keys(Which).KeyCodeReturn = KeyCodeReturn
  223.     Keys(Which).ASCII = ASCII
  224.     Keys(Which).Modifiers = Modifiers
  225.     Keys(Which).Repeat = Repeat
  226.  

This skips every QB64 key command completely and goes directly back to the source for our input handling: GetKeyState from the windows library.  Using this command, I can get any keystate that Windows recognizes from my keyboard (and anyone else's keyboard, that is hooked up, for that matter) -- and it recognizes a TON of keys which none of our current input methods handle.

The list of keys which the routine can recognize is here, for anyone who is interested: https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes

Now this basically only tells us two things about a key -- is it up, or is it down?  It doesn't tell the difference between "A" or "a",  It doesn't care if CAPSLOCK is active, or not.  It just tells us if the physical key itself is up or down.

And  then, we have to process and return the proper values ourselves -- which is what the routines I'm working up here does for us.

Right now, I only have about half of the keycodes entered into the program, but I'll get around to the rest of them tomorrow.  At that point, I'll have a program which works on my computer,  with my keyboard (and probably anyone else's who uses a US keyboard).   If Rho or Tempodi notice that the routine is giving them incorrect results for certain key combinations, then all they'll need to do is remap those keys to return the proper results they desire.

Feel free to test it out and see if there's any changes you guys would make with things, or any suggestions you might have for improvements.  I think once I get this sorted out, I'll be able to work up a nice customizable input routine that should be flexible enough to work with any keyboard layout.  (And even find other, extended, keys such as Play, Stop, ect for video/music control.)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #1 on: December 29, 2019, 07:43:33 am »
An update which should have all the US keys properly mapped for use:

Code: QB64: [Select]
  1. DECLARE LIBRARY 'function is already used by QB64 so "User32" is not required
  2.     FUNCTION GetKeyState% (BYVAL vkey AS LONG)
  3.  
  4.  
  5. TYPE KeyboardInfo_Type
  6.     Index AS LONG
  7.     KeyCodeReturn AS LONG
  8.     ASCII AS STRING
  9.     Modifiers AS LONG
  10.     Repeat AS _FLOAT
  11.     LastHit AS _FLOAT
  12.     Down AS INTEGER
  13. DIM SHARED Keys(1000) AS KeyboardInfo_Type
  14. CONST NONE = 0, KEY_CTRL = 1, KEY_NO_CTRL = 2
  15. CONST KEY_SHIFT = 4, KEY_NO_SHIFT = 8, KEY_ALT = 16, KEY_NO_ALT = 32
  16. CONST KEY_ALTGR = 64, CASECHANGE = 128, TOGGLE = 256
  17.  
  18. Set_US_Keys
  19.  
  20.  
  21. COLOR 15, 2
  22.     k = GetKeyHit(s$)
  23.     IF k <> 0 THEN PRINT k, s$
  24.  
  25.     _LIMIT 30
  26. LOOP UNTIL k = 27 'escape
  27.  
  28.  
  29. FUNCTION GetKeyHit (s$)
  30.         FOR i = 0 TO 1000
  31.             SELECT CASE Keys(i).Index
  32.                 CASE 0: r = 0
  33.                 CASE ELSE: r = GetKeyState(Keys(i).Index)
  34.             END SELECT
  35.  
  36.             IF r AND &H8000 THEN 'the key is down
  37.                 IF Keys(16).Down THEN CaseShift = -1 ELSE CaseShift = 0
  38.                 IF Keys(i).Modifiers AND CASECHANGE THEN
  39.                     IF _CAPSLOCK THEN CaseShift = NOT CaseShift
  40.                 END IF
  41.  
  42.                 IF Keys(i).Down = 0 THEN 'If the key state is recorded as up
  43.                     checkkeys:
  44.                     IF (Keys(i).Modifiers AND KEY_SHIFT) THEN 'we have a shift modifier on the key
  45.                         IF CaseShift THEN 'and shift is down
  46.                             Keys(i).LastHit = TIMER + Keys(i).Repeat 'and record when we hit it for repeat purposes
  47.                             GetKeyHit = Keys(i).KeyCodeReturn: s$ = Keys(i).ASCII
  48.                             Keys(i).Down = -1 'record it as being down
  49.                         END IF
  50.                     ELSEIF (Keys(i).Modifiers AND KEY_NO_SHIFT) THEN 'we have a no shift modifier on the key
  51.                         IF CaseShift = 0 THEN
  52.                             Keys(i).LastHit = TIMER + Keys(i).Repeat 'and record when we hit it for repeat purposes
  53.                             GetKeyHit = Keys(i).KeyCodeReturn: s$ = Keys(i).ASCII
  54.                             Keys(i).Down = -1 'record it as being down
  55.                         END IF
  56.                     ELSE 'we have a NONE modifier on the key
  57.                         Keys(i).LastHit = TIMER + Keys(i).Repeat 'and record when we hit it for repeat purposes
  58.                         GetKeyHit = Keys(i).KeyCodeReturn: s$ = Keys(i).ASCII
  59.                         Keys(i).Down = -1 'record it as being down
  60.                     END IF
  61.                 ELSE 'the keystate has been recorded as being down
  62.                     IF TIMER <= Keys(i).LastHit THEN 'unless the repeat time has passed
  63.                         GetKeyHit = 0 'we don't report the key as being active
  64.                     ELSE 'if the repeat time has passed...
  65.                         IF (Keys(i).Modifiers AND TOGGLE) = 0 THEN GOTO checkkeys 'then recheck to see if the key is still down
  66.                     END IF
  67.                 END IF
  68.             ELSE 'the key is up
  69.                 IF Keys(i).Down THEN 'and the keys were reported as being down
  70.                     GetKeyHit = -Keys(i).KeyCodeReturn 'so report the key release
  71.                     Keys(i).Down = 0 'and record the key as being up now
  72.                     Keys(i).LastHit = 0 'and we can say it's last hit (in regards to repeating itself) is now done.
  73.                 END IF
  74.             END IF
  75.         NEXT
  76.  
  77.     END IF
  78.  
  79.  
  80. SUB SetNextKey (Index AS LONG, KeyCodeReturn AS LONG, ASCII AS STRING, Modifiers AS LONG, Repeat AS _FLOAT)
  81.     STATIC Which AS INTEGER
  82.     Which = Which + 1
  83.     Keys(Which).Index = Index
  84.     Keys(Which).KeyCodeReturn = KeyCodeReturn
  85.     Keys(Which).ASCII = ASCII
  86.     Keys(Which).Modifiers = Modifiers
  87.     Keys(Which).Repeat = Repeat
  88.     Keys(Which).LastHit = 0
  89.  
  90. SUB SetKey (Which AS LONG, Index AS LONG, KeyCodeReturn AS LONG, ASCII AS STRING, Modifiers AS LONG, Repeat AS _FLOAT)
  91.     Keys(Which).Index = Index
  92.     Keys(Which).KeyCodeReturn = KeyCodeReturn
  93.     Keys(Which).ASCII = ASCII
  94.     Keys(Which).Modifiers = Modifiers
  95.     Keys(Which).Repeat = Repeat
  96.  
  97. SUB Set_US_Keys
  98.     SetNextKey 1, 100001, "LMB", NONE, 0.2 'Left Mouse Button
  99.     SetNextKey 2, 100002, "RMB", NONE, 0.2 'Right Mouse Button
  100.     SetNextKey 3, 900001, "CANCEL", NONE, 0.2 'VK_Cancel
  101.     SetNextKey 4, 100003, "MMB", NONE, 0.2 'Middle Mouse Button
  102.     SetNextKey 5, 100004, "MB4", NONE, 0.2 'Mouse Button 4
  103.     SetNextKey 6, 100005, "MB5", NONE, 0.2 'Mouse Button 5
  104.     SetNextKey 7, 900007, "UNDEFINED", NONE, 0 'Undefined
  105.     SetNextKey 8, 8, CHR$(8), NONE, 0.2 'BackSpace
  106.     SetNextKey 9, 9, CHR$(9), NONE, 0.2 'Tab
  107.     SetNextKey 10, 900010, "RESERVED", NONE, 0 'Reserved
  108.     SetNextKey 11, 900011, "RESERVED", NONE, 0 'Reserved
  109.     SetNextKey 12, 19456, CHR$(0) + CHR$(76), NONE, 0.2 'Clear
  110.     SetNextKey 13, 13, CHR$(13), NONE, 0.2 'Enter
  111.     SetNextKey 14, 900014, "UNDEFINED", NONE, 0 'Undefined
  112.     SetNextKey 15, 900015, "UNDEFINED", NONE, 0 'Undefined
  113.     SetNextKey 16, 100016, "SHIFT", TOGGLE, 0 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  114.     SetNextKey 17, 100017, "CTRL", TOGGLE, 0 'Ctrl   (Same)
  115.     SetNextKey 18, 100018, "ALT", TOGGLE, 0 'Alt     (Same)
  116.     SetNextKey 19, 100019, "PAUSE", NONE, 0 'Pause
  117.     SetNextKey 20, 100301, "CAPS", TOGGLE, 0 'Caps Lock
  118.     SetNextKey 21, 900021, "VK_HANGUL", NONE, 0 'VK_Hangul
  119.     SetNextKey 22, 900022, "UNDEFINED", NONE, 0 'Undefined
  120.     SetNextKey 23, 900023, "VK_JUNJA", NONE, 0 'VK_Junja
  121.     SetNextKey 24, 900024, "VK_FINAL", NONE, 0 'VK_Final
  122.     SetNextKey 25, 900025, "VK_HANJA/VK_KANJI", NONE, 0 'VK_HANGA and VK_Kanji
  123.     SetNextKey 26, 900026, "UNDEFINED", NONE, 0 'Undefined
  124.     SetNextKey 27, 27, CHR$(27), NONE, 0.2 'ESC
  125.     SetNextKey 28, 900028, "VK_CONVERT", NONE, 0 'VK_Convert
  126.     SetNextKey 29, 900029, "VK_NONCONVERT", NONE, 0 'VK_NonConvery
  127.     SetNextKey 30, 900030, "VK_ACCEPT", NONE, 0 'VK_Accept
  128.     SetNextKey 31, 900031, "VK_MODECHANGE", NONE, 0 'VK_ModeChange
  129.     SetNextKey 32, 32, " ", NONE, 0.2 'Space
  130.     SetNextKey 33, 18688, CHR$(0) + CHR$(73), NONE, 0.2 'Page Up
  131.     SetNextKey 34, 20736, CHR$(0) + CHR$(81), NONE, 0.2 'Page Down
  132.     SetNextKey 35, 20224, CHR$(0) + CHR$(79), NONE, 0.2 'END
  133.     SetNextKey 36, 18176, CHR$(0) + CHR$(71), NONE, 0.2 'HOME
  134.     SetNextKey 37, 19200, CHR$(0) + CHR$(75), NONE, 0.2 'Left Arrow
  135.     SetNextKey 38, 18432, CHR$(0) + CHR$(72), NONE, 0.2 'Up Arrow
  136.     SetNextKey 39, 19712, CHR$(0) + CHR$(77), NONE, 0.2 'Right Arrow
  137.     SetNextKey 40, 20480, CHR$(0) + CHR$(80), NONE, 0.2 'Down Arrow
  138.     SetNextKey 41, 900041, "VK_SELECT", NONE, 0 'VK_SELECT
  139.     SetNextKey 42, 900042, "VK_PRINT", NONE, 0 'VK_PRINT
  140.     SetNextKey 43, 900043, "VK_EXECUTE", NONE, 0 'VK_EXECUTE
  141.     SetNextKey 44, 900044, "VK_SNAPSHOT", NONE, 0 'VK_SNAPSHOT
  142.     SetNextKey 45, 20992, CHR$(0) + CHR$(82), NONE, 0 'INS
  143.     SetNextKey 46, 21248, CHR$(0) + CHR$(83), NONE, 0 'DEL
  144.     SetNextKey 47, 900047, "VK_HELP", NONE, 0 'VK_HELP
  145.  
  146.  
  147.     SetNextKey 48, 48, "0", KEY_NO_SHIFT, 0.2 '0
  148.     SetNextKey 49, 49, "1", KEY_NO_SHIFT, 0.2 '1
  149.     SetNextKey 50, 50, "2", KEY_NO_SHIFT, 0.2 '2
  150.     SetNextKey 51, 51, "3", KEY_NO_SHIFT, 0.2 '3
  151.     SetNextKey 52, 52, "4", KEY_NO_SHIFT, 0.2 '4
  152.     SetNextKey 53, 53, "5", KEY_NO_SHIFT, 0.2 '5
  153.     SetNextKey 54, 54, "6", KEY_NO_SHIFT, 0.2 '6
  154.     SetNextKey 55, 55, "7", KEY_NO_SHIFT, 0.2 '7
  155.     SetNextKey 56, 56, "8", KEY_NO_SHIFT, 0.2 '8
  156.     SetNextKey 57, 57, "9", KEY_NO_SHIFT, 0.2 '9
  157.  
  158.     SetNextKey 48, 41, ")", KEY_SHIFT, 0.2 '0
  159.     SetNextKey 49, 33, "!", KEY_SHIFT, 0.2 '1
  160.     SetNextKey 50, 64, "@", KEY_SHIFT, 0.2 '2
  161.     SetNextKey 51, 35, "#", KEY_SHIFT, 0.2 '3
  162.     SetNextKey 52, 36, "$", KEY_SHIFT, 0.2 '4
  163.     SetNextKey 53, 37, "%", KEY_SHIFT, 0.2 '5
  164.     SetNextKey 54, 94, "^", KEY_SHIFT, 0.2 '6
  165.     SetNextKey 55, 38, "&", KEY_SHIFT, 0.2 '7
  166.     SetNextKey 56, 42, "*", KEY_SHIFT, 0.2 '8
  167.     SetNextKey 57, 40, "(", KEY_SHIFT, 0.2 '9
  168.  
  169.     SetNextKey 58, 900058, "UNDEFINED", NONE, 0 'Undefined
  170.     SetNextKey 59, 900059, "UNDEFINED", NONE, 0 'Undefined
  171.     SetNextKey 60, 900060, "UNDEFINED", NONE, 0 'Undefined
  172.     SetNextKey 61, 900061, "UNDEFINED", NONE, 0 'Undefined
  173.     SetNextKey 62, 900062, "UNDEFINED", NONE, 0 'Undefined
  174.     SetNextKey 63, 900063, "UNDEFINED", NONE, 0 'Undefined
  175.     SetNextKey 64, 900064, "UNDEFINED", NONE, 0 'Undefined
  176.  
  177.     SetNextKey 65, 65, "A", CASECHANGE + KEY_SHIFT, 0.2 'A
  178.     SetNextKey 66, 66, "B", CASECHANGE + KEY_SHIFT, 0.2 'B
  179.     SetNextKey 67, 67, "C", CASECHANGE + KEY_SHIFT, 0.2 'C
  180.     SetNextKey 68, 68, "D", CASECHANGE + KEY_SHIFT, 0.2 'D
  181.     SetNextKey 69, 69, "E", CASECHANGE + KEY_SHIFT, 0.2 'E
  182.     SetNextKey 70, 70, "F", CASECHANGE + KEY_SHIFT, 0.2 'F
  183.     SetNextKey 71, 71, "G", CASECHANGE + KEY_SHIFT, 0.2 'G
  184.     SetNextKey 72, 72, "H", CASECHANGE + KEY_SHIFT, 0.2 'H
  185.     SetNextKey 73, 73, "I", CASECHANGE + KEY_SHIFT, 0.2 'I
  186.     SetNextKey 74, 74, "J", CASECHANGE + KEY_SHIFT, 0.2 'J
  187.     SetNextKey 75, 75, "K", CASECHANGE + KEY_SHIFT, 0.2 'K
  188.     SetNextKey 76, 76, "L", CASECHANGE + KEY_SHIFT, 0.2 'L
  189.     SetNextKey 77, 77, "M", CASECHANGE + KEY_SHIFT, 0.2 'M
  190.     SetNextKey 78, 78, "N", CASECHANGE + KEY_SHIFT, 0.2 'N
  191.     SetNextKey 79, 79, "O", CASECHANGE + KEY_SHIFT, 0.2 'O
  192.     SetNextKey 80, 80, "P", CASECHANGE + KEY_SHIFT, 0.2 'P
  193.     SetNextKey 81, 81, "Q", CASECHANGE + KEY_SHIFT, 0.2 'Q
  194.     SetNextKey 82, 82, "R", CASECHANGE + KEY_SHIFT, 0.2 'R
  195.     SetNextKey 83, 83, "S", CASECHANGE + KEY_SHIFT, 0.2 'S
  196.     SetNextKey 84, 84, "T", CASECHANGE + KEY_SHIFT, 0.2 'T
  197.     SetNextKey 85, 85, "U", CASECHANGE + KEY_SHIFT, 0.2 'U
  198.     SetNextKey 86, 86, "V", CASECHANGE + KEY_SHIFT, 0.2 'V
  199.     SetNextKey 87, 87, "W", CASECHANGE + KEY_SHIFT, 0.2 'W
  200.     SetNextKey 88, 88, "X", CASECHANGE + KEY_SHIFT, 0.2 'X
  201.     SetNextKey 89, 89, "Y", CASECHANGE + KEY_SHIFT, 0.2 'Y
  202.     SetNextKey 90, 90, "Z", CASECHANGE + KEY_SHIFT, 0.2 'Z
  203.  
  204.     SetNextKey 65, 97, "a", CASECHANGE + KEY_NO_SHIFT, 0.2 'a
  205.     SetNextKey 66, 98, "b", CASECHANGE + KEY_NO_SHIFT, 0.2 'b
  206.     SetNextKey 67, 99, "c", CASECHANGE + KEY_NO_SHIFT, 0.2 'c
  207.     SetNextKey 68, 100, "d", CASECHANGE + KEY_NO_SHIFT, 0.2 'd
  208.     SetNextKey 69, 101, "e", CASECHANGE + KEY_NO_SHIFT, 0.2 'e
  209.     SetNextKey 70, 102, "f", CASECHANGE + KEY_NO_SHIFT, 0.2 'f
  210.     SetNextKey 71, 103, "g", CASECHANGE + KEY_NO_SHIFT, 0.2 'g
  211.     SetNextKey 72, 104, "h", CASECHANGE + KEY_NO_SHIFT, 0.2 'h
  212.     SetNextKey 73, 105, "i", CASECHANGE + KEY_NO_SHIFT, 0.2 'i
  213.     SetNextKey 74, 106, "j", CASECHANGE + KEY_NO_SHIFT, 0.2 'j
  214.     SetNextKey 75, 107, "k", CASECHANGE + KEY_NO_SHIFT, 0.2 'k
  215.     SetNextKey 76, 108, "l", CASECHANGE + KEY_NO_SHIFT, 0.2 'l
  216.     SetNextKey 77, 109, "m", CASECHANGE + KEY_NO_SHIFT, 0.2 'm
  217.     SetNextKey 78, 110, "n", CASECHANGE + KEY_NO_SHIFT, 0.2 'n
  218.     SetNextKey 79, 111, "o", CASECHANGE + KEY_NO_SHIFT, 0.2 'o
  219.     SetNextKey 80, 112, "p", CASECHANGE + KEY_NO_SHIFT, 0.2 'p
  220.     SetNextKey 81, 113, "q", CASECHANGE + KEY_NO_SHIFT, 0.2 'q
  221.     SetNextKey 82, 114, "r", CASECHANGE + KEY_NO_SHIFT, 0.2 'r
  222.     SetNextKey 83, 115, "s", CASECHANGE + KEY_NO_SHIFT, 0.2 's
  223.     SetNextKey 84, 116, "t", CASECHANGE + KEY_NO_SHIFT, 0.2 't
  224.     SetNextKey 85, 117, "u", CASECHANGE + KEY_NO_SHIFT, 0.2 'u
  225.     SetNextKey 86, 118, "v", CASECHANGE + KEY_NO_SHIFT, 0.2 'v
  226.     SetNextKey 87, 119, "w", CASECHANGE + KEY_NO_SHIFT, 0.2 'w
  227.     SetNextKey 88, 120, "x", CASECHANGE + KEY_NO_SHIFT, 0.2 'x
  228.     SetNextKey 89, 121, "y", CASECHANGE + KEY_NO_SHIFT, 0.2 'y
  229.     SetNextKey 90, 122, "z", CASECHANGE + KEY_NO_SHIFT, 0.2 'z
  230.  
  231.     SetNextKey 91, 100311, "VK_LWIN", TOGGLE, 0.2 'Left WIN
  232.     SetNextKey 92, 100312, "VK_RWIN", TOGGLE, 0.2 'Right WIN
  233.     SetNextKey 93, 100319, "VK_APPS", TOGGLE, 0.2 'Applications Key  (Menu key)
  234.     SetNextKey 94, 900094, "RESERVED", NONE, 0 'Reserved
  235.     SetNextKey 95, 900095, "VK_SLEEP", NONE, 0.2 'VK_SLEEP
  236.  
  237.     SetNextKey 96, 48, "0", NONE, 0.2 'Numpad 0
  238.     SetNextKey 97, 49, "1", NONE, 0.2 'Numpad 1
  239.     SetNextKey 98, 50, "2", NONE, 0.2 'Numpad 2
  240.     SetNextKey 99, 51, "3", NONE, 0.2 'Numpad 3
  241.     SetNextKey 100, 52, "4", NONE, 0.2 'Numpad 4
  242.     SetNextKey 101, 53, "5", NONE, 0.2 'Numpad 5
  243.     SetNextKey 102, 54, "6", NONE, 0.2 'Numpad 6
  244.     SetNextKey 103, 55, "7", NONE, 0.2 'Numpad 7
  245.     SetNextKey 104, 56, "8", NONE, 0.2 'Numpad 8
  246.     SetNextKey 105, 57, "9", NONE, 0.2 'Numpad 9
  247.  
  248.     SetNextKey 106, 42, "*", NONE, 0.2 'Muliply
  249.     SetNextKey 107, 43, "+", NONE, 0.2 'Add
  250.     SetNextKey 108, 900108, "VK_SEPARATOR", NONE, 0.2 'VK_SEPARATOR (Whatever the hell that is)
  251.     SetNextKey 109, 51, "-", NONE, 0.2 'Subtract
  252.     SetNextKey 110, 52, ".", NONE, 0.2 'Decimal
  253.     SetNextKey 111, 53, "/", NONE, 0.2 'Divide
  254.  
  255.     SetNextKey 112, 15104, CHR$(0) + CHR$(59), NONE, 0.2 'F1
  256.     SetNextKey 113, 15360, CHR$(0) + CHR$(60), NONE, 0.2 'F2
  257.     SetNextKey 114, 15616, CHR$(0) + CHR$(61), NONE, 0.2 'F3
  258.     SetNextKey 115, 15872, CHR$(0) + CHR$(62), NONE, 0.2 'F4
  259.     SetNextKey 116, 16128, CHR$(0) + CHR$(63), NONE, 0.2 'F5
  260.     SetNextKey 117, 16384, CHR$(0) + CHR$(64), NONE, 0.2 'F6
  261.     SetNextKey 118, 16640, CHR$(0) + CHR$(65), NONE, 0.2 'F7
  262.     SetNextKey 119, 16896, CHR$(0) + CHR$(66), NONE, 0.2 'F8
  263.     SetNextKey 120, 17152, CHR$(0) + CHR$(67), NONE, 0.2 'F9
  264.     SetNextKey 121, 17408, CHR$(0) + CHR$(68), NONE, 0.2 'F10
  265.     SetNextKey 122, 34048, CHR$(0) + CHR$(133), NONE, 0.2 'F11
  266.     SetNextKey 123, 34304, CHR$(0) + CHR$(134), NONE, 0.2 'F12
  267.     SetNextKey 124, 900124, "F13", NONE, 0.2 'F13
  268.     SetNextKey 125, 900125, "F14", NONE, 0.2 'F14
  269.     SetNextKey 126, 900126, "F15", NONE, 0.2 'F15
  270.     SetNextKey 127, 900127, "F16", NONE, 0.2 'F16
  271.     SetNextKey 128, 900128, "F17", NONE, 0.2 'F17
  272.     SetNextKey 129, 900129, "F18", NONE, 0.2 'F18
  273.     SetNextKey 130, 900130, "F19", NONE, 0.2 'F19
  274.     SetNextKey 131, 900131, "F20", NONE, 0.2 'F20
  275.     SetNextKey 132, 900132, "F21", NONE, 0.2 'F21
  276.     SetNextKey 133, 900133, "F22", NONE, 0.2 'F22
  277.     SetNextKey 134, 900134, "F23", NONE, 0.2 'F23
  278.     SetNextKey 135, 900135, "F24", NONE, 0.2 'F24
  279.  
  280.     FOR i = 136 TO 143
  281.         SetNextKey i, 900000 + i, "UNASSIGNED", NONE, 0 'Unassigned
  282.     NEXT
  283.  
  284.     SetNextKey 144, 100300, "VK_NUMLOCK", TOGGLE, 0.2 'NUM LOCK
  285.     SetNextKey 145, 100302, "VK_SCROLL", TOGGLE, 0.2 'SCROLL LOCK
  286.  
  287.     SetNextKey 146, 900146, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  288.     SetNextKey 147, 900147, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  289.     SetNextKey 148, 900148, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  290.     SetNextKey 149, 900149, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  291.     SetNextKey 150, 900150, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  292.  
  293.     FOR i = 151 TO 159
  294.         SetNextKey i, 900000 + i, "UNASSIGNED", NONE, 0 'Unassigned
  295.     NEXT
  296.  
  297.     SetNextKey 160, 100304, "VK_LSHIFT", TOGGLE, 0.2 'Left SHIFT
  298.     SetNextKey 161, 100303, "VK_RSHIFT", TOGGLE, 0.2 'Right SHIFT
  299.     SetNextKey 162, 100306, "VK_LCONTROL", TOGGLE, 0.2 'Left CONTROL
  300.     SetNextKey 163, 100305, "VK_RCONTROL", TOGGLE, 0.2 'Right CONTROL
  301.     SetNextKey 164, 100308, "VK_LMENU", TOGGLE, 0.2 'Left Alt (Why does MS document these as Menu keys??)
  302.     SetNextKey 165, 100309, "VK_RMENU", TOGGLE, 0.2 'Right Alt
  303.  
  304.     SetNextKey 166, 900166, "BK_BROWSER_BACK", NONE, 0.2 'Browser back
  305.     SetNextKey 167, 900167, "BK_BROWSER_FORWARD", NONE, 0.2 'Browser forwar
  306.     SetNextKey 168, 900168, "BK_BROWSER_REFRESH", NONE, 0.2 'Browser refresh
  307.     SetNextKey 169, 900169, "BK_BROWSER_STOP", NONE, 0.2 'Browser stop
  308.     SetNextKey 170, 900170, "BK_BROWSER_SEARCH", NONE, 0.2 'Browser search
  309.     SetNextKey 171, 900171, "BK_BROWSER_FAVORITES", NONE, 0.2 'Browser favorites
  310.     SetNextKey 172, 900172, "BK_BROWSER_HOME", NONE, 0.2 'Browser home
  311.     SetNextKey 173, 900173, "BK_VOLUME_MUTE", NONE, 0.2 'Mute
  312.     SetNextKey 174, 900174, "BK_VOLUME_DOWN", NONE, 0.2 'Vol Down
  313.     SetNextKey 175, 900175, "BK_VOLUME_UP", NONE, 0.2 'Vol Up
  314.     SetNextKey 176, 900176, "VK_MEDIA_NEXT_TRACK", NONE, 0.2 'Media Next
  315.     SetNextKey 177, 900177, "VK_MEDIA_PREV_TRACK", NONE, 0.2 'Media Prev
  316.     SetNextKey 178, 900178, "VK_MEDIA_STOP", NONE, 0.2 'Media Stop
  317.     SetNextKey 179, 900179, "VK_MEDIA_PLAY_PAUSE", NONE, 0.2 'Media Play/Pause
  318.     SetNextKey 180, 900180, "VK_LAUNCH_MAIL", NONE, 0.2 'Launch Mail
  319.     SetNextKey 181, 900181, "VK_LAUNCH_MEDIA_SELECT", NONE, 0.2 'Launch Media Select
  320.     SetNextKey 182, 900182, "VK_LAUNCH_APP1", NONE, 0.2 'Launch App1
  321.     SetNextKey 183, 900183, "VK_LAUNCH_APP1", NONE, 0.2 'Launch App2
  322.  
  323.     SetNextKey 184, 900184, "RESERVED", NONE, 0 'Reserved
  324.     SetNextKey 185, 900185, "RESERVED", NONE, 0 'Reserved
  325.  
  326.     SetNextKey 186, 59, ";", KEY_NO_SHIFT, 0.2 'US STANDARD ;:
  327.     SetNextKey 186, 58, ":", KEY_SHIFT, 0.2 'US STANDARD ;:
  328.     SetNextKey 187, 61, "=", KEY_NO_SHIFT, 0.2 '=
  329.     SetNextKey 187, 43, "+", KEY_SHIFT, 0.2 '+
  330.     SetNextKey 188, 44, ",", KEY_NO_SHIFT, 0.2 ',
  331.     SetNextKey 188, 60, "<", KEY_SHIFT, 0.2 ',
  332.     SetNextKey 189, 45, "-", KEY_NO_SHIFT, 0.2 '-
  333.     SetNextKey 189, 95, "_", KEY_SHIFT, 0.2 '-
  334.     SetNextKey 190, 46, ".", KEY_NO_SHIFT, 0.2 '.
  335.     SetNextKey 190, 62, ">", KEY_SHIFT, 0.2 '.
  336.     SetNextKey 191, 47, "/", KEY_NO_SHIFT, 0.2 'US STANDARD /?
  337.     SetNextKey 191, 63, "?", KEY_SHIFT, 0.2 'US STANDARD ?
  338.     SetNextKey 192, 96, "`", KEY_NO_SHIFT, 0.2 'US STANARD `
  339.     SetNextKey 192, 126, "~", KEY_SHIFT, 0.2 'US STANDARD ~
  340.  
  341.     FOR i = 193 TO 215
  342.         SetNextKey i, 900000 + i, "RESERVED", NONE, 0 'Reserved
  343.     NEXT
  344.     FOR i = 216 TO 218
  345.         SetNextKey i, 900000 + i, "UNASSIGNED", NONE, 0 'Unassigned
  346.     NEXT
  347.  
  348.     SetNextKey 219, 91, "[", KEY_NO_SHIFT, 0.2 'US STANDARD [
  349.     SetNextKey 219, 123, "{", KEY_SHIFT, 0.2 'US STANDARD {
  350.     SetNextKey 220, 92, "\", KEY_NO_SHIFT, 0.2 'US STANDARD \
  351.     SetNextKey 220, 124, "|", KEY_SHIFT, 0.2 'US STANDARD |
  352.     SetNextKey 221, 93, "]", KEY_NO_SHIFT, 0.2 'US STANDARD ]
  353.     SetNextKey 221, 125, "}", KEY_SHIFT, 0.2 'US STANDARD }
  354.     SetNextKey 222, 39, "'", KEY_NO_SHIFT, 0.2 'US STANDARD '
  355.     SetNextKey 222, 34, CHR$(34), KEY_SHIFT, 0.2 'US STANDARD "
  356.  
  357.     SetNextKey 223, 900223, "VK_OEM_8", NONE, 0 'OEM SPECIFIC
  358.     SetNextKey 224, 900224, "RESERVED", NONE, 0 'Reserved
  359.     SetNextKey 225, 900225, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  360.     SetNextKey 226, 900226, "VK_OEM_102", NONE, 0 'Either the Angle Bracket key, or Backslash on RT 102-key keyboard
  361.     SetNextKey 227, 900227, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  362.     SetNextKey 228, 900228, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  363.  
  364.     SetNextKey 229, 900229, "VK_PROCESS", NONE, 0 'IME PROCESS key (whatever that is)
  365.     SetNextKey 230, 900230, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  366.     SetNextKey 231, 900231, "VK_PACKET", NONE, 0 'Used to pass UNICODE characters (however that works)
  367.  
  368.     SetNextKey 232, 900232, "UNASSIGNED", NONE, 0 'Unassigned
  369.     FOR i = 233 TO 245
  370.         SetNextKey i, 900000 + i, "OEM SPECIFIC", NONE, 0 'OEM SPECIFIC
  371.     NEXT
  372.  
  373.     SetNextKey 246, 900246, "VK_ATTN", NONE, 0 'VK_ATTN
  374.     SetNextKey 247, 900247, "VK_CRSEL", NONE, 0 'VK_CRSEL
  375.     SetNextKey 248, 900248, "VK_EXSEL", NONE, 0 'VK_EXSEL
  376.     SetNextKey 249, 900249, "VK_EREOF", NONE, 0 'VK_EREOF
  377.     SetNextKey 250, 900250, "VK_PLAY", NONE, 0 'VK_PLAY
  378.     SetNextKey 251, 900251, "VK_ZOOM", NONE, 0 'VK_ZOOM
  379.     SetNextKey 252, 900252, "RESERVED", NONE, 0 'RESERVED
  380.     SetNextKey 253, 900253, "VK_PA1", NONE, 0 'VK_PA1
  381.     SetNextKey 254, 900254, "VK_OEM_CLEAR", NONE, 0 'VK_OEM_CLEAR

Initial testing seems to show that this works as intended for me, giving both KEYHIT and INKEY$ type character returns.  Of course, there's a lot of keys that this thing can detect that _KEYHIT was never actually designed to return values for (such as some of the browser buttons, or media buttons that several newer keyboards have), so I had to design my own keyhit codes for those keys..   The simple standard I came up with is just 900000 + the windows code for the key, so some keys may come up with those code for unusual keyboards. 

In the end, I figure it's best to report a key being hit, no matter what it is, if we can report it, than it is to just ignore it!  Someone can always remap it's output values later for whatever their needs might be, if they want to, if we can detect it!  ;)

It might not be an idea solution for code which one needs to share globally, (at least not unless somebody can configure various language packs to work with different layouts, like we have different map_unicode pages), but it'll allow users to customize the scan code settings and adjust them to their keyboard/needs.  :)

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Programmable Keyboard Input
« Reply #2 on: December 29, 2019, 09:49:53 am »
Great work !

1. I must run it in DEVelopment version the latest that today I have downloaded from QB64 webpage.
2. I find that it is ok for US keyboard and that both with external USB keyboard both with normal keyboard of the notebook it is ok and it shows the key like an US keyboard while using them into any windows application they work as IT keyboard (also if the USB keyboard is not just IT for key that it shows).
So  each one can define the right key symbol for the different keys copying and modding the Set_US_Keys SUB.

I must  stress that also mouse Lbutton Rbutton and Mbutton are ok while Mousewheel is not catched, I don't know if it must be captured but this thing can be useful to get out the instruction of keyboard and mouse already standing in QB64.

My keyboard has only F12 keys, I cannot test the other Fkeys. Moreover PrintScreen don't give a feedback to have been pressed so Scroll Lock while Break close this your application!
And you make the magic about Windows Keys (right and left) and AppKey, now you can get their status also if then the focus pass to the OS that activate the OS menu .

If I am able to install the latest dev version in my Ubuntu emulator I can test it also there.
Programming isn't difficult, only it's  consuming time and coffee

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #3 on: December 29, 2019, 10:31:43 am »
For whatever reason, there’s no code for the mousewheel, so I can’t retrieve that information with this.  However, you can now get the 4th and 5th mouse buttons back (if your mouse has the extra ones, as mine does).  I also find it nice that one could easily use it as an extra way to exit a SLEEP-style routine with it reporting a mouse click as a key event.  ;)

There’s a lot of keys that it checks for, that I simply have to assume work without testing, as I don’t have them on my keyboard.  The media buttons work which I have, but I don’t have any of the extended F-keys, browser buttons, or quick-launch buttons to test it.

As for PrintScreen, I’ll double check and make certain I didn’t skip/mislabel it somewhere, and see if I can sort out why it’s not giving any feedback, and I’ll report back on it later.  ;)



And I can save you the testing on Ubuntu; it won’t work there.  GetKeyState is a Windows library routine and thus not available for Mac/Linux.



Thank you for testing it, so far!  I didn’t even realize it required the Development build to work properly (I think it’s the _CAPSLOCK command which we’re missing).  I have to admit, I’m anxiously looking forward to the next stable version being released soon, just so all the new commands will be available for everyone to test and utilize from now on.  ;)
« Last Edit: December 29, 2019, 10:36:20 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: Programmable Keyboard Input
« Reply #4 on: December 29, 2019, 10:53:41 am »
Testing in progress ... trying to add a suitable Set_DE_Keys() sub ...

Probably this function could be used to autoselect the right Set_??_Keys() sub, once a few more int'l users have provided the respective SUBs for their keyboards (https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardlayout)
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #5 on: December 29, 2019, 12:13:47 pm »
Testing in progress ... trying to add a suitable Set_DE_Keys() sub ...

Probably this function could be used to autoselect the right Set_??_Keys() sub, once a few more int'l users have provided the respective SUBs for their keyboards (https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getkeyboardlayout)

After getting it up and going the first time, I'm now attempting to simplify the data structure and the process behind things to make it a little easier for others to work with.   Take a quick look and see if this format might be a little simpler to deal with (as long as you keep auto-formatting disabled so it spaces itself properly.)

Code: [Select]
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA   1,    900001,         0,         0,         0,           0,        0.2
DATA   2,    900002,         0,         0,         0,           0,        0.2
DATA   3,    900003,         0,         0,         0,           0,        0.2
DATA   4,    900004,         0,         0,         0,           0,        0.2
DATA   5,    900005,         0,         0,         0,           0,        0.2
DATA   6,    900006,         0,         0,         0,           0,        0.2
DATA   7,    900007,         0,         0,         0,           0,        0.2
DATA   8,         9,         0,         0,         0,           0,        0.2
DATA   9,         9,         0,         0,         0,           0,        0.2
DATA  10,    900010,         0,         0,         0,           0,        0.2
DATA  11,    900011,         0,         0,         0,           0,        0.2
DATA  12,     19456,         0,         0,         0,           0,        0.2
DATA  13,        13,         0,         0,         0,           0,        0.2
DATA  14,    900014,         0,         0,         0,           0,        0.2
DATA  15,    900015,         0,         0,         0,           0,        0.2
DATA  16,    100016,         0,         0,         0,           0,         -1
DATA  17,    100017,         0,         0,         0,           0,         -1
DATA  18,    100018,         0,         0,         0,           0,         -1
DATA  19,    100019,         0,         0,         0,           0,        0.2
DATA  20,    100301,         0,         0,         0,           0,         -1
DATA  21,    900021,         0,         0,         0,           0,        0.2
DATA  22,    900022,         0,         0,         0,           0,        0.2
DATA  23,    900023,         0,         0,         0,           0,        0.2
DATA  24,    900024,         0,         0,         0,           0,        0.2
DATA  25,    900025,         0,         0,         0,           0,        0.2
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA  26,    900026,         0,         0,         0,           0,        0.2
DATA  27,        27,         0,         0,         0,           0,        0.2
DATA  28,    900028,         0,         0,         0,           0,        0.2
DATA  29,    900029,         0,         0,         0,           0,        0.2
DATA  30,    900030,         0,         0,         0,           0,        0.2
DATA  31,    900031,         0,         0,         0,           0,        0.2
DATA  32,        32,         0,         0,         0,           0,        0.2
DATA  33,     18688,         0,         0,         0,           0,        0.2
DATA  34,     20736,         0,         0,         0,           0,        0.2
DATA  35,     20224,         0,         0,         0,           0,        0.2
DATA  36,     18176,         0,         0,         0,           0,        0.2
DATA  37,     19200,         0,         0,         0,           0,        0.2
DATA  38,     18432,         0,         0,         0,           0,        0.2
DATA  39,     19712,         0,         0,         0,           0,        0.2
DATA  40,     20480,         0,         0,         0,           0,        0.2
DATA  41,    900041,         0,         0,         0,           0,         -1
DATA  42,    900042,         0,         0,         0,           0,         -1
DATA  43,    900043,         0,         0,         0,           0,         -1
DATA  44,    900044,         0,         0,         0,           0,         -1
DATA  45,     20992,         0,         0,         0,           0,        0.2
DATA  46,     21248,         0,         0,         0,           0,        0.2
DATA  47,    900047,         0,         0,         0,           0,        0.2
DATA  48,        48,         0,        41,         0,           0,        0.2 '0
DATA  49,        49,         0,        33,         0,           0,        0.2 '1
DATA  50,        50,         0,        64,         0,           0,        0.2 '2
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA  51,        51,         0,        35,         0,           0,        0.2 '3
DATA  52,        52,         0,        36,         0,           0,        0.2 '4
DATA  53,        53,         0,        37,         0,           0,        0.2 '5
DATA  54,        54,         0,        94,         0,           0,        0.2 '6
DATA  55,        55,         0,        38,         0,           0,        0.2 '7
DATA  56,        56,         0,        42,         0,           0,        0.2 '8
DATA  57,        57,         0,        40,         0,           0,        0.2 '9
DATA  58,    900058,         0,         0,         0,           0,        0.2 'Undefined
DATA  59,    900059,         0,         0,         0,           0,        0.2 'Undefined
DATA  60,    900060,         0,         0,         0,           0,        0.2 'Undefined
DATA  61,    900061,         0,         0,         0,           0,        0.2 'Undefined
DATA  62,    900062,         0,         0,         0,           0,        0.2 'Undefined
DATA  63,    900063,         0,         0,         0,           0,        0.2 'Undefined
DATA  64,    900064,         0,         0,         0,           0,        0.2 'Undefined
DATA  65,        65,         0,        97,         0,           0,        0.2 'a
DATA  66,        66,         0,        98,         0,           0,        0.2 'b
DATA  67,        67,         0,        99,         0,           0,        0.2 'c
DATA  68,        68,         0,       100,         0,           0,        0.2 'd
DATA  69,        69,         0,       101,         0,           0,        0.2 'e
DATA  70,        70,         0,       102,         0,           0,        0.2 'f
DATA  71,        71,         0,       103,         0,           0,        0.2 'g
DATA  72,        72,         0,       104,         0,           0,        0.2 'h
DATA  73,        73,         0,       105,         0,           0,        0.2 'i
DATA  74,        74,         0,       106,         0,           0,        0.2 'j
DATA  75,        75,         0,       107,         0,           0,        0.2 'k
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA  76,        76,         0,       108,         0,           0,        0.2 'l
DATA  77,        77,         0,       109,         0,           0,        0.2 'm
DATA  78,        78,         0,       110,         0,           0,        0.2 'n
DATA  79,        79,         0,       111,         0,           0,        0.2 'o
DATA  80,        80,         0,       112,         0,           0,        0.2 'p
DATA  81,        81,         0,       113,         0,           0,        0.2 'q
DATA  82,        82,         0,       114,         0,           0,        0.2 'r
DATA  83,        83,         0,       115,         0,           0,        0.2 's
DATA  84,        84,         0,       116,         0,           0,        0.2 't
DATA  85,        85,         0,       117,         0,           0,        0.2 'u
DATA  86,        86,         0,       118,         0,           0,        0.2 'v
DATA  87,        87,         0,       119,         0,           0,        0.2 'w
DATA  88,        88,         0,       120,         0,           0,        0.2 'x
DATA  89,        89,         0,       121,         0,           0,        0.2 'y
DATA  90,        90,         0,       122,         0,           0,        0.2 'z
DATA  91,    100311,         0,         0,         0,           0,        0.2 'Left WIN
DATA  92,    100312,         0,         0,         0,           0,        0.2 'Right WIN
DATA  93,    100319,         0,         0,         0,           0,        0.2 'Applications (Menu)
DATA  94,    900094,         0,         0,         0,           0,        0.2 'Reserved
DATA  95,    900095,         0,         0,         0,           0,        0.2 'VK_SLEEP
DATA  96,        48,         0,         0,         0,           0,        0.2 'Numpad 0
DATA  97,        49,         0,         0,         0,           0,        0.2 'Numpad 1
DATA  98,        50,         0,         0,         0,           0,        0.2 'Numpad 2
DATA  99,        51,         0,         0,         0,           0,        0.2 'Numpad 3
DATA 100,        52,         0,         0,         0,           0,        0.2 'Numpad 4
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA 101,        53,         0,         0,         0,           0,        0.2 'Numpad 5
DATA 102,        54,         0,         0,         0,           0,        0.2 'Numpad 6
DATA 103,        55,         0,         0,         0,           0,        0.2 'Numpad 7
DATA 104,        56,         0,         0,         0,           0,        0.2 'Numpad 8
DATA 105,        57,         0,         0,         0,           0,        0.2 'Numpad 9
DATA 106,        42,         0,         0,         0,           0,        0.2 'Numpad *
DATA 107,        43,         0,         0,         0,           0,        0.2 'Numpad +
DATA 108,    900108,         0,         0,         0,           0,        0.2 'VK_SEPARATOR
DATA 109,        51,         0,         0,         0,           0,        0.2 'Numpad -
DATA 110,        52,         0,         0,         0,           0,        0.2 'Numpad .
DATA 111,        53,         0,         0,         0,           0,        0.2 'Numpad /
DATA 112,     15104,         0,         0,         0,           0,        0.2 'F1
DATA 113,     15360,         0,         0,         0,           0,        0.2 'F2
DATA 114,     15616,         0,         0,         0,           0,        0.2 'F3
DATA 115,     15872,         0,         0,         0,           0,        0.2 'F4
DATA 116,     16128,         0,         0,         0,           0,        0.2 'F5
DATA 117,     16384,         0,         0,         0,           0,        0.2 'F6
DATA 118,     16640,         0,         0,         0,           0,        0.2 'F7
DATA 119,     16896,         0,         0,         0,           0,        0.2 'F8
DATA 120,     17152,         0,         0,         0,           0,        0.2 'F9
DATA 121,     17408,         0,         0,         0,           0,        0.2 'F10
DATA 122,     34048,         0,         0,         0,           0,        0.2 'F11
DATA 123,     34304,         0,         0,         0,           0,        0.2 'F12
DATA 124,    900124,         0,         0,         0,           0,        0.2 'F13
DATA 125,    900125,         0,         0,         0,           0,        0.2 'F14
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA 126,    900126,         0,         0,         0,           0,        0.2 'F15
DATA 127,    900127,         0,         0,         0,           0,        0.2 'F16
DATA 128,    900128,         0,         0,         0,           0,        0.2 'F17
DATA 129,    900129,         0,         0,         0,           0,        0.2 'F18
DATA 130,    900130,         0,         0,         0,           0,        0.2 'F19
DATA 131,    900131,         0,         0,         0,           0,        0.2 'F20
DATA 132,    900132,         0,         0,         0,           0,        0.2 'F21
DATA 133,    900133,         0,         0,         0,           0,        0.2 'F22
DATA 134,    900134,         0,         0,         0,           0,        0.2 'F23
DATA 135,    900135,         0,         0,         0,           0,        0.2 'F24
DATA 136,    900136,         0,         0,         0,           0,        0.2 'Unassigned
DATA 137,    900137,         0,         0,         0,           0,        0.2 'Unassigned
DATA 138,    900138,         0,         0,         0,           0,        0.2 'Unassigned
DATA 139,    900139,         0,         0,         0,           0,        0.2 'Unassigned
DATA 140,    900140,         0,         0,         0,           0,        0.2 'Unassigned
DATA 141,    900141,         0,         0,         0,           0,        0.2 'Unassigned
DATA 142,    900142,         0,         0,         0,           0,        0.2 'Unassigned
DATA 143,    900143,         0,         0,         0,           0,        0.2 'Unassigned
DATA 144,    100300,         0,         0,         0,           0,        0.2 'NUM LOCK
DATA 145,    100302,         0,         0,         0,           0,        0.2 'SCROLL LOCK
DATA 146,    900146,         0,         0,         0,           0,        0.2 'OEM SPECIFIC
DATA 147,    900147,         0,         0,         0,           0,        0.2 'OEM SPECIFIC
DATA 148,    900148,         0,         0,         0,           0,        0.2 'OEM SPECIFIC
DATA 149,    900149,         0,         0,         0,           0,        0.2 'OEM SPECIFIC
DATA 150,    900150,         0,         0,         0,           0,        0.2 'OEM SPECIFIC
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA 151,    900151,         0,         0,         0,           0,        0.2 'Unassigned
DATA 152,    900152,         0,         0,         0,           0,        0.2 'Unassigned
DATA 153,    900153,         0,         0,         0,           0,        0.2 'Unassigned
DATA 154,    900154,         0,         0,         0,           0,        0.2 'Unassigned
DATA 155,    900155,         0,         0,         0,           0,        0.2 'Unassigned
DATA 156,    900156,         0,         0,         0,           0,        0.2 'Unassigned
DATA 157,    900157,         0,         0,         0,           0,        0.2 'Unassigned
DATA 158,    900158,         0,         0,         0,           0,        0.2 'Unassigned
DATA 159,    900159,         0,         0,         0,           0,        0.2 'Unassigned
DATA 160,    100304,         0,         0,         0,           0,        0.2 'Left Shift
DATA 161,    100303,         0,         0,         0,           0,        0.2 'Right Shift
DATA 162,    100306,         0,         0,         0,           0,        0.2 'Left Control
DATA 163,    100305,         0,         0,         0,           0,        0.2 'Right Control
DATA 164,    100308,         0,         0,         0,           0,        0.2 'Left Alt
DATA 165,    100309,         0,         0,         0,           0,        0.2 'Right Alt
DATA 166,    900166,         0,         0,         0,           0,        0.2 'Browser back
DATA 167,    900167,         0,         0,         0,           0,        0.2 'Browser forward
DATA 168,    900168,         0,         0,         0,           0,        0.2 'Browser refresh
DATA 169,    900169,         0,         0,         0,           0,        0.2 'Browser stop
DATA 170,    900170,         0,         0,         0,           0,        0.2 'Browser search
DATA 171,    900171,         0,         0,         0,           0,        0.2 'Browser favorites
DATA 172,    900172,         0,         0,         0,           0,        0.2 'Browser home
DATA 173,    900173,         0,         0,         0,           0,        0.2 'Mute
DATA 174,    900174,         0,         0,         0,           0,        0.2 'Vol Down
DATA 175,    900175,         0,         0,         0,           0,        0.2 'Vol Up
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
DATA 176,    900176,         0,         0,         0,           0,        0.2 'Media Next
DATA 177,    900177,         0,         0,         0,           0,        0.2 'Media prev
DATA 178,    900178,         0,         0,         0,           0,        0.2 'Media stop
DATA 179,    900179,         0,         0,         0,           0,        0.2 'Media Play/Pause
DATA 180,    900180,         0,         0,         0,           0,        0.2 'Launch mail
DATA 181,    900181,         0,         0,         0,           0,        0.2 'Launch media select
DATA 182,    900182,         0,         0,         0,           0,        0.2 'Launch app1
DATA 183,    900183,         0,         0,         0,           0,        0.2 'Launch app2

The idea here is to simplify the data structure down to where it'd read one windows code for us, and then return the proper result based on the various keyboard states which we might have/want.

 Take the letter A for an example:

DATA  65,        65,         0,        97,         0,           0,        0.2 'a

That first 65 is the windows key which GetKeyState looks at, which normally corresponds with "A".
The next 64 would be the normal QB64 _KEYHIT return code (if possible to use).
Next would be the ASCII code of any character which we might want to map to CTRL-A.   (Such as CHR$(1), for people who like those old-style mappings.)
The 97 is the ASCII code which we'd return if SHIFT was held down.  (Shift-A, in this case.)  It's the lowercase"a".
Same for ALT-A, if we  want to map a character to it, and AltGr-A, in case we want to map a return character to it.
The last value is the repeat timer, for how quickly we repeat the key if we keep it held down. 




I'm still working on converting my old data into the new format, but I think it'll end up being a little more intuitive for others to use and build upon.  Just like MapUnicode, we can eventually get a collection of data statements and then someone can insert those into their code and just RESTORE us_keyboard_codes, or RESTORE DE_keyboard_codes, as needed. 

Give me another day or so, and I'll see about giving you guys a working version of the more simplified stuff to build upon; until then, consider what I've got here so far to be more of a working proof-of-concept of what I'm hoping to accomplish with the final, finished version.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Programmable Keyboard Input
« Reply #6 on: December 29, 2019, 05:22:45 pm »
Hi Steve
thanks for tip for Ubuntu...
it lasts to who use in professional manner Linux to give a feedback showing a similar OS function in Ubuntu or in Debian or others.

A question:
in your structure how do you manage CAPSLOCK and NUMLOCK to distinguish between A and a or 7 and Home?
Quote
'   Index   Unmodified      Ctrl      Shift       Alt         AltGr           Repeat
 
« Last Edit: December 29, 2019, 06:02:57 pm by TempodiBasic »
Programming isn't difficult, only it's  consuming time and coffee

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #7 on: December 29, 2019, 06:40:41 pm »
Hi Steve
thanks for tip for Ubuntu...
it lasts to who use in professional manner Linux to give a feedback showing a similar OS function in Ubuntu or in Debian or others.

A question:
in your structure how do you manage CAPSLOCK and NUMLOCK to distinguish between A and a or 7 and Home?

One important thing I’ve noticed; the only characters affected by CAPSLOCK are A-Z, and they always hold code values 65-90 and 97-122, regardless of how other buttons might move, or be mapped differently.

Since that Index is constant, theres no need to ask the user for which characters are affected by CAPSLOCK — we already know.  ;)

As for NUMLOCK, Windows itself distinguishes between the 7 and Home, or 6 and right arrow for us.  We don’t have to check those values at all!

So the way it’s being handled in my new format is:

CAPSLOCK — internally, by windows GetScanKey Index.
NUMSLOCK — not at all, as Windows does this distinction for us.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #8 on: December 29, 2019, 09:21:46 pm »
My overhauled system, which might be easier for others to use and adjust for their own needs now:

Code: QB64: [Select]
  1. DECLARE LIBRARY 'function is already used by QB64 so "User32" is not required
  2.     FUNCTION GetKeyState% (BYVAL vkey AS LONG)
  3.  
  4. TYPE KeyboardInfo_Type
  5.     Index AS LONG
  6.     ASCII AS LONG
  7.     Ctrl AS LONG
  8.     Shift AS LONG
  9.     Alt AS LONG
  10.     AltGr AS LONG
  11.     Repeat AS _FLOAT
  12.     LastHit AS _FLOAT
  13.     Down AS LONG
  14.  
  15. DIM SHARED Keys(254) AS KeyboardInfo_Type
  16. Init_KeyCodes
  17. Remap_KeyCode 65, 65, 1, 97, 160, 142, 0.2: 'a
  18.  
  19.     k = KeyHit
  20.     IF k <> 0 THEN
  21.         PRINT k;
  22.         IF ABS(k) < 256 THEN PRINT CHR$(34); CHR$(ABS(k)); CHR$(34) ELSE PRINT
  23.     END IF
  24.  
  25.     _LIMIT 30
  26. LOOP UNTIL k = 27 'escape
  27.  
  28.  
  29. FUNCTION KeyHit&
  30.     STATIC ReturnCount AS INTEGER
  31.     STATIC ReturnValues(30) AS LONG
  32.     IF Keys(1).Index = 0 THEN Init_KeyCodes 'if someone forgets to put the init routine in their code, be certain to initialize the codes before attempting to use them.
  33.  
  34.  
  35.     IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  36.         'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  37.         KeyHit = ReturnValues(1)
  38.         FOR i = 1 TO ReturnCount - 1
  39.             ReturnValues(i) = ReturnValues(i + 1)
  40.         NEXT
  41.         ReturnCount = ReturnCount - 1
  42.         EXIT FUNCTION
  43.     END IF
  44.  
  45.     IF Keys(16).Down THEN Shift = -1 ELSE Shift = 0
  46.     IF Keys(17).Down THEN Ctrl = -1 ELSE Ctrl = 0
  47.     IF Keys(18).Down THEN Alt = -1 ELSE Alt = 0
  48.     IF Ctrl AND Alt THEN AltGr = -1 ELSE AltGr = 0
  49.  
  50.         FOR i = 1 TO 254
  51.  
  52.             r = GetKeyState(Keys(i).Index) AND &H8000
  53.  
  54.             IF r THEN 'the key is down
  55.  
  56.  
  57.                 IF Keys(i).LastHit THEN
  58.                     IF ExtendedTimer > Keys(i).LastHit THEN
  59.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  60.                         ReturnValues(ReturnCount) = Keys(i).Down 'and put the existing value back in the buffer, as a key repeat
  61.                     END IF
  62.                 ELSE
  63.  
  64.                     IF Keys(i).Down = 0 THEN 'the key was up on the last pass.
  65.                         IF AltGr <> 0 AND Keys(i).AltGr <> 0 THEN 'return the altgr value
  66.                             Keys(i).Down = Keys(i).AltGr
  67.                         ELSEIF Shift <> 0 AND Keys(i).Shift <> 0 THEN 'return the shift value
  68.                             Keys(i).Down = Keys(i).Shift
  69.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  70.                                 SELECT CASE i
  71.                                     CASE 65 TO 90, 97 TO 122: Keys(i).Down = Keys(i).ASCII
  72.                                 END SELECT
  73.                             END IF
  74.                         ELSEIF (Ctrl <> 0) AND (Keys(i).Ctrl <> 0) THEN 'return the ctrl value
  75.                             Keys(i).Down = Keys(i).Ctrl
  76.                         ELSEIF Alt <> 0 AND Keys(i).Alt <> 0 THEN 'return the alt value
  77.                             Keys(i).Down = Keys(i).Alt
  78.                         ELSE 'all that's left is to return the ASCII value
  79.                             Keys(i).Down = Keys(i).ASCII
  80.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  81.                                 SELECT CASE i
  82.                                     CASE 65 TO 90, 97 TO 122: Keys(i).Down = Keys(i).Shift
  83.                                 END SELECT
  84.                             END IF
  85.  
  86.                         END IF
  87.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  88.                         ReturnValues(ReturnCount) = Keys(i).Down 'and store the value in the buffer
  89.  
  90.                         IF Keys(i).Repeat = -1 THEN 'keys that are set to a -1 on repeat simply toggle state as on, or off.
  91.                             Keys(i).LastHit = 1E+1000 'such as SHIFT, CTRL, ALT...
  92.                         ELSE
  93.                             Keys(i).LastHit = ExtendedTimer + Keys(i).Repeat 'and record when we hit it for repeat purposes
  94.                         END IF
  95.                     END IF
  96.                 END IF
  97.             ELSE
  98.                 IF Keys(i).Down THEN 'the key was down on the last pass
  99.                     ReturnCount = ReturnCount + 1
  100.                     ReturnValues(ReturnCount) = -Keys(i).Down 'mark it as being up on this one
  101.                 END IF
  102.                 Keys(i).Down = 0 'and set it back down for future passes
  103.                 Keys(i).LastHit = 0 'once again, set it as being ready to be hit again
  104.             END IF
  105.         NEXT
  106.  
  107.         IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  108.             'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  109.             KeyHit = ReturnValues(1)
  110.             FOR i = 1 TO ReturnCount - 1
  111.                 ReturnValues(i) = ReturnValues(i + 1)
  112.             NEXT
  113.             ReturnCount = ReturnCount - 1
  114.             EXIT FUNCTION
  115.         END IF
  116.  
  117.     END IF 'End of IF _WINDOWHASFOCUS
  118.  
  119.  
  120.  
  121.  
  122. SUB Remap_KeyCode (Which AS LONG, ASCII AS LONG, Ctrl AS LONG, Shift AS LONG, Alt AS LONG, AltGr AS LONG, Repeat AS _FLOAT)
  123.     DIM i AS LONG
  124.     i = Which
  125.     Keys(i).Index = i
  126.     Keys(i).ASCII = ASCII
  127.     Keys(i).Ctrl = Ctrl
  128.     Keys(i).Shift = Shift
  129.     Keys(i).Alt = Alt
  130.     Keys(i).AltGr = AltGr
  131.     Keys(i).Repeat = Repeat
  132.     Keys(i).LastHit = 0
  133.     Keys(i).Down = 0
  134.  
  135.  
  136. SUB Init_KeyCodes
  137.     RESTORE default_keyboard_data
  138.     FOR i = 1 TO 254
  139.         READ Keys(i).Index, Keys(i).ASCII, Keys(i).Ctrl, Keys(i).Shift, Keys(i).Alt, Keys(i).AltGr, Keys(i).Repeat
  140.         Keys(i).LastHit = 0: Keys(i).Down = 0
  141.     NEXT
  142.  
  143.     default_keyboard_data:
  144.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  145.     DATA 1,900001,0,0,0,0,0.2:
  146.     DATA 2,900002,0,0,0,0,0.2:
  147.     DATA 3,900003,0,0,0,0,0.2:
  148.     DATA 4,900004,0,0,0,0,0.2:
  149.     DATA 5,900005,0,0,0,0,0.2:
  150.     DATA 6,900006,0,0,0,0,0.2:
  151.     DATA 7,900007,0,0,0,0,0.2: 'Undefined
  152.     DATA 8,8,0,0,0,0,0.2:
  153.     DATA 9,9,0,0,0,0,0.2:
  154.     DATA 10,900010,0,0,0,0,0.2: 'Reserved
  155.     DATA 11,900011,0,0,0,0,0.2: 'Reserved
  156.     DATA 12,19456,0,0,0,0,0.2:
  157.     DATA 13,13,0,0,0,0,0.2:
  158.     DATA 14,900014,0,0,0,0,0.2: 'Undefined
  159.     DATA 15,900015,0,0,0,0,0.2: 'Undefined
  160.     DATA 16,100016,0,0,0,0,-1: 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  161.     DATA 17,100017,0,0,0,0,-1: 'Ctrl   (Same)
  162.     DATA 18,100018,0,0,0,0,-1: 'Alt     (Same)
  163.     DATA 19,100019,0,0,0,0,0.2:
  164.     DATA 20,100301,0,0,0,0,-1: 'Caps Lock
  165.     DATA 21,900021,0,0,0,0,0.2:
  166.     DATA 22,900022,0,0,0,0,0.2: 'Undefined
  167.     DATA 23,900023,0,0,0,0,0.2:
  168.     DATA 24,900024,0,0,0,0,0.2:
  169.     DATA 25,900025,0,0,0,0,0.2:
  170.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  171.     DATA 26,900026,0,0,0,0,0.2: 'Undefined
  172.     DATA 27,27,0,0,0,0,0.2:
  173.     DATA 28,900028,0,0,0,0,0.2:
  174.     DATA 29,900029,0,0,0,0,0.2:
  175.     DATA 30,900030,0,0,0,0,0.2:
  176.     DATA 31,900031,0,0,0,0,0.2:
  177.     DATA 32,32,0,0,0,0,0.2:
  178.     DATA 33,18688,0,0,0,0,0.2:
  179.     DATA 34,20736,0,0,0,0,0.2:
  180.     DATA 35,20224,0,0,0,0,0.2:
  181.     DATA 36,18176,0,0,0,0,0.2:
  182.     DATA 37,19200,0,0,0,0,0.2:
  183.     DATA 38,18432,0,0,0,0,0.2:
  184.     DATA 39,19712,0,0,0,0,0.2:
  185.     DATA 40,20480,0,0,0,0,0.2:
  186.     DATA 41,900041,0,0,0,0,-1:
  187.     DATA 42,900042,0,0,0,0,-1:
  188.     DATA 43,900043,0,0,0,0,-1:
  189.     DATA 44,900044,0,0,0,0,-1:
  190.     DATA 45,20992,0,0,0,0,0.2:
  191.     DATA 46,21248,0,0,0,0,0.2:
  192.     DATA 47,900047,0,0,0,0,0.2: 'VK_HELP
  193.     DATA 48,48,0,41,0,0,0.2: '0
  194.     DATA 49,49,0,33,0,0,0.2: '1
  195.     DATA 50,50,0,64,0,0,0.2: '2
  196.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  197.     DATA 51,51,0,35,0,0,0.2: '3
  198.     DATA 52,52,0,36,0,0,0.2: '4
  199.     DATA 53,53,0,37,0,0,0.2: '5
  200.     DATA 54,54,0,94,0,0,0.2: '6
  201.     DATA 55,55,0,38,0,0,0.2: '7
  202.     DATA 56,56,0,42,0,0,0.2: '8
  203.     DATA 57,57,0,40,0,0,0.2: '9
  204.     DATA 58,900058,0,0,0,0,0.2: 'Undefined
  205.     DATA 59,900059,0,0,0,0,0.2: 'Undefined
  206.     DATA 60,900060,0,0,0,0,0.2: 'Undefined
  207.     DATA 61,900061,0,0,0,0,0.2: 'Undefined
  208.     DATA 62,900062,0,0,0,0,0.2: 'Undefined
  209.     DATA 63,900063,0,0,0,0,0.2: 'Undefined
  210.     DATA 64,900064,0,0,0,0,0.2: 'Undefined
  211.     DATA 65,65,0,97,0,0,0.2: 'a
  212.     DATA 66,66,0,98,0,0,0.2: 'b
  213.     DATA 67,67,0,99,0,0,0.2: 'c
  214.     DATA 68,68,0,100,0,0,0.2: 'd
  215.     DATA 69,69,0,101,0,0,0.2: 'e
  216.     DATA 70,70,0,102,0,0,0.2: 'f
  217.     DATA 71,71,0,103,0,0,0.2: 'g
  218.     DATA 72,72,0,104,0,0,0.2: 'h
  219.     DATA 73,73,0,105,0,0,0.2: 'i
  220.     DATA 74,74,0,106,0,0,0.2: 'j
  221.     DATA 75,75,0,107,0,0,0.2: 'k
  222.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  223.     DATA 76,76,0,108,0,0,0.2: 'l
  224.     DATA 77,77,0,109,0,0,0.2: 'm
  225.     DATA 78,78,0,110,0,0,0.2: 'n
  226.     DATA 79,79,0,111,0,0,0.2: 'o
  227.     DATA 80,80,0,112,0,0,0.2: 'p
  228.     DATA 81,81,0,113,0,0,0.2: 'q
  229.     DATA 82,82,0,114,0,0,0.2: 'r
  230.     DATA 83,83,0,115,0,0,0.2: 's
  231.     DATA 84,84,0,116,0,0,0.2: 't
  232.     DATA 85,85,0,117,0,0,0.2: 'u
  233.     DATA 86,86,0,118,0,0,0.2: 'v
  234.     DATA 87,87,0,119,0,0,0.2: 'w
  235.     DATA 88,88,0,120,0,0,0.2: 'x
  236.     DATA 89,89,0,121,0,0,0.2: 'y
  237.     DATA 90,90,0,122,0,0,0.2: 'z
  238.     DATA 91,100311,0,0,0,0,-1: 'Left WIN
  239.     DATA 92,100312,0,0,0,0,-1: 'Right WIN
  240.     DATA 93,100319,0,0,0,0,-1: 'Applications (Menu)
  241.     DATA 94,900094,0,0,0,0,0.2: 'Reserved
  242.     DATA 95,900095,0,0,0,0,0.2: 'VK_SLEEP
  243.     DATA 96,48,0,0,0,0,0.2: 'Numpad 0
  244.     DATA 97,49,0,0,0,0,0.2: 'Numpad 1
  245.     DATA 98,50,0,0,0,0,0.2: 'Numpad 2
  246.     DATA 99,51,0,0,0,0,0.2: 'Numpad 3
  247.     DATA 100,52,0,0,0,0,0.2: 'Numpad 4
  248.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  249.     DATA 101,53,0,0,0,0,0.2: 'Numpad 5
  250.     DATA 102,54,0,0,0,0,0.2: 'Numpad 6
  251.     DATA 103,55,0,0,0,0,0.2: 'Numpad 7
  252.     DATA 104,56,0,0,0,0,0.2: 'Numpad 8
  253.     DATA 105,57,0,0,0,0,0.2: 'Numpad 9
  254.     DATA 106,42,0,0,0,0,0.2: 'Numpad *
  255.     DATA 107,43,0,0,0,0,0.2: 'Numpad +
  256.     DATA 108,900108,0,0,0,0,0.2: 'VK_SEPARATOR
  257.     DATA 109,51,0,0,0,0,0.2: 'Numpad -
  258.     DATA 110,52,0,0,0,0,0.2: 'Numpad .
  259.     DATA 111,53,0,0,0,0,0.2: 'Numpad /
  260.     DATA 112,15104,0,0,0,0,0.2: 'F1
  261.     DATA 113,15360,0,0,0,0,0.2: 'F2
  262.     DATA 114,15616,0,0,0,0,0.2: 'F3
  263.     DATA 115,15872,0,0,0,0,0.2: 'F4
  264.     DATA 116,16128,0,0,0,0,0.2: 'F5
  265.     DATA 117,16384,0,0,0,0,0.2: 'F6
  266.     DATA 118,16640,0,0,0,0,0.2: 'F7
  267.     DATA 119,16896,0,0,0,0,0.2: 'F8
  268.     DATA 120,17152,0,0,0,0,0.2: 'F9
  269.     DATA 121,17408,0,0,0,0,0.2: 'F10
  270.     DATA 122,34048,0,0,0,0,0.2: 'F11
  271.     DATA 123,34304,0,0,0,0,0.2: 'F12
  272.     DATA 124,900124,0,0,0,0,0.2: 'F13
  273.     DATA 125,900125,0,0,0,0,0.2: 'F14
  274.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  275.     DATA 126,900126,0,0,0,0,0.2: 'F15
  276.     DATA 127,900127,0,0,0,0,0.2: 'F16
  277.     DATA 128,900128,0,0,0,0,0.2: 'F17
  278.     DATA 129,900129,0,0,0,0,0.2: 'F18
  279.     DATA 130,900130,0,0,0,0,0.2: 'F19
  280.     DATA 131,900131,0,0,0,0,0.2: 'F20
  281.     DATA 132,900132,0,0,0,0,0.2: 'F21
  282.     DATA 133,900133,0,0,0,0,0.2: 'F22
  283.     DATA 134,900134,0,0,0,0,0.2: 'F23
  284.     DATA 135,900135,0,0,0,0,0.2: 'F24
  285.     DATA 136,900136,0,0,0,0,0.2: 'Unassigned
  286.     DATA 137,900137,0,0,0,0,0.2: 'Unassigned
  287.     DATA 138,900138,0,0,0,0,0.2: 'Unassigned
  288.     DATA 139,900139,0,0,0,0,0.2: 'Unassigned
  289.     DATA 140,900140,0,0,0,0,0.2: 'Unassigned
  290.     DATA 141,900141,0,0,0,0,0.2: 'Unassigned
  291.     DATA 142,900142,0,0,0,0,0.2: 'Unassigned
  292.     DATA 143,900143,0,0,0,0,0.2: 'Unassigned
  293.     DATA 144,100300,0,0,0,0,-1: 'NUM LOCK
  294.     DATA 145,100302,0,0,0,0,-1: 'SCROLL LOCK
  295.     DATA 146,900146,0,0,0,0,0.2: 'OEM SPECIFIC
  296.     DATA 147,900147,0,0,0,0,0.2: 'OEM SPECIFIC
  297.     DATA 148,900148,0,0,0,0,0.2: 'OEM SPECIFIC
  298.     DATA 149,900149,0,0,0,0,0.2: 'OEM SPECIFIC
  299.     DATA 150,900150,0,0,0,0,0.2: 'OEM SPECIFIC
  300.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  301.     DATA 151,900151,0,0,0,0,0.2: 'Unassigned
  302.     DATA 152,900152,0,0,0,0,0.2: 'Unassigned
  303.     DATA 153,900153,0,0,0,0,0.2: 'Unassigned
  304.     DATA 154,900154,0,0,0,0,0.2: 'Unassigned
  305.     DATA 155,900155,0,0,0,0,0.2: 'Unassigned
  306.     DATA 156,900156,0,0,0,0,0.2: 'Unassigned
  307.     DATA 157,900157,0,0,0,0,0.2: 'Unassigned
  308.     DATA 158,900158,0,0,0,0,0.2: 'Unassigned
  309.     DATA 159,900159,0,0,0,0,0.2: 'Unassigned
  310.     DATA 160,100304,0,0,0,0,-1: 'Left Shift
  311.     DATA 161,100303,0,0,0,0,-1: 'Right Shift
  312.     DATA 162,100306,0,0,0,0,-1: 'Left Control
  313.     DATA 163,100305,0,0,0,0,-1: 'Right Control
  314.     DATA 164,100308,0,0,0,0,-1: 'Left Alt
  315.     DATA 165,100309,0,0,0,0,-1: 'Right Alt
  316.     DATA 166,900166,0,0,0,0,0.2: 'Browser back
  317.     DATA 167,900167,0,0,0,0,0.2: 'Browser forward
  318.     DATA 168,900168,0,0,0,0,0.2: 'Browser refresh
  319.     DATA 169,900169,0,0,0,0,0.2: 'Browser stop
  320.     DATA 170,900170,0,0,0,0,0.2: 'Browser search
  321.     DATA 171,900171,0,0,0,0,0.2: 'Browser favorites
  322.     DATA 172,900172,0,0,0,0,0.2: 'Browser home
  323.     DATA 173,900173,0,0,0,0,0.2: 'Mute
  324.     DATA 174,900174,0,0,0,0,0.2: 'Vol Down
  325.     DATA 175,900175,0,0,0,0,0.2: 'Vol Up
  326.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  327.     DATA 176,900176,0,0,0,0,0.2: 'Media Next
  328.     DATA 177,900177,0,0,0,0,0.2: 'Media prev
  329.     DATA 178,900178,0,0,0,0,0.2: 'Media stop
  330.     DATA 179,900179,0,0,0,0,0.2: 'Media Play/Pause
  331.     DATA 180,900180,0,0,0,0,0.2: 'Launch mail
  332.     DATA 181,900181,0,0,0,0,0.2: 'Launch media select
  333.     DATA 182,900182,0,0,0,0,0.2: 'Launch app1
  334.     DATA 183,900183,0,0,0,0,0.2: 'Launch app2
  335.     DATA 184,900184,0,0,0,0,0.2: 'Reserved
  336.     DATA 185,900185,0,0,0,0,0.2: 'Reserved
  337.     DATA 186,59,0,58,0,0,0.2: ';:
  338.     DATA 187,61,0,43,0,0,0.2: '=+
  339.     DATA 188,44,0,60,0,0,0.2: ',<
  340.     DATA 189,45,0,95,0,0,0.2: '-_
  341.     DATA 190,46,0,62,0,0,0.2: '.>
  342.     DATA 191,47,0,63,0,0,0.2: '/?
  343.     DATA 192,96,0,126,0,0,0.2: '`~
  344.     DATA 193,900193,0,0,0,0,0.2: 'Reserved
  345.     DATA 194,900194,0,0,0,0,0.2: 'Reserved
  346.     DATA 195,900195,0,0,0,0,0.2: 'Reserved
  347.     DATA 196,900196,0,0,0,0,0.2: 'Reserved
  348.     DATA 197,900197,0,0,0,0,0.2: 'Reserved
  349.     DATA 198,900198,0,0,0,0,0.2: 'Reserved
  350.     DATA 199,900199,0,0,0,0,0.2: 'Reserved
  351.     DATA 200,900200,0,0,0,0,0.2: 'Reserved
  352.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  353.     DATA 201,900201,0,0,0,0,0.2: 'Reserved
  354.     DATA 202,900202,0,0,0,0,0.2: 'Reserved
  355.     DATA 203,900203,0,0,0,0,0.2: 'Reserved
  356.     DATA 204,900204,0,0,0,0,0.2: 'Reserved
  357.     DATA 205,900205,0,0,0,0,0.2: 'Reserved
  358.     DATA 206,900206,0,0,0,0,0.2: 'Reserved
  359.     DATA 207,900207,0,0,0,0,0.2: 'Reserved
  360.     DATA 208,900208,0,0,0,0,0.2: 'Reserved
  361.     DATA 209,900209,0,0,0,0,0.2: 'Reserved
  362.     DATA 210,900210,0,0,0,0,0.2: 'Reserved
  363.     DATA 211,900211,0,0,0,0,0.2: 'Reserved
  364.     DATA 212,900212,0,0,0,0,0.2: 'Reserved
  365.     DATA 213,900213,0,0,0,0,0.2: 'Reserved
  366.     DATA 214,900214,0,0,0,0,0.2: 'Reserved
  367.     DATA 215,900215,0,0,0,0,0.2: 'Reserved
  368.     DATA 216,900216,0,0,0,0,0.2: 'Unassigned
  369.     DATA 217,900217,0,0,0,0,0.2: 'Unassigned
  370.     DATA 218,900218,0,0,0,0,0.2: 'Unassigned
  371.     DATA 219,91,0,123,0,0,0.2: '[{
  372.     DATA 220,92,0,124,0,0,0.2: '\|
  373.     DATA 221,93,0,125,0,0,0.2: ']}
  374.     DATA 222,39,0,34,0,0,0.2: ''"
  375.     DATA 223,900223,0,0,0,0,0.2: 'OEM SPECIFIC
  376.     DATA 224,900224,0,0,0,0,0.2: 'Reserved
  377.     DATA 225,900225,0,0,0,0,0.2: 'OEM SPECIFIC d
  378.     DATA 226,900226,0,0,0,0,0.2: 'Either the Angle Bracket key,or Backslash on RT 102-key keyboard
  379.     DATA 227,900227,0,0,0,0,0.2: 'OEM SPECIFIC
  380.     DATA 228,900228,0,0,0,0,0.2: 'OEM SPECIFIC
  381.     DATA 229,900229,0,0,0,0,0.2: 'IME PROCESS key (whatever that is)
  382.     DATA 230,900230,0,0,0,0,0.2: 'OEM SPECIFIC
  383.     DATA 231,900231,0,0,0,0,0.2: 'Used to pass UNICODE characters (however that works)
  384.     DATA 232,900232,0,0,0,0,0.2: 'Unassigned
  385.     DATA 233,900233,0,0,0,0,0.2: 'OEM SPECIFIC
  386.     DATA 234,900234,0,0,0,0,0.2: 'OEM SPECIFIC
  387.     DATA 235,900235,0,0,0,0,0.2: 'OEM SPECIFIC
  388.     DATA 236,900236,0,0,0,0,0.2: 'OEM SPECIFIC
  389.     DATA 237,900237,0,0,0,0,0.2: 'OEM SPECIFIC
  390.     DATA 238,900238,0,0,0,0,0.2: 'OEM SPECIFIC
  391.     DATA 239,900239,0,0,0,0,0.2: 'OEM SPECIFIC
  392.     DATA 240,900240,0,0,0,0,0.2: 'OEM SPECIFIC
  393.     DATA 241,900241,0,0,0,0,0.2: 'OEM SPECIFIC
  394.     DATA 242,900242,0,0,0,0,0.2: 'OEM SPECIFIC
  395.     DATA 243,900243,0,0,0,0,0.2: 'OEM SPECIFIC
  396.     DATA 244,900244,0,0,0,0,0.2: 'OEM SPECIFIC
  397.     DATA 245,900245,0,0,0,0,0.2: 'OEM SPECIFIC
  398.     DATA 246,900246,0,0,0,0,0.2: 'VK_ATTN
  399.     DATA 247,900247,0,0,0,0,0.2: 'VK_ATTN
  400.     DATA 248,900248,0,0,0,0,0.2: 'VK_ATTN
  401.     DATA 249,900249,0,0,0,0,0.2: 'VK_ATTN
  402.     DATA 250,900250,0,0,0,0,0.2: 'VK_ATTN
  403.     DATA 251,900251,0,0,0,0,0.2: 'VK_ATTN
  404.     DATA 252,900252,0,0,0,0,0.2: 'Reserved
  405.     DATA 253,900253,0,0,0,0,0.2: 'VK_PA1
  406.     DATA 254,900253,0,0,0,0,0.2: 'VK_OEM_CLEAR
  407.     DATA 0,0,0,0,0,0,0.2: 'END OF DATA
  408.  
  409.  
  410.  
  411. FUNCTION ExtendedTimer##
  412.     'modified extendedtimer to store the old day's count, and not have to recalculate it every time the routine is called.
  413.  
  414.     STATIC olds AS _FLOAT, old_day AS _FLOAT
  415.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  416.     DIM s AS _FLOAT, day AS STRING
  417.     IF olds = 0 THEN 'calculate the day the first time the extended timer runs
  418.         day = DATE$
  419.         m = VAL(LEFT$(day, 2))
  420.         d = VAL(MID$(day, 4, 2))
  421.         y = VAL(RIGHT$(day, 4)) - 1970
  422.         SELECT CASE m 'Add the number of days for each previous month passed
  423.             CASE 2: d = d + 31
  424.             CASE 3: d = d + 59
  425.             CASE 4: d = d + 90
  426.             CASE 5: d = d + 120
  427.             CASE 6: d = d + 151
  428.             CASE 7: d = d + 181
  429.             CASE 8: d = d + 212
  430.             CASE 9: d = d + 243
  431.             CASE 10: d = d + 273
  432.             CASE 11: d = d + 304
  433.             CASE 12: d = d + 334
  434.         END SELECT
  435.         IF (y MOD 4) = 2 AND m > 2 THEN d = d + 1 'add a day if this is leap year and we're past february
  436.         d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  437.         d = d + (y + 2) \ 4 'add in days for leap years passed
  438.         s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  439.         old_day = s
  440.     END IF
  441.     IF TIMER < oldt THEN 'we went from 23:59:59 (a second before midnight) to 0:0:0 (midnight)
  442.         old_day = s + 83400 'add another worth of seconds to our counter
  443.     END IF
  444.     oldt = TIMER
  445.     olds = old_day + oldt
  446.     ExtendedTimer## = olds
  447.  
  448.  


If you look close, you'll notice that I'm doing things a little simpler this time around, now that I've sorted out more-or-less what I'd like the code to do.  The biggest thing a user would need to do here is pay attention to these two commands which I highlight for your attention:

Code: [Select]
Init_KeyCodes
Remap_KeyCode 65, 65, 1, 97, 160, 142, 0.2: 'a

First we need to initialize all the keycodes to what we'd normally find with a US keyboard.  That's done via the Init_Keycodes routine (optional to call, as we'll do it automatically if it's not included, but remapping may not work properly for you unless you just want to manually map the whole key system yourself).  If you want to remap keys, please remember to initialize them first.

Second, we have a simple Remap_KeyCode routine, which we can now use to remap those keys to give us whatever returns we might possibly desire.  In this case, I remapped "A" to give me all sorts of input values:

Natural A = "A"
Ctrl-A = CHR$(1)
Shift-A = "a"
Alt-A = CHR$(160)
AltGr-A = CHR$(142)

Should your keyboard give you results which don't match expected values, I'd suggest doing two things:

1) First, check the original values and make certain I didn't make a typo in there.  That's a lot of data to manually enter, and I'm human.  I won't swear there isn't something or other in there with a missing digit, improper value, or typo.  If you do find one of those things, kindly inform me of them so I can correct them for my own library and future use.

2) Once you're certain the original data is glitch free, (or at least as certain as you can be), feel free to remap the character to whatever you need it to represent.  If you take time to remap a whole keyboard/language, kindly share it with us.  I'll collect all the user's mappings and save them in a library file with the main code here, and then others can just select which mapping they need and be good to go in the future. 



Me personally, I might remap some rather useful extended ASCII characters to use for my input needs.  I don't use the numpad very often, so CTRL-numpad keys might make for a nice way to enter the ASCII codes for drawing single and double lines, for some of my personal projects.  ;)
« Last Edit: December 30, 2019, 10:34:14 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: Programmable Keyboard Input
« Reply #9 on: December 30, 2019, 09:20:56 am »
Well Steve, this remapping seems to work pretty well.
However, please check the way how you obtain the modifiers. I still get AltGr chars when pressing either CTRL and ALT together, I told you that AltGr is not equal to any arbitrary CTRL+ALT combo, but to LEFT-CTRL + RIGHT-ALT only. Every other CTRL/ALT combo is no AltGr. And if AltGr is detected, then it's AltGr only, no regular ALT anymore.

Code: QB64: [Select]
  1. '--- get modifiers ---
  2. shift% = _KEYDOWN(100303) OR _KEYDOWN(100304)
  3. ctrl% = _KEYDOWN(100305) OR _KEYDOWN(100306)
  4. altgr% = _KEYDOWN(100307) AND _KEYDOWN(100306)
  5. alt% = (_KEYDOWN(100307) OR _KEYDOWN(100308)) AND NOT altgr%
  6.  

will be back, when DE remapping is finished...
« Last Edit: November 21, 2020, 08:50:58 am by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Programmable Keyboard Input
« Reply #10 on: December 30, 2019, 09:36:36 am »
Very good for internal managment of CapsLock and NumLock!

Now that it seems to be at final version of your code I'll build IT sub initialization for IT keyboard.
Programming isn't difficult, only it's  consuming time and coffee

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #11 on: December 30, 2019, 10:11:42 am »
Well Steve, this remapping seems to work pretty well.
However, please check the way how you obtain the modifiers. I still get AltGr chars when pressing either CTRL and ALT together, I told you that AltGr is not equal to any arbitrary CTRL+ALT combo, but to LEFT-CTRL + RIGHT-ALT only. Every other CTRL/ALT combo is no AltGr. And if AltGr is detected, then it's AltGr only, no regular ALT anymore.

Code: QB64: [Select]
  1. '--- get modifiers ---
  2. shift% = _KEYDOWN(100303) OR _KEYDOWN(100304)
  3. ctrl% = _KEYDOWN(100305) OR _KEYDOWN(100306)
  4. altgr% = _KEYDOWN(100307) AND _KEYDOWN(100306)
  5. alt% = (_KEYDOWN(100307) OR _KEYDOWN(100308)) AND NOT altgr%
  6.  

will be back, when DE remapping is finished...

Change here is rather simple, just make the internal line:

IF Keys(165).Down AND Keys(162).Down THEN AltGr = -1 ELSE AltGr = 0



Wiki explains the keys to us, here: https://en.wikipedia.org/wiki/AltGr_key

Quote
The right Alt key is usually an equivalent of the AltGr key because both the right Alt key and the AltGr key share the same scancode and are indistinguishable by software.  However, on some keyboards it may not be the case, i.e. the keyboard has two Alt keys, each of which acts as the left Alt key. On compact keyboards like those of netbooks, the right Alt key may be missing altogether. To allow the specific functionality of AltGr when typing non-English text on such keyboards, Windows allows it to be emulated by pressing the Alt key together with the Control key:

Ctrl+Alt ≈ AltGr

This seems to indicate that Right-Alt = AltGr (and Windows on screen keyboard reads it as such), and that Alt + Control are only used as a substitute when the Right-Alt is unavailable.

Perhaps we’d be best suited to either use Keys(165) alone as the AltGr (right alt = AltGr), or else I should just make it a customizable configuration that users can set to their personal needs/taste.  After all, we allow the remapping of everything else, if we want to...
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Programmable Keyboard Input
« Reply #12 on: December 30, 2019, 10:32:47 am »
See if this works better for you, Rho:

Code: QB64: [Select]
  1. DECLARE LIBRARY 'function is already used by QB64 so "User32" is not required
  2.     FUNCTION GetKeyState% (BYVAL vkey AS LONG)
  3.  
  4. TYPE KeyboardInfo_Type
  5.     Index AS LONG
  6.     ASCII AS LONG
  7.     Ctrl AS LONG
  8.     Shift AS LONG
  9.     Alt AS LONG
  10.     AltGr AS LONG
  11.     Repeat AS _FLOAT
  12.     LastHit AS _FLOAT
  13.     Down AS LONG
  14.  
  15. DIM SHARED Keys(254) AS KeyboardInfo_Type
  16. Init_KeyCodes
  17. Remap_KeyCode 65, 65, 1, 97, 160, 142, 0.2: 'a
  18.  
  19.     k = KeyHit
  20.     IF k <> 0 THEN
  21.         PRINT k;
  22.         IF ABS(k) < 256 THEN PRINT CHR$(34); CHR$(ABS(k)); CHR$(34) ELSE PRINT
  23.     END IF
  24.  
  25.     _LIMIT 30
  26. LOOP UNTIL k = 27 'escape
  27.  
  28. SUB SetAltGr (Key1 AS INTEGER, Key2 AS INTEGER)
  29.     AltGr(0) = Key1 'any key from our index (0 says no key)
  30.     AltGr(1) = Key2 'PLUS any other key from our index (0 says no additional key)
  31.     'Using this, we can set AltGr to become several things.
  32.     'AltGr(0) = 165, AltGr(1) = 0 -- This would say we're using the RIGHT Alt key (alone) to simulate the AltGr key.  (Windows Onscreen Keyboard does this.)
  33.     'AltGr(0) = 17, AltGr(1) = 18 -- This would use any CTRL-ALT combo to simulate a AltGr keypress.
  34.     'Some useful values are listed for quick reference below
  35.     '0 = NoKey
  36.     '17 = ANY Ctrl
  37.     '18 = ANY Alt
  38.     '162 = Left Control
  39.     '163 = Right Control
  40.     '164 = Left Alt
  41.     '165 = Right Alt
  42.  
  43.     'Default is for AltGr(0) = 165, AltGr(1) = 0, which uses Right-Alt alone as the AltGr key.
  44.     'Feel free to customize the setting to your personal preference/need.
  45.  
  46. FUNCTION KeyHit&
  47.     STATIC ReturnCount AS INTEGER
  48.     STATIC ReturnValues(30) AS LONG
  49.     'IF Keys(1).Index = 0 THEN Init_KeyCodes 'if someone forgets to put the init routine in their code, be certain to initialize the codes before attempting to use them.
  50.  
  51.  
  52.     IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  53.         'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  54.         KeyHit = ReturnValues(1)
  55.         FOR i = 1 TO ReturnCount - 1
  56.             ReturnValues(i) = ReturnValues(i + 1)
  57.         NEXT
  58.         ReturnCount = ReturnCount - 1
  59.         EXIT FUNCTION
  60.     END IF
  61.  
  62.     IF Keys(16).Down THEN Shift = -1 ELSE Shift = 0
  63.     IF Keys(17).Down THEN Ctrl = -1 ELSE Ctrl = 0
  64.     IF Keys(18).Down THEN Alt = -1 ELSE Alt = 0
  65.     IF AltGr(0) <> 0 AND AltGr(1) <> 0 THEN
  66.         IF Keys(AltGr(0)).Down AND Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  67.     ELSEIF AltGr(1) <> 0 THEN
  68.         IF Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  69.     ELSEIF AltGr(0) <> 0 THEN
  70.         IF Keys(0).Down THEN AltGr = -1 ELSE AltGr = 0
  71.     ELSE
  72.         AltGr = 0
  73.     END IF
  74.  
  75.  
  76.  
  77.         FOR i = 1 TO 254
  78.  
  79.             r = GetKeyState(Keys(i).Index) AND &H8000
  80.  
  81.             IF r THEN 'the key is down
  82.  
  83.  
  84.                 IF Keys(i).LastHit THEN
  85.                     IF ExtendedTimer > Keys(i).LastHit THEN
  86.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  87.                         ReturnValues(ReturnCount) = Keys(i).Down 'and put the existing value back in the buffer, as a key repeat
  88.                     END IF
  89.                 ELSE
  90.  
  91.                     IF Keys(i).Down = 0 THEN 'the key was up on the last pass.
  92.                         IF AltGr <> 0 AND Keys(i).AltGr <> 0 THEN 'return the altgr value
  93.                             Keys(i).Down = Keys(i).AltGr
  94.                         ELSEIF Shift <> 0 AND Keys(i).Shift <> 0 THEN 'return the shift value
  95.                             Keys(i).Down = Keys(i).Shift
  96.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  97.                                 SELECT CASE i
  98.                                     CASE 65 TO 90, 97 TO 122: Keys(i).Down = Keys(i).ASCII
  99.                                 END SELECT
  100.                             END IF
  101.                         ELSEIF (Ctrl <> 0) AND (Keys(i).Ctrl <> 0) THEN 'return the ctrl value
  102.                             Keys(i).Down = Keys(i).Ctrl
  103.                         ELSEIF Alt <> 0 AND Keys(i).Alt <> 0 THEN 'return the alt value
  104.                             Keys(i).Down = Keys(i).Alt
  105.                         ELSE 'all that's left is to return the ASCII value
  106.                             Keys(i).Down = Keys(i).ASCII
  107.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  108.                                 SELECT CASE i
  109.                                     CASE 65 TO 90, 97 TO 122: Keys(i).Down = Keys(i).Shift
  110.                                 END SELECT
  111.                             END IF
  112.                         END IF
  113.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  114.                         ReturnValues(ReturnCount) = Keys(i).Down 'and store the value in the buffer
  115.  
  116.                         IF Keys(i).Repeat = -1 THEN 'keys that are set to a -1 on repeat simply toggle state as on, or off.
  117.                             Keys(i).LastHit = 1E+1000 'such as SHIFT, CTRL, ALT...
  118.                         ELSE
  119.                             Keys(i).LastHit = ExtendedTimer + Keys(i).Repeat 'and record when we hit it for repeat purposes
  120.                         END IF
  121.                     END IF
  122.                 END IF
  123.             ELSE
  124.                 IF Keys(i).Down THEN 'the key was down on the last pass
  125.                     ReturnCount = ReturnCount + 1
  126.                     ReturnValues(ReturnCount) = -Keys(i).Down 'mark it as being up on this one
  127.                 END IF
  128.                 Keys(i).Down = 0 'and set it back down for future passes
  129.                 Keys(i).LastHit = 0 'once again, set it as being ready to be hit again
  130.             END IF
  131.         NEXT
  132.  
  133.         IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  134.             'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  135.             KeyHit = ReturnValues(1)
  136.             FOR i = 1 TO ReturnCount - 1
  137.                 ReturnValues(i) = ReturnValues(i + 1)
  138.             NEXT
  139.             ReturnCount = ReturnCount - 1
  140.             EXIT FUNCTION
  141.         END IF
  142.  
  143.     END IF 'End of IF _WINDOWHASFOCUS
  144.  
  145.  
  146.  
  147.  
  148. SUB Remap_KeyCode (Which AS LONG, ASCII AS LONG, Ctrl AS LONG, Shift AS LONG, Alt AS LONG, AltGr AS LONG, Repeat AS _FLOAT)
  149.     DIM i AS LONG
  150.     i = Which
  151.     Keys(i).Index = i
  152.     Keys(i).ASCII = ASCII
  153.     Keys(i).Ctrl = Ctrl
  154.     Keys(i).Shift = Shift
  155.     Keys(i).Alt = Alt
  156.     Keys(i).AltGr = AltGr
  157.     Keys(i).Repeat = Repeat
  158.     Keys(i).LastHit = 0
  159.     Keys(i).Down = 0
  160.  
  161.  
  162. SUB Init_KeyCodes
  163.     RESTORE default_keyboard_data
  164.     FOR i = 1 TO 254
  165.         READ Keys(i).Index, Keys(i).ASCII, Keys(i).Ctrl, Keys(i).Shift, Keys(i).Alt, Keys(i).AltGr, Keys(i).Repeat
  166.         Keys(i).LastHit = 0: Keys(i).Down = 0
  167.     NEXT
  168.  
  169.     default_keyboard_data:
  170.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  171.     DATA 1,900001,0,0,0,0,0.2:
  172.     DATA 2,900002,0,0,0,0,0.2:
  173.     DATA 3,900003,0,0,0,0,0.2:
  174.     DATA 4,900004,0,0,0,0,0.2:
  175.     DATA 5,900005,0,0,0,0,0.2:
  176.     DATA 6,900006,0,0,0,0,0.2:
  177.     DATA 7,900007,0,0,0,0,0.2: 'Undefined
  178.     DATA 8,8,0,0,0,0,0.2:
  179.     DATA 9,9,0,0,0,0,0.2:
  180.     DATA 10,900010,0,0,0,0,0.2: 'Reserved
  181.     DATA 11,900011,0,0,0,0,0.2: 'Reserved
  182.     DATA 12,19456,0,0,0,0,0.2:
  183.     DATA 13,13,0,0,0,0,0.2:
  184.     DATA 14,900014,0,0,0,0,0.2: 'Undefined
  185.     DATA 15,900015,0,0,0,0,0.2: 'Undefined
  186.     DATA 16,100016,0,0,0,0,-1: 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  187.     DATA 17,100017,0,0,0,0,-1: 'Ctrl   (Same)
  188.     DATA 18,100018,0,0,0,0,-1: 'Alt     (Same)
  189.     DATA 19,100019,0,0,0,0,0.2:
  190.     DATA 20,100301,0,0,0,0,-1: 'Caps Lock
  191.     DATA 21,900021,0,0,0,0,0.2:
  192.     DATA 22,900022,0,0,0,0,0.2: 'Undefined
  193.     DATA 23,900023,0,0,0,0,0.2:
  194.     DATA 24,900024,0,0,0,0,0.2:
  195.     DATA 25,900025,0,0,0,0,0.2:
  196.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  197.     DATA 26,900026,0,0,0,0,0.2: 'Undefined
  198.     DATA 27,27,0,0,0,0,0.2:
  199.     DATA 28,900028,0,0,0,0,0.2:
  200.     DATA 29,900029,0,0,0,0,0.2:
  201.     DATA 30,900030,0,0,0,0,0.2:
  202.     DATA 31,900031,0,0,0,0,0.2:
  203.     DATA 32,32,0,0,0,0,0.2:
  204.     DATA 33,18688,0,0,0,0,0.2:
  205.     DATA 34,20736,0,0,0,0,0.2:
  206.     DATA 35,20224,0,0,0,0,0.2:
  207.     DATA 36,18176,0,0,0,0,0.2:
  208.     DATA 37,19200,0,0,0,0,0.2:
  209.     DATA 38,18432,0,0,0,0,0.2:
  210.     DATA 39,19712,0,0,0,0,0.2:
  211.     DATA 40,20480,0,0,0,0,0.2:
  212.     DATA 41,900041,0,0,0,0,-1:
  213.     DATA 42,900042,0,0,0,0,-1:
  214.     DATA 43,900043,0,0,0,0,-1:
  215.     DATA 44,900044,0,0,0,0,-1:
  216.     DATA 45,20992,0,0,0,0,0.2:
  217.     DATA 46,21248,0,0,0,0,0.2:
  218.     DATA 47,900047,0,0,0,0,0.2: 'VK_HELP
  219.     DATA 48,48,0,41,0,0,0.2: '0
  220.     DATA 49,49,0,33,0,0,0.2: '1
  221.     DATA 50,50,0,64,0,0,0.2: '2
  222.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  223.     DATA 51,51,0,35,0,0,0.2: '3
  224.     DATA 52,52,0,36,0,0,0.2: '4
  225.     DATA 53,53,0,37,0,0,0.2: '5
  226.     DATA 54,54,0,94,0,0,0.2: '6
  227.     DATA 55,55,0,38,0,0,0.2: '7
  228.     DATA 56,56,0,42,0,0,0.2: '8
  229.     DATA 57,57,0,40,0,0,0.2: '9
  230.     DATA 58,900058,0,0,0,0,0.2: 'Undefined
  231.     DATA 59,900059,0,0,0,0,0.2: 'Undefined
  232.     DATA 60,900060,0,0,0,0,0.2: 'Undefined
  233.     DATA 61,900061,0,0,0,0,0.2: 'Undefined
  234.     DATA 62,900062,0,0,0,0,0.2: 'Undefined
  235.     DATA 63,900063,0,0,0,0,0.2: 'Undefined
  236.     DATA 64,900064,0,0,0,0,0.2: 'Undefined
  237.     DATA 65,65,0,97,0,0,0.2: 'a
  238.     DATA 66,66,0,98,0,0,0.2: 'b
  239.     DATA 67,67,0,99,0,0,0.2: 'c
  240.     DATA 68,68,0,100,0,0,0.2: 'd
  241.     DATA 69,69,0,101,0,0,0.2: 'e
  242.     DATA 70,70,0,102,0,0,0.2: 'f
  243.     DATA 71,71,0,103,0,0,0.2: 'g
  244.     DATA 72,72,0,104,0,0,0.2: 'h
  245.     DATA 73,73,0,105,0,0,0.2: 'i
  246.     DATA 74,74,0,106,0,0,0.2: 'j
  247.     DATA 75,75,0,107,0,0,0.2: 'k
  248.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  249.     DATA 76,76,0,108,0,0,0.2: 'l
  250.     DATA 77,77,0,109,0,0,0.2: 'm
  251.     DATA 78,78,0,110,0,0,0.2: 'n
  252.     DATA 79,79,0,111,0,0,0.2: 'o
  253.     DATA 80,80,0,112,0,0,0.2: 'p
  254.     DATA 81,81,0,113,0,0,0.2: 'q
  255.     DATA 82,82,0,114,0,0,0.2: 'r
  256.     DATA 83,83,0,115,0,0,0.2: 's
  257.     DATA 84,84,0,116,0,0,0.2: 't
  258.     DATA 85,85,0,117,0,0,0.2: 'u
  259.     DATA 86,86,0,118,0,0,0.2: 'v
  260.     DATA 87,87,0,119,0,0,0.2: 'w
  261.     DATA 88,88,0,120,0,0,0.2: 'x
  262.     DATA 89,89,0,121,0,0,0.2: 'y
  263.     DATA 90,90,0,122,0,0,0.2: 'z
  264.     DATA 91,100311,0,0,0,0,-1: 'Left WIN
  265.     DATA 92,100312,0,0,0,0,-1: 'Right WIN
  266.     DATA 93,100319,0,0,0,0,-1: 'Applications (Menu)
  267.     DATA 94,900094,0,0,0,0,0.2: 'Reserved
  268.     DATA 95,900095,0,0,0,0,0.2: 'VK_SLEEP
  269.     DATA 96,48,0,0,0,0,0.2: 'Numpad 0
  270.     DATA 97,49,0,0,0,0,0.2: 'Numpad 1
  271.     DATA 98,50,0,0,0,0,0.2: 'Numpad 2
  272.     DATA 99,51,0,0,0,0,0.2: 'Numpad 3
  273.     DATA 100,52,0,0,0,0,0.2: 'Numpad 4
  274.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  275.     DATA 101,53,0,0,0,0,0.2: 'Numpad 5
  276.     DATA 102,54,0,0,0,0,0.2: 'Numpad 6
  277.     DATA 103,55,0,0,0,0,0.2: 'Numpad 7
  278.     DATA 104,56,0,0,0,0,0.2: 'Numpad 8
  279.     DATA 105,57,0,0,0,0,0.2: 'Numpad 9
  280.     DATA 106,42,0,0,0,0,0.2: 'Numpad *
  281.     DATA 107,43,0,0,0,0,0.2: 'Numpad +
  282.     DATA 108,900108,0,0,0,0,0.2: 'VK_SEPARATOR
  283.     DATA 109,51,0,0,0,0,0.2: 'Numpad -
  284.     DATA 110,52,0,0,0,0,0.2: 'Numpad .
  285.     DATA 111,53,0,0,0,0,0.2: 'Numpad /
  286.     DATA 112,15104,0,0,0,0,0.2: 'F1
  287.     DATA 113,15360,0,0,0,0,0.2: 'F2
  288.     DATA 114,15616,0,0,0,0,0.2: 'F3
  289.     DATA 115,15872,0,0,0,0,0.2: 'F4
  290.     DATA 116,16128,0,0,0,0,0.2: 'F5
  291.     DATA 117,16384,0,0,0,0,0.2: 'F6
  292.     DATA 118,16640,0,0,0,0,0.2: 'F7
  293.     DATA 119,16896,0,0,0,0,0.2: 'F8
  294.     DATA 120,17152,0,0,0,0,0.2: 'F9
  295.     DATA 121,17408,0,0,0,0,0.2: 'F10
  296.     DATA 122,34048,0,0,0,0,0.2: 'F11
  297.     DATA 123,34304,0,0,0,0,0.2: 'F12
  298.     DATA 124,900124,0,0,0,0,0.2: 'F13
  299.     DATA 125,900125,0,0,0,0,0.2: 'F14
  300.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  301.     DATA 126,900126,0,0,0,0,0.2: 'F15
  302.     DATA 127,900127,0,0,0,0,0.2: 'F16
  303.     DATA 128,900128,0,0,0,0,0.2: 'F17
  304.     DATA 129,900129,0,0,0,0,0.2: 'F18
  305.     DATA 130,900130,0,0,0,0,0.2: 'F19
  306.     DATA 131,900131,0,0,0,0,0.2: 'F20
  307.     DATA 132,900132,0,0,0,0,0.2: 'F21
  308.     DATA 133,900133,0,0,0,0,0.2: 'F22
  309.     DATA 134,900134,0,0,0,0,0.2: 'F23
  310.     DATA 135,900135,0,0,0,0,0.2: 'F24
  311.     DATA 136,900136,0,0,0,0,0.2: 'Unassigned
  312.     DATA 137,900137,0,0,0,0,0.2: 'Unassigned
  313.     DATA 138,900138,0,0,0,0,0.2: 'Unassigned
  314.     DATA 139,900139,0,0,0,0,0.2: 'Unassigned
  315.     DATA 140,900140,0,0,0,0,0.2: 'Unassigned
  316.     DATA 141,900141,0,0,0,0,0.2: 'Unassigned
  317.     DATA 142,900142,0,0,0,0,0.2: 'Unassigned
  318.     DATA 143,900143,0,0,0,0,0.2: 'Unassigned
  319.     DATA 144,100300,0,0,0,0,-1: 'NUM LOCK
  320.     DATA 145,100302,0,0,0,0,-1: 'SCROLL LOCK
  321.     DATA 146,900146,0,0,0,0,0.2: 'OEM SPECIFIC
  322.     DATA 147,900147,0,0,0,0,0.2: 'OEM SPECIFIC
  323.     DATA 148,900148,0,0,0,0,0.2: 'OEM SPECIFIC
  324.     DATA 149,900149,0,0,0,0,0.2: 'OEM SPECIFIC
  325.     DATA 150,900150,0,0,0,0,0.2: 'OEM SPECIFIC
  326.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  327.     DATA 151,900151,0,0,0,0,0.2: 'Unassigned
  328.     DATA 152,900152,0,0,0,0,0.2: 'Unassigned
  329.     DATA 153,900153,0,0,0,0,0.2: 'Unassigned
  330.     DATA 154,900154,0,0,0,0,0.2: 'Unassigned
  331.     DATA 155,900155,0,0,0,0,0.2: 'Unassigned
  332.     DATA 156,900156,0,0,0,0,0.2: 'Unassigned
  333.     DATA 157,900157,0,0,0,0,0.2: 'Unassigned
  334.     DATA 158,900158,0,0,0,0,0.2: 'Unassigned
  335.     DATA 159,900159,0,0,0,0,0.2: 'Unassigned
  336.     DATA 160,100304,0,0,0,0,-1: 'Left Shift
  337.     DATA 161,100303,0,0,0,0,-1: 'Right Shift
  338.     DATA 162,100306,0,0,0,0,-1: 'Left Control
  339.     DATA 163,100305,0,0,0,0,-1: 'Right Control
  340.     DATA 164,100308,0,0,0,0,-1: 'Left Alt
  341.     DATA 165,100309,0,0,0,0,-1: 'Right Alt
  342.     DATA 166,900166,0,0,0,0,0.2: 'Browser back
  343.     DATA 167,900167,0,0,0,0,0.2: 'Browser forward
  344.     DATA 168,900168,0,0,0,0,0.2: 'Browser refresh
  345.     DATA 169,900169,0,0,0,0,0.2: 'Browser stop
  346.     DATA 170,900170,0,0,0,0,0.2: 'Browser search
  347.     DATA 171,900171,0,0,0,0,0.2: 'Browser favorites
  348.     DATA 172,900172,0,0,0,0,0.2: 'Browser home
  349.     DATA 173,900173,0,0,0,0,0.2: 'Mute
  350.     DATA 174,900174,0,0,0,0,0.2: 'Vol Down
  351.     DATA 175,900175,0,0,0,0,0.2: 'Vol Up
  352.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  353.     DATA 176,900176,0,0,0,0,0.2: 'Media Next
  354.     DATA 177,900177,0,0,0,0,0.2: 'Media prev
  355.     DATA 178,900178,0,0,0,0,0.2: 'Media stop
  356.     DATA 179,900179,0,0,0,0,0.2: 'Media Play/Pause
  357.     DATA 180,900180,0,0,0,0,0.2: 'Launch mail
  358.     DATA 181,900181,0,0,0,0,0.2: 'Launch media select
  359.     DATA 182,900182,0,0,0,0,0.2: 'Launch app1
  360.     DATA 183,900183,0,0,0,0,0.2: 'Launch app2
  361.     DATA 184,900184,0,0,0,0,0.2: 'Reserved
  362.     DATA 185,900185,0,0,0,0,0.2: 'Reserved
  363.     DATA 186,59,0,58,0,0,0.2: ';:
  364.     DATA 187,61,0,43,0,0,0.2: '=+
  365.     DATA 188,44,0,60,0,0,0.2: ',<
  366.     DATA 189,45,0,95,0,0,0.2: '-_
  367.     DATA 190,46,0,62,0,0,0.2: '.>
  368.     DATA 191,47,0,63,0,0,0.2: '/?
  369.     DATA 192,96,0,126,0,0,0.2: '`~
  370.     DATA 193,900193,0,0,0,0,0.2: 'Reserved
  371.     DATA 194,900194,0,0,0,0,0.2: 'Reserved
  372.     DATA 195,900195,0,0,0,0,0.2: 'Reserved
  373.     DATA 196,900196,0,0,0,0,0.2: 'Reserved
  374.     DATA 197,900197,0,0,0,0,0.2: 'Reserved
  375.     DATA 198,900198,0,0,0,0,0.2: 'Reserved
  376.     DATA 199,900199,0,0,0,0,0.2: 'Reserved
  377.     DATA 200,900200,0,0,0,0,0.2: 'Reserved
  378.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  379.     DATA 201,900201,0,0,0,0,0.2: 'Reserved
  380.     DATA 202,900202,0,0,0,0,0.2: 'Reserved
  381.     DATA 203,900203,0,0,0,0,0.2: 'Reserved
  382.     DATA 204,900204,0,0,0,0,0.2: 'Reserved
  383.     DATA 205,900205,0,0,0,0,0.2: 'Reserved
  384.     DATA 206,900206,0,0,0,0,0.2: 'Reserved
  385.     DATA 207,900207,0,0,0,0,0.2: 'Reserved
  386.     DATA 208,900208,0,0,0,0,0.2: 'Reserved
  387.     DATA 209,900209,0,0,0,0,0.2: 'Reserved
  388.     DATA 210,900210,0,0,0,0,0.2: 'Reserved
  389.     DATA 211,900211,0,0,0,0,0.2: 'Reserved
  390.     DATA 212,900212,0,0,0,0,0.2: 'Reserved
  391.     DATA 213,900213,0,0,0,0,0.2: 'Reserved
  392.     DATA 214,900214,0,0,0,0,0.2: 'Reserved
  393.     DATA 215,900215,0,0,0,0,0.2: 'Reserved
  394.     DATA 216,900216,0,0,0,0,0.2: 'Unassigned
  395.     DATA 217,900217,0,0,0,0,0.2: 'Unassigned
  396.     DATA 218,900218,0,0,0,0,0.2: 'Unassigned
  397.     DATA 219,91,0,123,0,0,0.2: '[{
  398.     DATA 220,92,0,124,0,0,0.2: '\|
  399.     DATA 221,93,0,125,0,0,0.2: ']}
  400.     DATA 222,39,0,34,0,0,0.2: ''"
  401.     DATA 223,900223,0,0,0,0,0.2: 'OEM SPECIFIC
  402.     DATA 224,900224,0,0,0,0,0.2: 'Reserved
  403.     DATA 225,900225,0,0,0,0,0.2: 'OEM SPECIFIC d
  404.     DATA 226,900226,0,0,0,0,0.2: 'Either the Angle Bracket key,or Backslash on RT 102-key keyboard
  405.     DATA 227,900227,0,0,0,0,0.2: 'OEM SPECIFIC
  406.     DATA 228,900228,0,0,0,0,0.2: 'OEM SPECIFIC
  407.     DATA 229,900229,0,0,0,0,0.2: 'IME PROCESS key (whatever that is)
  408.     DATA 230,900230,0,0,0,0,0.2: 'OEM SPECIFIC
  409.     DATA 231,900231,0,0,0,0,0.2: 'Used to pass UNICODE characters (however that works)
  410.     DATA 232,900232,0,0,0,0,0.2: 'Unassigned
  411.     DATA 233,900233,0,0,0,0,0.2: 'OEM SPECIFIC
  412.     DATA 234,900234,0,0,0,0,0.2: 'OEM SPECIFIC
  413.     DATA 235,900235,0,0,0,0,0.2: 'OEM SPECIFIC
  414.     DATA 236,900236,0,0,0,0,0.2: 'OEM SPECIFIC
  415.     DATA 237,900237,0,0,0,0,0.2: 'OEM SPECIFIC
  416.     DATA 238,900238,0,0,0,0,0.2: 'OEM SPECIFIC
  417.     DATA 239,900239,0,0,0,0,0.2: 'OEM SPECIFIC
  418.     DATA 240,900240,0,0,0,0,0.2: 'OEM SPECIFIC
  419.     DATA 241,900241,0,0,0,0,0.2: 'OEM SPECIFIC
  420.     DATA 242,900242,0,0,0,0,0.2: 'OEM SPECIFIC
  421.     DATA 243,900243,0,0,0,0,0.2: 'OEM SPECIFIC
  422.     DATA 244,900244,0,0,0,0,0.2: 'OEM SPECIFIC
  423.     DATA 245,900245,0,0,0,0,0.2: 'OEM SPECIFIC
  424.     DATA 246,900246,0,0,0,0,0.2: 'VK_ATTN
  425.     DATA 247,900247,0,0,0,0,0.2: 'VK_ATTN
  426.     DATA 248,900248,0,0,0,0,0.2: 'VK_ATTN
  427.     DATA 249,900249,0,0,0,0,0.2: 'VK_ATTN
  428.     DATA 250,900250,0,0,0,0,0.2: 'VK_ATTN
  429.     DATA 251,900251,0,0,0,0,0.2: 'VK_ATTN
  430.     DATA 252,900252,0,0,0,0,0.2: 'Reserved
  431.     DATA 253,900253,0,0,0,0,0.2: 'VK_PA1
  432.     DATA 254,900253,0,0,0,0,0.2: 'VK_OEM_CLEAR
  433.     DATA 0,0,0,0,0,0,0.2: 'END OF DATA
  434.     AltGr(0) = 165
  435.     AltGr(1) = 0
  436.  
  437.  
  438. FUNCTION ExtendedTimer##
  439.     'modified extendedtimer to store the old day's count, and not have to recalculate it every time the routine is called.
  440.  
  441.     STATIC olds AS _FLOAT, old_day AS _FLOAT
  442.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  443.     DIM s AS _FLOAT, day AS STRING
  444.     IF olds = 0 THEN 'calculate the day the first time the extended timer runs
  445.         day = DATE$
  446.         m = VAL(LEFT$(day, 2))
  447.         d = VAL(MID$(day, 4, 2))
  448.         y = VAL(RIGHT$(day, 4)) - 1970
  449.         SELECT CASE m 'Add the number of days for each previous month passed
  450.             CASE 2: d = d + 31
  451.             CASE 3: d = d + 59
  452.             CASE 4: d = d + 90
  453.             CASE 5: d = d + 120
  454.             CASE 6: d = d + 151
  455.             CASE 7: d = d + 181
  456.             CASE 8: d = d + 212
  457.             CASE 9: d = d + 243
  458.             CASE 10: d = d + 273
  459.             CASE 11: d = d + 304
  460.             CASE 12: d = d + 334
  461.         END SELECT
  462.         IF (y MOD 4) = 2 AND m > 2 THEN d = d + 1 'add a day if this is leap year and we're past february
  463.         d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  464.         d = d + (y + 2) \ 4 'add in days for leap years passed
  465.         s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  466.         old_day = s
  467.     END IF
  468.     IF TIMER < oldt THEN 'we went from 23:59:59 (a second before midnight) to 0:0:0 (midnight)
  469.         old_day = s + 83400 'add another worth of seconds to our counter
  470.     END IF
  471.     oldt = TIMER
  472.     olds = old_day + oldt
  473.     ExtendedTimer## = olds

We now have the following code added to the routine:

Code: QB64: [Select]
  1. SUB SetAltGr (Key1 AS INTEGER, Key2 AS INTEGER)
  2.     AltGr(0) = Key1 'any key from our index (0 says no key)
  3.     AltGr(1) = Key2 'PLUS any other key from our index (0 says no additional key)
  4.     'Using this, we can set AltGr to become several things.
  5.     'AltGr(0) = 165, AltGr(1) = 0 -- This would say we're using the RIGHT Alt key (alone) to simulate the AltGr key.  (Windows Onscreen Keyboard does this.)
  6.     'AltGr(0) = 17, AltGr(1) = 18 -- This would use any CTRL-ALT combo to simulate a AltGr keypress.
  7.     'Some useful values are listed for quick reference below
  8.     '0 = NoKey
  9.     '17 = ANY Ctrl
  10.     '18 = ANY Alt
  11.     '162 = Left Control
  12.     '163 = Right Control
  13.     '164 = Left Alt
  14.     '165 = Right Alt
  15.  
  16.     'Default is for AltGr(0) = 165, AltGr(1) = 0, which uses Right-Alt alone as the AltGr key.
  17.     'Feel free to customize the setting to your personal preference/need.

AltGr is now customizable so folks can set whatever 1 or 2 hit key-combo they want to activate it.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: Programmable Keyboard Input
« Reply #13 on: December 30, 2019, 11:19:53 am »
Works perfect :)

Thanks
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: Programmable Keyboard Input
« Reply #14 on: December 30, 2019, 11:42:36 am »
Using the SDL version to rebuild its behavior with "programmable input" and just noticed, that SDL even returns a different char/value for the ALT+SHIFT combo, whereas SHIFT+CTRL returns same as CTRL only and CTRL-SHIFT-ALT returns same as ALT only.

Here's what I use on the SDL side:
Code: QB64: [Select]
  1. '-----------------------
  2. '--- The INKEY$ test ---
  3. '-----------------------
  4.     i$ = ""
  5.     WHILE i$ = ""
  6.         _LIMIT 50
  7.         i$ = INKEY$
  8.     WEND
  9.     IF LEN(i$) = 2 THEN
  10.         PRINT "CHR$(0) +", ASC(i$, 2), RIGHT$(i$, 1)
  11.     ELSE
  12.         PRINT "-------->", ASC(i$, 1), i$
  13.     END IF
  14.     IF i$ = CHR$(27) THEN CLS
  15. LOOP UNTIL i$ = CHR$(13)
  16.  
  17.  
« Last Edit: December 30, 2019, 11:44:16 am by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack