1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
8 #include "errormessage.h"
11 #include "windowstool.h"
19 void Engine::checkFocusWindow()
26 HWND hwndFore = GetForegroundWindow();
27 DWORD threadId = GetWindowThreadProcessId(hwndFore, NULL);
33 if (m_currentFocusOfThread &&
34 m_currentFocusOfThread->m_threadId == threadId &&
35 m_currentFocusOfThread->m_hwndFocus == m_hwndFocus)
38 m_emacsEditKillLine.reset();
41 if (!m_detachedThreadIds.empty())
43 for (DetachedThreadIds::iterator i = m_detachedThreadIds.begin();
44 i != m_detachedThreadIds.end(); i ++)
46 FocusOfThreads::iterator j = m_focusOfThreads.find((*i));
47 if (j != m_focusOfThreads.end())
49 FocusOfThread *fot = &((*j).second);
51 m_log << _T("RemoveThread") << std::endl;
52 m_log << _T("\tHWND:\t") << std::hex << (int)fot->m_hwndFocus
53 << std::dec << std::endl;
54 m_log << _T("\tTHREADID:") << fot->m_threadId << std::endl;
55 m_log << _T("\tCLASS:\t") << fot->m_className << std::endl;
56 m_log << _T("\tTITLE:\t") << fot->m_titleName << std::endl;
58 m_focusOfThreads.erase(j);
61 m_detachedThreadIds.erase
62 (m_detachedThreadIds.begin(), m_detachedThreadIds.end());
65 FocusOfThreads::iterator i = m_focusOfThreads.find(threadId);
66 if (i != m_focusOfThreads.end())
68 m_currentFocusOfThread = &((*i).second);
69 if (!m_currentFocusOfThread->m_isConsole || 2 <= count)
71 if (m_currentFocusOfThread->m_keymaps.empty())
72 setCurrentKeymap(NULL);
74 setCurrentKeymap(*m_currentFocusOfThread->m_keymaps.begin());
75 m_hwndFocus = m_currentFocusOfThread->m_hwndFocus;
76 checkShow(m_hwndFocus);
79 m_log << _T("FocusChanged") << std::endl;
80 m_log << _T("\tHWND:\t")
81 << std::hex << (int)m_currentFocusOfThread->m_hwndFocus
82 << std::dec << std::endl;
83 m_log << _T("\tTHREADID:")
84 << m_currentFocusOfThread->m_threadId << std::endl;
85 m_log << _T("\tCLASS:\t")
86 << m_currentFocusOfThread->m_className << std::endl;
87 m_log << _T("\tTITLE:\t")
88 << m_currentFocusOfThread->m_titleName << std::endl;
95 _TCHAR className[GANA_MAX_ATOM_LENGTH];
96 if (GetClassName(hwndFore, className, NUMBER_OF(className)))
98 if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0)
100 _TCHAR titleName[1024];
101 if (GetWindowText(hwndFore, titleName, NUMBER_OF(titleName)) == 0)
102 titleName[0] = _T('\0');
103 setFocus(hwndFore, threadId, className, titleName, true);
104 Acquire a(&m_log, 1);
105 m_log << _T("HWND:\t") << std::hex << reinterpret_cast<int>(hwndFore)
106 << std::dec << std::endl;
107 m_log << _T("THREADID:") << threadId << std::endl;
108 m_log << _T("CLASS:\t") << className << std::endl;
109 m_log << _T("TITLE:\t") << titleName << std::endl << std::endl;
116 if (m_globalFocus.m_keymaps.empty())
118 Acquire a(&m_log, 1);
119 m_log << _T("NO GLOBAL FOCUS") << std::endl;
120 m_currentFocusOfThread = NULL;
121 setCurrentKeymap(NULL);
125 if (m_currentFocusOfThread != &m_globalFocus)
127 Acquire a(&m_log, 1);
128 m_log << _T("GLOBAL FOCUS") << std::endl;
129 m_currentFocusOfThread = &m_globalFocus;
130 setCurrentKeymap(m_globalFocus.m_keymaps.front());
138 // is modifier pressed ?
139 bool Engine::isPressed(Modifier::Type i_mt)
141 const Keymap::ModAssignments &ma = m_currentKeymap->getModAssignments(i_mt);
142 for (Keymap::ModAssignments::const_iterator i = ma.begin();
144 if ((*i).m_key->m_isPressed)
150 // fix modifier key (if fixed, return true)
151 bool Engine::fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am)
153 // for all modifier ...
154 for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)
156 // get modifier assignments (list of modifier keys)
157 const Keymap::ModAssignments &ma =
158 m_currentKeymap->getModAssignments(static_cast<Modifier::Type>(i));
160 for (Keymap::ModAssignments::const_iterator
161 j = ma.begin(); j != ma.end(); ++ j)
162 if (io_mkey->m_key == (*j).m_key) // is io_mkey a modifier ?
165 Acquire a(&m_log, 1);
166 m_log << _T("* Modifier Key") << std::endl;
168 // set dontcare for this modifier
169 io_mkey->m_modifier.dontcare(static_cast<Modifier::Type>(i));
170 *o_am = (*j).m_assignMode;
174 *o_am = Keymap::AM_notModifier;
180 void Engine::outputToLog(const Key *i_key, const ModifiedKey &i_mkey,
184 Acquire a(&m_log, i_debugLevel);
187 for (i = 0; i < i_key->getScanCodesSize(); ++ i)
189 if (i_key->getScanCodes()[i].m_flags & ScanCode::E0) m_log << _T("E0-");
190 if (i_key->getScanCodes()[i].m_flags & ScanCode::E1) m_log << _T("E1-");
191 if (!(i_key->getScanCodes()[i].m_flags & ScanCode::E0E1))
193 m_log << _T("0x") << std::hex << std::setw(2) << std::setfill(_T('0'))
194 << static_cast<int>(i_key->getScanCodes()[i].m_scan)
195 << std::dec << _T(" ");
198 if (!i_mkey.m_key) // key corresponds to no phisical key
204 m_log << _T(" ") << i_mkey << std::endl;
209 void Engine::describeBindings()
211 Acquire a(&m_log, 0);
213 Keymap::DescribeParam dp;
214 for (KeymapPtrList::iterator i = m_currentFocusOfThread->m_keymaps.begin();
215 i != m_currentFocusOfThread->m_keymaps.end(); ++ i)
216 (*i)->describe(m_log, &dp);
221 // update m_lastPressedKey
222 void Engine::updateLastPressedKey(Key *i_key)
224 m_lastPressedKey[1] = m_lastPressedKey[0];
225 m_lastPressedKey[0] = i_key;
228 // set current keymap
229 void Engine::setCurrentKeymap(const Keymap *i_keymap, bool i_doesAddToHistory)
231 if (i_doesAddToHistory)
233 m_keymapPrefixHistory.push_back(const_cast<Keymap *>(m_currentKeymap));
234 if (MAX_KEYMAP_PREFIX_HISTORY < m_keymapPrefixHistory.size())
235 m_keymapPrefixHistory.pop_front();
238 m_keymapPrefixHistory.clear();
239 m_currentKeymap = i_keymap;
243 // get current modifiers
244 Modifier Engine::getCurrentModifiers(Key *i_key, bool i_isPressed)
247 cmods.add(m_currentLock);
249 cmods.press(Modifier::Type_Shift , isPressed(Modifier::Type_Shift ));
250 cmods.press(Modifier::Type_Alt , isPressed(Modifier::Type_Alt ));
251 cmods.press(Modifier::Type_Control, isPressed(Modifier::Type_Control));
252 cmods.press(Modifier::Type_Windows, isPressed(Modifier::Type_Windows));
253 cmods.press(Modifier::Type_Up , !i_isPressed);
254 cmods.press(Modifier::Type_Down , i_isPressed);
256 cmods.press(Modifier::Type_Repeat , false);
257 if (m_lastPressedKey[0] == i_key)
260 cmods.press(Modifier::Type_Repeat, true);
262 if (m_lastPressedKey[1] == i_key)
263 cmods.press(Modifier::Type_Repeat, true);
266 for (int i = Modifier::Type_Mod0; i <= Modifier::Type_Mod9; ++ i)
267 cmods.press(static_cast<Modifier::Type>(i),
268 isPressed(static_cast<Modifier::Type>(i)));
274 // generate keyboard event for a key
275 void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)
277 // check if key is event
278 bool isEvent = false;
279 for (Key **e = Event::events; *e; ++ e)
286 bool isAlreadyReleased = false;
290 if (i_doPress && !i_key->m_isPressedOnWin32)
291 ++ m_currentKeyPressCountOnWin32;
294 if (i_key->m_isPressedOnWin32)
295 -- m_currentKeyPressCountOnWin32;
297 isAlreadyReleased = true;
299 i_key->m_isPressedOnWin32 = i_doPress;
302 i_key->m_isPressedByAssign = i_doPress;
304 Key *sync = m_setting->m_keyboard.getSyncKey();
306 if (!isAlreadyReleased || i_key == sync)
308 KEYBOARD_INPUT_DATA kid = { 0, 0, 0, 0, 0 };
309 const ScanCode *sc = i_key->getScanCodes();
310 for (size_t i = 0; i < i_key->getScanCodesSize(); ++ i)
312 kid.MakeCode = sc[i].m_scan;
313 kid.Flags = sc[i].m_flags;
315 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
318 injectInput(&kid, NULL);
321 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
322 CHECK_TRUE( GetOverlappedResult(m_device, &m_ol, &len, TRUE) );
324 #elif defined(_WIN95)
325 DeviceIoControl(m_device, 2, &kid, sizeof(kid), NULL, 0, &len, NULL);
331 m_lastGeneratedKey = i_doPress ? i_key : NULL;
336 Acquire a(&m_log, 1);
337 m_log << _T("\t\t =>\t");
338 if (isAlreadyReleased)
339 m_log << _T("(already released) ");
341 ModifiedKey mkey(i_key);
342 mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);
343 mkey.m_modifier.on(Modifier::Type_Down, i_doPress);
344 outputToLog(i_key, mkey, 1);
349 void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)
352 i_c.m_keymap = i_keymap;
353 i_c.m_mkey.m_key = i_event;
354 if (const Keymap::KeyAssignment *keyAssign =
355 i_c.m_keymap->searchAssignment(i_c.m_mkey))
358 Acquire a(&m_log, 1);
359 m_log << std::endl << _T(" ")
360 << i_event->getName() << std::endl;
362 generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);
367 // genete modifier events
368 void Engine::generateModifierEvents(const Modifier &i_mod)
371 Acquire a(&m_log, 1);
372 m_log << _T("* Gen Modifiers\t{") << std::endl;
375 for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i)
377 Keyboard::Mods &mods =
378 m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));
380 if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))
381 // no need to process
383 else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))
384 // we have to press this modifier
386 bool noneIsPressed = true;
387 bool noneIsPressedByAssign = true;
388 for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i)
390 if ((*i)->m_isPressedOnWin32)
391 noneIsPressed = false;
392 if ((*i)->m_isPressedByAssign)
393 noneIsPressedByAssign = false;
397 if (noneIsPressedByAssign)
398 generateKeyEvent(mods.front(), true, false);
400 for (Keyboard::Mods::iterator
401 i = mods.begin(); i != mods.end(); ++ i)
402 if ((*i)->m_isPressedByAssign)
403 generateKeyEvent((*i), true, false);
408 // we have to release this modifier
410 // avoid such sequences as "Alt U-ALt" or "Windows U-Windows"
411 if (i == Modifier::Type_Alt || i == Modifier::Type_Windows)
413 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)
414 if ((*j) == m_lastGeneratedKey)
416 Keyboard::Mods *mods =
417 &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);
418 if (mods->size() == 0)
419 mods = &m_setting->m_keyboard.getModifiers(
420 Modifier::Type_Control);
421 if (0 < mods->size())
423 generateKeyEvent(mods->front(), true, false);
424 generateKeyEvent(mods->front(), false, false);
430 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)
432 if ((*j)->m_isPressedOnWin32)
433 generateKeyEvent((*j), false, false);
439 Acquire a(&m_log, 1);
440 m_log << _T("\t\t}") << std::endl;
445 // generate keyboard events for action
446 void Engine::generateActionEvents(const Current &i_c, const Action *i_a,
449 switch (i_a->getType())
452 case Action::Type_key:
454 const ModifiedKey &mkey
455 = reinterpret_cast<ActionKey *>(
456 const_cast<Action *>(i_a))->m_modifiedKey;
460 (mkey.m_modifier.isOn(Modifier::Type_Up) ||
461 mkey.m_modifier.isDontcare(Modifier::Type_Up)))
462 generateKeyEvent(mkey.m_key, false, true);
465 else if (i_doPress &&
466 (mkey.m_modifier.isOn(Modifier::Type_Down) ||
467 mkey.m_modifier.isDontcare(Modifier::Type_Down)))
469 Modifier modifier = mkey.m_modifier;
470 modifier.add(i_c.m_mkey.m_modifier);
471 generateModifierEvents(modifier);
472 generateKeyEvent(mkey.m_key, true, true);
478 case Action::Type_keySeq:
480 const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);
481 generateKeySeqEvents(i_c, aks->m_keySeq,
482 i_doPress ? Part_down : Part_up);
487 case Action::Type_function:
489 const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);
490 bool is_up = (!i_doPress &&
491 (af->m_modifier.isOn(Modifier::Type_Up) ||
492 af->m_modifier.isDontcare(Modifier::Type_Up)));
493 bool is_down = (i_doPress &&
494 (af->m_modifier.isOn(Modifier::Type_Down) ||
495 af->m_modifier.isDontcare(Modifier::Type_Down)));
497 if (!is_down && !is_up)
501 Acquire a(&m_log, 1);
502 m_log << _T("\t\t >\t") << af->m_functionData;
506 param.m_isPressed = i_doPress;
507 param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;
509 param.m_doesNeedEndl = true;
512 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);
513 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);
515 af->m_functionData->exec(this, ¶m);
517 if (param.m_doesNeedEndl)
519 Acquire a(&m_log, 1);
528 // generate keyboard events for keySeq
529 void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,
532 const KeySeq::Actions &actions = i_keySeq->getActions();
535 if (i_part == Part_up)
536 generateActionEvents(i_c, actions[actions.size() - 1], false);
540 for (i = 0 ; i < actions.size() - 1; ++ i)
542 generateActionEvents(i_c, actions[i], true);
543 generateActionEvents(i_c, actions[i], false);
545 generateActionEvents(i_c, actions[i], true);
546 if (i_part == Part_all)
547 generateActionEvents(i_c, actions[i], false);
552 // generate keyboard events for current key
553 void Engine::generateKeyboardEvents(const Current &i_c)
555 if (++ m_generateKeyboardEventsRecursionGuard ==
556 MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT)
559 m_log << _T("error: too deep keymap recursion. there may be a loop.")
564 const Keymap::KeyAssignment *keyAssign
565 = i_c.m_keymap->searchAssignment(i_c.m_mkey);
568 const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();
570 generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);
574 if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||
575 keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))
576 generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);
578 generateKeySeqEvents(i_c, keyAssign->m_keySeq,
579 i_c.isPressed() ? Part_down : Part_up);
581 m_generateKeyboardEventsRecursionGuard --;
585 // generate keyboard events for current key
586 void Engine::beginGeneratingKeyboardEvents(
587 const Current &i_c, bool i_isModifier)
589 // (1) (2) (3) (4) (1)
590 // up/down: D- U- D- U- D-
591 // keymap: m_currentKeymap m_currentKeymap X X m_currentKeymap
592 // memo: &Prefix(X) ... ... ... ...
593 // m_isPrefix: false true true false false
597 bool isPhysicallyPressed
598 = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);
601 ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);
605 if (isPhysicallyPressed)
607 cnew.m_mkey.m_modifier.off(Modifier::Type_Up);
608 cnew.m_mkey.m_modifier.on(Modifier::Type_Down);
612 cnew.m_mkey.m_modifier.on(Modifier::Type_Up);
613 cnew.m_mkey.m_modifier.off(Modifier::Type_Down);
615 for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)
617 Modifier::Type type = static_cast<Modifier::Type>(i);
618 if (cnew.m_mkey.m_modifier.isDontcare(type) &&
619 !i_c.m_mkey.m_modifier.isDontcare(type))
620 cnew.m_mkey.m_modifier.press(
621 type, i_c.m_mkey.m_modifier.isPressed(type));
625 Acquire a(&m_log, 1);
626 m_log << _T("* substitute") << std::endl;
628 outputToLog(mkey.m_key, cnew.m_mkey, 1);
632 const Keymap *tmpKeymap = m_currentKeymap;
633 if (i_isModifier || !m_isPrefix) ;
634 else if (isPhysicallyPressed) // when (3)
636 else if (!isPhysicallyPressed) // when (2)
637 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();
639 // for m_emacsEditKillLine function
640 m_emacsEditKillLine.m_doForceReset = !i_isModifier;
642 // generate key event !
643 m_generateKeyboardEventsRecursionGuard = 0;
644 if (isPhysicallyPressed)
645 generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);
646 generateKeyboardEvents(cnew);
647 if (!isPhysicallyPressed)
648 generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);
650 // for m_emacsEditKillLine function
651 if (m_emacsEditKillLine.m_doForceReset)
652 m_emacsEditKillLine.reset();
657 else if (!m_isPrefix) // when (1), (4)
658 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();
659 else if (!isPhysicallyPressed) // when (2)
660 m_currentKeymap = tmpKeymap;
665 unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)
668 kid.type = INPUT_KEYBOARD;
670 kid.ki.wScan = i_kid->MakeCode;
671 kid.ki.dwFlags = KEYEVENTF_SCANCODE;
672 kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;
673 kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;
674 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK)
676 kid.ki.dwFlags |= KEYEVENTF_KEYUP;
678 if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0)
680 kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
682 SendInput(1, &kid, sizeof(kid));
688 // pop all pressed key on win32
689 void Engine::keyboardResetOnWin32()
691 for (Keyboard::KeyIterator
692 i = m_setting->m_keyboard.getKeyIterator(); *i; ++ i)
694 if ((*i)->m_isPressedOnWin32)
695 generateKeyEvent((*i), false, true);
701 unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, KBDLLHOOKSTRUCT *i_kid)
703 return i_this->keyboardDetour(i_kid);
706 unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)
709 Acquire a(&m_log, 1);
711 << _T("keyboardDetour: vkCode=") << i_kid->vkCode
712 << _T(" scanCode=") << i_kid->scanCode
713 << _T(" flags=") << i_kid->flags << std::endl;
715 if (i_kid->flags & LLKHF_INJECTED)
722 KEYBOARD_INPUT_DATA kid;
725 kid.MakeCode = i_kid->scanCode;
727 if (i_kid->flags & LLKHF_UP)
729 kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
731 if (i_kid->flags & LLKHF_EXTENDED)
733 kid.Flags |= KEYBOARD_INPUT_DATA::E0;
736 kid.ExtraInformation = 0;
738 Acquire a(&m_cskidq);
739 m_kidq.push_back(kid);
740 SetEvent(m_readEvent);
746 // keyboard handler thread
747 unsigned int WINAPI Engine::keyboardHandler(void *i_this)
749 reinterpret_cast<Engine *>(i_this)->keyboardHandler();
753 void Engine::keyboardHandler()
756 CHECK_TRUE( SetEvent(m_threadEvent) );
760 while (!m_doForceTerminate)
762 KEYBOARD_INPUT_DATA kid;
769 Acquire a(&m_log, 1);
770 m_log << _T("begin ReadFile();") << std::endl;
776 if (!ReadFile(m_device, &kid, sizeof(kid), &len, &m_ol))
778 if (GetLastError() != ERROR_IO_PENDING)
782 HANDLE handles[] = { m_readEvent, m_interruptThreadEvent };
784 switch (MsgWaitForMultipleObjects(NUMBER_OF(handles), &handles[0],
785 FALSE, INFINITE, QS_POSTMESSAGE))
787 case WAIT_OBJECT_0: // m_readEvent
790 Acquire a(&m_cskidq);
795 kid = m_kidq.front();
799 SetEvent(m_readEvent);
803 if (!GetOverlappedResult(m_device, &m_ol, &len, FALSE))
808 case WAIT_OBJECT_0 + 1: // m_interruptThreadEvent
810 switch (m_interruptThreadReason) {
813 Acquire a(&m_log, 0);
814 m_log << _T("internal error: m_interruptThreadReason == ")
815 << m_interruptThreadReason << std::endl;
819 case InterruptThreadReason_Terminate:
822 case InterruptThreadReason_Pause: {
823 CHECK_TRUE( SetEvent(m_threadEvent) );
824 while (WaitForMultipleObjects(1, &m_interruptThreadEvent,
825 FALSE, INFINITE) != WAIT_OBJECT_0)
827 switch (m_interruptThreadReason) {
828 case InterruptThreadReason_Terminate:
831 case InterruptThreadReason_Resume:
838 CHECK_TRUE( SetEvent(m_threadEvent) );
844 case WAIT_OBJECT_0 + NUMBER_OF(handles):
848 while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
850 switch (message.message)
856 m_currentLock.on(Modifier::Type_Touchpad);
857 m_currentLock.on(Modifier::Type_TouchpadSticky);
860 m_currentLock.off(Modifier::Type_Touchpad);
861 Acquire a(&m_log, 1);
862 m_log << _T("touchpad: ") << message.wParam
863 << _T(".") << (message.lParam & 0xffff)
864 << _T(".") << (message.lParam >> 16 & 0xffff)
881 Acquire a(&m_log, 1);
882 m_log << _T("end ReadFile();") << std::endl;
884 #elif defined(_WIN95)
885 if (!DeviceIoControl(m_device, 1, NULL, 0, &kid, sizeof(kid), &len, NULL))
895 if (!m_setting || // m_setting has not been loaded
896 !m_isEnabled) // disabled
901 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));
902 outputToLog(&key, ModifiedKey(), 0);
908 injectInput(&kid, NULL);
910 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
911 GetOverlappedResult(m_device, &m_ol, &len, TRUE);
913 #elif defined(_WIN95)
914 DeviceIoControl(m_device, 2, &kid, sizeof(kid), NULL, 0, &len, NULL);
919 updateLastPressedKey(NULL);
925 if (!m_currentFocusOfThread ||
930 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
931 GetOverlappedResult(m_device, &m_ol, &len, TRUE);
933 #elif defined(_WIN95)
934 DeviceIoControl(m_device, 2, &kid, sizeof(kid), NULL, 0, &len, NULL);
938 Acquire a(&m_log, 0);
939 if (!m_currentFocusOfThread)
940 m_log << _T("internal error: m_currentFocusOfThread == NULL")
942 if (!m_currentKeymap)
943 m_log << _T("internal error: m_currentKeymap == NULL")
945 updateLastPressedKey(NULL);
950 c.m_keymap = m_currentKeymap;
951 c.m_i = m_currentFocusOfThread->m_keymaps.begin();
954 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));
955 c.m_mkey = m_setting->m_keyboard.searchKey(key);
958 c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);
963 // press the key and update counter
964 bool isPhysicallyPressed
965 = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);
968 if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)
969 ++ m_currentKeyPressCount;
970 else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)
971 -- m_currentKeyPressCount;
972 c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;
976 c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,
977 isPhysicallyPressed);
978 Keymap::AssignMode am;
979 bool isModifier = fixModifierKey(&c.m_mkey, &am);
982 if (isModifier && m_doesIgnoreModifierForPrefix)
983 am = Keymap::AM_true;
984 if (m_doesEditNextModifier)
986 Modifier modifier = m_modifierForNextKey;
987 modifier.add(c.m_mkey.m_modifier);
988 c.m_mkey.m_modifier = modifier;
993 outputToLog(&key, c.m_mkey, 0);
994 else if (am == Keymap::AM_true)
997 Acquire a(&m_log, 1);
998 m_log << _T("* true modifier") << std::endl;
1000 // true modifier doesn't generate scan code
1001 outputToLog(&key, c.m_mkey, 1);
1003 else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable)
1006 Acquire a(&m_log, 1);
1007 if (am == Keymap::AM_oneShot)
1008 m_log << _T("* one shot modifier") << std::endl;
1010 m_log << _T("* one shot repeatable modifier") << std::endl;
1012 // oneShot modifier doesn't generate scan code
1013 outputToLog(&key, c.m_mkey, 1);
1014 if (isPhysicallyPressed)
1016 if (am == Keymap::AM_oneShotRepeatable // the key is repeating
1017 && m_oneShotKey.m_key == c.m_mkey.m_key)
1019 if (m_oneShotRepeatableRepeatCount <
1020 m_setting->m_oneShotRepeatableDelay) {
1024 beginGeneratingKeyboardEvents(cnew, false);
1026 ++ m_oneShotRepeatableRepeatCount;
1028 m_oneShotKey = c.m_mkey;
1029 m_oneShotRepeatableRepeatCount = 0;
1034 if (m_oneShotKey.m_key)
1037 cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;
1038 cnew.m_mkey.m_modifier.off(Modifier::Type_Up);
1039 cnew.m_mkey.m_modifier.on(Modifier::Type_Down);
1040 beginGeneratingKeyboardEvents(cnew, false);
1043 cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;
1044 cnew.m_mkey.m_modifier.on(Modifier::Type_Up);
1045 cnew.m_mkey.m_modifier.off(Modifier::Type_Down);
1046 beginGeneratingKeyboardEvents(cnew, false);
1048 m_oneShotKey.m_key = NULL;
1049 m_oneShotRepeatableRepeatCount = 0;
1052 else if (c.m_mkey.m_key)
1055 outputToLog(&key, c.m_mkey, 1);
1056 if (isPhysicallyPressed)
1057 m_oneShotKey.m_key = NULL;
1058 beginGeneratingKeyboardEvents(c, isModifier);
1061 // if counter is zero, reset modifiers and keys on win32
1062 if (m_currentKeyPressCount <= 0)
1065 Acquire a(&m_log, 1);
1066 m_log << _T("* No key is pressed") << std::endl;
1068 generateModifierEvents(Modifier());
1069 if (0 < m_currentKeyPressCountOnWin32)
1070 keyboardResetOnWin32();
1071 m_currentKeyPressCount = 0;
1072 m_currentKeyPressCountOnWin32 = 0;
1073 m_oneShotKey.m_key = NULL;
1074 if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)
1075 m_currentLock.off(Modifier::Type_TouchpadSticky);
1079 updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);
1084 CHECK_TRUE( SetEvent(m_threadEvent) );
1088 Engine::Engine(tomsgstream &i_log)
1089 : m_hwndAssocWindow(NULL),
1091 m_device(INVALID_HANDLE_VALUE),
1092 m_didMayuStartDevice(false),
1093 m_threadEvent(NULL),
1094 m_mayudVersion(_T("unknown")),
1097 m_interruptThreadEvent(NULL),
1101 m_doForceTerminate(false),
1104 m_isSynchronizing(false),
1106 m_generateKeyboardEventsRecursionGuard(0),
1107 m_currentKeyPressCount(0),
1108 m_currentKeyPressCountOnWin32(0),
1109 m_lastGeneratedKey(NULL),
1110 m_oneShotRepeatableRepeatCount(0),
1112 m_currentKeymap(NULL),
1113 m_currentFocusOfThread(NULL),
1115 m_afShellExecute(NULL),
1119 for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)
1120 m_lastPressedKey[i] = NULL;
1122 // set default lock state
1123 for (int i = 0; i < Modifier::Type_end; ++ i)
1124 m_currentLock.dontcare(static_cast<Modifier::Type>(i));
1125 for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)
1126 m_currentLock.release(static_cast<Modifier::Type>(i));
1130 throw ErrorMessage() << loadString(IDS_driverNotInstalled);
1132 #endif // !NO_DRIVER
1136 TCHAR versionBuf[256];
1139 if (DeviceIoControl(m_device, IOCTL_MAYU_GET_VERSION, NULL, 0,
1140 versionBuf, sizeof(versionBuf), &length, NULL)
1142 && length < sizeof(versionBuf)) // fail safe
1143 m_mayudVersion = tstring(versionBuf, length / 2);
1145 #endif // !NO_DRIVER
1146 // create event for sync
1147 CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );
1149 // create named pipe for &SetImeString
1150 m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),
1151 PIPE_ACCESS_OUTBOUND,
1155 StrExprArg::setEngine(this);
1162 // open mayu m_device
1165 m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
1166 0, NULL, OPEN_EXISTING,
1167 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
1168 #endif // !NO_DRIVER
1169 #elif defined(_WIN95)
1170 m_device = CreateFile(MAYU_DEVICE_FILE_NAME, 0,
1171 0, NULL, CREATE_NEW, FILE_FLAG_DELETE_ON_CLOSE, NULL);
1176 if (m_device != INVALID_HANDLE_VALUE) {
1183 SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
1186 SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_START);
1189 StartService(hs, 0, NULL);
1190 CloseServiceHandle(hs);
1191 m_didMayuStartDevice = true;
1193 CloseServiceHandle(hscm);
1196 // open mayu m_device
1197 m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
1198 0, NULL, OPEN_EXISTING,
1199 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
1200 #endif // !NO_DRIVER
1202 return (m_device != INVALID_HANDLE_VALUE);
1206 // close mayu device
1207 void Engine::close()
1209 if (m_device != INVALID_HANDLE_VALUE) {
1211 CHECK_TRUE( CloseHandle(m_device) );
1212 #endif // !NO_DRIVER
1214 m_device = INVALID_HANDLE_VALUE;
1218 // start keyboard handler thread
1219 void Engine::start()
1221 CHECK_TRUE( m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
1224 CHECK_TRUE( m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
1225 CHECK_TRUE( m_interruptThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
1227 m_ol.OffsetHigh = 0;
1228 m_ol.hEvent = m_readEvent;
1231 CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );
1232 CHECK( WAIT_OBJECT_0 ==, WaitForSingleObject(m_threadEvent, INFINITE) );
1236 // stop keyboard handler thread
1241 m_doForceTerminate = true;
1245 m_interruptThreadReason = InterruptThreadReason_Terminate;
1246 SetEvent(m_interruptThreadEvent);
1247 #elif defined(_WIN95)
1248 DeviceIoControl(m_device, 3, NULL, 0, NULL, 0, NULL, NULL);
1251 //M_DeviceIoControl(m_device, IOCTL_MAYU_DETOUR_CANCEL,
1252 // &buf, sizeof(buf), &buf, sizeof(buf), &buf, NULL);
1254 // wait for message handler thread terminate
1255 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
1256 CHECK_TRUE( CloseHandle(m_threadEvent) );
1257 m_threadEvent = NULL;
1258 WaitForSingleObject(m_threadHandle, 100);
1259 CHECK_TRUE( CloseHandle(m_threadHandle) );
1260 m_threadHandle = NULL;
1264 if (m_didMayuStartDevice)
1266 SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
1269 SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_STOP);
1273 ControlService(hs, SERVICE_CONTROL_STOP, &ss);
1274 CloseServiceHandle(hs);
1276 CloseServiceHandle(hscm);
1280 CHECK_TRUE( CloseHandle(m_readEvent) );
1282 CHECK_TRUE( CloseHandle(m_interruptThreadEvent) );
1283 m_interruptThreadEvent = NULL;
1288 bool Engine::pause()
1291 if (m_device != INVALID_HANDLE_VALUE) {
1293 m_interruptThreadReason = InterruptThreadReason_Pause;
1294 SetEvent(m_interruptThreadEvent);
1295 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
1298 #endif // !NO_DRIVER
1305 bool Engine::resume()
1308 if (m_device == INVALID_HANDLE_VALUE) {
1311 return false; // FIXME
1313 #endif // !NO_DRIVER
1315 m_interruptThreadReason = InterruptThreadReason_Resume;
1316 SetEvent(m_interruptThreadEvent);
1317 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
1324 bool Engine::prepairQuit()
1326 // terminate and unload DLL for ThumbSense support if loaded
1327 manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),
1328 false, &m_sts4mayu);
1329 manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),
1330 false, &m_cts4mayu);
1338 CHECK_TRUE( CloseHandle(m_eSync) );
1343 #endif // !NO_DRIVER
1345 // destroy named pipe for &SetImeString
1346 if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE)
1348 DisconnectNamedPipe(m_hookPipe);
1349 CHECK_TRUE( CloseHandle(m_hookPipe) );
1355 void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,
1356 TCHAR *i_dependDllName,
1357 bool i_load, HMODULE *i_pTs4mayu)
1359 Acquire a(&m_log, 0);
1361 if (i_load == false)
1365 bool (WINAPI *pTs4mayuTerm)();
1367 pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");
1368 if (pTs4mayuTerm() == true)
1369 FreeLibrary(*i_pTs4mayu);
1371 m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;
1378 m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;
1382 if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0)
1384 m_log << _T("load ") << i_ts4mayuDllName
1385 << _T(" failed: can't find ") << i_dependDllName
1390 *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);
1391 if (*i_pTs4mayu == NULL)
1393 m_log << _T("load ") << i_ts4mayuDllName
1394 << _T(" failed: can't find it") << std::endl;
1398 bool (WINAPI *pTs4mayuInit)(UINT);
1400 pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");
1401 if (pTs4mayuInit(m_threadId) == true)
1402 m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;
1404 m_log << i_ts4mayuDllName
1405 <<_T(" load failed: can't initialize") << std::endl;
1414 bool Engine::setSetting(Setting *i_setting)
1417 if (m_isSynchronizing)
1422 for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();
1425 Key *key = i_setting->m_keyboard.searchKey(*(*i));
1428 key->m_isPressed = (*i)->m_isPressed;
1429 key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;
1430 key->m_isPressedByAssign = (*i)->m_isPressedByAssign;
1433 if (m_lastGeneratedKey)
1434 m_lastGeneratedKey =
1435 i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);
1436 for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)
1437 if (m_lastPressedKey[i])
1438 m_lastPressedKey[i] =
1439 i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);
1442 m_setting = i_setting;
1444 manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),
1445 m_setting->m_sts4mayu, &m_sts4mayu);
1446 manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),
1447 m_setting->m_cts4mayu, &m_cts4mayu);
1449 g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;
1450 if (m_currentFocusOfThread)
1452 for (FocusOfThreads::iterator i = m_focusOfThreads.begin();
1453 i != m_focusOfThreads.end(); i ++)
1455 FocusOfThread *fot = &(*i).second;
1456 m_setting->m_keymaps.searchWindow(&fot->m_keymaps,
1457 fot->m_className, fot->m_titleName);
1460 m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));
1461 if (m_globalFocus.m_keymaps.empty())
1463 Acquire a(&m_log, 0);
1464 m_log << _T("internal error: m_globalFocus.m_keymap is empty")
1467 m_currentFocusOfThread = &m_globalFocus;
1468 setCurrentKeymap(m_globalFocus.m_keymaps.front());
1474 void Engine::checkShow(HWND i_hwnd)
1476 // update show style of window
1477 // this update should be done in hook DLL, but to
1478 // avoid update-loss for some applications(such as
1479 // cmd.exe), we update here.
1480 bool isMaximized = false;
1481 bool isMinimized = false;
1482 bool isMDIMaximized = false;
1483 bool isMDIMinimized = false;
1487 LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);
1489 LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);
1491 if (exStyle & WS_EX_MDICHILD)
1493 WINDOWPLACEMENT placement;
1494 placement.length = sizeof(WINDOWPLACEMENT);
1495 if (GetWindowPlacement(i_hwnd, &placement))
1497 switch (placement.showCmd)
1499 case SW_SHOWMAXIMIZED:
1500 isMDIMaximized = true;
1502 case SW_SHOWMINIMIZED:
1503 isMDIMinimized = true;
1513 LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);
1515 LONG style = GetWindowLong(i_hwnd, GWL_STYLE);
1517 if ((style & WS_CHILD) == 0)
1519 WINDOWPLACEMENT placement;
1520 placement.length = sizeof(WINDOWPLACEMENT);
1521 if (GetWindowPlacement(i_hwnd, &placement))
1523 switch (placement.showCmd)
1525 case SW_SHOWMAXIMIZED:
1528 case SW_SHOWMINIMIZED:
1537 i_hwnd = GetParent(i_hwnd);
1539 setShow(isMDIMaximized, isMDIMinimized, true);
1540 setShow(isMaximized, isMinimized, false);
1545 bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId,
1546 const tstringi &i_className, const tstringi &i_titleName,
1550 if (m_isSynchronizing)
1552 if (i_hwndFocus == NULL)
1555 // remove newly created thread's id from m_detachedThreadIds
1556 if (!m_detachedThreadIds.empty())
1558 DetachedThreadIds::iterator i;
1563 for (i = m_detachedThreadIds.begin();
1564 i != m_detachedThreadIds.end(); ++ i)
1565 if (*i == i_threadId)
1567 m_detachedThreadIds.erase(i);
1575 FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);
1576 if (i != m_focusOfThreads.end())
1579 if (fot->m_hwndFocus == i_hwndFocus &&
1580 fot->m_isConsole == i_isConsole &&
1581 fot->m_className == i_className &&
1582 fot->m_titleName == i_titleName)
1587 i = m_focusOfThreads.insert(
1588 FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;
1590 fot->m_threadId = i_threadId;
1592 fot->m_hwndFocus = i_hwndFocus;
1593 fot->m_isConsole = i_isConsole;
1594 fot->m_className = i_className;
1595 fot->m_titleName = i_titleName;
1599 m_setting->m_keymaps.searchWindow(&fot->m_keymaps,
1600 i_className, i_titleName);
1601 ASSERT(0 < fot->m_keymaps.size());
1604 fot->m_keymaps.clear();
1605 checkShow(i_hwndFocus);
1611 bool Engine::setLockState(bool i_isNumLockToggled,
1612 bool i_isCapsLockToggled,
1613 bool i_isScrollLockToggled,
1614 bool i_isKanaLockToggled,
1615 bool i_isImeLockToggled,
1616 bool i_isImeCompToggled)
1619 if (m_isSynchronizing)
1621 m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);
1622 m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);
1623 m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);
1624 m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);
1625 m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);
1626 m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);
1632 bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,
1636 if (m_isSynchronizing)
1638 Acquire b(&m_log, 1);
1639 Modifier::Type max, min;
1640 if (i_isMDI == true) {
1641 max = Modifier::Type_MdiMaximized;
1642 min = Modifier::Type_MdiMinimized;
1646 max = Modifier::Type_Maximized;
1647 min = Modifier::Type_Minimized;
1649 m_currentLock.on(max, i_isMaximized);
1650 m_currentLock.on(min, i_isMinimized);
1651 m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :
1652 i_isMinimized ? _T("Minimized") : _T("Normal"));
1653 if (i_isMDI == true)
1655 m_log << _T(" (MDI)");
1663 bool Engine::syncNotify()
1666 if (!m_isSynchronizing)
1668 CHECK_TRUE( SetEvent(m_eSync) );
1673 // thread detach notify
1674 bool Engine::threadDetachNotify(DWORD i_threadId)
1677 m_detachedThreadIds.push_back(i_threadId);
1683 void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle)
1686 *o_helpMessage = m_helpMessage;
1687 *o_helpTitle = m_helpTitle;
1692 void Engine::commandNotify(
1693 HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam)
1695 Acquire b(&m_log, 0);
1696 HWND hf = m_hwndFocus;
1700 if (GetWindowThreadProcessId(hf, NULL) ==
1701 GetWindowThreadProcessId(m_hwndAssocWindow, NULL))
1702 return; // inhibit the investigation of MADO TSUKAI NO YUUTSU
1704 const _TCHAR *target = NULL;
1705 int number_target = 0;
1708 target = _T("ToItself");
1709 else if (i_hwnd == GetParent(hf))
1710 target = _T("ToParentWindow");
1713 // Function::toMainWindow
1717 HWND p = GetParent(h);
1723 target = _T("ToMainWindow");
1726 // Function::toOverlappedWindow
1731 LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);
1733 LONG style = GetWindowLong(h, GWL_STYLE);
1735 if ((style & WS_CHILD) == 0)
1740 target = _T("ToOverlappedWindow");
1745 for (number_target = 0; h; number_target ++, h = GetParent(h))
1753 m_log << _T("&PostMessage(");
1757 m_log << number_target;
1758 m_log << _T(", ") << i_message
1759 << _T(", 0x") << std::hex << i_wParam
1760 << _T(", 0x") << i_lParam << _T(") # hwnd = ")
1761 << reinterpret_cast<int>(i_hwnd) << _T(", ")
1762 << _T("message = ") << std::dec;
1763 if (i_message == WM_COMMAND)
1764 m_log << _T("WM_COMMAND, ");
1765 else if (i_message == WM_SYSCOMMAND)
1766 m_log << _T("WM_SYSCOMMAND, ");
1768 m_log << i_message << _T(", ");
1769 m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")
1770 << _T("wID = ") << LOWORD(i_wParam) << _T(", ")
1771 << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;