llkeyboard.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /**
  2. * @file llkeyboard.cpp
  3. * @brief Handler for assignable key bindings
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include "indra_constants.h"
  34. #include "llkeyboard.h"
  35. #include "llstl.h"
  36. #include "llwindow.h"
  37. //
  38. // Globals
  39. //
  40. LLKeyboard* gKeyboardp = NULL;
  41. //static
  42. std::map<KEY,std::string> LLKeyboard::sKeysToNames;
  43. std::map<std::string,KEY> LLKeyboard::sNamesToKeys;
  44. //
  45. // Class Implementation
  46. //
  47. LLKeyboard::LLKeyboard()
  48. : mCallbacks(NULL),
  49. mNumpadDistinct(ND_NUMLOCK_OFF)
  50. {
  51. // Constructor for LLTimer inits each timer. We want them to be constructed
  52. // without being initialized, so we shut them down here.
  53. for (S32 i = 0; i < KEY_COUNT; ++i)
  54. {
  55. mKeyLevelFrameCount[i] = 0;
  56. mKeyLevel[i] = false;
  57. mKeyUp[i] = false;
  58. mKeyDown[i] = false;
  59. mKeyRepeated[i] = false;
  60. }
  61. mInsertMode = LL_KIM_INSERT;
  62. mCurTranslatedKey = KEY_NONE;
  63. mCurScanKey = KEY_NONE;
  64. addKeyName(' ', "Space" );
  65. addKeyName(KEY_RETURN, "Enter" );
  66. addKeyName(KEY_LEFT, "Left" );
  67. addKeyName(KEY_RIGHT, "Right" );
  68. addKeyName(KEY_UP, "Up" );
  69. addKeyName(KEY_DOWN, "Down" );
  70. addKeyName(KEY_ESCAPE, "Esc" );
  71. addKeyName(KEY_HOME, "Home" );
  72. addKeyName(KEY_END, "End" );
  73. addKeyName(KEY_PAGE_UP, "PgUp" );
  74. addKeyName(KEY_PAGE_DOWN, "PgDn" );
  75. addKeyName(KEY_F1, "F1" );
  76. addKeyName(KEY_F2, "F2" );
  77. addKeyName(KEY_F3, "F3" );
  78. addKeyName(KEY_F4, "F4" );
  79. addKeyName(KEY_F5, "F5" );
  80. addKeyName(KEY_F6, "F6" );
  81. addKeyName(KEY_F7, "F7" );
  82. addKeyName(KEY_F8, "F8" );
  83. addKeyName(KEY_F9, "F9" );
  84. addKeyName(KEY_F10, "F10" );
  85. addKeyName(KEY_F11, "F11" );
  86. addKeyName(KEY_F12, "F12" );
  87. addKeyName(KEY_TAB, "Tab" );
  88. addKeyName(KEY_ADD, "Add" );
  89. addKeyName(KEY_SUBTRACT, "Subtract" );
  90. addKeyName(KEY_MULTIPLY, "Multiply" );
  91. addKeyName(KEY_DIVIDE, "Divide" );
  92. addKeyName(KEY_PAD_DIVIDE, "PAD_DIVIDE" );
  93. addKeyName(KEY_PAD_LEFT, "PAD_LEFT" );
  94. addKeyName(KEY_PAD_RIGHT, "PAD_RIGHT" );
  95. addKeyName(KEY_PAD_DOWN, "PAD_DOWN" );
  96. addKeyName(KEY_PAD_UP, "PAD_UP" );
  97. addKeyName(KEY_PAD_HOME, "PAD_HOME" );
  98. addKeyName(KEY_PAD_END, "PAD_END" );
  99. addKeyName(KEY_PAD_PGUP, "PAD_PGUP" );
  100. addKeyName(KEY_PAD_PGDN, "PAD_PGDN" );
  101. addKeyName(KEY_PAD_CENTER, "PAD_CENTER" );
  102. addKeyName(KEY_PAD_INS, "PAD_INS" );
  103. addKeyName(KEY_PAD_DEL, "PAD_DEL" );
  104. addKeyName(KEY_PAD_RETURN, "PAD_Enter" );
  105. addKeyName(KEY_BUTTON0, "PAD_BUTTON0" );
  106. addKeyName(KEY_BUTTON1, "PAD_BUTTON1" );
  107. addKeyName(KEY_BUTTON2, "PAD_BUTTON2" );
  108. addKeyName(KEY_BUTTON3, "PAD_BUTTON3" );
  109. addKeyName(KEY_BUTTON4, "PAD_BUTTON4" );
  110. addKeyName(KEY_BUTTON5, "PAD_BUTTON5" );
  111. addKeyName(KEY_BUTTON6, "PAD_BUTTON6" );
  112. addKeyName(KEY_BUTTON7, "PAD_BUTTON7" );
  113. addKeyName(KEY_BUTTON8, "PAD_BUTTON8" );
  114. addKeyName(KEY_BUTTON9, "PAD_BUTTON9" );
  115. addKeyName(KEY_BUTTON10, "PAD_BUTTON10" );
  116. addKeyName(KEY_BUTTON11, "PAD_BUTTON11" );
  117. addKeyName(KEY_BUTTON12, "PAD_BUTTON12" );
  118. addKeyName(KEY_BUTTON13, "PAD_BUTTON13" );
  119. addKeyName(KEY_BUTTON14, "PAD_BUTTON14" );
  120. addKeyName(KEY_BUTTON15, "PAD_BUTTON15" );
  121. addKeyName(KEY_BACKSPACE, "Backsp" );
  122. addKeyName(KEY_DELETE, "Del" );
  123. addKeyName(KEY_SHIFT, "Shift" );
  124. addKeyName(KEY_CONTROL, "Ctrl" );
  125. addKeyName(KEY_ALT, "Alt" );
  126. addKeyName(KEY_HYPHEN, "-" );
  127. addKeyName(KEY_EQUALS, "=" );
  128. addKeyName(KEY_INSERT, "Ins" );
  129. addKeyName(KEY_CAPSLOCK, "CapsLock" );
  130. }
  131. void LLKeyboard::addKeyName(KEY key, const std::string& name)
  132. {
  133. sKeysToNames[key] = name;
  134. std::string nameuc = name;
  135. LLStringUtil::toUpper(nameuc);
  136. sNamesToKeys[nameuc] = key;
  137. }
  138. // BUG this has to be called when an OS dialog is shown, otherwise modifier key
  139. // state is wrong because the keyup event is never received by the main window.
  140. void LLKeyboard::resetKeys()
  141. {
  142. for (S32 i = 0; i < KEY_COUNT; ++i)
  143. {
  144. if (mKeyLevel[i])
  145. {
  146. mKeyLevel[i] = false;
  147. }
  148. }
  149. for (S32 i = 0; i < KEY_COUNT; ++i)
  150. {
  151. mKeyUp[i] = false;
  152. }
  153. for (S32 i = 0; i < KEY_COUNT; ++i)
  154. {
  155. mKeyDown[i] = false;
  156. }
  157. for (S32 i = 0; i < KEY_COUNT; ++i)
  158. {
  159. mKeyRepeated[i] = false;
  160. }
  161. }
  162. bool LLKeyboard::translateKey(U32 os_key, KEY* out_key, MASK mask)
  163. {
  164. #if LL_LINUX || LL_WINDOWS
  165. // *HACK: translate AZERTY PC keyboards '²' key into its QWERTY equivalent
  166. // '`' key for accelerators/shortcuts (e.g. quick snapshot with CTRL `).
  167. # if LL_LINUX
  168. if (os_key == 0xb2 && (mask & (MASK_CONTROL | MASK_ALT)))
  169. # else // LL_WINDOWS
  170. if (os_key == 0xde && (mask & (MASK_CONTROL | MASK_ALT)))
  171. # endif
  172. {
  173. LL_DEBUGS("KeyCodes") << "Key code: " << std::hex << os_key
  174. << " - Mask: " << mask << std::dec
  175. << " - Translated key: 0x60" << LL_ENDL;
  176. *out_key = 0x60;
  177. return true;
  178. }
  179. #endif
  180. // Only translate keys in the map, ignore all other keys for now
  181. std::map<U32, KEY>::iterator iter = mTranslateKeyMap.find(os_key);
  182. if (iter == mTranslateKeyMap.end())
  183. {
  184. *out_key = 0;
  185. LL_DEBUGS("KeyCodes") << "Unknown key code: 0x" << std::hex << os_key
  186. << std::dec << LL_ENDL;
  187. return false;
  188. }
  189. *out_key = iter->second;
  190. LL_DEBUGS("KeyCodes") << "Key code: 0x" << std::hex << os_key
  191. << " - Translation: 0x" << (U32)*out_key << std::dec
  192. << LL_ENDL;
  193. return true;
  194. }
  195. U32 LLKeyboard::inverseTranslateKey(KEY translated_key)
  196. {
  197. std::map<KEY, U32>::iterator iter;
  198. iter = mInvTranslateKeyMap.find(translated_key);
  199. if (iter == mInvTranslateKeyMap.end())
  200. {
  201. LL_DEBUGS("KeyCodes") << "Unknown translated key: 0x" << std::hex
  202. << (U32)translated_key << std::dec << LL_ENDL;
  203. return 0;
  204. }
  205. LL_DEBUGS("KeyCodes") << "Translated key: 0x" << std::hex
  206. << (U32)translated_key << " - Original key code: 0x"
  207. << iter->second << std::dec << LL_ENDL;
  208. return iter->second;
  209. }
  210. bool LLKeyboard::handleTranslatedKeyDown(KEY translated_key,
  211. U32 translated_mask)
  212. {
  213. bool repeated = false;
  214. // Is this the first time the key went down ?
  215. // If so, generate "character" message
  216. if (!mKeyLevel[translated_key])
  217. {
  218. mKeyLevel[translated_key] = true;
  219. mKeyLevelTimer[translated_key].reset();
  220. mKeyLevelFrameCount[translated_key] = 0;
  221. mKeyRepeated[translated_key] = false;
  222. }
  223. else
  224. {
  225. // Level is already down, assume it is repeated.
  226. repeated = true;
  227. mKeyRepeated[translated_key] = true;
  228. }
  229. mKeyDown[translated_key] = true;
  230. mCurTranslatedKey = (KEY)translated_key;
  231. return mCallbacks->handleTranslatedKeyDown(translated_key, translated_mask,
  232. repeated);
  233. }
  234. bool LLKeyboard::handleTranslatedKeyUp(KEY translated_key, U32 translated_mask)
  235. {
  236. LL_DEBUGS("UserInput") << "keyup: " << translated_key << LL_ENDL;
  237. if (!mKeyLevel[translated_key])
  238. {
  239. return false;
  240. }
  241. mKeyLevel[translated_key] = false;
  242. // Only generate key up events if the key is thought to be down. This
  243. // allows you to call resetKeys() in the middle of a frame and ignore
  244. // subsequent KEY_UP messages in the same frame. This was causing the
  245. // sequence W<return> in chat to move agents forward. JC
  246. mKeyUp[translated_key] = true;
  247. return mCallbacks->handleTranslatedKeyUp(translated_key, translated_mask);
  248. }
  249. void LLKeyboard::toggleInsertMode()
  250. {
  251. if (LL_KIM_INSERT == mInsertMode)
  252. {
  253. mInsertMode = LL_KIM_OVERWRITE;
  254. }
  255. else
  256. {
  257. mInsertMode = LL_KIM_INSERT;
  258. }
  259. }
  260. // Returns time in seconds since key was pressed.
  261. F32 LLKeyboard::getKeyElapsedTime(KEY key)
  262. {
  263. return mKeyLevelTimer[key].getElapsedTimeF32();
  264. }
  265. // Returns time in frames since key was pressed.
  266. S32 LLKeyboard::getKeyElapsedFrameCount(KEY key)
  267. {
  268. return mKeyLevelFrameCount[key];
  269. }
  270. //static
  271. bool LLKeyboard::keyFromString(const char* str, KEY* key)
  272. {
  273. S32 length = strlen(str);
  274. if (length < 1)
  275. {
  276. return false;
  277. }
  278. if (length == 1)
  279. {
  280. const char ch = toupper(*str);
  281. if (('0' <= ch && ch <= '9') ||
  282. ('A' <= ch && ch <= 'Z') ||
  283. ('!' <= ch && ch <= '/') || // !"#$%&'()*+,-./
  284. (':' <= ch && ch <= '@') || // :;<=>?@
  285. ('[' <= ch && ch <= '`') || // [\]^_`
  286. ('{' <= ch && ch <= '~')) // {|}~
  287. {
  288. *key = ch;
  289. return true;
  290. }
  291. }
  292. std::string instring(str);
  293. LLStringUtil::toUpper(instring);
  294. KEY res = get_if_there(sNamesToKeys, instring, (KEY)0);
  295. if (res != 0)
  296. {
  297. *key = res;
  298. return true;
  299. }
  300. llwarns << "Failed to convert string: " << str << llendl;
  301. return false;
  302. }
  303. //static
  304. std::string LLKeyboard::stringFromKey(KEY key)
  305. {
  306. std::string res = get_if_there(sKeysToNames, key, std::string());
  307. if (res.empty())
  308. {
  309. char buffer[2];
  310. buffer[0] = key;
  311. buffer[1] = '\0';
  312. res = std::string(buffer);
  313. }
  314. return res;
  315. }
  316. //static
  317. bool LLKeyboard::maskFromString(const char* str, MASK* mask)
  318. {
  319. if (!str || *str == '\0')
  320. {
  321. return false;
  322. }
  323. if (!strcmp(str, "NONE"))
  324. {
  325. *mask = MASK_NONE;
  326. return true;
  327. }
  328. if (!strcmp(str, "SHIFT"))
  329. {
  330. *mask = MASK_SHIFT;
  331. return true;
  332. }
  333. if (!strcmp(str, "CTL"))
  334. {
  335. *mask = MASK_CONTROL;
  336. return true;
  337. }
  338. if (!strcmp(str, "ALT"))
  339. {
  340. *mask = MASK_ALT;
  341. return true;
  342. }
  343. if (!strcmp(str, "CTL_SHIFT"))
  344. {
  345. *mask = MASK_CONTROL | MASK_SHIFT;
  346. return true;
  347. }
  348. if (!strcmp(str, "ALT_SHIFT"))
  349. {
  350. *mask = MASK_ALT | MASK_SHIFT;
  351. return true;
  352. }
  353. if (!strcmp(str, "CTL_ALT"))
  354. {
  355. *mask = MASK_CONTROL | MASK_ALT;
  356. return true;
  357. }
  358. if (!strcmp(str, "CTL_ALT_SHIFT"))
  359. {
  360. *mask = MASK_CONTROL | MASK_ALT | MASK_SHIFT;
  361. return true;
  362. }
  363. return false;
  364. }