-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// engine.cpp
-
-
-#include "misc.h"
-
-#include "engine.h"
-#include "errormessage.h"
-#include "hook.h"
-#include "mayurc.h"
-#include "windowstool.h"
-
-#include <iomanip>
-
-#include <process.h>
-
-
-// check focus window
-void Engine::checkFocusWindow()
-{
- int count = 0;
-
- restart:
- count ++;
-
- HWND hwndFore = GetForegroundWindow();
- DWORD threadId = GetWindowThreadProcessId(hwndFore, NULL);
-
- if (hwndFore)
- {
- {
- Acquire a(&m_cs);
- if (m_currentFocusOfThread &&
- m_currentFocusOfThread->m_threadId == threadId &&
- m_currentFocusOfThread->m_hwndFocus == m_hwndFocus)
- return;
-
- m_emacsEditKillLine.reset();
-
- // erase dead thread
- if (!m_detachedThreadIds.empty())
- {
- for (DetachedThreadIds::iterator i = m_detachedThreadIds.begin();
- i != m_detachedThreadIds.end(); i ++)
- {
- FocusOfThreads::iterator j = m_focusOfThreads.find((*i));
- if (j != m_focusOfThreads.end())
- {
- FocusOfThread *fot = &((*j).second);
- Acquire a(&m_log, 1);
- m_log << _T("RemoveThread") << std::endl;
- m_log << _T("\tHWND:\t") << std::hex << (int)fot->m_hwndFocus
- << std::dec << std::endl;
- m_log << _T("\tTHREADID:") << fot->m_threadId << std::endl;
- m_log << _T("\tCLASS:\t") << fot->m_className << std::endl;
- m_log << _T("\tTITLE:\t") << fot->m_titleName << std::endl;
- m_log << std::endl;
- m_focusOfThreads.erase(j);
- }
- }
- m_detachedThreadIds.erase
- (m_detachedThreadIds.begin(), m_detachedThreadIds.end());
- }
-
- FocusOfThreads::iterator i = m_focusOfThreads.find(threadId);
- if (i != m_focusOfThreads.end())
- {
- m_currentFocusOfThread = &((*i).second);
- if (!m_currentFocusOfThread->m_isConsole || 2 <= count)
- {
- if (m_currentFocusOfThread->m_keymaps.empty())
- setCurrentKeymap(NULL);
- else
- setCurrentKeymap(*m_currentFocusOfThread->m_keymaps.begin());
- m_hwndFocus = m_currentFocusOfThread->m_hwndFocus;
- checkShow(m_hwndFocus);
-
- Acquire a(&m_log, 1);
- m_log << _T("FocusChanged") << std::endl;
- m_log << _T("\tHWND:\t")
- << std::hex << (int)m_currentFocusOfThread->m_hwndFocus
- << std::dec << std::endl;
- m_log << _T("\tTHREADID:")
- << m_currentFocusOfThread->m_threadId << std::endl;
- m_log << _T("\tCLASS:\t")
- << m_currentFocusOfThread->m_className << std::endl;
- m_log << _T("\tTITLE:\t")
- << m_currentFocusOfThread->m_titleName << std::endl;
- m_log << std::endl;
- return;
- }
- }
- }
-
- _TCHAR className[GANA_MAX_ATOM_LENGTH];
- if (GetClassName(hwndFore, className, NUMBER_OF(className)))
- {
- if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0)
- {
- _TCHAR titleName[1024];
- if (GetWindowText(hwndFore, titleName, NUMBER_OF(titleName)) == 0)
- titleName[0] = _T('\0');
- setFocus(hwndFore, threadId, className, titleName, true);
- Acquire a(&m_log, 1);
- m_log << _T("HWND:\t") << std::hex << reinterpret_cast<int>(hwndFore)
- << std::dec << std::endl;
- m_log << _T("THREADID:") << threadId << std::endl;
- m_log << _T("CLASS:\t") << className << std::endl;
- m_log << _T("TITLE:\t") << titleName << std::endl << std::endl;
- goto restart;
- }
- }
- }
-
- Acquire a(&m_cs);
- if (m_globalFocus.m_keymaps.empty())
- {
- Acquire a(&m_log, 1);
- m_log << _T("NO GLOBAL FOCUS") << std::endl;
- m_currentFocusOfThread = NULL;
- setCurrentKeymap(NULL);
- }
- else
- {
- if (m_currentFocusOfThread != &m_globalFocus)
- {
- Acquire a(&m_log, 1);
- m_log << _T("GLOBAL FOCUS") << std::endl;
- m_currentFocusOfThread = &m_globalFocus;
- setCurrentKeymap(m_globalFocus.m_keymaps.front());
- }
- }
- m_hwndFocus = NULL;
-}
-
-
-
-// is modifier pressed ?
-bool Engine::isPressed(Modifier::Type i_mt)
-{
- const Keymap::ModAssignments &ma = m_currentKeymap->getModAssignments(i_mt);
- for (Keymap::ModAssignments::const_iterator i = ma.begin();
- i != ma.end(); ++ i)
- if ((*i).m_key->m_isPressed)
- return true;
- return false;
-}
-
-
-// fix modifier key (if fixed, return true)
-bool Engine::fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am)
-{
- // for all modifier ...
- for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)
- {
- // get modifier assignments (list of modifier keys)
- const Keymap::ModAssignments &ma =
- m_currentKeymap->getModAssignments(static_cast<Modifier::Type>(i));
-
- for (Keymap::ModAssignments::const_iterator
- j = ma.begin(); j != ma.end(); ++ j)
- if (io_mkey->m_key == (*j).m_key) // is io_mkey a modifier ?
- {
- {
- Acquire a(&m_log, 1);
- m_log << _T("* Modifier Key") << std::endl;
- }
- // set dontcare for this modifier
- io_mkey->m_modifier.dontcare(static_cast<Modifier::Type>(i));
- *o_am = (*j).m_assignMode;
- return true;
- }
- }
- *o_am = Keymap::AM_notModifier;
- return false;
-}
-
-
-// output to m_log
-void Engine::outputToLog(const Key *i_key, const ModifiedKey &i_mkey,
- int i_debugLevel)
-{
- size_t i;
- Acquire a(&m_log, i_debugLevel);
-
- // output scan codes
- for (i = 0; i < i_key->getScanCodesSize(); ++ i)
- {
- if (i_key->getScanCodes()[i].m_flags & ScanCode::E0) m_log << _T("E0-");
- if (i_key->getScanCodes()[i].m_flags & ScanCode::E1) m_log << _T("E1-");
- if (!(i_key->getScanCodes()[i].m_flags & ScanCode::E0E1))
- m_log << _T(" ");
- m_log << _T("0x") << std::hex << std::setw(2) << std::setfill(_T('0'))
- << static_cast<int>(i_key->getScanCodes()[i].m_scan)
- << std::dec << _T(" ");
- }
-
- if (!i_mkey.m_key) // key corresponds to no phisical key
- {
- m_log << std::endl;
- return;
- }
-
- m_log << _T(" ") << i_mkey << std::endl;
-}
-
-
-// describe bindings
-void Engine::describeBindings()
-{
- Acquire a(&m_log, 0);
-
- Keymap::DescribeParam dp;
- for (KeymapPtrList::iterator i = m_currentFocusOfThread->m_keymaps.begin();
- i != m_currentFocusOfThread->m_keymaps.end(); ++ i)
- (*i)->describe(m_log, &dp);
- m_log << std::endl;
-}
-
-
-// update m_lastPressedKey
-void Engine::updateLastPressedKey(Key *i_key)
-{
- m_lastPressedKey[1] = m_lastPressedKey[0];
- m_lastPressedKey[0] = i_key;
-}
-
-// set current keymap
-void Engine::setCurrentKeymap(const Keymap *i_keymap, bool i_doesAddToHistory)
-{
- if (i_doesAddToHistory)
- {
- m_keymapPrefixHistory.push_back(const_cast<Keymap *>(m_currentKeymap));
- if (MAX_KEYMAP_PREFIX_HISTORY < m_keymapPrefixHistory.size())
- m_keymapPrefixHistory.pop_front();
- }
- else
- m_keymapPrefixHistory.clear();
- m_currentKeymap = i_keymap;
-}
-
-
-// get current modifiers
-Modifier Engine::getCurrentModifiers(Key *i_key, bool i_isPressed)
-{
- Modifier cmods;
- cmods.add(m_currentLock);
-
- cmods.press(Modifier::Type_Shift , isPressed(Modifier::Type_Shift ));
- cmods.press(Modifier::Type_Alt , isPressed(Modifier::Type_Alt ));
- cmods.press(Modifier::Type_Control, isPressed(Modifier::Type_Control));
- cmods.press(Modifier::Type_Windows, isPressed(Modifier::Type_Windows));
- cmods.press(Modifier::Type_Up , !i_isPressed);
- cmods.press(Modifier::Type_Down , i_isPressed);
-
- cmods.press(Modifier::Type_Repeat , false);
- if (m_lastPressedKey[0] == i_key)
- {
- if (i_isPressed)
- cmods.press(Modifier::Type_Repeat, true);
- else
- if (m_lastPressedKey[1] == i_key)
- cmods.press(Modifier::Type_Repeat, true);
- }
-
- for (int i = Modifier::Type_Mod0; i <= Modifier::Type_Mod9; ++ i)
- cmods.press(static_cast<Modifier::Type>(i),
- isPressed(static_cast<Modifier::Type>(i)));
-
- return cmods;
-}
-
-
-// generate keyboard event for a key
-void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)
-{
- // check if key is event
- bool isEvent = false;
- for (Key **e = Event::events; *e; ++ e)
- if (*e == i_key)
- {
- isEvent = true;
- break;
- }
-
- bool isAlreadyReleased = false;
-
- if (!isEvent)
- {
- if (i_doPress && !i_key->m_isPressedOnWin32)
- ++ m_currentKeyPressCountOnWin32;
- else if (!i_doPress)
- {
- if (i_key->m_isPressedOnWin32)
- -- m_currentKeyPressCountOnWin32;
- else
- isAlreadyReleased = true;
- }
- i_key->m_isPressedOnWin32 = i_doPress;
-
- if (i_isByAssign)
- i_key->m_isPressedByAssign = i_doPress;
-
- Key *sync = m_setting->m_keyboard.getSyncKey();
-
- if (!isAlreadyReleased || i_key == sync)
- {
- KEYBOARD_INPUT_DATA kid = { 0, 0, 0, 0, 0 };
- const ScanCode *sc = i_key->getScanCodes();
- for (size_t i = 0; i < i_key->getScanCodesSize(); ++ i)
- {
- kid.MakeCode = sc[i].m_scan;
- kid.Flags = sc[i].m_flags;
- if (!i_doPress)
- kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
-#ifdef NO_DRIVER
- injectInput(&kid, NULL);
-#else // !NO_DRIVER
- DWORD len;
- WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
- CHECK_TRUE( GetOverlappedResult(m_device, &m_ol, &len, TRUE) );
-#endif // !NO_DRIVER
- }
-
- m_lastGeneratedKey = i_doPress ? i_key : NULL;
- }
- }
-
- {
- Acquire a(&m_log, 1);
- m_log << _T("\t\t =>\t");
- if (isAlreadyReleased)
- m_log << _T("(already released) ");
- }
- ModifiedKey mkey(i_key);
- mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);
- mkey.m_modifier.on(Modifier::Type_Down, i_doPress);
- outputToLog(i_key, mkey, 1);
-}
-
-
-// genete event
-void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)
-{
- // generate
- i_c.m_keymap = i_keymap;
- i_c.m_mkey.m_key = i_event;
- if (const Keymap::KeyAssignment *keyAssign =
- i_c.m_keymap->searchAssignment(i_c.m_mkey))
- {
- {
- Acquire a(&m_log, 1);
- m_log << std::endl << _T(" ")
- << i_event->getName() << std::endl;
- }
- generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);
- }
-}
-
-
-// genete modifier events
-void Engine::generateModifierEvents(const Modifier &i_mod)
-{
- {
- Acquire a(&m_log, 1);
- m_log << _T("* Gen Modifiers\t{") << std::endl;
- }
-
- for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i)
- {
- Keyboard::Mods &mods =
- m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));
-
- if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))
- // no need to process
- ;
- else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))
- // we have to press this modifier
- {
- bool noneIsPressed = true;
- bool noneIsPressedByAssign = true;
- for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i)
- {
- if ((*i)->m_isPressedOnWin32)
- noneIsPressed = false;
- if ((*i)->m_isPressedByAssign)
- noneIsPressedByAssign = false;
- }
- if (noneIsPressed)
- {
- if (noneIsPressedByAssign)
- generateKeyEvent(mods.front(), true, false);
- else
- for (Keyboard::Mods::iterator
- i = mods.begin(); i != mods.end(); ++ i)
- if ((*i)->m_isPressedByAssign)
- generateKeyEvent((*i), true, false);
- }
- }
-
- else
- // we have to release this modifier
- {
- // avoid such sequences as "Alt U-ALt" or "Windows U-Windows"
- if (i == Modifier::Type_Alt || i == Modifier::Type_Windows)
- {
- for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)
- if ((*j) == m_lastGeneratedKey)
- {
- Keyboard::Mods *mods =
- &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);
- if (mods->size() == 0)
- mods = &m_setting->m_keyboard.getModifiers(
- Modifier::Type_Control);
- if (0 < mods->size())
- {
- generateKeyEvent(mods->front(), true, false);
- generateKeyEvent(mods->front(), false, false);
- }
- break;
- }
- }
-
- for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)
- {
- if ((*j)->m_isPressedOnWin32)
- generateKeyEvent((*j), false, false);
- }
- }
- }
-
- {
- Acquire a(&m_log, 1);
- m_log << _T("\t\t}") << std::endl;
- }
-}
-
-
-// generate keyboard events for action
-void Engine::generateActionEvents(const Current &i_c, const Action *i_a,
- bool i_doPress)
-{
- switch (i_a->getType())
- {
- // key
- case Action::Type_key:
- {
- const ModifiedKey &mkey
- = reinterpret_cast<ActionKey *>(
- const_cast<Action *>(i_a))->m_modifiedKey;
-
- // release
- if (!i_doPress &&
- (mkey.m_modifier.isOn(Modifier::Type_Up) ||
- mkey.m_modifier.isDontcare(Modifier::Type_Up)))
- generateKeyEvent(mkey.m_key, false, true);
-
- // press
- else if (i_doPress &&
- (mkey.m_modifier.isOn(Modifier::Type_Down) ||
- mkey.m_modifier.isDontcare(Modifier::Type_Down)))
- {
- Modifier modifier = mkey.m_modifier;
- modifier.add(i_c.m_mkey.m_modifier);
- generateModifierEvents(modifier);
- generateKeyEvent(mkey.m_key, true, true);
- }
- break;
- }
-
- // keyseq
- case Action::Type_keySeq:
- {
- const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);
- generateKeySeqEvents(i_c, aks->m_keySeq,
- i_doPress ? Part_down : Part_up);
- break;
- }
-
- // function
- case Action::Type_function:
- {
- const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);
- bool is_up = (!i_doPress &&
- (af->m_modifier.isOn(Modifier::Type_Up) ||
- af->m_modifier.isDontcare(Modifier::Type_Up)));
- bool is_down = (i_doPress &&
- (af->m_modifier.isOn(Modifier::Type_Down) ||
- af->m_modifier.isDontcare(Modifier::Type_Down)));
-
- if (!is_down && !is_up)
- break;
-
- {
- Acquire a(&m_log, 1);
- m_log << _T("\t\t >\t") << af->m_functionData;
- }
-
- FunctionParam param;
- param.m_isPressed = i_doPress;
- param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;
- param.m_c = i_c;
- param.m_doesNeedEndl = true;
- param.m_af = af;
-
- param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);
- param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);
-
- af->m_functionData->exec(this, ¶m);
-
- if (param.m_doesNeedEndl)
- {
- Acquire a(&m_log, 1);
- m_log << std::endl;
- }
- break;
- }
- }
-}
-
-
-// generate keyboard events for keySeq
-void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,
- Part i_part)
-{
- const KeySeq::Actions &actions = i_keySeq->getActions();
- if (actions.empty())
- return;
- if (i_part == Part_up)
- generateActionEvents(i_c, actions[actions.size() - 1], false);
- else
- {
- size_t i;
- for (i = 0 ; i < actions.size() - 1; ++ i)
- {
- generateActionEvents(i_c, actions[i], true);
- generateActionEvents(i_c, actions[i], false);
- }
- generateActionEvents(i_c, actions[i], true);
- if (i_part == Part_all)
- generateActionEvents(i_c, actions[i], false);
- }
-}
-
-
-// generate keyboard events for current key
-void Engine::generateKeyboardEvents(const Current &i_c)
-{
- if (++ m_generateKeyboardEventsRecursionGuard ==
- MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT)
- {
- Acquire a(&m_log);
- m_log << _T("error: too deep keymap recursion. there may be a loop.")
- << std::endl;
- return;
- }
-
- const Keymap::KeyAssignment *keyAssign
- = i_c.m_keymap->searchAssignment(i_c.m_mkey);
- if (!keyAssign)
- {
- const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();
- ASSERT( keySeq );
- generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);
- }
- else
- {
- if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||
- keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))
- generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);
- else
- generateKeySeqEvents(i_c, keyAssign->m_keySeq,
- i_c.isPressed() ? Part_down : Part_up);
- }
- m_generateKeyboardEventsRecursionGuard --;
-}
-
-
-// generate keyboard events for current key
-void Engine::beginGeneratingKeyboardEvents(
- const Current &i_c, bool i_isModifier)
-{
- // (1) (2) (3) (4) (1)
- // up/down: D- U- D- U- D-
- // keymap: m_currentKeymap m_currentKeymap X X m_currentKeymap
- // memo: &Prefix(X) ... ... ... ...
- // m_isPrefix: false true true false false
-
- Current cnew(i_c);
-
- bool isPhysicallyPressed
- = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);
-
- // substitute
- ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);
- if (mkey.m_key)
- {
- cnew.m_mkey = mkey;
- if (isPhysicallyPressed)
- {
- cnew.m_mkey.m_modifier.off(Modifier::Type_Up);
- cnew.m_mkey.m_modifier.on(Modifier::Type_Down);
- }
- else
- {
- cnew.m_mkey.m_modifier.on(Modifier::Type_Up);
- cnew.m_mkey.m_modifier.off(Modifier::Type_Down);
- }
- for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i)
- {
- Modifier::Type type = static_cast<Modifier::Type>(i);
- if (cnew.m_mkey.m_modifier.isDontcare(type) &&
- !i_c.m_mkey.m_modifier.isDontcare(type))
- cnew.m_mkey.m_modifier.press(
- type, i_c.m_mkey.m_modifier.isPressed(type));
- }
-
- {
- Acquire a(&m_log, 1);
- m_log << _T("* substitute") << std::endl;
- }
- outputToLog(mkey.m_key, cnew.m_mkey, 1);
- }
-
- // for prefix key
- const Keymap *tmpKeymap = m_currentKeymap;
- if (i_isModifier || !m_isPrefix) ;
- else if (isPhysicallyPressed) // when (3)
- m_isPrefix = false;
- else if (!isPhysicallyPressed) // when (2)
- m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();
-
- // for m_emacsEditKillLine function
- m_emacsEditKillLine.m_doForceReset = !i_isModifier;
-
- // generate key event !
- m_generateKeyboardEventsRecursionGuard = 0;
- if (isPhysicallyPressed)
- generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);
- generateKeyboardEvents(cnew);
- if (!isPhysicallyPressed)
- generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);
-
- // for m_emacsEditKillLine function
- if (m_emacsEditKillLine.m_doForceReset)
- m_emacsEditKillLine.reset();
-
- // for prefix key
- if (i_isModifier)
- ;
- else if (!m_isPrefix) // when (1), (4)
- m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();
- else if (!isPhysicallyPressed) // when (2)
- m_currentKeymap = tmpKeymap;
-}
-
-
-#ifdef NO_DRIVER
-unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)
-{
- INPUT kid;
- kid.type = INPUT_KEYBOARD;
- kid.ki.wVk = 0;
- kid.ki.wScan = i_kid->MakeCode;
- kid.ki.dwFlags = KEYEVENTF_SCANCODE;
- kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;
- kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;
- if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK)
- {
- kid.ki.dwFlags |= KEYEVENTF_KEYUP;
- }
- if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0)
- {
- kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
- }
- SendInput(1, &kid, sizeof(kid));
- return 1;
-}
-#endif // NO_DRIVER
-
-
-// pop all pressed key on win32
-void Engine::keyboardResetOnWin32()
-{
- for (Keyboard::KeyIterator
- i = m_setting->m_keyboard.getKeyIterator(); *i; ++ i)
- {
- if ((*i)->m_isPressedOnWin32)
- generateKeyEvent((*i), false, true);
- }
-}
-
-
-#ifdef NO_DRIVER
-unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, KBDLLHOOKSTRUCT *i_kid)
-{
- return i_this->keyboardDetour(i_kid);
-}
-
-unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)
-{
-#if 0
- Acquire a(&m_log, 1);
- m_log << std::hex
- << _T("keyboardDetour: vkCode=") << i_kid->vkCode
- << _T(" scanCode=") << i_kid->scanCode
- << _T(" flags=") << i_kid->flags << std::endl;
-#endif
- if (i_kid->flags & LLKHF_INJECTED)
- {
- return 0;
- }
- else
- {
- Key key;
- KEYBOARD_INPUT_DATA kid;
-
- kid.UnitId = 0;
- kid.MakeCode = i_kid->scanCode;
- kid.Flags = 0;
- if (i_kid->flags & LLKHF_UP)
- {
- kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;
- }
- if (i_kid->flags & LLKHF_EXTENDED)
- {
- kid.Flags |= KEYBOARD_INPUT_DATA::E0;
- }
- kid.Reserved = 0;
- kid.ExtraInformation = 0;
-
- Acquire a(&m_cskidq);
- m_kidq.push_back(kid);
- SetEvent(m_readEvent);
- return 1;
- }
-}
-#endif // NO_DRIVER
-
-// keyboard handler thread
-unsigned int WINAPI Engine::keyboardHandler(void *i_this)
-{
- reinterpret_cast<Engine *>(i_this)->keyboardHandler();
- _endthreadex(0);
- return 0;
-}
-void Engine::keyboardHandler()
-{
- // initialize ok
- CHECK_TRUE( SetEvent(m_threadEvent) );
-
- // loop
- Key key;
- while (!m_doForceTerminate)
- {
- KEYBOARD_INPUT_DATA kid;
-
-#ifndef NO_DRIVER
- DWORD len;
-#endif // !NO_DRIVER
- {
- Acquire a(&m_log, 1);
- m_log << _T("begin ReadFile();") << std::endl;
- }
-#ifdef NO_DRIVER
- if (1)
- {
-#else // !NO_DRIVER
- if (!ReadFile(m_device, &kid, sizeof(kid), &len, &m_ol))
- {
- if (GetLastError() != ERROR_IO_PENDING)
- continue;
-#endif // !NO_DRIVER
-
- HANDLE handles[] = { m_readEvent, m_interruptThreadEvent };
- rewait:
- switch (MsgWaitForMultipleObjects(NUMBER_OF(handles), &handles[0],
- FALSE, INFINITE, QS_POSTMESSAGE))
- {
- case WAIT_OBJECT_0: // m_readEvent
-#ifdef NO_DRIVER
- {
- Acquire a(&m_cskidq);
- if (m_kidq.empty())
- {
- goto rewait;
- }
- kid = m_kidq.front();
- m_kidq.pop_front();
- if (!m_kidq.empty())
- {
- SetEvent(m_readEvent);
- }
- }
-#else // !NO_DRIVER
- if (!GetOverlappedResult(m_device, &m_ol, &len, FALSE))
- continue;
-#endif // !NO_DRIVER
- break;
-
- case WAIT_OBJECT_0 + 1: // m_interruptThreadEvent
- CancelIo(m_device);
- switch (m_interruptThreadReason) {
- default: {
- ASSERT( false );
- Acquire a(&m_log, 0);
- m_log << _T("internal error: m_interruptThreadReason == ")
- << m_interruptThreadReason << std::endl;
- break;
- }
-
- case InterruptThreadReason_Terminate:
- goto break_while;
-
- case InterruptThreadReason_Pause: {
- CHECK_TRUE( SetEvent(m_threadEvent) );
- while (WaitForMultipleObjects(1, &m_interruptThreadEvent,
- FALSE, INFINITE) != WAIT_OBJECT_0)
- ;
- switch (m_interruptThreadReason) {
- case InterruptThreadReason_Terminate:
- goto break_while;
-
- case InterruptThreadReason_Resume:
- break;
-
- default:
- ASSERT( false );
- break;
- }
- CHECK_TRUE( SetEvent(m_threadEvent) );
- break;
- }
- }
- break;
-
- case WAIT_OBJECT_0 + NUMBER_OF(handles):
- {
- MSG message;
-
- while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
- {
- switch (message.message)
- {
- case WM_APP + 201:
- {
- if (message.wParam)
- {
- m_currentLock.on(Modifier::Type_Touchpad);
- m_currentLock.on(Modifier::Type_TouchpadSticky);
- }
- else
- m_currentLock.off(Modifier::Type_Touchpad);
- Acquire a(&m_log, 1);
- m_log << _T("touchpad: ") << message.wParam
- << _T(".") << (message.lParam & 0xffff)
- << _T(".") << (message.lParam >> 16 & 0xffff)
- << std::endl;
- break;
- }
- default:
- break;
- }
- }
- goto rewait;
- }
-
- default:
- ASSERT( false );
- continue;
- }
- }
- {
- Acquire a(&m_log, 1);
- m_log << _T("end ReadFile();") << std::endl;
- }
-
- checkFocusWindow();
-
- if (!m_setting || // m_setting has not been loaded
- !m_isEnabled) // disabled
- {
- if (m_isLogMode)
- {
- Key key;
- key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));
- outputToLog(&key, ModifiedKey(), 0);
- }
- else
- {
-#ifdef NO_DRIVER
- injectInput(&kid, NULL);
-#else // !NO_DRIVER
- WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
- GetOverlappedResult(m_device, &m_ol, &len, TRUE);
-#endif // !NO_DRIVER
- }
- updateLastPressedKey(NULL);
- continue;
- }
-
- Acquire a(&m_cs);
-
- if (!m_currentFocusOfThread ||
- !m_currentKeymap)
- {
-#ifndef NO_DRIVER
- WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);
- GetOverlappedResult(m_device, &m_ol, &len, TRUE);
-#endif // !NO_DRIVER
- Acquire a(&m_log, 0);
- if (!m_currentFocusOfThread)
- m_log << _T("internal error: m_currentFocusOfThread == NULL")
- << std::endl;
- if (!m_currentKeymap)
- m_log << _T("internal error: m_currentKeymap == NULL")
- << std::endl;
- updateLastPressedKey(NULL);
- continue;
- }
-
- Current c;
- c.m_keymap = m_currentKeymap;
- c.m_i = m_currentFocusOfThread->m_keymaps.begin();
-
- // search key
- key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));
- c.m_mkey = m_setting->m_keyboard.searchKey(key);
- if (!c.m_mkey.m_key)
- {
- c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);
- if (c.m_mkey.m_key)
- continue;
- }
-
- // press the key and update counter
- bool isPhysicallyPressed
- = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);
- if (c.m_mkey.m_key)
- {
- if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)
- ++ m_currentKeyPressCount;
- else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)
- -- m_currentKeyPressCount;
- c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;
- }
-
- // create modifiers
- c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,
- isPhysicallyPressed);
- Keymap::AssignMode am;
- bool isModifier = fixModifierKey(&c.m_mkey, &am);
- if (m_isPrefix)
- {
- if (isModifier && m_doesIgnoreModifierForPrefix)
- am = Keymap::AM_true;
- if (m_doesEditNextModifier)
- {
- Modifier modifier = m_modifierForNextKey;
- modifier.add(c.m_mkey.m_modifier);
- c.m_mkey.m_modifier = modifier;
- }
- }
-
- if (m_isLogMode)
- outputToLog(&key, c.m_mkey, 0);
- else if (am == Keymap::AM_true)
- {
- {
- Acquire a(&m_log, 1);
- m_log << _T("* true modifier") << std::endl;
- }
- // true modifier doesn't generate scan code
- outputToLog(&key, c.m_mkey, 1);
- }
- else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable)
- {
- {
- Acquire a(&m_log, 1);
- if (am == Keymap::AM_oneShot)
- m_log << _T("* one shot modifier") << std::endl;
- else
- m_log << _T("* one shot repeatable modifier") << std::endl;
- }
- // oneShot modifier doesn't generate scan code
- outputToLog(&key, c.m_mkey, 1);
- if (isPhysicallyPressed)
- {
- if (am == Keymap::AM_oneShotRepeatable // the key is repeating
- && m_oneShotKey.m_key == c.m_mkey.m_key)
- {
- if (m_oneShotRepeatableRepeatCount <
- m_setting->m_oneShotRepeatableDelay) {
- ; // delay
- } else {
- Current cnew = c;
- beginGeneratingKeyboardEvents(cnew, false);
- }
- ++ m_oneShotRepeatableRepeatCount;
- } else {
- m_oneShotKey = c.m_mkey;
- m_oneShotRepeatableRepeatCount = 0;
- }
- }
- else
- {
- if (m_oneShotKey.m_key)
- {
- Current cnew = c;
- cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;
- cnew.m_mkey.m_modifier.off(Modifier::Type_Up);
- cnew.m_mkey.m_modifier.on(Modifier::Type_Down);
- beginGeneratingKeyboardEvents(cnew, false);
-
- cnew = c;
- cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;
- cnew.m_mkey.m_modifier.on(Modifier::Type_Up);
- cnew.m_mkey.m_modifier.off(Modifier::Type_Down);
- beginGeneratingKeyboardEvents(cnew, false);
- }
- m_oneShotKey.m_key = NULL;
- m_oneShotRepeatableRepeatCount = 0;
- }
- }
- else if (c.m_mkey.m_key)
- // normal key
- {
- outputToLog(&key, c.m_mkey, 1);
- if (isPhysicallyPressed)
- m_oneShotKey.m_key = NULL;
- beginGeneratingKeyboardEvents(c, isModifier);
- }
-
- // if counter is zero, reset modifiers and keys on win32
- if (m_currentKeyPressCount <= 0)
- {
- {
- Acquire a(&m_log, 1);
- m_log << _T("* No key is pressed") << std::endl;
- }
- generateModifierEvents(Modifier());
- if (0 < m_currentKeyPressCountOnWin32)
- keyboardResetOnWin32();
- m_currentKeyPressCount = 0;
- m_currentKeyPressCountOnWin32 = 0;
- m_oneShotKey.m_key = NULL;
- if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)
- m_currentLock.off(Modifier::Type_TouchpadSticky);
- }
-
- key.initialize();
- updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);
- }
- break_while:
- CHECK_TRUE( SetEvent(m_threadEvent) );
-}
-
-
-Engine::Engine(tomsgstream &i_log)
- : m_hwndAssocWindow(NULL),
- m_setting(NULL),
- m_device(INVALID_HANDLE_VALUE),
- m_didMayuStartDevice(false),
- m_threadEvent(NULL),
- m_mayudVersion(_T("unknown")),
- m_readEvent(NULL),
- m_interruptThreadEvent(NULL),
- m_sts4mayu(NULL),
- m_cts4mayu(NULL),
- m_doForceTerminate(false),
- m_isLogMode(false),
- m_isEnabled(true),
- m_isSynchronizing(false),
- m_eSync(NULL),
- m_generateKeyboardEventsRecursionGuard(0),
- m_currentKeyPressCount(0),
- m_currentKeyPressCountOnWin32(0),
- m_lastGeneratedKey(NULL),
- m_oneShotRepeatableRepeatCount(0),
- m_isPrefix(false),
- m_currentKeymap(NULL),
- m_currentFocusOfThread(NULL),
- m_hwndFocus(NULL),
- m_afShellExecute(NULL),
- m_variable(0),
- m_log(i_log)
-{
- for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)
- m_lastPressedKey[i] = NULL;
-
- // set default lock state
- for (int i = 0; i < Modifier::Type_end; ++ i)
- m_currentLock.dontcare(static_cast<Modifier::Type>(i));
- for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)
- m_currentLock.release(static_cast<Modifier::Type>(i));
-
-#ifndef NO_DRIVER
- if (!open()) {
- throw ErrorMessage() << loadString(IDS_driverNotInstalled);
- }
-#endif // !NO_DRIVER
-
-#ifndef NO_DRIVER
- {
- TCHAR versionBuf[256];
- DWORD length = 0;
-
- if (DeviceIoControl(m_device, IOCTL_MAYU_GET_VERSION, NULL, 0,
- versionBuf, sizeof(versionBuf), &length, NULL)
- && length
- && length < sizeof(versionBuf)) // fail safe
- m_mayudVersion = tstring(versionBuf, length / 2);
- }
-#endif // !NO_DRIVER
- // create event for sync
- CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );
- // create named pipe for &SetImeString
- m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),
- PIPE_ACCESS_OUTBOUND,
- PIPE_TYPE_BYTE, 1,
- 0, 0, 0, NULL);
- StrExprArg::setEngine(this);
-}
-
-
-// open mayu device
-bool Engine::open()
-{
- // open mayu m_device
-#ifndef NO_DRIVER
- m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
-#endif // !NO_DRIVER
-
- if (m_device != INVALID_HANDLE_VALUE) {
- return true;
- }
-
-#ifndef NO_DRIVER
- // start mayud
- SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
- if (hscm)
- {
- SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_START);
- if (hs)
- {
- StartService(hs, 0, NULL);
- CloseServiceHandle(hs);
- m_didMayuStartDevice = true;
- }
- CloseServiceHandle(hscm);
- }
-
- // open mayu m_device
- m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
- 0, NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
-#endif // !NO_DRIVER
- return (m_device != INVALID_HANDLE_VALUE);
-}
-
-
-// close mayu device
-void Engine::close()
-{
- if (m_device != INVALID_HANDLE_VALUE) {
-#ifndef NO_DRIVER
- CHECK_TRUE( CloseHandle(m_device) );
-#endif // !NO_DRIVER
- }
- m_device = INVALID_HANDLE_VALUE;
-}
-
-
-// start keyboard handler thread
-void Engine::start()
-{
- CHECK_TRUE( m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
-
- CHECK_TRUE( m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
- CHECK_TRUE( m_interruptThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );
- m_ol.Offset = 0;
- m_ol.OffsetHigh = 0;
- m_ol.hEvent = m_readEvent;
-
- CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );
- CHECK( WAIT_OBJECT_0 ==, WaitForSingleObject(m_threadEvent, INFINITE) );
-}
-
-
-// stop keyboard handler thread
-void Engine::stop()
-{
- if (m_threadEvent)
- {
- m_doForceTerminate = true;
- do
- {
- m_interruptThreadReason = InterruptThreadReason_Terminate;
- SetEvent(m_interruptThreadEvent);
- //DWORD buf;
- //M_DeviceIoControl(m_device, IOCTL_MAYU_DETOUR_CANCEL,
- // &buf, sizeof(buf), &buf, sizeof(buf), &buf, NULL);
-
- // wait for message handler thread terminate
- } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
- CHECK_TRUE( CloseHandle(m_threadEvent) );
- m_threadEvent = NULL;
- WaitForSingleObject(m_threadHandle, 100);
- CHECK_TRUE( CloseHandle(m_threadHandle) );
- m_threadHandle = NULL;
-
- // stop mayud
- if (m_didMayuStartDevice)
- {
- SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
- if (hscm)
- {
- SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_STOP);
- if (hs)
- {
- SERVICE_STATUS ss;
- ControlService(hs, SERVICE_CONTROL_STOP, &ss);
- CloseServiceHandle(hs);
- }
- CloseServiceHandle(hscm);
- }
- }
-
- CHECK_TRUE( CloseHandle(m_readEvent) );
- m_readEvent = NULL;
- CHECK_TRUE( CloseHandle(m_interruptThreadEvent) );
- m_interruptThreadEvent = NULL;
- }
-}
-
-bool Engine::pause()
-{
- if (m_device != INVALID_HANDLE_VALUE) {
- do {
- m_interruptThreadReason = InterruptThreadReason_Pause;
- SetEvent(m_interruptThreadEvent);
- } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
-#ifndef NO_DRIVER
- close();
-#endif // !NO_DRIVER
- }
- return true;
-}
-
-
-bool Engine::resume()
-{
- if (m_device == INVALID_HANDLE_VALUE) {
-#ifndef NO_DRIVER
- if (!open()) {
- return false; // FIXME
- }
-#endif // !NO_DRIVER
- do {
- m_interruptThreadReason = InterruptThreadReason_Resume;
- SetEvent(m_interruptThreadEvent);
- } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);
- }
- return true;
-}
-
-
-bool Engine::prepairQuit()
-{
- // terminate and unload DLL for ThumbSense support if loaded
- manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),
- false, &m_sts4mayu);
- manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),
- false, &m_cts4mayu);
- return true;
-}
-
-
-Engine::~Engine()
-{
- stop();
- CHECK_TRUE( CloseHandle(m_eSync) );
-
- // close m_device
-#ifndef NO_DRIVER
- close();
-#endif // !NO_DRIVER
- // destroy named pipe for &SetImeString
- if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE)
- {
- DisconnectNamedPipe(m_hookPipe);
- CHECK_TRUE( CloseHandle(m_hookPipe) );
- }
-}
-
-
-void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,
- TCHAR *i_dependDllName,
- bool i_load, HMODULE *i_pTs4mayu)
-{
- Acquire a(&m_log, 0);
-
- if (i_load == false)
- {
- if (*i_pTs4mayu)
- {
- bool (WINAPI *pTs4mayuTerm)();
-
- pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");
- if (pTs4mayuTerm() == true)
- FreeLibrary(*i_pTs4mayu);
- *i_pTs4mayu = NULL;
- m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;
- }
- }
- else
- {
- if (*i_pTs4mayu)
- {
- m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;
- }
- else
- {
- if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0)
- {
- m_log << _T("load ") << i_ts4mayuDllName
- << _T(" failed: can't find ") << i_dependDllName
- << std::endl;
- }
- else
- {
- *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);
- if (*i_pTs4mayu == NULL)
- {
- m_log << _T("load ") << i_ts4mayuDllName
- << _T(" failed: can't find it") << std::endl;
- }
- else
- {
- bool (WINAPI *pTs4mayuInit)(UINT);
-
- pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");
- if (pTs4mayuInit(m_threadId) == true)
- m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;
- else
- m_log << i_ts4mayuDllName
- <<_T(" load failed: can't initialize") << std::endl;
- }
- }
- }
- }
-}
-
-
-// set m_setting
-bool Engine::setSetting(Setting *i_setting)
-{
- Acquire a(&m_cs);
- if (m_isSynchronizing)
- return false;
-
- if (m_setting)
- {
- for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();
- *i; ++ i)
- {
- Key *key = i_setting->m_keyboard.searchKey(*(*i));
- if (key)
- {
- key->m_isPressed = (*i)->m_isPressed;
- key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;
- key->m_isPressedByAssign = (*i)->m_isPressedByAssign;
- }
- }
- if (m_lastGeneratedKey)
- m_lastGeneratedKey =
- i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);
- for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)
- if (m_lastPressedKey[i])
- m_lastPressedKey[i] =
- i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);
- }
-
- m_setting = i_setting;
-
- manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),
- m_setting->m_sts4mayu, &m_sts4mayu);
- manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),
- m_setting->m_cts4mayu, &m_cts4mayu);
-
- g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;
- if (m_currentFocusOfThread)
- {
- for (FocusOfThreads::iterator i = m_focusOfThreads.begin();
- i != m_focusOfThreads.end(); i ++)
- {
- FocusOfThread *fot = &(*i).second;
- m_setting->m_keymaps.searchWindow(&fot->m_keymaps,
- fot->m_className, fot->m_titleName);
- }
- }
- m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));
- if (m_globalFocus.m_keymaps.empty())
- {
- Acquire a(&m_log, 0);
- m_log << _T("internal error: m_globalFocus.m_keymap is empty")
- << std::endl;
- }
- m_currentFocusOfThread = &m_globalFocus;
- setCurrentKeymap(m_globalFocus.m_keymaps.front());
- m_hwndFocus = NULL;
- return true;
-}
-
-
-void Engine::checkShow(HWND i_hwnd)
-{
- // update show style of window
- // this update should be done in hook DLL, but to
- // avoid update-loss for some applications(such as
- // cmd.exe), we update here.
- bool isMaximized = false;
- bool isMinimized = false;
- bool isMDIMaximized = false;
- bool isMDIMinimized = false;
- while (i_hwnd)
- {
-#ifdef MAYU64
- LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);
-#else
- LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);
-#endif
- if (exStyle & WS_EX_MDICHILD)
- {
- WINDOWPLACEMENT placement;
- placement.length = sizeof(WINDOWPLACEMENT);
- if (GetWindowPlacement(i_hwnd, &placement))
- {
- switch (placement.showCmd)
- {
- case SW_SHOWMAXIMIZED:
- isMDIMaximized = true;
- break;
- case SW_SHOWMINIMIZED:
- isMDIMinimized = true;
- break;
- case SW_SHOWNORMAL:
- default:
- break;
- }
- }
- }
-
-#ifdef MAYU64
- LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);
-#else
- LONG style = GetWindowLong(i_hwnd, GWL_STYLE);
-#endif
- if ((style & WS_CHILD) == 0)
- {
- WINDOWPLACEMENT placement;
- placement.length = sizeof(WINDOWPLACEMENT);
- if (GetWindowPlacement(i_hwnd, &placement))
- {
- switch (placement.showCmd)
- {
- case SW_SHOWMAXIMIZED:
- isMaximized = true;
- break;
- case SW_SHOWMINIMIZED:
- isMinimized = true;
- break;
- case SW_SHOWNORMAL:
- default:
- break;
- }
- }
- }
- i_hwnd = GetParent(i_hwnd);
- }
- setShow(isMDIMaximized, isMDIMinimized, true);
- setShow(isMaximized, isMinimized, false);
-}
-
-
-// focus
-bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId,
- const tstringi &i_className, const tstringi &i_titleName,
- bool i_isConsole)
-{
- Acquire a(&m_cs);
- if (m_isSynchronizing)
- return false;
- if (i_hwndFocus == NULL)
- return true;
-
- // remove newly created thread's id from m_detachedThreadIds
- if (!m_detachedThreadIds.empty())
- {
- DetachedThreadIds::iterator i;
- bool retry;
- do
- {
- retry = false;
- for (i = m_detachedThreadIds.begin();
- i != m_detachedThreadIds.end(); ++ i)
- if (*i == i_threadId)
- {
- m_detachedThreadIds.erase(i);
- retry = true;
- break;
- }
- } while (retry);
- }
-
- FocusOfThread *fot;
- FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);
- if (i != m_focusOfThreads.end())
- {
- fot = &(*i).second;
- if (fot->m_hwndFocus == i_hwndFocus &&
- fot->m_isConsole == i_isConsole &&
- fot->m_className == i_className &&
- fot->m_titleName == i_titleName)
- return true;
- }
- else
- {
- i = m_focusOfThreads.insert(
- FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;
- fot = &(*i).second;
- fot->m_threadId = i_threadId;
- }
- fot->m_hwndFocus = i_hwndFocus;
- fot->m_isConsole = i_isConsole;
- fot->m_className = i_className;
- fot->m_titleName = i_titleName;
-
- if (m_setting)
- {
- m_setting->m_keymaps.searchWindow(&fot->m_keymaps,
- i_className, i_titleName);
- ASSERT(0 < fot->m_keymaps.size());
- }
- else
- fot->m_keymaps.clear();
- checkShow(i_hwndFocus);
- return true;
-}
-
-
-// lock state
-bool Engine::setLockState(bool i_isNumLockToggled,
- bool i_isCapsLockToggled,
- bool i_isScrollLockToggled,
- bool i_isKanaLockToggled,
- bool i_isImeLockToggled,
- bool i_isImeCompToggled)
-{
- Acquire a(&m_cs);
- if (m_isSynchronizing)
- return false;
- m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);
- m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);
- m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);
- m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);
- m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);
- m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);
- return true;
-}
-
-
-// show
-bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,
- bool i_isMDI)
-{
- Acquire a(&m_cs);
- if (m_isSynchronizing)
- return false;
- Acquire b(&m_log, 1);
- Modifier::Type max, min;
- if (i_isMDI == true) {
- max = Modifier::Type_MdiMaximized;
- min = Modifier::Type_MdiMinimized;
- }
- else
- {
- max = Modifier::Type_Maximized;
- min = Modifier::Type_Minimized;
- }
- m_currentLock.on(max, i_isMaximized);
- m_currentLock.on(min, i_isMinimized);
- m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :
- i_isMinimized ? _T("Minimized") : _T("Normal"));
- if (i_isMDI == true)
- {
- m_log << _T(" (MDI)");
- }
- m_log << std::endl;
- return true;
-}
-
-
-// sync
-bool Engine::syncNotify()
-{
- Acquire a(&m_cs);
- if (!m_isSynchronizing)
- return false;
- CHECK_TRUE( SetEvent(m_eSync) );
- return true;
-}
-
-
-// thread detach notify
-bool Engine::threadDetachNotify(DWORD i_threadId)
-{
- Acquire a(&m_cs);
- m_detachedThreadIds.push_back(i_threadId);
- return true;
-}
-
-
-// get help message
-void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle)
-{
- Acquire a(&m_cs);
- *o_helpMessage = m_helpMessage;
- *o_helpTitle = m_helpTitle;
-}
-
-
-// command notify
-void Engine::commandNotify(
- HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam)
-{
- Acquire b(&m_log, 0);
- HWND hf = m_hwndFocus;
- if (!hf)
- return;
-
- if (GetWindowThreadProcessId(hf, NULL) ==
- GetWindowThreadProcessId(m_hwndAssocWindow, NULL))
- return; // inhibit the investigation of MADO TSUKAI NO YUUTSU
-
- const _TCHAR *target = NULL;
- int number_target = 0;
-
- if (i_hwnd == hf)
- target = _T("ToItself");
- else if (i_hwnd == GetParent(hf))
- target = _T("ToParentWindow");
- else
- {
- // Function::toMainWindow
- HWND h = hf;
- while (true)
- {
- HWND p = GetParent(h);
- if (!p)
- break;
- h = p;
- }
- if (i_hwnd == h)
- target = _T("ToMainWindow");
- else
- {
- // Function::toOverlappedWindow
- HWND h = hf;
- while (h)
- {
-#ifdef MAYU64
- LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);
-#else
- LONG style = GetWindowLong(h, GWL_STYLE);
-#endif
- if ((style & WS_CHILD) == 0)
- break;
- h = GetParent(h);
- }
- if (i_hwnd == h)
- target = _T("ToOverlappedWindow");
- else
- {
- // number
- HWND h = hf;
- for (number_target = 0; h; number_target ++, h = GetParent(h))
- if (i_hwnd == h)
- break;
- return;
- }
- }
- }
-
- m_log << _T("&PostMessage(");
- if (target)
- m_log << target;
- else
- m_log << number_target;
- m_log << _T(", ") << i_message
- << _T(", 0x") << std::hex << i_wParam
- << _T(", 0x") << i_lParam << _T(") # hwnd = ")
- << reinterpret_cast<int>(i_hwnd) << _T(", ")
- << _T("message = ") << std::dec;
- if (i_message == WM_COMMAND)
- m_log << _T("WM_COMMAND, ");
- else if (i_message == WM_SYSCOMMAND)
- m_log << _T("WM_SYSCOMMAND, ");
- else
- m_log << i_message << _T(", ");
- m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")
- << _T("wID = ") << LOWORD(i_wParam) << _T(", ")
- << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;
-}
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
+// engine.cpp\r
+\r
+\r
+#include "misc.h"\r
+\r
+#include "engine.h"\r
+#include "errormessage.h"\r
+#include "hook.h"\r
+#include "mayurc.h"\r
+#include "windowstool.h"\r
+\r
+#include <iomanip>\r
+\r
+#include <process.h>\r
+\r
+\r
+// check focus window\r
+void Engine::checkFocusWindow()\r
+{\r
+ int count = 0;\r
+\r
+restart:\r
+ count ++;\r
+\r
+ HWND hwndFore = GetForegroundWindow();\r
+ DWORD threadId = GetWindowThreadProcessId(hwndFore, NULL);\r
+\r
+ if (hwndFore) {\r
+ {\r
+ Acquire a(&m_cs);\r
+ if (m_currentFocusOfThread &&\r
+ m_currentFocusOfThread->m_threadId == threadId &&\r
+ m_currentFocusOfThread->m_hwndFocus == m_hwndFocus)\r
+ return;\r
+\r
+ m_emacsEditKillLine.reset();\r
+\r
+ // erase dead thread\r
+ if (!m_detachedThreadIds.empty()) {\r
+ for (DetachedThreadIds::iterator i = m_detachedThreadIds.begin();\r
+ i != m_detachedThreadIds.end(); i ++) {\r
+ FocusOfThreads::iterator j = m_focusOfThreads.find((*i));\r
+ if (j != m_focusOfThreads.end()) {\r
+ FocusOfThread *fot = &((*j).second);\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("RemoveThread") << std::endl;\r
+ m_log << _T("\tHWND:\t") << std::hex << (int)fot->m_hwndFocus\r
+ << std::dec << std::endl;\r
+ m_log << _T("\tTHREADID:") << fot->m_threadId << std::endl;\r
+ m_log << _T("\tCLASS:\t") << fot->m_className << std::endl;\r
+ m_log << _T("\tTITLE:\t") << fot->m_titleName << std::endl;\r
+ m_log << std::endl;\r
+ m_focusOfThreads.erase(j);\r
+ }\r
+ }\r
+ m_detachedThreadIds.erase\r
+ (m_detachedThreadIds.begin(), m_detachedThreadIds.end());\r
+ }\r
+\r
+ FocusOfThreads::iterator i = m_focusOfThreads.find(threadId);\r
+ if (i != m_focusOfThreads.end()) {\r
+ m_currentFocusOfThread = &((*i).second);\r
+ if (!m_currentFocusOfThread->m_isConsole || 2 <= count) {\r
+ if (m_currentFocusOfThread->m_keymaps.empty())\r
+ setCurrentKeymap(NULL);\r
+ else\r
+ setCurrentKeymap(*m_currentFocusOfThread->m_keymaps.begin());\r
+ m_hwndFocus = m_currentFocusOfThread->m_hwndFocus;\r
+ checkShow(m_hwndFocus);\r
+\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("FocusChanged") << std::endl;\r
+ m_log << _T("\tHWND:\t")\r
+ << std::hex << (int)m_currentFocusOfThread->m_hwndFocus\r
+ << std::dec << std::endl;\r
+ m_log << _T("\tTHREADID:")\r
+ << m_currentFocusOfThread->m_threadId << std::endl;\r
+ m_log << _T("\tCLASS:\t")\r
+ << m_currentFocusOfThread->m_className << std::endl;\r
+ m_log << _T("\tTITLE:\t")\r
+ << m_currentFocusOfThread->m_titleName << std::endl;\r
+ m_log << std::endl;\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ _TCHAR className[GANA_MAX_ATOM_LENGTH];\r
+ if (GetClassName(hwndFore, className, NUMBER_OF(className))) {\r
+ if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {\r
+ _TCHAR titleName[1024];\r
+ if (GetWindowText(hwndFore, titleName, NUMBER_OF(titleName)) == 0)\r
+ titleName[0] = _T('\0');\r
+ setFocus(hwndFore, threadId, className, titleName, true);\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("HWND:\t") << std::hex << reinterpret_cast<int>(hwndFore)\r
+ << std::dec << std::endl;\r
+ m_log << _T("THREADID:") << threadId << std::endl;\r
+ m_log << _T("CLASS:\t") << className << std::endl;\r
+ m_log << _T("TITLE:\t") << titleName << std::endl << std::endl;\r
+ goto restart;\r
+ }\r
+ }\r
+ }\r
+\r
+ Acquire a(&m_cs);\r
+ if (m_globalFocus.m_keymaps.empty()) {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("NO GLOBAL FOCUS") << std::endl;\r
+ m_currentFocusOfThread = NULL;\r
+ setCurrentKeymap(NULL);\r
+ } else {\r
+ if (m_currentFocusOfThread != &m_globalFocus) {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("GLOBAL FOCUS") << std::endl;\r
+ m_currentFocusOfThread = &m_globalFocus;\r
+ setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
+ }\r
+ }\r
+ m_hwndFocus = NULL;\r
+}\r
+\r
+\r
+\r
+// is modifier pressed ?\r
+bool Engine::isPressed(Modifier::Type i_mt)\r
+{\r
+ const Keymap::ModAssignments &ma = m_currentKeymap->getModAssignments(i_mt);\r
+ for (Keymap::ModAssignments::const_iterator i = ma.begin();\r
+ i != ma.end(); ++ i)\r
+ if ((*i).m_key->m_isPressed)\r
+ return true;\r
+ return false;\r
+}\r
+\r
+\r
+// fix modifier key (if fixed, return true)\r
+bool Engine::fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am)\r
+{\r
+ // for all modifier ...\r
+ for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {\r
+ // get modifier assignments (list of modifier keys)\r
+ const Keymap::ModAssignments &ma =\r
+ m_currentKeymap->getModAssignments(static_cast<Modifier::Type>(i));\r
+\r
+ for (Keymap::ModAssignments::const_iterator\r
+ j = ma.begin(); j != ma.end(); ++ j)\r
+ if (io_mkey->m_key == (*j).m_key) { // is io_mkey a modifier ?\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("* Modifier Key") << std::endl;\r
+ }\r
+ // set dontcare for this modifier\r
+ io_mkey->m_modifier.dontcare(static_cast<Modifier::Type>(i));\r
+ *o_am = (*j).m_assignMode;\r
+ return true;\r
+ }\r
+ }\r
+ *o_am = Keymap::AM_notModifier;\r
+ return false;\r
+}\r
+\r
+\r
+// output to m_log\r
+void Engine::outputToLog(const Key *i_key, const ModifiedKey &i_mkey,\r
+ int i_debugLevel)\r
+{\r
+ size_t i;\r
+ Acquire a(&m_log, i_debugLevel);\r
+\r
+ // output scan codes\r
+ for (i = 0; i < i_key->getScanCodesSize(); ++ i) {\r
+ if (i_key->getScanCodes()[i].m_flags & ScanCode::E0) m_log << _T("E0-");\r
+ if (i_key->getScanCodes()[i].m_flags & ScanCode::E1) m_log << _T("E1-");\r
+ if (!(i_key->getScanCodes()[i].m_flags & ScanCode::E0E1))\r
+ m_log << _T(" ");\r
+ m_log << _T("0x") << std::hex << std::setw(2) << std::setfill(_T('0'))\r
+ << static_cast<int>(i_key->getScanCodes()[i].m_scan)\r
+ << std::dec << _T(" ");\r
+ }\r
+\r
+ if (!i_mkey.m_key) { // key corresponds to no phisical key\r
+ m_log << std::endl;\r
+ return;\r
+ }\r
+\r
+ m_log << _T(" ") << i_mkey << std::endl;\r
+}\r
+\r
+\r
+// describe bindings\r
+void Engine::describeBindings()\r
+{\r
+ Acquire a(&m_log, 0);\r
+\r
+ Keymap::DescribeParam dp;\r
+ for (KeymapPtrList::iterator i = m_currentFocusOfThread->m_keymaps.begin();\r
+ i != m_currentFocusOfThread->m_keymaps.end(); ++ i)\r
+ (*i)->describe(m_log, &dp);\r
+ m_log << std::endl;\r
+}\r
+\r
+\r
+// update m_lastPressedKey\r
+void Engine::updateLastPressedKey(Key *i_key)\r
+{\r
+ m_lastPressedKey[1] = m_lastPressedKey[0];\r
+ m_lastPressedKey[0] = i_key;\r
+}\r
+\r
+// set current keymap\r
+void Engine::setCurrentKeymap(const Keymap *i_keymap, bool i_doesAddToHistory)\r
+{\r
+ if (i_doesAddToHistory) {\r
+ m_keymapPrefixHistory.push_back(const_cast<Keymap *>(m_currentKeymap));\r
+ if (MAX_KEYMAP_PREFIX_HISTORY < m_keymapPrefixHistory.size())\r
+ m_keymapPrefixHistory.pop_front();\r
+ } else\r
+ m_keymapPrefixHistory.clear();\r
+ m_currentKeymap = i_keymap;\r
+}\r
+\r
+\r
+// get current modifiers\r
+Modifier Engine::getCurrentModifiers(Key *i_key, bool i_isPressed)\r
+{\r
+ Modifier cmods;\r
+ cmods.add(m_currentLock);\r
+\r
+ cmods.press(Modifier::Type_Shift , isPressed(Modifier::Type_Shift ));\r
+ cmods.press(Modifier::Type_Alt , isPressed(Modifier::Type_Alt ));\r
+ cmods.press(Modifier::Type_Control, isPressed(Modifier::Type_Control));\r
+ cmods.press(Modifier::Type_Windows, isPressed(Modifier::Type_Windows));\r
+ cmods.press(Modifier::Type_Up , !i_isPressed);\r
+ cmods.press(Modifier::Type_Down , i_isPressed);\r
+\r
+ cmods.press(Modifier::Type_Repeat , false);\r
+ if (m_lastPressedKey[0] == i_key) {\r
+ if (i_isPressed)\r
+ cmods.press(Modifier::Type_Repeat, true);\r
+ else\r
+ if (m_lastPressedKey[1] == i_key)\r
+ cmods.press(Modifier::Type_Repeat, true);\r
+ }\r
+\r
+ for (int i = Modifier::Type_Mod0; i <= Modifier::Type_Mod9; ++ i)\r
+ cmods.press(static_cast<Modifier::Type>(i),\r
+ isPressed(static_cast<Modifier::Type>(i)));\r
+\r
+ return cmods;\r
+}\r
+\r
+\r
+// generate keyboard event for a key\r
+void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)\r
+{\r
+ // check if key is event\r
+ bool isEvent = false;\r
+ for (Key **e = Event::events; *e; ++ e)\r
+ if (*e == i_key) {\r
+ isEvent = true;\r
+ break;\r
+ }\r
+\r
+ bool isAlreadyReleased = false;\r
+\r
+ if (!isEvent) {\r
+ if (i_doPress && !i_key->m_isPressedOnWin32)\r
+ ++ m_currentKeyPressCountOnWin32;\r
+ else if (!i_doPress) {\r
+ if (i_key->m_isPressedOnWin32)\r
+ -- m_currentKeyPressCountOnWin32;\r
+ else\r
+ isAlreadyReleased = true;\r
+ }\r
+ i_key->m_isPressedOnWin32 = i_doPress;\r
+\r
+ if (i_isByAssign)\r
+ i_key->m_isPressedByAssign = i_doPress;\r
+\r
+ Key *sync = m_setting->m_keyboard.getSyncKey();\r
+\r
+ if (!isAlreadyReleased || i_key == sync) {\r
+ KEYBOARD_INPUT_DATA kid = { 0, 0, 0, 0, 0 };\r
+ const ScanCode *sc = i_key->getScanCodes();\r
+ for (size_t i = 0; i < i_key->getScanCodesSize(); ++ i) {\r
+ kid.MakeCode = sc[i].m_scan;\r
+ kid.Flags = sc[i].m_flags;\r
+ if (!i_doPress)\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ injectInput(&kid, NULL);\r
+ }\r
+\r
+ m_lastGeneratedKey = i_doPress ? i_key : NULL;\r
+ }\r
+ }\r
+\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("\t\t =>\t");\r
+ if (isAlreadyReleased)\r
+ m_log << _T("(already released) ");\r
+ }\r
+ ModifiedKey mkey(i_key);\r
+ mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
+ mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
+ outputToLog(i_key, mkey, 1);\r
+}\r
+\r
+\r
+// genete event\r
+void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)\r
+{\r
+ // generate\r
+ i_c.m_keymap = i_keymap;\r
+ i_c.m_mkey.m_key = i_event;\r
+ if (const Keymap::KeyAssignment *keyAssign =\r
+ i_c.m_keymap->searchAssignment(i_c.m_mkey)) {\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << std::endl << _T(" ")\r
+ << i_event->getName() << std::endl;\r
+ }\r
+ generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
+ }\r
+}\r
+\r
+\r
+// genete modifier events\r
+void Engine::generateModifierEvents(const Modifier &i_mod)\r
+{\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("* Gen Modifiers\t{") << std::endl;\r
+ }\r
+\r
+ for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i) {\r
+ Keyboard::Mods &mods =\r
+ m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));\r
+\r
+ if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))\r
+ // no need to process\r
+ ;\r
+ else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))\r
+ // we have to press this modifier\r
+ {\r
+ bool noneIsPressed = true;\r
+ bool noneIsPressedByAssign = true;\r
+ for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i) {\r
+ if ((*i)->m_isPressedOnWin32)\r
+ noneIsPressed = false;\r
+ if ((*i)->m_isPressedByAssign)\r
+ noneIsPressedByAssign = false;\r
+ }\r
+ if (noneIsPressed) {\r
+ if (noneIsPressedByAssign)\r
+ generateKeyEvent(mods.front(), true, false);\r
+ else\r
+ for (Keyboard::Mods::iterator\r
+ i = mods.begin(); i != mods.end(); ++ i)\r
+ if ((*i)->m_isPressedByAssign)\r
+ generateKeyEvent((*i), true, false);\r
+ }\r
+ }\r
+\r
+ else\r
+ // we have to release this modifier\r
+ {\r
+ // avoid such sequences as "Alt U-ALt" or "Windows U-Windows"\r
+ if (i == Modifier::Type_Alt || i == Modifier::Type_Windows) {\r
+ for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)\r
+ if ((*j) == m_lastGeneratedKey) {\r
+ Keyboard::Mods *mods =\r
+ &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);\r
+ if (mods->size() == 0)\r
+ mods = &m_setting->m_keyboard.getModifiers(\r
+ Modifier::Type_Control);\r
+ if (0 < mods->size()) {\r
+ generateKeyEvent(mods->front(), true, false);\r
+ generateKeyEvent(mods->front(), false, false);\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j) {\r
+ if ((*j)->m_isPressedOnWin32)\r
+ generateKeyEvent((*j), false, false);\r
+ }\r
+ }\r
+ }\r
+\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("\t\t}") << std::endl;\r
+ }\r
+}\r
+\r
+\r
+// generate keyboard events for action\r
+void Engine::generateActionEvents(const Current &i_c, const Action *i_a,\r
+ bool i_doPress)\r
+{\r
+ switch (i_a->getType()) {\r
+ // key\r
+ case Action::Type_key: {\r
+ const ModifiedKey &mkey\r
+ = reinterpret_cast<ActionKey *>(\r
+ const_cast<Action *>(i_a))->m_modifiedKey;\r
+\r
+ // release\r
+ if (!i_doPress &&\r
+ (mkey.m_modifier.isOn(Modifier::Type_Up) ||\r
+ mkey.m_modifier.isDontcare(Modifier::Type_Up)))\r
+ generateKeyEvent(mkey.m_key, false, true);\r
+\r
+ // press\r
+ else if (i_doPress &&\r
+ (mkey.m_modifier.isOn(Modifier::Type_Down) ||\r
+ mkey.m_modifier.isDontcare(Modifier::Type_Down))) {\r
+ Modifier modifier = mkey.m_modifier;\r
+ modifier.add(i_c.m_mkey.m_modifier);\r
+ generateModifierEvents(modifier);\r
+ generateKeyEvent(mkey.m_key, true, true);\r
+ }\r
+ break;\r
+ }\r
+\r
+ // keyseq\r
+ case Action::Type_keySeq: {\r
+ const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);\r
+ generateKeySeqEvents(i_c, aks->m_keySeq,\r
+ i_doPress ? Part_down : Part_up);\r
+ break;\r
+ }\r
+\r
+ // function\r
+ case Action::Type_function: {\r
+ const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);\r
+ bool is_up = (!i_doPress &&\r
+ (af->m_modifier.isOn(Modifier::Type_Up) ||\r
+ af->m_modifier.isDontcare(Modifier::Type_Up)));\r
+ bool is_down = (i_doPress &&\r
+ (af->m_modifier.isOn(Modifier::Type_Down) ||\r
+ af->m_modifier.isDontcare(Modifier::Type_Down)));\r
+\r
+ if (!is_down && !is_up)\r
+ break;\r
+\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("\t\t >\t") << af->m_functionData;\r
+ }\r
+\r
+ FunctionParam param;\r
+ param.m_isPressed = i_doPress;\r
+ param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;\r
+ param.m_c = i_c;\r
+ param.m_doesNeedEndl = true;\r
+ param.m_af = af;\r
+\r
+ param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
+ param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
+\r
+ af->m_functionData->exec(this, ¶m);\r
+\r
+ if (param.m_doesNeedEndl) {\r
+ Acquire a(&m_log, 1);\r
+ m_log << std::endl;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+// generate keyboard events for keySeq\r
+void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,\r
+ Part i_part)\r
+{\r
+ const KeySeq::Actions &actions = i_keySeq->getActions();\r
+ if (actions.empty())\r
+ return;\r
+ if (i_part == Part_up)\r
+ generateActionEvents(i_c, actions[actions.size() - 1], false);\r
+ else {\r
+ size_t i;\r
+ for (i = 0 ; i < actions.size() - 1; ++ i) {\r
+ generateActionEvents(i_c, actions[i], true);\r
+ generateActionEvents(i_c, actions[i], false);\r
+ }\r
+ generateActionEvents(i_c, actions[i], true);\r
+ if (i_part == Part_all)\r
+ generateActionEvents(i_c, actions[i], false);\r
+ }\r
+}\r
+\r
+\r
+// generate keyboard events for current key\r
+void Engine::generateKeyboardEvents(const Current &i_c)\r
+{\r
+ if (++ m_generateKeyboardEventsRecursionGuard ==\r
+ MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT) {\r
+ Acquire a(&m_log);\r
+ m_log << _T("error: too deep keymap recursion. there may be a loop.")\r
+ << std::endl;\r
+ return;\r
+ }\r
+\r
+ const Keymap::KeyAssignment *keyAssign\r
+ = i_c.m_keymap->searchAssignment(i_c.m_mkey);\r
+ if (!keyAssign) {\r
+ const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();\r
+ ASSERT( keySeq );\r
+ generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);\r
+ } else {\r
+ if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||\r
+ keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))\r
+ generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
+ else\r
+ generateKeySeqEvents(i_c, keyAssign->m_keySeq,\r
+ i_c.isPressed() ? Part_down : Part_up);\r
+ }\r
+ m_generateKeyboardEventsRecursionGuard --;\r
+}\r
+\r
+\r
+// generate keyboard events for current key\r
+void Engine::beginGeneratingKeyboardEvents(\r
+ const Current &i_c, bool i_isModifier)\r
+{\r
+ // (1) (2) (3) (4) (1)\r
+ // up/down: D- U- D- U- D-\r
+ // keymap: m_currentKeymap m_currentKeymap X X m_currentKeymap\r
+ // memo: &Prefix(X) ... ... ... ...\r
+ // m_isPrefix: false true true false false\r
+\r
+ Current cnew(i_c);\r
+\r
+ bool isPhysicallyPressed\r
+ = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);\r
+\r
+ // substitute\r
+ ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);\r
+ if (mkey.m_key) {\r
+ cnew.m_mkey = mkey;\r
+ if (isPhysicallyPressed) {\r
+ cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
+ cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
+ } else {\r
+ cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
+ cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
+ }\r
+ for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {\r
+ Modifier::Type type = static_cast<Modifier::Type>(i);\r
+ if (cnew.m_mkey.m_modifier.isDontcare(type) &&\r
+ !i_c.m_mkey.m_modifier.isDontcare(type))\r
+ cnew.m_mkey.m_modifier.press(\r
+ type, i_c.m_mkey.m_modifier.isPressed(type));\r
+ }\r
+\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("* substitute") << std::endl;\r
+ }\r
+ outputToLog(mkey.m_key, cnew.m_mkey, 1);\r
+ }\r
+\r
+ // for prefix key\r
+ const Keymap *tmpKeymap = m_currentKeymap;\r
+ if (i_isModifier || !m_isPrefix) ;\r
+ else if (isPhysicallyPressed) // when (3)\r
+ m_isPrefix = false;\r
+ else if (!isPhysicallyPressed) // when (2)\r
+ m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
+\r
+ // for m_emacsEditKillLine function\r
+ m_emacsEditKillLine.m_doForceReset = !i_isModifier;\r
+\r
+ // generate key event !\r
+ m_generateKeyboardEventsRecursionGuard = 0;\r
+ if (isPhysicallyPressed)\r
+ generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);\r
+ generateKeyboardEvents(cnew);\r
+ if (!isPhysicallyPressed)\r
+ generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);\r
+\r
+ // for m_emacsEditKillLine function\r
+ if (m_emacsEditKillLine.m_doForceReset)\r
+ m_emacsEditKillLine.reset();\r
+\r
+ // for prefix key\r
+ if (i_isModifier)\r
+ ;\r
+ else if (!m_isPrefix) // when (1), (4)\r
+ m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
+ else if (!isPhysicallyPressed) // when (2)\r
+ m_currentKeymap = tmpKeymap;\r
+}\r
+\r
+\r
+unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)\r
+{\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::E1) {\r
+ INPUT kid[2];\r
+ int count = 1;\r
+\r
+ kid[0].type = INPUT_MOUSE;\r
+ kid[0].mi.dx = 0;\r
+ kid[0].mi.dy = 0;\r
+ kid[0].mi.time = 0;\r
+ kid[0].mi.mouseData = 0;\r
+ kid[0].mi.dwExtraInfo = 0;\r
+ switch (i_kid->MakeCode) {\r
+ case 1:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;\r
+ } else {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;\r
+ }\r
+ break;\r
+ case 2:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;\r
+ } else {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;\r
+ }\r
+ break;\r
+ case 3:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEUP;\r
+ } else {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;\r
+ }\r
+ break;\r
+ case 4:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ return 1;\r
+ } else {\r
+ kid[0].mi.mouseData = WHEEL_DELTA;\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;\r
+ }\r
+ break;\r
+ case 5:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ return 1;\r
+ } else {\r
+ kid[0].mi.mouseData = -WHEEL_DELTA;\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;\r
+ }\r
+ break;\r
+ case 6:\r
+ kid[0].mi.mouseData = XBUTTON1;\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_XUP;\r
+ } else {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;\r
+ }\r
+ break;\r
+ case 7:\r
+ kid[0].mi.mouseData = XBUTTON2;\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_XUP;\r
+ } else {\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;\r
+ }\r
+ break;\r
+ case 8:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ return 1;\r
+ } else {\r
+ kid[0].mi.mouseData = WHEEL_DELTA;\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;\r
+ }\r
+ break;\r
+ case 9:\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ return 1;\r
+ } else {\r
+ kid[0].mi.mouseData = -WHEEL_DELTA;\r
+ kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;\r
+ }\r
+ break;\r
+ default:\r
+ return 1;\r
+ break;\r
+ }\r
+ if (!(i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) &&\r
+ i_kid->MakeCode != 4 && i_kid->MakeCode != 5 &&\r
+ i_kid->MakeCode != 8 && i_kid->MakeCode != 9) {\r
+ HWND hwnd;\r
+ POINT pt;\r
+\r
+ if (GetCursorPos(&pt) && (hwnd = WindowFromPoint(pt))) {\r
+ _TCHAR className[GANA_MAX_ATOM_LENGTH];\r
+ if (GetClassName(hwnd, className, NUMBER_OF(className))) {\r
+ if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {\r
+ SetForegroundWindow(hwnd);\r
+ }\r
+ }\r
+ }\r
+ if (m_dragging) {\r
+ kid[0].mi.dx = 65535 * m_msllHookCurrent.pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
+ kid[0].mi.dy = 65535 * m_msllHookCurrent.pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
+ kid[0].mi.dwFlags |= MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;\r
+\r
+ kid[1].type = INPUT_MOUSE;\r
+ kid[1].mi.dx = 65535 * pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
+ kid[1].mi.dy = 65535 * pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
+ kid[1].mi.time = 0;\r
+ kid[1].mi.mouseData = 0;\r
+ kid[1].mi.dwExtraInfo = 0;\r
+ kid[1].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;\r
+\r
+ count = 2;\r
+ }\r
+ }\r
+ SendInput(count, &kid[0], sizeof(kid[0]));\r
+ } else {\r
+ INPUT kid;\r
+\r
+ kid.type = INPUT_KEYBOARD;\r
+ kid.ki.wVk = 0;\r
+ kid.ki.wScan = i_kid->MakeCode;\r
+ kid.ki.dwFlags = KEYEVENTF_SCANCODE;\r
+ kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;\r
+ kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ kid.ki.dwFlags |= KEYEVENTF_KEYUP;\r
+ }\r
+ if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0) {\r
+ kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
+ }\r
+ SendInput(1, &kid, sizeof(kid));\r
+ }\r
+ return 1;\r
+}\r
+\r
+\r
+// pop all pressed key on win32\r
+void Engine::keyboardResetOnWin32()\r
+{\r
+ for (Keyboard::KeyIterator\r
+ i = m_setting->m_keyboard.getKeyIterator(); *i; ++ i) {\r
+ if ((*i)->m_isPressedOnWin32)\r
+ generateKeyEvent((*i), false, true);\r
+ }\r
+}\r
+\r
+\r
+unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)\r
+{\r
+ return i_this->keyboardDetour(reinterpret_cast<KBDLLHOOKSTRUCT*>(i_lParam));\r
+}\r
+\r
+unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)\r
+{\r
+#if 0\r
+ Acquire a(&m_log, 1);\r
+ m_log << std::hex\r
+ << _T("keyboardDetour: vkCode=") << i_kid->vkCode\r
+ << _T(" scanCode=") << i_kid->scanCode\r
+ << _T(" flags=") << i_kid->flags << std::endl;\r
+#endif\r
+ if ((i_kid->flags & LLKHF_INJECTED) || !m_isEnabled) {\r
+ return 0;\r
+ } else {\r
+ Key key;\r
+ KEYBOARD_INPUT_DATA kid;\r
+\r
+ kid.UnitId = 0;\r
+ kid.MakeCode = i_kid->scanCode;\r
+ kid.Flags = 0;\r
+ if (i_kid->flags & LLKHF_UP) {\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ }\r
+ if (i_kid->flags & LLKHF_EXTENDED) {\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::E0;\r
+ }\r
+ kid.Reserved = 0;\r
+ kid.ExtraInformation = 0;\r
+\r
+ WaitForSingleObject(m_queueMutex, INFINITE);\r
+ m_inputQueue->push_back(kid);\r
+ SetEvent(m_readEvent);\r
+ ReleaseMutex(m_queueMutex);\r
+ return 1;\r
+ }\r
+}\r
+\r
+unsigned int WINAPI Engine::mouseDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)\r
+{\r
+ return i_this->mouseDetour(i_wParam, reinterpret_cast<MSLLHOOKSTRUCT*>(i_lParam));\r
+}\r
+\r
+unsigned int Engine::mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid)\r
+{\r
+ if (i_mid->flags & LLMHF_INJECTED || !m_isEnabled || !m_setting || !m_setting->m_mouseEvent) {\r
+ return 0;\r
+ } else {\r
+ KEYBOARD_INPUT_DATA kid;\r
+\r
+ kid.UnitId = 0;\r
+ kid.Flags = KEYBOARD_INPUT_DATA::E1;\r
+ kid.Reserved = 0;\r
+ kid.ExtraInformation = 0;\r
+ switch (i_message) {\r
+ case WM_LBUTTONUP:\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ case WM_LBUTTONDOWN:\r
+ kid.MakeCode = 1;\r
+ break;\r
+ case WM_RBUTTONUP:\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ case WM_RBUTTONDOWN:\r
+ kid.MakeCode = 2;\r
+ break;\r
+ case WM_MBUTTONUP:\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ case WM_MBUTTONDOWN:\r
+ kid.MakeCode = 3;\r
+ break;\r
+ case WM_MOUSEWHEEL:\r
+ if (i_mid->mouseData & (1<<31)) {\r
+ kid.MakeCode = 5;\r
+ } else {\r
+ kid.MakeCode = 4;\r
+ }\r
+ break;\r
+ case WM_XBUTTONUP:\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ case WM_XBUTTONDOWN:\r
+ switch ((i_mid->mouseData >> 16) & 0xFFFFU) {\r
+ case XBUTTON1:\r
+ kid.MakeCode = 6;\r
+ break;\r
+ case XBUTTON2:\r
+ kid.MakeCode = 7;\r
+ break;\r
+ default:\r
+ return 0;\r
+ break;\r
+ }\r
+ break;\r
+ case WM_MOUSEHWHEEL:\r
+ if (i_mid->mouseData & (1<<31)) {\r
+ kid.MakeCode = 9;\r
+ } else {\r
+ kid.MakeCode = 8;\r
+ }\r
+ break;\r
+ case WM_MOUSEMOVE: {\r
+ LONG dx = i_mid->pt.x - g_hookData->m_mousePos.x;\r
+ LONG dy = i_mid->pt.y - g_hookData->m_mousePos.y;\r
+ HWND target = reinterpret_cast<HWND>(g_hookData->m_hwndMouseHookTarget);\r
+\r
+ LONG dr = 0;\r
+ dr += (i_mid->pt.x - m_msllHookCurrent.pt.x) * (i_mid->pt.x - m_msllHookCurrent.pt.x);\r
+ dr += (i_mid->pt.y - m_msllHookCurrent.pt.y) * (i_mid->pt.y - m_msllHookCurrent.pt.y);\r
+ if (m_buttonPressed && !m_dragging && m_setting->m_dragThreshold &&\r
+ (m_setting->m_dragThreshold * m_setting->m_dragThreshold < dr)) {\r
+ kid.MakeCode = 0;\r
+ WaitForSingleObject(m_queueMutex, INFINITE);\r
+ m_dragging = true;\r
+ m_inputQueue->push_back(kid);\r
+ SetEvent(m_readEvent);\r
+ ReleaseMutex(m_queueMutex);\r
+ }\r
+\r
+ switch (g_hookData->m_mouseHookType) {\r
+ case MouseHookType_Wheel:\r
+ // For this type, g_hookData->m_mouseHookParam means\r
+ // translate rate mouse move to wheel.\r
+ mouse_event(MOUSEEVENTF_WHEEL, 0, 0,\r
+ g_hookData->m_mouseHookParam * dy, 0);\r
+ return 1;\r
+ break;\r
+ case MouseHookType_WindowMove: {\r
+ RECT curRect;\r
+\r
+ if (!GetWindowRect(target, &curRect))\r
+ return 0;\r
+\r
+ // g_hookData->m_mouseHookParam < 0 means\r
+ // target window to move is MDI.\r
+ if (g_hookData->m_mouseHookParam < 0) {\r
+ HWND parent = GetParent(target);\r
+ POINT p = {curRect.left, curRect.top};\r
+\r
+ if (parent == NULL || !ScreenToClient(parent, &p))\r
+ return 0;\r
+\r
+ curRect.left = p.x;\r
+ curRect.top = p.y;\r
+ }\r
+\r
+ SetWindowPos(target, NULL,\r
+ curRect.left + dx,\r
+ curRect.top + dy,\r
+ 0, 0,\r
+ SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE |\r
+ SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);\r
+ g_hookData->m_mousePos = i_mid->pt;\r
+ return 0;\r
+ break;\r
+ }\r
+ case MouseHookType_None:\r
+ default:\r
+ return 0;\r
+ break;\r
+ }\r
+ }\r
+ case WM_LBUTTONDBLCLK:\r
+ case WM_RBUTTONDBLCLK:\r
+ case WM_MBUTTONDBLCLK:\r
+ case WM_XBUTTONDBLCLK:\r
+ default:\r
+ return 0;\r
+ break;\r
+ }\r
+\r
+ WaitForSingleObject(m_queueMutex, INFINITE);\r
+\r
+ if (kid.Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
+ m_buttonPressed = false;\r
+ if (m_dragging) {\r
+ KEYBOARD_INPUT_DATA kid2;\r
+\r
+ m_dragging = false;\r
+ kid2.UnitId = 0;\r
+ kid2.Flags = KEYBOARD_INPUT_DATA::E1 | KEYBOARD_INPUT_DATA::BREAK;\r
+ kid2.Reserved = 0;\r
+ kid2.ExtraInformation = 0;\r
+ kid2.MakeCode = 0;\r
+ m_inputQueue->push_back(kid2);\r
+ }\r
+ } else if (i_message != WM_MOUSEWHEEL && i_message != WM_MOUSEHWHEEL) {\r
+ m_buttonPressed = true;\r
+ m_msllHookCurrent = *i_mid;\r
+ }\r
+\r
+ m_inputQueue->push_back(kid);\r
+\r
+ if (i_message == WM_MOUSEWHEEL || i_message == WM_MOUSEHWHEEL) {\r
+ kid.UnitId = 0;\r
+ kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
+ kid.Reserved = 0;\r
+ kid.ExtraInformation = 0;\r
+ m_inputQueue->push_back(kid);\r
+ }\r
+\r
+ SetEvent(m_readEvent);\r
+ ReleaseMutex(m_queueMutex);\r
+\r
+ return 1;\r
+ }\r
+}\r
+\r
+// keyboard handler thread\r
+unsigned int WINAPI Engine::keyboardHandler(void *i_this)\r
+{\r
+ reinterpret_cast<Engine *>(i_this)->keyboardHandler();\r
+ _endthreadex(0);\r
+ return 0;\r
+}\r
+void Engine::keyboardHandler()\r
+{\r
+ // loop\r
+ Key key;\r
+ while (1) {\r
+ KEYBOARD_INPUT_DATA kid;\r
+\r
+ WaitForSingleObject(m_queueMutex, INFINITE);\r
+ while (SignalObjectAndWait(m_queueMutex, m_readEvent, INFINITE, true) == WAIT_OBJECT_0) {\r
+ if (m_inputQueue == NULL) {\r
+ ReleaseMutex(m_queueMutex);\r
+ return;\r
+ }\r
+\r
+ if (m_inputQueue->empty()) {\r
+ ResetEvent(m_readEvent);\r
+ continue;\r
+ }\r
+\r
+ kid = m_inputQueue->front();\r
+ m_inputQueue->pop_front();\r
+ if (m_inputQueue->empty()) {\r
+ ResetEvent(m_readEvent);\r
+ }\r
+\r
+ break;\r
+\r
+#if 0\r
+ case WAIT_OBJECT_0 + NUMBER_OF(handles): {\r
+ MSG message;\r
+\r
+ while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {\r
+ switch (message.message) {\r
+ case WM_APP + 201: {\r
+ if (message.wParam) {\r
+ m_currentLock.on(Modifier::Type_Touchpad);\r
+ m_currentLock.on(Modifier::Type_TouchpadSticky);\r
+ } else\r
+ m_currentLock.off(Modifier::Type_Touchpad);\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("touchpad: ") << message.wParam\r
+ << _T(".") << (message.lParam & 0xffff)\r
+ << _T(".") << (message.lParam >> 16 & 0xffff)\r
+ << std::endl;\r
+ break;\r
+ }\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ goto rewait;\r
+ }\r
+#endif\r
+ }\r
+ ReleaseMutex(m_queueMutex);\r
+\r
+ checkFocusWindow();\r
+\r
+ if (!m_setting || // m_setting has not been loaded\r
+ !m_isEnabled) { // disabled\r
+ if (m_isLogMode) {\r
+ Key key;\r
+ key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
+ outputToLog(&key, ModifiedKey(), 0);\r
+ if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
+ // through mouse event even if log mode\r
+ injectInput(&kid, NULL);\r
+ }\r
+ } else {\r
+ injectInput(&kid, NULL);\r
+ }\r
+ updateLastPressedKey(NULL);\r
+ continue;\r
+ }\r
+\r
+ Acquire a(&m_cs);\r
+\r
+ if (!m_currentFocusOfThread ||\r
+ !m_currentKeymap) {\r
+ injectInput(&kid, NULL);\r
+ Acquire a(&m_log, 0);\r
+ if (!m_currentFocusOfThread)\r
+ m_log << _T("internal error: m_currentFocusOfThread == NULL")\r
+ << std::endl;\r
+ if (!m_currentKeymap)\r
+ m_log << _T("internal error: m_currentKeymap == NULL")\r
+ << std::endl;\r
+ updateLastPressedKey(NULL);\r
+ continue;\r
+ }\r
+\r
+ Current c;\r
+ c.m_keymap = m_currentKeymap;\r
+ c.m_i = m_currentFocusOfThread->m_keymaps.begin();\r
+\r
+ // search key\r
+ key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
+ c.m_mkey = m_setting->m_keyboard.searchKey(key);\r
+ if (!c.m_mkey.m_key) {\r
+ c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);\r
+ if (c.m_mkey.m_key)\r
+ continue;\r
+ }\r
+\r
+ // press the key and update counter\r
+ bool isPhysicallyPressed\r
+ = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);\r
+ if (c.m_mkey.m_key) {\r
+ if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)\r
+ ++ m_currentKeyPressCount;\r
+ else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)\r
+ -- m_currentKeyPressCount;\r
+ c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;\r
+ }\r
+\r
+ // create modifiers\r
+ c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,\r
+ isPhysicallyPressed);\r
+ Keymap::AssignMode am;\r
+ bool isModifier = fixModifierKey(&c.m_mkey, &am);\r
+ if (m_isPrefix) {\r
+ if (isModifier && m_doesIgnoreModifierForPrefix)\r
+ am = Keymap::AM_true;\r
+ if (m_doesEditNextModifier) {\r
+ Modifier modifier = m_modifierForNextKey;\r
+ modifier.add(c.m_mkey.m_modifier);\r
+ c.m_mkey.m_modifier = modifier;\r
+ }\r
+ }\r
+\r
+ if (m_isLogMode) {\r
+ outputToLog(&key, c.m_mkey, 0);\r
+ if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
+ // through mouse event even if log mode\r
+ injectInput(&kid, NULL);\r
+ }\r
+ } else if (am == Keymap::AM_true) {\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("* true modifier") << std::endl;\r
+ }\r
+ // true modifier doesn't generate scan code\r
+ outputToLog(&key, c.m_mkey, 1);\r
+ } else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable) {\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ if (am == Keymap::AM_oneShot)\r
+ m_log << _T("* one shot modifier") << std::endl;\r
+ else\r
+ m_log << _T("* one shot repeatable modifier") << std::endl;\r
+ }\r
+ // oneShot modifier doesn't generate scan code\r
+ outputToLog(&key, c.m_mkey, 1);\r
+ if (isPhysicallyPressed) {\r
+ if (am == Keymap::AM_oneShotRepeatable // the key is repeating\r
+ && m_oneShotKey.m_key == c.m_mkey.m_key) {\r
+ if (m_oneShotRepeatableRepeatCount <\r
+ m_setting->m_oneShotRepeatableDelay) {\r
+ ; // delay\r
+ } else {\r
+ Current cnew = c;\r
+ beginGeneratingKeyboardEvents(cnew, false);\r
+ }\r
+ ++ m_oneShotRepeatableRepeatCount;\r
+ } else {\r
+ m_oneShotKey = c.m_mkey;\r
+ m_oneShotRepeatableRepeatCount = 0;\r
+ }\r
+ } else {\r
+ if (m_oneShotKey.m_key) {\r
+ Current cnew = c;\r
+ cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
+ cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
+ cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
+ beginGeneratingKeyboardEvents(cnew, false);\r
+\r
+ cnew = c;\r
+ cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
+ cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
+ cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
+ beginGeneratingKeyboardEvents(cnew, false);\r
+ }\r
+ m_oneShotKey.m_key = NULL;\r
+ m_oneShotRepeatableRepeatCount = 0;\r
+ }\r
+ } else if (c.m_mkey.m_key) {\r
+ // normal key\r
+ outputToLog(&key, c.m_mkey, 1);\r
+ if (isPhysicallyPressed)\r
+ m_oneShotKey.m_key = NULL;\r
+ beginGeneratingKeyboardEvents(c, isModifier);\r
+ } else {\r
+ // undefined key\r
+ if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
+ // through mouse event even if undefined for fail safe\r
+ injectInput(&kid, NULL);\r
+ }\r
+ }\r
+\r
+ // if counter is zero, reset modifiers and keys on win32\r
+ if (m_currentKeyPressCount <= 0) {\r
+ {\r
+ Acquire a(&m_log, 1);\r
+ m_log << _T("* No key is pressed") << std::endl;\r
+ }\r
+ generateModifierEvents(Modifier());\r
+ if (0 < m_currentKeyPressCountOnWin32)\r
+ keyboardResetOnWin32();\r
+ m_currentKeyPressCount = 0;\r
+ m_currentKeyPressCountOnWin32 = 0;\r
+ m_oneShotKey.m_key = NULL;\r
+ if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)\r
+ m_currentLock.off(Modifier::Type_TouchpadSticky);\r
+ }\r
+\r
+ key.initialize();\r
+ updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);\r
+ }\r
+}\r
+\r
+\r
+Engine::Engine(tomsgstream &i_log)\r
+ : m_hwndAssocWindow(NULL),\r
+ m_setting(NULL),\r
+ m_buttonPressed(false),\r
+ m_dragging(false),\r
+ m_keyboardHandler(installKeyboardHook, Engine::keyboardDetour),\r
+ m_mouseHandler(installMouseHook, Engine::mouseDetour),\r
+ m_inputQueue(NULL),\r
+ m_readEvent(NULL),\r
+ m_queueMutex(NULL),\r
+ m_sts4mayu(NULL),\r
+ m_cts4mayu(NULL),\r
+ m_isLogMode(false),\r
+ m_isEnabled(true),\r
+ m_isSynchronizing(false),\r
+ m_eSync(NULL),\r
+ m_generateKeyboardEventsRecursionGuard(0),\r
+ m_currentKeyPressCount(0),\r
+ m_currentKeyPressCountOnWin32(0),\r
+ m_lastGeneratedKey(NULL),\r
+ m_oneShotRepeatableRepeatCount(0),\r
+ m_isPrefix(false),\r
+ m_currentKeymap(NULL),\r
+ m_currentFocusOfThread(NULL),\r
+ m_hwndFocus(NULL),\r
+ m_afShellExecute(NULL),\r
+ m_variable(0),\r
+ m_log(i_log) {\r
+ BOOL (WINAPI *pChangeWindowMessageFilter)(UINT, DWORD) =\r
+ reinterpret_cast<BOOL (WINAPI*)(UINT, DWORD)>(GetProcAddress(GetModuleHandle(_T("user32.dll")), "ChangeWindowMessageFilter"));\r
+\r
+ if(pChangeWindowMessageFilter != NULL) {\r
+ pChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);\r
+ }\r
+\r
+ for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
+ m_lastPressedKey[i] = NULL;\r
+\r
+ // set default lock state\r
+ for (int i = 0; i < Modifier::Type_end; ++ i)\r
+ m_currentLock.dontcare(static_cast<Modifier::Type>(i));\r
+ for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)\r
+ m_currentLock.release(static_cast<Modifier::Type>(i));\r
+\r
+ // create event for sync\r
+ CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
+ // create named pipe for &SetImeString\r
+ m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),\r
+ PIPE_ACCESS_OUTBOUND,\r
+ PIPE_TYPE_BYTE, 1,\r
+ 0, 0, 0, NULL);\r
+ StrExprArg::setEngine(this);\r
+\r
+ m_msllHookCurrent.pt.x = 0;\r
+ m_msllHookCurrent.pt.y = 0;\r
+ m_msllHookCurrent.mouseData = 0;\r
+ m_msllHookCurrent.flags = 0;\r
+ m_msllHookCurrent.time = 0;\r
+ m_msllHookCurrent.dwExtraInfo = 0;\r
+}\r
+\r
+\r
+\r
+\r
+// start keyboard handler thread\r
+void Engine::start() {\r
+ m_keyboardHandler.start(this);\r
+ m_mouseHandler.start(this);\r
+\r
+ CHECK_TRUE( m_inputQueue = new std::deque<KEYBOARD_INPUT_DATA> );\r
+ CHECK_TRUE( m_queueMutex = CreateMutex(NULL, FALSE, NULL) );\r
+ CHECK_TRUE( m_readEvent = CreateEvent(NULL, TRUE, FALSE, NULL) );\r
+ m_ol.Offset = 0;\r
+ m_ol.OffsetHigh = 0;\r
+ m_ol.hEvent = m_readEvent;\r
+\r
+ CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );\r
+}\r
+\r
+\r
+// stop keyboard handler thread\r
+void Engine::stop() {\r
+ m_mouseHandler.stop();\r
+ m_keyboardHandler.stop();\r
+\r
+ WaitForSingleObject(m_queueMutex, INFINITE);\r
+ delete m_inputQueue;\r
+ m_inputQueue = NULL;\r
+ SetEvent(m_readEvent);\r
+ ReleaseMutex(m_queueMutex);\r
+\r
+ WaitForSingleObject(m_threadHandle, 2000);\r
+ CHECK_TRUE( CloseHandle(m_threadHandle) );\r
+ m_threadHandle = NULL;\r
+\r
+ CHECK_TRUE( CloseHandle(m_readEvent) );\r
+ m_readEvent = NULL;\r
+}\r
+\r
+\r
+bool Engine::prepairQuit() {\r
+ // terminate and unload DLL for ThumbSense support if loaded\r
+ manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
+ false, &m_sts4mayu);\r
+ manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
+ false, &m_cts4mayu);\r
+ return true;\r
+}\r
+\r
+\r
+Engine::~Engine() {\r
+ CHECK_TRUE( CloseHandle(m_eSync) );\r
+\r
+ // destroy named pipe for &SetImeString\r
+ if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE) {\r
+ DisconnectNamedPipe(m_hookPipe);\r
+ CHECK_TRUE( CloseHandle(m_hookPipe) );\r
+ }\r
+}\r
+\r
+\r
+void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,\r
+ TCHAR *i_dependDllName,\r
+ bool i_load, HMODULE *i_pTs4mayu) {\r
+ Acquire a(&m_log, 0);\r
+\r
+ if (i_load == false) {\r
+ if (*i_pTs4mayu) {\r
+ bool (WINAPI *pTs4mayuTerm)();\r
+\r
+ pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");\r
+ if (pTs4mayuTerm() == true)\r
+ FreeLibrary(*i_pTs4mayu);\r
+ *i_pTs4mayu = NULL;\r
+ m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;\r
+ }\r
+ } else {\r
+ if (*i_pTs4mayu) {\r
+ m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;\r
+ } else {\r
+ if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0) {\r
+ m_log << _T("load ") << i_ts4mayuDllName\r
+ << _T(" failed: can't find ") << i_dependDllName\r
+ << std::endl;\r
+ } else {\r
+ *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);\r
+ if (*i_pTs4mayu == NULL) {\r
+ m_log << _T("load ") << i_ts4mayuDllName\r
+ << _T(" failed: can't find it") << std::endl;\r
+ } else {\r
+ bool (WINAPI *pTs4mayuInit)(UINT);\r
+\r
+ pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");\r
+ if (pTs4mayuInit(m_threadId) == true)\r
+ m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;\r
+ else\r
+ m_log << i_ts4mayuDllName\r
+ <<_T(" load failed: can't initialize") << std::endl;\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+\r
+// set m_setting\r
+bool Engine::setSetting(Setting *i_setting) {\r
+ Acquire a(&m_cs);\r
+ if (m_isSynchronizing)\r
+ return false;\r
+\r
+ if (m_setting) {\r
+ for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();\r
+ *i; ++ i) {\r
+ Key *key = i_setting->m_keyboard.searchKey(*(*i));\r
+ if (key) {\r
+ key->m_isPressed = (*i)->m_isPressed;\r
+ key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;\r
+ key->m_isPressedByAssign = (*i)->m_isPressedByAssign;\r
+ }\r
+ }\r
+ if (m_lastGeneratedKey)\r
+ m_lastGeneratedKey =\r
+ i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);\r
+ for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
+ if (m_lastPressedKey[i])\r
+ m_lastPressedKey[i] =\r
+ i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);\r
+ }\r
+\r
+ m_setting = i_setting;\r
+\r
+ manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
+ m_setting->m_sts4mayu, &m_sts4mayu);\r
+ manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
+ m_setting->m_cts4mayu, &m_cts4mayu);\r
+\r
+ g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;\r
+ if (m_currentFocusOfThread) {\r
+ for (FocusOfThreads::iterator i = m_focusOfThreads.begin();\r
+ i != m_focusOfThreads.end(); i ++) {\r
+ FocusOfThread *fot = &(*i).second;\r
+ m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
+ fot->m_className, fot->m_titleName);\r
+ }\r
+ }\r
+ m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));\r
+ if (m_globalFocus.m_keymaps.empty()) {\r
+ Acquire a(&m_log, 0);\r
+ m_log << _T("internal error: m_globalFocus.m_keymap is empty")\r
+ << std::endl;\r
+ }\r
+ m_currentFocusOfThread = &m_globalFocus;\r
+ setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
+ m_hwndFocus = NULL;\r
+ return true;\r
+}\r
+\r
+\r
+void Engine::checkShow(HWND i_hwnd) {\r
+ // update show style of window\r
+ // this update should be done in hook DLL, but to\r
+ // avoid update-loss for some applications(such as\r
+ // cmd.exe), we update here.\r
+ bool isMaximized = false;\r
+ bool isMinimized = false;\r
+ bool isMDIMaximized = false;\r
+ bool isMDIMinimized = false;\r
+ while (i_hwnd) {\r
+#ifdef MAYU64\r
+ LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);\r
+#else\r
+ LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);\r
+#endif\r
+ if (exStyle & WS_EX_MDICHILD) {\r
+ WINDOWPLACEMENT placement;\r
+ placement.length = sizeof(WINDOWPLACEMENT);\r
+ if (GetWindowPlacement(i_hwnd, &placement)) {\r
+ switch (placement.showCmd) {\r
+ case SW_SHOWMAXIMIZED:\r
+ isMDIMaximized = true;\r
+ break;\r
+ case SW_SHOWMINIMIZED:\r
+ isMDIMinimized = true;\r
+ break;\r
+ case SW_SHOWNORMAL:\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+#ifdef MAYU64\r
+ LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
+#else\r
+ LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
+#endif\r
+ if ((style & WS_CHILD) == 0) {\r
+ WINDOWPLACEMENT placement;\r
+ placement.length = sizeof(WINDOWPLACEMENT);\r
+ if (GetWindowPlacement(i_hwnd, &placement)) {\r
+ switch (placement.showCmd) {\r
+ case SW_SHOWMAXIMIZED:\r
+ isMaximized = true;\r
+ break;\r
+ case SW_SHOWMINIMIZED:\r
+ isMinimized = true;\r
+ break;\r
+ case SW_SHOWNORMAL:\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ i_hwnd = GetParent(i_hwnd);\r
+ }\r
+ setShow(isMDIMaximized, isMDIMinimized, true);\r
+ setShow(isMaximized, isMinimized, false);\r
+}\r
+\r
+\r
+// focus\r
+bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId,\r
+ const tstringi &i_className, const tstringi &i_titleName,\r
+ bool i_isConsole) {\r
+ Acquire a(&m_cs);\r
+ if (m_isSynchronizing)\r
+ return false;\r
+ if (i_hwndFocus == NULL)\r
+ return true;\r
+\r
+ // remove newly created thread's id from m_detachedThreadIds\r
+ if (!m_detachedThreadIds.empty()) {\r
+ DetachedThreadIds::iterator i;\r
+ bool retry;\r
+ do {\r
+ retry = false;\r
+ for (i = m_detachedThreadIds.begin();\r
+ i != m_detachedThreadIds.end(); ++ i)\r
+ if (*i == i_threadId) {\r
+ m_detachedThreadIds.erase(i);\r
+ retry = true;\r
+ break;\r
+ }\r
+ } while (retry);\r
+ }\r
+\r
+ FocusOfThread *fot;\r
+ FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);\r
+ if (i != m_focusOfThreads.end()) {\r
+ fot = &(*i).second;\r
+ if (fot->m_hwndFocus == i_hwndFocus &&\r
+ fot->m_isConsole == i_isConsole &&\r
+ fot->m_className == i_className &&\r
+ fot->m_titleName == i_titleName)\r
+ return true;\r
+ } else {\r
+ i = m_focusOfThreads.insert(\r
+ FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;\r
+ fot = &(*i).second;\r
+ fot->m_threadId = i_threadId;\r
+ }\r
+ fot->m_hwndFocus = i_hwndFocus;\r
+ fot->m_isConsole = i_isConsole;\r
+ fot->m_className = i_className;\r
+ fot->m_titleName = i_titleName;\r
+\r
+ if (m_setting) {\r
+ m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
+ i_className, i_titleName);\r
+ ASSERT(0 < fot->m_keymaps.size());\r
+ } else\r
+ fot->m_keymaps.clear();\r
+ checkShow(i_hwndFocus);\r
+ return true;\r
+}\r
+\r
+\r
+// lock state\r
+bool Engine::setLockState(bool i_isNumLockToggled,\r
+ bool i_isCapsLockToggled,\r
+ bool i_isScrollLockToggled,\r
+ bool i_isKanaLockToggled,\r
+ bool i_isImeLockToggled,\r
+ bool i_isImeCompToggled) {\r
+ Acquire a(&m_cs);\r
+ if (m_isSynchronizing)\r
+ return false;\r
+ m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);\r
+ m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);\r
+ m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);\r
+ m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);\r
+ m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);\r
+ m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);\r
+ return true;\r
+}\r
+\r
+\r
+// show\r
+bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,\r
+ bool i_isMDI) {\r
+ Acquire a(&m_cs);\r
+ if (m_isSynchronizing)\r
+ return false;\r
+ Acquire b(&m_log, 1);\r
+ Modifier::Type max, min;\r
+ if (i_isMDI == true) {\r
+ max = Modifier::Type_MdiMaximized;\r
+ min = Modifier::Type_MdiMinimized;\r
+ } else {\r
+ max = Modifier::Type_Maximized;\r
+ min = Modifier::Type_Minimized;\r
+ }\r
+ m_currentLock.on(max, i_isMaximized);\r
+ m_currentLock.on(min, i_isMinimized);\r
+ m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :\r
+ i_isMinimized ? _T("Minimized") : _T("Normal"));\r
+ if (i_isMDI == true) {\r
+ m_log << _T(" (MDI)");\r
+ }\r
+ m_log << std::endl;\r
+ return true;\r
+}\r
+\r
+\r
+// sync\r
+bool Engine::syncNotify() {\r
+ Acquire a(&m_cs);\r
+ if (!m_isSynchronizing)\r
+ return false;\r
+ CHECK_TRUE( SetEvent(m_eSync) );\r
+ return true;\r
+}\r
+\r
+\r
+// thread detach notify\r
+bool Engine::threadDetachNotify(DWORD i_threadId) {\r
+ Acquire a(&m_cs);\r
+ m_detachedThreadIds.push_back(i_threadId);\r
+ return true;\r
+}\r
+\r
+\r
+// get help message\r
+void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle) {\r
+ Acquire a(&m_cs);\r
+ *o_helpMessage = m_helpMessage;\r
+ *o_helpTitle = m_helpTitle;\r
+}\r
+\r
+\r
+unsigned int WINAPI Engine::InputHandler::run(void *i_this)\r
+{\r
+ reinterpret_cast<InputHandler*>(i_this)->run();\r
+ _endthreadex(0);\r
+ return 0;\r
+}\r
+\r
+Engine::InputHandler::InputHandler(INSTALL_HOOK i_installHook, INPUT_DETOUR i_inputDetour)\r
+ : m_installHook(i_installHook), m_inputDetour(i_inputDetour)\r
+{\r
+ CHECK_TRUE(m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL));\r
+ CHECK_TRUE(m_hThread = (HANDLE)_beginthreadex(NULL, 0, run, this, CREATE_SUSPENDED, &m_threadId));\r
+}\r
+\r
+Engine::InputHandler::~InputHandler()\r
+{\r
+ CloseHandle(m_hEvent);\r
+}\r
+\r
+void Engine::InputHandler::run()\r
+{\r
+ MSG msg;\r
+\r
+ CHECK_FALSE(m_installHook(m_inputDetour, m_engine, true));\r
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);\r
+ SetEvent(m_hEvent);\r
+\r
+ while (GetMessage(&msg, NULL, 0, 0)) {\r
+ // nothing to do...\r
+ }\r
+\r
+ CHECK_FALSE(m_installHook(m_inputDetour, m_engine, false));\r
+\r
+ return;\r
+}\r
+\r
+int Engine::InputHandler::start(Engine *i_engine)\r
+{\r
+ m_engine = i_engine;\r
+ ResumeThread(m_hThread);\r
+ WaitForSingleObject(m_hEvent, INFINITE);\r
+ return 0;\r
+}\r
+\r
+int Engine::InputHandler::stop()\r
+{\r
+ PostThreadMessage(m_threadId, WM_QUIT, 0, 0);\r
+ WaitForSingleObject(m_hThread, INFINITE);\r
+ return 0;\r
+}\r