OSDN Git Service

Add a new class to handle the TLS stuff
[xkeymacs/xkeymacs.git] / xkeymacsdll / xkeymacsdll.cpp
index aad62e3..d8da65e 100644 (file)
@@ -1,11 +1,12 @@
 // xkeymacsdll.cpp : Defines the initialization routines for the DLL.\r
 //\r
 \r
-#include "stdafx.h"\r
-#include "resource.h"\r
+#include "xkeymacsdll.h"\r
 #include "Utils.h"\r
 #include "Commands.h"\r
-#include <afxdllx.h>\r
+#include "CmdTable.h"\r
+#include "TLS.h"\r
+#include "../xkeymacs/resource.h"\r
 #include <math.h>\r
 #include <Imm.h>\r
 #include <vector>\r
 static char THIS_FILE[] = __FILE__;\r
 #endif\r
 \r
-struct Modifier {\r
-       LPCTSTR name;\r
-       int id;\r
-};\r
-\r
-static const Modifier Modifiers[] = {\r
-//     { _T("A-"), ALT },\r
-       { _T("C-"), CONTROL},\r
-//     { _T("H-"), HYPER },\r
-       { _T("M-"), META },\r
-       { _T("S-"), SHIFT },\r
-//     { _T("s-"), SUPER },\r
-       { _T("Ctrl+"), WIN_CTRL },\r
-       { _T("Alt+"), WIN_ALT },\r
-       { _T("Win+"), WIN_WIN },\r
-};\r
-static const int MAX_MODIFIER = _countof(Modifiers);\r
-\r
-static const KeyName KeyNames[] = {\r
-//     { VK_LBUTTON,           _T("mouse-1") },                                // does not work well\r
-//     { VK_RBUTTON,           _T("mouse-3") },                                // does not work well\r
-       { VK_CANCEL,            _T("break") },\r
-//     { VK_MBUTTON,           _T("mouse-2") },                                // does not work well\r
-       { VK_BACK,                      _T("backspace") },\r
-       { VK_TAB,                       _T("tab") },\r
-       { VK_RETURN,            _T("return") },\r
-       { VK_CAPITAL,           _T("capslock") },\r
-       { VK_KANA,                      _T("kana") },\r
-       { VK_KANJI,                     _T("kanji") },\r
-       { VK_ESCAPE,            _T("escape") },\r
-       { VK_CONVERT,           _T("convert") },\r
-       { VK_NONCONVERT,        _T("nonconvert") },\r
-//     { VK_SPACE,                     _T("SPC") },                                    // [? ]\r
-       { VK_PRIOR,                     _T("prior") },\r
-       { VK_NEXT,                      _T("next") },\r
-       { VK_END,                       _T("end") },\r
-       { VK_HOME,                      _T("home") },\r
-       { VK_LEFT,                      _T("left") },\r
-       { VK_UP,                        _T("up") },\r
-       { VK_RIGHT,                     _T("right") },\r
-       { VK_DOWN,                      _T("down") },\r
-       { VK_SELECT,            _T("select") },\r
-       { VK_PRINT,                     _T("print") },\r
-       { VK_EXECUTE,           _T("execute") },\r
-       { VK_SNAPSHOT,          _T("printscreen") },                    // work as print\r
-       { VK_INSERT,            _T("insert") },\r
-       { VK_DELETE,            _T("delete") },\r
-       { VK_LWIN,                      _T("lwindow") },\r
-       { VK_RWIN,                      _T("rwindow") },\r
-       { VK_APPS,                      _T("apps") },\r
-       { VK_SLEEP,                     _T("sleep") },\r
-       { VK_NUMPAD0,           _T("kp-0") },\r
-       { VK_NUMPAD1,           _T("kp-1") },\r
-       { VK_NUMPAD2,           _T("kp-2") },\r
-       { VK_NUMPAD3,           _T("kp-3") },\r
-       { VK_NUMPAD4,           _T("kp-4") },\r
-       { VK_NUMPAD5,           _T("kp-5") },\r
-       { VK_NUMPAD6,           _T("kp-6") },\r
-       { VK_NUMPAD7,           _T("kp-7") },\r
-       { VK_NUMPAD8,           _T("kp-8") },\r
-       { VK_NUMPAD9,           _T("kp-9") },\r
-       { VK_MULTIPLY,          _T("kp-multiply") },\r
-       { VK_ADD,                       _T("kp-add") },\r
-       { VK_SUBTRACT,          _T("kp-subtract") },\r
-       { VK_DECIMAL,           _T("kp-decimal") },\r
-       { VK_DIVIDE,            _T("kp-divide") },\r
-//     { VK_F1,                        _T("f1") },                                             // FIXME\r
-//     { VK_F2,                        _T("f2") },                                             // Move at the end of definition of function keys to keep away confliction f1/f2 and f1?/f2? by _tcsncmp() i.e. strncmp()\r
-       { VK_F3,                        _T("f3") },\r
-       { VK_F4,                        _T("f4") },\r
-       { VK_F5,                        _T("f5") },\r
-       { VK_F6,                        _T("f6") },\r
-       { VK_F7,                        _T("f7") },\r
-       { VK_F8,                        _T("f8") },\r
-       { VK_F9,                        _T("f9") },\r
-       { VK_F10,                       _T("f10") },\r
-       { VK_F11,                       _T("f11") },\r
-       { VK_F12,                       _T("f12") },\r
-       { VK_F13,                       _T("f13") },\r
-       { VK_F14,                       _T("f14") },\r
-       { VK_F15,                       _T("f15") },\r
-       { VK_F16,                       _T("f16") },\r
-       { VK_F17,                       _T("f17") },\r
-       { VK_F18,                       _T("f18") },\r
-       { VK_F19,                       _T("f19") },\r
-       { VK_F20,                       _T("f20") },\r
-       { VK_F21,                       _T("f21") },\r
-       { VK_F22,                       _T("f22") },\r
-       { VK_F23,                       _T("f23") },\r
-       { VK_F24,                       _T("f24") },\r
-       { VK_F1,                        _T("f1") },\r
-       { VK_F2,                        _T("f2") },\r
-       { VK_NUMLOCK,           _T("kp-numlock") },\r
-       { VK_SCROLL,            _T("scroll") },\r
-       { 0xa6,                         _T("browser-back") },                   // VK_BROWSER_BACK\r
-       { 0xa7,                         _T("browser-forward") },                // VK_BROWSER_FORWARD\r
-       { 0xa8,                         _T("browser-refresh") },                // VK_BROWSER_REFRESH\r
-       { 0xa9,                         _T("browser-stop") },                   // VK_BROWSER_STOP\r
-       { 0xaa,                         _T("browser-search") },                 // VK_BROWSER_SEARCH\r
-       { 0xab,                         _T("browser-favorites") },              // VK_BROWSER_FAVORITES\r
-       { 0xac,                         _T("browser-home") },                   // VK_BROWSER_HOME\r
-       { 0xad,                         _T("volume-mute") },                    // VK_VOLUME_MUTE\r
-       { 0xae,                         _T("volume-down") },                    // VK_VOLUME_DOWN\r
-       { 0xaf,                         _T("volume-up") },                              // VK_VOLUME_UP\r
-       { 0xb0,                         _T("media-next-track") },               // VK_MEDIA_NEXT_TRACK\r
-       { 0xb1,                         _T("media-prev-track") },               // VK_MEDIA_PREV_TRACK\r
-       { 0xb2,                         _T("media-stop") },                             // VK_MEDIA_STOP\r
-       { 0xb3,                         _T("media-play-pause") },               // VK_MEDIA_PLAY_PAUSE\r
-       { 0xb4,                         _T("launch-mail") },                    // VK_LAUNCH_MAIL\r
-       { 0xb5,                         _T("launch-media-select") },    // VK_LAUNCH_MEDIA_SELECT\r
-       { 0xb6,                         _T("launch-1") },                               // VK_LAUNCH_APP1\r
-       { 0xb7,                         _T("launch-2") },                               // VK_LAUNCH_APP2\r
-};\r
-static const int MAX_KEYNAME = _countof(KeyNames);\r
-\r
 static AFX_EXTENSION_MODULE XkeymacsdllDLL = { NULL, NULL };\r
 \r
 static HINSTANCE g_hDllInst = NULL;\r
-static DWORD g_TlsIndex = 0;\r
 \r
 extern "C" int APIENTRY\r
 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
 {\r
        g_hDllInst = hInstance;\r
-       LPVOID lpData;\r
        \r
        // Remove this if you use lpReserved\r
        UNREFERENCED_PARAMETER(lpReserved);\r
@@ -173,27 +57,20 @@ DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
                        e->Delete();\r
 //                     CUtils::Log("DllMain: 'new' threw an exception");\r
                }\r
-\r
-               if ((g_TlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)\r
+               if (!TLS::Alloc())\r
                        return FALSE;\r
-               // fall through\r
        case DLL_THREAD_ATTACH:\r
-               if ((lpData = LocalAlloc(LPTR, sizeof(HHOOK))) != NULL)\r
-                       TlsSetValue(g_TlsIndex, lpData);\r
                break;\r
        case DLL_PROCESS_DETACH:\r
                TRACE0("XKEYMACSDLL.DLL Terminating!\n");\r
                // Terminate the library before destructors are called\r
                AfxTermExtensionModule(XkeymacsdllDLL);\r
                CXkeymacsDll::ReleaseKeyboardHook();\r
-               if ((lpData = TlsGetValue(g_TlsIndex)) != NULL)\r
-                       LocalFree(lpData);\r
-               TlsFree(g_TlsIndex);\r
+               TLS::Free();\r
                break;\r
        case DLL_THREAD_DETACH:\r
                CXkeymacsDll::ReleaseKeyboardHook();\r
-               if ((lpData = TlsGetValue(g_TlsIndex)) != NULL)\r
-                       LocalFree(lpData);\r
+               TLS::FreeLocal();\r
                break;\r
        }\r
        return 1;   // ok\r
@@ -203,33 +80,33 @@ DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
 // CXkeymacsDll Class\r
 //////////////////////////////////////////////////////////////////////\r
 \r
-#include "xkeymacsDll.h"\r
 #pragma data_seg(".xkmcs")\r
-       bool    CXkeymacsDll::m_bEnableKeyboardHook = false;\r
-       DWORD   CXkeymacsDll::m_nHookAltRelease = 0;\r
-       BOOL    CXkeymacsDll::m_bRightControl   = FALSE;\r
-       BOOL    CXkeymacsDll::m_bRightAlt               = FALSE;\r
-       BOOL    CXkeymacsDll::m_bRightShift             = FALSE;\r
-       BOOL    CXkeymacsDll::m_bHook                   = TRUE;\r
-       BYTE    CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
-       int             CXkeymacsDll::m_nAccelerate = 0;\r
-       int             CXkeymacsDll::m_nKeyboardSpeed = 31;\r
-       HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};\r
-       HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;\r
-       BOOL    CXkeymacsDll::m_bCursor = FALSE;\r
-       TCHAR   CXkeymacsDll::m_M_xTip[128] = "";\r
-       CONFIG  CXkeymacsDll::m_Config = {0};\r
+Config CXkeymacsDll::m_Config = {0};\r
+bool CXkeymacsDll::m_bEnableKeyboardHook = false;\r
+bool CXkeymacsDll::m_bHook = true;\r
+int CXkeymacsDll::m_nAccelerate = 0;\r
+int CXkeymacsDll::m_nKeyboardSpeed = 31;\r
+HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;\r
+BOOL CXkeymacsDll::m_bCursor = FALSE;\r
+HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};\r
 #pragma data_seg()\r
+\r
+AppConfig* CXkeymacsDll::m_CurrentConfig = NULL;\r
+BYTE (*CXkeymacsDll::m_CmdID)[MAX_KEY];\r
+char (*CXkeymacsDll::m_FuncID)[MAX_KEY];\r
 HHOOK CXkeymacsDll::m_hHookCallWnd = NULL;\r
 HHOOK CXkeymacsDll::m_hHookCallWndRet = NULL;\r
 HHOOK CXkeymacsDll::m_hHookGetMessage = NULL;\r
 HHOOK CXkeymacsDll::m_hHookShell = NULL;\r
-int CXkeymacsDll::m_nAppID = 0;\r
+DWORD CXkeymacsDll::m_nHookAltRelease = 0;\r
+BOOL CXkeymacsDll::m_bRightShift = FALSE;\r
+BOOL CXkeymacsDll::m_bRightControl = FALSE;\r
+BOOL CXkeymacsDll::m_bRightAlt = FALSE;\r
+TCHAR CXkeymacsDll::m_M_xTip[128] = "";\r
+BYTE CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
 CList<CClipboardSnap *, CClipboardSnap *> CXkeymacsDll::m_oKillRing;\r
 int CXkeymacsDll::m_nKillRing = 0;\r
-BOOL CXkeymacsDll::m_bRecordingMacro = FALSE;\r
-BOOL CXkeymacsDll::m_bDown[MAX_KEY] = {0};\r
-std::list<KbdMacro> CXkeymacsDll::m_Macro;\r
+KbdMacro* CXkeymacsDll::m_kbdMacro = NULL;\r
 \r
 BOOL CXkeymacsDll::SaveConfig()\r
 {\r
@@ -263,7 +140,7 @@ BOOL CXkeymacsDll::LoadConfig()
        return res;\r
 }\r
 \r
-void CXkeymacsDll::SetConfig(const CONFIG& config)\r
+void CXkeymacsDll::SetConfig(const Config& config)\r
 {\r
        m_Config = config;\r
 }\r
@@ -277,19 +154,10 @@ void CXkeymacsDll::SetHooks()
        m_bEnableKeyboardHook = true;\r
 }\r
 \r
-void CXkeymacsDll::SetKeyboardHook()\r
+void CXkeymacsDll::SetKeyboardHook(DWORD threadId)\r
 {\r
-       LPVOID lpData = TlsGetValue(g_TlsIndex);\r
-       if (!lpData) {\r
-               lpData = LocalAlloc(LPTR, sizeof(HHOOK));\r
-               if (!lpData)\r
-                       return;\r
-               if (!TlsSetValue(g_TlsIndex, lpData))\r
-                       return;\r
-       }\r
-       HHOOK *phHook = reinterpret_cast<HHOOK *>(lpData);\r
-       if (!*phHook)\r
-               *phHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hDllInst, GetCurrentThreadId());\r
+       if (!TLS::GetKeyboardHook())\r
+               TLS::PutKeyboardHook(SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hDllInst, threadId ? threadId : GetCurrentThreadId()));\r
 }\r
 \r
 inline void unhook(HHOOK &hh)\r
@@ -316,46 +184,61 @@ void CXkeymacsDll::ReleaseHooks()
 \r
 void CXkeymacsDll::ReleaseKeyboardHook()\r
 {\r
-       HHOOK *phHook = reinterpret_cast<HHOOK *>(TlsGetValue(g_TlsIndex));\r
-       if (phHook)\r
-               unhook(*phHook);\r
+       HHOOK hook = TLS::GetKeyboardHook();\r
+       if (!hook)\r
+               return;\r
+       UnhookWindowsHookEx(hook);\r
+}\r
+\r
+void CXkeymacsDll::SetHookStateDirect(bool enable)\r
+{\r
+       m_bHook = enable;\r
+}\r
+\r
+void CXkeymacsDll::ToggleHookState()\r
+{\r
+       SetHookState(!m_bHook);\r
+}\r
+\r
+void CXkeymacsDll::SetHookState(bool enable)\r
+{\r
+       DWORD ack, read;\r
+       IPC32Message msg;\r
+       msg.Type = IPC32_HOOKSTATE;\r
+       msg.Enable = enable;\r
+       if (!CallNamedPipe(m_Config.PipeNameForIPC32, &msg, offsetof(IPC32Message, Enable) + sizeof(bool), &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT))\r
+               CUtils::Log(_T("SetHookState: CallNamedPipe failed. (%d)"), GetLastError());\r
+\r
+       ShowHookState();\r
 }\r
 \r
-void CXkeymacsDll::ToggleKeyboardHookState()\r
+bool CXkeymacsDll::GetHookState()\r
 {\r
-       m_bHook = !m_bHook;\r
-       ShowKeyboardHookState();\r
+       return m_bHook;\r
 }\r
 \r
-void CXkeymacsDll::ShowKeyboardHookState()\r
+void CXkeymacsDll::ShowHookState()\r
 {\r
-       ICONMSG msg = {MAIN_ICON,};\r
+       IconState main = { MAIN_ICON, STATUS_ENABLE };\r
        if (m_bHook) {\r
                if (CCommands::IsTemporarilyDisableXKeymacs()) {\r
-                       msg.nState = STATUS_DISABLE_TMP;\r
+                       main.State = STATUS_DISABLE_TMP;\r
                        m_hCurrentCursor = m_hCursor[STATUS_DISABLE_TMP];\r
                } else {\r
-                       msg.nState = STATUS_ENABLE;\r
+                       main.State = STATUS_ENABLE;\r
                        m_hCurrentCursor = m_hCursor[STATUS_ENABLE];\r
                }\r
-       } else {\r
-               msg.nState = STATUS_DISABLE_WOCQ;\r
-       }\r
-       if (m_Config.nSettingStyle[m_nAppID] == SETTING_DISABLE\r
-        || (!_tcsicmp(m_Config.szSpecialApp[m_nAppID], _T("Default"))\r
-         && CUtils::IsDefaultIgnoreApplication())) {\r
-               msg.nState = STATUS_DISABLE;\r
+       } else\r
+               main.State = STATUS_DISABLE_WOCQ;\r
+       if (m_CurrentConfig->SettingStyle == SETTING_DISABLE ||\r
+                       (!_tcsicmp(m_CurrentConfig->AppName, _T("Default")) && CUtils::IsDefaultIgnoreApplication())) {\r
+               main.State = STATUS_DISABLE;\r
                m_hCurrentCursor = m_hCursor[STATUS_DISABLE];\r
        }\r
-       SendIconMessage(&msg, 1);\r
+       SendIconMessage(&main, 1);\r
        DoSetCursor();\r
 }\r
 \r
-BOOL CXkeymacsDll::IsKeyboardHook()\r
-{\r
-       return m_bHook;\r
-}\r
-\r
 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)\r
 {\r
        SetKeyboardHook();\r
@@ -363,21 +246,23 @@ LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lPar
                const CWPSTRUCT *cwps = reinterpret_cast<CWPSTRUCT *>(lParam);\r
                switch (cwps->message) {\r
                case WM_IME_STARTCOMPOSITION:\r
-                       InitKeyboardProc(TRUE);\r
+                       AppName::SetIMEState(true);\r
+                       InitKeyboardProc();\r
                        break;\r
                case WM_IME_ENDCOMPOSITION:\r
-                       InitKeyboardProc(FALSE);\r
+                       AppName::SetIMEState(false);\r
+                       InitKeyboardProc();\r
                        break;\r
                case WM_SETFOCUS:\r
-                       if (cwps->hwnd == GetForegroundWindow()) {\r
-                               InitKeyboardProc(FALSE);\r
-                               ShowKeyboardHookState();\r
-                       }\r
+                       AppName::SetIMEState(false);\r
+                       InitKeyboardProc();\r
+                       ShowHookState();\r
                        break;\r
                case WM_NCACTIVATE:\r
                        if (cwps->wParam && cwps->hwnd == GetForegroundWindow()) {\r
-                               InitKeyboardProc(FALSE);\r
-                               ShowKeyboardHookState();\r
+                               AppName::SetIMEState(false);\r
+                               InitKeyboardProc();\r
+                               ShowHookState();\r
                        }\r
                        break;\r
                }\r
@@ -393,7 +278,7 @@ LRESULT CALLBACK CXkeymacsDll::CallWndRetProc(int nCode, WPARAM wParam, LPARAM l
                switch (cwprets->message) {\r
                case WM_SETTEXT:\r
                        if (cwprets->hwnd == GetForegroundWindow())\r
-                               InitKeyboardProc(FALSE);\r
+                               InitKeyboardProc();\r
                        break;\r
                case WM_SETCURSOR:\r
                        DoSetCursor();\r
@@ -410,10 +295,12 @@ LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lPara
                const MSG *msg = reinterpret_cast<MSG *>(lParam);\r
                switch (msg->message) {\r
                case WM_IME_STARTCOMPOSITION:\r
-                       InitKeyboardProc(TRUE);\r
+                       AppName::SetIMEState(true);\r
+                       InitKeyboardProc();\r
                        break;\r
                case WM_IME_ENDCOMPOSITION:\r
-                       InitKeyboardProc(FALSE);\r
+                       AppName::SetIMEState(false);\r
+                       InitKeyboardProc();\r
                        break;\r
                }\r
        }\r
@@ -423,169 +310,52 @@ LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lPara
 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)\r
 {\r
        if (nCode == HSHELL_WINDOWACTIVATED) {\r
-               TCHAR className[256];\r
-               GetClassName((HWND)wParam, className, 255);\r
+               SetKeyboardHook(GetWindowThreadProcessId(reinterpret_cast<HWND>(wParam), NULL));\r
+               TCHAR className[CLASS_NAME_LENGTH];\r
+               GetClassName(reinterpret_cast<HWND>(wParam), className, CLASS_NAME_LENGTH);\r
                if (!_tcsicmp(className, _T("ConsoleWindowClass"))) {\r
-                       InitKeyboardProc(FALSE);\r
-                       ShowKeyboardHookState();\r
+                       AppName::SetIMEState(false);\r
+                       InitKeyboardProc();\r
+                       ShowHookState();\r
                }\r
        }\r
        return CallNextHookEx(NULL, nCode, wParam, lParam);\r
 }\r
 \r
-UINT CXkeymacsDll::GetModifierState(BOOL bPhysicalKey)\r
-{\r
-       UINT result = 0;\r
-       if (IsDown(VK_SHIFT, bPhysicalKey))\r
-               result |= SHIFT;\r
-       if (IsDown(VK_CONTROL, bPhysicalKey))\r
-               result |= CONTROL;\r
-       if (IsDown(VK_MENU, bPhysicalKey))\r
-               result |= META;\r
-       return result;\r
-}\r
-\r
-void CXkeymacsDll::SetModifierState(UINT after, UINT before)\r
-{\r
-       if (after & SHIFT && !(before & SHIFT))\r
-               DepressKey(VK_SHIFT);\r
-       else if (!(after & SHIFT) && before & SHIFT)\r
-               ReleaseKey(VK_SHIFT);\r
-\r
-       if (after & CONTROL && !(before & CONTROL)) {\r
-               UpdateKeyboardState(VK_CONTROL, 1);\r
-               DepressKey(VK_CONTROL);\r
-       } else if (!(after & CONTROL) && before & CONTROL) {\r
-               ReleaseKey(VK_CONTROL);\r
-               UpdateKeyboardState(VK_CONTROL, 0);\r
-       }\r
-\r
-       const BOOL bHookApp =\r
-               CUtils::IsVisualCpp() ||  CUtils::IsVisualStudio() ||\r
-               CUtils::IsInternetExplorer() || CUtils::IsFirefox() || CUtils::IsChrome();\r
-       if (after & META && !(before & META)) {\r
-               if (bHookApp)\r
-                       m_nHookAltRelease |= HOOK_ALT_LATER;\r
-               DepressKey(VK_MENU);\r
-       } else if (!(after & META) && before & META) {\r
-               if (bHookApp)\r
-                       ++m_nHookAltRelease;\r
-               ReleaseKey(VK_MENU);\r
-       }\r
-}\r
-\r
-BOOL CXkeymacsDll::UpdateKeyboardState(BYTE bVk, BYTE bState)\r
-{\r
-       BYTE ks[256] = {'\0'};\r
-       if (!GetKeyboardState(ks))\r
-               return FALSE;\r
-       ks[bVk] = bState;\r
-       return SetKeyboardState(ks);\r
-}\r
-\r
-BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)\r
-{\r
-       return bPhysicalKey ? GetAsyncKeyState(bVk) < 0 : GetKeyState(bVk) < 0;\r
-}\r
-\r
-void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)\r
-{\r
-       switch (bVk) {\r
-       case VK_CONTROL:\r
-               if (m_bRightControl)\r
-                       dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
-               break;\r
-\r
-       case VK_MENU:\r
-               if (m_bRightAlt)\r
-                       dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
-               break;\r
-\r
-       case VK_SHIFT:\r
-               if (m_bRightShift) {\r
-                       if (CUtils::IsXPorLater())\r
-                               bVk = VK_RSHIFT;\r
-                       else\r
-                               dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
-               }\r
-               break;\r
-       case VK_PAUSE:\r
-               if (IsDown(VK_CONTROL, FALSE)) // Break\r
-                       dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
-               break;\r
-       case VK_INSERT:\r
-       case VK_DELETE:\r
-       case VK_HOME:\r
-       case VK_END:\r
-       case VK_NEXT:\r
-       case VK_PRIOR:\r
-       case VK_UP:\r
-       case VK_DOWN:\r
-       case VK_RIGHT:\r
-       case VK_LEFT:\r
-       case VK_NUMLOCK:\r
-       case VK_PRINT:\r
-               dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
-               break;\r
-       }\r
-//     CUtils::Log(_T("b: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
-       keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());\r
-//     CUtils::Log(_T("a: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
-}\r
-\r
-void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal)        // bVk is virtual-key code, MSDN said\r
-{\r
-       if (bOriginal) {\r
-//             CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,\r
-//                     IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
-//                     IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
-               SetOriginal(GetModifierState(), bVk);\r
-       }\r
-       DoKeybd_event(bVk, 0);\r
-}\r
-\r
-void CXkeymacsDll::ReleaseKey(BYTE bVk)        // bVk is virtual-key code, MSDN said\r
-{\r
-       DoKeybd_event(bVk, KEYEVENTF_KEYUP);\r
-}\r
-\r
-void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)\r
-{\r
-       while (n--) {\r
-               DepressKey(bVk, bOriginal);\r
-               ReleaseKey(bVk);\r
-       }\r
-}\r
-\r
-void CXkeymacsDll::InitKeyboardProc(BOOL bImeComposition)\r
+void CXkeymacsDll::InitKeyboardProc()\r
 {\r
-       CUtils::SetApplicationName(bImeComposition);\r
-       if (_tcsnicmp(m_Config.szSpecialApp[m_nAppID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_Config.szWindowText[m_nAppID])) {     // PROCESSENTRY32 has only 0xF bytes of Name\r
-               m_nAppID = -1;\r
+       AppName::Init();\r
+       if (m_CurrentConfig == NULL ||\r
+                       _tcsnicmp(m_CurrentConfig->AppName, AppName::GetAppName(), 0xF) ||      // PROCESSENTRY32 has only 0xF bytes of Name\r
+                       !CUtils::IsMatchWindowText(m_CurrentConfig->WindowText)) {\r
+               m_CurrentConfig = NULL;\r
                for (int nAppID = 0; nAppID < MAX_APP; ++nAppID) {\r
-                       if (_tcsnicmp(m_Config.szSpecialApp[nAppID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_Config.szWindowText[nAppID]))\r
+                       AppConfig* appConfig = m_Config.AppConfig + nAppID;\r
+                       if (_tcsnicmp(appConfig->AppName, AppName::GetAppName(), 0xF) || !CUtils::IsMatchWindowText(appConfig->WindowText))\r
                                continue;\r
-                       if (m_nAppID < 0)\r
-                               m_nAppID = nAppID;\r
+                       if (m_CurrentConfig == NULL)\r
+                               m_CurrentConfig = appConfig;\r
                        else {\r
-                               const LPCSTR curText = m_Config.szWindowText[m_nAppID];\r
-                               const LPCSTR newText = m_Config.szWindowText[nAppID];\r
-                               const int curType = CUtils::GetWindowTextType(curText);\r
-                               const int newType = CUtils::GetWindowTextType(newText);\r
+                               LPCTSTR curText = m_CurrentConfig->WindowText;\r
+                               LPCTSTR newText = appConfig->WindowText;\r
+                               int curType = CUtils::GetWindowTextType(curText);\r
+                               int newType = CUtils::GetWindowTextType(newText);\r
                                if (curType < newType || curType == newType && _tcscmp(curText, newText) <= 0)\r
-                                       m_nAppID = nAppID;\r
+                                       m_CurrentConfig = appConfig;\r
                        }\r
                }\r
-               if (m_nAppID < 0)\r
-                       m_nAppID = GetAppID(_T("Default"), 0);\r
+               if (m_CurrentConfig == NULL)\r
+                       m_CurrentConfig = GetAppConfig(_T("Default"), m_Config.AppConfig);\r
        }\r
-       if (m_Config.nSettingStyle[m_nAppID] != SETTING_DISABLE &&\r
-                       (_tcsicmp(m_Config.szSpecialApp[m_nAppID], _T("Default")) || !CUtils::IsDefaultIgnoreApplication()) &&\r
-                       !bImeComposition && CUtils::IsDialog() && m_Config.bUseDialogSetting[m_nAppID])\r
+       if (m_CurrentConfig->SettingStyle != SETTING_DISABLE &&\r
+                       (_tcsicmp(m_CurrentConfig->AppName, _T("Default")) || !CUtils::IsDefaultIgnoreApplication()) &&\r
+                       !AppName::GetIMEState() && CUtils::IsDialog() && m_CurrentConfig->UseDialogSetting)\r
                // Use Dialog Setting\r
-               m_nAppID = GetAppID(_T("Dialog"), m_nAppID);\r
+               m_CurrentConfig = GetAppConfig(_T("Dialog"), m_CurrentConfig);\r
+       m_CmdID = m_CurrentConfig->CmdID;\r
+       m_FuncID = m_CurrentConfig->FuncID;\r
 \r
-       ICONMSG msg[3] = {\r
+       IconState msg[3] = {\r
                {CX_ICON, OFF_ICON, ""},\r
                {MX_ICON, OFF_ICON, ""},\r
                {META_ICON, OFF_ICON, ""}\r
@@ -596,19 +366,20 @@ void CXkeymacsDll::InitKeyboardProc(BOOL bImeComposition)
        CCommands::Reset();\r
 }\r
 \r
-int CXkeymacsDll::GetAppID(LPCSTR szName, int fallback)\r
+AppConfig* CXkeymacsDll::GetAppConfig(LPCTSTR name, AppConfig* fallback)\r
 {\r
        for (int i = 0; i < MAX_APP; ++i)\r
-               if (!_tcsicmp(m_Config.szSpecialApp[i], szName))\r
-                       return i;\r
+               if (!_tcsicmp(m_Config.AppConfig[i].AppName, name))\r
+                       return m_Config.AppConfig + i;\r
        return fallback;\r
 }\r
 \r
 LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
 {\r
-       const BYTE nOrigKey = static_cast<BYTE>(wParam);\r
-       const bool bRelease = (HIWORD(lParam) & KF_UP) != 0;\r
-       const bool bExtended = (HIWORD(lParam) & KF_EXTENDED) != 0;\r
+       BYTE nOrigKey = static_cast<BYTE>(wParam);\r
+       bool bRelease = (HIWORD(lParam) & KF_UP) != 0;\r
+       bool bExtended = (HIWORD(lParam) & KF_EXTENDED) != 0;\r
+       BYTE nKey = nOrigKey;\r
 \r
        static BOOL bLocked = FALSE;\r
        static const BYTE RECURSIVE_KEY = 0x07;\r
@@ -618,7 +389,7 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
 \r
 //     CUtils::Log(_T("nCode = %#x, nKey = %#x, lParam = %#x"), nCode, nOrigKey, lParam);\r
 \r
-       if (!m_bEnableKeyboardHook || CUtils::IsXkeymacs() ||\r
+       if (!m_bEnableKeyboardHook || m_CurrentConfig == NULL || CUtils::IsXkeymacs() ||\r
                        nCode < 0 || nCode == HC_NOREMOVE)\r
                return CallNextHookEx(NULL, nCode, wParam, lParam);\r
 \r
@@ -635,7 +406,6 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
 \r
        CancelMarkWithShift(nOrigKey, bRelease);\r
 \r
-       BYTE nKey = nOrigKey;\r
        switch (nKey) {\r
        case VK_CONTROL:\r
                nKey = bExtended ? VK_RCONTROL : VK_LCONTROL;\r
@@ -648,9 +418,6 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
                break;\r
        }\r
 \r
-#define fCommand(type) (Commands[m_Config.nCommandID[m_nAppID][(type)][nKey]].fCommand)\r
-#define nFunctionID (m_Config.nFunctionID[m_nAppID][nType][nKey])\r
-\r
        if (bRelease) {\r
                switch (nOrigKey) {\r
                case VK_MENU:\r
@@ -666,7 +433,7 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
                case VK_RWIN:\r
                case VK_APPS:\r
                        for (int i = 0; i < MAX_COMMAND_TYPE; ++i) {\r
-                               int (*const fCommand)() = fCommand(i);\r
+                               int (*fCommand)() = CmdTable::Command(m_CmdID[i][nKey]);\r
                                if (fCommand && !(nOrigKey == VK_MENU && fCommand == CCommands::MetaAlt))\r
                                        goto HOOK;\r
                        }\r
@@ -682,11 +449,11 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
                goto DO_NOTHING;\r
        }\r
 \r
-       if (m_Config.nSettingStyle[m_nAppID] == SETTING_DISABLE)\r
+       if (m_CurrentConfig->SettingStyle == SETTING_DISABLE)\r
                goto DO_NOTHING;\r
 \r
        // Do Nothing for Meadow, Mule for Win32, ... if those use default setting.\r
-       if (!_tcsicmp(m_Config.szSpecialApp[m_nAppID], _T("Default")) && CUtils::IsDefaultIgnoreApplication())\r
+       if (!_tcsicmp(m_CurrentConfig->AppName, _T("Default")) && CUtils::IsDefaultIgnoreApplication())\r
                goto DO_NOTHING;\r
 \r
        switch (IsPassThrough(nKey)) {\r
@@ -701,8 +468,8 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
        // set command type\r
        int nType = IsDown(VK_SHIFT) * SHIFT | IsControl() * CONTROL | IsMeta() * META | CCommands::bC_x() * CONTROLX;\r
        // Ignore undefined C-x ?\r
-       if (nType & CONTROLX && fCommand(nType) == NULL && nFunctionID < 0) {\r
-               if (m_Config.bIgnoreUndefinedC_x[m_nAppID]) {\r
+       if (nType & CONTROLX && m_CmdID[nType][nKey] == 0 && m_FuncID[nType][nKey] < 0) {\r
+               if (m_CurrentConfig->IgnoreUndefC_x) {\r
                        CCommands::Reset(GOTO_HOOK);\r
                        goto HOOK;\r
                }\r
@@ -710,8 +477,8 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
        }\r
        // Ignore undefined Meta Ctrl+?\r
        if (CCommands::bM_() && nType & CONTROL) {\r
-               if (fCommand(nType) == NULL && nFunctionID < 0) {\r
-                       if (m_Config.bIgnoreUndefinedMetaCtrl[m_nAppID]) {\r
+               if (m_CmdID[nType][nKey] == 0 && m_FuncID[nType][nKey] < 0) {\r
+                       if (m_CurrentConfig->IgnoreUndefMetaCtrl) {\r
                                if (CheckOriginal(CONTROL, nKey))\r
                                        goto DO_NOTHING;\r
                                CCommands::Reset(GOTO_HOOK);\r
@@ -729,19 +496,17 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
        if (CheckOriginal(nVirtualType, nOrigKey))\r
                goto DO_NOTHING;\r
 \r
-       int (*const fCommand)() = fCommand(nType);\r
+       int (*fCommand)() = CmdTable::Command(m_CmdID[nType][nKey]);\r
        if (fCommand == CCommands::EnableOrDisableXKeymacs) {\r
-               ToggleKeyboardHookState();\r
+               ToggleHookState();\r
                goto HOOK;\r
        }\r
        if (fCommand == CCommands::EnableXKeymacs) {\r
-               if (!m_bHook)\r
-                       ToggleKeyboardHookState();\r
+               SetHookState(true);\r
                goto HOOK;\r
        }\r
        if (fCommand == CCommands::DisableXKeymacs) {\r
-               if (m_bHook)\r
-                       ToggleKeyboardHookState();\r
+               SetHookState(false);\r
                goto HOOK;\r
        }\r
        if (!m_bHook)\r
@@ -789,19 +554,15 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
                        memset(szPath, 0, sizeof(szPath));\r
                        goto HOOK;\r
                } else if (nKey && index < MAX_PATH - 1) {\r
-                       const BOOL bIsShiftDown = IsDown(VK_SHIFT, FALSE);\r
-                       TCHAR nAscii = 0;\r
-                       do { // 1-127\r
-                               if (a2v(++nAscii) == nKey && bIsShiftDown == IsShift(nAscii)) {\r
-//                                     CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, nAscii, nAscii);\r
-                                       if (index < _tcslen(szPath))\r
-                                               memmove(szPath + index + 1, szPath + index, MAX_PATH - index - 1);\r
-                                       szPath[index++] = nAscii;\r
-//                                     CUtils::Log("M-x: %c(%#04x)", nAscii, nAscii);\r
-                                       SetM_xTip(szPath);\r
-                                       goto HOOKX;\r
-                               }\r
-                       } while (nAscii != 127);\r
+                       if (SHORT ascii = ConvVkey(nKey | (static_cast<BYTE>(IsDown(VK_SHIFT, FALSE)) << 8), 1)) {\r
+//                             CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, ascii, ascii);\r
+                               if (index < _tcslen(szPath))\r
+                                       memmove(szPath + index + 1, szPath + index, MAX_PATH - index - 1);\r
+                               szPath[index++] = static_cast<TCHAR>(ascii);\r
+//                             CUtils::Log("M-x: %c(%#04x)", ascii, ascii);\r
+                               SetM_xTip(szPath);\r
+                               goto HOOKX;\r
+                       }\r
                }\r
        }\r
 \r
@@ -817,13 +578,13 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
        }\r
 \r
 #define OneShotModifier(type, vk, mod) \\r
-       if (fCommand(nType & ~type) == CCommands::OneShotModifier ## mod || \\r
-                       fCommand(nType) == CCommands::OneShotModifier ## mod ## Repeat) { \\r
+       if (CmdTable::Command(m_CmdID[nType & ~type][nKey]) == CCommands::OneShotModifier ## mod || \\r
+                       CmdTable::Command(m_CmdID[nType][nKey]) == CCommands::OneShotModifier ## mod ## Repeat) { \\r
                nOneShotModifier[nKey] = vk; \\r
                DepressKey(vk); \\r
                bCherryOneShotModifier = TRUE; \\r
                goto HOOK; \\r
-       } else if (fCommand(nType & ~CONTROL) == CCommands::OneShotModifier ## mod ## Repeat) { \\r
+       } else if (CmdTable::Command(m_CmdID[nType & ~CONTROL][nKey]) == CCommands::OneShotModifier ## mod ## Repeat) { \\r
                ReleaseKey(vk); \\r
                bCherryOneShotModifier = FALSE; \\r
                Kdu(nKey); \\r
@@ -840,13 +601,12 @@ LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lPa
        if (i == MAX_KEY)\r
                bCherryOneShotModifier = FALSE;\r
 \r
-       if (0 <= nFunctionID && nFunctionID < MAX_FUNCTION && m_Config.szFunctionDefinition[nFunctionID][0]) {\r
-               CallFunction(nFunctionID);\r
+       int id = m_FuncID[nType][nKey];\r
+       if (0 <= id && id < MAX_FUNCTION) {\r
+               CallFunction(id);\r
                CCommands::Reset(GOTO_HOOK);\r
                goto HOOK;\r
        }\r
-#undef fCommand\r
-#undef nFunctionID\r
 \r
        if (!fCommand) {\r
                if (nOrigKey == VK_CONTROL || nOrigKey == VK_MENU || nOrigKey == VK_SHIFT)\r
@@ -901,11 +661,8 @@ RECURSIVE_COMMAND:
 \r
 DO_NOTHING:\r
        SetModifierIcons();\r
-       if (m_bRecordingMacro && (!bRelease || m_bDown[wParam])) {\r
-               KbdMacro m = { nCode, wParam, lParam, TRUE };\r
-               m_Macro.push_back(m);\r
-               m_bDown[wParam] |= !bRelease;\r
-       }\r
+       if (m_kbdMacro)\r
+               m_kbdMacro->Record(nKey, bRelease);\r
        return CallNextHookEx(NULL, nCode, wParam, lParam);\r
 \r
 RECURSIVE:\r
@@ -920,38 +677,6 @@ HOOK_RECURSIVE_KEY:
        return TRUE;\r
 }\r
 \r
-void CXkeymacsDll::SetModifierIcons()\r
-{\r
-       ICONMSG msg[6] = {\r
-               {MX_ICON, CCommands::bM_x(), ""},\r
-               {CX_ICON, CCommands::bC_x(), ""},\r
-               {META_ICON, CCommands::bM_(), ""},\r
-               {SHIFT_ICON, IsDown(VK_SHIFT, FALSE), ""},\r
-               {CTRL_ICON, IsControl(), ""},\r
-               {ALT_ICON, IsDown(VK_MENU, FALSE), ""}\r
-       };\r
-       _tcscpy_s(msg[0].szTip, m_M_xTip);\r
-       SendIconMessage(msg, 6);\r
-}\r
-\r
-BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)\r
-{\r
-       BYTE bVk = 0;\r
-       const BYTE *pnID = m_Config.nCommandID[m_nAppID][NONE];\r
-       do {\r
-               switch (bVk) {\r
-               case VK_SHIFT:\r
-               case VK_CONTROL:\r
-               case VK_MENU:\r
-               case 0xf0: // Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.\r
-                       continue;\r
-               }\r
-               if (IsDown(bVk, bPhysicalKey) && Commands[pnID[bVk]].fCommand == Modifier)\r
-                       return TRUE;\r
-       } while (++bVk);\r
-       return FALSE;\r
-}\r
-\r
 void CXkeymacsDll::CancelMarkWithShift(BYTE nKey, bool bRelease)\r
 {\r
        static bool bShift;\r
@@ -975,6 +700,199 @@ exit:
        return;\r
 }\r
 \r
+int CXkeymacsDll::IsPassThrough(BYTE nKey)\r
+{\r
+       BYTE bVk = 0;\r
+       const BYTE *pnID = m_CmdID[NONE]; \r
+       do {\r
+               if (IsDown(bVk) && CmdTable::Command(pnID[bVk]) == CCommands::PassThrough) {\r
+                       if (bVk == nKey)\r
+                               return GOTO_HOOK;\r
+                       return GOTO_DO_NOTHING;\r
+               }\r
+       } while (++bVk);\r
+       return CONTINUE;\r
+}\r
+\r
+void CXkeymacsDll::InvokeM_x(LPCTSTR szPath)\r
+{\r
+//     CUtils::Log("M-x: szPath=_%s_", szPath);\r
+       int (*fCommand)() = NULL;\r
+       for (int i = 0; i < MAX_COMMAND; ++i)\r
+               if (_tcsicmp(szPath, CmdTable::Name(i)) == 0) {\r
+                       fCommand = CmdTable::Command(i);\r
+                       break;\r
+               }\r
+       if (fCommand) {\r
+//             CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);\r
+               fCommand();\r
+       } else {\r
+//             CUtils::Log("M-x: Path: _%s_", szPath);\r
+               ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);\r
+       }\r
+}\r
+\r
+void CXkeymacsDll::SetModifierIcons()\r
+{\r
+       IconState icons[6] = {\r
+               {MX_ICON, CCommands::bM_x(), ""},\r
+               {CX_ICON, CCommands::bC_x(), ""},\r
+               {META_ICON, CCommands::bM_(), ""},\r
+               {SHIFT_ICON, IsDown(VK_SHIFT, FALSE), ""},\r
+               {CTRL_ICON, IsControl(), ""},\r
+               {ALT_ICON, IsDown(VK_MENU, FALSE), ""}\r
+       };\r
+       _tcscpy_s(icons[0].Tip, m_M_xTip);\r
+       SendIconMessage(icons, 6);\r
+}\r
+\r
+void CXkeymacsDll::SetM_xTip(LPCTSTR szPath)\r
+{\r
+       _tcscpy_s(m_M_xTip, "M-x LED");\r
+       if (szPath && _tcslen(szPath) < 128 - 5)\r
+               _stprintf_s(m_M_xTip, "M-x %s", szPath);\r
+}\r
+\r
+void CXkeymacsDll::SendIconMessage(IconState *state, int num)\r
+{\r
+       DWORD ack, read;\r
+       IPC32Message msg;\r
+       msg.Type = IPC32_ICON;\r
+       memcpy(msg.IconState, state, num * sizeof(IconState));\r
+       if (!CallNamedPipe(m_Config.PipeNameForIPC32, &msg, offsetof(IPC32Message, IconState) + sizeof(IconState) * num, &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT)) {\r
+#ifdef DEBUG_IPC\r
+               CUtils::Log(_T("SendIconMessage: CallNamedPipe failed. (%d)"), GetLastError());\r
+#endif\r
+       }\r
+}\r
+\r
+void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)\r
+{\r
+       while (n--) {\r
+               DepressKey(bVk, bOriginal);\r
+               ReleaseKey(bVk);\r
+       }\r
+}\r
+\r
+void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal)        // bVk is virtual-key code, MSDN said\r
+{\r
+       if (bOriginal) {\r
+//             CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,\r
+//                     IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
+//                     IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
+               SetOriginal(GetModifierState(), bVk);\r
+       }\r
+       DoKeybd_event(bVk, 0);\r
+}\r
+\r
+void CXkeymacsDll::ReleaseKey(BYTE bVk)        // bVk is virtual-key code, MSDN said\r
+{\r
+       DoKeybd_event(bVk, KEYEVENTF_KEYUP);\r
+}\r
+\r
+void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)\r
+{\r
+       switch (bVk) {\r
+       case VK_CONTROL:\r
+               if (m_bRightControl)\r
+                       dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
+               break;\r
+\r
+       case VK_MENU:\r
+               if (m_bRightAlt)\r
+                       dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
+               break;\r
+\r
+       case VK_SHIFT:\r
+               if (m_bRightShift)\r
+                       bVk = VK_RSHIFT;\r
+               break;\r
+       case VK_PAUSE:\r
+               if (IsDown(VK_CONTROL, FALSE)) // Break\r
+                       dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
+               break;\r
+       case VK_INSERT:\r
+       case VK_DELETE:\r
+       case VK_HOME:\r
+       case VK_END:\r
+       case VK_NEXT:\r
+       case VK_PRIOR:\r
+       case VK_UP:\r
+       case VK_DOWN:\r
+       case VK_RIGHT:\r
+       case VK_LEFT:\r
+       case VK_NUMLOCK:\r
+       case VK_PRINT:\r
+               dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
+               break;\r
+       }\r
+//     CUtils::Log(_T("b: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
+       keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());\r
+//     CUtils::Log(_T("a: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
+}\r
+\r
+void CXkeymacsDll::SetOriginal(UINT nType, BYTE bVk)\r
+{\r
+       m_nOriginal[nType & ~SHIFT][bVk]++;\r
+}\r
+\r
+int CXkeymacsDll::CheckOriginal(UINT nType, BYTE bVk)\r
+{\r
+       nType &= ~SHIFT;\r
+       if (m_nOriginal[nType][bVk])\r
+               return m_nOriginal[nType][bVk]--;\r
+       return 0;\r
+}\r
+\r
+UINT CXkeymacsDll::GetModifierState(BOOL bPhysicalKey)\r
+{\r
+       UINT result = 0;\r
+       if (IsDown(VK_SHIFT, bPhysicalKey))\r
+               result |= SHIFT;\r
+       if (IsDown(VK_CONTROL, bPhysicalKey))\r
+               result |= CONTROL;\r
+       if (IsDown(VK_MENU, bPhysicalKey))\r
+               result |= META;\r
+       return result;\r
+}\r
+\r
+void CXkeymacsDll::SetModifierState(UINT after, UINT before)\r
+{\r
+       if (after & SHIFT && !(before & SHIFT))\r
+               DepressKey(VK_SHIFT);\r
+       else if (!(after & SHIFT) && before & SHIFT)\r
+               ReleaseKey(VK_SHIFT);\r
+\r
+       if (after & CONTROL && !(before & CONTROL))\r
+               DepressKey(VK_CONTROL);\r
+       else if (!(after & CONTROL) && before & CONTROL) {\r
+               ReleaseKey(VK_CONTROL);\r
+               UpdateKeyboardState(VK_CONTROL, 0);\r
+       }\r
+\r
+       BOOL bHookApp =\r
+               CUtils::IsVisualCpp() ||  CUtils::IsVisualStudio() ||\r
+               CUtils::IsInternetExplorer() || CUtils::IsFirefox() || CUtils::IsChrome();\r
+       if (after & META && !(before & META)) {\r
+               if (bHookApp)\r
+                       m_nHookAltRelease |= HOOK_ALT_LATER;\r
+               DepressKey(VK_MENU);\r
+       } else if (!(after & META) && before & META) {\r
+               if (bHookApp)\r
+                       ++m_nHookAltRelease;\r
+               ReleaseKey(VK_MENU);\r
+       }\r
+}\r
+\r
+BOOL CXkeymacsDll::UpdateKeyboardState(BYTE bVk, BYTE bState)\r
+{\r
+       BYTE ks[256] = {'\0'};\r
+       if (!GetKeyboardState(ks))\r
+               return FALSE;\r
+       ks[bVk] = bState;\r
+       return SetKeyboardState(ks);\r
+}\r
+\r
 BOOL CXkeymacsDll::IsControl()\r
 {\r
        return CCommands::bC_() || IsDepressedModifier(CCommands::C_);\r
@@ -985,9 +903,32 @@ BOOL CXkeymacsDll::IsMeta()
        return CCommands::bM_() || IsDepressedModifier(CCommands::MetaAlt);\r
 }\r
 \r
+BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)\r
+{\r
+       BYTE bVk = 0;\r
+       const BYTE *pnID = m_CmdID[NONE];\r
+       do {\r
+               switch (bVk) {\r
+               case VK_SHIFT:\r
+               case VK_CONTROL:\r
+               case VK_MENU:\r
+               case 0xf0: // Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.\r
+                       continue;\r
+               }\r
+               if (IsDown(bVk, bPhysicalKey) && CmdTable::Command(pnID[bVk]) == Modifier)\r
+                       return TRUE;\r
+       } while (++bVk);\r
+       return FALSE;\r
+}\r
+\r
+BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)\r
+{\r
+       return bPhysicalKey ? GetAsyncKeyState(bVk) < 0 : GetKeyState(bVk) < 0;\r
+}\r
+\r
 void CXkeymacsDll::AddKillRing(BOOL bNewData)\r
 {\r
-       if (m_Config.nKillRingMax[m_nAppID] == 0) {\r
+       if (m_CurrentConfig->KillRingMax == 0) {\r
                return;\r
        }\r
 \r
@@ -1018,7 +959,7 @@ void CXkeymacsDll::AddKillRing(BOOL bNewData)
 \r
        m_nKillRing = 0;\r
 \r
-       if (m_Config.nKillRingMax[m_nAppID] < m_oKillRing.GetCount()) {\r
+       if (m_CurrentConfig->KillRingMax < m_oKillRing.GetCount()) {\r
                CClipboardSnap *pSnap = m_oKillRing.GetTail();\r
                delete pSnap;\r
                pSnap = NULL;\r
@@ -1030,7 +971,7 @@ void CXkeymacsDll::AddKillRing(BOOL bNewData)
 // Return FALSE if there is no more data\r
 CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)\r
 {\r
-       if (m_Config.nKillRingMax[m_nAppID] == 0) {\r
+       if (m_CurrentConfig->KillRingMax == 0) {\r
                return NULL;\r
        }\r
 \r
@@ -1064,126 +1005,46 @@ CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)
        return pSnap->GetNext();\r
 }\r
 \r
-void CXkeymacsDll::SetOriginal(UINT nType, BYTE bVk)\r
-{\r
-       m_nOriginal[nType & ~SHIFT][bVk]++;\r
-}\r
-\r
-int CXkeymacsDll::CheckOriginal(UINT nType, BYTE bVk)\r
-{\r
-       nType &= ~SHIFT;\r
-       if (m_nOriginal[nType][bVk])\r
-               return m_nOriginal[nType][bVk]--;\r
-       return 0;\r
-}\r
-\r
 void CXkeymacsDll::IncreaseKillRingIndex(int nKillRing)\r
 {\r
        m_nKillRing += nKillRing;\r
 }\r
 \r
-BOOL CXkeymacsDll::GetEnableCUA()\r
-{\r
-       return m_Config.bEnableCUA[m_nAppID];\r
-}\r
-\r
-void CXkeymacsDll::StartRecordMacro()\r
-{\r
-       if (CCommands::bC_u())\r
-               CallMacro();\r
-       m_bRecordingMacro = TRUE;\r
-       m_Macro.erase(m_Macro.begin(), m_Macro.end());\r
-       ZeroMemory(m_bDown, MAX_KEY);\r
-}\r
-\r
-void CXkeymacsDll::EndRecordMacro()\r
+bool CXkeymacsDll::GetEnableCUA()\r
 {\r
-       m_bRecordingMacro = FALSE;\r
-       while (!m_Macro.empty()) { // remove not released push\r
-               const KbdMacro& m = m_Macro.back();\r
-               if (HIWORD(m.lParam) & KF_UP)\r
-                       break;\r
-               m_Macro.pop_back();\r
-       }\r
+       return m_CurrentConfig->EnableCUA;\r
 }\r
 \r
-void CXkeymacsDll::CallMacro()\r
+bool CXkeymacsDll::Get326Compatible()\r
 {\r
-       if (m_bRecordingMacro)\r
-               m_bRecordingMacro = FALSE;\r
-       UINT before = GetModifierState(FALSE);\r
-       SetModifierState(0, before);\r
-       for (std::list<KbdMacro>::const_iterator m = m_Macro.begin(); m != m_Macro.end(); ++m)\r
-               if (HIWORD(m->lParam) & KF_UP)\r
-                       ReleaseKey(static_cast<BYTE>(m->wParam));\r
-               else\r
-                       DepressKey(static_cast<BYTE>(m->wParam), m->bOriginal);\r
-       SetModifierState(before, 0);\r
+       return m_CurrentConfig->Is326Compatible;\r
 }\r
 \r
-BOOL CXkeymacsDll::Is106Keyboard()\r
+bool CXkeymacsDll::Is106Keyboard()\r
 {\r
-       return m_Config.b106Keyboard;\r
+       return m_Config.Is106Keyboard;\r
 }\r
 \r
-int CXkeymacsDll::IsPassThrough(BYTE nKey)\r
+void CXkeymacsDll::SetKbMacro(KbdMacro* kbdMacro)\r
 {\r
-       BYTE bVk = 0;\r
-       const BYTE *pnID = m_Config.nCommandID[m_nAppID][NONE]; \r
-       do {\r
-               if (IsDown(bVk) && Commands[pnID[bVk]].fCommand == CCommands::PassThrough) {\r
-                       if (bVk == nKey)\r
-                               return GOTO_HOOK;\r
-                       return GOTO_DO_NOTHING;\r
-               }\r
-       } while (++bVk);\r
-       return CONTINUE;\r
+       m_kbdMacro = kbdMacro;\r
 }\r
 \r
 // call an original command which is defined in dot.xkeymacs\r
-void CXkeymacsDll::CallFunction(int nFuncID)\r
+void CXkeymacsDll::CallFunction(int id)\r
 {\r
-       if (nFuncID < 0 || nFuncID >= MAX_FUNCTION)\r
-               return;\r
-       LPCTSTR def = m_Config.szFunctionDefinition[nFuncID];\r
-       if (!def[0])\r
-               return;\r
-       std::vector<KeyBind> keybinds;\r
-       const LPCTSTR last = def + _tcslen(def) - 1;\r
-       if (*def == _T('"') && *last == _T('"')) {\r
-               ++def; // skip '"'\r
-               while (def < last)\r
-                       keybinds.push_back(ParseKey(def));\r
-       } else if (*def == _T('[') && *last == _T(']')) {\r
-               while (++def < last) { // skip '[', ']', and ' '\r
-                       if (*def == _T('?')) { // [?f ?o ?o]\r
-                               keybinds.push_back(ParseKey(++def));\r
-                               continue;\r
-                       }\r
-                       // [VK]\r
-                       for (int i = 0; i < MAX_KEYNAME; ++i) {\r
-                               size_t keylen = _tcslen(KeyNames[i].name);\r
-                               if (!_tcsncmp(def, KeyNames[i].name, keylen)) {\r
-                                       KeyBind keybind = {NONE, KeyNames[i].bVk};\r
-                                       keybinds.push_back(keybind);\r
-                                       def += keylen;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-       } else\r
+       if (id < 0 || id >= MAX_FUNCTION)\r
                return;\r
-\r
        BOOL bM_x = FALSE;\r
        TCHAR szPath[MAX_PATH] = {'\0'};\r
        unsigned int index = 0;\r
        BOOL bInitialized = FALSE;\r
        UINT before = GetModifierState(FALSE);\r
 \r
-       for (std::vector<KeyBind>::const_iterator p = keybinds.begin(); p != keybinds.end(); ++p) {\r
-               const int nType = p->nType;\r
-               const BYTE bVk = p->bVk;\r
-               int (*fCommand)() = nType < MAX_COMMAND_TYPE ? Commands[m_Config.nCommandID[m_nAppID][nType][bVk]].fCommand : NULL;\r
+       for (KeyBind *p = m_Config.FuncDefs[id]; p->bVk; ++p) {\r
+               int nType = p->nType;\r
+               BYTE bVk = p->bVk;\r
+               int (*fCommand)() = nType < MAX_COMMAND_TYPE ? CmdTable::Command(m_CmdID[nType][bVk]) : NULL;\r
                if (fCommand) {\r
                        if (fCommand == CCommands::ExecuteExtendedCommand)\r
                                bM_x = TRUE;\r
@@ -1191,7 +1052,7 @@ void CXkeymacsDll::CallFunction(int nFuncID)
                                SetModifierState(0, before);\r
                                bInitialized = TRUE;\r
                        }\r
-//                     CUtils::Log("CallFunction: Command Name: %s", Commands[m_Config.nCommandID[m_nAppID][nType][bVk]].szCommandName);\r
+//                     CUtils::Log("CallFunction: Command Name: %s", Commands[m_CurrentConfig->CmdID[nType][bVk]].szCommandName);\r
                        while (fCommand() == GOTO_RECURSIVE)\r
                                ;\r
                        continue;\r
@@ -1199,16 +1060,8 @@ void CXkeymacsDll::CallFunction(int nFuncID)
                if (bM_x) {\r
                        if (bVk == VK_RETURN)\r
                                InvokeM_x(szPath);\r
-                       else if (bVk != 0) {\r
-                               TCHAR nAscii = 0;\r
-                               do { // 1-127\r
-                                       if (a2v(++nAscii) == bVk && ((nType & SHIFT) != 0) == IsShift(nAscii)) {\r
-//                                             CUtils::Log("M-x: %#X (%c), %#X (%c)", bVk, bVk, nAscii, nAscii);\r
-                                               szPath[index++] = nAscii;\r
-                                               break;\r
-                                       }\r
-                               } while (nAscii != 127);\r
-                       }\r
+                       else if (bVk != 0)\r
+                               szPath[index++] = static_cast<TCHAR>(ConvVkey((bVk | (nType << 8)) & 0x7ff /* drop CONTROLX */, 1));\r
                        continue;\r
                }\r
                if (!bInitialized) {\r
@@ -1224,7 +1077,7 @@ void CXkeymacsDll::CallFunction(int nFuncID)
                if (nType & SHIFT)\r
                        DepressKey(VK_SHIFT);\r
                Kdu(bVk);\r
-               const int nNextType = (p + 1) != keybinds.end() ? (p + 1)->nType : 0;\r
+               int nNextType = (p + 1)->nType;\r
                if (nType & SHIFT && !(nNextType & SHIFT))\r
                        ReleaseKey(VK_SHIFT);\r
                if (nType & WIN_ALT && !(nNextType & WIN_ALT))\r
@@ -1241,219 +1094,33 @@ void CXkeymacsDll::CallFunction(int nFuncID)
        return;\r
 }\r
 \r
-KeyBind CXkeymacsDll::ParseKey(LPCTSTR& def)\r
+SHORT CXkeymacsDll::ConvVkey(SHORT in, int mode)\r
 {\r
-       KeyBind keybind = {NONE};\r
-       if (*def == _T('\\')) { // set modifiers\r
-               ++def;\r
-       LOOP:\r
-               for (int i = 0; i < MAX_MODIFIER; ++i) {\r
-                       size_t len = _tcslen(Modifiers[i].name);\r
-                       if (!_tcsncmp(def, Modifiers[i].name, len)) {\r
-                               keybind.nType |= Modifiers[i].id;\r
-                               def += len;\r
-                               goto LOOP;\r
-                       }\r
-               }\r
-       }\r
-       if (IsShift(*def) && !(keybind.nType & (WIN_CTRL | WIN_ALT | WIN_WIN)))\r
-               keybind.nType |= SHIFT;\r
-       int i = 0;\r
-       for (; i < MAX_KEYNAME; ++i) {\r
-               size_t len = _tcslen(KeyNames[i].name);\r
-               if (!_tcsncmp(def, KeyNames[i].name, len)) {\r
-                       def += len;\r
-                       break;\r
-               }\r
-       }\r
-       keybind.bVk = i < MAX_KEYNAME ? KeyNames[i].bVk : a2v(*def++);\r
-       return keybind;\r
-}\r
-\r
-BOOL CXkeymacsDll::IsShift(TCHAR nAscii)\r
-{\r
-       switch (nAscii) {\r
-       case _T(' '):\r
-               return FALSE;\r
-       case _T('!'):\r
-       case _T('"'):\r
-       case _T('#'):\r
-       case _T('$'):\r
-       case _T('%'):\r
-       case _T('&'):\r
-               return TRUE;\r
-       case _T('\''):\r
-               return m_Config.b106Keyboard;\r
-       case _T('('):\r
-       case _T(')'):\r
-       case _T('*'):\r
-       case _T('+'):\r
-               return TRUE;\r
-       case _T(','):\r
-       case _T('-'):\r
-       case _T('.'):\r
-       case _T('/'):\r
-       case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'):\r
-               return FALSE;\r
-       case _T(':'):\r
-               return !m_Config.b106Keyboard;\r
-       case _T(';'):\r
-               return FALSE;\r
-       case _T('<'):\r
-               return TRUE;\r
-       case _T('='):\r
-               return m_Config.b106Keyboard;\r
-       case _T('>'):\r
-       case _T('?'):\r
-               return TRUE;\r
-       case _T('@'):\r
-               return !m_Config.b106Keyboard;\r
-       case _T('A'): case _T('B'): case _T('C'): case _T('D'): case _T('E'): case _T('F'): case _T('G'): case _T('H'): case _T('I'): case _T('J'): \r
-       case _T('K'): case _T('L'): case _T('M'): case _T('N'): case _T('O'): case _T('P'): case _T('Q'): case _T('R'): case _T('S'): case _T('T'): \r
-       case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
-               return TRUE;\r
-       case _T('['):\r
-       case _T('\\'):\r
-       case _T(']'):\r
-               return FALSE;\r
-       case _T('^'):\r
-               return !m_Config.b106Keyboard;\r
-       case _T('_'):\r
-               return TRUE;\r
-       case _T('`'):\r
-               return m_Config.b106Keyboard;\r
-       case _T('a'): case _T('b'): case _T('c'): case _T('d'): case _T('e'): case _T('f'): case _T('g'): case _T('h'): case _T('i'): case _T('j'): \r
-       case _T('k'): case _T('l'): case _T('m'): case _T('n'): case _T('o'): case _T('p'): case _T('q'): case _T('r'): case _T('s'): case _T('t'): \r
-       case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
-               return FALSE;\r
-       case _T('{'):\r
-       case _T('|'):\r
-       case _T('}'):\r
-       case _T('~'):\r
-               return TRUE;\r
-       default:\r
-               return FALSE;\r
+       HKL h = GetKeyboardLayout(0);\r
+       if (mode == 0) { // ASCII to VKey and state\r
+               SHORT r = VkKeyScanEx(static_cast<TCHAR>(in), h);\r
+               if (r < 0) // no key correcpont to the char\r
+                       return 0;\r
+               return r & 0x7ff; // drop state flags of Hankaku and others\r
        }\r
-}\r
-\r
-BYTE CXkeymacsDll::a2v(TCHAR nAscii)\r
-{\r
-       switch (nAscii) {\r
-       case _T(' '):\r
-               return VK_SPACE;\r
-       case _T('!'):\r
-               return '1';\r
-       case _T('"'):\r
-               return m_Config.b106Keyboard ? '2' : (BYTE) 0xde;       // VK_OEM_7\r
-       case _T('#'):\r
-               return '3';\r
-       case _T('$'):\r
-               return '4';\r
-       case _T('%'):\r
-               return '5';\r
-       case _T('&'):\r
-               return m_Config.b106Keyboard ? '6' : '7';\r
-       case _T('\''):\r
-               return m_Config.b106Keyboard ? '7' : (BYTE) 0xde;       // VK_OEM_7\r
-       case _T('('):\r
-               return m_Config.b106Keyboard ? '8' : '9';\r
-       case _T(')'):\r
-               return m_Config.b106Keyboard ? '9' : '0';\r
-       case _T('*'):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xba : '8';       // VK_OEM_1\r
-       case _T('+'):\r
-               return 0xbb;    // VK_OEM_PLUS\r
-       case _T(','):\r
-               return 0xbc;    // VK_OEM_COMMA\r
-       case _T('-'):\r
-               return 0xbd;    // VK_OEM_MINUS\r
-       case _T('.'):\r
-               return 0xbe;    // VK_OEM_PERIOD\r
-       case _T('/'):\r
-               return 0xbf;    // VK_OEM_2\r
-       case _T('0'): case _T('1'): case _T('2'): case _T('3'): case _T('4'): case _T('5'): case _T('6'): case _T('7'): case _T('8'): case _T('9'):\r
-               return nAscii;\r
-       case _T(':'):\r
-               return 0xba;    // VK_OEM_1\r
-       case _T(';'):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xbb : (BYTE) 0xba;       // VK_OEM_PLUS  VK_OEM_1\r
-       case _T('<'):\r
-               return 0xbc;    // VK_OEM_COMMA\r
-       case _T('='):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xbd : (BYTE) 0xbb;       // VK_OEM_MINUS VK_OEM_PLUS\r
-       case _T('>'):\r
-               return 0xbe;    // VK_OEM_PERIOD\r
-       case _T('?'):\r
-               return 0xbf;    // VK_OEM_2\r
-       case _T('@'):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xc0 : '2';\r
-       case _T('A'): case _T('B'): case _T('C'): case _T('D'): case _T('E'): case _T('F'): case _T('G'): case _T('H'): case _T('I'): case _T('J'): \r
-       case _T('K'): case _T('L'): case _T('M'): case _T('N'): case _T('O'): case _T('P'): case _T('Q'): case _T('R'): case _T('S'): case _T('T'): \r
-       case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
-               return nAscii;\r
-       case _T('['):\r
-               return 0xdb;    // VK_OEM_4\r
-       case _T('\\'):\r
-               return 0xdc;    // VK_OEM_5\r
-       case _T(']'):\r
-               return 0xdd;    // VK_OEM_6\r
-       case _T('^'):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xde : '6';       // VK_OEM_7\r
-       case _T('_'):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xe2 : (BYTE) 0xbd;       // VK_OEM_102   VK_OEM_MINUS\r
-       case _T('`'):\r
-               return 0xc0;    // VK_OEM_3\r
-       case _T('a'): case _T('b'): case _T('c'): case _T('d'): case _T('e'): case _T('f'): case _T('g'): case _T('h'): case _T('i'): case _T('j'): \r
-       case _T('k'): case _T('l'): case _T('m'): case _T('n'): case _T('o'): case _T('p'): case _T('q'): case _T('r'): case _T('s'): case _T('t'): \r
-       case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
-               return (BYTE) (nAscii - (_T('a') - _T('A')));\r
-       case _T('{'):\r
-               return 0xdb;    // VK_OEM_4\r
-       case _T('|'):\r
-               return 0xdc;    // VK_OEM_5\r
-       case _T('}'):\r
-               return 0xdd;    // VK_OEM_6\r
-       case _T('~'):\r
-               return m_Config.b106Keyboard ? (BYTE) 0xde : (BYTE) 0xc0;       // VK_OEM_7     VK_OEM_3\r
-       default:\r
+       // VKey and state to ASCII\r
+       const BYTE down = 0x80;\r
+       BYTE state[256] = {0};\r
+       if (in & (1 << 8))\r
+               state[VK_SHIFT] = down;\r
+       if (in & (2 << 8))\r
+               state[VK_CONTROL] = down;\r
+       if (in & (4 << 8))\r
+               state[VK_MENU] = down;\r
+       UINT vkey = in & 0xff;\r
+       state[vkey] = down;\r
+       WORD word = 0;\r
+       int r = ToAsciiEx(vkey, MapVirtualKeyEx(vkey, MAPVK_VK_TO_VSC, h), state, &word, 0, h);\r
+       if (r == 0)\r
                return 0;\r
-       }\r
-}\r
-\r
-BOOL CXkeymacsDll::IsMatchWindowText(CString szWindowText)\r
-{\r
-       BOOL bIsMatchWindowText = TRUE;\r
-\r
-       TCHAR szCurrentWindowText[WINDOW_TEXT_LENGTH] = {'\0'};\r
-       GetWindowText(GetForegroundWindow(), szCurrentWindowText, sizeof(szCurrentWindowText));\r
-\r
-       switch (CUtils::GetWindowTextType(szWindowText)) {\r
-       case IDS_WINDOW_TEXT_MATCH:                                                             // *foo*\r
-               szWindowText.Delete(0);                                                         // Delete first '*'\r
-               szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
-               bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText);\r
-               break;\r
-       case IDS_WINDOW_TEXT_MATCH_FORWARD:                                             // foo*\r
-               szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
-               bIsMatchWindowText = 0 == CString(szCurrentWindowText).Find(szWindowText);\r
-               break;\r
-       case IDS_WINDOW_TEXT_MATCH_BACKWARD:                                    // *foo\r
-               szWindowText.Delete(0);                                                         // Delete first '*'\r
-               bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText, CString(szCurrentWindowText).GetLength() - szWindowText.GetLength());\r
-               break;\r
-       case IDS_WINDOW_TEXT_MATCH_FULL:                                                // foo\r
-               bIsMatchWindowText = szWindowText == CString(szCurrentWindowText);\r
-               break;\r
-       case IDS_WINDOW_TEXT_IGNORE:                                                    // *\r
-               bIsMatchWindowText = TRUE;\r
-               break;\r
-       default:\r
-               ASSERT(0);\r
-               break;\r
-       }\r
-\r
-//     CUtils::Log(_T("IsMatchWindowText: %d, _%s_, _%s_"), bIsMatchWindowText, szCurrentWindowText, szWindowText);\r
-       return bIsMatchWindowText;\r
+       if (r == 1)\r
+               return static_cast<SHORT>(word);\r
+       return static_cast<SHORT>(word >> 8); // drop a dead key\r
 }\r
 \r
 void CXkeymacsDll::SetAccelerate(int nAccelerate)\r
@@ -1492,46 +1159,6 @@ void CXkeymacsDll::SetCursorData(HCURSOR hEnable, HCURSOR hDisableTMP, HCURSOR h
 \r
 void CXkeymacsDll::DoSetCursor()\r
 {\r
-       if (m_bCursor && m_hCurrentCursor) {\r
+       if (m_bCursor && m_hCurrentCursor)\r
                ::SetCursor(m_hCurrentCursor);\r
-       }\r
-}\r
-\r
-BOOL CXkeymacsDll::Get326Compatible()\r
-{\r
-       return m_Config.b326Compatible[m_nAppID];\r
-}\r
-\r
-void CXkeymacsDll::InvokeM_x(LPCTSTR szPath)\r
-{\r
-//     CUtils::Log("M-x: szPath=_%s_", szPath);\r
-       int (*fCommand)() = NULL;\r
-\r
-       for (int i = 0; i < MAX_COMMAND; ++i) {\r
-               if (_tcsicmp(szPath, Commands[i].szCommandName) == 0) {\r
-                       fCommand = Commands[i].fCommand;\r
-                       break;\r
-               }\r
-       }\r
-\r
-       if (fCommand) {\r
-//             CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);\r
-               fCommand();\r
-       } else {\r
-//             CUtils::Log("M-x: Path: _%s_", szPath);\r
-               ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);\r
-       }\r
-}\r
-\r
-void CXkeymacsDll::SetM_xTip(LPCTSTR szPath)\r
-{\r
-       _tcscpy_s(m_M_xTip, "M-x LED");\r
-       if (szPath && _tcslen(szPath) < 128 - 5)\r
-               _stprintf_s(m_M_xTip, "M-x %s", szPath);\r
-}\r
-\r
-BOOL CXkeymacsDll::SendIconMessage(ICONMSG *pMsg, DWORD num)\r
-{\r
-       DWORD ack, read;\r
-       return CallNamedPipe(ICON_PIPE, pMsg, sizeof(ICONMSG) * num, &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT);\r
 }\r