summaryrefslogtreecommitdiff
path: root/indra/llwindow/llkeyboardwin32.cpp
diff options
context:
space:
mode:
authorJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
committerJames Cook <james@lindenlab.com>2007-01-02 08:33:20 +0000
commit420b91db29485df39fd6e724e782c449158811cb (patch)
treeb471a94563af914d3ed3edd3e856d21cb1b69945 /indra/llwindow/llkeyboardwin32.cpp
Print done when done.
Diffstat (limited to 'indra/llwindow/llkeyboardwin32.cpp')
-rw-r--r--indra/llwindow/llkeyboardwin32.cpp372
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