llkeyboardwin32.cpp

Go to the documentation of this file.
00001 
00032 #if LL_WINDOWS
00033 
00034 #include "linden_common.h"
00035 
00036 #include "llkeyboardwin32.h"
00037 
00038 #include "llwindow.h"
00039 
00040 #define WIN32_LEAN_AND_MEAN
00041 #include <winsock2.h>
00042 #include <windows.h>
00043 
00044 LLKeyboardWin32::LLKeyboardWin32()
00045 {
00046         // Set up key mapping for windows - eventually can read this from a file?
00047         // Anything not in the key map gets dropped
00048         // Add default A-Z
00049 
00050         // Virtual key mappings from WinUser.h
00051 
00052         KEY cur_char;
00053         for (cur_char = 'A'; cur_char <= 'Z'; cur_char++)
00054         {
00055                 mTranslateKeyMap[cur_char] = (KEY)cur_char;
00056         }
00057 
00058         for (cur_char = '0'; cur_char <= '9'; cur_char++)
00059         {
00060                 mTranslateKeyMap[cur_char] = (KEY)cur_char;
00061         }
00062         // numpad number keys
00063         for (cur_char = 0x60; cur_char <= 0x69; cur_char++)
00064         {
00065                 mTranslateKeyMap[cur_char] = (KEY)('0' + (0x60 - cur_char));
00066         }
00067 
00068 
00069         mTranslateKeyMap[VK_SPACE] = ' ';
00070         mTranslateKeyMap[VK_OEM_1] = ';';
00071         // When the user hits, for example, Ctrl-= as a keyboard shortcut,
00072         // Windows generates VK_OEM_PLUS.  This is true on both QWERTY and DVORAK
00073         // keyboards in the US.  Numeric keypad '+' generates VK_ADD below.
00074         // Thus we translate it as '='.
00075         // Potential bug: This may not be true on international keyboards. JC
00076         mTranslateKeyMap[VK_OEM_PLUS]   = '=';
00077         mTranslateKeyMap[VK_OEM_COMMA]  = ',';
00078         mTranslateKeyMap[VK_OEM_MINUS]  = '-';
00079         mTranslateKeyMap[VK_OEM_PERIOD] = '.';
00080         mTranslateKeyMap[VK_OEM_2] = KEY_PAD_DIVIDE;
00081         mTranslateKeyMap[VK_OEM_3] = '`';
00082         mTranslateKeyMap[VK_OEM_4] = '[';
00083         mTranslateKeyMap[VK_OEM_5] = '\\';
00084         mTranslateKeyMap[VK_OEM_6] = ']';
00085         mTranslateKeyMap[VK_OEM_7] = '\'';
00086         mTranslateKeyMap[VK_ESCAPE] = KEY_ESCAPE;
00087         mTranslateKeyMap[VK_RETURN] = KEY_RETURN;
00088         mTranslateKeyMap[VK_LEFT] = KEY_LEFT;
00089         mTranslateKeyMap[VK_RIGHT] = KEY_RIGHT;
00090         mTranslateKeyMap[VK_UP] = KEY_UP;
00091         mTranslateKeyMap[VK_DOWN] = KEY_DOWN;
00092         mTranslateKeyMap[VK_BACK] = KEY_BACKSPACE;
00093         mTranslateKeyMap[VK_INSERT] = KEY_INSERT;
00094         mTranslateKeyMap[VK_DELETE] = KEY_DELETE;
00095         mTranslateKeyMap[VK_SHIFT] = KEY_SHIFT;
00096         mTranslateKeyMap[VK_CONTROL] = KEY_CONTROL;
00097         mTranslateKeyMap[VK_MENU] = KEY_ALT;
00098         mTranslateKeyMap[VK_CAPITAL] = KEY_CAPSLOCK;
00099         mTranslateKeyMap[VK_HOME] = KEY_HOME;
00100         mTranslateKeyMap[VK_END] = KEY_END;
00101         mTranslateKeyMap[VK_PRIOR] = KEY_PAGE_UP;
00102         mTranslateKeyMap[VK_NEXT] = KEY_PAGE_DOWN;
00103         mTranslateKeyMap[VK_TAB] = KEY_TAB;
00104         mTranslateKeyMap[VK_ADD] = KEY_ADD;
00105         mTranslateKeyMap[VK_SUBTRACT] = KEY_SUBTRACT;
00106         mTranslateKeyMap[VK_MULTIPLY] = KEY_MULTIPLY;
00107         mTranslateKeyMap[VK_DIVIDE] = KEY_DIVIDE;
00108         mTranslateKeyMap[VK_F1] = KEY_F1;
00109         mTranslateKeyMap[VK_F2] = KEY_F2;
00110         mTranslateKeyMap[VK_F3] = KEY_F3;
00111         mTranslateKeyMap[VK_F4] = KEY_F4;
00112         mTranslateKeyMap[VK_F5] = KEY_F5;
00113         mTranslateKeyMap[VK_F6] = KEY_F6;
00114         mTranslateKeyMap[VK_F7] = KEY_F7;
00115         mTranslateKeyMap[VK_F8] = KEY_F8;
00116         mTranslateKeyMap[VK_F9] = KEY_F9;
00117         mTranslateKeyMap[VK_F10] = KEY_F10;
00118         mTranslateKeyMap[VK_F11] = KEY_F11;
00119         mTranslateKeyMap[VK_F12] = KEY_F12;
00120         mTranslateKeyMap[VK_CLEAR] = KEY_PAD_CENTER;
00121 
00122         // Build inverse map
00123         std::map<U16, KEY>::iterator iter;
00124         for (iter = mTranslateKeyMap.begin(); iter != mTranslateKeyMap.end(); iter++)
00125         {
00126                 mInvTranslateKeyMap[iter->second] = iter->first;
00127         }
00128 
00129         // numpad map
00130         mTranslateNumpadMap[0x60] = KEY_PAD_INS;        // keypad 0
00131         mTranslateNumpadMap[0x61] = KEY_PAD_END;        // keypad 1
00132         mTranslateNumpadMap[0x62] = KEY_PAD_DOWN;       // keypad 2
00133         mTranslateNumpadMap[0x63] = KEY_PAD_PGDN;       // keypad 3
00134         mTranslateNumpadMap[0x64] = KEY_PAD_LEFT;       // keypad 4
00135         mTranslateNumpadMap[0x65] = KEY_PAD_CENTER;     // keypad 5
00136         mTranslateNumpadMap[0x66] = KEY_PAD_RIGHT;      // keypad 6
00137         mTranslateNumpadMap[0x67] = KEY_PAD_HOME;       // keypad 7
00138         mTranslateNumpadMap[0x68] = KEY_PAD_UP;         // keypad 8
00139         mTranslateNumpadMap[0x69] = KEY_PAD_PGUP;       // keypad 9
00140         mTranslateNumpadMap[0x6A] = KEY_PAD_MULTIPLY;   // keypad *
00141         mTranslateNumpadMap[0x6B] = KEY_PAD_ADD;        // keypad +
00142         mTranslateNumpadMap[0x6D] = KEY_PAD_SUBTRACT;   // keypad -
00143         mTranslateNumpadMap[0x6E] = KEY_PAD_DEL;        // keypad .
00144         mTranslateNumpadMap[0x6F] = KEY_PAD_DIVIDE;     // keypad /
00145 
00146         for (iter = mTranslateNumpadMap.begin(); iter != mTranslateNumpadMap.end(); iter++)
00147         {
00148                 mInvTranslateNumpadMap[iter->second] = iter->first;
00149         }
00150 }
00151 
00152 // Asynchronously poll the control, alt and shift keys and set the
00153 // appropriate states.
00154 // Note: this does not generate edges.
00155 void LLKeyboardWin32::resetMaskKeys()
00156 {
00157         // GetAsyncKeyState returns a short and uses the most significant
00158         // bit to indicate that the key is down.
00159         if (GetAsyncKeyState(VK_SHIFT) & 0x8000)
00160         {
00161                 mKeyLevel[KEY_SHIFT] = TRUE;
00162         }
00163 
00164         if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
00165         {
00166                 mKeyLevel[KEY_CONTROL] = TRUE;
00167         }
00168 
00169         if (GetAsyncKeyState(VK_MENU) & 0x8000)
00170         {
00171                 mKeyLevel[KEY_ALT] = TRUE;
00172         }
00173 }
00174 
00175 
00176 //void LLKeyboardWin32::setModifierKeyLevel( KEY key, BOOL new_state )
00177 //{
00178 //      if( mKeyLevel[key] != new_state )
00179 //      {
00180 //              mKeyLevelFrameCount[key] = 0;
00181 //
00182 //              if( new_state )
00183 //              {
00184 //                      mKeyLevelTimer[key].reset();
00185 //              }
00186 //              mKeyLevel[key] = new_state;
00187 //      }
00188 //}
00189 
00190 
00191 MASK LLKeyboardWin32::updateModifiers()
00192 {
00193         //RN: this seems redundant, as we should have already received the appropriate
00194         // messages for the modifier keys
00195 
00196         // Scan the modifier keys as of the last Windows key message
00197         // (keydown encoded in high order bit of short)
00198         mKeyLevel[KEY_CAPSLOCK] = (GetKeyState(VK_CAPITAL) & 0x0001) != 0; // Low order bit carries the toggle state.
00199         // Get mask for keyboard events
00200         MASK mask = currentMask(FALSE);
00201         return mask;
00202 }
00203 
00204 
00205 // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags
00206 BOOL LLKeyboardWin32::handleKeyDown(const U16 key, MASK mask)
00207 {
00208         KEY             translated_key;
00209         U32             translated_mask;
00210         BOOL    handled = FALSE;
00211 
00212         translated_mask = updateModifiers();
00213 
00214         if (translateExtendedKey(key, mask, &translated_key))
00215         {
00216                 handled = handleTranslatedKeyDown(translated_key, translated_mask);
00217         }
00218 
00219         return handled;
00220 }
00221 
00222 // mask is ignored, except for extended flag -- we poll the modifier keys for the other flags
00223 BOOL LLKeyboardWin32::handleKeyUp(const U16 key, MASK mask)
00224 {
00225         KEY             translated_key;
00226         U32             translated_mask;
00227         BOOL    handled = FALSE;
00228 
00229         translated_mask = updateModifiers();
00230 
00231         if (translateExtendedKey(key, mask, &translated_key))
00232         {
00233                 handled = handleTranslatedKeyUp(translated_key, translated_mask);
00234         }
00235 
00236         return handled;
00237 }
00238 
00239 
00240 MASK LLKeyboardWin32::currentMask(BOOL)
00241 {
00242         MASK mask = MASK_NONE;
00243 
00244         if (mKeyLevel[KEY_SHIFT])               mask |= MASK_SHIFT;
00245         if (mKeyLevel[KEY_CONTROL])             mask |= MASK_CONTROL;
00246         if (mKeyLevel[KEY_ALT])                 mask |= MASK_ALT;
00247 
00248         return mask;
00249 }
00250 
00251 
00252 void LLKeyboardWin32::scanKeyboard()
00253 {
00254         S32 key;
00255         MSG     msg;
00256         BOOL pending_key_events = PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_NOREMOVE | PM_NOYIELD);
00257         for (key = 0; key < KEY_COUNT; key++)
00258         {
00259                 // On Windows, verify key down state. JC
00260                 // RN: only do this if we don't have further key events in the queue
00261                 // as otherwise there might be key repeat events still waiting for this key we are now dumping
00262                 if (!pending_key_events && mKeyLevel[key])
00263                 {
00264                         // *TODO: I KNOW there must be a better way of
00265                         // interrogating the key state than this, using async key
00266                         // state can cause ALL kinds of bugs - Doug
00267                         if (key < KEY_BUTTON0)
00268                         {
00269                                 // ...under windows make sure the key actually still is down.
00270                                 // ...translate back to windows key
00271                                 U16 virtual_key = inverseTranslateExtendedKey(key);
00272                                 // keydown in highest bit
00273                                 if (!pending_key_events && !(GetAsyncKeyState(virtual_key) & 0x8000))
00274                                 {
00275                                         //llinfos << "Key up event missed, resetting" << llendl;
00276                                         mKeyLevel[key] = FALSE;
00277                                 }
00278                         }
00279                 }
00280 
00281                 // Generate callback if any event has occurred on this key this frame.
00282                 // Can't just test mKeyLevel, because this could be a slow frame and
00283                 // key might have gone down then up. JC
00284                 if (mKeyLevel[key] || mKeyDown[key] || mKeyUp[key])
00285                 {
00286                         mCurScanKey = key;
00287                         mCallbacks->handleScanKey(key, mKeyDown[key], mKeyUp[key], mKeyLevel[key]);
00288                 }
00289         }
00290 
00291         // Reset edges for next frame
00292         for (key = 0; key < KEY_COUNT; key++)
00293         {
00294                 mKeyUp[key] = FALSE;
00295                 mKeyDown[key] = FALSE;
00296                 if (mKeyLevel[key])
00297                 {
00298                         mKeyLevelFrameCount[key]++;
00299                 }
00300         }
00301 }
00302 
00303 BOOL LLKeyboardWin32::translateExtendedKey(const U16 os_key, const MASK mask, KEY *translated_key)
00304 {
00305         if(mNumpadDistinct == ND_NUMLOCK_ON)
00306         {
00307                 std::map<U16, KEY>::iterator iter = mTranslateNumpadMap.find(os_key);
00308                 if (iter != mTranslateNumpadMap.end())
00309                 {
00310                         *translated_key = iter->second;
00311                         return TRUE;
00312                 }
00313         }
00314 
00315         BOOL success = translateKey(os_key, translated_key);
00316         if(mNumpadDistinct != ND_NEVER) {
00317                 if(!success) return success;
00318                 if(mask & MASK_EXTENDED) 
00319                 {
00320                         // this is where we'd create new keycodes for extended keys
00321                         // the set of extended keys includes the 'normal' arrow keys and 
00322                         // the pgup/dn/insert/home/end/delete cluster above the arrow keys
00323                         // see http://windowssdk.msdn.microsoft.com/en-us/library/ms646280.aspx
00324 
00325                         // only process the return key if numlock is off
00326                         if(((mNumpadDistinct == ND_NUMLOCK_OFF && 
00327                                  !(GetKeyState(VK_NUMLOCK) & 1)) 
00328                                  || mNumpadDistinct == ND_NUMLOCK_ON) &&
00329                                         *translated_key == KEY_RETURN) {
00330                                         *translated_key = KEY_PAD_RETURN;
00331                         }
00332                 }
00333                 else 
00334                 {
00335                         // the non-extended keys, those are in the numpad
00336                         switch (*translated_key) 
00337                         {
00338                                 case KEY_LEFT:
00339                                         *translated_key = KEY_PAD_LEFT; break;
00340                                 case KEY_RIGHT: 
00341                                         *translated_key = KEY_PAD_RIGHT; break;
00342                                 case KEY_UP: 
00343                                         *translated_key = KEY_PAD_UP; break;
00344                                 case KEY_DOWN:
00345                                         *translated_key = KEY_PAD_DOWN; break;
00346                                 case KEY_HOME:
00347                                         *translated_key = KEY_PAD_HOME; break;
00348                                 case KEY_END:
00349                                         *translated_key = KEY_PAD_END; break;
00350                                 case KEY_PAGE_UP:
00351                                         *translated_key = KEY_PAD_PGUP; break;
00352                                 case KEY_PAGE_DOWN:
00353                                         *translated_key = KEY_PAD_PGDN; break;
00354                                 case KEY_INSERT:
00355                                         *translated_key = KEY_PAD_INS; break;
00356                                 case KEY_DELETE:
00357                                         *translated_key = KEY_PAD_DEL; break;
00358                         }
00359                 }
00360         }
00361         return success;
00362 }
00363 
00364 U16  LLKeyboardWin32::inverseTranslateExtendedKey(const KEY translated_key)
00365 {
00366         // if numlock is on, then we need to translate KEY_PAD_FOO to the corresponding number pad number
00367         if((mNumpadDistinct == ND_NUMLOCK_ON) && (GetKeyState(VK_NUMLOCK) & 1))
00368         {
00369                 std::map<KEY, U16>::iterator iter = mInvTranslateNumpadMap.find(translated_key);
00370                 if (iter != mInvTranslateNumpadMap.end())
00371                 {
00372                         return iter->second;
00373                 }
00374         }
00375 
00376         // if numlock is off or we're not converting numbers to arrows, we map our keypad arrows
00377         // to regular arrows since Windows doesn't distinguish between them
00378         KEY converted_key = translated_key;
00379         switch (converted_key) 
00380         {
00381                 case KEY_PAD_LEFT:
00382                         converted_key = KEY_LEFT; break;
00383                 case KEY_PAD_RIGHT: 
00384                         converted_key = KEY_RIGHT; break;
00385                 case KEY_PAD_UP: 
00386                         converted_key = KEY_UP; break;
00387                 case KEY_PAD_DOWN:
00388                         converted_key = KEY_DOWN; break;
00389                 case KEY_PAD_HOME:
00390                         converted_key = KEY_HOME; break;
00391                 case KEY_PAD_END:
00392                         converted_key = KEY_END; break;
00393                 case KEY_PAD_PGUP:
00394                         converted_key = KEY_PAGE_UP; break;
00395                 case KEY_PAD_PGDN:
00396                         converted_key = KEY_PAGE_DOWN; break;
00397                 case KEY_PAD_INS:
00398                         converted_key = KEY_INSERT; break;
00399                 case KEY_PAD_DEL:
00400                         converted_key = KEY_DELETE; break;
00401                 case KEY_PAD_RETURN:
00402                         converted_key = KEY_RETURN; break;
00403         }
00404         // convert our virtual keys to OS keys
00405         return inverseTranslateKey(converted_key);
00406 }
00407 
00408 #endif

Generated on Fri May 16 08:33:02 2008 for SecondLife by  doxygen 1.5.5