PageRenderTime 31ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llwindow/llkeyboardwin32.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 405 lines | 272 code | 47 blank | 86 comment | 49 complexity | fc663d60a73e7f85dcd9c85cdbc7080a MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llkeyboardwin32.cpp
  3. * @brief Handler for assignable key bindings
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #if LL_WINDOWS
  27. #include "linden_common.h"
  28. #define WIN32_LEAN_AND_MEAN
  29. #include <winsock2.h>
  30. #include <windows.h>
  31. #include "llkeyboardwin32.h"
  32. #include "llwindowcallbacks.h"
  33. LLKeyboardWin32::LLKeyboardWin32()
  34. {
  35. // Set up key mapping for windows - eventually can read this from a file?
  36. // Anything not in the key map gets dropped
  37. // Add default A-Z
  38. // Virtual key mappings from WinUser.h
  39. KEY cur_char;
  40. for (cur_char = 'A'; cur_char <= 'Z'; cur_char++)
  41. {
  42. mTranslateKeyMap[cur_char] = (KEY)cur_char;
  43. }
  44. for (cur_char = '0'; cur_char <= '9'; cur_char++)
  45. {
  46. mTranslateKeyMap[cur_char] = (KEY)cur_char;
  47. }
  48. // numpad number keys
  49. for (cur_char = 0x60; cur_char <= 0x69; cur_char++)
  50. {
  51. mTranslateKeyMap[cur_char] = (KEY)('0' + (cur_char - 0x60));
  52. }
  53. mTranslateKeyMap[VK_SPACE] = ' ';
  54. mTranslateKeyMap[VK_OEM_1] = ';';
  55. // When the user hits, for example, Ctrl-= as a keyboard shortcut,
  56. // Windows generates VK_OEM_PLUS. This is true on both QWERTY and DVORAK
  57. // keyboards in the US. Numeric keypad '+' generates VK_ADD below.
  58. // Thus we translate it as '='.
  59. // Potential bug: This may not be true on international keyboards. JC
  60. mTranslateKeyMap[VK_OEM_PLUS] = '=';
  61. mTranslateKeyMap[VK_OEM_COMMA] = ',';
  62. mTranslateKeyMap[VK_OEM_MINUS] = '-';
  63. mTranslateKeyMap[VK_OEM_PERIOD] = '.';
  64. mTranslateKeyMap[VK_OEM_2] = '/';//This used to be KEY_PAD_DIVIDE, but that breaks typing into text fields in media prims
  65. mTranslateKeyMap[VK_OEM_3] = '`';
  66. mTranslateKeyMap[VK_OEM_4] = '[';
  67. mTranslateKeyMap[VK_OEM_5] = '\\';
  68. mTranslateKeyMap[VK_OEM_6] = ']';
  69. mTranslateKeyMap[VK_OEM_7] = '\'';
  70. mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE;
  71. mTranslateKeyMap[VK_RETURN] = KEY_RETURN;
  72. mTranslateKeyMap[VK_LEFT] = KEY_LEFT;
  73. mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT;
  74. mTranslateKeyMap[VK_UP] = KEY_UP;
  75. mTranslateKeyMap[VK_DOWN] = KEY_DOWN;
  76. mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE;
  77. mTranslateKeyMap[VK_INSERT] = KEY_INSERT;
  78. mTranslateKeyMap[VK_DELETE] = KEY_DELETE;
  79. mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT;
  80. mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL;
  81. mTranslateKeyMap[VK_MENU] = KEY_ALT;
  82. mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK;
  83. mTranslateKeyMap[VK_HOME] = KEY_HOME;
  84. mTranslateKeyMap[VK_END] = KEY_END;
  85. mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP;
  86. mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN;
  87. mTranslateKeyMap[VK_TAB] = KEY_TAB;
  88. mTranslateKeyMap[VK_ADD] = KEY_ADD;
  89. mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT;
  90. mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY;
  91. mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE;
  92. mTranslateKeyMap[VK_F1] = KEY_F1;
  93. mTranslateKeyMap[VK_F2] = KEY_F2;
  94. mTranslateKeyMap[VK_F3] = KEY_F3;
  95. mTranslateKeyMap[VK_F4] = KEY_F4;
  96. mTranslateKeyMap[VK_F5] = KEY_F5;
  97. mTranslateKeyMap[VK_F6] = KEY_F6;
  98. mTranslateKeyMap[VK_F7] = KEY_F7;
  99. mTranslateKeyMap[VK_F8] = KEY_F8;
  100. mTranslateKeyMap[VK_F9] = KEY_F9;
  101. mTranslateKeyMap[VK_F10] = KEY_F10;
  102. mTranslateKeyMap[VK_F11] = KEY_F11;
  103. mTranslateKeyMap[VK_F12] = KEY_F12;
  104. mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER;
  105. // Build inverse map
  106. std::map<U16, KEY>::iterator iter;
  107. for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++)
  108. {
  109. mInvTranslateKeyMap[iter->second] = iter->first;
  110. }
  111. // numpad map
  112. mTranslateNumpadMap[0x60] = KEY_PAD_INS; // keypad 0
  113. mTranslateNumpadMap[0x61] = KEY_PAD_END; // keypad 1
  114. mTranslateNumpadMap[0x62] = KEY_PAD_DOWN; // keypad 2
  115. mTranslateNumpadMap[0x63] = KEY_PAD_PGDN; // keypad 3
  116. mTranslateNumpadMap[0x64] = KEY_PAD_LEFT; // keypad 4
  117. mTranslateNumpadMap[0x65] = KEY_PAD_CENTER; // keypad 5
  118. mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT; // keypad 6
  119. mTranslateNumpadMap[0x67] = KEY_PAD_HOME; // keypad 7
  120. mTranslateNumpadMap[0x68] = KEY_PAD_UP; // keypad 8
  121. mTranslateNumpadMap[0x69] = KEY_PAD_PGUP; // keypad 9
  122. mTranslateNumpadMap[0x6A] = KEY_PAD_MULTIPLY; // keypad *
  123. mTranslateNumpadMap[0x6B] = KEY_PAD_ADD; // keypad +
  124. mTranslateNumpadMap[0x6D] = KEY_PAD_SUBTRACT; // keypad -
  125. mTranslateNumpadMap[0x6E] = KEY_PAD_DEL; // keypad .
  126. mTranslateNumpadMap[0x6F] = KEY_PAD_DIVIDE; // keypad /
  127. for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++)
  128. {
  129. mInvTranslateNumpadMap[iter->second] = iter->first;
  130. }
  131. }
  132. // Asynchronously poll the control, alt and shift keys and set the
  133. // appropriate states.
  134. // Note: this does not generate edges.
  135. void LLKeyboardWin32::resetMaskKeys()
  136. {
  137. // GetAsyncKeyState returns a short and uses the most significant
  138. // bit to indicate that the key is down.
  139. if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
  140. {
  141. mKeyLevel[KEY_SHIFT] = TRUE;
  142. }
  143. if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
  144. {
  145. mKeyLevel[KEY_CONTROL] = TRUE;
  146. }
  147. if (GetAsyncKeyState(VK_MENU) & 0x8000)
  148. {
  149. mKeyLevel[KEY_ALT] = TRUE;
  150. }
  151. }
  152. //void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state )
  153. //{
  154. // if( mKeyLevel[key] != new_state )
  155. // {
  156. // mKeyLevelFrameCount[key] = 0;
  157. //
  158. // if( new_state )
  159. // {
  160. // mKeyLevelTimer[key].reset();
  161. // }
  162. // mKeyLevel[key] = new_state;
  163. // }
  164. //}
  165. MASK LLKeyboardWin32::updateModifiers()
  166. {
  167. //RN: this seems redundant, as we should have already received the appropriate
  168. // messages for the modifier keys
  169. // Scan the modifier keys as of the last Windows key message
  170. // (keydown encoded in high order bit of short)
  171. mKeyLevel[KEY_CAPSLOCK] = (GetKeyState(VK_CAPITAL) & 0x0001) != 0; // Low order bit carries the toggle state.
  172. // Get mask for keyboard events
  173. MASK mask = currentMask(FALSE);
  174. return mask;
  175. }
  176. // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags
  177. BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask)
  178. {
  179. KEY translated_key;
  180. U32 translated_mask;
  181. BOOL handled = FALSE;
  182. translated_mask = updateModifiers();
  183. if (translateExtendedKey(key, mask, &translated_key))
  184. {
  185. handled = handleTranslatedKeyDown(translated_key, translated_mask);
  186. }
  187. return handled;
  188. }
  189. // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags
  190. BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask)
  191. {
  192. KEY translated_key;
  193. U32 translated_mask;
  194. BOOL handled = FALSE;
  195. translated_mask = updateModifiers();
  196. if (translateExtendedKey(key, mask, &translated_key))
  197. {
  198. handled = handleTranslatedKeyUp(translated_key, translated_mask);
  199. }
  200. return handled;
  201. }
  202. MASK LLKeyboardWin32::currentMask(BOOL)
  203. {
  204. MASK mask = MASK_NONE;
  205. if (mKeyLevel[KEY_SHIFT]) mask |= MASK_SHIFT;
  206. if (mKeyLevel[KEY_CONTROL]) mask |= MASK_CONTROL;
  207. if (mKeyLevel[KEY_ALT]) mask |= MASK_ALT;
  208. return mask;
  209. }
  210. void LLKeyboardWin32::scanKeyboard()
  211. {
  212. S32 key;
  213. MSG msg;
  214. BOOL pending_key_events = PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
  215. for (key = 0; key < KEY_COUNT; key++)
  216. {
  217. // On Windows, verify key down state. JC
  218. // RN: only do this if we don't have further key events in the queue
  219. // as otherwise there might be key repeat events still waiting for this key we are now dumping
  220. if (!pending_key_events && mKeyLevel[key])
  221. {
  222. // *TODO: I KNOW there must be a better way of
  223. // interrogating the key state than this, using async key
  224. // state can cause ALL kinds of bugs - Doug
  225. if (key < KEY_BUTTON0)
  226. {
  227. // ...under windows make sure the key actually still is down.
  228. // ...translate back to windows key
  229. U16 virtual_key = inverseTranslateExtendedKey(key);
  230. // keydown in highest bit
  231. if (!pending_key_events && !(GetAsyncKeyState(virtual_key) & 0x8000))
  232. {
  233. //llinfos << "Key up event missed, resetting" << llendl;
  234. mKeyLevel[key] = FALSE;
  235. }
  236. }
  237. }
  238. // Generate callback if any event has occurred on this key this frame.
  239. // Can't just test mKeyLevel, because this could be a slow frame and
  240. // key might have gone down then up. JC
  241. if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key])
  242. {
  243. mCurScanKey = key;
  244. mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]);
  245. }
  246. }
  247. // Reset edges for next frame
  248. for (key = 0; key < KEY_COUNT; key++)
  249. {
  250. mKeyUp[key] = FALSE;
  251. mKeyDown[key] = FALSE;
  252. if (mKeyLevel[key])
  253. {
  254. mKeyLevelFrameCount[key]++;
  255. }
  256. }
  257. }
  258. BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key)
  259. {
  260. if(mNumpadDistinct == ND_NUMLOCK_ON)
  261. {
  262. std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key);
  263. if (iter != mTranslateNumpadMap.end())
  264. {
  265. *translated_key = iter->second;
  266. return TRUE;
  267. }
  268. }
  269. BOOL success = translateKey(os_key, translated_key);
  270. if(mNumpadDistinct != ND_NEVER) {
  271. if(!success) return success;
  272. if(mask & MASK_EXTENDED)
  273. {
  274. // this is where we'd create new keycodes for extended keys
  275. // the set of extended keys includes the 'normal' arrow keys and
  276. // the pgup/dn/insert/home/end/delete cluster above the arrow keys
  277. // see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx
  278. // only process the return key if numlock is off
  279. if(((mNumpadDistinct == ND_NUMLOCK_OFF &&
  280. !(GetKeyState(VK_NUMLOCK) & 1))
  281. || mNumpadDistinct == ND_NUMLOCK_ON) &&
  282. *translated_key == KEY_RETURN) {
  283. *translated_key = KEY_PAD_RETURN;
  284. }
  285. }
  286. else
  287. {
  288. // the non-extended keys, those are in the numpad
  289. switch (*translated_key)
  290. {
  291. case KEY_LEFT:
  292. *translated_key = KEY_PAD_LEFT; break;
  293. case KEY_RIGHT:
  294. *translated_key = KEY_PAD_RIGHT; break;
  295. case KEY_UP:
  296. *translated_key = KEY_PAD_UP; break;
  297. case KEY_DOWN:
  298. *translated_key = KEY_PAD_DOWN; break;
  299. case KEY_HOME:
  300. *translated_key = KEY_PAD_HOME; break;
  301. case KEY_END:
  302. *translated_key = KEY_PAD_END; break;
  303. case KEY_PAGE_UP:
  304. *translated_key = KEY_PAD_PGUP; break;
  305. case KEY_PAGE_DOWN:
  306. *translated_key = KEY_PAD_PGDN; break;
  307. case KEY_INSERT:
  308. *translated_key = KEY_PAD_INS; break;
  309. case KEY_DELETE:
  310. *translated_key = KEY_PAD_DEL; break;
  311. }
  312. }
  313. }
  314. return success;
  315. }
  316. U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key)
  317. {
  318. // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number
  319. if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1))
  320. {
  321. std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key);
  322. if (iter != mInvTranslateNumpadMap.end())
  323. {
  324. return iter->second;
  325. }
  326. }
  327. // if numlock is off or we're not converting numbers to arrows, we map our keypad arrows
  328. // to regular arrows since Windows doesn't distinguish between them
  329. KEY converted_key = translated_key;
  330. switch (converted_key)
  331. {
  332. case KEY_PAD_LEFT:
  333. converted_key = KEY_LEFT; break;
  334. case KEY_PAD_RIGHT:
  335. converted_key = KEY_RIGHT; break;
  336. case KEY_PAD_UP:
  337. converted_key = KEY_UP; break;
  338. case KEY_PAD_DOWN:
  339. converted_key = KEY_DOWN; break;
  340. case KEY_PAD_HOME:
  341. converted_key = KEY_HOME; break;
  342. case KEY_PAD_END:
  343. converted_key = KEY_END; break;
  344. case KEY_PAD_PGUP:
  345. converted_key = KEY_PAGE_UP; break;
  346. case KEY_PAD_PGDN:
  347. converted_key = KEY_PAGE_DOWN; break;
  348. case KEY_PAD_INS:
  349. converted_key = KEY_INSERT; break;
  350. case KEY_PAD_DEL:
  351. converted_key = KEY_DELETE; break;
  352. case KEY_PAD_RETURN:
  353. converted_key = KEY_RETURN; break;
  354. }
  355. // convert our virtual keys to OS keys
  356. return inverseTranslateKey(converted_key);
  357. }
  358. #endif