1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\r
8 #include "errormessage.h"
\r
11 #include "windowstool.h"
\r
15 #include <process.h>
\r
18 // check focus window
\r
19 void Engine::checkFocusWindow()
\r
26 HWND hwndFore = GetForegroundWindow();
\r
27 DWORD threadId = GetWindowThreadProcessId(hwndFore, NULL);
\r
32 if (m_currentFocusOfThread &&
\r
33 m_currentFocusOfThread->m_threadId == threadId &&
\r
34 m_currentFocusOfThread->m_hwndFocus == m_hwndFocus)
\r
37 m_emacsEditKillLine.reset();
\r
39 // erase dead thread
\r
40 if (!m_detachedThreadIds.empty()) {
\r
41 for (DetachedThreadIds::iterator i = m_detachedThreadIds.begin();
\r
42 i != m_detachedThreadIds.end(); i ++) {
\r
43 FocusOfThreads::iterator j = m_focusOfThreads.find((*i));
\r
44 if (j != m_focusOfThreads.end()) {
\r
45 FocusOfThread *fot = &((*j).second);
\r
46 Acquire a(&m_log, 1);
\r
47 m_log << _T("RemoveThread") << std::endl;
\r
48 m_log << _T("\tHWND:\t") << std::hex << (int)fot->m_hwndFocus
\r
49 << std::dec << std::endl;
\r
50 m_log << _T("\tTHREADID:") << fot->m_threadId << std::endl;
\r
51 m_log << _T("\tCLASS:\t") << fot->m_className << std::endl;
\r
52 m_log << _T("\tTITLE:\t") << fot->m_titleName << std::endl;
\r
54 m_focusOfThreads.erase(j);
\r
57 m_detachedThreadIds.erase
\r
58 (m_detachedThreadIds.begin(), m_detachedThreadIds.end());
\r
61 FocusOfThreads::iterator i = m_focusOfThreads.find(threadId);
\r
62 if (i != m_focusOfThreads.end()) {
\r
63 m_currentFocusOfThread = &((*i).second);
\r
64 if (!m_currentFocusOfThread->m_isConsole || 2 <= count) {
\r
65 if (m_currentFocusOfThread->m_keymaps.empty())
\r
66 setCurrentKeymap(NULL);
\r
68 setCurrentKeymap(*m_currentFocusOfThread->m_keymaps.begin());
\r
69 m_hwndFocus = m_currentFocusOfThread->m_hwndFocus;
\r
70 checkShow(m_hwndFocus);
\r
72 Acquire a(&m_log, 1);
\r
73 m_log << _T("FocusChanged") << std::endl;
\r
74 m_log << _T("\tHWND:\t")
\r
75 << std::hex << (int)m_currentFocusOfThread->m_hwndFocus
\r
76 << std::dec << std::endl;
\r
77 m_log << _T("\tTHREADID:")
\r
78 << m_currentFocusOfThread->m_threadId << std::endl;
\r
79 m_log << _T("\tCLASS:\t")
\r
80 << m_currentFocusOfThread->m_className << std::endl;
\r
81 m_log << _T("\tTITLE:\t")
\r
82 << m_currentFocusOfThread->m_titleName << std::endl;
\r
89 _TCHAR className[GANA_MAX_ATOM_LENGTH];
\r
90 if (GetClassName(hwndFore, className, NUMBER_OF(className))) {
\r
91 if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {
\r
92 _TCHAR titleName[1024];
\r
93 if (GetWindowText(hwndFore, titleName, NUMBER_OF(titleName)) == 0)
\r
94 titleName[0] = _T('\0');
\r
95 setFocus(hwndFore, threadId, className, titleName, true);
\r
96 Acquire a(&m_log, 1);
\r
97 m_log << _T("HWND:\t") << std::hex << reinterpret_cast<int>(hwndFore)
\r
98 << std::dec << std::endl;
\r
99 m_log << _T("THREADID:") << threadId << std::endl;
\r
100 m_log << _T("CLASS:\t") << className << std::endl;
\r
101 m_log << _T("TITLE:\t") << titleName << std::endl << std::endl;
\r
108 if (m_globalFocus.m_keymaps.empty()) {
\r
109 Acquire a(&m_log, 1);
\r
110 m_log << _T("NO GLOBAL FOCUS") << std::endl;
\r
111 m_currentFocusOfThread = NULL;
\r
112 setCurrentKeymap(NULL);
\r
114 if (m_currentFocusOfThread != &m_globalFocus) {
\r
115 Acquire a(&m_log, 1);
\r
116 m_log << _T("GLOBAL FOCUS") << std::endl;
\r
117 m_currentFocusOfThread = &m_globalFocus;
\r
118 setCurrentKeymap(m_globalFocus.m_keymaps.front());
\r
121 m_hwndFocus = NULL;
\r
126 // is modifier pressed ?
\r
127 bool Engine::isPressed(Modifier::Type i_mt)
\r
129 const Keymap::ModAssignments &ma = m_currentKeymap->getModAssignments(i_mt);
\r
130 for (Keymap::ModAssignments::const_iterator i = ma.begin();
\r
131 i != ma.end(); ++ i)
\r
132 if ((*i).m_key->m_isPressed)
\r
138 // fix modifier key (if fixed, return true)
\r
139 bool Engine::fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am)
\r
141 // for all modifier ...
\r
142 for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {
\r
143 // get modifier assignments (list of modifier keys)
\r
144 const Keymap::ModAssignments &ma =
\r
145 m_currentKeymap->getModAssignments(static_cast<Modifier::Type>(i));
\r
147 for (Keymap::ModAssignments::const_iterator
\r
148 j = ma.begin(); j != ma.end(); ++ j)
\r
149 if (io_mkey->m_key == (*j).m_key) { // is io_mkey a modifier ?
\r
151 Acquire a(&m_log, 1);
\r
152 m_log << _T("* Modifier Key") << std::endl;
\r
154 // set dontcare for this modifier
\r
155 io_mkey->m_modifier.dontcare(static_cast<Modifier::Type>(i));
\r
156 *o_am = (*j).m_assignMode;
\r
160 *o_am = Keymap::AM_notModifier;
\r
166 void Engine::outputToLog(const Key *i_key, const ModifiedKey &i_mkey,
\r
170 Acquire a(&m_log, i_debugLevel);
\r
172 // output scan codes
\r
173 for (i = 0; i < i_key->getScanCodesSize(); ++ i) {
\r
174 if (i_key->getScanCodes()[i].m_flags & ScanCode::E0) m_log << _T("E0-");
\r
175 if (i_key->getScanCodes()[i].m_flags & ScanCode::E1) m_log << _T("E1-");
\r
176 if (!(i_key->getScanCodes()[i].m_flags & ScanCode::E0E1))
\r
178 m_log << _T("0x") << std::hex << std::setw(2) << std::setfill(_T('0'))
\r
179 << static_cast<int>(i_key->getScanCodes()[i].m_scan)
\r
180 << std::dec << _T(" ");
\r
183 if (!i_mkey.m_key) { // key corresponds to no phisical key
\r
184 m_log << std::endl;
\r
188 m_log << _T(" ") << i_mkey << std::endl;
\r
192 // describe bindings
\r
193 void Engine::describeBindings()
\r
195 Acquire a(&m_log, 0);
\r
197 Keymap::DescribeParam dp;
\r
198 for (KeymapPtrList::iterator i = m_currentFocusOfThread->m_keymaps.begin();
\r
199 i != m_currentFocusOfThread->m_keymaps.end(); ++ i)
\r
200 (*i)->describe(m_log, &dp);
\r
201 m_log << std::endl;
\r
205 // update m_lastPressedKey
\r
206 void Engine::updateLastPressedKey(Key *i_key)
\r
208 m_lastPressedKey[1] = m_lastPressedKey[0];
\r
209 m_lastPressedKey[0] = i_key;
\r
212 // set current keymap
\r
213 void Engine::setCurrentKeymap(const Keymap *i_keymap, bool i_doesAddToHistory)
\r
215 if (i_doesAddToHistory) {
\r
216 m_keymapPrefixHistory.push_back(const_cast<Keymap *>(m_currentKeymap));
\r
217 if (MAX_KEYMAP_PREFIX_HISTORY < m_keymapPrefixHistory.size())
\r
218 m_keymapPrefixHistory.pop_front();
\r
220 m_keymapPrefixHistory.clear();
\r
221 m_currentKeymap = i_keymap;
\r
225 // get current modifiers
\r
226 Modifier Engine::getCurrentModifiers(Key *i_key, bool i_isPressed)
\r
229 cmods.add(m_currentLock);
\r
231 cmods.press(Modifier::Type_Shift , isPressed(Modifier::Type_Shift ));
\r
232 cmods.press(Modifier::Type_Alt , isPressed(Modifier::Type_Alt ));
\r
233 cmods.press(Modifier::Type_Control, isPressed(Modifier::Type_Control));
\r
234 cmods.press(Modifier::Type_Windows, isPressed(Modifier::Type_Windows));
\r
235 cmods.press(Modifier::Type_Up , !i_isPressed);
\r
236 cmods.press(Modifier::Type_Down , i_isPressed);
\r
238 cmods.press(Modifier::Type_Repeat , false);
\r
239 if (m_lastPressedKey[0] == i_key) {
\r
241 cmods.press(Modifier::Type_Repeat, true);
\r
243 if (m_lastPressedKey[1] == i_key)
\r
244 cmods.press(Modifier::Type_Repeat, true);
\r
247 for (int i = Modifier::Type_Mod0; i <= Modifier::Type_Mod9; ++ i)
\r
248 cmods.press(static_cast<Modifier::Type>(i),
\r
249 isPressed(static_cast<Modifier::Type>(i)));
\r
255 // generate keyboard event for a key
\r
256 void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)
\r
258 // check if key is event
\r
259 bool isEvent = false;
\r
260 for (Key **e = Event::events; *e; ++ e)
\r
266 bool isAlreadyReleased = false;
\r
269 if (i_doPress && !i_key->m_isPressedOnWin32)
\r
270 ++ m_currentKeyPressCountOnWin32;
\r
271 else if (!i_doPress) {
\r
272 if (i_key->m_isPressedOnWin32)
\r
273 -- m_currentKeyPressCountOnWin32;
\r
275 isAlreadyReleased = true;
\r
277 i_key->m_isPressedOnWin32 = i_doPress;
\r
280 i_key->m_isPressedByAssign = i_doPress;
\r
282 Key *sync = m_setting->m_keyboard.getSyncKey();
\r
284 if (!isAlreadyReleased || i_key == sync) {
\r
285 KEYBOARD_INPUT_DATA kid = { 0, 0, 0, 0, 0 };
\r
286 const ScanCode *sc = i_key->getScanCodes();
\r
287 for (size_t i = 0; i < i_key->getScanCodesSize(); ++ i) {
\r
288 kid.MakeCode = sc[i].m_scan;
\r
289 kid.Flags = sc[i].m_flags;
\r
291 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
293 injectInput(&kid, NULL);
\r
294 #else // !NO_DRIVER
\r
296 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
\r
297 CHECK_TRUE( GetOverlappedResult(m_device, &m_ol, &len, TRUE) );
\r
298 #endif // !NO_DRIVER
\r
301 m_lastGeneratedKey = i_doPress ? i_key : NULL;
\r
306 Acquire a(&m_log, 1);
\r
307 m_log << _T("\t\t =>\t");
\r
308 if (isAlreadyReleased)
\r
309 m_log << _T("(already released) ");
\r
311 ModifiedKey mkey(i_key);
\r
312 mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);
\r
313 mkey.m_modifier.on(Modifier::Type_Down, i_doPress);
\r
314 outputToLog(i_key, mkey, 1);
\r
319 void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)
\r
322 i_c.m_keymap = i_keymap;
\r
323 i_c.m_mkey.m_key = i_event;
\r
324 if (const Keymap::KeyAssignment *keyAssign =
\r
325 i_c.m_keymap->searchAssignment(i_c.m_mkey)) {
\r
327 Acquire a(&m_log, 1);
\r
328 m_log << std::endl << _T(" ")
\r
329 << i_event->getName() << std::endl;
\r
331 generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);
\r
336 // genete modifier events
\r
337 void Engine::generateModifierEvents(const Modifier &i_mod)
\r
340 Acquire a(&m_log, 1);
\r
341 m_log << _T("* Gen Modifiers\t{") << std::endl;
\r
344 for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i) {
\r
345 Keyboard::Mods &mods =
\r
346 m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));
\r
348 if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))
\r
349 // no need to process
\r
351 else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))
\r
352 // we have to press this modifier
\r
354 bool noneIsPressed = true;
\r
355 bool noneIsPressedByAssign = true;
\r
356 for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i) {
\r
357 if ((*i)->m_isPressedOnWin32)
\r
358 noneIsPressed = false;
\r
359 if ((*i)->m_isPressedByAssign)
\r
360 noneIsPressedByAssign = false;
\r
362 if (noneIsPressed) {
\r
363 if (noneIsPressedByAssign)
\r
364 generateKeyEvent(mods.front(), true, false);
\r
366 for (Keyboard::Mods::iterator
\r
367 i = mods.begin(); i != mods.end(); ++ i)
\r
368 if ((*i)->m_isPressedByAssign)
\r
369 generateKeyEvent((*i), true, false);
\r
374 // we have to release this modifier
\r
376 // avoid such sequences as "Alt U-ALt" or "Windows U-Windows"
\r
377 if (i == Modifier::Type_Alt || i == Modifier::Type_Windows) {
\r
378 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)
\r
379 if ((*j) == m_lastGeneratedKey) {
\r
380 Keyboard::Mods *mods =
\r
381 &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);
\r
382 if (mods->size() == 0)
\r
383 mods = &m_setting->m_keyboard.getModifiers(
\r
384 Modifier::Type_Control);
\r
385 if (0 < mods->size()) {
\r
386 generateKeyEvent(mods->front(), true, false);
\r
387 generateKeyEvent(mods->front(), false, false);
\r
393 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j) {
\r
394 if ((*j)->m_isPressedOnWin32)
\r
395 generateKeyEvent((*j), false, false);
\r
401 Acquire a(&m_log, 1);
\r
402 m_log << _T("\t\t}") << std::endl;
\r
407 // generate keyboard events for action
\r
408 void Engine::generateActionEvents(const Current &i_c, const Action *i_a,
\r
411 switch (i_a->getType()) {
\r
413 case Action::Type_key: {
\r
414 const ModifiedKey &mkey
\r
415 = reinterpret_cast<ActionKey *>(
\r
416 const_cast<Action *>(i_a))->m_modifiedKey;
\r
420 (mkey.m_modifier.isOn(Modifier::Type_Up) ||
\r
421 mkey.m_modifier.isDontcare(Modifier::Type_Up)))
\r
422 generateKeyEvent(mkey.m_key, false, true);
\r
425 else if (i_doPress &&
\r
426 (mkey.m_modifier.isOn(Modifier::Type_Down) ||
\r
427 mkey.m_modifier.isDontcare(Modifier::Type_Down))) {
\r
428 Modifier modifier = mkey.m_modifier;
\r
429 modifier.add(i_c.m_mkey.m_modifier);
\r
430 generateModifierEvents(modifier);
\r
431 generateKeyEvent(mkey.m_key, true, true);
\r
437 case Action::Type_keySeq: {
\r
438 const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);
\r
439 generateKeySeqEvents(i_c, aks->m_keySeq,
\r
440 i_doPress ? Part_down : Part_up);
\r
445 case Action::Type_function: {
\r
446 const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);
\r
447 bool is_up = (!i_doPress &&
\r
448 (af->m_modifier.isOn(Modifier::Type_Up) ||
\r
449 af->m_modifier.isDontcare(Modifier::Type_Up)));
\r
450 bool is_down = (i_doPress &&
\r
451 (af->m_modifier.isOn(Modifier::Type_Down) ||
\r
452 af->m_modifier.isDontcare(Modifier::Type_Down)));
\r
454 if (!is_down && !is_up)
\r
458 Acquire a(&m_log, 1);
\r
459 m_log << _T("\t\t >\t") << af->m_functionData;
\r
462 FunctionParam param;
\r
463 param.m_isPressed = i_doPress;
\r
464 param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;
\r
466 param.m_doesNeedEndl = true;
\r
469 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);
\r
470 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);
\r
472 af->m_functionData->exec(this, ¶m);
\r
474 if (param.m_doesNeedEndl) {
\r
475 Acquire a(&m_log, 1);
\r
476 m_log << std::endl;
\r
484 // generate keyboard events for keySeq
\r
485 void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,
\r
488 const KeySeq::Actions &actions = i_keySeq->getActions();
\r
489 if (actions.empty())
\r
491 if (i_part == Part_up)
\r
492 generateActionEvents(i_c, actions[actions.size() - 1], false);
\r
495 for (i = 0 ; i < actions.size() - 1; ++ i) {
\r
496 generateActionEvents(i_c, actions[i], true);
\r
497 generateActionEvents(i_c, actions[i], false);
\r
499 generateActionEvents(i_c, actions[i], true);
\r
500 if (i_part == Part_all)
\r
501 generateActionEvents(i_c, actions[i], false);
\r
506 // generate keyboard events for current key
\r
507 void Engine::generateKeyboardEvents(const Current &i_c)
\r
509 if (++ m_generateKeyboardEventsRecursionGuard ==
\r
510 MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT) {
\r
512 m_log << _T("error: too deep keymap recursion. there may be a loop.")
\r
517 const Keymap::KeyAssignment *keyAssign
\r
518 = i_c.m_keymap->searchAssignment(i_c.m_mkey);
\r
520 const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();
\r
522 generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);
\r
524 if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||
\r
525 keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))
\r
526 generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);
\r
528 generateKeySeqEvents(i_c, keyAssign->m_keySeq,
\r
529 i_c.isPressed() ? Part_down : Part_up);
\r
531 m_generateKeyboardEventsRecursionGuard --;
\r
535 // generate keyboard events for current key
\r
536 void Engine::beginGeneratingKeyboardEvents(
\r
537 const Current &i_c, bool i_isModifier)
\r
539 // (1) (2) (3) (4) (1)
\r
540 // up/down: D- U- D- U- D-
\r
541 // keymap: m_currentKeymap m_currentKeymap X X m_currentKeymap
\r
542 // memo: &Prefix(X) ... ... ... ...
\r
543 // m_isPrefix: false true true false false
\r
547 bool isPhysicallyPressed
\r
548 = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);
\r
551 ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);
\r
553 cnew.m_mkey = mkey;
\r
554 if (isPhysicallyPressed) {
\r
555 cnew.m_mkey.m_modifier.off(Modifier::Type_Up);
\r
556 cnew.m_mkey.m_modifier.on(Modifier::Type_Down);
\r
558 cnew.m_mkey.m_modifier.on(Modifier::Type_Up);
\r
559 cnew.m_mkey.m_modifier.off(Modifier::Type_Down);
\r
561 for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {
\r
562 Modifier::Type type = static_cast<Modifier::Type>(i);
\r
563 if (cnew.m_mkey.m_modifier.isDontcare(type) &&
\r
564 !i_c.m_mkey.m_modifier.isDontcare(type))
\r
565 cnew.m_mkey.m_modifier.press(
\r
566 type, i_c.m_mkey.m_modifier.isPressed(type));
\r
570 Acquire a(&m_log, 1);
\r
571 m_log << _T("* substitute") << std::endl;
\r
573 outputToLog(mkey.m_key, cnew.m_mkey, 1);
\r
577 const Keymap *tmpKeymap = m_currentKeymap;
\r
578 if (i_isModifier || !m_isPrefix) ;
\r
579 else if (isPhysicallyPressed) // when (3)
\r
580 m_isPrefix = false;
\r
581 else if (!isPhysicallyPressed) // when (2)
\r
582 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();
\r
584 // for m_emacsEditKillLine function
\r
585 m_emacsEditKillLine.m_doForceReset = !i_isModifier;
\r
587 // generate key event !
\r
588 m_generateKeyboardEventsRecursionGuard = 0;
\r
589 if (isPhysicallyPressed)
\r
590 generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);
\r
591 generateKeyboardEvents(cnew);
\r
592 if (!isPhysicallyPressed)
\r
593 generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);
\r
595 // for m_emacsEditKillLine function
\r
596 if (m_emacsEditKillLine.m_doForceReset)
\r
597 m_emacsEditKillLine.reset();
\r
602 else if (!m_isPrefix) // when (1), (4)
\r
603 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();
\r
604 else if (!isPhysicallyPressed) // when (2)
\r
605 m_currentKeymap = tmpKeymap;
\r
610 unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)
\r
612 if (i_kid->Flags & KEYBOARD_INPUT_DATA::E1) {
\r
616 kid[0].type = INPUT_MOUSE;
\r
619 kid[0].mi.time = 0;
\r
620 kid[0].mi.mouseData = 0;
\r
621 kid[0].mi.dwExtraInfo = 0;
\r
622 switch (i_kid->MakeCode) {
\r
624 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
625 kid[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
\r
627 kid[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
\r
631 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
632 kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;
\r
634 kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
\r
638 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
639 kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
\r
641 kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
\r
645 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
648 kid[0].mi.mouseData = WHEEL_DELTA;
\r
649 kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;
\r
653 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
656 kid[0].mi.mouseData = -WHEEL_DELTA;
\r
657 kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;
\r
661 kid[0].mi.mouseData = XBUTTON1;
\r
662 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
663 kid[0].mi.dwFlags = MOUSEEVENTF_XUP;
\r
665 kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;
\r
669 kid[0].mi.mouseData = XBUTTON2;
\r
670 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
671 kid[0].mi.dwFlags = MOUSEEVENTF_XUP;
\r
673 kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;
\r
677 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
680 kid[0].mi.mouseData = WHEEL_DELTA;
\r
681 kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;
\r
685 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
688 kid[0].mi.mouseData = -WHEEL_DELTA;
\r
689 kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;
\r
696 if (!(i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) &&
\r
697 i_kid->MakeCode != 4 && i_kid->MakeCode != 5 &&
\r
698 i_kid->MakeCode != 8 && i_kid->MakeCode != 9) {
\r
702 if (GetCursorPos(&pt) && (hwnd = WindowFromPoint(pt))) {
\r
703 _TCHAR className[GANA_MAX_ATOM_LENGTH];
\r
704 if (GetClassName(hwnd, className, NUMBER_OF(className))) {
\r
705 if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {
\r
706 SetForegroundWindow(hwnd);
\r
711 kid[0].mi.dx = 65535 * m_msllHookCurrent.pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
712 kid[0].mi.dy = 65535 * m_msllHookCurrent.pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
713 kid[0].mi.dwFlags |= MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
\r
715 kid[1].type = INPUT_MOUSE;
\r
716 kid[1].mi.dx = 65535 * pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);
\r
717 kid[1].mi.dy = 65535 * pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);
\r
718 kid[1].mi.time = 0;
\r
719 kid[1].mi.mouseData = 0;
\r
720 kid[1].mi.dwExtraInfo = 0;
\r
721 kid[1].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;
\r
726 SendInput(count, &kid[0], sizeof(kid[0]));
\r
730 kid.type = INPUT_KEYBOARD;
\r
732 kid.ki.wScan = i_kid->MakeCode;
\r
733 kid.ki.dwFlags = KEYEVENTF_SCANCODE;
\r
734 kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;
\r
735 kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;
\r
736 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
737 kid.ki.dwFlags |= KEYEVENTF_KEYUP;
\r
739 if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0) {
\r
740 kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
\r
742 SendInput(1, &kid, sizeof(kid));
\r
746 #endif // NO_DRIVER
\r
749 // pop all pressed key on win32
\r
750 void Engine::keyboardResetOnWin32()
\r
752 for (Keyboard::KeyIterator
\r
753 i = m_setting->m_keyboard.getKeyIterator(); *i; ++ i) {
\r
754 if ((*i)->m_isPressedOnWin32)
\r
755 generateKeyEvent((*i), false, true);
\r
761 unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)
\r
763 return i_this->keyboardDetour(reinterpret_cast<KBDLLHOOKSTRUCT*>(i_lParam));
\r
766 unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)
\r
769 Acquire a(&m_log, 1);
\r
771 << _T("keyboardDetour: vkCode=") << i_kid->vkCode
\r
772 << _T(" scanCode=") << i_kid->scanCode
\r
773 << _T(" flags=") << i_kid->flags << std::endl;
\r
775 if (i_kid->flags & LLKHF_INJECTED) {
\r
779 KEYBOARD_INPUT_DATA kid;
\r
782 kid.MakeCode = i_kid->scanCode;
\r
784 if (i_kid->flags & LLKHF_UP) {
\r
785 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
787 if (i_kid->flags & LLKHF_EXTENDED) {
\r
788 kid.Flags |= KEYBOARD_INPUT_DATA::E0;
\r
791 kid.ExtraInformation = 0;
\r
793 Acquire a(&m_cskidq);
\r
794 m_kidq.push_back(kid);
\r
795 SetEvent(m_readEvent);
\r
800 unsigned int WINAPI Engine::mouseDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)
\r
802 return i_this->mouseDetour(i_wParam, reinterpret_cast<MSLLHOOKSTRUCT*>(i_lParam));
\r
805 unsigned int Engine::mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid)
\r
807 if (i_mid->flags & LLMHF_INJECTED || !m_setting || !m_setting->m_mouseEvent) {
\r
810 KEYBOARD_INPUT_DATA kid;
\r
813 kid.Flags = KEYBOARD_INPUT_DATA::E1;
\r
815 kid.ExtraInformation = 0;
\r
816 switch (i_message) {
\r
818 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
819 case WM_LBUTTONDOWN:
\r
823 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
824 case WM_RBUTTONDOWN:
\r
828 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
829 case WM_MBUTTONDOWN:
\r
832 case WM_MOUSEWHEEL:
\r
833 if (i_mid->mouseData & (1<<31)) {
\r
840 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
841 case WM_XBUTTONDOWN:
\r
842 switch ((i_mid->mouseData >> 16) & 0xFFFFU) {
\r
854 case WM_MOUSEHWHEEL:
\r
855 if (i_mid->mouseData & (1<<31)) {
\r
861 case WM_MOUSEMOVE: {
\r
862 LONG dx = i_mid->pt.x - g_hookData->m_mousePos.x;
\r
863 LONG dy = i_mid->pt.y - g_hookData->m_mousePos.y;
\r
864 HWND target = reinterpret_cast<HWND>(g_hookData->m_hwndMouseHookTarget);
\r
867 dr += (i_mid->pt.x - m_msllHookCurrent.pt.x) * (i_mid->pt.x - m_msllHookCurrent.pt.x);
\r
868 dr += (i_mid->pt.y - m_msllHookCurrent.pt.y) * (i_mid->pt.y - m_msllHookCurrent.pt.y);
\r
869 if (m_buttonPressed && !m_dragging && m_setting->m_dragThreshold &&
\r
870 (m_setting->m_dragThreshold * m_setting->m_dragThreshold < dr)) {
\r
871 Acquire a(&m_cskidq);
\r
875 m_kidq.push_back(kid);
\r
876 SetEvent(m_readEvent);
\r
879 switch (g_hookData->m_mouseHookType) {
\r
880 case MouseHookType_Wheel:
\r
881 // For this type, g_hookData->m_mouseHookParam means
\r
882 // translate rate mouse move to wheel.
\r
883 mouse_event(MOUSEEVENTF_WHEEL, 0, 0,
\r
884 g_hookData->m_mouseHookParam * dy, 0);
\r
887 case MouseHookType_WindowMove: {
\r
890 if (!GetWindowRect(target, &curRect))
\r
893 // g_hookData->m_mouseHookParam < 0 means
\r
894 // target window to move is MDI.
\r
895 if (g_hookData->m_mouseHookParam < 0) {
\r
896 HWND parent = GetParent(target);
\r
897 POINT p = {curRect.left, curRect.top};
\r
899 if (parent == NULL || !ScreenToClient(parent, &p))
\r
902 curRect.left = p.x;
\r
906 SetWindowPos(target, NULL,
\r
910 SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE |
\r
911 SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
\r
912 g_hookData->m_mousePos = i_mid->pt;
\r
916 case MouseHookType_None:
\r
922 case WM_LBUTTONDBLCLK:
\r
923 case WM_RBUTTONDBLCLK:
\r
924 case WM_MBUTTONDBLCLK:
\r
925 case WM_XBUTTONDBLCLK:
\r
931 Acquire a(&m_cskidq);
\r
933 if (kid.Flags & KEYBOARD_INPUT_DATA::BREAK) {
\r
934 m_buttonPressed = false;
\r
936 KEYBOARD_INPUT_DATA kid2;
\r
938 m_dragging = false;
\r
940 kid2.Flags = KEYBOARD_INPUT_DATA::E1 | KEYBOARD_INPUT_DATA::BREAK;
\r
942 kid2.ExtraInformation = 0;
\r
944 m_kidq.push_back(kid2);
\r
945 SetEvent(m_readEvent);
\r
947 } else if (i_message != WM_MOUSEWHEEL && i_message != WM_MOUSEHWHEEL) {
\r
948 m_buttonPressed = true;
\r
949 m_msllHookCurrent = *i_mid;
\r
952 m_kidq.push_back(kid);
\r
953 SetEvent(m_readEvent);
\r
955 if (i_message == WM_MOUSEWHEEL || i_message == WM_MOUSEHWHEEL) {
\r
957 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
\r
959 kid.ExtraInformation = 0;
\r
960 m_kidq.push_back(kid);
\r
961 SetEvent(m_readEvent);
\r
967 #endif // NO_DRIVER
\r
969 // keyboard handler thread
\r
970 unsigned int WINAPI Engine::keyboardHandler(void *i_this)
\r
972 reinterpret_cast<Engine *>(i_this)->keyboardHandler();
\r
976 void Engine::keyboardHandler()
\r
979 CHECK_TRUE( SetEvent(m_threadEvent) );
\r
983 while (!m_doForceTerminate) {
\r
984 KEYBOARD_INPUT_DATA kid;
\r
988 #endif // !NO_DRIVER
\r
990 Acquire a(&m_log, 1);
\r
991 m_log << _T("begin ReadFile();") << std::endl;
\r
995 #else // !NO_DRIVER
\r
996 if (!ReadFile(m_device, &kid, sizeof(kid), &len, &m_ol)) {
\r
997 if (GetLastError() != ERROR_IO_PENDING)
\r
999 #endif // !NO_DRIVER
\r
1001 HANDLE handles[] = { m_readEvent, m_interruptThreadEvent };
\r
1003 switch (MsgWaitForMultipleObjects(NUMBER_OF(handles), &handles[0],
\r
1004 FALSE, INFINITE, QS_POSTMESSAGE)) {
\r
1005 case WAIT_OBJECT_0: // m_readEvent
\r
1008 Acquire a(&m_cskidq);
\r
1009 if (m_kidq.empty()) {
\r
1012 kid = m_kidq.front();
\r
1013 m_kidq.pop_front();
\r
1014 if (!m_kidq.empty()) {
\r
1015 SetEvent(m_readEvent);
\r
1018 #else // !NO_DRIVER
\r
1019 if (!GetOverlappedResult(m_device, &m_ol, &len, FALSE))
\r
1021 #endif // !NO_DRIVER
\r
1024 case WAIT_OBJECT_0 + 1: // m_interruptThreadEvent
\r
1025 CancelIo(m_device);
\r
1026 switch (m_interruptThreadReason) {
\r
1029 Acquire a(&m_log, 0);
\r
1030 m_log << _T("internal error: m_interruptThreadReason == ")
\r
1031 << m_interruptThreadReason << std::endl;
\r
1035 case InterruptThreadReason_Terminate:
\r
1038 case InterruptThreadReason_Pause: {
\r
1039 CHECK_TRUE( SetEvent(m_threadEvent) );
\r
1040 while (WaitForMultipleObjects(1, &m_interruptThreadEvent,
\r
1041 FALSE, INFINITE) != WAIT_OBJECT_0)
\r
1043 switch (m_interruptThreadReason) {
\r
1044 case InterruptThreadReason_Terminate:
\r
1047 case InterruptThreadReason_Resume:
\r
1054 CHECK_TRUE( SetEvent(m_threadEvent) );
\r
1060 case WAIT_OBJECT_0 + NUMBER_OF(handles): {
\r
1063 while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
\r
1064 switch (message.message) {
\r
1065 case WM_APP + 201: {
\r
1066 if (message.wParam) {
\r
1067 m_currentLock.on(Modifier::Type_Touchpad);
\r
1068 m_currentLock.on(Modifier::Type_TouchpadSticky);
\r
1070 m_currentLock.off(Modifier::Type_Touchpad);
\r
1071 Acquire a(&m_log, 1);
\r
1072 m_log << _T("touchpad: ") << message.wParam
\r
1073 << _T(".") << (message.lParam & 0xffff)
\r
1074 << _T(".") << (message.lParam >> 16 & 0xffff)
\r
1091 Acquire a(&m_log, 1);
\r
1092 m_log << _T("end ReadFile();") << std::endl;
\r
1095 checkFocusWindow();
\r
1097 if (!m_setting || // m_setting has not been loaded
\r
1098 !m_isEnabled) { // disabled
\r
1099 if (m_isLogMode) {
\r
1101 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));
\r
1102 outputToLog(&key, ModifiedKey(), 0);
\r
1103 if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {
\r
1104 // through mouse event even if log mode
\r
1105 injectInput(&kid, NULL);
\r
1109 injectInput(&kid, NULL);
\r
1110 #else // !NO_DRIVER
\r
1111 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
\r
1112 GetOverlappedResult(m_device, &m_ol, &len, TRUE);
\r
1113 #endif // !NO_DRIVER
\r
1115 updateLastPressedKey(NULL);
\r
1121 if (!m_currentFocusOfThread ||
\r
1122 !m_currentKeymap) {
\r
1124 injectInput(&kid, NULL);
\r
1126 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
\r
1127 GetOverlappedResult(m_device, &m_ol, &len, TRUE);
\r
1128 #endif // !NO_DRIVER
\r
1129 Acquire a(&m_log, 0);
\r
1130 if (!m_currentFocusOfThread)
\r
1131 m_log << _T("internal error: m_currentFocusOfThread == NULL")
\r
1133 if (!m_currentKeymap)
\r
1134 m_log << _T("internal error: m_currentKeymap == NULL")
\r
1136 updateLastPressedKey(NULL);
\r
1141 c.m_keymap = m_currentKeymap;
\r
1142 c.m_i = m_currentFocusOfThread->m_keymaps.begin();
\r
1145 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));
\r
1146 c.m_mkey = m_setting->m_keyboard.searchKey(key);
\r
1147 if (!c.m_mkey.m_key) {
\r
1148 c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);
\r
1149 if (c.m_mkey.m_key)
\r
1153 // press the key and update counter
\r
1154 bool isPhysicallyPressed
\r
1155 = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);
\r
1156 if (c.m_mkey.m_key) {
\r
1157 if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)
\r
1158 ++ m_currentKeyPressCount;
\r
1159 else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)
\r
1160 -- m_currentKeyPressCount;
\r
1161 c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;
\r
1164 // create modifiers
\r
1165 c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,
\r
1166 isPhysicallyPressed);
\r
1167 Keymap::AssignMode am;
\r
1168 bool isModifier = fixModifierKey(&c.m_mkey, &am);
\r
1170 if (isModifier && m_doesIgnoreModifierForPrefix)
\r
1171 am = Keymap::AM_true;
\r
1172 if (m_doesEditNextModifier) {
\r
1173 Modifier modifier = m_modifierForNextKey;
\r
1174 modifier.add(c.m_mkey.m_modifier);
\r
1175 c.m_mkey.m_modifier = modifier;
\r
1179 if (m_isLogMode) {
\r
1180 outputToLog(&key, c.m_mkey, 0);
\r
1181 if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {
\r
1182 // through mouse event even if log mode
\r
1183 injectInput(&kid, NULL);
\r
1185 } else if (am == Keymap::AM_true) {
\r
1187 Acquire a(&m_log, 1);
\r
1188 m_log << _T("* true modifier") << std::endl;
\r
1190 // true modifier doesn't generate scan code
\r
1191 outputToLog(&key, c.m_mkey, 1);
\r
1192 } else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable) {
\r
1194 Acquire a(&m_log, 1);
\r
1195 if (am == Keymap::AM_oneShot)
\r
1196 m_log << _T("* one shot modifier") << std::endl;
\r
1198 m_log << _T("* one shot repeatable modifier") << std::endl;
\r
1200 // oneShot modifier doesn't generate scan code
\r
1201 outputToLog(&key, c.m_mkey, 1);
\r
1202 if (isPhysicallyPressed) {
\r
1203 if (am == Keymap::AM_oneShotRepeatable // the key is repeating
\r
1204 && m_oneShotKey.m_key == c.m_mkey.m_key) {
\r
1205 if (m_oneShotRepeatableRepeatCount <
\r
1206 m_setting->m_oneShotRepeatableDelay) {
\r
1210 beginGeneratingKeyboardEvents(cnew, false);
\r
1212 ++ m_oneShotRepeatableRepeatCount;
\r
1214 m_oneShotKey = c.m_mkey;
\r
1215 m_oneShotRepeatableRepeatCount = 0;
\r
1218 if (m_oneShotKey.m_key) {
\r
1220 cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;
\r
1221 cnew.m_mkey.m_modifier.off(Modifier::Type_Up);
\r
1222 cnew.m_mkey.m_modifier.on(Modifier::Type_Down);
\r
1223 beginGeneratingKeyboardEvents(cnew, false);
\r
1226 cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;
\r
1227 cnew.m_mkey.m_modifier.on(Modifier::Type_Up);
\r
1228 cnew.m_mkey.m_modifier.off(Modifier::Type_Down);
\r
1229 beginGeneratingKeyboardEvents(cnew, false);
\r
1231 m_oneShotKey.m_key = NULL;
\r
1232 m_oneShotRepeatableRepeatCount = 0;
\r
1234 } else if (c.m_mkey.m_key) {
\r
1236 outputToLog(&key, c.m_mkey, 1);
\r
1237 if (isPhysicallyPressed)
\r
1238 m_oneShotKey.m_key = NULL;
\r
1239 beginGeneratingKeyboardEvents(c, isModifier);
\r
1242 if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {
\r
1243 // through mouse event even if undefined for fail safe
\r
1244 injectInput(&kid, NULL);
\r
1248 // if counter is zero, reset modifiers and keys on win32
\r
1249 if (m_currentKeyPressCount <= 0) {
\r
1251 Acquire a(&m_log, 1);
\r
1252 m_log << _T("* No key is pressed") << std::endl;
\r
1254 generateModifierEvents(Modifier());
\r
1255 if (0 < m_currentKeyPressCountOnWin32)
\r
1256 keyboardResetOnWin32();
\r
1257 m_currentKeyPressCount = 0;
\r
1258 m_currentKeyPressCountOnWin32 = 0;
\r
1259 m_oneShotKey.m_key = NULL;
\r
1260 if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)
\r
1261 m_currentLock.off(Modifier::Type_TouchpadSticky);
\r
1265 updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);
\r
1268 CHECK_TRUE( SetEvent(m_threadEvent) );
\r
1272 Engine::Engine(tomsgstream &i_log)
\r
1273 : m_hwndAssocWindow(NULL),
\r
1275 m_device(INVALID_HANDLE_VALUE),
\r
1276 m_didMayuStartDevice(false),
\r
1277 m_threadEvent(NULL),
\r
1278 m_mayudVersion(_T("unknown")),
\r
1279 m_buttonPressed(false),
\r
1280 m_dragging(false),
\r
1281 m_keyboardHandler(installKeyboardHook, Engine::keyboardDetour),
\r
1282 m_mouseHandler(installMouseHook, Engine::mouseDetour),
\r
1283 m_readEvent(NULL),
\r
1284 m_interruptThreadEvent(NULL),
\r
1287 m_doForceTerminate(false),
\r
1288 m_isLogMode(false),
\r
1289 m_isEnabled(true),
\r
1290 m_isSynchronizing(false),
\r
1292 m_generateKeyboardEventsRecursionGuard(0),
\r
1293 m_currentKeyPressCount(0),
\r
1294 m_currentKeyPressCountOnWin32(0),
\r
1295 m_lastGeneratedKey(NULL),
\r
1296 m_oneShotRepeatableRepeatCount(0),
\r
1297 m_isPrefix(false),
\r
1298 m_currentKeymap(NULL),
\r
1299 m_currentFocusOfThread(NULL),
\r
1300 m_hwndFocus(NULL),
\r
1301 m_afShellExecute(NULL),
\r
1304 for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)
\r
1305 m_lastPressedKey[i] = NULL;
\r
1307 // set default lock state
\r
1308 for (int i = 0; i < Modifier::Type_end; ++ i)
\r
1309 m_currentLock.dontcare(static_cast<Modifier::Type>(i));
\r
1310 for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)
\r
1311 m_currentLock.release(static_cast<Modifier::Type>(i));
\r
1315 throw ErrorMessage() << loadString(IDS_driverNotInstalled);
\r
1317 #endif // !NO_DRIVER
\r
1321 TCHAR versionBuf[256];
\r
1324 if (DeviceIoControl(m_device, IOCTL_MAYU_GET_VERSION, NULL, 0,
\r
1325 versionBuf, sizeof(versionBuf), &length, NULL)
\r
1327 && length < sizeof(versionBuf)) // fail safe
\r
1328 m_mayudVersion = tstring(versionBuf, length / 2);
\r
1330 #endif // !NO_DRIVER
\r
1331 // create event for sync
\r
1332 CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );
\r
1333 // create named pipe for &SetImeString
\r
1334 m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),
\r
1335 PIPE_ACCESS_OUTBOUND,
\r
1336 PIPE_TYPE_BYTE, 1,
\r
1338 StrExprArg::setEngine(this);
\r
1340 m_msllHookCurrent.pt.x = 0;
\r
1341 m_msllHookCurrent.pt.y = 0;
\r
1342 m_msllHookCurrent.mouseData = 0;
\r
1343 m_msllHookCurrent.flags = 0;
\r
1344 m_msllHookCurrent.time = 0;
\r
1345 m_msllHookCurrent.dwExtraInfo = 0;
\r
1349 // open mayu device
\r
1350 bool Engine::open() {
\r
1351 // open mayu m_device
\r
1353 m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
\r
1354 0, NULL, OPEN_EXISTING,
\r
1355 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
\r
1356 #endif // !NO_DRIVER
\r
1358 if (m_device != INVALID_HANDLE_VALUE) {
\r
1364 SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
1366 SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_START);
\r
1368 StartService(hs, 0, NULL);
\r
1369 CloseServiceHandle(hs);
\r
1370 m_didMayuStartDevice = true;
\r
1372 CloseServiceHandle(hscm);
\r
1375 // open mayu m_device
\r
1376 m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
\r
1377 0, NULL, OPEN_EXISTING,
\r
1378 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
\r
1379 #endif // !NO_DRIVER
\r
1380 return (m_device != INVALID_HANDLE_VALUE);
\r
1384 // close mayu device
\r
1385 void Engine::close() {
\r
1386 if (m_device != INVALID_HANDLE_VALUE) {
\r
1388 CHECK_TRUE( CloseHandle(m_device) );
\r
1389 #endif // !NO_DRIVER
\r
1391 m_device = INVALID_HANDLE_VALUE;
\r
1395 // start keyboard handler thread
\r
1396 void Engine::start() {
\r
1397 m_keyboardHandler.start(this);
\r
1398 m_mouseHandler.start(this);
\r
1399 CHECK_TRUE( m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
\r
1401 CHECK_TRUE( m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
\r
1402 CHECK_TRUE( m_interruptThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
\r
1404 m_ol.OffsetHigh = 0;
\r
1405 m_ol.hEvent = m_readEvent;
\r
1407 CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );
\r
1408 CHECK( WAIT_OBJECT_0 ==, WaitForSingleObject(m_threadEvent, INFINITE) );
\r
1412 // stop keyboard handler thread
\r
1413 void Engine::stop() {
\r
1414 if (m_threadEvent) {
\r
1415 m_doForceTerminate = true;
\r
1417 m_interruptThreadReason = InterruptThreadReason_Terminate;
\r
1418 SetEvent(m_interruptThreadEvent);
\r
1420 //M_DeviceIoControl(m_device, IOCTL_MAYU_DETOUR_CANCEL,
\r
1421 // &buf, sizeof(buf), &buf, sizeof(buf), &buf, NULL);
\r
1423 // wait for message handler thread terminate
\r
1424 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
\r
1425 CHECK_TRUE( CloseHandle(m_threadEvent) );
\r
1426 m_threadEvent = NULL;
\r
1427 WaitForSingleObject(m_threadHandle, 100);
\r
1428 CHECK_TRUE( CloseHandle(m_threadHandle) );
\r
1429 m_threadHandle = NULL;
\r
1432 if (m_didMayuStartDevice) {
\r
1433 SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
\r
1435 SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_STOP);
\r
1437 SERVICE_STATUS ss;
\r
1438 ControlService(hs, SERVICE_CONTROL_STOP, &ss);
\r
1439 CloseServiceHandle(hs);
\r
1441 CloseServiceHandle(hscm);
\r
1445 CHECK_TRUE( CloseHandle(m_readEvent) );
\r
1446 m_readEvent = NULL;
\r
1447 CHECK_TRUE( CloseHandle(m_interruptThreadEvent) );
\r
1448 m_interruptThreadEvent = NULL;
\r
1450 m_mouseHandler.stop();
\r
1451 m_keyboardHandler.stop();
\r
1454 bool Engine::pause() {
\r
1455 if (m_device != INVALID_HANDLE_VALUE) {
\r
1457 m_interruptThreadReason = InterruptThreadReason_Pause;
\r
1458 SetEvent(m_interruptThreadEvent);
\r
1459 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
\r
1462 #endif // !NO_DRIVER
\r
1468 bool Engine::resume() {
\r
1469 if (m_device == INVALID_HANDLE_VALUE) {
\r
1472 return false; // FIXME
\r
1474 #endif // !NO_DRIVER
\r
1476 m_interruptThreadReason = InterruptThreadReason_Resume;
\r
1477 SetEvent(m_interruptThreadEvent);
\r
1478 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
\r
1484 bool Engine::prepairQuit() {
\r
1485 // terminate and unload DLL for ThumbSense support if loaded
\r
1486 manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),
\r
1487 false, &m_sts4mayu);
\r
1488 manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),
\r
1489 false, &m_cts4mayu);
\r
1494 Engine::~Engine() {
\r
1496 CHECK_TRUE( CloseHandle(m_eSync) );
\r
1501 #endif // !NO_DRIVER
\r
1502 // destroy named pipe for &SetImeString
\r
1503 if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE) {
\r
1504 DisconnectNamedPipe(m_hookPipe);
\r
1505 CHECK_TRUE( CloseHandle(m_hookPipe) );
\r
1510 void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,
\r
1511 TCHAR *i_dependDllName,
\r
1512 bool i_load, HMODULE *i_pTs4mayu) {
\r
1513 Acquire a(&m_log, 0);
\r
1515 if (i_load == false) {
\r
1516 if (*i_pTs4mayu) {
\r
1517 bool (WINAPI *pTs4mayuTerm)();
\r
1519 pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");
\r
1520 if (pTs4mayuTerm() == true)
\r
1521 FreeLibrary(*i_pTs4mayu);
\r
1522 *i_pTs4mayu = NULL;
\r
1523 m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;
\r
1526 if (*i_pTs4mayu) {
\r
1527 m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;
\r
1529 if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0) {
\r
1530 m_log << _T("load ") << i_ts4mayuDllName
\r
1531 << _T(" failed: can't find ") << i_dependDllName
\r
1534 *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);
\r
1535 if (*i_pTs4mayu == NULL) {
\r
1536 m_log << _T("load ") << i_ts4mayuDllName
\r
1537 << _T(" failed: can't find it") << std::endl;
\r
1539 bool (WINAPI *pTs4mayuInit)(UINT);
\r
1541 pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");
\r
1542 if (pTs4mayuInit(m_threadId) == true)
\r
1543 m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;
\r
1545 m_log << i_ts4mayuDllName
\r
1546 <<_T(" load failed: can't initialize") << std::endl;
\r
1555 bool Engine::setSetting(Setting *i_setting) {
\r
1557 if (m_isSynchronizing)
\r
1561 for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();
\r
1563 Key *key = i_setting->m_keyboard.searchKey(*(*i));
\r
1565 key->m_isPressed = (*i)->m_isPressed;
\r
1566 key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;
\r
1567 key->m_isPressedByAssign = (*i)->m_isPressedByAssign;
\r
1570 if (m_lastGeneratedKey)
\r
1571 m_lastGeneratedKey =
\r
1572 i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);
\r
1573 for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)
\r
1574 if (m_lastPressedKey[i])
\r
1575 m_lastPressedKey[i] =
\r
1576 i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);
\r
1579 m_setting = i_setting;
\r
1581 manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),
\r
1582 m_setting->m_sts4mayu, &m_sts4mayu);
\r
1583 manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),
\r
1584 m_setting->m_cts4mayu, &m_cts4mayu);
\r
1586 g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;
\r
1587 if (m_currentFocusOfThread) {
\r
1588 for (FocusOfThreads::iterator i = m_focusOfThreads.begin();
\r
1589 i != m_focusOfThreads.end(); i ++) {
\r
1590 FocusOfThread *fot = &(*i).second;
\r
1591 m_setting->m_keymaps.searchWindow(&fot->m_keymaps,
\r
1592 fot->m_className, fot->m_titleName);
\r
1595 m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));
\r
1596 if (m_globalFocus.m_keymaps.empty()) {
\r
1597 Acquire a(&m_log, 0);
\r
1598 m_log << _T("internal error: m_globalFocus.m_keymap is empty")
\r
1601 m_currentFocusOfThread = &m_globalFocus;
\r
1602 setCurrentKeymap(m_globalFocus.m_keymaps.front());
\r
1603 m_hwndFocus = NULL;
\r
1608 void Engine::checkShow(HWND i_hwnd) {
\r
1609 // update show style of window
\r
1610 // this update should be done in hook DLL, but to
\r
1611 // avoid update-loss for some applications(such as
\r
1612 // cmd.exe), we update here.
\r
1613 bool isMaximized = false;
\r
1614 bool isMinimized = false;
\r
1615 bool isMDIMaximized = false;
\r
1616 bool isMDIMinimized = false;
\r
1619 LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);
\r
1621 LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);
\r
1623 if (exStyle & WS_EX_MDICHILD) {
\r
1624 WINDOWPLACEMENT placement;
\r
1625 placement.length = sizeof(WINDOWPLACEMENT);
\r
1626 if (GetWindowPlacement(i_hwnd, &placement)) {
\r
1627 switch (placement.showCmd) {
\r
1628 case SW_SHOWMAXIMIZED:
\r
1629 isMDIMaximized = true;
\r
1631 case SW_SHOWMINIMIZED:
\r
1632 isMDIMinimized = true;
\r
1634 case SW_SHOWNORMAL:
\r
1642 LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);
\r
1644 LONG style = GetWindowLong(i_hwnd, GWL_STYLE);
\r
1646 if ((style & WS_CHILD) == 0) {
\r
1647 WINDOWPLACEMENT placement;
\r
1648 placement.length = sizeof(WINDOWPLACEMENT);
\r
1649 if (GetWindowPlacement(i_hwnd, &placement)) {
\r
1650 switch (placement.showCmd) {
\r
1651 case SW_SHOWMAXIMIZED:
\r
1652 isMaximized = true;
\r
1654 case SW_SHOWMINIMIZED:
\r
1655 isMinimized = true;
\r
1657 case SW_SHOWNORMAL:
\r
1663 i_hwnd = GetParent(i_hwnd);
\r
1665 setShow(isMDIMaximized, isMDIMinimized, true);
\r
1666 setShow(isMaximized, isMinimized, false);
\r
1671 bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId,
\r
1672 const tstringi &i_className, const tstringi &i_titleName,
\r
1673 bool i_isConsole) {
\r
1675 if (m_isSynchronizing)
\r
1677 if (i_hwndFocus == NULL)
\r
1680 // remove newly created thread's id from m_detachedThreadIds
\r
1681 if (!m_detachedThreadIds.empty()) {
\r
1682 DetachedThreadIds::iterator i;
\r
1686 for (i = m_detachedThreadIds.begin();
\r
1687 i != m_detachedThreadIds.end(); ++ i)
\r
1688 if (*i == i_threadId) {
\r
1689 m_detachedThreadIds.erase(i);
\r
1696 FocusOfThread *fot;
\r
1697 FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);
\r
1698 if (i != m_focusOfThreads.end()) {
\r
1699 fot = &(*i).second;
\r
1700 if (fot->m_hwndFocus == i_hwndFocus &&
\r
1701 fot->m_isConsole == i_isConsole &&
\r
1702 fot->m_className == i_className &&
\r
1703 fot->m_titleName == i_titleName)
\r
1706 i = m_focusOfThreads.insert(
\r
1707 FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;
\r
1708 fot = &(*i).second;
\r
1709 fot->m_threadId = i_threadId;
\r
1711 fot->m_hwndFocus = i_hwndFocus;
\r
1712 fot->m_isConsole = i_isConsole;
\r
1713 fot->m_className = i_className;
\r
1714 fot->m_titleName = i_titleName;
\r
1717 m_setting->m_keymaps.searchWindow(&fot->m_keymaps,
\r
1718 i_className, i_titleName);
\r
1719 ASSERT(0 < fot->m_keymaps.size());
\r
1721 fot->m_keymaps.clear();
\r
1722 checkShow(i_hwndFocus);
\r
1728 bool Engine::setLockState(bool i_isNumLockToggled,
\r
1729 bool i_isCapsLockToggled,
\r
1730 bool i_isScrollLockToggled,
\r
1731 bool i_isKanaLockToggled,
\r
1732 bool i_isImeLockToggled,
\r
1733 bool i_isImeCompToggled) {
\r
1735 if (m_isSynchronizing)
\r
1737 m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);
\r
1738 m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);
\r
1739 m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);
\r
1740 m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);
\r
1741 m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);
\r
1742 m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);
\r
1748 bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,
\r
1751 if (m_isSynchronizing)
\r
1753 Acquire b(&m_log, 1);
\r
1754 Modifier::Type max, min;
\r
1755 if (i_isMDI == true) {
\r
1756 max = Modifier::Type_MdiMaximized;
\r
1757 min = Modifier::Type_MdiMinimized;
\r
1759 max = Modifier::Type_Maximized;
\r
1760 min = Modifier::Type_Minimized;
\r
1762 m_currentLock.on(max, i_isMaximized);
\r
1763 m_currentLock.on(min, i_isMinimized);
\r
1764 m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :
\r
1765 i_isMinimized ? _T("Minimized") : _T("Normal"));
\r
1766 if (i_isMDI == true) {
\r
1767 m_log << _T(" (MDI)");
\r
1769 m_log << std::endl;
\r
1775 bool Engine::syncNotify() {
\r
1777 if (!m_isSynchronizing)
\r
1779 CHECK_TRUE( SetEvent(m_eSync) );
\r
1784 // thread detach notify
\r
1785 bool Engine::threadDetachNotify(DWORD i_threadId) {
\r
1787 m_detachedThreadIds.push_back(i_threadId);
\r
1792 // get help message
\r
1793 void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle) {
\r
1795 *o_helpMessage = m_helpMessage;
\r
1796 *o_helpTitle = m_helpTitle;
\r
1801 void Engine::commandNotify(
\r
1802 HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam) {
\r
1803 Acquire b(&m_log, 0);
\r
1804 HWND hf = m_hwndFocus;
\r
1808 if (GetWindowThreadProcessId(hf, NULL) ==
\r
1809 GetWindowThreadProcessId(m_hwndAssocWindow, NULL))
\r
1810 return; // inhibit the investigation of MADO TSUKAI NO YUUTSU
\r
1812 const _TCHAR *target = NULL;
\r
1813 int number_target = 0;
\r
1816 target = _T("ToItself");
\r
1817 else if (i_hwnd == GetParent(hf))
\r
1818 target = _T("ToParentWindow");
\r
1820 // Function::toMainWindow
\r
1823 HWND p = GetParent(h);
\r
1829 target = _T("ToMainWindow");
\r
1831 // Function::toOverlappedWindow
\r
1835 LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);
\r
1837 LONG style = GetWindowLong(h, GWL_STYLE);
\r
1839 if ((style & WS_CHILD) == 0)
\r
1844 target = _T("ToOverlappedWindow");
\r
1848 for (number_target = 0; h; number_target ++, h = GetParent(h))
\r
1856 m_log << _T("&PostMessage(");
\r
1860 m_log << number_target;
\r
1861 m_log << _T(", ") << i_message
\r
1862 << _T(", 0x") << std::hex << i_wParam
\r
1863 << _T(", 0x") << i_lParam << _T(") # hwnd = ")
\r
1864 << reinterpret_cast<int>(i_hwnd) << _T(", ")
\r
1865 << _T("message = ") << std::dec;
\r
1866 if (i_message == WM_COMMAND)
\r
1867 m_log << _T("WM_COMMAND, ");
\r
1868 else if (i_message == WM_SYSCOMMAND)
\r
1869 m_log << _T("WM_SYSCOMMAND, ");
\r
1871 m_log << i_message << _T(", ");
\r
1872 m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")
\r
1873 << _T("wID = ") << LOWORD(i_wParam) << _T(", ")
\r
1874 << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;
\r
1877 unsigned int WINAPI Engine::InputHandler::run(void *i_this)
\r
1879 reinterpret_cast<InputHandler*>(i_this)->run();
\r
1884 Engine::InputHandler::InputHandler(INSTALL_HOOK i_installHook, INPUT_DETOUR i_inputDetour)
\r
1885 : m_installHook(i_installHook), m_inputDetour(i_inputDetour)
\r
1887 CHECK_TRUE(m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL));
\r
1888 CHECK_TRUE(m_hThread = (HANDLE)_beginthreadex(NULL, 0, run, this, CREATE_SUSPENDED, &m_threadId));
\r
1891 Engine::InputHandler::~InputHandler()
\r
1893 CloseHandle(m_hEvent);
\r
1896 void Engine::InputHandler::run()
\r
1900 CHECK_FALSE(m_installHook(m_inputDetour, m_engine, true));
\r
1901 PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
\r
1902 SetEvent(m_hEvent);
\r
1904 while (GetMessage(&msg, NULL, 0, 0)) {
\r
1905 // nothing to do...
\r
1908 CHECK_FALSE(m_installHook(m_inputDetour, m_engine, false));
\r
1913 int Engine::InputHandler::start(Engine *i_engine)
\r
1915 m_engine = i_engine;
\r
1916 ResumeThread(m_hThread);
\r
1917 WaitForSingleObject(m_hEvent, INFINITE);
\r
1921 int Engine::InputHandler::stop()
\r
1923 PostThreadMessage(m_threadId, WM_QUIT, 0, 0);
\r
1924 WaitForSingleObject(m_hThread, INFINITE);
\r