OSDN Git Service

enable command notify on x64
[yamy/yamy.git] / engine.cpp
index 7202adf..f5dbd2c 100644 (file)
@@ -289,13 +289,7 @@ void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)
                                kid.Flags = sc[i].m_flags;\r
                                if (!i_doPress)\r
                                        kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
-#ifdef NO_DRIVER\r
                                injectInput(&kid, NULL);\r
-#else // !NO_DRIVER\r
-                               DWORD len;\r
-                               WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
-                               CHECK_TRUE( GetOverlappedResult(m_device, &m_ol, &len, TRUE) );\r
-#endif // !NO_DRIVER\r
                        }\r
 \r
                        m_lastGeneratedKey = i_doPress ? i_key : NULL;\r
@@ -606,64 +600,126 @@ void Engine::beginGeneratingKeyboardEvents(
 }\r
 \r
 \r
-#ifdef NO_DRIVER\r
 unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)\r
 {\r
-       INPUT kid;\r
        if (i_kid->Flags & KEYBOARD_INPUT_DATA::E1) {\r
-               kid.type = INPUT_MOUSE;\r
-               {\r
-                       Acquire a(&m_cskidq);\r
-                       kid.mi.dx = m_msllHookCurrent.pt.x;\r
-                       kid.mi.dy = m_msllHookCurrent.pt.y;\r
-                       kid.mi.time = m_msllHookCurrent.time;\r
-               }\r
-               kid.mi.mouseData = 0;\r
-               kid.mi.dwExtraInfo = 0;\r
-               kid.mi.dwFlags = MOUSEEVENTF_ABSOLUTE;\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.mi.dwFlags |= MOUSEEVENTF_LEFTUP;\r
+                               kid[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;\r
                        } else {\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_LEFTDOWN;\r
+                               kid[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;\r
                        }\r
                        break;\r
                case 2:\r
                        if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_RIGHTUP;\r
+                               kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;\r
                        } else {\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_RIGHTDOWN;\r
+                               kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;\r
                        }\r
                        break;\r
                case 3:\r
                        if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_MIDDLEUP;\r
+                               kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEUP;\r
                        } else {\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_MIDDLEDOWN;\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.mi.mouseData = WHEEL_DELTA;\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_WHEEL;\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.mi.mouseData = -WHEEL_DELTA;\r
-                               kid.mi.dwFlags |= MOUSEEVENTF_WHEEL;\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
@@ -676,11 +732,10 @@ unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHO
                if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0) {\r
                        kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
                }\r
+               SendInput(1, &kid, sizeof(kid));\r
        }\r
-       SendInput(1, &kid, sizeof(kid));\r
        return 1;\r
 }\r
-#endif // NO_DRIVER\r
 \r
 \r
 // pop all pressed key on win32\r
@@ -694,7 +749,6 @@ void Engine::keyboardResetOnWin32()
 }\r
 \r
 \r
-#ifdef NO_DRIVER\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
@@ -709,7 +763,7 @@ unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)
        << _T(" scanCode=") << i_kid->scanCode\r
        << _T(" flags=") << i_kid->flags << std::endl;\r
 #endif\r
-       if (i_kid->flags & LLKHF_INJECTED) {\r
+       if ((i_kid->flags & LLKHF_INJECTED) || !m_isEnabled) {\r
                return 0;\r
        } else {\r
                Key key;\r
@@ -727,9 +781,10 @@ unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)
                kid.Reserved = 0;\r
                kid.ExtraInformation = 0;\r
 \r
-               Acquire a(&m_cskidq);\r
-               m_kidq.push_back(kid);\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
@@ -741,7 +796,7 @@ unsigned int WINAPI Engine::mouseDetour(Engine *i_this, WPARAM i_wParam, LPARAM
 \r
 unsigned int Engine::mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid)\r
 {\r
-       if (i_mid->flags & LLMHF_INJECTED || !m_setting->m_mouseEvent) {\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
@@ -773,35 +828,134 @@ unsigned int Engine::mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid)
                                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_MOUSEHWHEEL:\r
-               case WM_XBUTTONDOWN:\r
-               case WM_XBUTTONUP:\r
                case WM_XBUTTONDBLCLK:\r
-               case WM_MOUSEMOVE:\r
                default:\r
                        return 0;\r
                        break;\r
                }\r
 \r
-               Acquire a(&m_cskidq);\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_msllHookCurrent.pt.x = i_mid->pt.x;\r
-               m_msllHookCurrent.pt.y = i_mid->pt.y;\r
-               m_msllHookCurrent.mouseData = i_mid->mouseData;\r
-               m_msllHookCurrent.flags = i_mid->flags;\r
-               m_msllHookCurrent.time = i_mid->time;\r
-               m_msllHookCurrent.dwExtraInfo = i_mid->dwExtraInfo;\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
-               m_kidq.push_back(kid);\r
                SetEvent(m_readEvent);\r
+               ReleaseMutex(m_queueMutex);\r
 \r
                return 1;\r
        }\r
 }\r
-#endif // NO_DRIVER\r
 \r
 // keyboard handler thread\r
 unsigned int WINAPI Engine::keyboardHandler(void *i_this)\r
@@ -812,88 +966,32 @@ unsigned int WINAPI Engine::keyboardHandler(void *i_this)
 }\r
 void Engine::keyboardHandler()\r
 {\r
-       // initialize ok\r
-       CHECK_TRUE( SetEvent(m_threadEvent) );\r
-\r
        // loop\r
        Key key;\r
-       while (!m_doForceTerminate) {\r
+       while (1) {\r
                KEYBOARD_INPUT_DATA kid;\r
 \r
-#ifndef NO_DRIVER\r
-               DWORD len;\r
-#endif // !NO_DRIVER\r
-               {\r
-                       Acquire a(&m_log, 1);\r
-                       m_log << _T("begin ReadFile();") << std::endl;\r
-               }\r
-#ifdef NO_DRIVER\r
-               if (1) {\r
-#else // !NO_DRIVER\r
-               if (!ReadFile(m_device, &kid, sizeof(kid), &len, &m_ol)) {\r
-                       if (GetLastError() != ERROR_IO_PENDING)\r
-                               continue;\r
-#endif // !NO_DRIVER\r
-\r
-                       HANDLE handles[] = { m_readEvent, m_interruptThreadEvent };\r
-rewait:\r
-                       switch (MsgWaitForMultipleObjects(NUMBER_OF(handles), &handles[0],\r
-                                                                                         FALSE, INFINITE, QS_POSTMESSAGE)) {\r
-                       case WAIT_OBJECT_0:                     // m_readEvent\r
-#ifdef NO_DRIVER\r
-                               {\r
-                                       Acquire a(&m_cskidq);\r
-                                       if (m_kidq.empty()) {\r
-                                               goto rewait;\r
-                                       }\r
-                                       kid = m_kidq.front();\r
-                                       m_kidq.pop_front();\r
-                                       if (!m_kidq.empty()) {\r
-                                               SetEvent(m_readEvent);\r
-                                       }\r
-                               }\r
-#else // !NO_DRIVER\r
-                               if (!GetOverlappedResult(m_device, &m_ol, &len, FALSE))\r
-                                       continue;\r
-#endif // !NO_DRIVER\r
-                               break;\r
-\r
-                       case WAIT_OBJECT_0 + 1:                 // m_interruptThreadEvent\r
-                               CancelIo(m_device);\r
-                               switch (m_interruptThreadReason) {\r
-                               default: {\r
-                                       ASSERT( false );\r
-                                       Acquire a(&m_log, 0);\r
-                                       m_log << _T("internal error: m_interruptThreadReason == ")\r
-                                       << m_interruptThreadReason << std::endl;\r
-                                       break;\r
-                               }\r
-\r
-                               case InterruptThreadReason_Terminate:\r
-                                       goto break_while;\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
-                               case InterruptThreadReason_Pause: {\r
-                                       CHECK_TRUE( SetEvent(m_threadEvent) );\r
-                                       while (WaitForMultipleObjects(1, &m_interruptThreadEvent,\r
-                                                                                                 FALSE, INFINITE) != WAIT_OBJECT_0)\r
-                                               ;\r
-                                       switch (m_interruptThreadReason) {\r
-                                       case InterruptThreadReason_Terminate:\r
-                                               goto break_while;\r
+                       if (m_inputQueue->empty()) {\r
+                               ResetEvent(m_readEvent);\r
+                               continue;\r
+                       }\r
 \r
-                                       case InterruptThreadReason_Resume:\r
-                                               break;\r
+                       kid = m_inputQueue->front();\r
+                       m_inputQueue->pop_front();\r
+                       if (m_inputQueue->empty()) {\r
+                               ResetEvent(m_readEvent);\r
+                       }\r
 \r
-                                       default:\r
-                                               ASSERT( false );\r
-                                               break;\r
-                                       }\r
-                                       CHECK_TRUE( SetEvent(m_threadEvent) );\r
-                                       break;\r
-                               }\r
-                               }\r
-                               break;\r
+                       break;\r
 \r
+#if 0\r
                        case WAIT_OBJECT_0 + NUMBER_OF(handles): {\r
                                MSG message;\r
 \r
@@ -918,16 +1016,9 @@ rewait:
                                }\r
                                goto rewait;\r
                        }\r
-\r
-                       default:\r
-                               ASSERT( false );\r
-                               continue;\r
-                       }\r
-               }\r
-               {\r
-                       Acquire a(&m_log, 1);\r
-                       m_log << _T("end ReadFile();") << std::endl;\r
+#endif\r
                }\r
+               ReleaseMutex(m_queueMutex);\r
 \r
                checkFocusWindow();\r
 \r
@@ -937,13 +1028,12 @@ rewait:
                                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
-#ifdef NO_DRIVER\r
                                injectInput(&kid, NULL);\r
-#else // !NO_DRIVER\r
-                               WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
-                               GetOverlappedResult(m_device, &m_ol, &len, TRUE);\r
-#endif // !NO_DRIVER\r
                        }\r
                        updateLastPressedKey(NULL);\r
                        continue;\r
@@ -953,10 +1043,7 @@ rewait:
 \r
                if (!m_currentFocusOfThread ||\r
                                !m_currentKeymap) {\r
-#ifndef NO_DRIVER\r
-                       WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
-                       GetOverlappedResult(m_device, &m_ol, &len, TRUE);\r
-#endif // !NO_DRIVER\r
+                       injectInput(&kid, NULL);\r
                        Acquire a(&m_log, 0);\r
                        if (!m_currentFocusOfThread)\r
                                m_log << _T("internal error: m_currentFocusOfThread == NULL")\r
@@ -1062,13 +1149,18 @@ rewait:
                                m_oneShotKey.m_key = NULL;\r
                                m_oneShotRepeatableRepeatCount = 0;\r
                        }\r
-               } else if (c.m_mkey.m_key)\r
+               } else if (c.m_mkey.m_key) {\r
                        // normal key\r
-               {\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
@@ -1090,25 +1182,21 @@ rewait:
                key.initialize();\r
                updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);\r
        }\r
-break_while:\r
-       CHECK_TRUE( SetEvent(m_threadEvent) );\r
 }\r
 \r
 \r
 Engine::Engine(tomsgstream &i_log)\r
                : m_hwndAssocWindow(NULL),\r
                m_setting(NULL),\r
-               m_device(INVALID_HANDLE_VALUE),\r
-               m_didMayuStartDevice(false),\r
-               m_threadEvent(NULL),\r
-               m_mayudVersion(_T("unknown")),\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_interruptThreadEvent(NULL),\r
+               m_queueMutex(NULL),\r
                m_sts4mayu(NULL),\r
                m_cts4mayu(NULL),\r
-               m_doForceTerminate(false),\r
                m_isLogMode(false),\r
                m_isEnabled(true),\r
                m_isSynchronizing(false),\r
@@ -1125,6 +1213,13 @@ Engine::Engine(tomsgstream &i_log)
                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
@@ -1134,24 +1229,6 @@ Engine::Engine(tomsgstream &i_log)
        for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)\r
                m_currentLock.release(static_cast<Modifier::Type>(i));\r
 \r
-#ifndef NO_DRIVER\r
-       if (!open()) {\r
-               throw ErrorMessage() << loadString(IDS_driverNotInstalled);\r
-       }\r
-#endif // !NO_DRIVER\r
-\r
-#ifndef NO_DRIVER\r
-       {\r
-               TCHAR versionBuf[256];\r
-               DWORD length = 0;\r
-\r
-               if (DeviceIoControl(m_device, IOCTL_MAYU_GET_VERSION, NULL, 0,\r
-                                                       versionBuf, sizeof(versionBuf), &length, NULL)\r
-                               && length\r
-                               && length < sizeof(versionBuf))                 // fail safe\r
-                       m_mayudVersion = tstring(versionBuf, length / 2);\r
-       }\r
-#endif // !NO_DRIVER\r
        // create event for sync\r
        CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
        // create named pipe for &SetImeString\r
@@ -1170,138 +1247,41 @@ Engine::Engine(tomsgstream &i_log)
 }\r
 \r
 \r
-// open mayu device\r
-bool Engine::open() {\r
-       // open mayu m_device\r
-#ifndef NO_DRIVER\r
-       m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,\r
-                                                 0, NULL, OPEN_EXISTING,\r
-                                                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);\r
-#endif // !NO_DRIVER\r
-\r
-       if (m_device != INVALID_HANDLE_VALUE) {\r
-               return true;\r
-       }\r
-\r
-#ifndef NO_DRIVER\r
-       // start mayud\r
-       SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
-       if (hscm) {\r
-               SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_START);\r
-               if (hs) {\r
-                       StartService(hs, 0, NULL);\r
-                       CloseServiceHandle(hs);\r
-                       m_didMayuStartDevice = true;\r
-               }\r
-               CloseServiceHandle(hscm);\r
-       }\r
-\r
-       // open mayu m_device\r
-       m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,\r
-                                                 0, NULL, OPEN_EXISTING,\r
-                                                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);\r
-#endif // !NO_DRIVER\r
-       return (m_device != INVALID_HANDLE_VALUE);\r
-}\r
-\r
-\r
-// close mayu device\r
-void Engine::close() {\r
-       if (m_device != INVALID_HANDLE_VALUE) {\r
-#ifndef NO_DRIVER\r
-               CHECK_TRUE( CloseHandle(m_device) );\r
-#endif // !NO_DRIVER\r
-       }\r
-       m_device = INVALID_HANDLE_VALUE;\r
-}\r
 \r
 \r
 // start keyboard handler thread\r
 void Engine::start() {\r
        m_keyboardHandler.start(this);\r
        m_mouseHandler.start(this);\r
-       CHECK_TRUE( m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
 \r
-       CHECK_TRUE( m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
-       CHECK_TRUE( m_interruptThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\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
-       CHECK( WAIT_OBJECT_0 ==, WaitForSingleObject(m_threadEvent, INFINITE) );\r
 }\r
 \r
 \r
 // stop keyboard handler thread\r
 void Engine::stop() {\r
-       if (m_threadEvent) {\r
-               m_doForceTerminate = true;\r
-               do {\r
-                       m_interruptThreadReason = InterruptThreadReason_Terminate;\r
-                       SetEvent(m_interruptThreadEvent);\r
-                       //DWORD buf;\r
-                       //M_DeviceIoControl(m_device, IOCTL_MAYU_DETOUR_CANCEL,\r
-                       //                &buf, sizeof(buf), &buf, sizeof(buf), &buf, NULL);\r
-\r
-                       // wait for message handler thread terminate\r
-               } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
-               CHECK_TRUE( CloseHandle(m_threadEvent) );\r
-               m_threadEvent = NULL;\r
-               WaitForSingleObject(m_threadHandle, 100);\r
-               CHECK_TRUE( CloseHandle(m_threadHandle) );\r
-               m_threadHandle = NULL;\r
-\r
-               // stop mayud\r
-               if (m_didMayuStartDevice) {\r
-                       SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
-                       if (hscm) {\r
-                               SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_STOP);\r
-                               if (hs) {\r
-                                       SERVICE_STATUS ss;\r
-                                       ControlService(hs, SERVICE_CONTROL_STOP, &ss);\r
-                                       CloseServiceHandle(hs);\r
-                               }\r
-                               CloseServiceHandle(hscm);\r
-                       }\r
-               }\r
-\r
-               CHECK_TRUE( CloseHandle(m_readEvent) );\r
-               m_readEvent = NULL;\r
-               CHECK_TRUE( CloseHandle(m_interruptThreadEvent) );\r
-               m_interruptThreadEvent = NULL;\r
-       }\r
        m_mouseHandler.stop();\r
        m_keyboardHandler.stop();\r
-}\r
 \r
-bool Engine::pause() {\r
-       if (m_device != INVALID_HANDLE_VALUE) {\r
-               do {\r
-                       m_interruptThreadReason = InterruptThreadReason_Pause;\r
-                       SetEvent(m_interruptThreadEvent);\r
-               } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
-#ifndef NO_DRIVER\r
-               close();\r
-#endif // !NO_DRIVER\r
-       }\r
-       return true;\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
-bool Engine::resume() {\r
-       if (m_device == INVALID_HANDLE_VALUE) {\r
-#ifndef NO_DRIVER\r
-               if (!open()) {\r
-                       return false;                           // FIXME\r
-               }\r
-#endif // !NO_DRIVER\r
-               do {\r
-                       m_interruptThreadReason = InterruptThreadReason_Resume;\r
-                       SetEvent(m_interruptThreadEvent);\r
-               } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
-       }\r
-       return true;\r
+       CHECK_TRUE( CloseHandle(m_readEvent) );\r
+       m_readEvent = NULL;\r
 }\r
 \r
 \r
@@ -1316,13 +1296,8 @@ bool Engine::prepairQuit() {
 \r
 \r
 Engine::~Engine() {\r
-       stop();\r
        CHECK_TRUE( CloseHandle(m_eSync) );\r
 \r
-       // close m_device\r
-#ifndef NO_DRIVER\r
-       close();\r
-#endif // !NO_DRIVER\r
        // destroy named pipe for &SetImeString\r
        if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE) {\r
                DisconnectNamedPipe(m_hookPipe);\r
@@ -1621,83 +1596,6 @@ void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle) {
 }\r
 \r
 \r
-// command notify\r
-void Engine::commandNotify(\r
-       HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam) {\r
-       Acquire b(&m_log, 0);\r
-       HWND hf = m_hwndFocus;\r
-       if (!hf)\r
-               return;\r
-\r
-       if (GetWindowThreadProcessId(hf, NULL) ==\r
-                       GetWindowThreadProcessId(m_hwndAssocWindow, NULL))\r
-               return; // inhibit the investigation of MADO TSUKAI NO YUUTSU\r
-\r
-       const _TCHAR *target = NULL;\r
-       int number_target = 0;\r
-\r
-       if (i_hwnd == hf)\r
-               target = _T("ToItself");\r
-       else if (i_hwnd == GetParent(hf))\r
-               target = _T("ToParentWindow");\r
-       else {\r
-               // Function::toMainWindow\r
-               HWND h = hf;\r
-               while (true) {\r
-                       HWND p = GetParent(h);\r
-                       if (!p)\r
-                               break;\r
-                       h = p;\r
-               }\r
-               if (i_hwnd == h)\r
-                       target = _T("ToMainWindow");\r
-               else {\r
-                       // Function::toOverlappedWindow\r
-                       HWND h = hf;\r
-                       while (h) {\r
-#ifdef MAYU64\r
-                               LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);\r
-#else\r
-                               LONG style = GetWindowLong(h, GWL_STYLE);\r
-#endif\r
-                               if ((style & WS_CHILD) == 0)\r
-                                       break;\r
-                               h = GetParent(h);\r
-                       }\r
-                       if (i_hwnd == h)\r
-                               target = _T("ToOverlappedWindow");\r
-                       else {\r
-                               // number\r
-                               HWND h = hf;\r
-                               for (number_target = 0; h; number_target ++, h = GetParent(h))\r
-                                       if (i_hwnd == h)\r
-                                               break;\r
-                               return;\r
-                       }\r
-               }\r
-       }\r
-\r
-       m_log << _T("&PostMessage(");\r
-       if (target)\r
-               m_log << target;\r
-       else\r
-               m_log << number_target;\r
-       m_log << _T(", ") << i_message\r
-       << _T(", 0x") << std::hex << i_wParam\r
-       << _T(", 0x") << i_lParam << _T(") # hwnd = ")\r
-       << reinterpret_cast<int>(i_hwnd) << _T(", ")\r
-       << _T("message = ") << std::dec;\r
-       if (i_message == WM_COMMAND)\r
-               m_log << _T("WM_COMMAND, ");\r
-       else if (i_message == WM_SYSCOMMAND)\r
-               m_log << _T("WM_SYSCOMMAND, ");\r
-       else\r
-               m_log << i_message << _T(", ");\r
-       m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")\r
-       << _T("wID = ") << LOWORD(i_wParam) << _T(", ")\r
-       << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;\r
-}\r
-\r
 unsigned int WINAPI Engine::InputHandler::run(void *i_this)\r
 {\r
        reinterpret_cast<InputHandler*>(i_this)->run();\r