00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "stdmisc.h"
00029 #include "misc/di_keyboard_device.h"
00030
00031 #ifdef NL_OS_WINDOWS
00032
00033 #include "nel/misc/win_event_emitter.h"
00034 #include <memory>
00035 #include <dinput.h>
00036 #include <Winuser.h>
00037
00038 #include "Mmsystem.h"
00039
00040
00041 #ifdef min
00042 #undef min
00043 #endif
00044
00045 #ifdef max
00046 #undef max
00047 #endif
00048
00049 namespace NLMISC
00050 {
00051
00052
00053 struct CKeyConv
00054 {
00055 uint DIKey;
00056 TKey NelKey;
00057 const char *KeyName;
00058 bool Repeatable;
00059 };
00060
00061
00062 static const CKeyConv DIToNel[] =
00063 {
00064
00065 {DIK_F1, KeyF1, "F1", true},
00066 {DIK_F2, KeyF2, "F2", true},
00067 {DIK_F3, KeyF3, "F3", true},
00068 {DIK_F4, KeyF4, "F4", true},
00069 {DIK_F5, KeyF5, "F5", true},
00070 {DIK_F6, KeyF6, "F6", true},
00071 {DIK_F7, KeyF7, "F7", true},
00072 {DIK_F8, KeyF8, "F8", true},
00073 {DIK_F9, KeyF9, "F9", true},
00074 {DIK_F10, KeyF10, "F10", true},
00075 {DIK_F11, KeyF11, "F11", true},
00076 {DIK_F12, KeyF12, "F12", true},
00077 {DIK_F13, KeyF13, "F13", true},
00078 {DIK_F14, KeyF14, "F14", true},
00079 {DIK_F15, KeyF15, "F15", true},
00080
00081 {DIK_NUMPAD0, KeyNUMPAD0, "NUMPAD0", true},
00082 {DIK_NUMPAD1, KeyNUMPAD1, "NUMPAD1", true},
00083 {DIK_NUMPAD2, KeyNUMPAD2, "NUMPAD2", true},
00084 {DIK_NUMPAD3, KeyNUMPAD3, "NUMPAD3", true},
00085 {DIK_NUMPAD4, KeyNUMPAD4, "NUMPAD4", true},
00086 {DIK_NUMPAD5, KeyNUMPAD5, "NUMPAD5", true},
00087 {DIK_NUMPAD6, KeyNUMPAD6, "NUMPAD6", true},
00088 {DIK_NUMPAD7, KeyNUMPAD7, "NUMPAD7", true},
00089 {DIK_NUMPAD8, KeyNUMPAD8, "NUMPAD8", true},
00090 {DIK_NUMPAD9, KeyNUMPAD9, "NUMPAD9", true},
00091
00092 {DIK_DIVIDE, KeyDIVIDE, "/", true},
00093 {DIK_DECIMAL, KeyDECIMAL, "NUMPAD .", true},
00094
00095 {DIK_LSHIFT, KeyLSHIFT, "LEFT SHIFT", false},
00096 {DIK_RSHIFT, KeyRSHIFT, "RIGHT SHIFT", false},
00097
00098 {DIK_LCONTROL, KeyLCONTROL, "LEFT CONTROL", false},
00099 {DIK_RCONTROL, KeyRCONTROL, "RIGHT CONTROL", false},
00100
00101 {DIK_LMENU, KeyLMENU, "ALT", false},
00102 {DIK_RMENU, KeyRMENU, "ALT GR", false},
00103
00104 {DIK_UP, KeyUP, "UP", true},
00105 {DIK_PRIOR, KeyPRIOR, "PRIOR", true},
00106 {DIK_LEFT, KeyLEFT, "LEFT", true},
00107 {DIK_RIGHT, KeyRIGHT, "RIGHT", true},
00108 {DIK_END, KeyEND, "END", true},
00109 {DIK_DOWN, KeyDOWN, "DOWN", true},
00110 {DIK_NEXT, KeyNEXT, "NEXT", true},
00111 {DIK_INSERT, KeyINSERT, "INSERT", true},
00112 {DIK_DELETE, KeyDELETE, "DELETE", true},
00113 {DIK_HOME, KeyHOME, "HOME", true},
00114 {DIK_LWIN, KeyLWIN, "LEFT WIN", false},
00115 {DIK_RWIN, KeyRWIN, "RIGHT WIN", false},
00116 {DIK_APPS, KeyAPPS, "APPS", false},
00117
00118 {DIK_SYSRQ, KeySNAPSHOT, "SNAPSHOT", false},
00119 {DIK_SCROLL, KeySCROLL, "SCROLL", false},
00120 {DIK_PAUSE, KeyPAUSE, "PAUSE", false},
00121
00122 {DIK_NUMLOCK, KeyNUMLOCK, "NUMLOCK", false},
00123
00124
00125
00126 {DIK_CONVERT, KeyCONVERT, "CONVERT", false},
00127 {DIK_NOCONVERT, KeyNONCONVERT, "NOCONVERT", true},
00128
00129 {DIK_KANA, KeyKANA, false},
00130 {DIK_KANJI, KeyKANJI, false},
00131 };
00132
00133
00135 const CKeyConv *CDIKeyboard::DIKeyToNelKeyTab[CDIKeyboard::NumKeys];
00136
00138 CDIKeyboard::CDIKeyboard(CWinEventEmitter *we, HWND hwnd)
00139 : _Keyboard(NULL),
00140 _WE(we),
00141 ShiftPressed(false),
00142 CtrlPressed(false),
00143 AltPressed(false),
00144 _CapsLockToggle(true),
00145 _hWnd(hwnd),
00146 _RepeatDelay(250),
00147 _RepeatPeriod(200),
00148 _FirstPressDate(-1),
00149 _LastDIKeyPressed(0)
00150 {
00151 if (::GetKeyboardState((PBYTE) _VKKeyState) == FALSE)
00152 {
00153 std::fill(_VKKeyState, _VKKeyState + NumKeys, 0);
00154 }
00155
00156 HKEY hKey;
00157 if (::RegOpenKeyEx(HKEY_CURRENT_USER, "Keyboard Layout", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
00158 {
00159 DWORD type = REG_DWORD;
00160 DWORD value;
00161 DWORD size = sizeof(DWORD);
00162 if (::RegQueryValueEx(hKey, "Attributes", NULL, &type, (LPBYTE) &value, &size) == ERROR_SUCCESS)
00163 {
00164 _CapsLockToggle = (value & (1 << 16)) == 0;
00165 }
00166 ::RegCloseKey(hKey);
00167 }
00168
00169 int keybDelay;
00170 if (::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &keybDelay, 0) != 0)
00171 {
00172 _RepeatDelay = 250 + 250 * keybDelay;
00173 }
00174 DWORD keybSpeed;
00175 if (::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &keybSpeed, 0) != 0)
00176 {
00177 _RepeatPeriod = (uint) (1000.f / (keybSpeed * (27.5f / 31.f) + 2.5f));
00178 }
00179
00180 _KBLayout = ::GetKeyboardLayout(NULL);
00181
00182 _RepetitionDisabled.resize(NumKeys);
00183 _RepetitionDisabled.clearAll();
00184 }
00185
00187 void CDIKeyboard::updateVKKeyState(uint diKey, bool pressed, TKey &keyValue, TKey &charValue)
00188 {
00189 bool extKey;
00190 bool repeatable;
00191 keyValue = DIKeyToNelKey(diKey, extKey, repeatable);
00192
00193 if (keyValue == 0)
00194 {
00195 charValue = keyValue;
00196 return;
00197 }
00198
00199 if (pressed)
00200 {
00201
00202 switch (keyValue)
00203 {
00204 case KeyPAUSE:
00205 case KeyKANA:
00206 case KeyKANJI:
00207 _VKKeyState[keyValue] ^= 0x01;
00208 break;
00209 case KeyCAPITAL:
00210 if (_CapsLockToggle)
00211 {
00212 _VKKeyState[keyValue] ^= 0x01;
00213
00214 }
00215 else
00216 {
00217 if ((_VKKeyState[keyValue] & 0x01) == 0)
00218 {
00219 _VKKeyState[keyValue] |= 0x01;
00220
00221 }
00222 }
00223 break;
00224 case KeyNUMLOCK:
00225 _VKKeyState[keyValue] ^= 0x01;
00226
00227 break;
00228 case KeySCROLL:
00229 _VKKeyState[keyValue] ^= 0x01;
00230
00231 break;
00232
00233 }
00234
00235 _VKKeyState[keyValue] |= 0x80;
00236 }
00237 else
00238 {
00239 _VKKeyState[keyValue] &= ~0x80;
00240 }
00241
00242 switch (keyValue)
00243 {
00244 case KeyLSHIFT: charValue = KeySHIFT; break;
00245 case KeyRSHIFT: charValue = KeySHIFT; break;
00246 case KeyLCONTROL: charValue = KeyCONTROL; break;
00247 case KeyRCONTROL: charValue = KeyCONTROL; break;
00248 case KeyLMENU: charValue = KeyMENU; break;
00249 case KeyRMENU: charValue = KeyMENU; break;
00250 default: charValue = keyValue; break;
00251 }
00252
00253 if (charValue == KeySHIFT && !_CapsLockToggle)
00254 {
00255 if (_VKKeyState[KeyCAPITAL] & 0x01)
00256 {
00257 _VKKeyState[KeyCAPITAL] &= ~0x01;
00258
00259 }
00260 }
00261
00262 if (charValue != keyValue)
00263 {
00264 _VKKeyState[charValue] = _VKKeyState[keyValue];
00265 }
00266
00267 updateCtrlAltShiftValues();
00268 }
00269
00271 void CDIKeyboard::updateCtrlAltShiftValues()
00272 {
00273 ShiftPressed = (_VKKeyState[KeySHIFT] & 0x80) != 0;
00274 CtrlPressed = (_VKKeyState[KeyCONTROL] & 0x80) != 0;
00275 AltPressed = (_VKKeyState[KeyMENU] & 0x80) != 0;
00276 }
00277
00279 CDIKeyboard::~CDIKeyboard()
00280 {
00281 if (_Keyboard)
00282 {
00283 _Keyboard->Unacquire();
00284 _Keyboard->Release();
00285 }
00286 }
00287
00289 CDIKeyboard *CDIKeyboard::createKeyboardDevice(IDirectInput8 *di8,
00290 HWND hwnd,
00291 CDIEventEmitter *diEventEmitter,
00292 CWinEventEmitter *we
00293 ) throw(EDirectInput)
00294 {
00295 std::auto_ptr<CDIKeyboard> kb(new CDIKeyboard(we, hwnd));
00296 kb->_DIEventEmitter = diEventEmitter;
00297 HRESULT result = di8->CreateDevice(GUID_SysKeyboard, &kb->_Keyboard, NULL);
00298 if (result != DI_OK) throw EDirectInputNoKeyboard();
00299 result = kb->_Keyboard->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
00300 if (result != DI_OK) throw EDirectInputCooperativeLevelFailed();
00301 result = kb->_Keyboard->SetDataFormat(&c_dfDIKeyboard);
00302 kb->setBufferSize(16);
00303 kb->_Keyboard->Acquire();
00304 return kb.release();
00305 }
00306
00308 void CDIKeyboard::poll(CInputDeviceServer *dev)
00309 {
00310 nlassert(_Keyboard);
00311 nlassert(_KeyboardBufferSize > 0);
00312 static std::vector<DIDEVICEOBJECTDATA> datas;
00313 datas.resize(_KeyboardBufferSize);
00314 DWORD numElements = _KeyboardBufferSize;
00315 HRESULT result = _Keyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
00316 if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
00317 {
00318 result = _Keyboard->Acquire();
00319 if (result != DI_OK) return;
00320
00321 ::GetKeyboardState((unsigned char *) _VKKeyState);
00322 _LastDIKeyPressed = 0;
00323 updateCtrlAltShiftValues();
00324 result = _Keyboard->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
00325 if (result != DI_OK) return;
00326 }
00327 else if (result != DI_OK)
00328 {
00329 return;
00330 }
00331
00332 _PollTime = (uint32) CTime::getLocalTime();
00333
00334
00335
00336 for (uint k = 0; k < numElements; ++k)
00337 {
00338 CDIEvent *die = new CDIEvent;
00339 die->Emitter = this;
00340 die->Datas = datas[k];
00341 dev->submitEvent(die);
00342 }
00343 }
00344
00346 void CDIKeyboard::transitionOccured(CEventServer *server, const IInputDeviceEvent *nextMessage)
00347 {
00348 repeatKey(buildDateFromEvent(nextMessage), server);
00349 }
00350
00352 TKeyButton CDIKeyboard::buildKeyButtonsFlags() const
00353 {
00354 return (TKeyButton) ( (ShiftPressed ? shiftKeyButton : 0)
00355 | (CtrlPressed ? altKeyButton : 0)
00356 | (AltPressed ? ctrlKeyButton : 0)
00357 );
00358 }
00359
00361 void CDIKeyboard::keyTriggered(bool pressed, uint dikey, CEventServer *server, uint32 date)
00362 {
00363 #if 0
00364 const uint numPairs = sizeof(DIToNel) / sizeof(CKeyConv);
00365 for (uint k = 0; k < numPairs; ++k)
00366 {
00367 if (DIToNel[k].DIKey == key)
00368 {
00369 nlinfo(DIToNel[k].KeyName);
00370 }
00371 }
00372 #endif
00373
00374
00375 TKey keyValue, charValue;
00376 updateVKKeyState(dikey, pressed, keyValue, charValue);
00377 if (keyValue == 0) return;
00378
00379 CEventKey *ek;
00380 if (pressed ) ek = new CEventKeyDown(keyValue, buildKeyButtonsFlags(), false, _DIEventEmitter);
00381 else ek = new CEventKeyUp(keyValue, buildKeyButtonsFlags(), _DIEventEmitter);
00382 server->postEvent(ek);
00383
00384 if (pressed)
00385 {
00386 if (_RepetitionDisabled[(uint) keyValue] == false)
00387 {
00388 _LastEmitDate = _FirstPressDate = date;
00389 _LastDIKeyPressed = dikey;
00390 }
00391 else
00392 {
00393 _LastDIKeyPressed = 0;
00394 return;
00395 }
00396 }
00397 else
00398 {
00399
00400 if (dikey == _LastDIKeyPressed)
00401 {
00402 _LastDIKeyPressed = 0;
00403 }
00404
00405 if (_RepetitionDisabled[(uint) keyValue] == true)
00406 {
00407 return;
00408 }
00409 }
00410
00411
00412 if (keyValue >= KeyNUMPAD0 && keyValue <= KeyNUMPAD9 || keyValue == KeyDECIMAL)
00413 {
00414 if ((_VKKeyState[KeyNUMLOCK] & 0x01) != 0)
00415 {
00416 sendUnicode(charValue, dikey, server, pressed);
00417 }
00418 }
00419 else
00420 {
00421 sendUnicode(charValue, dikey, server, pressed);
00422 }
00423
00424 _FirstPressDate = date;
00425 }
00426
00428 void CDIKeyboard::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
00429 {
00430 CDIEvent *die = safe_cast<CDIEvent *>(deviceEvent);
00431 bool pressed = (die->Datas.dwData & 0x80) != 0;
00432 keyTriggered(pressed, (uint) die->Datas.dwOfs, server, die->Datas.dwTimeStamp);
00433 }
00434
00436 TMouseButton CDIKeyboard::buildKeyboardButtonFlags() const
00437 {
00438 nlassert(_Keyboard);
00439 return _DIEventEmitter->buildKeyboardButtonFlags();
00440 }
00441
00443 bool CDIKeyboard::setBufferSize(uint size)
00444 {
00445 nlassert(size > 0);
00446 nlassert(_Keyboard);
00447 _Keyboard->Unacquire();
00448 DIPROPDWORD dipdw;
00449 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
00450 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
00451 dipdw.diph.dwObj = 0;
00452 dipdw.diph.dwHow = DIPH_DEVICE;
00453 dipdw.dwData = size;
00454 HRESULT r = _Keyboard->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph );
00455 if (r != DI_OK) return false;
00456 _KeyboardBufferSize = size;
00457 return true;
00458 }
00459
00461 uint CDIKeyboard::getBufferSize() const
00462 {
00463 return _KeyboardBufferSize;
00464 }
00465
00467 TKey CDIKeyboard::DIKeyToNelKey(uint diKey, bool &extKey, bool &repeatable)
00468 {
00469
00470 static tableBuilt = false;
00471
00472 if (!tableBuilt)
00473 {
00474 uint k;
00475 for (k = 0; k < NumKeys; ++k)
00476 {
00477 DIKeyToNelKeyTab[k] = NULL;
00478 }
00479 const uint numPairs = sizeof(DIToNel) / sizeof(CKeyConv);
00480 for (k = 0; k < numPairs; ++k)
00481 {
00482 DIKeyToNelKeyTab[DIToNel[k].DIKey] = &DIToNel[k];
00483 }
00484 tableBuilt = true;
00485 }
00486
00487
00488
00489 if (DIKeyToNelKeyTab[diKey] != NULL)
00490 {
00491 const CKeyConv &keyConv = *DIKeyToNelKeyTab[diKey];
00492 extKey = true;
00493 repeatable = keyConv.Repeatable;
00494 return keyConv.NelKey;
00495 }
00496
00497
00498
00499
00500 TKey key = (TKey) ::MapVirtualKeyEx(diKey, 1, _KBLayout);
00501 extKey = false;
00502 return key;
00503 }
00504
00506 void CDIKeyboard::sendUnicode(TKey vkey, uint dikey, CEventServer *server, bool pressed)
00507 {
00508 const uint maxNumKeys = 8;
00509 WCHAR keyUnicodes[maxNumKeys];
00510 uint8 oldShift = _VKKeyState[KeySHIFT];
00512 if (!_CapsLockToggle && _VKKeyState[KeyCAPITAL] & 0x01)
00513 {
00514 _VKKeyState[KeySHIFT] = 0;
00515 }
00516
00517 int res = ::ToUnicodeEx(vkey, dikey | (pressed ? 0 : (1 << 15)), (unsigned char *) _VKKeyState, keyUnicodes, maxNumKeys, 0, _KBLayout);
00518
00519 _VKKeyState[KeySHIFT] = oldShift;
00520
00521 for (sint k = 0; k < res; ++k)
00522 {
00523 CEventChar *evc = new CEventChar((ucchar) keyUnicodes[k], buildKeyButtonsFlags(), _DIEventEmitter);
00524 server->postEvent(evc);
00525 }
00526 }
00527
00529 void CDIKeyboard::repeatKey(uint32 currentDate, CEventServer *server)
00530 {
00531 if (_LastDIKeyPressed == 0 || _LastDIKeyPressed == DIK_INSERT) return;
00532 bool extKey;
00533 bool repeatable;
00534 TKey vkey = DIKeyToNelKey(_LastDIKeyPressed, extKey, repeatable);
00535 if (vkey == 0) return;
00536 if (currentDate - _FirstPressDate < _RepeatDelay) return;
00537
00538 sint32 firstDate = _LastEmitDate - (_FirstPressDate + _RepeatDelay);
00539 sint32 lastDate = currentDate - (_FirstPressDate + _RepeatDelay);
00540 if (firstDate < 0) firstDate = 0;
00541
00542 if (lastDate < firstDate) return;
00543
00544 uint numRep = (uint) ((lastDate + _RepeatPeriod - 1) / _RepeatPeriod - (firstDate + _RepeatPeriod - 1) / _RepeatPeriod);
00545 numRep = std::min(16u, numRep);
00546 if ((sint) numRep < 0) return;
00547
00548
00549
00550 if (vkey >= KeyNUMPAD0 && vkey <= KeyNUMPAD9 || vkey == KeyDECIMAL)
00551 {
00552
00553 if ((_VKKeyState[KeyNUMLOCK] & 0x01) != 0)
00554 {
00555 for (uint k = 0; k < numRep; ++k)
00556 {
00557 sendUnicode(vkey, _LastDIKeyPressed, server, true);
00558 }
00559 }
00560 else
00561 {
00562
00563 for (uint k = 0; k < numRep; ++k)
00564 {
00565 CEventKey *ek = new CEventKeyDown(vkey, buildKeyButtonsFlags(), true, _DIEventEmitter);
00566 server->postEvent(ek);
00567 }
00568 }
00569 }
00570 else
00571 {
00572 for (uint k = 0; k < numRep; ++k)
00573 {
00574
00575 if (extKey && repeatable)
00576 {
00577 CEventKey *ek = new CEventKeyDown(vkey, buildKeyButtonsFlags(), true, _DIEventEmitter);
00578 server->postEvent(ek);
00579 }
00580 else
00581 {
00582 sendUnicode(vkey, _LastDIKeyPressed, server, true);
00583 }
00584 }
00585 }
00586
00587 _LastEmitDate = currentDate;
00588 }
00589
00591 uint32 CDIKeyboard::buildDateFromEvent(const IInputDeviceEvent *deviceEvent)
00592 {
00593 if (deviceEvent)
00594 {
00595 const CDIEvent *die = safe_cast<const CDIEvent *>(deviceEvent);
00596 return (uint32) die->Datas.dwData;
00597 }
00598 else
00599 {
00600 return _PollTime;
00601 }
00602 }
00603
00605 void CDIKeyboard::disableRepetition(const TKey *keyTab, uint numKey)
00606 {
00607 _RepetitionDisabled.clearAll();
00608 for (uint k = 0; k < numKey; ++k)
00609 {
00610 _RepetitionDisabled.set((sint) keyTab[k]);
00611 }
00612
00613 if (_LastDIKeyPressed != 0)
00614 {
00615 bool extKey;
00616 bool repeatable;
00617 TKey key = DIKeyToNelKey(_LastDIKeyPressed, extKey, repeatable);
00618 if (_RepetitionDisabled[(uint) key])
00619 {
00620
00621 _LastDIKeyPressed = 0;
00622 }
00623 }
00624 }
00625
00627 uint CDIKeyboard::getNumDisabledRepetition() const
00628 {
00629 uint numKey = 0;
00630 for (uint k = 0; k < NumKeys; ++k)
00631 {
00632 if (_RepetitionDisabled[k]) ++numKey;
00633 }
00634 return numKey;
00635 }
00636
00638 void CDIKeyboard::getDisabledRepetitions(TKey *destTab) const
00639 {
00640 for (uint k = 0; k < NumKeys; ++k)
00641 {
00642 if (_RepetitionDisabled[k]) *destTab++ = (TKey) k;
00643 }
00644 }
00645
00646
00647
00648 }
00649
00650
00651 #endif NL_OS_WINDOWS