QB64.org Forum

Active Forums => Programs => Topic started by: SMcNeill on December 29, 2019, 12:06:32 am

Title: Programmable Keyboard Input
Post by: SMcNeill 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.)
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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.  :)

Title: Re: Programmable Keyboard Input
Post by: TempodiBasic 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.
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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.  ;)
Title: Re: Programmable Keyboard Input
Post by: RhoSigma 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)
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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.  ;)
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic 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
 
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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.  ;)
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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.  ;)
Title: Re: Programmable Keyboard Input
Post by: RhoSigma 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...
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic 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.
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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...
Title: Re: Programmable Keyboard Input
Post by: SMcNeill 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.  ;)
Title: Re: Programmable Keyboard Input
Post by: RhoSigma on December 30, 2019, 11:19:53 am
Works perfect :)

Thanks
Title: Re: Programmable Keyboard Input
Post by: RhoSigma 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.  
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on December 30, 2019, 01:39:15 pm
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.

I didn't think folks would need any further flexibility than what I'd started with, but it's quite easy to expand our functionality.  See if this version handles all the extreme input cases you could imagine, where you might need to remap characters for different values:

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

We now have the option to remap (or add) extended keycodes to our input handler, if we want to, using:

Code: [Select]
SUB Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
For testing purposes, I remapped A to give us a whole swarm of different various inputs which it can now relate to:
"A" -- when used alone and in combination with other keys -- returns us values which can be:  65, 1, 97, 160, 142, 143, 241, 242, 243, 244, 245, 246

I'm thinking that someone should be able to map just about any type of character to any sort of combo that they want now, without any problem at all!  Forget plain old key & shift-key combos!!  Now you can do key, shift-key, ctrl-shift-key, alt-shift-key, altgr-key, shift-altgr-key, and several other possible combinations!

If you can detect the keys on your system, you should be able to map them to respond to whatever the heck you want them to for you.  :)

Title: Re: Programmable Keyboard Input
Post by: RhoSigma on December 30, 2019, 02:04:36 pm
Well, thank you once again for your efforts Steve,

I'd agree, that this might be overkill for most people. From that point of view it's perfect, that you chose to put the "extended" remapping into a extra SUB, so everybody who doesn't need it can just leave it alone. On the other hand we now have an excellent piece of code suitable for almost any thinkable key combo, and I hope many of our international members will take the time to add at least the regular mappings for their respective keyboards, so this library will evolve well in the future.

For me it will be possible now to exactly rebuilt the INKEY$ behavior as SDL had, and which worked so well for my projects.

Thank You
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on December 30, 2019, 02:42:21 pm
Happy to do it, as this is something which I’ll be using in various projects as well, once we get it all shined up and polished.  ;)

For my latest project, I wanted to be able to allow users to set their own customizable hotkeys for various program actions, and that just isn’t possible with our current input routines.  _KEYHIT doesn’t work right, or play nice, with many of the CTRL keys.  (Heck, it doesn’t even register some of the unmodified keys, like the Menu/App key!)  INKEY$ has limited readability...

I’d always thought, “At least we have _DEVICES to fall back on...”

WRONG!!

It’s completely, utterly, 100% broken.  It doesn’t return the values from the _DEVICES page at all now — it’s more the INP(&H60) character set.  It doesn’t read ALT at all...  It’s just broke.

/sigh

Which, when all taken together, leads me to end up just writing my own programmable input handler, which we see here.  I hope others will find it useful, but in the end, it’s primary purpose is to be something which I can plug in and use for my own personal projects in the future. 

Got to admit though, I will be rather happy once others contribute some international remappings to things.  It’ll be nice to provide that functionality for others in the future, as well.  ;)
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on December 31, 2019, 11:58:43 am
Edited post above to fix a small glitch with some codes not printing thanks to an incorrect look-up being done with CAPSLOCK modifying things.
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on December 31, 2019, 12:36:03 pm
Added a few helper functions to the programmable keyboard routines above. 

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.     FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
  4.  
  5. TYPE KeyboardInfo_Type
  6.     Index AS LONG
  7.     ASCII AS LONG
  8.     Ctrl AS LONG
  9.     Shift AS LONG
  10.     Alt AS LONG
  11.     AltGr AS LONG
  12.     Repeat AS _FLOAT
  13.     LastHit AS _FLOAT
  14.     Down AS LONG
  15.     AltShift AS LONG
  16.     AltCtrl AS LONG
  17.     AltAltGr AS LONG
  18.     CtrlShift AS LONG
  19.     CtrlAlt AS LONG
  20.     CtrlAltGr AS LONG
  21.     ShiftAltGr AS LONG
  22.     CtrlAltShift AS LONG
  23.  
  24. DIM SHARED Keys(254) AS KeyboardInfo_Type
  25. Init_KeyCodes
  26. Remap_KeyCode 65, 65, 1, 97, 160, 142, 0.2: 'A , , a,  , Ž
  27. 'Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
  28. Remap_Extended_KeyCode 65, 143, 241, 242, 243, 244, 245, 246 ' and more!
  29.  
  30.  
  31. PRINT "Test out the input handler.  Try lots of options! => ";
  32. junk$ = ExtendedInput
  33. PRINT junk$
  34. PRINT "Pretty nifty, right?"
  35. KeyClear 'Notice that without this, we'll read the keyup event from where ENTER is lifted up, as the first character value below.
  36.  
  37.     k = KeyHit
  38.     IF k <> 0 THEN
  39.         'LOCATE 1, 1
  40.         PRINT k;
  41.         IF ABS(k) < 256 THEN PRINT CHR$(34); CHR$(ABS(k)); CHR$(34) ELSE PRINT
  42.     END IF
  43.     'LOCATE 2, 1: PRINT KeyDown(1) 'Test to see if CHR$(1) is held down (which is generated via a CTRL-A combo)
  44.     _LIMIT 30
  45. LOOP UNTIL k = 27 'escape
  46.  
  47. SUB SetAltGr (Key1 AS INTEGER, Key2 AS INTEGER)
  48.     AltGr(0) = Key1 'any key from our index (0 says no key)
  49.     AltGr(1) = Key2 'PLUS any other key from our index (0 says no additional key)
  50.     'Using this, we can set AltGr to become several things.
  51.     '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.)
  52.     'AltGr(0) = 17, AltGr(1) = 18 -- This would use any CTRL-ALT combo to simulate a AltGr keypress.
  53.     'Some useful values are listed for quick reference below
  54.     '0 = NoKey
  55.     '17 = ANY Ctrl
  56.     '18 = ANY Alt
  57.     '162 = Left Control
  58.     '163 = Right Control
  59.     '164 = Left Alt
  60.     '165 = Right Alt
  61.  
  62.     'Default is for AltGr(0) = 165, AltGr(1) = 0, which uses Right-Alt alone as the AltGr key.
  63.     'Feel free to customize the setting to your personal preference/need.
  64.  
  65. SUB KeyClear
  66.     _DELAY .05 'give time for a keyup event to log itself so we can clear it
  67.     DO: k = KeyHit: LOOP UNTIL k = 0
  68.  
  69. FUNCTION KeyHit&
  70.     STATIC ReturnCount AS INTEGER
  71.     STATIC ReturnValues(30) AS LONG
  72.     SHARED AltGr, Alt, Shift, Ctrl
  73.     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.
  74.  
  75.  
  76.     IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  77.         'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  78.         KeyHit = ReturnValues(1)
  79.         FOR i = 1 TO ReturnCount - 1
  80.             ReturnValues(i) = ReturnValues(i + 1)
  81.         NEXT
  82.         ReturnCount = ReturnCount - 1
  83.         EXIT FUNCTION
  84.     END IF
  85.  
  86.     IF Keys(16).Down THEN Shift = -1 ELSE Shift = 0
  87.     IF Keys(17).Down THEN Ctrl = -1 ELSE Ctrl = 0
  88.     IF Keys(18).Down THEN Alt = -1 ELSE Alt = 0
  89.     IF AltGr(0) <> 0 AND AltGr(1) <> 0 THEN
  90.         IF Keys(AltGr(0)).Down AND Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  91.     ELSEIF AltGr(1) <> 0 THEN
  92.         IF Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  93.     ELSEIF AltGr(0) <> 0 THEN
  94.         IF Keys(AltGr(0)).Down THEN AltGr = -1 ELSE AltGr = 0
  95.     ELSE
  96.         AltGr = 0
  97.     END IF
  98.  
  99.     'until Ctrl or Alt status, if the key down was used to help generate AltGr as a modifier key
  100.     IF AltGr THEN
  101.         IF (AltGr(0) = 18 OR AltGr(1) = 18) THEN Alt = 0 'if we use both ALT keys to represent part of AltGr, when AltGr is active, Alt isn't.
  102.         IF (AltGr(0) = 164 OR AltGr(1) = 164) AND Keys(165).Down = 0 THEN Alt = 0 'if we use Left ALT keys to represent part of AltGr, when AltGr is active, Left Alt isn't.
  103.         IF (AltGr(0) = 165 OR AltGr(1) = 165) AND Keys(164).Down = 0 THEN Alt = 0 'if we use Right ALT keys to represent part of AltGr, when AltGr is active, Right Alt isn't.
  104.         IF (AltGr(0) = 17 OR AltGr(1) = 17) THEN Ctrl = 0 'if we use both CTRL keys to represent part of AltGr, when AltGr is active, Ctrl isn't.
  105.         IF (AltGr(0) = 162 OR AltGr(1) = 162) AND Keys(163).Down = 0 THEN Ctrl = 0 'if we use Left CTRL keys to represent part of AltGr, when AltGr is active, Left Ctrl isn't.
  106.         IF (AltGr(0) = 163 OR AltGr(1) = 163) AND Keys(162).Down = 0 THEN Ctrl = 0 'if we use Right CTRL keys to represent part of AltGr, when AltGr is active, Right Ctrl isn't.
  107.     END IF
  108.  
  109.     IF Alt AND Shift THEN AltShift = -1 ELSE AltShift = 0
  110.     IF Alt AND Ctrl THEN AltCtrl = -1 ELSE AltCtrl = 0
  111.     IF Alt AND AltAltGR THEN AltAltGR = -1 ELSE AltAltGR = 0
  112.     IF Ctrl AND Shift THEN CtrlShift = -1 ELSE CtrlShift = 0
  113.     IF Shift AND AltGr THEN ShiftAltGr = -1 ELSE ShiftAltGr = 0
  114.     IF Ctrl AND Alt AND Shift THEN CtrlAltShift = -1 ELSE CtrlAltShift = 0
  115.  
  116.         FOR i = 1 TO 254
  117.  
  118.             r = GetKeyState(Keys(i).Index) AND &H8000
  119.  
  120.             IF r THEN 'the key is down
  121.  
  122.  
  123.                 IF Keys(i).LastHit THEN
  124.                     IF ExtendedTimer > Keys(i).LastHit THEN
  125.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  126.                         ReturnValues(ReturnCount) = Keys(i).Down 'and put the existing value back in the buffer, as a key repeat
  127.                     END IF
  128.                 ELSE
  129.  
  130.                     IF Keys(i).Down = 0 THEN 'the key was up on the last pass.
  131.                         IF CtrlAltShift <> 0 AND Keys(i).CtrlAltShift <> 0 THEN 'return the CtrlAltShift value
  132.                             Keys(i).Down = Keys(i).CtrlAltShift
  133.                         ELSEIF AltAltGR <> 0 AND Keys(i).AltAltGr <> 0 THEN 'return the AltAltGr value
  134.                             Keys(i).Down = Keys(i).AltAltGr
  135.                         ELSEIF CtrlAltGr& <> 0 AND Keys(i).CtrlAltGr& <> 0 THEN 'return the CtrlAltGr& value
  136.                             Keys(i).Down = Keys(i).CtrlAltGr&
  137.                         ELSEIF ShiftAltGr <> 0 AND Keys(i).ShiftAltGr <> 0 THEN 'return the ShiftAltGr value
  138.                             Keys(i).Down = Keys(i).ShiftAltGr
  139.                         ELSEIF CtrlShift <> 0 AND Keys(i).CtrlShift <> 0 THEN 'return the CtrlShift value
  140.                             Keys(i).Down = Keys(i).CtrlShift
  141.                         ELSEIF AltCtrl <> 0 AND Keys(i).AltCtrl <> 0 THEN 'return the AltCtrl value
  142.                             Keys(i).Down = Keys(i).AltCtrl
  143.                         ELSEIF AltShift <> 0 AND Keys(i).AltShift <> 0 THEN 'return the AltShift value
  144.                             Keys(i).Down = Keys(i).AltShift
  145.                         ELSEIF AltGr <> 0 AND Keys(i).AltGr <> 0 THEN 'return the altgr value
  146.                             Keys(i).Down = Keys(i).AltGr
  147.                         ELSEIF Shift <> 0 AND Keys(i).Shift <> 0 THEN 'return the shift value
  148.                             Keys(i).Down = Keys(i).Shift
  149.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  150.                                 SELECT CASE i
  151.                                     CASE 65 TO 90: Keys(i).Down = Keys(i).ASCII
  152.                                 END SELECT
  153.                             END IF
  154.                         ELSEIF (Ctrl <> 0) AND (Keys(i).Ctrl <> 0) THEN 'return the ctrl value
  155.                             Keys(i).Down = Keys(i).Ctrl
  156.                         ELSEIF Alt <> 0 AND Keys(i).Alt <> 0 THEN 'return the alt value
  157.                             Keys(i).Down = Keys(i).Alt
  158.                         ELSE 'all that's left is to return the ASCII value
  159.                             Keys(i).Down = Keys(i).ASCII
  160.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  161.                                 SELECT CASE i
  162.                                     CASE 65 TO 90: Keys(i).Down = Keys(i).Shift
  163.                                 END SELECT
  164.                             END IF
  165.                         END IF
  166.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  167.                         ReturnValues(ReturnCount) = Keys(i).Down 'and store the value in the buffer
  168.  
  169.                         IF Keys(i).Repeat = -1 THEN 'keys that are set to a -1 on repeat simply toggle state as on, or off.
  170.                             Keys(i).LastHit = 1E+1000 'such as SHIFT, CTRL, ALT...
  171.                         ELSE
  172.                             Keys(i).LastHit = ExtendedTimer + Keys(i).Repeat 'and record when we hit it for repeat purposes
  173.                         END IF
  174.                     END IF
  175.                 END IF
  176.             ELSE
  177.                 IF Keys(i).Down THEN 'the key was down on the last pass
  178.                     ReturnCount = ReturnCount + 1
  179.                     ReturnValues(ReturnCount) = -Keys(i).Down 'mark it as being up on this one
  180.                 END IF
  181.                 Keys(i).Down = 0 'and set it back down for future passes
  182.                 Keys(i).LastHit = 0 'once again, set it as being ready to be hit again
  183.             END IF
  184.         NEXT
  185.  
  186.         IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  187.             'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  188.             KeyHit = ReturnValues(1)
  189.             FOR i = 1 TO ReturnCount - 1
  190.                 ReturnValues(i) = ReturnValues(i + 1)
  191.             NEXT
  192.             ReturnCount = ReturnCount - 1
  193.             EXIT FUNCTION
  194.         END IF
  195.  
  196.     END IF 'End of IF _WINDOWHASFOCUS
  197.  
  198.  
  199.  
  200.  
  201. SUB Remap_KeyCode (Which AS LONG, ASCII AS LONG, Ctrl AS LONG, Shift AS LONG, Alt AS LONG, AltGr AS LONG, Repeat AS _FLOAT)
  202.     DIM i AS LONG
  203.     i = Which
  204.     Keys(i).Index = i
  205.     Keys(i).ASCII = ASCII
  206.     Keys(i).Ctrl = Ctrl
  207.     Keys(i).Shift = Shift
  208.     Keys(i).Alt = Alt
  209.     Keys(i).AltGr = AltGr
  210.     Keys(i).Repeat = Repeat
  211.     Keys(i).LastHit = 0
  212.     Keys(i).Down = 0
  213.  
  214. SUB Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, _
  215.          CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
  216.     Keys(Which&).AltShift = AltShift&
  217.     Keys(Which&).AltCtrl = AltCtrl&
  218.     Keys(Which&).AltAltGr = AltAltGr&
  219.     Keys(Which&).CtrlShift = CtrlShift&
  220.     Keys(Which&).CtrlAltGr = CtrlAltGr&
  221.     Keys(Which&).ShiftAltGr = ShiftAltGr&
  222.     Keys(Which&).CtrlAltShift = CtrlAltShift&
  223.  
  224. FUNCTION KeyDown& (Code AS LONG)
  225.     IF Code <= 0 THEN EXIT FUNCTION
  226.     FOR i = 1 TO 254
  227.         IF GetAsyncKeyState(i) THEN 'first check for actual physical keys down
  228.             IF Keys(i).ASCII = Code THEN KeyDown = -1: EXIT FUNCTION 'then check to see if the code matches anything we've mapped it to.
  229.             IF Keys(i).Shift = Code THEN KeyDown = -1: EXIT FUNCTION
  230.             IF Keys(i).Alt = Code THEN KeyDown = -1: EXIT FUNCTION
  231.             IF Keys(i).AltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  232.             IF Keys(i).AltShift = Code THEN KeyDown = -1: EXIT FUNCTION
  233.             IF Keys(i).AltCtrl = Code THEN KeyDown = -1: EXIT FUNCTION
  234.             IF Keys(i).AltAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  235.             IF Keys(i).CtrlShift = Code THEN KeyDown = -1: EXIT FUNCTION
  236.             IF Keys(i).CtrlAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  237.             IF Keys(i).ShiftAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  238.             IF Keys(i).CtrlAltShift = Code THEN KeyDown = -1: EXIT FUNCTION
  239.         END IF
  240.     NEXT
  241.     KeyDown& = 0
  242.  
  243. SUB Init_KeyCodes
  244.     RESTORE default_keyboard_data
  245.     FOR i = 1 TO 254
  246.         READ Keys(i).Index, Keys(i).ASCII, Keys(i).Ctrl, Keys(i).Shift, Keys(i).Alt, Keys(i).AltGr, Keys(i).Repeat
  247.         Keys(i).LastHit = 0: Keys(i).Down = 0
  248.     NEXT
  249.  
  250.     default_keyboard_data:
  251.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  252.     DATA 1,900001,0,0,0,0,0.2: 'Left Mouse Button
  253.     DATA 2,900002,0,0,0,0,0.2: 'Right Mouse Button
  254.     DATA 3,900003,0,0,0,0,0.2: 'VK_Cancel
  255.     DATA 4,900004,0,0,0,0,0.2: 'Middle Mouse Button
  256.     DATA 5,900005,0,0,0,0,0.2: 'Mouse Button 4
  257.     DATA 6,900006,0,0,0,0,0.2: 'Mouse Button 5
  258.     DATA 7,900007,0,0,0,0,0.2: 'Undefined
  259.     DATA 8,8,0,0,0,0,0.2: 'Backspace
  260.     DATA 9,9,0,0,0,0,0.2: 'Tab
  261.     DATA 10,900010,0,0,0,0,0.2: 'Reserved
  262.     DATA 11,900011,0,0,0,0,0.2: 'Reserved
  263.     DATA 12,19456,0,0,0,0,0.2: 'Clear
  264.     DATA 13,13,0,0,0,0,0.2: 'Enter
  265.     DATA 14,900014,0,0,0,0,0.2: 'Undefined
  266.     DATA 15,900015,0,0,0,0,0.2: 'Undefined
  267.     DATA 16,100016,0,0,0,0,-1: 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  268.     DATA 17,100017,0,0,0,0,-1: 'Ctrl   (Same)
  269.     DATA 18,100018,0,0,0,0,-1: 'Alt     (Same)
  270.     DATA 19,100019,0,0,0,0,0.2: 'Pause
  271.     DATA 20,100301,0,0,0,0,-1: 'Caps Lock
  272.     DATA 21,900021,0,0,0,0,0.2: 'VK_Hangul
  273.     DATA 22,900022,0,0,0,0,0.2: 'Undefined
  274.     DATA 23,900023,0,0,0,0,0.2: 'VK_Junja
  275.     DATA 24,900024,0,0,0,0,0.2: 'VK_Final
  276.     DATA 25,900025,0,0,0,0,0.2: 'VK_Hanga//VK_Kanji
  277.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  278.     DATA 26,900026,0,0,0,0,0.2: 'Undefined
  279.     DATA 27,27,0,0,0,0,0.2: 'ESC
  280.     DATA 28,900028,0,0,0,0,0.2: 'VK_Convert
  281.     DATA 29,900029,0,0,0,0,0.2: 'VK_NonConvert
  282.     DATA 30,900030,0,0,0,0,0.2: 'VK_Accept
  283.     DATA 31,900031,0,0,0,0,0.2: 'VK_ModeChange
  284.     DATA 32,32,0,0,0,0,0.2: 'VK_Space
  285.     DATA 33,18688,0,0,0,0,0.2: 'Page Up
  286.     DATA 34,20736,0,0,0,0,0.2: 'Page Down
  287.     DATA 35,20224,0,0,0,0,0.2: 'End
  288.     DATA 36,18176,0,0,0,0,0.2: 'Home
  289.     DATA 37,19200,0,0,0,0,0.2: 'Left Arrow
  290.     DATA 38,18432,0,0,0,0,0.2: 'Up Arrow
  291.     DATA 39,19712,0,0,0,0,0.2: 'Right Arrow
  292.     DATA 40,20480,0,0,0,0,0.2: 'Down Arrow
  293.     DATA 41,900041,0,0,0,0,-1: 'VK_SELECT
  294.     DATA 42,900042,0,0,0,0,-1: 'CK_PRINT
  295.     DATA 43,900043,0,0,0,0,-1: 'VK_EXECUTE
  296.     DATA 44,900044,0,0,0,0,-1: 'VK_SNAPSHOT
  297.     DATA 45,20992,0,0,0,0,0.2: 'INS
  298.     DATA 46,21248,0,0,0,0,0.2: 'DEL
  299.     DATA 47,900047,0,0,0,0,0.2: 'VK_HELP
  300.     DATA 48,48,0,41,0,0,0.2: '0
  301.     DATA 49,49,0,33,0,0,0.2: '1
  302.     DATA 50,50,0,64,0,0,0.2: '2
  303.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  304.     DATA 51,51,0,35,0,0,0.2: '3
  305.     DATA 52,52,0,36,0,0,0.2: '4
  306.     DATA 53,53,0,37,0,0,0.2: '5
  307.     DATA 54,54,0,94,0,0,0.2: '6
  308.     DATA 55,55,0,38,0,0,0.2: '7
  309.     DATA 56,56,0,42,0,0,0.2: '8
  310.     DATA 57,57,0,40,0,0,0.2: '9
  311.     DATA 58,900058,0,0,0,0,0.2: 'Undefined
  312.     DATA 59,900059,0,0,0,0,0.2: 'Undefined
  313.     DATA 60,900060,0,0,0,0,0.2: 'Undefined
  314.     DATA 61,900061,0,0,0,0,0.2: 'Undefined
  315.     DATA 62,900062,0,0,0,0,0.2: 'Undefined
  316.     DATA 63,900063,0,0,0,0,0.2: 'Undefined
  317.     DATA 64,900064,0,0,0,0,0.2: 'Undefined
  318.     DATA 65,65,0,97,0,0,0.2: 'a
  319.     DATA 66,66,0,98,0,0,0.2: 'b
  320.     DATA 67,67,0,99,0,0,0.2: 'c
  321.     DATA 68,68,0,100,0,0,0.2: 'd
  322.     DATA 69,69,0,101,0,0,0.2: 'e
  323.     DATA 70,70,0,102,0,0,0.2: 'f
  324.     DATA 71,71,0,103,0,0,0.2: 'g
  325.     DATA 72,72,0,104,0,0,0.2: 'h
  326.     DATA 73,73,0,105,0,0,0.2: 'i
  327.     DATA 74,74,0,106,0,0,0.2: 'j
  328.     DATA 75,75,0,107,0,0,0.2: 'k
  329.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  330.     DATA 76,76,0,108,0,0,0.2: 'l
  331.     DATA 77,77,0,109,0,0,0.2: 'm
  332.     DATA 78,78,0,110,0,0,0.2: 'n
  333.     DATA 79,79,0,111,0,0,0.2: 'o
  334.     DATA 80,80,0,112,0,0,0.2: 'p
  335.     DATA 81,81,0,113,0,0,0.2: 'q
  336.     DATA 82,82,0,114,0,0,0.2: 'r
  337.     DATA 83,83,0,115,0,0,0.2: 's
  338.     DATA 84,84,0,116,0,0,0.2: 't
  339.     DATA 85,85,0,117,0,0,0.2: 'u
  340.     DATA 86,86,0,118,0,0,0.2: 'v
  341.     DATA 87,87,0,119,0,0,0.2: 'w
  342.     DATA 88,88,0,120,0,0,0.2: 'x
  343.     DATA 89,89,0,121,0,0,0.2: 'y
  344.     DATA 90,90,0,122,0,0,0.2: 'z
  345.     DATA 91,100311,0,0,0,0,-1: 'Left WIN
  346.     DATA 92,100312,0,0,0,0,-1: 'Right WIN
  347.     DATA 93,100319,0,0,0,0,-1: 'Applications (Menu)
  348.     DATA 94,900094,0,0,0,0,0.2: 'Reserved
  349.     DATA 95,900095,0,0,0,0,0.2: 'VK_SLEEP
  350.     DATA 96,48,0,0,0,0,0.2: 'Numpad 0
  351.     DATA 97,49,0,0,0,0,0.2: 'Numpad 1
  352.     DATA 98,50,0,0,0,0,0.2: 'Numpad 2
  353.     DATA 99,51,0,0,0,0,0.2: 'Numpad 3
  354.     DATA 100,52,0,0,0,0,0.2: 'Numpad 4
  355.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  356.     DATA 101,53,0,0,0,0,0.2: 'Numpad 5
  357.     DATA 102,54,0,0,0,0,0.2: 'Numpad 6
  358.     DATA 103,55,0,0,0,0,0.2: 'Numpad 7
  359.     DATA 104,56,0,0,0,0,0.2: 'Numpad 8
  360.     DATA 105,57,0,0,0,0,0.2: 'Numpad 9
  361.     DATA 106,42,0,0,0,0,0.2: 'Numpad *
  362.     DATA 107,43,0,0,0,0,0.2: 'Numpad +
  363.     DATA 108,900108,0,0,0,0,0.2: 'VK_SEPARATOR
  364.     DATA 109,51,0,0,0,0,0.2: 'Numpad -
  365.     DATA 110,52,0,0,0,0,0.2: 'Numpad .
  366.     DATA 111,53,0,0,0,0,0.2: 'Numpad /
  367.     DATA 112,15104,0,0,0,0,0.2: 'F1
  368.     DATA 113,15360,0,0,0,0,0.2: 'F2
  369.     DATA 114,15616,0,0,0,0,0.2: 'F3
  370.     DATA 115,15872,0,0,0,0,0.2: 'F4
  371.     DATA 116,16128,0,0,0,0,0.2: 'F5
  372.     DATA 117,16384,0,0,0,0,0.2: 'F6
  373.     DATA 118,16640,0,0,0,0,0.2: 'F7
  374.     DATA 119,16896,0,0,0,0,0.2: 'F8
  375.     DATA 120,17152,0,0,0,0,0.2: 'F9
  376.     DATA 121,17408,0,0,0,0,0.2: 'F10
  377.     DATA 122,34048,0,0,0,0,0.2: 'F11
  378.     DATA 123,34304,0,0,0,0,0.2: 'F12
  379.     DATA 124,900124,0,0,0,0,0.2: 'F13
  380.     DATA 125,900125,0,0,0,0,0.2: 'F14
  381.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  382.     DATA 126,900126,0,0,0,0,0.2: 'F15
  383.     DATA 127,900127,0,0,0,0,0.2: 'F16
  384.     DATA 128,900128,0,0,0,0,0.2: 'F17
  385.     DATA 129,900129,0,0,0,0,0.2: 'F18
  386.     DATA 130,900130,0,0,0,0,0.2: 'F19
  387.     DATA 131,900131,0,0,0,0,0.2: 'F20
  388.     DATA 132,900132,0,0,0,0,0.2: 'F21
  389.     DATA 133,900133,0,0,0,0,0.2: 'F22
  390.     DATA 134,900134,0,0,0,0,0.2: 'F23
  391.     DATA 135,900135,0,0,0,0,0.2: 'F24
  392.     DATA 136,900136,0,0,0,0,0.2: 'Unassigned
  393.     DATA 137,900137,0,0,0,0,0.2: 'Unassigned
  394.     DATA 138,900138,0,0,0,0,0.2: 'Unassigned
  395.     DATA 139,900139,0,0,0,0,0.2: 'Unassigned
  396.     DATA 140,900140,0,0,0,0,0.2: 'Unassigned
  397.     DATA 141,900141,0,0,0,0,0.2: 'Unassigned
  398.     DATA 142,900142,0,0,0,0,0.2: 'Unassigned
  399.     DATA 143,900143,0,0,0,0,0.2: 'Unassigned
  400.     DATA 144,100300,0,0,0,0,-1: 'NUM LOCK
  401.     DATA 145,100302,0,0,0,0,-1: 'SCROLL LOCK
  402.     DATA 146,900146,0,0,0,0,0.2: 'OEM SPECIFIC
  403.     DATA 147,900147,0,0,0,0,0.2: 'OEM SPECIFIC
  404.     DATA 148,900148,0,0,0,0,0.2: 'OEM SPECIFIC
  405.     DATA 149,900149,0,0,0,0,0.2: 'OEM SPECIFIC
  406.     DATA 150,900150,0,0,0,0,0.2: 'OEM SPECIFIC
  407.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  408.     DATA 151,900151,0,0,0,0,0.2: 'Unassigned
  409.     DATA 152,900152,0,0,0,0,0.2: 'Unassigned
  410.     DATA 153,900153,0,0,0,0,0.2: 'Unassigned
  411.     DATA 154,900154,0,0,0,0,0.2: 'Unassigned
  412.     DATA 155,900155,0,0,0,0,0.2: 'Unassigned
  413.     DATA 156,900156,0,0,0,0,0.2: 'Unassigned
  414.     DATA 157,900157,0,0,0,0,0.2: 'Unassigned
  415.     DATA 158,900158,0,0,0,0,0.2: 'Unassigned
  416.     DATA 159,900159,0,0,0,0,0.2: 'Unassigned
  417.     DATA 160,100304,0,0,0,0,-1: 'Left Shift
  418.     DATA 161,100303,0,0,0,0,-1: 'Right Shift
  419.     DATA 162,100306,0,0,0,0,-1: 'Left Control
  420.     DATA 163,100305,0,0,0,0,-1: 'Right Control
  421.     DATA 164,100308,0,0,0,0,-1: 'Left Alt
  422.     DATA 165,100309,0,0,0,0,-1: 'Right Alt
  423.     DATA 166,900166,0,0,0,0,0.2: 'Browser back
  424.     DATA 167,900167,0,0,0,0,0.2: 'Browser forward
  425.     DATA 168,900168,0,0,0,0,0.2: 'Browser refresh
  426.     DATA 169,900169,0,0,0,0,0.2: 'Browser stop
  427.     DATA 170,900170,0,0,0,0,0.2: 'Browser search
  428.     DATA 171,900171,0,0,0,0,0.2: 'Browser favorites
  429.     DATA 172,900172,0,0,0,0,0.2: 'Browser home
  430.     DATA 173,900173,0,0,0,0,0.2: 'Mute
  431.     DATA 174,900174,0,0,0,0,0.2: 'Vol Down
  432.     DATA 175,900175,0,0,0,0,0.2: 'Vol Up
  433.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  434.     DATA 176,900176,0,0,0,0,0.2: 'Media Next
  435.     DATA 177,900177,0,0,0,0,0.2: 'Media prev
  436.     DATA 178,900178,0,0,0,0,0.2: 'Media stop
  437.     DATA 179,900179,0,0,0,0,0.2: 'Media Play/Pause
  438.     DATA 180,900180,0,0,0,0,0.2: 'Launch mail
  439.     DATA 181,900181,0,0,0,0,0.2: 'Launch media select
  440.     DATA 182,900182,0,0,0,0,0.2: 'Launch app1
  441.     DATA 183,900183,0,0,0,0,0.2: 'Launch app2
  442.     DATA 184,900184,0,0,0,0,0.2: 'Reserved
  443.     DATA 185,900185,0,0,0,0,0.2: 'Reserved
  444.     DATA 186,59,0,58,0,0,0.2: ';:
  445.     DATA 187,61,0,43,0,0,0.2: '=+
  446.     DATA 188,44,0,60,0,0,0.2: ',<
  447.     DATA 189,45,0,95,0,0,0.2: '-_
  448.     DATA 190,46,0,62,0,0,0.2: '.>
  449.     DATA 191,47,0,63,0,0,0.2: '/?
  450.     DATA 192,96,0,126,0,0,0.2: '`~
  451.     DATA 193,900193,0,0,0,0,0.2: 'Reserved
  452.     DATA 194,900194,0,0,0,0,0.2: 'Reserved
  453.     DATA 195,900195,0,0,0,0,0.2: 'Reserved
  454.     DATA 196,900196,0,0,0,0,0.2: 'Reserved
  455.     DATA 197,900197,0,0,0,0,0.2: 'Reserved
  456.     DATA 198,900198,0,0,0,0,0.2: 'Reserved
  457.     DATA 199,900199,0,0,0,0,0.2: 'Reserved
  458.     DATA 200,900200,0,0,0,0,0.2: 'Reserved
  459.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  460.     DATA 201,900201,0,0,0,0,0.2: 'Reserved
  461.     DATA 202,900202,0,0,0,0,0.2: 'Reserved
  462.     DATA 203,900203,0,0,0,0,0.2: 'Reserved
  463.     DATA 204,900204,0,0,0,0,0.2: 'Reserved
  464.     DATA 205,900205,0,0,0,0,0.2: 'Reserved
  465.     DATA 206,900206,0,0,0,0,0.2: 'Reserved
  466.     DATA 207,900207,0,0,0,0,0.2: 'Reserved
  467.     DATA 208,900208,0,0,0,0,0.2: 'Reserved
  468.     DATA 209,900209,0,0,0,0,0.2: 'Reserved
  469.     DATA 210,900210,0,0,0,0,0.2: 'Reserved
  470.     DATA 211,900211,0,0,0,0,0.2: 'Reserved
  471.     DATA 212,900212,0,0,0,0,0.2: 'Reserved
  472.     DATA 213,900213,0,0,0,0,0.2: 'Reserved
  473.     DATA 214,900214,0,0,0,0,0.2: 'Reserved
  474.     DATA 215,900215,0,0,0,0,0.2: 'Reserved
  475.     DATA 216,900216,0,0,0,0,0.2: 'Unassigned
  476.     DATA 217,900217,0,0,0,0,0.2: 'Unassigned
  477.     DATA 218,900218,0,0,0,0,0.2: 'Unassigned
  478.     DATA 219,91,0,123,0,0,0.2: '[{
  479.     DATA 220,92,0,124,0,0,0.2: '\|
  480.     DATA 221,93,0,125,0,0,0.2: ']}
  481.     DATA 222,39,0,34,0,0,0.2: ''"
  482.     DATA 223,900223,0,0,0,0,0.2: 'OEM SPECIFIC
  483.     DATA 224,900224,0,0,0,0,0.2: 'Reserved
  484.     DATA 225,900225,0,0,0,0,0.2: 'OEM SPECIFIC d
  485.     DATA 226,900226,0,0,0,0,0.2: 'Either the Angle Bracket key,or Backslash on RT 102-key keyboard
  486.     DATA 227,900227,0,0,0,0,0.2: 'OEM SPECIFIC
  487.     DATA 228,900228,0,0,0,0,0.2: 'OEM SPECIFIC
  488.     DATA 229,900229,0,0,0,0,0.2: 'IME PROCESS key (whatever that is)
  489.     DATA 230,900230,0,0,0,0,0.2: 'OEM SPECIFIC
  490.     DATA 231,900231,0,0,0,0,0.2: 'Used to pass UNICODE characters (however that works)
  491.     DATA 232,900232,0,0,0,0,0.2: 'Unassigned
  492.     DATA 233,900233,0,0,0,0,0.2: 'OEM SPECIFIC
  493.     DATA 234,900234,0,0,0,0,0.2: 'OEM SPECIFIC
  494.     DATA 235,900235,0,0,0,0,0.2: 'OEM SPECIFIC
  495.     DATA 236,900236,0,0,0,0,0.2: 'OEM SPECIFIC
  496.     DATA 237,900237,0,0,0,0,0.2: 'OEM SPECIFIC
  497.     DATA 238,900238,0,0,0,0,0.2: 'OEM SPECIFIC
  498.     DATA 239,900239,0,0,0,0,0.2: 'OEM SPECIFIC
  499.     DATA 240,900240,0,0,0,0,0.2: 'OEM SPECIFIC
  500.     DATA 241,900241,0,0,0,0,0.2: 'OEM SPECIFIC
  501.     DATA 242,900242,0,0,0,0,0.2: 'OEM SPECIFIC
  502.     DATA 243,900243,0,0,0,0,0.2: 'OEM SPECIFIC
  503.     DATA 244,900244,0,0,0,0,0.2: 'OEM SPECIFIC
  504.     DATA 245,900245,0,0,0,0,0.2: 'OEM SPECIFIC
  505.     DATA 246,900246,0,0,0,0,0.2: 'VK_ATTN
  506.     DATA 247,900247,0,0,0,0,0.2: 'VK_ATTN
  507.     DATA 248,900248,0,0,0,0,0.2: 'VK_ATTN
  508.     DATA 249,900249,0,0,0,0,0.2: 'VK_ATTN
  509.     DATA 250,900250,0,0,0,0,0.2: 'VK_ATTN
  510.     DATA 251,900251,0,0,0,0,0.2: 'VK_ATTN
  511.     DATA 252,900252,0,0,0,0,0.2: 'Reserved
  512.     DATA 253,900253,0,0,0,0,0.2: 'VK_PA1
  513.     DATA 254,900253,0,0,0,0,0.2: 'VK_OEM_CLEAR
  514.     DATA 0,0,0,0,0,0,0.2: 'END OF DATA
  515.     AltGr(0) = 165
  516.     AltGr(1) = 0
  517.  
  518.  
  519. FUNCTION ExtendedTimer##
  520.     'modified extendedtimer to store the old day's count, and not have to recalculate it every time the routine is called.
  521.  
  522.     STATIC olds AS _FLOAT, old_day AS _FLOAT
  523.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  524.     DIM s AS _FLOAT, day AS STRING
  525.     IF olds = 0 THEN 'calculate the day the first time the extended timer runs
  526.         day = DATE$
  527.         m = VAL(LEFT$(day, 2))
  528.         d = VAL(MID$(day, 4, 2))
  529.         y = VAL(RIGHT$(day, 4)) - 1970
  530.         SELECT CASE m 'Add the number of days for each previous month passed
  531.             CASE 2: d = d + 31
  532.             CASE 3: d = d + 59
  533.             CASE 4: d = d + 90
  534.             CASE 5: d = d + 120
  535.             CASE 6: d = d + 151
  536.             CASE 7: d = d + 181
  537.             CASE 8: d = d + 212
  538.             CASE 9: d = d + 243
  539.             CASE 10: d = d + 273
  540.             CASE 11: d = d + 304
  541.             CASE 12: d = d + 334
  542.         END SELECT
  543.         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
  544.         d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  545.         d = d + (y + 2) \ 4 'add in days for leap years passed
  546.         s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  547.         old_day = s
  548.     END IF
  549.     IF TIMER < oldt THEN 'we went from 23:59:59 (a second before midnight) to 0:0:0 (midnight)
  550.         old_day = s + 83400 'add another worth of seconds to our counter
  551.     END IF
  552.     oldt = TIMER
  553.     olds = old_day + oldt
  554.     ExtendedTimer## = olds
  555.  
  556.  
  557.  
  558.  
  559.  
  560.  
  561. FUNCTION ExtendedInput$
  562.     SHARED AltGr, Alt, Shift, Ctrl
  563.     PCOPY 0, 1
  564.     A = _AUTODISPLAY: X = POS(0): Y = CSRLIN
  565.     CP = 0: OldCP = 0 'Cursor Position
  566.     _KEYCLEAR
  567.     DO
  568.         PCOPY 1, 0
  569.  
  570.         k = KeyHit
  571.         IF Alt THEN AltDown = -1 ELSE AltDown = 0
  572.         SELECT CASE k 'without alt, add any keypresses to our input
  573.             CASE 8
  574.                 oldin$ = in$
  575.                 IF CP > 0 THEN OldCP = CP: CP = CP - 1
  576.                 in$ = LEFT$(in$, CP) + MID$(in$, CP + 2) 'backspace to erase input
  577.             CASE 9
  578.                 oldin$ = in$
  579.                 in$ = LEFT$(in$, CP) + SPACE$(4) + MID$(in$, CP + 1) 'four spaces for any TAB entered
  580.                 OldCP = CP
  581.                 CP = CP + 4
  582.             CASE 48 TO 57 '0 to 9
  583.                 IF AltDown THEN
  584.                     AltWasDown = -1: alt$ = alt$ + CHR$(k)
  585.                 ELSE
  586.                     oldin$ = in$
  587.                     in$ = LEFT$(in$, CP) + CHR$(k) + MID$(in$, CP + 1) 'add input to our string
  588.                     OldCP = CP
  589.                     CP = CP + 1
  590.                 END IF
  591.             CASE 1 TO 255 'the rest of the ASCII characters
  592.                 IF Ctrl AND (k = 118 OR k = 86) THEN
  593.                     oldin$ = in$
  594.                     in$ = LEFT$(in$, CP) + _CLIPBOARD$ + MID$(in$, CP + 1) 'ctrl-v paste
  595.                     'CTRL-V leaves cursor in position before the paste, without moving it after.
  596.                     'Feel free to modify that behavior here, if you want it to move to after the paste.
  597.                 ELSEIF Ctrl AND (k = 122 OR k = 90) THEN
  598.                     SWAP in$, oldin$: SWAP OldCP, CP 'ctrl-z undo
  599.                 ELSE
  600.                     oldin$ = in$
  601.                     in$ = LEFT$(in$, CP) + CHR$(k) + MID$(in$, CP + 1) 'add input to our string
  602.                     OldCP = CP
  603.                     CP = CP + 1
  604.                 END IF
  605.             CASE 18176 'Home
  606.                 CP = 0
  607.             CASE 20224 'End
  608.                 CP = LEN(in$)
  609.             CASE 21248 'Delete
  610.                 oldin$ = in$
  611.                 in$ = LEFT$(in$, CP) + MID$(in$, CP + 2)
  612.             CASE 19200 'Left
  613.                 CP = CP - 1
  614.                 IF CP < 0 THEN CP = 0
  615.             CASE 19712 'Right
  616.                 CP = CP + 1
  617.                 IF CP > LEN(in$) THEN CP = LEN(in$)
  618.         END SELECT
  619.  
  620.         alt$ = RIGHT$(alt$, 3)
  621.         IF AltWasDown = -1 AND AltDown = 0 THEN
  622.             v = VAL(alt$)
  623.             IF v >= 0 AND v <= 255 THEN in$ = in$ + CHR$(v): CP = CP + 1
  624.             alt$ = "": AltWasDown = 0
  625.         END IF
  626.         blink = (blink + 1) MOD 30
  627.         LOCATE Y, X
  628.         PRINT LEFT$(in$, CP);
  629.         IF blink \ 15 THEN PRINT " "; ELSE PRINT "_";
  630.         PRINT MID$(in$, CP + 1)
  631.  
  632.         _DISPLAY
  633.         _LIMIT 30
  634.     LOOP UNTIL k = 13
  635.  
  636.     PCOPY 1, 0
  637.     LOCATE Y, X: PRINT in$
  638.     ExtendedInput$ = in$

I've now added in (and slightly modified the code so that it works with the new Keyhit) the ExtendedInput function from here: https://www.qb64.org/forum/index.php?topic=1954.0

Also added a KeyDown routine which can read our new extended/remapped keycodes and tell us if simply if they're up or down.

Also added a KeyClear routine which will wait for key-up presses to finish processing and then clear them so we don't read them with future calls to the Keyhit routine.

Title: Re: Programmable Keyboard Input
Post by: SMcNeill on January 03, 2020, 10:40:31 am
Playing around with the programmable keyboard, I think I now have it configured so an user can just swap from American to German keyboards with a single simple command.

For those of you with foreign keyboards, and who normally use CP1250, give this a little test run, if you will:

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.     FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
  4.  
  5. TYPE KeyboardInfo_Type
  6.     Index AS LONG
  7.     ASCII AS LONG
  8.     Ctrl AS LONG
  9.     Shift AS LONG
  10.     Alt AS LONG
  11.     AltGr AS LONG
  12.     Repeat AS _FLOAT
  13.     LastHit AS _FLOAT
  14.     Down AS LONG
  15.     AltShift AS LONG
  16.     AltCtrl AS LONG
  17.     AltAltGr AS LONG
  18.     CtrlShift AS LONG
  19.     CtrlAlt AS LONG
  20.     CtrlAltGr AS LONG
  21.     ShiftAltGr AS LONG
  22.     CtrlAltShift AS LONG
  23.  
  24. DIM SHARED Keys(254) AS KeyboardInfo_Type
  25. Init_KeyCodes "DE"
  26. 'Remap_KeyCode 65, 65, 1, 97, 160, 142, 0.2: 'A , , a,  , Ž
  27. 'Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
  28. 'Remap_Extended_KeyCode 65, 143, 241, 242, 243, 244, 245, 246 ' and more!
  29.  
  30.  
  31. 'PRINT "Test out the input handler.  Try lots of options! => ";
  32. 'junk$ = ExtendedInput
  33. 'PRINT junk$
  34. 'PRINT
  35. 'PRINT "Pretty nifty, right?"
  36. 'KeyClear 'Notice that without this, we'll read the keyup event from where ENTER is lifted up, as the first character value below.
  37.  
  38.     k = KeyHit
  39.     IF k <> 0 THEN
  40.         'LOCATE 1, 1
  41.         SELECT CASE k
  42.             CASE 900001 'left mouse
  43.             CASE 1 TO 255
  44.                 PRINT k, CHR$(k)
  45.             CASE IS <= 0
  46.             CASE ELSE
  47.                 PRINT k
  48.         END SELECT
  49.  
  50.     END IF
  51.     'LOCATE 2, 1: PRINT KeyDown(1) 'Test to see if CHR$(1) is held down (which is generated via a CTRL-A combo)
  52.     _LIMIT 30
  53. LOOP UNTIL k = 27 'escape
  54.  
  55. SUB SetAltGr (Key1 AS INTEGER, Key2 AS INTEGER)
  56.     AltGr(0) = Key1 'any key from our index (0 says no key)
  57.     AltGr(1) = Key2 'PLUS any other key from our index (0 says no additional key)
  58.     'Using this, we can set AltGr to become several things.
  59.     '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.)
  60.     'AltGr(0) = 17, AltGr(1) = 18 -- This would use any CTRL-ALT combo to simulate a AltGr keypress.
  61.     'Some useful values are listed for quick reference below
  62.     '0 = NoKey
  63.     '17 = ANY Ctrl
  64.     '18 = ANY Alt
  65.     '162 = Left Control
  66.     '163 = Right Control
  67.     '164 = Left Alt
  68.     '165 = Right Alt
  69.  
  70.     'Default is for AltGr(0) = 165, AltGr(1) = 0, which uses Right-Alt alone as the AltGr key.
  71.     'Feel free to customize the setting to your personal preference/need.
  72.  
  73. SUB KeyClear
  74.     _DELAY .05 'give time for a keyup event to log itself so we can clear it
  75.     DO: k = KeyHit: LOOP UNTIL k = 0
  76.  
  77. FUNCTION KeyHit&
  78.     STATIC ReturnCount AS INTEGER
  79.     STATIC ReturnValues(30) AS LONG
  80.     SHARED AltGr, Alt, Shift, Ctrl
  81.     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.
  82.  
  83.  
  84.     IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  85.         'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  86.         KeyHit = ReturnValues(1)
  87.         FOR i = 1 TO ReturnCount - 1
  88.             ReturnValues(i) = ReturnValues(i + 1)
  89.         NEXT
  90.         ReturnCount = ReturnCount - 1
  91.         EXIT FUNCTION
  92.     END IF
  93.  
  94.     IF Keys(16).Down THEN Shift = -1 ELSE Shift = 0
  95.     IF Keys(17).Down THEN Ctrl = -1 ELSE Ctrl = 0
  96.     IF Keys(18).Down THEN Alt = -1 ELSE Alt = 0
  97.     IF AltGr(0) <> 0 AND AltGr(1) <> 0 THEN
  98.         IF Keys(AltGr(0)).Down AND Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  99.     ELSEIF AltGr(1) <> 0 THEN
  100.         IF Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  101.     ELSEIF AltGr(0) <> 0 THEN
  102.         IF Keys(AltGr(0)).Down THEN AltGr = -1 ELSE AltGr = 0
  103.     ELSE
  104.         AltGr = 0
  105.     END IF
  106.  
  107.     'until Ctrl or Alt status, if the key down was used to help generate AltGr as a modifier key
  108.     IF AltGr THEN
  109.         IF (AltGr(0) = 18 OR AltGr(1) = 18) THEN Alt = 0 'if we use both ALT keys to represent part of AltGr, when AltGr is active, Alt isn't.
  110.         IF (AltGr(0) = 164 OR AltGr(1) = 164) AND Keys(165).Down = 0 THEN Alt = 0 'if we use Left ALT keys to represent part of AltGr, when AltGr is active, Left Alt isn't.
  111.         IF (AltGr(0) = 165 OR AltGr(1) = 165) AND Keys(164).Down = 0 THEN Alt = 0 'if we use Right ALT keys to represent part of AltGr, when AltGr is active, Right Alt isn't.
  112.         IF (AltGr(0) = 17 OR AltGr(1) = 17) THEN Ctrl = 0 'if we use both CTRL keys to represent part of AltGr, when AltGr is active, Ctrl isn't.
  113.         IF (AltGr(0) = 162 OR AltGr(1) = 162) AND Keys(163).Down = 0 THEN Ctrl = 0 'if we use Left CTRL keys to represent part of AltGr, when AltGr is active, Left Ctrl isn't.
  114.         IF (AltGr(0) = 163 OR AltGr(1) = 163) AND Keys(162).Down = 0 THEN Ctrl = 0 'if we use Right CTRL keys to represent part of AltGr, when AltGr is active, Right Ctrl isn't.
  115.     END IF
  116.  
  117.     IF Alt AND Shift THEN AltShift = -1 ELSE AltShift = 0
  118.     IF Alt AND Ctrl THEN AltCtrl = -1 ELSE AltCtrl = 0
  119.     IF Alt AND AltAltGR THEN AltAltGR = -1 ELSE AltAltGR = 0
  120.     IF Ctrl AND Shift THEN CtrlShift = -1 ELSE CtrlShift = 0
  121.     IF Shift AND AltGr THEN ShiftAltGr = -1 ELSE ShiftAltGr = 0
  122.     IF Ctrl AND Alt AND Shift THEN CtrlAltShift = -1 ELSE CtrlAltShift = 0
  123.  
  124.         FOR i = 1 TO 254
  125.  
  126.             r = GetKeyState(Keys(i).Index) AND &H8000
  127.  
  128.             IF r THEN 'the key is down
  129.  
  130.  
  131.                 IF Keys(i).LastHit THEN
  132.                     IF ExtendedTimer > Keys(i).LastHit THEN
  133.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  134.                         ReturnValues(ReturnCount) = Keys(i).Down 'and put the existing value back in the buffer, as a key repeat
  135.                     END IF
  136.                 ELSE
  137.  
  138.                     IF Keys(i).Down = 0 THEN 'the key was up on the last pass.
  139.                         IF CtrlAltShift <> 0 AND Keys(i).CtrlAltShift <> 0 THEN 'return the CtrlAltShift value
  140.                             Keys(i).Down = Keys(i).CtrlAltShift
  141.                         ELSEIF AltAltGR <> 0 AND Keys(i).AltAltGr <> 0 THEN 'return the AltAltGr value
  142.                             Keys(i).Down = Keys(i).AltAltGr
  143.                         ELSEIF CtrlAltGr& <> 0 AND Keys(i).CtrlAltGr& <> 0 THEN 'return the CtrlAltGr& value
  144.                             Keys(i).Down = Keys(i).CtrlAltGr&
  145.                         ELSEIF ShiftAltGr <> 0 AND Keys(i).ShiftAltGr <> 0 THEN 'return the ShiftAltGr value
  146.                             Keys(i).Down = Keys(i).ShiftAltGr
  147.                         ELSEIF CtrlShift <> 0 AND Keys(i).CtrlShift <> 0 THEN 'return the CtrlShift value
  148.                             Keys(i).Down = Keys(i).CtrlShift
  149.                         ELSEIF AltCtrl <> 0 AND Keys(i).AltCtrl <> 0 THEN 'return the AltCtrl value
  150.                             Keys(i).Down = Keys(i).AltCtrl
  151.                         ELSEIF AltShift <> 0 AND Keys(i).AltShift <> 0 THEN 'return the AltShift value
  152.                             Keys(i).Down = Keys(i).AltShift
  153.                         ELSEIF AltGr <> 0 AND Keys(i).AltGr <> 0 THEN 'return the altgr value
  154.                             Keys(i).Down = Keys(i).AltGr
  155.                         ELSEIF Shift <> 0 AND Keys(i).Shift <> 0 THEN 'return the shift value
  156.                             Keys(i).Down = Keys(i).Shift
  157.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  158.                                 SELECT CASE i
  159.                                     CASE 65 TO 90: Keys(i).Down = Keys(i).ASCII
  160.                                 END SELECT
  161.                             END IF
  162.                         ELSEIF (Ctrl <> 0) AND (Keys(i).Ctrl <> 0) THEN 'return the ctrl value
  163.                             Keys(i).Down = Keys(i).Ctrl
  164.                         ELSEIF Alt <> 0 AND Keys(i).Alt <> 0 THEN 'return the alt value
  165.                             Keys(i).Down = Keys(i).Alt
  166.                         ELSE 'all that's left is to return the ASCII value
  167.                             Keys(i).Down = Keys(i).ASCII
  168.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  169.                                 SELECT CASE i
  170.                                     CASE 65 TO 90: Keys(i).Down = Keys(i).Shift
  171.                                 END SELECT
  172.                             END IF
  173.                         END IF
  174.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  175.                         ReturnValues(ReturnCount) = Keys(i).Down 'and store the value in the buffer
  176.  
  177.                         IF Keys(i).Repeat = -1 THEN 'keys that are set to a -1 on repeat simply toggle state as on, or off.
  178.                             Keys(i).LastHit = 1E+1000 'such as SHIFT, CTRL, ALT...
  179.                         ELSE
  180.                             Keys(i).LastHit = ExtendedTimer + Keys(i).Repeat 'and record when we hit it for repeat purposes
  181.                         END IF
  182.                     END IF
  183.                 END IF
  184.             ELSE
  185.                 IF Keys(i).Down THEN 'the key was down on the last pass
  186.                     ReturnCount = ReturnCount + 1
  187.                     ReturnValues(ReturnCount) = -Keys(i).Down 'mark it as being up on this one
  188.                 END IF
  189.                 Keys(i).Down = 0 'and set it back down for future passes
  190.                 Keys(i).LastHit = 0 'once again, set it as being ready to be hit again
  191.             END IF
  192.         NEXT
  193.  
  194.         IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  195.             'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  196.             KeyHit = ReturnValues(1)
  197.             FOR i = 1 TO ReturnCount - 1
  198.                 ReturnValues(i) = ReturnValues(i + 1)
  199.             NEXT
  200.             ReturnCount = ReturnCount - 1
  201.             EXIT FUNCTION
  202.         END IF
  203.  
  204.     END IF 'End of IF _WINDOWHASFOCUS
  205.  
  206.  
  207.  
  208.  
  209. SUB Remap_KeyCode (Which AS LONG, ASCII AS LONG, Ctrl AS LONG, Shift AS LONG, Alt AS LONG, AltGr AS LONG, Repeat AS _FLOAT)
  210.     DIM i AS LONG
  211.     i = Which
  212.     Keys(i).Index = i
  213.     Keys(i).ASCII = ASCII
  214.     Keys(i).Ctrl = Ctrl
  215.     Keys(i).Shift = Shift
  216.     Keys(i).Alt = Alt
  217.     Keys(i).AltGr = AltGr
  218.     Keys(i).Repeat = Repeat
  219.     Keys(i).LastHit = 0
  220.     Keys(i).Down = 0
  221.  
  222. SUB Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, _
  223.          CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
  224.     Keys(Which&).AltShift = AltShift&
  225.     Keys(Which&).AltCtrl = AltCtrl&
  226.     Keys(Which&).AltAltGr = AltAltGr&
  227.     Keys(Which&).CtrlShift = CtrlShift&
  228.     Keys(Which&).CtrlAltGr = CtrlAltGr&
  229.     Keys(Which&).ShiftAltGr = ShiftAltGr&
  230.     Keys(Which&).CtrlAltShift = CtrlAltShift&
  231.  
  232. FUNCTION KeyDown& (Code AS LONG)
  233.     IF Code <= 0 THEN EXIT FUNCTION
  234.     FOR i = 1 TO 254
  235.         IF GetAsyncKeyState(i) THEN 'first check for actual physical keys down
  236.             IF Keys(i).ASCII = Code THEN KeyDown = -1: EXIT FUNCTION 'then check to see if the code matches anything we've mapped it to.
  237.             IF Keys(i).Shift = Code THEN KeyDown = -1: EXIT FUNCTION
  238.             IF Keys(i).Alt = Code THEN KeyDown = -1: EXIT FUNCTION
  239.             IF Keys(i).AltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  240.             IF Keys(i).AltShift = Code THEN KeyDown = -1: EXIT FUNCTION
  241.             IF Keys(i).AltCtrl = Code THEN KeyDown = -1: EXIT FUNCTION
  242.             IF Keys(i).AltAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  243.             IF Keys(i).CtrlShift = Code THEN KeyDown = -1: EXIT FUNCTION
  244.             IF Keys(i).CtrlAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  245.             IF Keys(i).ShiftAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  246.             IF Keys(i).CtrlAltShift = Code THEN KeyDown = -1: EXIT FUNCTION
  247.         END IF
  248.     NEXT
  249.     KeyDown& = 0
  250.  
  251. SUB Init_KeyCodes (Language AS STRING)
  252.     RESTORE default_keyboard_data
  253.     FOR i = 1 TO 254
  254.         READ Keys(i).Index, Keys(i).ASCII, Keys(i).Ctrl, Keys(i).Shift, Keys(i).Alt, Keys(i).AltGr, Keys(i).Repeat
  255.         Keys(i).LastHit = 0: Keys(i).Down = 0
  256.     NEXT
  257.  
  258.     default_keyboard_data:
  259.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  260.     DATA 1,900001,0,0,0,0,0.2: 'Left Mouse Button
  261.     DATA 2,900002,0,0,0,0,0.2: 'Right Mouse Button
  262.     DATA 3,900003,0,0,0,0,0.2: 'VK_Cancel
  263.     DATA 4,900004,0,0,0,0,0.2: 'Middle Mouse Button
  264.     DATA 5,900005,0,0,0,0,0.2: 'Mouse Button 4
  265.     DATA 6,900006,0,0,0,0,0.2: 'Mouse Button 5
  266.     DATA 7,900007,0,0,0,0,0.2: 'Undefined
  267.     DATA 8,8,0,0,0,0,0.2: 'Backspace
  268.     DATA 9,9,0,0,0,0,0.2: 'Tab
  269.     DATA 10,900010,0,0,0,0,0.2: 'Reserved
  270.     DATA 11,900011,0,0,0,0,0.2: 'Reserved
  271.     DATA 12,19456,0,0,0,0,0.2: 'Clear
  272.     DATA 13,13,0,0,0,0,0.2: 'Enter
  273.     DATA 14,900014,0,0,0,0,0.2: 'Undefined
  274.     DATA 15,900015,0,0,0,0,0.2: 'Undefined
  275.     DATA 16,100016,0,0,0,0,-1: 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  276.     DATA 17,100017,0,0,0,0,-1: 'Ctrl   (Same)
  277.     DATA 18,100018,0,0,0,0,-1: 'Alt     (Same)
  278.     DATA 19,100019,0,0,0,0,0.2: 'Pause
  279.     DATA 20,100301,0,0,0,0,-1: 'Caps Lock
  280.     DATA 21,900021,0,0,0,0,0.2: 'VK_Hangul
  281.     DATA 22,900022,0,0,0,0,0.2: 'Undefined
  282.     DATA 23,900023,0,0,0,0,0.2: 'VK_Junja
  283.     DATA 24,900024,0,0,0,0,0.2: 'VK_Final
  284.     DATA 25,900025,0,0,0,0,0.2: 'VK_Hanga//VK_Kanji
  285.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  286.     DATA 26,900026,0,0,0,0,0.2: 'Undefined
  287.     DATA 27,27,0,0,0,0,0.2: 'ESC
  288.     DATA 28,900028,0,0,0,0,0.2: 'VK_Convert
  289.     DATA 29,900029,0,0,0,0,0.2: 'VK_NonConvert
  290.     DATA 30,900030,0,0,0,0,0.2: 'VK_Accept
  291.     DATA 31,900031,0,0,0,0,0.2: 'VK_ModeChange
  292.     DATA 32,32,0,0,0,0,0.2: 'VK_Space
  293.     DATA 33,18688,0,0,0,0,0.2: 'Page Up
  294.     DATA 34,20736,0,0,0,0,0.2: 'Page Down
  295.     DATA 35,20224,0,0,0,0,0.2: 'End
  296.     DATA 36,18176,0,0,0,0,0.2: 'Home
  297.     DATA 37,19200,0,0,0,0,0.2: 'Left Arrow
  298.     DATA 38,18432,0,0,0,0,0.2: 'Up Arrow
  299.     DATA 39,19712,0,0,0,0,0.2: 'Right Arrow
  300.     DATA 40,20480,0,0,0,0,0.2: 'Down Arrow
  301.     DATA 41,900041,0,0,0,0,-1: 'VK_SELECT
  302.     DATA 42,900042,0,0,0,0,-1: 'CK_PRINT
  303.     DATA 43,900043,0,0,0,0,-1: 'VK_EXECUTE
  304.     DATA 44,900044,0,0,0,0,-1: 'VK_SNAPSHOT
  305.     DATA 45,20992,0,0,0,0,0.2: 'INS
  306.     DATA 46,21248,0,0,0,0,0.2: 'DEL
  307.     DATA 47,900047,0,0,0,0,0.2: 'VK_HELP
  308.     DATA 48,48,0,41,0,0,0.2: '0
  309.     DATA 49,49,0,33,0,0,0.2: '1
  310.     DATA 50,50,0,64,0,0,0.2: '2
  311.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  312.     DATA 51,51,0,35,0,0,0.2: '3
  313.     DATA 52,52,0,36,0,0,0.2: '4
  314.     DATA 53,53,0,37,0,0,0.2: '5
  315.     DATA 54,54,0,94,0,0,0.2: '6
  316.     DATA 55,55,0,38,0,0,0.2: '7
  317.     DATA 56,56,0,42,0,0,0.2: '8
  318.     DATA 57,57,0,40,0,0,0.2: '9
  319.     DATA 58,900058,0,0,0,0,0.2: 'Undefined
  320.     DATA 59,900059,0,0,0,0,0.2: 'Undefined
  321.     DATA 60,900060,0,0,0,0,0.2: 'Undefined
  322.     DATA 61,900061,0,0,0,0,0.2: 'Undefined
  323.     DATA 62,900062,0,0,0,0,0.2: 'Undefined
  324.     DATA 63,900063,0,0,0,0,0.2: 'Undefined
  325.     DATA 64,900064,0,0,0,0,0.2: 'Undefined
  326.     DATA 65,65,0,97,0,0,0.2: 'a
  327.     DATA 66,66,0,98,0,0,0.2: 'b
  328.     DATA 67,67,0,99,0,0,0.2: 'c
  329.     DATA 68,68,0,100,0,0,0.2: 'd
  330.     DATA 69,69,0,101,0,0,0.2: 'e
  331.     DATA 70,70,0,102,0,0,0.2: 'f
  332.     DATA 71,71,0,103,0,0,0.2: 'g
  333.     DATA 72,72,0,104,0,0,0.2: 'h
  334.     DATA 73,73,0,105,0,0,0.2: 'i
  335.     DATA 74,74,0,106,0,0,0.2: 'j
  336.     DATA 75,75,0,107,0,0,0.2: 'k
  337.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  338.     DATA 76,76,0,108,0,0,0.2: 'l
  339.     DATA 77,77,0,109,0,0,0.2: 'm
  340.     DATA 78,78,0,110,0,0,0.2: 'n
  341.     DATA 79,79,0,111,0,0,0.2: 'o
  342.     DATA 80,80,0,112,0,0,0.2: 'p
  343.     DATA 81,81,0,113,0,0,0.2: 'q
  344.     DATA 82,82,0,114,0,0,0.2: 'r
  345.     DATA 83,83,0,115,0,0,0.2: 's
  346.     DATA 84,84,0,116,0,0,0.2: 't
  347.     DATA 85,85,0,117,0,0,0.2: 'u
  348.     DATA 86,86,0,118,0,0,0.2: 'v
  349.     DATA 87,87,0,119,0,0,0.2: 'w
  350.     DATA 88,88,0,120,0,0,0.2: 'x
  351.     DATA 89,89,0,121,0,0,0.2: 'y
  352.     DATA 90,90,0,122,0,0,0.2: 'z
  353.     DATA 91,100311,0,0,0,0,-1: 'Left WIN
  354.     DATA 92,100312,0,0,0,0,-1: 'Right WIN
  355.     DATA 93,100319,0,0,0,0,-1: 'Applications (Menu)
  356.     DATA 94,900094,0,0,0,0,0.2: 'Reserved
  357.     DATA 95,900095,0,0,0,0,0.2: 'VK_SLEEP
  358.     DATA 96,48,0,0,0,0,0.2: 'Numpad 0
  359.     DATA 97,49,0,0,0,0,0.2: 'Numpad 1
  360.     DATA 98,50,0,0,0,0,0.2: 'Numpad 2
  361.     DATA 99,51,0,0,0,0,0.2: 'Numpad 3
  362.     DATA 100,52,0,0,0,0,0.2: 'Numpad 4
  363.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  364.     DATA 101,53,0,0,0,0,0.2: 'Numpad 5
  365.     DATA 102,54,0,0,0,0,0.2: 'Numpad 6
  366.     DATA 103,55,0,0,0,0,0.2: 'Numpad 7
  367.     DATA 104,56,0,0,0,0,0.2: 'Numpad 8
  368.     DATA 105,57,0,0,0,0,0.2: 'Numpad 9
  369.     DATA 106,42,0,0,0,0,0.2: 'Numpad *
  370.     DATA 107,43,0,0,0,0,0.2: 'Numpad +
  371.     DATA 108,900108,0,0,0,0,0.2: 'VK_SEPARATOR
  372.     DATA 109,51,0,0,0,0,0.2: 'Numpad -
  373.     DATA 110,52,0,0,0,0,0.2: 'Numpad .
  374.     DATA 111,53,0,0,0,0,0.2: 'Numpad /
  375.     DATA 112,15104,0,0,0,0,0.2: 'F1
  376.     DATA 113,15360,0,0,0,0,0.2: 'F2
  377.     DATA 114,15616,0,0,0,0,0.2: 'F3
  378.     DATA 115,15872,0,0,0,0,0.2: 'F4
  379.     DATA 116,16128,0,0,0,0,0.2: 'F5
  380.     DATA 117,16384,0,0,0,0,0.2: 'F6
  381.     DATA 118,16640,0,0,0,0,0.2: 'F7
  382.     DATA 119,16896,0,0,0,0,0.2: 'F8
  383.     DATA 120,17152,0,0,0,0,0.2: 'F9
  384.     DATA 121,17408,0,0,0,0,0.2: 'F10
  385.     DATA 122,34048,0,0,0,0,0.2: 'F11
  386.     DATA 123,34304,0,0,0,0,0.2: 'F12
  387.     DATA 124,900124,0,0,0,0,0.2: 'F13
  388.     DATA 125,900125,0,0,0,0,0.2: 'F14
  389.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  390.     DATA 126,900126,0,0,0,0,0.2: 'F15
  391.     DATA 127,900127,0,0,0,0,0.2: 'F16
  392.     DATA 128,900128,0,0,0,0,0.2: 'F17
  393.     DATA 129,900129,0,0,0,0,0.2: 'F18
  394.     DATA 130,900130,0,0,0,0,0.2: 'F19
  395.     DATA 131,900131,0,0,0,0,0.2: 'F20
  396.     DATA 132,900132,0,0,0,0,0.2: 'F21
  397.     DATA 133,900133,0,0,0,0,0.2: 'F22
  398.     DATA 134,900134,0,0,0,0,0.2: 'F23
  399.     DATA 135,900135,0,0,0,0,0.2: 'F24
  400.     DATA 136,900136,0,0,0,0,0.2: 'Unassigned
  401.     DATA 137,900137,0,0,0,0,0.2: 'Unassigned
  402.     DATA 138,900138,0,0,0,0,0.2: 'Unassigned
  403.     DATA 139,900139,0,0,0,0,0.2: 'Unassigned
  404.     DATA 140,900140,0,0,0,0,0.2: 'Unassigned
  405.     DATA 141,900141,0,0,0,0,0.2: 'Unassigned
  406.     DATA 142,900142,0,0,0,0,0.2: 'Unassigned
  407.     DATA 143,900143,0,0,0,0,0.2: 'Unassigned
  408.     DATA 144,100300,0,0,0,0,-1: 'NUM LOCK
  409.     DATA 145,100302,0,0,0,0,-1: 'SCROLL LOCK
  410.     DATA 146,900146,0,0,0,0,0.2: 'OEM SPECIFIC
  411.     DATA 147,900147,0,0,0,0,0.2: 'OEM SPECIFIC
  412.     DATA 148,900148,0,0,0,0,0.2: 'OEM SPECIFIC
  413.     DATA 149,900149,0,0,0,0,0.2: 'OEM SPECIFIC
  414.     DATA 150,900150,0,0,0,0,0.2: 'OEM SPECIFIC
  415.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  416.     DATA 151,900151,0,0,0,0,0.2: 'Unassigned
  417.     DATA 152,900152,0,0,0,0,0.2: 'Unassigned
  418.     DATA 153,900153,0,0,0,0,0.2: 'Unassigned
  419.     DATA 154,900154,0,0,0,0,0.2: 'Unassigned
  420.     DATA 155,900155,0,0,0,0,0.2: 'Unassigned
  421.     DATA 156,900156,0,0,0,0,0.2: 'Unassigned
  422.     DATA 157,900157,0,0,0,0,0.2: 'Unassigned
  423.     DATA 158,900158,0,0,0,0,0.2: 'Unassigned
  424.     DATA 159,900159,0,0,0,0,0.2: 'Unassigned
  425.     DATA 160,100304,0,0,0,0,-1: 'Left Shift
  426.     DATA 161,100303,0,0,0,0,-1: 'Right Shift
  427.     DATA 162,100306,0,0,0,0,-1: 'Left Control
  428.     DATA 163,100305,0,0,0,0,-1: 'Right Control
  429.     DATA 164,100308,0,0,0,0,-1: 'Left Alt
  430.     DATA 165,100309,0,0,0,0,-1: 'Right Alt
  431.     DATA 166,900166,0,0,0,0,0.2: 'Browser back
  432.     DATA 167,900167,0,0,0,0,0.2: 'Browser forward
  433.     DATA 168,900168,0,0,0,0,0.2: 'Browser refresh
  434.     DATA 169,900169,0,0,0,0,0.2: 'Browser stop
  435.     DATA 170,900170,0,0,0,0,0.2: 'Browser search
  436.     DATA 171,900171,0,0,0,0,0.2: 'Browser favorites
  437.     DATA 172,900172,0,0,0,0,0.2: 'Browser home
  438.     DATA 173,900173,0,0,0,0,0.2: 'Mute
  439.     DATA 174,900174,0,0,0,0,0.2: 'Vol Down
  440.     DATA 175,900175,0,0,0,0,0.2: 'Vol Up
  441.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  442.     DATA 176,900176,0,0,0,0,0.2: 'Media Next
  443.     DATA 177,900177,0,0,0,0,0.2: 'Media prev
  444.     DATA 178,900178,0,0,0,0,0.2: 'Media stop
  445.     DATA 179,900179,0,0,0,0,0.2: 'Media Play/Pause
  446.     DATA 180,900180,0,0,0,0,0.2: 'Launch mail
  447.     DATA 181,900181,0,0,0,0,0.2: 'Launch media select
  448.     DATA 182,900182,0,0,0,0,0.2: 'Launch app1
  449.     DATA 183,900183,0,0,0,0,0.2: 'Launch app2
  450.     DATA 184,900184,0,0,0,0,0.2: 'Reserved
  451.     DATA 185,900185,0,0,0,0,0.2: 'Reserved
  452.     DATA 186,59,0,58,0,0,0.2: ';:
  453.     DATA 187,61,0,43,0,0,0.2: '=+
  454.     DATA 188,44,0,60,0,0,0.2: ',<
  455.     DATA 189,45,0,95,0,0,0.2: '-_
  456.     DATA 190,46,0,62,0,0,0.2: '.>
  457.     DATA 191,47,0,63,0,0,0.2: '/?
  458.     DATA 192,96,0,126,0,0,0.2: '`~
  459.     DATA 193,900193,0,0,0,0,0.2: 'Reserved
  460.     DATA 194,900194,0,0,0,0,0.2: 'Reserved
  461.     DATA 195,900195,0,0,0,0,0.2: 'Reserved
  462.     DATA 196,900196,0,0,0,0,0.2: 'Reserved
  463.     DATA 197,900197,0,0,0,0,0.2: 'Reserved
  464.     DATA 198,900198,0,0,0,0,0.2: 'Reserved
  465.     DATA 199,900199,0,0,0,0,0.2: 'Reserved
  466.     DATA 200,900200,0,0,0,0,0.2: 'Reserved
  467.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  468.     DATA 201,900201,0,0,0,0,0.2: 'Reserved
  469.     DATA 202,900202,0,0,0,0,0.2: 'Reserved
  470.     DATA 203,900203,0,0,0,0,0.2: 'Reserved
  471.     DATA 204,900204,0,0,0,0,0.2: 'Reserved
  472.     DATA 205,900205,0,0,0,0,0.2: 'Reserved
  473.     DATA 206,900206,0,0,0,0,0.2: 'Reserved
  474.     DATA 207,900207,0,0,0,0,0.2: 'Reserved
  475.     DATA 208,900208,0,0,0,0,0.2: 'Reserved
  476.     DATA 209,900209,0,0,0,0,0.2: 'Reserved
  477.     DATA 210,900210,0,0,0,0,0.2: 'Reserved
  478.     DATA 211,900211,0,0,0,0,0.2: 'Reserved
  479.     DATA 212,900212,0,0,0,0,0.2: 'Reserved
  480.     DATA 213,900213,0,0,0,0,0.2: 'Reserved
  481.     DATA 214,900214,0,0,0,0,0.2: 'Reserved
  482.     DATA 215,900215,0,0,0,0,0.2: 'Reserved
  483.     DATA 216,900216,0,0,0,0,0.2: 'Unassigned
  484.     DATA 217,900217,0,0,0,0,0.2: 'Unassigned
  485.     DATA 218,900218,0,0,0,0,0.2: 'Unassigned
  486.     DATA 219,91,0,123,0,0,0.2: '[{
  487.     DATA 220,92,0,124,0,0,0.2: '\|
  488.     DATA 221,93,0,125,0,0,0.2: ']}
  489.     DATA 222,39,0,34,0,0,0.2: ''"
  490.     DATA 223,900223,0,0,0,0,0.2: 'OEM SPECIFIC
  491.     DATA 224,900224,0,0,0,0,0.2: 'Reserved
  492.     DATA 225,900225,0,0,0,0,0.2: 'OEM SPECIFIC d
  493.     DATA 226,900226,0,0,0,0,0.2: 'Either the Angle Bracket key,or Backslash on RT 102-key keyboard
  494.     DATA 227,900227,0,0,0,0,0.2: 'OEM SPECIFIC
  495.     DATA 228,900228,0,0,0,0,0.2: 'OEM SPECIFIC
  496.     DATA 229,900229,0,0,0,0,0.2: 'IME PROCESS key (whatever that is)
  497.     DATA 230,900230,0,0,0,0,0.2: 'OEM SPECIFIC
  498.     DATA 231,900231,0,0,0,0,0.2: 'Used to pass UNICODE characters (however that works)
  499.     DATA 232,900232,0,0,0,0,0.2: 'Unassigned
  500.     DATA 233,900233,0,0,0,0,0.2: 'OEM SPECIFIC
  501.     DATA 234,900234,0,0,0,0,0.2: 'OEM SPECIFIC
  502.     DATA 235,900235,0,0,0,0,0.2: 'OEM SPECIFIC
  503.     DATA 236,900236,0,0,0,0,0.2: 'OEM SPECIFIC
  504.     DATA 237,900237,0,0,0,0,0.2: 'OEM SPECIFIC
  505.     DATA 238,900238,0,0,0,0,0.2: 'OEM SPECIFIC
  506.     DATA 239,900239,0,0,0,0,0.2: 'OEM SPECIFIC
  507.     DATA 240,900240,0,0,0,0,0.2: 'OEM SPECIFIC
  508.     DATA 241,900241,0,0,0,0,0.2: 'OEM SPECIFIC
  509.     DATA 242,900242,0,0,0,0,0.2: 'OEM SPECIFIC
  510.     DATA 243,900243,0,0,0,0,0.2: 'OEM SPECIFIC
  511.     DATA 244,900244,0,0,0,0,0.2: 'OEM SPECIFIC
  512.     DATA 245,900245,0,0,0,0,0.2: 'OEM SPECIFIC
  513.     DATA 246,900246,0,0,0,0,0.2: 'VK_ATTN
  514.     DATA 247,900247,0,0,0,0,0.2: 'VK_ATTN
  515.     DATA 248,900248,0,0,0,0,0.2: 'VK_ATTN
  516.     DATA 249,900249,0,0,0,0,0.2: 'VK_ATTN
  517.     DATA 250,900250,0,0,0,0,0.2: 'VK_ATTN
  518.     DATA 251,900251,0,0,0,0,0.2: 'VK_ATTN
  519.     DATA 252,900252,0,0,0,0,0.2: 'Reserved
  520.     DATA 253,900253,0,0,0,0,0.2: 'VK_PA1
  521.     DATA 254,900253,0,0,0,0,0.2: 'VK_OEM_CLEAR
  522.     DATA 0,0,0,0,0,0,0.2: 'END OF DATA
  523.     AltGr(0) = 165
  524.     AltGr(1) = 0
  525.  
  526.     SELECT CASE Language
  527.         CASE "DE"
  528.             RESTORE Microsoft_windows_cp1250:
  529.             FOR i = 128 TO 255
  530.                 READ unicode
  531.                 _MAPUNICODE unicode TO ASCIIcode
  532.             NEXT
  533.             Microsoft_windows_cp1250:
  534.             DATA 8364,0,8218,0,8222,8230,8224,8225,0,8240,352,8249,346,356,381,377
  535.             DATA 0,8216,8217,8220,8221,8226,8211,8212,0,8482,353,8250,347,357,382,378
  536.             DATA 160,711,728,321,164,260,166,167,168,169,350,171,172,173,174,379
  537.             DATA 176,177,731,322,180,181,182,183,184,261,351,187,317,733,318,380
  538.             DATA 340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270
  539.             DATA 272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223
  540.             DATA 341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271
  541.             DATA 273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729
  542.             'Remap_KeyCode (Which, ASCII, Ctrl , Shift, Alt, AltGr, Repeat AS _FLOAT)
  543.             Remap_KeyCode 226, 60, 0, 62, 124, 92, 0.2 '<>|
  544.             Remap_KeyCode 219, 225, 0, 63, 0, 0, 0.2 '-
  545.             Remap_KeyCode 48, 48, 0, 61, 0, 125, 0.2 '0
  546.             Remap_KeyCode 192, 148, 0, 153, 0, 0, 0.2
  547.             Remap_KeyCode 222, 132, 0, 142, 0, 0, 0.2
  548.             Remap_KeyCode 50, 50, 0, 34, 0, 253, 0.2: '2 .. I don't see a superscript 3 for AltGr codes for the 3 key.
  549.             Remap_KeyCode 51, 51, 0, 35, 0, 0, 0.2: '3 ..I don't see the squiggle for this in the ASCII code.  It needs to be changed, but I dunno with what.
  550.             Remap_KeyCode 54, 54, 0, 38, 0, 0, 0.2: '6
  551.             Remap_KeyCode 55, 55, 0, 47, 0, 123, 0.2: '7
  552.             Remap_KeyCode 56, 56, 0, 40, 0, 91, 0.2: '8
  553.             Remap_KeyCode 57, 57, 0, 41, 0, 93, 0.2: '9
  554.             Remap_KeyCode 186, 129, 0, 154, 0, 0, 0.2: ';:
  555.             Remap_KeyCode 187, 43, 0, 42, 0, 126, 0.2: '=+
  556.             Remap_KeyCode 191, 35, 0, 249, 0, 0, 0.2: '/?
  557.             Remap_KeyCode 81, 81, 0, 113, 0, 64, 0.2: 'q
  558.             Remap_KeyCode 69, 69, 0, 101, 0, 238, 0.2: 'e
  559.             Remap_KeyCode 77, 77, 0, 109, 0, 0, 0.2: 'm -- again, I failed to find the goofy u which AltGr produces in the 256 ASCII set
  560.     END SELECT
  561.  
  562.  
  563.  
  564.  
  565.  
  566. FUNCTION ExtendedTimer##
  567.     'modified extendedtimer to store the old day's count, and not have to recalculate it every time the routine is called.
  568.  
  569.     STATIC olds AS _FLOAT, old_day AS _FLOAT
  570.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  571.     DIM s AS _FLOAT, day AS STRING
  572.     IF olds = 0 THEN 'calculate the day the first time the extended timer runs
  573.         day = DATE$
  574.         m = VAL(LEFT$(day, 2))
  575.         d = VAL(MID$(day, 4, 2))
  576.         y = VAL(RIGHT$(day, 4)) - 1970
  577.         SELECT CASE m 'Add the number of days for each previous month passed
  578.             CASE 2: d = d + 31
  579.             CASE 3: d = d + 59
  580.             CASE 4: d = d + 90
  581.             CASE 5: d = d + 120
  582.             CASE 6: d = d + 151
  583.             CASE 7: d = d + 181
  584.             CASE 8: d = d + 212
  585.             CASE 9: d = d + 243
  586.             CASE 10: d = d + 273
  587.             CASE 11: d = d + 304
  588.             CASE 12: d = d + 334
  589.         END SELECT
  590.         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
  591.         d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  592.         d = d + (y + 2) \ 4 'add in days for leap years passed
  593.         s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  594.         old_day = s
  595.     END IF
  596.     IF TIMER < oldt THEN 'we went from 23:59:59 (a second before midnight) to 0:0:0 (midnight)
  597.         old_day = s + 83400 'add another worth of seconds to our counter
  598.     END IF
  599.     oldt = TIMER
  600.     olds = old_day + oldt
  601.     ExtendedTimer## = olds
  602.  
  603.  
  604.  
  605.  
  606.  
  607.  
  608. FUNCTION ExtendedInput$
  609.     SHARED AltGr, Alt, Shift, Ctrl
  610.     PCOPY 0, 1
  611.     A = _AUTODISPLAY: X = POS(0): Y = CSRLIN
  612.     CP = 0: OldCP = 0 'Cursor Position
  613.     _KEYCLEAR
  614.     DO
  615.         PCOPY 1, 0
  616.  
  617.         k = KeyHit
  618.         IF Alt THEN AltDown = -1 ELSE AltDown = 0
  619.         SELECT CASE k 'without alt, add any keypresses to our input
  620.             CASE 8
  621.                 oldin$ = in$
  622.                 IF CP > 0 THEN OldCP = CP: CP = CP - 1
  623.                 in$ = LEFT$(in$, CP) + MID$(in$, CP + 2) 'backspace to erase input
  624.             CASE 9
  625.                 oldin$ = in$
  626.                 in$ = LEFT$(in$, CP) + SPACE$(4) + MID$(in$, CP + 1) 'four spaces for any TAB entered
  627.                 OldCP = CP
  628.                 CP = CP + 4
  629.             CASE 48 TO 57 '0 to 9
  630.                 IF AltDown THEN
  631.                     AltWasDown = -1: alt$ = alt$ + CHR$(k)
  632.                 ELSE
  633.                     oldin$ = in$
  634.                     in$ = LEFT$(in$, CP) + CHR$(k) + MID$(in$, CP + 1) 'add input to our string
  635.                     OldCP = CP
  636.                     CP = CP + 1
  637.                 END IF
  638.             CASE 1 TO 255 'the rest of the ASCII characters
  639.                 IF Ctrl AND (k = 118 OR k = 86) THEN
  640.                     oldin$ = in$
  641.                     in$ = LEFT$(in$, CP) + _CLIPBOARD$ + MID$(in$, CP + 1) 'ctrl-v paste
  642.                     'CTRL-V leaves cursor in position before the paste, without moving it after.
  643.                     'Feel free to modify that behavior here, if you want it to move to after the paste.
  644.                 ELSEIF Ctrl AND (k = 122 OR k = 90) THEN
  645.                     SWAP in$, oldin$: SWAP OldCP, CP 'ctrl-z undo
  646.                 ELSE
  647.                     oldin$ = in$
  648.                     in$ = LEFT$(in$, CP) + CHR$(k) + MID$(in$, CP + 1) 'add input to our string
  649.                     OldCP = CP
  650.                     CP = CP + 1
  651.                 END IF
  652.             CASE 18176 'Home
  653.                 CP = 0
  654.             CASE 20224 'End
  655.                 CP = LEN(in$)
  656.             CASE 21248 'Delete
  657.                 oldin$ = in$
  658.                 in$ = LEFT$(in$, CP) + MID$(in$, CP + 2)
  659.             CASE 19200 'Left
  660.                 CP = CP - 1
  661.                 IF CP < 0 THEN CP = 0
  662.             CASE 19712 'Right
  663.                 CP = CP + 1
  664.                 IF CP > LEN(in$) THEN CP = LEN(in$)
  665.         END SELECT
  666.  
  667.         alt$ = RIGHT$(alt$, 3)
  668.         IF AltWasDown = -1 AND AltDown = 0 THEN
  669.             v = VAL(alt$)
  670.             IF v >= 0 AND v <= 255 THEN in$ = in$ + CHR$(v): CP = CP + 1
  671.             alt$ = "": AltWasDown = 0
  672.         END IF
  673.         blink = (blink + 1) MOD 30
  674.         LOCATE Y, X
  675.         PRINT LEFT$(in$, CP);
  676.         IF blink \ 15 THEN PRINT " "; ELSE PRINT "_";
  677.         PRINT MID$(in$, CP + 1)
  678.  
  679.         _DISPLAY
  680.         _LIMIT 30
  681.     LOOP UNTIL k = 13
  682.  
  683.     PCOPY 1, 0
  684.     LOCATE Y, X: PRINT in$
  685.     ExtendedInput$ = in$
  686.  

I know there's a few symbols missing, but those may simply be my weak eyes overlooking them as I scanned the character page for their codes repeatedly for them.  (Such as the squiggle wiggle SHIFT-3 has with the onscreen keyboard.)

There's also a few onscreen keys which I couldn't seem to read at all... WHY, I dunno. Is it a glitch with the onscreen keyboard?  With the windows library function I used to check key presses?  My code??  I dunno!!  Will it work with an actual keyboard and not the onscreen one that Win 10 provides?  I dunno!

All I can say at this point is, "Feel free to test it out and let me know how it works (if at all)."  Hopefully it'll work for folks with non-standard US keyboards, who use CP1250..  If not -- well, I didn't actually promise it would act.  I just promise that I tried to make it work.. :P
Title: Re: Programmable Keyboard Input
Post by: RhoSigma on January 03, 2020, 12:03:35 pm
Hi Steve,

tested with the real DE keyboard (not onscreen), it seems to work properly for the regular keys (no modifier) and their respective SHIFT mappings, except for the squiggle wiggle SHIFT-3 (paragraph btw.) However some of the AltGr mappings are wrong or missing.
Man, then I realized, we need a custom font when working with _MAPUNICODE. Done so, but no difference, even worse on some SHIFT+key (interpunctation keys mainly).

Another thing to think of, many european languages can be properly displayed using CP437. I'd prefer not to be forced on a specific CP, because it requires custom fonts to be used, which is not always disireable.

IMHO, you should keep the routines as they were before and let the users in the respective countries contribute the required mappings over time, which you can then put into their own SUBs like "SetKeymapDE()", "SetKeymapFR()" etc.
This might take a bit more time, until people will contribute, but I think it's better than "overautomate" things, which obviously can't be automated very well by its nature.
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic on January 04, 2020, 07:39:14 pm
Hi Steve
here my feedback on the last code that you have posted at you last post here.
Well it does not recognize
LeftClick of mouse

more it doesn't distinguish between 3 on keyboard 3 on numlock keyboard, on numlock keyboard, / on numlock and 5

for the remaining part I'm testing for adjust of value and board on the screen.
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on January 04, 2020, 08:34:38 pm
Hi Steve
here my feedback on the last code that you have posted at you last post here.
Well it does not recognize
LeftClick of mouse

more it doesn't distinguish between 3 on keyboard 3 on numlock keyboard, on numlock keyboard, / on numlock and 5

for the remaining part I'm testing for adjust of value and board on the screen.

It works with the left mouse just fine; I just have it ignore it on purpose so it doesn't spam the code 900001 every time I clicked on something with the onscreen keyboard.  ;)

Code: [Select]
        SELECT CASE k
            CASE 900001 'left mouse
            CASE 1 TO 255
                PRINT k, CHR$(k)
            CASE IS <= 0
            CASE ELSE
                PRINT k
        END SELECT

Quote
more it doesn't distinguish between 3 on keyboard 3 on numlock keyboard, on numlock keyboard, / on numlock and 5

I mapped these to the Windows Onscreen keyboard, so I'm not certain how accurate they'll work with an actual keyboard.  According to Rho, they don't seem to work worth a hoot for him, so I guess I'll just have to wait for users to assign their own keys and share them with us, before I can build a swappable language/keyboard library.  There's only so much testing/experimenting I can do with the built-in tools Microsoft gives us, and all I can do is try and code the keys to match what they offer for me -- which apparently isn't that similar to the real hardware.   :(

Thanks for testing it out, and reporting back for me.  At the least, perhaps it'll be a roadmap to help show others how they can map their own language/keyboard to work with the system.  I think this, along with the UTF-8 and Unicode convertors I worked up, will be more than capable to handle any input/output needs which someone needs in the future, once they configure the two to work together for them.  ;)
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic on January 05, 2020, 11:26:46 am
Hi Steve
the first feedback:

this is the keyboard that I'm using to test your code.
  [ This attachment cannot be displayed inline in 'Print Page' view ]  
and these are the difference that I 'm finding with US standard setting
in this moment if I press the key in your application I get the code on the middle with the following characters while if I press the keys on the first column in another application for example Notepad of Windows I get the characters that I read on the keyboard.

Quote
keys used  -> code   char get vs--> IT
shift + . ->62    >   -->:
shift + , -> 60  <  --> ;
ù  -> 35  # -->ù
. ->  249  . -->§
à ->  132     -->à
Shift+à -> 142 ->   -->°
altgr + à-> 132   -->#
ò -> 148 ->  -->ò
shift + ò -> 153 ->   -->ç
altgr +ò ->    -->@
è ->129  -->è
Shift + è -> 154   -->è
altgr + à -> 129  -->[
altgr + + ->126  tilde -->]
' ->225   -->'
93 -> ] --> ì
altgr + shift + + ->125  tilde  --> }
altgr + shift + è -> 154  -->{
shift+ì -> 125  } -->^
shift+3 ->35 # --> £

where you see blank is a character that is not of italian alphabet and not on the keyboard.
Thanks for your work...

now how can I build up  the SUB  IT_Keyboard ? I don't like to mess your wonderful work, so I wait for instructions.
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic on January 05, 2020, 11:39:55 am
the second feedback:
about
Quote
more it doesn't distinguish between 3 on keyboard 3 on numlock keyboard, on numlock keyboard, / on numlock and 5

I want be clearer than above affirmation:
in your application if I press key 3 with has  also a # on it I get back 51  3, and this same result I get back if I press - on the numeric keypad on the right of the keyboard (over the + and at right of *) so for now we cannot distinguish between these two keys, moreover if I activate NumLock we can add another key that gets back with 51  3 in your application and this is the 3 (PGDN) key on numeric keypad.

the same issue arises with key 5 (%)  and / of numeric keypad that together give back 53  5, moreover if I activate NumLock I get back the same code pressing 5 on numeric keypad. I think that it will be a way to distinguish among these keys.

Thanks to read
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on January 05, 2020, 12:23:38 pm
It distinguishes between the numbers and the numpad; it simply has been coded to return the same values for us, making it seem as it it hasn't.

For the number keys above the alphabet:

Code: [Select]
    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

And for the numpad:
Code: [Select]
    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 /

Let's compare the two values 3, for example:
    DATA 51,51,0,35,0,0,0.2: '3
    DATA 99,51,0,0,0,0,0.2: 'Numpad 3

The Red values above represent the internal key which Windows designates for the physical key on our keyboard.
The Blue values are the ASCII values which we return when we press that key.  They're different physical keys, but we've mapped them both to return the same values for us. 

I suppose I should probably write a small helper routine for us though, so one can tell which of the physical keys is being pressed, just in case they wanted to be able to distinguish between the two of them -- though that would actually be just as simple as check with the physical value.

IF keys(51).down then 'It's the number 3, above the letter keys
IF keys(99).down then 'It's the numpad 3
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on January 05, 2020, 03:29:03 pm
now how can I build up  the SUB  IT_Keyboard ? I don't like to mess your wonderful work, so I wait for instructions.

Here's the simplest way:

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.     FUNCTION GetAsyncKeyState% (BYVAL vkey AS LONG)
  4.  
  5. TYPE KeyboardInfo_Type
  6.     Index AS LONG
  7.     ASCII AS LONG
  8.     Ctrl AS LONG
  9.     Shift AS LONG
  10.     Alt AS LONG
  11.     AltGr AS LONG
  12.     Repeat AS _FLOAT
  13.     LastHit AS _FLOAT
  14.     Down AS LONG
  15.     AltShift AS LONG
  16.     AltCtrl AS LONG
  17.     AltAltGr AS LONG
  18.     CtrlShift AS LONG
  19.     CtrlAlt AS LONG
  20.     CtrlAltGr AS LONG
  21.     ShiftAltGr AS LONG
  22.     CtrlAltShift AS LONG
  23.  
  24. DIM SHARED Keys(254) AS KeyboardInfo_Type
  25. Init_KeyCodes
  26. Remap_KeyCode 65, 65, 1, 97, 160, 142, 0.2: 'A , , a,  , Ž
  27. 'Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
  28. Remap_Extended_KeyCode 65, 143, 241, 242, 243, 244, 245, 246 ' and more!
  29.  
  30.  
  31.     k = KeyHit
  32.     IF k > 0 THEN
  33.         CLS
  34.         IF k > 0 THEN PRINT "Physical Key Down: "; Physical_KeyDown(k)
  35.         PRINT "Key Code Down: "; k;
  36.         IF ABS(k) < 256 THEN PRINT CHR$(34); CHR$(ABS(k)); CHR$(34) ELSE PRINT
  37.     END IF
  38.     _LIMIT 30
  39. LOOP UNTIL k = 27 'escape
  40.  
  41. SUB SetAltGr (Key1 AS INTEGER, Key2 AS INTEGER)
  42.     AltGr(0) = Key1 'any key from our index (0 says no key)
  43.     AltGr(1) = Key2 'PLUS any other key from our index (0 says no additional key)
  44.     'Using this, we can set AltGr to become several things.
  45.     '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.)
  46.     'AltGr(0) = 17, AltGr(1) = 18 -- This would use any CTRL-ALT combo to simulate a AltGr keypress.
  47.     'Some useful values are listed for quick reference below
  48.     '0 = NoKey
  49.     '17 = ANY Ctrl
  50.     '18 = ANY Alt
  51.     '162 = Left Control
  52.     '163 = Right Control
  53.     '164 = Left Alt
  54.     '165 = Right Alt
  55.  
  56.     'Default is for AltGr(0) = 165, AltGr(1) = 0, which uses Right-Alt alone as the AltGr key.
  57.     'Feel free to customize the setting to your personal preference/need.
  58.  
  59. SUB KeyClear
  60.     _DELAY .05 'give time for a keyup event to log itself so we can clear it
  61.     DO: k = KeyHit: LOOP UNTIL k = 0
  62.  
  63. FUNCTION KeyHit&
  64.     STATIC ReturnCount AS INTEGER
  65.     STATIC ReturnValues(30) AS LONG
  66.     SHARED AltGr, Alt, Shift, Ctrl
  67.     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.
  68.  
  69.  
  70.     IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  71.         'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  72.         KeyHit = ReturnValues(1)
  73.         FOR i = 1 TO ReturnCount - 1
  74.             ReturnValues(i) = ReturnValues(i + 1)
  75.         NEXT
  76.         ReturnCount = ReturnCount - 1
  77.         EXIT FUNCTION
  78.     END IF
  79.  
  80.     IF Keys(16).Down THEN Shift = -1 ELSE Shift = 0
  81.     IF Keys(17).Down THEN Ctrl = -1 ELSE Ctrl = 0
  82.     IF Keys(18).Down THEN Alt = -1 ELSE Alt = 0
  83.     IF AltGr(0) <> 0 AND AltGr(1) <> 0 THEN
  84.         IF Keys(AltGr(0)).Down AND Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  85.     ELSEIF AltGr(1) <> 0 THEN
  86.         IF Keys(AltGr(1)).Down THEN AltGr = -1 ELSE AltGr = 0
  87.     ELSEIF AltGr(0) <> 0 THEN
  88.         IF Keys(AltGr(0)).Down THEN AltGr = -1 ELSE AltGr = 0
  89.     ELSE
  90.         AltGr = 0
  91.     END IF
  92.  
  93.     'until Ctrl or Alt status, if the key down was used to help generate AltGr as a modifier key
  94.     IF AltGr THEN
  95.         IF (AltGr(0) = 18 OR AltGr(1) = 18) THEN Alt = 0 'if we use both ALT keys to represent part of AltGr, when AltGr is active, Alt isn't.
  96.         IF (AltGr(0) = 164 OR AltGr(1) = 164) AND Keys(165).Down = 0 THEN Alt = 0 'if we use Left ALT keys to represent part of AltGr, when AltGr is active, Left Alt isn't.
  97.         IF (AltGr(0) = 165 OR AltGr(1) = 165) AND Keys(164).Down = 0 THEN Alt = 0 'if we use Right ALT keys to represent part of AltGr, when AltGr is active, Right Alt isn't.
  98.         IF (AltGr(0) = 17 OR AltGr(1) = 17) THEN Ctrl = 0 'if we use both CTRL keys to represent part of AltGr, when AltGr is active, Ctrl isn't.
  99.         IF (AltGr(0) = 162 OR AltGr(1) = 162) AND Keys(163).Down = 0 THEN Ctrl = 0 'if we use Left CTRL keys to represent part of AltGr, when AltGr is active, Left Ctrl isn't.
  100.         IF (AltGr(0) = 163 OR AltGr(1) = 163) AND Keys(162).Down = 0 THEN Ctrl = 0 'if we use Right CTRL keys to represent part of AltGr, when AltGr is active, Right Ctrl isn't.
  101.     END IF
  102.  
  103.     IF Alt AND Shift THEN AltShift = -1 ELSE AltShift = 0
  104.     IF Alt AND Ctrl THEN AltCtrl = -1 ELSE AltCtrl = 0
  105.     IF Alt AND AltAltGR THEN AltAltGR = -1 ELSE AltAltGR = 0
  106.     IF Ctrl AND Shift THEN CtrlShift = -1 ELSE CtrlShift = 0
  107.     IF Shift AND AltGr THEN ShiftAltGr = -1 ELSE ShiftAltGr = 0
  108.     IF Ctrl AND Alt AND Shift THEN CtrlAltShift = -1 ELSE CtrlAltShift = 0
  109.  
  110.         FOR i = 1 TO 254
  111.  
  112.             r = GetKeyState(Keys(i).Index) AND &H8000
  113.  
  114.             IF r THEN 'the key is down
  115.  
  116.  
  117.                 IF Keys(i).LastHit THEN
  118.                     IF ExtendedTimer > Keys(i).LastHit THEN
  119.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  120.                         ReturnValues(ReturnCount) = Keys(i).Down 'and put the existing value back in the buffer, as a key repeat
  121.                     END IF
  122.                 ELSE
  123.  
  124.                     IF Keys(i).Down = 0 THEN 'the key was up on the last pass.
  125.                         IF CtrlAltShift <> 0 AND Keys(i).CtrlAltShift <> 0 THEN 'return the CtrlAltShift value
  126.                             Keys(i).Down = Keys(i).CtrlAltShift
  127.                         ELSEIF AltAltGR <> 0 AND Keys(i).AltAltGr <> 0 THEN 'return the AltAltGr value
  128.                             Keys(i).Down = Keys(i).AltAltGr
  129.                         ELSEIF CtrlAltGr& <> 0 AND Keys(i).CtrlAltGr& <> 0 THEN 'return the CtrlAltGr& value
  130.                             Keys(i).Down = Keys(i).CtrlAltGr&
  131.                         ELSEIF ShiftAltGr <> 0 AND Keys(i).ShiftAltGr <> 0 THEN 'return the ShiftAltGr value
  132.                             Keys(i).Down = Keys(i).ShiftAltGr
  133.                         ELSEIF CtrlShift <> 0 AND Keys(i).CtrlShift <> 0 THEN 'return the CtrlShift value
  134.                             Keys(i).Down = Keys(i).CtrlShift
  135.                         ELSEIF AltCtrl <> 0 AND Keys(i).AltCtrl <> 0 THEN 'return the AltCtrl value
  136.                             Keys(i).Down = Keys(i).AltCtrl
  137.                         ELSEIF AltShift <> 0 AND Keys(i).AltShift <> 0 THEN 'return the AltShift value
  138.                             Keys(i).Down = Keys(i).AltShift
  139.                         ELSEIF AltGr <> 0 AND Keys(i).AltGr <> 0 THEN 'return the altgr value
  140.                             Keys(i).Down = Keys(i).AltGr
  141.                         ELSEIF Shift <> 0 AND Keys(i).Shift <> 0 THEN 'return the shift value
  142.                             Keys(i).Down = Keys(i).Shift
  143.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  144.                                 SELECT CASE i
  145.                                     CASE 65 TO 90: Keys(i).Down = Keys(i).ASCII
  146.                                 END SELECT
  147.                             END IF
  148.                         ELSEIF (Ctrl <> 0) AND (Keys(i).Ctrl <> 0) THEN 'return the ctrl value
  149.                             Keys(i).Down = Keys(i).Ctrl
  150.                         ELSEIF Alt <> 0 AND Keys(i).Alt <> 0 THEN 'return the alt value
  151.                             Keys(i).Down = Keys(i).Alt
  152.                         ELSE 'all that's left is to return the ASCII value
  153.                             Keys(i).Down = Keys(i).ASCII
  154.                             IF _CAPSLOCK = 0 THEN 'caps lock basically reverses the behavior of the shift key with the letters A-Z and a-z
  155.                                 SELECT CASE i
  156.                                     CASE 65 TO 90: Keys(i).Down = Keys(i).Shift
  157.                                 END SELECT
  158.                             END IF
  159.                         END IF
  160.                         ReturnCount = ReturnCount + 1 'add one to the return buffer
  161.                         ReturnValues(ReturnCount) = Keys(i).Down 'and store the value in the buffer
  162.  
  163.                         IF Keys(i).Repeat = -1 THEN 'keys that are set to a -1 on repeat simply toggle state as on, or off.
  164.                             Keys(i).LastHit = 1E+1000 'such as SHIFT, CTRL, ALT...
  165.                         ELSE
  166.                             Keys(i).LastHit = ExtendedTimer + Keys(i).Repeat 'and record when we hit it for repeat purposes
  167.                         END IF
  168.                     END IF
  169.                 END IF
  170.             ELSE
  171.                 IF Keys(i).Down THEN 'the key was down on the last pass
  172.                     ReturnCount = ReturnCount + 1
  173.                     ReturnValues(ReturnCount) = -Keys(i).Down 'mark it as being up on this one
  174.                 END IF
  175.                 Keys(i).Down = 0 'and set it back down for future passes
  176.                 Keys(i).LastHit = 0 'once again, set it as being ready to be hit again
  177.             END IF
  178.         NEXT
  179.  
  180.         IF ReturnCount > 0 THEN 'If we generated a cue of values last pass, clear those up first, before getting new values.
  181.             'The only time we really see this is when we hit a shift, ctrl, alt key, usually.
  182.             KeyHit = ReturnValues(1)
  183.             FOR i = 1 TO ReturnCount - 1
  184.                 ReturnValues(i) = ReturnValues(i + 1)
  185.             NEXT
  186.             ReturnCount = ReturnCount - 1
  187.             EXIT FUNCTION
  188.         END IF
  189.  
  190.     END IF 'End of IF _WINDOWHASFOCUS
  191.  
  192.  
  193.  
  194.  
  195. SUB Remap_KeyCode (Which AS LONG, ASCII AS LONG, Ctrl AS LONG, Shift AS LONG, Alt AS LONG, AltGr AS LONG, Repeat AS _FLOAT)
  196.     DIM i AS LONG
  197.     i = Which
  198.     Keys(i).Index = i
  199.     Keys(i).ASCII = ASCII
  200.     Keys(i).Ctrl = Ctrl
  201.     Keys(i).Shift = Shift
  202.     Keys(i).Alt = Alt
  203.     Keys(i).AltGr = AltGr
  204.     Keys(i).Repeat = Repeat
  205.     Keys(i).LastHit = 0
  206.     Keys(i).Down = 0
  207.  
  208. SUB Remap_Extended_KeyCode (Which&, AltShift&, AltCtrl&, AltAltGr&, _
  209.          CtrlShift&, CtrlAltGr&, ShiftAltGr&, CtrlAltShift&)
  210.     Keys(Which&).AltShift = AltShift&
  211.     Keys(Which&).AltCtrl = AltCtrl&
  212.     Keys(Which&).AltAltGr = AltAltGr&
  213.     Keys(Which&).CtrlShift = CtrlShift&
  214.     Keys(Which&).CtrlAltGr = CtrlAltGr&
  215.     Keys(Which&).ShiftAltGr = ShiftAltGr&
  216.     Keys(Which&).CtrlAltShift = CtrlAltShift&
  217.  
  218. FUNCTION KeyDown& (Code AS LONG)
  219.         IF Code <= 0 THEN EXIT FUNCTION
  220.         FOR i = 1 TO 254
  221.             IF GetAsyncKeyState(i) THEN 'first check for actual physical keys down
  222.                 IF Keys(i).ASCII = Code THEN KeyDown = -1: EXIT FUNCTION 'then check to see if the code matches anything we've mapped it to.
  223.                 IF Keys(i).Shift = Code THEN KeyDown = -1: EXIT FUNCTION
  224.                 IF Keys(i).Alt = Code THEN KeyDown = -1: EXIT FUNCTION
  225.                 IF Keys(i).AltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  226.                 IF Keys(i).AltShift = Code THEN KeyDown = -1: EXIT FUNCTION
  227.                 IF Keys(i).AltCtrl = Code THEN KeyDown = -1: EXIT FUNCTION
  228.                 IF Keys(i).AltAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  229.                 IF Keys(i).CtrlShift = Code THEN KeyDown = -1: EXIT FUNCTION
  230.                 IF Keys(i).CtrlAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  231.                 IF Keys(i).ShiftAltGr = Code THEN KeyDown = -1: EXIT FUNCTION
  232.                 IF Keys(i).CtrlAltShift = Code THEN KeyDown = -1: EXIT FUNCTION
  233.             END IF
  234.         NEXT
  235.         KeyDown& = 0
  236.     END IF
  237.  
  238. FUNCTION Physical_KeyDown& (Code AS LONG)
  239.         IF Code <= 0 THEN EXIT FUNCTION
  240.         FOR i = 1 TO 254
  241.             IF GetAsyncKeyState(i) THEN 'first check for actual physical keys down
  242.                 IF Keys(i).ASCII = Code THEN Physical_KeyDown = i: EXIT FUNCTION 'then check to see if the code matches anything we've mapped it to.
  243.                 IF Keys(i).Shift = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  244.                 IF Keys(i).Alt = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  245.                 IF Keys(i).AltGr = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  246.                 IF Keys(i).AltShift = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  247.                 IF Keys(i).AltCtrl = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  248.                 IF Keys(i).AltAltGr = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  249.                 IF Keys(i).CtrlShift = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  250.                 IF Keys(i).CtrlAltGr = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  251.                 IF Keys(i).ShiftAltGr = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  252.                 IF Keys(i).CtrlAltShift = Code THEN Physical_KeyDown = i: EXIT FUNCTION
  253.             END IF
  254.         NEXT
  255.         Physical_KeyDown& = 0
  256.     END IF
  257.  
  258.  
  259. SUB Init_KeyCodes
  260.     RESTORE default_keyboard_data
  261.     FOR i = 1 TO 254
  262.         READ Keys(i).Index, Keys(i).ASCII, Keys(i).Ctrl, Keys(i).Shift, Keys(i).Alt, Keys(i).AltGr, Keys(i).Repeat
  263.         Keys(i).LastHit = 0: Keys(i).Down = 0
  264.     NEXT
  265.  
  266.     default_keyboard_data:
  267.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  268.     DATA 1,900001,0,0,0,0,0.2: 'Left Mouse Button
  269.     DATA 2,900002,0,0,0,0,0.2: 'Right Mouse Button
  270.     DATA 3,900003,0,0,0,0,0.2: 'VK_Cancel
  271.     DATA 4,900004,0,0,0,0,0.2: 'Middle Mouse Button
  272.     DATA 5,900005,0,0,0,0,0.2: 'Mouse Button 4
  273.     DATA 6,900006,0,0,0,0,0.2: 'Mouse Button 5
  274.     DATA 7,900007,0,0,0,0,0.2: 'Undefined
  275.     DATA 8,8,0,0,0,0,0.2: 'Backspace
  276.     DATA 9,9,0,0,0,0,0.2: 'Tab
  277.     DATA 10,900010,0,0,0,0,0.2: 'Reserved
  278.     DATA 11,900011,0,0,0,0,0.2: 'Reserved
  279.     DATA 12,19456,0,0,0,0,0.2: 'Clear
  280.     DATA 13,13,0,0,0,0,0.2: 'Enter
  281.     DATA 14,900014,0,0,0,0,0.2: 'Undefined
  282.     DATA 15,900015,0,0,0,0,0.2: 'Undefined
  283.     DATA 16,100016,0,0,0,0,-1: 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  284.     DATA 17,100017,0,0,0,0,-1: 'Ctrl   (Same)
  285.     DATA 18,100018,0,0,0,0,-1: 'Alt     (Same)
  286.     DATA 19,100019,0,0,0,0,0.2: 'Pause
  287.     DATA 20,100301,0,0,0,0,-1: 'Caps Lock
  288.     DATA 21,900021,0,0,0,0,0.2: 'VK_Hangul
  289.     DATA 22,900022,0,0,0,0,0.2: 'Undefined
  290.     DATA 23,900023,0,0,0,0,0.2: 'VK_Junja
  291.     DATA 24,900024,0,0,0,0,0.2: 'VK_Final
  292.     DATA 25,900025,0,0,0,0,0.2: 'VK_Hanga//VK_Kanji
  293.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  294.     DATA 26,900026,0,0,0,0,0.2: 'Undefined
  295.     DATA 27,27,0,0,0,0,0.2: 'ESC
  296.     DATA 28,900028,0,0,0,0,0.2: 'VK_Convert
  297.     DATA 29,900029,0,0,0,0,0.2: 'VK_NonConvert
  298.     DATA 30,900030,0,0,0,0,0.2: 'VK_Accept
  299.     DATA 31,900031,0,0,0,0,0.2: 'VK_ModeChange
  300.     DATA 32,32,0,0,0,0,0.2: 'VK_Space
  301.     DATA 33,18688,0,0,0,0,0.2: 'Page Up
  302.     DATA 34,20736,0,0,0,0,0.2: 'Page Down
  303.     DATA 35,20224,0,0,0,0,0.2: 'End
  304.     DATA 36,18176,0,0,0,0,0.2: 'Home
  305.     DATA 37,19200,0,0,0,0,0.2: 'Left Arrow
  306.     DATA 38,18432,0,0,0,0,0.2: 'Up Arrow
  307.     DATA 39,19712,0,0,0,0,0.2: 'Right Arrow
  308.     DATA 40,20480,0,0,0,0,0.2: 'Down Arrow
  309.     DATA 41,900041,0,0,0,0,-1: 'VK_SELECT
  310.     DATA 42,900042,0,0,0,0,-1: 'CK_PRINT
  311.     DATA 43,900043,0,0,0,0,-1: 'VK_EXECUTE
  312.     DATA 44,900044,0,0,0,0,-1: 'VK_SNAPSHOT
  313.     DATA 45,20992,0,0,0,0,0.2: 'INS
  314.     DATA 46,21248,0,0,0,0,0.2: 'DEL
  315.     DATA 47,900047,0,0,0,0,0.2: 'VK_HELP
  316.     DATA 48,48,0,41,0,0,0.2: '0
  317.     DATA 49,49,0,33,0,0,0.2: '1
  318.     DATA 50,50,0,64,0,0,0.2: '2
  319.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  320.     DATA 51,51,0,35,0,0,0.2: '3
  321.     DATA 52,52,0,36,0,0,0.2: '4
  322.     DATA 53,53,0,37,0,0,0.2: '5
  323.     DATA 54,54,0,94,0,0,0.2: '6
  324.     DATA 55,55,0,38,0,0,0.2: '7
  325.     DATA 56,56,0,42,0,0,0.2: '8
  326.     DATA 57,57,0,40,0,0,0.2: '9
  327.     DATA 58,900058,0,0,0,0,0.2: 'Undefined
  328.     DATA 59,900059,0,0,0,0,0.2: 'Undefined
  329.     DATA 60,900060,0,0,0,0,0.2: 'Undefined
  330.     DATA 61,900061,0,0,0,0,0.2: 'Undefined
  331.     DATA 62,900062,0,0,0,0,0.2: 'Undefined
  332.     DATA 63,900063,0,0,0,0,0.2: 'Undefined
  333.     DATA 64,900064,0,0,0,0,0.2: 'Undefined
  334.     DATA 65,65,0,97,0,0,0.2: 'a
  335.     DATA 66,66,0,98,0,0,0.2: 'b
  336.     DATA 67,67,0,99,0,0,0.2: 'c
  337.     DATA 68,68,0,100,0,0,0.2: 'd
  338.     DATA 69,69,0,101,0,0,0.2: 'e
  339.     DATA 70,70,0,102,0,0,0.2: 'f
  340.     DATA 71,71,0,103,0,0,0.2: 'g
  341.     DATA 72,72,0,104,0,0,0.2: 'h
  342.     DATA 73,73,0,105,0,0,0.2: 'i
  343.     DATA 74,74,0,106,0,0,0.2: 'j
  344.     DATA 75,75,0,107,0,0,0.2: 'k
  345.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  346.     DATA 76,76,0,108,0,0,0.2: 'l
  347.     DATA 77,77,0,109,0,0,0.2: 'm
  348.     DATA 78,78,0,110,0,0,0.2: 'n
  349.     DATA 79,79,0,111,0,0,0.2: 'o
  350.     DATA 80,80,0,112,0,0,0.2: 'p
  351.     DATA 81,81,0,113,0,0,0.2: 'q
  352.     DATA 82,82,0,114,0,0,0.2: 'r
  353.     DATA 83,83,0,115,0,0,0.2: 's
  354.     DATA 84,84,0,116,0,0,0.2: 't
  355.     DATA 85,85,0,117,0,0,0.2: 'u
  356.     DATA 86,86,0,118,0,0,0.2: 'v
  357.     DATA 87,87,0,119,0,0,0.2: 'w
  358.     DATA 88,88,0,120,0,0,0.2: 'x
  359.     DATA 89,89,0,121,0,0,0.2: 'y
  360.     DATA 90,90,0,122,0,0,0.2: 'z
  361.     DATA 91,100311,0,0,0,0,-1: 'Left WIN
  362.     DATA 92,100312,0,0,0,0,-1: 'Right WIN
  363.     DATA 93,100319,0,0,0,0,-1: 'Applications (Menu)
  364.     DATA 94,900094,0,0,0,0,0.2: 'Reserved
  365.     DATA 95,900095,0,0,0,0,0.2: 'VK_SLEEP
  366.     DATA 96,48,0,0,0,0,0.2: 'Numpad 0
  367.     DATA 97,49,0,0,0,0,0.2: 'Numpad 1
  368.     DATA 98,50,0,0,0,0,0.2: 'Numpad 2
  369.     DATA 99,51,0,0,0,0,0.2: 'Numpad 3
  370.     DATA 100,52,0,0,0,0,0.2: 'Numpad 4
  371.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  372.     DATA 101,53,0,0,0,0,0.2: 'Numpad 5
  373.     DATA 102,54,0,0,0,0,0.2: 'Numpad 6
  374.     DATA 103,55,0,0,0,0,0.2: 'Numpad 7
  375.     DATA 104,56,0,0,0,0,0.2: 'Numpad 8
  376.     DATA 105,57,0,0,0,0,0.2: 'Numpad 9
  377.     DATA 106,42,0,0,0,0,0.2: 'Numpad *
  378.     DATA 107,43,0,0,0,0,0.2: 'Numpad +
  379.     DATA 108,900108,0,0,0,0,0.2: 'VK_SEPARATOR
  380.     DATA 109,51,0,0,0,0,0.2: 'Numpad -
  381.     DATA 110,52,0,0,0,0,0.2: 'Numpad .
  382.     DATA 111,53,0,0,0,0,0.2: 'Numpad /
  383.     DATA 112,15104,0,0,0,0,0.2: 'F1
  384.     DATA 113,15360,0,0,0,0,0.2: 'F2
  385.     DATA 114,15616,0,0,0,0,0.2: 'F3
  386.     DATA 115,15872,0,0,0,0,0.2: 'F4
  387.     DATA 116,16128,0,0,0,0,0.2: 'F5
  388.     DATA 117,16384,0,0,0,0,0.2: 'F6
  389.     DATA 118,16640,0,0,0,0,0.2: 'F7
  390.     DATA 119,16896,0,0,0,0,0.2: 'F8
  391.     DATA 120,17152,0,0,0,0,0.2: 'F9
  392.     DATA 121,17408,0,0,0,0,0.2: 'F10
  393.     DATA 122,34048,0,0,0,0,0.2: 'F11
  394.     DATA 123,34304,0,0,0,0,0.2: 'F12
  395.     DATA 124,900124,0,0,0,0,0.2: 'F13
  396.     DATA 125,900125,0,0,0,0,0.2: 'F14
  397.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  398.     DATA 126,900126,0,0,0,0,0.2: 'F15
  399.     DATA 127,900127,0,0,0,0,0.2: 'F16
  400.     DATA 128,900128,0,0,0,0,0.2: 'F17
  401.     DATA 129,900129,0,0,0,0,0.2: 'F18
  402.     DATA 130,900130,0,0,0,0,0.2: 'F19
  403.     DATA 131,900131,0,0,0,0,0.2: 'F20
  404.     DATA 132,900132,0,0,0,0,0.2: 'F21
  405.     DATA 133,900133,0,0,0,0,0.2: 'F22
  406.     DATA 134,900134,0,0,0,0,0.2: 'F23
  407.     DATA 135,900135,0,0,0,0,0.2: 'F24
  408.     DATA 136,900136,0,0,0,0,0.2: 'Unassigned
  409.     DATA 137,900137,0,0,0,0,0.2: 'Unassigned
  410.     DATA 138,900138,0,0,0,0,0.2: 'Unassigned
  411.     DATA 139,900139,0,0,0,0,0.2: 'Unassigned
  412.     DATA 140,900140,0,0,0,0,0.2: 'Unassigned
  413.     DATA 141,900141,0,0,0,0,0.2: 'Unassigned
  414.     DATA 142,900142,0,0,0,0,0.2: 'Unassigned
  415.     DATA 143,900143,0,0,0,0,0.2: 'Unassigned
  416.     DATA 144,100300,0,0,0,0,-1: 'NUM LOCK
  417.     DATA 145,100302,0,0,0,0,-1: 'SCROLL LOCK
  418.     DATA 146,900146,0,0,0,0,0.2: 'OEM SPECIFIC
  419.     DATA 147,900147,0,0,0,0,0.2: 'OEM SPECIFIC
  420.     DATA 148,900148,0,0,0,0,0.2: 'OEM SPECIFIC
  421.     DATA 149,900149,0,0,0,0,0.2: 'OEM SPECIFIC
  422.     DATA 150,900150,0,0,0,0,0.2: 'OEM SPECIFIC
  423.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  424.     DATA 151,900151,0,0,0,0,0.2: 'Unassigned
  425.     DATA 152,900152,0,0,0,0,0.2: 'Unassigned
  426.     DATA 153,900153,0,0,0,0,0.2: 'Unassigned
  427.     DATA 154,900154,0,0,0,0,0.2: 'Unassigned
  428.     DATA 155,900155,0,0,0,0,0.2: 'Unassigned
  429.     DATA 156,900156,0,0,0,0,0.2: 'Unassigned
  430.     DATA 157,900157,0,0,0,0,0.2: 'Unassigned
  431.     DATA 158,900158,0,0,0,0,0.2: 'Unassigned
  432.     DATA 159,900159,0,0,0,0,0.2: 'Unassigned
  433.     DATA 160,100304,0,0,0,0,-1: 'Left Shift
  434.     DATA 161,100303,0,0,0,0,-1: 'Right Shift
  435.     DATA 162,100306,0,0,0,0,-1: 'Left Control
  436.     DATA 163,100305,0,0,0,0,-1: 'Right Control
  437.     DATA 164,100308,0,0,0,0,-1: 'Left Alt
  438.     DATA 165,100309,0,0,0,0,-1: 'Right Alt
  439.     DATA 166,900166,0,0,0,0,0.2: 'Browser back
  440.     DATA 167,900167,0,0,0,0,0.2: 'Browser forward
  441.     DATA 168,900168,0,0,0,0,0.2: 'Browser refresh
  442.     DATA 169,900169,0,0,0,0,0.2: 'Browser stop
  443.     DATA 170,900170,0,0,0,0,0.2: 'Browser search
  444.     DATA 171,900171,0,0,0,0,0.2: 'Browser favorites
  445.     DATA 172,900172,0,0,0,0,0.2: 'Browser home
  446.     DATA 173,900173,0,0,0,0,0.2: 'Mute
  447.     DATA 174,900174,0,0,0,0,0.2: 'Vol Down
  448.     DATA 175,900175,0,0,0,0,0.2: 'Vol Up
  449.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  450.     DATA 176,900176,0,0,0,0,0.2: 'Media Next
  451.     DATA 177,900177,0,0,0,0,0.2: 'Media prev
  452.     DATA 178,900178,0,0,0,0,0.2: 'Media stop
  453.     DATA 179,900179,0,0,0,0,0.2: 'Media Play/Pause
  454.     DATA 180,900180,0,0,0,0,0.2: 'Launch mail
  455.     DATA 181,900181,0,0,0,0,0.2: 'Launch media select
  456.     DATA 182,900182,0,0,0,0,0.2: 'Launch app1
  457.     DATA 183,900183,0,0,0,0,0.2: 'Launch app2
  458.     DATA 184,900184,0,0,0,0,0.2: 'Reserved
  459.     DATA 185,900185,0,0,0,0,0.2: 'Reserved
  460.     DATA 186,59,0,58,0,0,0.2: ';:
  461.     DATA 187,61,0,43,0,0,0.2: '=+
  462.     DATA 188,44,0,60,0,0,0.2: ',<
  463.     DATA 189,45,0,95,0,0,0.2: '-_
  464.     DATA 190,46,0,62,0,0,0.2: '.>
  465.     DATA 191,47,0,63,0,0,0.2: '/?
  466.     DATA 192,96,0,126,0,0,0.2: '`~
  467.     DATA 193,900193,0,0,0,0,0.2: 'Reserved
  468.     DATA 194,900194,0,0,0,0,0.2: 'Reserved
  469.     DATA 195,900195,0,0,0,0,0.2: 'Reserved
  470.     DATA 196,900196,0,0,0,0,0.2: 'Reserved
  471.     DATA 197,900197,0,0,0,0,0.2: 'Reserved
  472.     DATA 198,900198,0,0,0,0,0.2: 'Reserved
  473.     DATA 199,900199,0,0,0,0,0.2: 'Reserved
  474.     DATA 200,900200,0,0,0,0,0.2: 'Reserved
  475.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  476.     DATA 201,900201,0,0,0,0,0.2: 'Reserved
  477.     DATA 202,900202,0,0,0,0,0.2: 'Reserved
  478.     DATA 203,900203,0,0,0,0,0.2: 'Reserved
  479.     DATA 204,900204,0,0,0,0,0.2: 'Reserved
  480.     DATA 205,900205,0,0,0,0,0.2: 'Reserved
  481.     DATA 206,900206,0,0,0,0,0.2: 'Reserved
  482.     DATA 207,900207,0,0,0,0,0.2: 'Reserved
  483.     DATA 208,900208,0,0,0,0,0.2: 'Reserved
  484.     DATA 209,900209,0,0,0,0,0.2: 'Reserved
  485.     DATA 210,900210,0,0,0,0,0.2: 'Reserved
  486.     DATA 211,900211,0,0,0,0,0.2: 'Reserved
  487.     DATA 212,900212,0,0,0,0,0.2: 'Reserved
  488.     DATA 213,900213,0,0,0,0,0.2: 'Reserved
  489.     DATA 214,900214,0,0,0,0,0.2: 'Reserved
  490.     DATA 215,900215,0,0,0,0,0.2: 'Reserved
  491.     DATA 216,900216,0,0,0,0,0.2: 'Unassigned
  492.     DATA 217,900217,0,0,0,0,0.2: 'Unassigned
  493.     DATA 218,900218,0,0,0,0,0.2: 'Unassigned
  494.     DATA 219,91,0,123,0,0,0.2: '[{
  495.     DATA 220,92,0,124,0,0,0.2: '\|
  496.     DATA 221,93,0,125,0,0,0.2: ']}
  497.     DATA 222,39,0,34,0,0,0.2: ''"
  498.     DATA 223,900223,0,0,0,0,0.2: 'OEM SPECIFIC
  499.     DATA 224,900224,0,0,0,0,0.2: 'Reserved
  500.     DATA 225,900225,0,0,0,0,0.2: 'OEM SPECIFIC d
  501.     DATA 226,900226,0,0,0,0,0.2: 'Either the Angle Bracket key,or Backslash on RT 102-key keyboard
  502.     DATA 227,900227,0,0,0,0,0.2: 'OEM SPECIFIC
  503.     DATA 228,900228,0,0,0,0,0.2: 'OEM SPECIFIC
  504.     DATA 229,900229,0,0,0,0,0.2: 'IME PROCESS key (whatever that is)
  505.     DATA 230,900230,0,0,0,0,0.2: 'OEM SPECIFIC
  506.     DATA 231,900231,0,0,0,0,0.2: 'Used to pass UNICODE characters (however that works)
  507.     DATA 232,900232,0,0,0,0,0.2: 'Unassigned
  508.     DATA 233,900233,0,0,0,0,0.2: 'OEM SPECIFIC
  509.     DATA 234,900234,0,0,0,0,0.2: 'OEM SPECIFIC
  510.     DATA 235,900235,0,0,0,0,0.2: 'OEM SPECIFIC
  511.     DATA 236,900236,0,0,0,0,0.2: 'OEM SPECIFIC
  512.     DATA 237,900237,0,0,0,0,0.2: 'OEM SPECIFIC
  513.     DATA 238,900238,0,0,0,0,0.2: 'OEM SPECIFIC
  514.     DATA 239,900239,0,0,0,0,0.2: 'OEM SPECIFIC
  515.     DATA 240,900240,0,0,0,0,0.2: 'OEM SPECIFIC
  516.     DATA 241,900241,0,0,0,0,0.2: 'OEM SPECIFIC
  517.     DATA 242,900242,0,0,0,0,0.2: 'OEM SPECIFIC
  518.     DATA 243,900243,0,0,0,0,0.2: 'OEM SPECIFIC
  519.     DATA 244,900244,0,0,0,0,0.2: 'OEM SPECIFIC
  520.     DATA 245,900245,0,0,0,0,0.2: 'OEM SPECIFIC
  521.     DATA 246,900246,0,0,0,0,0.2: 'VK_ATTN
  522.     DATA 247,900247,0,0,0,0,0.2: 'VK_ATTN
  523.     DATA 248,900248,0,0,0,0,0.2: 'VK_ATTN
  524.     DATA 249,900249,0,0,0,0,0.2: 'VK_ATTN
  525.     DATA 250,900250,0,0,0,0,0.2: 'VK_ATTN
  526.     DATA 251,900251,0,0,0,0,0.2: 'VK_ATTN
  527.     DATA 252,900252,0,0,0,0,0.2: 'Reserved
  528.     DATA 253,900253,0,0,0,0,0.2: 'VK_PA1
  529.     DATA 254,900253,0,0,0,0,0.2: 'VK_OEM_CLEAR
  530.     DATA 0,0,0,0,0,0,0.2: 'END OF DATA
  531.     AltGr(0) = 165
  532.     AltGr(1) = 0
  533.  
  534.  
  535. FUNCTION ExtendedTimer##
  536.     'modified extendedtimer to store the old day's count, and not have to recalculate it every time the routine is called.
  537.  
  538.     STATIC olds AS _FLOAT, old_day AS _FLOAT
  539.     DIM m AS INTEGER, d AS INTEGER, y AS INTEGER
  540.     DIM s AS _FLOAT, day AS STRING
  541.     IF olds = 0 THEN 'calculate the day the first time the extended timer runs
  542.         day = DATE$
  543.         m = VAL(LEFT$(day, 2))
  544.         d = VAL(MID$(day, 4, 2))
  545.         y = VAL(RIGHT$(day, 4)) - 1970
  546.         SELECT CASE m 'Add the number of days for each previous month passed
  547.             CASE 2: d = d + 31
  548.             CASE 3: d = d + 59
  549.             CASE 4: d = d + 90
  550.             CASE 5: d = d + 120
  551.             CASE 6: d = d + 151
  552.             CASE 7: d = d + 181
  553.             CASE 8: d = d + 212
  554.             CASE 9: d = d + 243
  555.             CASE 10: d = d + 273
  556.             CASE 11: d = d + 304
  557.             CASE 12: d = d + 334
  558.         END SELECT
  559.         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
  560.         d = (d - 1) + 365 * y 'current month days passed + 365 days per each standard year
  561.         d = d + (y + 2) \ 4 'add in days for leap years passed
  562.         s = d * 24 * 60 * 60 'Seconds are days * 24 hours * 60 minutes * 60 seconds
  563.         old_day = s
  564.     END IF
  565.     IF TIMER < oldt THEN 'we went from 23:59:59 (a second before midnight) to 0:0:0 (midnight)
  566.         old_day = s + 83400 'add another worth of seconds to our counter
  567.     END IF
  568.     oldt = TIMER
  569.     olds = old_day + oldt
  570.     ExtendedTimer## = olds
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577. FUNCTION ExtendedInput$
  578.     SHARED AltGr, Alt, Shift, Ctrl
  579.     PCOPY 0, 1
  580.     A = _AUTODISPLAY: X = POS(0): Y = CSRLIN
  581.     CP = 0: OldCP = 0 'Cursor Position
  582.     _KEYCLEAR
  583.     DO
  584.         PCOPY 1, 0
  585.  
  586.         k = KeyHit
  587.         IF Alt THEN AltDown = -1 ELSE AltDown = 0
  588.         SELECT CASE k 'without alt, add any keypresses to our input
  589.             CASE 8
  590.                 oldin$ = in$
  591.                 IF CP > 0 THEN OldCP = CP: CP = CP - 1
  592.                 in$ = LEFT$(in$, CP) + MID$(in$, CP + 2) 'backspace to erase input
  593.             CASE 9
  594.                 oldin$ = in$
  595.                 in$ = LEFT$(in$, CP) + SPACE$(4) + MID$(in$, CP + 1) 'four spaces for any TAB entered
  596.                 OldCP = CP
  597.                 CP = CP + 4
  598.             CASE 48 TO 57 '0 to 9
  599.                 IF AltDown THEN
  600.                     AltWasDown = -1: alt$ = alt$ + CHR$(k)
  601.                 ELSE
  602.                     oldin$ = in$
  603.                     in$ = LEFT$(in$, CP) + CHR$(k) + MID$(in$, CP + 1) 'add input to our string
  604.                     OldCP = CP
  605.                     CP = CP + 1
  606.                 END IF
  607.             CASE 1 TO 255 'the rest of the ASCII characters
  608.                 IF Ctrl AND (k = 118 OR k = 86) THEN
  609.                     oldin$ = in$
  610.                     in$ = LEFT$(in$, CP) + _CLIPBOARD$ + MID$(in$, CP + 1) 'ctrl-v paste
  611.                     'CTRL-V leaves cursor in position before the paste, without moving it after.
  612.                     'Feel free to modify that behavior here, if you want it to move to after the paste.
  613.                 ELSEIF Ctrl AND (k = 122 OR k = 90) THEN
  614.                     SWAP in$, oldin$: SWAP OldCP, CP 'ctrl-z undo
  615.                 ELSE
  616.                     oldin$ = in$
  617.                     in$ = LEFT$(in$, CP) + CHR$(k) + MID$(in$, CP + 1) 'add input to our string
  618.                     OldCP = CP
  619.                     CP = CP + 1
  620.                 END IF
  621.             CASE 18176 'Home
  622.                 CP = 0
  623.             CASE 20224 'End
  624.                 CP = LEN(in$)
  625.             CASE 21248 'Delete
  626.                 oldin$ = in$
  627.                 in$ = LEFT$(in$, CP) + MID$(in$, CP + 2)
  628.             CASE 19200 'Left
  629.                 CP = CP - 1
  630.                 IF CP < 0 THEN CP = 0
  631.             CASE 19712 'Right
  632.                 CP = CP + 1
  633.                 IF CP > LEN(in$) THEN CP = LEN(in$)
  634.         END SELECT
  635.  
  636.         alt$ = RIGHT$(alt$, 3)
  637.         IF AltWasDown = -1 AND AltDown = 0 THEN
  638.             v = VAL(alt$)
  639.             IF v >= 0 AND v <= 255 THEN in$ = in$ + CHR$(v): CP = CP + 1
  640.             alt$ = "": AltWasDown = 0
  641.         END IF
  642.         blink = (blink + 1) MOD 30
  643.         LOCATE Y, X
  644.         PRINT LEFT$(in$, CP);
  645.         IF blink \ 15 THEN PRINT " "; ELSE PRINT "_";
  646.         PRINT MID$(in$, CP + 1)
  647.  
  648.         _DISPLAY
  649.         _LIMIT 30
  650.     LOOP UNTIL k = 13
  651.  
  652.     PCOPY 1, 0
  653.     LOCATE Y, X: PRINT in$
  654.     ExtendedInput$ = in$
  655.  

Step 0: (This may be optional, depending on how you manage things.)

After the DIM SHARED AltGr(1) AS _UNSIGNED _BYTE, and before the Init_KeyCodes, you may want to use the _MAPUNICODE values to set up the proper code page to view and display your characters properly.  (If you need help with this step, let me know, but I figure anyone who uses _MAPUNICODE regularly shouldn't have any issues with using it to set the proper character page.)

Step 1: Run the program and test it out with your keyboard.  Whenever you find a key/combination which doesn't work properly, write down the physical keycode on a piece of paper, along with the symbol which that key should actually represent.  (Make a note of modifier keys, if needed, such as SHIFT or ALTGR, as well.)

Step 2: Once you have a list of keys which you want to remap, copy the whole SUB Init_KeyCodes, and paste a duplicate of it into the IDE.  Rename that duplicate to Init_IT_KeyCodes (for the Italian Keycodes; use a different abbreviation for a different language).

Step 3: Just scroll down the list and change the values that you need to, for the keys which you made a list of above.

For example, let's say Physical Key 186 is the less than "<" sign on your keyboard, rather than the semicolon ";".  The old line in question looks like this:
Code: [Select]
    DATA 186,59,0,58,0,0,0.2: ';:   
Those values represent:     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat

Semi-colon is ASCII character 59.  Colon is ASCII character 58.  As you can see, those represent the Unmodified keydown and the Shift-keydown code for that physical key.

Just look at your ASCII chart for your particular code page, and plug in the values that match the character your keyboard should've actually produced.

In this example, less than "<" is normally CHR$(60), so all you'd do is change that line to become:

    DATA 186,60,0,58,0,0,0.2: ';: 

That 59 became a 60.  Now, when you hit that  key, it'll display "<" instead of ";".

Step 4: Repeat with the rest of the physical keys which didn't match anything currently mapped.



And that's all there is to it! 

It's nothing very complicated, but it does require a human to sit down, stare at their personal keyboard, and then look up the proper ASCII values for their character page and plug them into the mapper at least once. 

Once somebody maps their values for us, I'll add them to the program and we'll collect a library that people can just pick and choose from, without having to remap everything personally, every time they want to use the routine.  All we need is someone to map things once to their physical keyboard layout, and then that mapping can be used by other people with that same language/keyboard forever more!!



And here's to hoping that several different people will remap their keyboards, and share them, for us.  :)
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic on January 05, 2020, 08:22:44 pm
Hi Steve
just another silly question:
Is the default_keyboard_data  the MS CP1252 ?
Title: Re: Programmable Keyboard Input
Post by: SMcNeill on January 05, 2020, 10:05:57 pm
Hi Steve
just another silly question:
Is the default_keyboard_data  the MS CP1252 ?

QB64 uses the default character page 437, unless you change yours using MAPUNICODE to map a different page to use/display.  https://www.qb64.org/wiki/Code_Pages#CP_437
Title: Re: Programmable Keyboard Input
Post by: TempodiBasic on January 16, 2020, 04:19:56 pm
I'm glad to post this add to Steve's work!

CP_850 for IT keyboard
and
CP_1252 for Western Europe countries (it works also for IT keyboard)

Code: QB64: [Select]
  1. SUB Init_KeyCodes (Language AS STRING)
  2.     RESTORE default_keyboard_data
  3.     FOR i = 1 TO 254
  4.         READ Keys(i).Index, Keys(i).ASCII, Keys(i).Ctrl, Keys(i).Shift, Keys(i).Alt, Keys(i).AltGr, Keys(i).Repeat
  5.         Keys(i).LastHit = 0: Keys(i).Down = 0
  6.     NEXT
  7.  
  8.     default_keyboard_data:
  9.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  10.     DATA 1,900001,0,0,0,0,0.2: 'Left Mouse Button
  11.     DATA 2,900002,0,0,0,0,0.2: 'Right Mouse Button
  12.     DATA 3,900003,0,0,0,0,0.2: 'VK_Cancel
  13.     DATA 4,900004,0,0,0,0,0.2: 'Middle Mouse Button
  14.     DATA 5,900005,0,0,0,0,0.2: 'Mouse Button 4
  15.     DATA 6,900006,0,0,0,0,0.2: 'Mouse Button 5
  16.     DATA 7,900007,0,0,0,0,0.2: 'Undefined
  17.     DATA 8,8,0,0,0,0,0.2: 'Backspace
  18.     DATA 9,9,0,0,0,0,0.2: 'Tab
  19.     DATA 10,900010,0,0,0,0,0.2: 'Reserved
  20.     DATA 11,900011,0,0,0,0,0.2: 'Reserved
  21.     DATA 12,19456,0,0,0,0,0.2: 'Clear
  22.     DATA 13,13,0,0,0,0,0.2: 'Enter
  23.     DATA 14,900014,0,0,0,0,0.2: 'Undefined
  24.     DATA 15,900015,0,0,0,0,0.2: 'Undefined
  25.     DATA 16,100016,0,0,0,0,-1: 'Shift (Notice I set it to simple toddle and report UP/DOWN results for us)
  26.     DATA 17,100017,0,0,0,0,-1: 'Ctrl   (Same)
  27.     DATA 18,100018,0,0,0,0,-1: 'Alt     (Same)
  28.     DATA 19,100019,0,0,0,0,0.2: 'Pause
  29.     DATA 20,100301,0,0,0,0,-1: 'Caps Lock
  30.     DATA 21,900021,0,0,0,0,0.2: 'VK_Hangul
  31.     DATA 22,900022,0,0,0,0,0.2: 'Undefined
  32.     DATA 23,900023,0,0,0,0,0.2: 'VK_Junja
  33.     DATA 24,900024,0,0,0,0,0.2: 'VK_Final
  34.     DATA 25,900025,0,0,0,0,0.2: 'VK_Hanga//VK_Kanji
  35.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  36.     DATA 26,900026,0,0,0,0,0.2: 'Undefined
  37.     DATA 27,27,0,0,0,0,0.2: 'ESC
  38.     DATA 28,900028,0,0,0,0,0.2: 'VK_Convert
  39.     DATA 29,900029,0,0,0,0,0.2: 'VK_NonConvert
  40.     DATA 30,900030,0,0,0,0,0.2: 'VK_Accept
  41.     DATA 31,900031,0,0,0,0,0.2: 'VK_ModeChange
  42.     DATA 32,32,0,0,0,0,0.2: 'VK_Space
  43.     DATA 33,18688,0,0,0,0,0.2: 'Page Up
  44.     DATA 34,20736,0,0,0,0,0.2: 'Page Down
  45.     DATA 35,20224,0,0,0,0,0.2: 'End
  46.     DATA 36,18176,0,0,0,0,0.2: 'Home
  47.     DATA 37,19200,0,0,0,0,0.2: 'Left Arrow
  48.     DATA 38,18432,0,0,0,0,0.2: 'Up Arrow
  49.     DATA 39,19712,0,0,0,0,0.2: 'Right Arrow
  50.     DATA 40,20480,0,0,0,0,0.2: 'Down Arrow
  51.     DATA 41,900041,0,0,0,0,-1: 'VK_SELECT
  52.     DATA 42,900042,0,0,0,0,-1: 'CK_PRINT
  53.     DATA 43,900043,0,0,0,0,-1: 'VK_EXECUTE
  54.     DATA 44,900044,0,0,0,0,-1: 'VK_SNAPSHOT
  55.     DATA 45,20992,0,0,0,0,0.2: 'INS
  56.     DATA 46,21248,0,0,0,0,0.2: 'DEL
  57.     DATA 47,900047,0,0,0,0,0.2: 'VK_HELP
  58.     DATA 48,48,0,41,0,0,0.2: '0
  59.     DATA 49,49,0,33,0,0,0.2: '1
  60.     DATA 50,50,0,64,0,0,0.2: '2
  61.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  62.     DATA 51,51,0,35,0,0,0.2: '3
  63.     DATA 52,52,0,36,0,0,0.2: '4
  64.     DATA 53,53,0,37,0,0,0.2: '5
  65.     DATA 54,54,0,94,0,0,0.2: '6
  66.     DATA 55,55,0,38,0,0,0.2: '7
  67.     DATA 56,56,0,42,0,0,0.2: '8
  68.     DATA 57,57,0,40,0,0,0.2: '9
  69.     DATA 58,900058,0,0,0,0,0.2: 'Undefined
  70.     DATA 59,900059,0,0,0,0,0.2: 'Undefined
  71.     DATA 60,900060,0,0,0,0,0.2: 'Undefined
  72.     DATA 61,900061,0,0,0,0,0.2: 'Undefined
  73.     DATA 62,900062,0,0,0,0,0.2: 'Undefined
  74.     DATA 63,900063,0,0,0,0,0.2: 'Undefined
  75.     DATA 64,900064,0,0,0,0,0.2: 'Undefined
  76.     DATA 65,65,0,97,0,0,0.2: 'a
  77.     DATA 66,66,0,98,0,0,0.2: 'b
  78.     DATA 67,67,0,99,0,0,0.2: 'c
  79.     DATA 68,68,0,100,0,0,0.2: 'd
  80.     DATA 69,69,0,101,0,0,0.2: 'e
  81.     DATA 70,70,0,102,0,0,0.2: 'f
  82.     DATA 71,71,0,103,0,0,0.2: 'g
  83.     DATA 72,72,0,104,0,0,0.2: 'h
  84.     DATA 73,73,0,105,0,0,0.2: 'i
  85.     DATA 74,74,0,106,0,0,0.2: 'j
  86.     DATA 75,75,0,107,0,0,0.2: 'k
  87.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  88.     DATA 76,76,0,108,0,0,0.2: 'l
  89.     DATA 77,77,0,109,0,0,0.2: 'm
  90.     DATA 78,78,0,110,0,0,0.2: 'n
  91.     DATA 79,79,0,111,0,0,0.2: 'o
  92.     DATA 80,80,0,112,0,0,0.2: 'p
  93.     DATA 81,81,0,113,0,0,0.2: 'q
  94.     DATA 82,82,0,114,0,0,0.2: 'r
  95.     DATA 83,83,0,115,0,0,0.2: 's
  96.     DATA 84,84,0,116,0,0,0.2: 't
  97.     DATA 85,85,0,117,0,0,0.2: 'u
  98.     DATA 86,86,0,118,0,0,0.2: 'v
  99.     DATA 87,87,0,119,0,0,0.2: 'w
  100.     DATA 88,88,0,120,0,0,0.2: 'x
  101.     DATA 89,89,0,121,0,0,0.2: 'y
  102.     DATA 90,90,0,122,0,0,0.2: 'z
  103.     DATA 91,100311,0,0,0,0,-1: 'Left WIN
  104.     DATA 92,100312,0,0,0,0,-1: 'Right WIN
  105.     DATA 93,100319,0,0,0,0,-1: 'Applications (Menu)
  106.     DATA 94,900094,0,0,0,0,0.2: 'Reserved
  107.     DATA 95,900095,0,0,0,0,0.2: 'VK_SLEEP
  108.     DATA 96,48,0,0,0,0,0.2: 'Numpad 0
  109.     DATA 97,49,0,0,0,0,0.2: 'Numpad 1
  110.     DATA 98,50,0,0,0,0,0.2: 'Numpad 2
  111.     DATA 99,51,0,0,0,0,0.2: 'Numpad 3
  112.     DATA 100,52,0,0,0,0,0.2: 'Numpad 4
  113.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  114.     DATA 101,53,0,0,0,0,0.2: 'Numpad 5
  115.     DATA 102,54,0,0,0,0,0.2: 'Numpad 6
  116.     DATA 103,55,0,0,0,0,0.2: 'Numpad 7
  117.     DATA 104,56,0,0,0,0,0.2: 'Numpad 8
  118.     DATA 105,57,0,0,0,0,0.2: 'Numpad 9
  119.     DATA 106,42,0,0,0,0,0.2: 'Numpad *
  120.     DATA 107,43,0,0,0,0,0.2: 'Numpad +
  121.     DATA 108,900108,0,0,0,0,0.2: 'VK_SEPARATOR
  122.     DATA 109,51,0,0,0,0,0.2: 'Numpad -
  123.     DATA 110,52,0,0,0,0,0.2: 'Numpad .
  124.     DATA 111,53,0,0,0,0,0.2: 'Numpad /
  125.     DATA 112,15104,0,0,0,0,0.2: 'F1
  126.     DATA 113,15360,0,0,0,0,0.2: 'F2
  127.     DATA 114,15616,0,0,0,0,0.2: 'F3
  128.     DATA 115,15872,0,0,0,0,0.2: 'F4
  129.     DATA 116,16128,0,0,0,0,0.2: 'F5            /
  130.     DATA 117,16384,0,0,0,0,0.2: 'F6
  131.     DATA 118,16640,0,0,0,0,0.2: 'F7
  132.     DATA 119,16896,0,0,0,0,0.2: 'F8
  133.     DATA 120,17152,0,0,0,0,0.2: 'F9
  134.     DATA 121,17408,0,0,0,0,0.2: 'F10
  135.     DATA 122,34048,0,0,0,0,0.2: 'F11
  136.     DATA 123,34304,0,0,0,0,0.2: 'F12
  137.     DATA 124,900124,0,0,0,0,0.2: 'F13
  138.     DATA 125,900125,0,0,0,0,0.2: 'F14
  139.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  140.     DATA 126,900126,0,0,0,0,0.2: 'F15
  141.     DATA 127,900127,0,0,0,0,0.2: 'F16
  142.     DATA 128,900128,0,0,0,0,0.2: 'F17
  143.     DATA 129,900129,0,0,0,0,0.2: 'F18
  144.     DATA 130,900130,0,0,0,0,0.2: 'F19
  145.     DATA 131,900131,0,0,0,0,0.2: 'F20
  146.     DATA 132,900132,0,0,0,0,0.2: 'F21
  147.     DATA 133,900133,0,0,0,0,0.2: 'F22
  148.     DATA 134,900134,0,0,0,0,0.2: 'F23
  149.     DATA 135,900135,0,0,0,0,0.2: 'F24
  150.     DATA 136,900136,0,0,0,0,0.2: 'Unassigned
  151.     DATA 137,900137,0,0,0,0,0.2: 'Unassigned
  152.     DATA 138,900138,0,0,0,0,0.2: 'Unassigned
  153.     DATA 139,900139,0,0,0,0,0.2: 'Unassigned
  154.     DATA 140,900140,0,0,0,0,0.2: 'Unassigned
  155.     DATA 141,900141,0,0,0,0,0.2: 'Unassigned
  156.     DATA 142,900142,0,0,0,0,0.2: 'Unassigned
  157.     DATA 143,900143,0,0,0,0,0.2: 'Unassigned
  158.     DATA 144,100300,0,0,0,0,-1: 'NUM LOCK
  159.     DATA 145,100302,0,0,0,0,-1: 'SCROLL LOCK
  160.     DATA 146,900146,0,0,0,0,0.2: 'OEM SPECIFIC
  161.     DATA 147,900147,0,0,0,0,0.2: 'OEM SPECIFIC
  162.     DATA 148,900148,0,0,0,0,0.2: 'OEM SPECIFIC
  163.     DATA 149,900149,0,0,0,0,0.2: 'OEM SPECIFIC
  164.     DATA 150,900150,0,0,0,0,0.2: 'OEM SPECIFIC
  165.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  166.     DATA 151,900151,0,0,0,0,0.2: 'Unassigned
  167.     DATA 152,900152,0,0,0,0,0.2: 'Unassigned
  168.     DATA 153,900153,0,0,0,0,0.2: 'Unassigned
  169.     DATA 154,900154,0,0,0,0,0.2: 'Unassigned
  170.     DATA 155,900155,0,0,0,0,0.2: 'Unassigned
  171.     DATA 156,900156,0,0,0,0,0.2: 'Unassigned
  172.     DATA 157,900157,0,0,0,0,0.2: 'Unassigned
  173.     DATA 158,900158,0,0,0,0,0.2: 'Unassigned
  174.     DATA 159,900159,0,0,0,0,0.2: 'Unassigned
  175.     DATA 160,100304,0,0,0,0,-1: 'Left Shift
  176.     DATA 161,100303,0,0,0,0,-1: 'Right Shift
  177.     DATA 162,100306,0,0,0,0,-1: 'Left Control
  178.     DATA 163,100305,0,0,0,0,-1: 'Right Control
  179.     DATA 164,100308,0,0,0,0,-1: 'Left Alt
  180.     DATA 165,100309,0,0,0,0,-1: 'Right Alt
  181.     DATA 166,900166,0,0,0,0,0.2: 'Browser back
  182.     DATA 167,900167,0,0,0,0,0.2: 'Browser forward
  183.     DATA 168,900168,0,0,0,0,0.2: 'Browser refresh
  184.     DATA 169,900169,0,0,0,0,0.2: 'Browser stop
  185.     DATA 170,900170,0,0,0,0,0.2: 'Browser search
  186.     DATA 171,900171,0,0,0,0,0.2: 'Browser favorites
  187.     DATA 172,900172,0,0,0,0,0.2: 'Browser home
  188.     DATA 173,900173,0,0,0,0,0.2: 'Mute
  189.     DATA 174,900174,0,0,0,0,0.2: 'Vol Down
  190.     DATA 175,900175,0,0,0,0,0.2: 'Vol Up
  191.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  192.     DATA 176,900176,0,0,0,0,0.2: 'Media Next
  193.     DATA 177,900177,0,0,0,0,0.2: 'Media prev
  194.     DATA 178,900178,0,0,0,0,0.2: 'Media stop
  195.     DATA 179,900179,0,0,0,0,0.2: 'Media Play/Pause
  196.     DATA 180,900180,0,0,0,0,0.2: 'Launch mail
  197.     DATA 181,900181,0,0,0,0,0.2: 'Launch media select
  198.     DATA 182,900182,0,0,0,0,0.2: 'Launch app1
  199.     DATA 183,900183,0,0,0,0,0.2: 'Launch app2
  200.     DATA 184,900184,0,0,0,0,0.2: 'Reserved
  201.     DATA 185,900185,0,0,0,0,0.2: 'Reserved
  202.     DATA 186,59,0,58,0,0,0.2: ';:
  203.     DATA 187,61,0,43,0,0,0.2: '=+
  204.     DATA 188,44,0,60,0,0,0.2: ',<
  205.     DATA 189,45,0,95,0,0,0.2: '-_
  206.     DATA 190,46,0,62,0,0,0.2: '.>
  207.     DATA 191,47,0,63,0,0,0.2: '/?
  208.     DATA 192,96,0,126,0,0,0.2: '`~
  209.     DATA 193,900193,0,0,0,0,0.2: 'Reserved
  210.     DATA 194,900194,0,0,0,0,0.2: 'Reserved
  211.     DATA 195,900195,0,0,0,0,0.2: 'Reserved
  212.     DATA 196,900196,0,0,0,0,0.2: 'Reserved
  213.     DATA 197,900197,0,0,0,0,0.2: 'Reserved
  214.     DATA 198,900198,0,0,0,0,0.2: 'Reserved
  215.     DATA 199,900199,0,0,0,0,0.2: 'Reserved
  216.     DATA 200,900200,0,0,0,0,0.2: 'Reserved
  217.     '   Index   Unmodified      Ctrl      Shift       Alt         AltGr     Repeat
  218.     DATA 201,900201,0,0,0,0,0.2: 'Reserved
  219.     DATA 202,900202,0,0,0,0,0.2: 'Reserved
  220.     DATA 203,900203,0,0,0,0,0.2: 'Reserved
  221.     DATA 204,900204,0,0,0,0,0.2: 'Reserved
  222.     DATA 205,900205,0,0,0,0,0.2: 'Reserved
  223.     DATA 206,900206,0,0,0,0,0.2: 'Reserved
  224.     DATA 207,900207,0,0,0,0,0.2: 'Reserved
  225.     DATA 208,900208,0,0,0,0,0.2: 'Reserved
  226.     DATA 209,900209,0,0,0,0,0.2: 'Reserved
  227.     DATA 210,900210,0,0,0,0,0.2: 'Reserved
  228.     DATA 211,900211,0,0,0,0,0.2: 'Reserved
  229.     DATA 212,900212,0,0,0,0,0.2: 'Reserved
  230.     DATA 213,900213,0,0,0,0,0.2: 'Reserved
  231.     DATA 214,900214,0,0,0,0,0.2: 'Reserved
  232.     DATA 215,900215,0,0,0,0,0.2: 'Reserved
  233.     DATA 216,900216,0,0,0,0,0.2: 'Unassigned
  234.     DATA 217,900217,0,0,0,0,0.2: 'Unassigned
  235.     DATA 218,900218,0,0,0,0,0.2: 'Unassigned
  236.     DATA 219,91,0,123,0,0,0.2: '[{
  237.     DATA 220,92,0,124,0,0,0.2: '\|
  238.     DATA 221,93,0,125,0,0,0.2: ']}
  239.     DATA 222,39,0,34,0,0,0.2: ''"
  240.     DATA 223,900223,0,0,0,0,0.2: 'OEM SPECIFIC
  241.     DATA 224,900224,0,0,0,0,0.2: 'Reserved
  242.     DATA 225,900225,0,0,0,0,0.2: 'OEM SPECIFIC d
  243.     DATA 226,900226,0,0,0,0,0.2: 'Either the Angle Bracket key,or Backslash on RT 102-key keyboard
  244.     DATA 227,900227,0,0,0,0,0.2: 'OEM SPECIFIC
  245.     DATA 228,900228,0,0,0,0,0.2: 'OEM SPECIFIC
  246.     DATA 229,900229,0,0,0,0,0.2: 'IME PROCESS key (whatever that is)
  247.     DATA 230,900230,0,0,0,0,0.2: 'OEM SPECIFIC
  248.     DATA 231,900231,0,0,0,0,0.2: 'Used to pass UNICODE characters (however that works)
  249.     DATA 232,900232,0,0,0,0,0.2: 'Unassigned
  250.     DATA 233,900233,0,0,0,0,0.2: 'OEM SPECIFIC
  251.     DATA 234,900234,0,0,0,0,0.2: 'OEM SPECIFIC
  252.     DATA 235,900235,0,0,0,0,0.2: 'OEM SPECIFIC
  253.     DATA 236,900236,0,0,0,0,0.2: 'OEM SPECIFIC
  254.     DATA 237,900237,0,0,0,0,0.2: 'OEM SPECIFIC
  255.     DATA 238,900238,0,0,0,0,0.2: 'OEM SPECIFIC
  256.     DATA 239,900239,0,0,0,0,0.2: 'OEM SPECIFIC
  257.     DATA 240,900240,0,0,0,0,0.2: 'OEM SPECIFIC
  258.     DATA 241,900241,0,0,0,0,0.2: 'OEM SPECIFIC
  259.     DATA 242,900242,0,0,0,0,0.2: 'OEM SPECIFIC
  260.     DATA 243,900243,0,0,0,0,0.2: 'OEM SPECIFIC
  261.     DATA 244,900244,0,0,0,0,0.2: 'OEM SPECIFIC
  262.     DATA 245,900245,0,0,0,0,0.2: 'OEM SPECIFIC
  263.     DATA 246,900246,0,0,0,0,0.2: 'VK_ATTN
  264.     DATA 247,900247,0,0,0,0,0.2: 'VK_ATTN
  265.     DATA 248,900248,0,0,0,0,0.2: 'VK_ATTN
  266.     DATA 249,900249,0,0,0,0,0.2: 'VK_ATTN
  267.     DATA 250,900250,0,0,0,0,0.2: 'VK_ATTN
  268.     DATA 251,900251,0,0,0,0,0.2: 'VK_ATTN
  269.     DATA 252,900252,0,0,0,0,0.2: 'Reserved
  270.     DATA 253,900253,0,0,0,0,0.2: 'VK_PA1
  271.     DATA 254,900253,0,0,0,0,0.2: 'VK_OEM_CLEAR
  272.     DATA 0,0,0,0,0,0,0.2: 'END OF DATA
  273.     AltGr(0) = 165
  274.     AltGr(1) = 0
  275.  
  276.     SELECT CASE Language
  277.         CASE "DE"
  278.             RESTORE Microsoft_windows_cp1250
  279.             FOR i = 128 TO 255
  280.                 READ unicode
  281.                 _MAPUNICODE unicode TO ASCIIcode
  282.             NEXT
  283.             Microsoft_windows_cp1250:
  284.             DATA 8364,0,8218,0,8222,8230,8224,8225,0,8240,352,8249,346,356,381,377
  285.             DATA 0,8216,8217,8220,8221,8226,8211,8212,0,8482,353,8250,347,357,382,378
  286.             DATA 160,711,728,321,164,260,166,167,168,169,350,171,172,173,174,379
  287.             DATA 176,177,731,322,180,181,182,183,184,261,351,187,317,733,318,380
  288.             DATA 340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270
  289.             DATA 272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223
  290.             DATA 341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271
  291.             DATA 273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729
  292.             'Remap_KeyCode (Which, ASCII, Ctrl , Shift, Alt, AltGr, Repeat AS _FLOAT)
  293.             Remap_KeyCode 226, 60, 0, 62, 124, 92, 0.2 '<>|
  294.             Remap_KeyCode 219, 225, 0, 63, 0, 0, 0.2 '-
  295.             Remap_KeyCode 48, 48, 0, 61, 0, 125, 0.2 '0
  296.             Remap_KeyCode 192, 148, 0, 153, 0, 0, 0.2
  297.             Remap_KeyCode 222, 132, 0, 142, 0, 0, 0.2
  298.             Remap_KeyCode 50, 50, 0, 34, 0, 253, 0.2: '2 .. I don't see a superscript 3 for AltGr codes for the 3 key.
  299.             Remap_KeyCode 51, 51, 0, 35, 0, 0, 0.2: '3 ..I don't see the squiggle for this in the ASCII code.  It needs to be changed, but I dunno with what.
  300.             Remap_KeyCode 54, 54, 0, 38, 0, 0, 0.2: '6
  301.             Remap_KeyCode 55, 55, 0, 47, 0, 123, 0.2: '7
  302.             Remap_KeyCode 56, 56, 0, 40, 0, 91, 0.2: '8
  303.             Remap_KeyCode 57, 57, 0, 41, 0, 93, 0.2: '9
  304.             Remap_KeyCode 186, 129, 0, 154, 0, 0, 0.2: ';:
  305.             Remap_KeyCode 187, 43, 0, 42, 0, 126, 0.2: '=+
  306.             Remap_KeyCode 191, 35, 0, 249, 0, 0, 0.2: '/?
  307.             Remap_KeyCode 81, 81, 0, 113, 0, 64, 0.2: 'q
  308.             Remap_KeyCode 69, 69, 0, 101, 0, 238, 0.2: 'e
  309.             Remap_KeyCode 77, 77, 0, 109, 0, 0, 0.2: 'm -- again, I failed to find the goofy u which AltGr produces in the 256 ASCII set
  310.  
  311.         CASE "WE"
  312.             RESTORE Microsoft_windows_cp1252
  313.             FOR i = 128 TO 255
  314.                 READ unicode
  315.                 _MAPUNICODE unicode TO ASCIIcode
  316.             NEXT
  317.  
  318.             Microsoft_windows_cp1252:
  319.             DATA 8364,0,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,0,381,0
  320.             DATA 0,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,0,382,376
  321.             DATA 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175
  322.             DATA 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191
  323.             DATA 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207
  324.             DATA 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223
  325.             DATA 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239
  326.             DATA 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255
  327.  
  328.  
  329.             'remap_KeyCode (Which, ASCII, Ctrl , Shift, Alt, AltGr, Repeat AS _FLOAT)
  330.             Remap_KeyCode 188, 44, 0, 59, 0, 0, 0.2: ',;
  331.             Remap_KeyCode 190, 46, 0, 58, 0, 0, 0.2: '.:
  332.             Remap_KeyCode 50, 50, 0, 34, 0, 0, 0.2: '2 "
  333.             Remap_KeyCode 51, 51, 0, 156, 0, 0, 0.2: '3 œ
  334.             Remap_KeyCode 191, 151, 0, 21, 0, 0, 0.2: '£ 
  335.             Remap_KeyCode 222, 133, 0, 248, 0, 35, 0.2: '… ø#
  336.             Remap_KeyCode 192, 149, 0, 128, 0, 64, 0.2: '• € @
  337.             Remap_KeyCode 186, 138, 0, 130, 0, 91, 0.2 'Š ‚ [
  338.             Remap_KeyCode 187, 43, 0, 42, 0, 93, 0.2 ' + * ]
  339.             Remap_KeyCode 54, 54, 0, 38, 0, 0, 0.2 '6 &
  340.             Remap_KeyCode 55, 55, 0, 47, 0, 0, 0.2 '7 /
  341.             Remap_KeyCode 56, 56, 0, 40, 0, 0, 0.2 '8(
  342.             Remap_KeyCode 57, 57, 0, 41, 0, 0, 0.2 '9 )
  343.             Remap_KeyCode 48, 48, 0, 61, 0, 0, 0.2 '0 =
  344.             Remap_KeyCode 219, 39, 0, 63, 0, 0, 0.2 ' ' ?
  345.             Remap_KeyCode 221, 141, 0, 94, 0, 0, 0.2 ' ^
  346.             Remap_KeyCode 226, 60, 0, 62, 0, 0, 0.2 '< >
  347.  
  348.         CASE "IT"
  349.  
  350.             RESTORE ASCII_cp850
  351.             FOR i = 128 TO 255
  352.                 READ unicode
  353.                 _MAPUNICODE unicode TO ASCIIcode
  354.             NEXT
  355.  
  356.             ASCII_cp850:
  357.             DATA 199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197
  358.             DATA 201,230,198,244,246,242,251,249,255,214,220,248,163,216,215,402
  359.             DATA 225,237,243,250,241,209,170,186,191,174,172,189,188,161,171,187
  360.             DATA 9617,9618,9619,9474,9508,193,194,192,169,9571,9553,9559,9565,162,165,9488
  361.             DATA 9492,9524,9516,9500,9472,9532,227,195,9562,9556,9577,9574,9568,9552,9580,164
  362.             DATA 240,208,202,203,200,305,205,206,207,9496,9484,9608,9604,166,204,9600
  363.             DATA 211,223,212,210,245,213,181,254,222,218,219,217,253,221,175,180
  364.             DATA 173,177,8215,190,182,167,247,184,176,168,183,185,179,178,9632,160
  365.  
  366.             'remap_KeyCode (Which, ASCII, Ctrl , Shift, Alt, AltGr, Repeat AS _FLOAT)
  367.             Remap_KeyCode 188, 44, 0, 59, 0, 0, 0.2: ',;
  368.             Remap_KeyCode 190, 46, 0, 58, 0, 0, 0.2: '.:
  369.             Remap_KeyCode 50, 50, 0, 34, 0, 0, 0.2: '2 "
  370.             Remap_KeyCode 51, 51, 0, 156, 0, 0, 0.2: '3 œ
  371.             Remap_KeyCode 191, 151, 0, 21, 0, 0, 0.2: '£ 
  372.             Remap_KeyCode 222, 133, 0, 248, 0, 35, 0.2: '… ø#
  373.             Remap_KeyCode 192, 149, 0, 128, 0, 64, 0.2: '• € @
  374.             Remap_KeyCode 186, 138, 0, 130, 0, 91, 0.2 'Š ‚ [
  375.             Remap_KeyCode 187, 43, 0, 42, 0, 93, 0.2 ' + * ]
  376.             Remap_KeyCode 54, 54, 0, 38, 0, 0, 0.2 '6 &
  377.             Remap_KeyCode 55, 55, 0, 47, 0, 0, 0.2 '7 /
  378.             Remap_KeyCode 56, 56, 0, 40, 0, 0, 0.2 '8(
  379.             Remap_KeyCode 57, 57, 0, 41, 0, 0, 0.2 '9 )
  380.             Remap_KeyCode 48, 48, 0, 61, 0, 0, 0.2 '0 =
  381.             Remap_KeyCode 219, 39, 0, 63, 0, 0, 0.2 ' ' ?
  382.             Remap_KeyCode 221, 141, 0, 94, 0, 0, 0.2 ' ^
  383.             Remap_KeyCode 226, 60, 0, 62, 0, 0, 0.2 '< >
  384.     END SELECT
  385.  

Please substitutes this SUB in the original posted by Steve and try if your keyboard layout works fine.
On my notebook using  original keyboard and USB keyboard  it is ok!
Title: Re: Programmable Keyboard Input
Post by: moises1953 on June 06, 2020, 02:42:28 am
The GetKeystate function extract messages from the queue, but may be that processing the message queue is a better solution, including the traslating. See here:

https://docs.microsoft.com/en-us/windows/win32/inputdev/using-keyboard-input

Quote
MSG msg;
BOOL bRet;

while (( bRet = GetMessage(&msg, (HWND) NULL, 0, 0)) != 0)
{
    if (bRet == -1);
    {
        // handle the error and possibly exit
    }
    else
    {
        if (TranslateAccelerator(hwndMain, haccl, &msg) == 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}