Stage.Keyboard.pas 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. //
  2. // The graphics engine GLXEngine
  3. //
  4. unit Stage.Keyboard;
  5. (*
  6. Provides on demand state of any key on the keyboard as well as a set of
  7. utility functions for working with virtual key codes.
  8. Note that windows maps the mouse buttons to virtual key codes too, and you
  9. can use the functions/classes in this unit to check mouse buttons too.
  10. See "Virtual-Key Codes" in the Win32 programmers references for a list of
  11. key code constants (VK_* constants are declared in the "Windows" unit).
  12. *)
  13. interface
  14. {$I Stage.Defines.inc}
  15. uses
  16. Winapi.Windows,
  17. System.SysUtils;
  18. type
  19. TVirtualKeyCode = Integer;
  20. const
  21. // pseudo wheel keys (we squat F23/F24), see KeyboardNotifyWheelMoved
  22. VK_MOUSEWHEELUP = VK_F23;
  23. VK_MOUSEWHEELDOWN = VK_F24;
  24. (* Check if the key corresponding to the given Char is down.
  25. The character is mapped to the <i>main keyboard</i> only, and not to the
  26. numeric keypad.
  27. The Shift/Ctrl/Alt state combinations that may be required to type the
  28. character are ignored (ie. 'a' is equivalent to 'A', and on my french
  29. keyboard, '5' = '(' = '[' since they all share the same physical key). *)
  30. function IsKeyDown(c: Char): Boolean; overload;
  31. (* Check if the given virtual key is down.
  32. This function is just a wrapper for GetAsyncKeyState. *)
  33. function IsKeyDown(vk: TVirtualKeyCode): Boolean; overload;
  34. (* Returns the first pressed key whose virtual key code is >= to minVkCode.
  35. If no key is pressed, the return value is -1, this function does NOT
  36. wait for user input.
  37. If you don't care about multiple key presses, just don't use the parameter. *)
  38. function KeyPressed(minVkCode: TVirtualKeyCode = 0): TVirtualKeyCode;
  39. (* Converts a virtual key code to its name.
  40. The name is expressed using the locale windows options. *)
  41. function VirtualKeyCodeToKeyName(vk: TVirtualKeyCode): String;
  42. (* Converts a key name to its virtual key code.
  43. The comparison is **NOT** case-sensitive, if no match is found, returns -1.
  44. The name is expressed using the locale windows options, except for mouse
  45. buttons which are translated to 'LBUTTON', 'MBUTTON' and 'RBUTTON'. *)
  46. function KeyNameToVirtualKeyCode(const keyName: String): TVirtualKeyCode;
  47. (* Returns the virtual keycode corresponding to the given char.
  48. The returned code is untranslated, f.i. 'a' and 'A' will give the same
  49. result. A return value of -1 means that the characted cannot be entered
  50. using the keyboard. *)
  51. function CharToVirtualKeyCode(c: Char): TVirtualKeyCode;
  52. (* Use this procedure to notify a wheel movement and have it resurfaced as key stroke.
  53. Honoured by IsKeyDown and KeyPressed *)
  54. procedure KeyboardNotifyWheelMoved(wheelDelta: Integer);
  55. var
  56. vLastWheelDelta: Integer;
  57. implementation // ------------------------------------------------------------
  58. const
  59. cLBUTTON = 'Left Mouse Button';
  60. cMBUTTON = 'Middle Mouse Button';
  61. cRBUTTON = 'Right Mouse Button';
  62. cUP = 'Up';
  63. cDOWN = 'Down';
  64. cRIGHT = 'Right';
  65. cLEFT = 'Left';
  66. cPAGEUP = 'Page up';
  67. cPAGEDOWN = 'Page down';
  68. cHOME = 'Home';
  69. cEND = 'End';
  70. cMOUSEWHEELUP = 'Mouse Wheel Up';
  71. cMOUSEWHEELDOWN = 'Mouse Wheel Down';
  72. cPAUSE = 'Pause';
  73. cSNAPSHOT = 'Print Screen';
  74. cNUMLOCK = 'Num Lock';
  75. cINSERT = 'Insert';
  76. cDELETE = 'Delete';
  77. cDIVIDE = 'Num /';
  78. cLWIN = 'Left Win';
  79. cRWIN = 'Right Win';
  80. cAPPS = 'Application Key';
  81. c0 = '~';
  82. c1 = '[';
  83. c2 = ']';
  84. c3 = ';';
  85. c4 = '''';
  86. c5 = '<';
  87. c6 = '>';
  88. c7 = '/';
  89. c8 = '\';
  90. function IsKeyDown(c: Char): Boolean;
  91. var
  92. vk: Integer;
  93. begin
  94. // '$FF' filters out translators like Shift, Ctrl, Alt
  95. vk := VkKeyScan(c) and $FF;
  96. if vk <> $FF then
  97. Result := (GetAsyncKeyState(vk) < 0)
  98. else
  99. Result := False;
  100. end;
  101. function IsKeyDown(vk: TVirtualKeyCode): Boolean;
  102. begin
  103. case vk of
  104. VK_MOUSEWHEELUP:
  105. begin
  106. Result := vLastWheelDelta > 0;
  107. if Result then
  108. vLastWheelDelta := 0;
  109. end;
  110. VK_MOUSEWHEELDOWN:
  111. begin
  112. Result := vLastWheelDelta < 0;
  113. if Result then
  114. vLastWheelDelta := 0;
  115. end;
  116. else
  117. Result := (GetAsyncKeyState(vk) < 0);
  118. end;
  119. end;
  120. function KeyPressed(minVkCode: TVirtualKeyCode = 0): TVirtualKeyCode;
  121. var
  122. i: Integer;
  123. buf: TKeyboardState;
  124. begin
  125. Assert(minVkCode >= 0);
  126. Result := -1;
  127. if GetKeyboardState(buf) then
  128. begin
  129. for i := minVkCode to High(buf) do
  130. begin
  131. if (buf[i] and $80) <> 0 then
  132. begin
  133. Result := i;
  134. Exit;
  135. end;
  136. end;
  137. end;
  138. if vLastWheelDelta <> 0 then
  139. begin
  140. if vLastWheelDelta > 0 then
  141. Result := VK_MOUSEWHEELUP
  142. else
  143. Result := VK_MOUSEWHEELDOWN;
  144. vLastWheelDelta := 0;
  145. end;
  146. end;
  147. function VirtualKeyCodeToKeyName(vk: TVirtualKeyCode): String;
  148. var
  149. nSize: Integer;
  150. begin
  151. // Win32 API can't translate mouse button virtual keys to string
  152. case vk of
  153. VK_LBUTTON:
  154. Result := cLBUTTON;
  155. VK_MBUTTON:
  156. Result := cMBUTTON;
  157. VK_RBUTTON:
  158. Result := cRBUTTON;
  159. VK_UP:
  160. Result := cUP;
  161. VK_DOWN:
  162. Result := cDOWN;
  163. VK_LEFT:
  164. Result := cLEFT;
  165. VK_RIGHT:
  166. Result := cRIGHT;
  167. VK_PRIOR:
  168. Result := cPAGEUP;
  169. VK_NEXT:
  170. Result := cPAGEDOWN;
  171. VK_HOME:
  172. Result := cHOME;
  173. VK_END:
  174. Result := cEND;
  175. VK_MOUSEWHEELUP:
  176. Result := cMOUSEWHEELUP;
  177. VK_MOUSEWHEELDOWN:
  178. Result := cMOUSEWHEELDOWN;
  179. VK_PAUSE: Result := cPAUSE;
  180. VK_SNAPSHOT: Result := cSNAPSHOT;
  181. VK_NUMLOCK: Result := cNUMLOCK;
  182. VK_INSERT: Result := cINSERT;
  183. VK_DELETE: Result := cDELETE;
  184. VK_DIVIDE: Result := cDIVIDE;
  185. VK_LWIN: Result := cLWIN;
  186. VK_RWIN: Result := cRWIN;
  187. VK_APPS: Result := cAPPS;
  188. 192: Result := c0;
  189. 219: Result := c1;
  190. 221: Result := c2;
  191. 186: Result := c3;
  192. 222: Result := c4;
  193. 188: Result := c5;
  194. 190: Result := c6;
  195. 191: Result := c7;
  196. 220: Result := c8;
  197. else
  198. nSize := 32; // should be enough
  199. SetLength(Result, nSize);
  200. vk := MapVirtualKey(vk, 0);
  201. nSize := GetKeyNameText((vk and $FF) shl 16, PChar(Result), nSize);
  202. SetLength(Result, nSize);
  203. end;
  204. end;
  205. function KeyNameToVirtualKeyCode(const keyName: String): TVirtualKeyCode;
  206. var
  207. i: Integer;
  208. begin
  209. // ok, I admit this is plain ugly. 8)
  210. Result := -1;
  211. for i := 0 to 255 do
  212. begin
  213. if SameText(VirtualKeyCodeToKeyName(i), keyName) then
  214. begin
  215. Result := i;
  216. Break;
  217. end;
  218. end;
  219. end;
  220. function CharToVirtualKeyCode(c: Char): TVirtualKeyCode;
  221. begin
  222. Result := VkKeyScan(c) and $FF;
  223. if Result = $FF then
  224. Result := -1;
  225. end;
  226. procedure KeyboardNotifyWheelMoved(wheelDelta: Integer);
  227. begin
  228. vLastWheelDelta := wheelDelta;
  229. end;
  230. //----------------------------------------------------------------------------
  231. end.