diff options
author | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
---|---|---|
committer | James Cook <james@lindenlab.com> | 2007-01-02 08:33:20 +0000 |
commit | 420b91db29485df39fd6e724e782c449158811cb (patch) | |
tree | b471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llwindow/llkeyboardwin32.cpp |
Print done when done.
Diffstat (limited to 'indra/llwindow/llkeyboardwin32.cpp')
-rw-r--r-- | indra/llwindow/llkeyboardwin32.cpp | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp new file mode 100644 index 0000000000..37eb967e27 --- /dev/null +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -0,0 +1,372 @@ +/** + * @file llkeyboardwin32.cpp + * @brief Handler for assignable key bindings + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#if LL_WINDOWS + +#include "linden_common.h" +#include "llkeyboardwin32.h" +#include "llwindow.h" + +LLKeyboardWin32::LLKeyboardWin32() +{ + // Set up key mapping for windows - eventually can read this from a file? + // Anything not in the key map gets dropped + // Add default A-Z + + // Virtual key mappings from WinUser.h + + KEY cur_char; + for (cur_char = 'A'; cur_char <= 'Z'; cur_char++) + { + mTranslateKeyMap[cur_char] = (KEY)cur_char; + } + + for (cur_char = '0'; cur_char <= '9'; cur_char++) + { + mTranslateKeyMap[cur_char] = (KEY)cur_char; + } + // numpad number keys + for (cur_char = 0x60; cur_char <= 0x69; cur_char++) + { + mTranslateKeyMap[cur_char] = (KEY)('0' + (0x60 - cur_char)); + } + + + mTranslateKeyMap[VK_SPACE] = ' '; + mTranslateKeyMap[VK_OEM_1] = ';'; + // When the user hits, for example, Ctrl-= as a keyboard shortcut, + // Windows generates VK_OEM_PLUS. This is true on both QWERTY and DVORAK + // keyboards in the US. Numeric keypad '+' generates VK_ADD below. + // Thus we translate it as '='. + // Potential bug: This may not be true on international keyboards. JC + mTranslateKeyMap[VK_OEM_PLUS] = '='; + mTranslateKeyMap[VK_OEM_COMMA] = ','; + mTranslateKeyMap[VK_OEM_MINUS] = '-'; + mTranslateKeyMap[VK_OEM_PERIOD] = '.'; + mTranslateKeyMap[VK_OEM_2] = '/'; + mTranslateKeyMap[VK_OEM_3] = '`'; + mTranslateKeyMap[VK_OEM_4] = '['; + mTranslateKeyMap[VK_OEM_5] = '\\'; + mTranslateKeyMap[VK_OEM_6] = ']'; + mTranslateKeyMap[VK_OEM_7] = '\''; + mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE; + mTranslateKeyMap[VK_RETURN] = KEY_RETURN; + mTranslateKeyMap[VK_LEFT] = KEY_LEFT; + mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT; + mTranslateKeyMap[VK_UP] = KEY_UP; + mTranslateKeyMap[VK_DOWN] = KEY_DOWN; + mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE; + mTranslateKeyMap[VK_INSERT] = KEY_INSERT; + mTranslateKeyMap[VK_DELETE] = KEY_DELETE; + mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT; + mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL; + mTranslateKeyMap[VK_MENU] = KEY_ALT; + mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK; + mTranslateKeyMap[VK_HOME] = KEY_HOME; + mTranslateKeyMap[VK_END] = KEY_END; + mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP; + mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN; + mTranslateKeyMap[VK_TAB] = KEY_TAB; + mTranslateKeyMap[VK_ADD] = KEY_ADD; + mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT; + mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY; + mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE; + mTranslateKeyMap[VK_F1] = KEY_F1; + mTranslateKeyMap[VK_F2] = KEY_F2; + mTranslateKeyMap[VK_F3] = KEY_F3; + mTranslateKeyMap[VK_F4] = KEY_F4; + mTranslateKeyMap[VK_F5] = KEY_F5; + mTranslateKeyMap[VK_F6] = KEY_F6; + mTranslateKeyMap[VK_F7] = KEY_F7; + mTranslateKeyMap[VK_F8] = KEY_F8; + mTranslateKeyMap[VK_F9] = KEY_F9; + mTranslateKeyMap[VK_F10] = KEY_F10; + mTranslateKeyMap[VK_F11] = KEY_F11; + mTranslateKeyMap[VK_F12] = KEY_F12; + mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER; + + // Build inverse map + std::map<U16, KEY>::iterator iter; + for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++) + { + mInvTranslateKeyMap[iter->second] = iter->first; + } + + // numpad map + mTranslateNumpadMap[0x60] = KEY_PAD_INS; // keypad 0 + mTranslateNumpadMap[0x61] = KEY_PAD_END; // keypad 1 + mTranslateNumpadMap[0x62] = KEY_PAD_DOWN; // keypad 2 + mTranslateNumpadMap[0x63] = KEY_PAD_PGDN; // keypad 3 + mTranslateNumpadMap[0x64] = KEY_PAD_LEFT; // keypad 4 + mTranslateNumpadMap[0x65] = KEY_PAD_CENTER; // keypad 5 + mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT; // keypad 6 + mTranslateNumpadMap[0x67] = KEY_PAD_HOME; // keypad 7 + mTranslateNumpadMap[0x68] = KEY_PAD_UP; // keypad 8 + mTranslateNumpadMap[0x69] = KEY_PAD_PGUP; // keypad 9 + mTranslateNumpadMap[0x6E] = KEY_PAD_DEL; // keypad . + + for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++) + { + mInvTranslateNumpadMap[iter->second] = iter->first; + } +} + +// Asynchronously poll the control, alt and shift keys and set the +// appropriate states. +// Note: this does not generate edges. +void LLKeyboardWin32::resetMaskKeys() +{ + // GetAsyncKeyState returns a short and uses the most significant + // bit to indicate that the key is down. + if (GetAsyncKeyState(VK_SHIFT) & 0x8000) + { + mKeyLevel[KEY_SHIFT] = TRUE; + } + + if (GetAsyncKeyState(VK_CONTROL) & 0x8000) + { + mKeyLevel[KEY_CONTROL] = TRUE; + } + + if (GetAsyncKeyState(VK_MENU) & 0x8000) + { + mKeyLevel[KEY_ALT] = TRUE; + } +} + + +void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state ) +{ + if( mKeyLevel[key] != new_state ) + { + mKeyLevelFrameCount[key] = 0; + + if( new_state ) + { + mKeyLevelTimer[key].reset(); + } + mKeyLevel[key] = new_state; + } +} + + +MASK LLKeyboardWin32::updateModifiers() +{ + // Scan the modifier keys as of the last Windows key message + // (keydown encoded in high order bit of short) + setModifierKeyLevel( KEY_SHIFT, GetKeyState(VK_SHIFT) & 0x8000 ); + setModifierKeyLevel( KEY_CONTROL, GetKeyState(VK_CONTROL) & 0x8000 ); + setModifierKeyLevel( KEY_ALT, GetKeyState(VK_MENU) & 0x8000 ); + setModifierKeyLevel( KEY_CAPSLOCK, GetKeyState(VK_CAPITAL) & 0x0001); // Low order bit carries the toggle state. + // Get mask for keyboard events + MASK mask = currentMask(FALSE); + return mask; +} + + +// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags +BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask) +{ + KEY translated_key; + U32 translated_mask; + BOOL handled = FALSE; + + translated_mask = updateModifiers(); + + if (translateExtendedKey(key, mask, &translated_key)) + { + handled = handleTranslatedKeyDown(translated_key, translated_mask); + } + + return handled; +} + + +// mask is ignored, except for extended flag -- we poll the modifier keys for the other flags +BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask) +{ + KEY translated_key; + U32 translated_mask; + BOOL handled = FALSE; + + translated_mask = updateModifiers(); + + if (translateExtendedKey(key, mask, &translated_key)) + { + handled = handleTranslatedKeyUp(translated_key, translated_mask); + } + + return handled; +} + + +MASK LLKeyboardWin32::currentMask(BOOL) +{ + MASK mask = MASK_NONE; + + if (mKeyLevel[KEY_SHIFT]) mask |= MASK_SHIFT; + if (mKeyLevel[KEY_CONTROL]) mask |= MASK_CONTROL; + if (mKeyLevel[KEY_ALT]) mask |= MASK_ALT; + + return mask; +} + + +void LLKeyboardWin32::scanKeyboard() +{ + S32 key; + for (key = 0; key < KEY_COUNT; key++) + { + // On Windows, verify key down state. JC + if (mKeyLevel[key]) + { + // FIXME: I KNOW there must be a better way of interrogating the key state than this, using async + // key state can cause ALL kinds of bugs - Doug + if (key < KEY_BUTTON0) + { + // ...under windows make sure the key actually still is down. + // ...translate back to windows key + U16 virtual_key = inverseTranslateExtendedKey(key); + // keydown in highest bit + if (!(GetAsyncKeyState(virtual_key) & 0x8000)) + { + //llinfos << "Key up event missed, resetting" << llendl; + mKeyLevel[key] = FALSE; + mKeyLevelFrameCount[key] = 0; + } + } + } + + // Generate callback if any event has occurred on this key this frame. + // Can't just test mKeyLevel, because this could be a slow frame and + // key might have gone down then up. JC + if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key]) + { + mCurScanKey = key; + mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]); + } + } + + // Reset edges for next frame + for (key = 0; key < KEY_COUNT; key++) + { + mKeyUp[key] = FALSE; + mKeyDown[key] = FALSE; + if (mKeyLevel[key]) + { + mKeyLevelFrameCount[key]++; + } + } +} + +BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key) +{ + if(mNumpadDistinct == ND_NUMLOCK_ON) + { + std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key); + if (iter != mTranslateNumpadMap.end()) + { + *translated_key = iter->second; + return TRUE; + } + } + + BOOL success = translateKey(os_key, translated_key); + if(mNumpadDistinct != ND_NEVER) { + if(!success) return success; + if(mask & MASK_EXTENDED) + { + // this is where we'd create new keycodes for extended keys + // the set of extended keys includes the 'normal' arrow keys and + // the pgup/dn/insert/home/end/delete cluster above the arrow keys + // see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx + + // only process the return key if numlock is off + if(((mNumpadDistinct == ND_NUMLOCK_OFF && + !(GetKeyState(VK_NUMLOCK) & 1)) + || mNumpadDistinct == ND_NUMLOCK_ON) && + *translated_key == KEY_RETURN) { + *translated_key = KEY_PAD_RETURN; + } + } + else + { + // the non-extended keys, those are in the numpad + switch (*translated_key) + { + case KEY_LEFT: + *translated_key = KEY_PAD_LEFT; break; + case KEY_RIGHT: + *translated_key = KEY_PAD_RIGHT; break; + case KEY_UP: + *translated_key = KEY_PAD_UP; break; + case KEY_DOWN: + *translated_key = KEY_PAD_DOWN; break; + case KEY_HOME: + *translated_key = KEY_PAD_HOME; break; + case KEY_END: + *translated_key = KEY_PAD_END; break; + case KEY_PAGE_UP: + *translated_key = KEY_PAD_PGUP; break; + case KEY_PAGE_DOWN: + *translated_key = KEY_PAD_PGDN; break; + case KEY_INSERT: + *translated_key = KEY_PAD_INS; break; + case KEY_DELETE: + *translated_key = KEY_PAD_DEL; break; + } + } + } + return success; +} + +U16 LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key) +{ + // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number + if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1)) + { + std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key); + if (iter != mInvTranslateNumpadMap.end()) + { + return iter->second; + } + } + + // if numlock is off or we're not converting numbers to arrows, we map our keypad arrows + // to regular arrows since Windows doesn't distinguish between them + KEY converted_key = translated_key; + switch (converted_key) + { + case KEY_PAD_LEFT: + converted_key = KEY_LEFT; break; + case KEY_PAD_RIGHT: + converted_key = KEY_RIGHT; break; + case KEY_PAD_UP: + converted_key = KEY_UP; break; + case KEY_PAD_DOWN: + converted_key = KEY_DOWN; break; + case KEY_PAD_HOME: + converted_key = KEY_HOME; break; + case KEY_PAD_END: + converted_key = KEY_END; break; + case KEY_PAD_PGUP: + converted_key = KEY_PAGE_UP; break; + case KEY_PAD_PGDN: + converted_key = KEY_PAGE_DOWN; break; + case KEY_PAD_INS: + converted_key = KEY_INSERT; break; + case KEY_PAD_DEL: + converted_key = KEY_DELETE; break; + case KEY_PAD_RETURN: + converted_key = KEY_RETURN; break; + } + // convert our virtual keys to OS keys + return inverseTranslateKey(converted_key); +} + +#endif |