OSDN Git Service

Fix a bug where some commands sensitive to being repeated such as
[xkeymacs/xkeymacs.git] / xkeymacsdll / xkeymacsdll.cpp
1 // xkeymacsdll.cpp : Defines the initialization routines for the DLL.\r
2 //\r
3 \r
4 #include "stdafx.h"\r
5 #include "resource.h"\r
6 #include "Utils.h"\r
7 #include "Commands.h"\r
8 #include <afxdllx.h>\r
9 #include <math.h>\r
10 #include <Imm.h>\r
11 #include <vector>\r
12 \r
13 #ifdef _DEBUG\r
14 #define new DEBUG_NEW\r
15 #undef THIS_FILE\r
16 static char THIS_FILE[] = __FILE__;\r
17 #endif\r
18 \r
19 struct Modifier {\r
20         LPCTSTR name;\r
21         int id;\r
22 };\r
23 \r
24 static const Modifier Modifiers[] = {\r
25 //      { _T("A-"), ALT },\r
26         { _T("C-"), CONTROL},\r
27 //      { _T("H-"), HYPER },\r
28         { _T("M-"), META },\r
29         { _T("S-"), SHIFT },\r
30 //      { _T("s-"), SUPER },\r
31         { _T("Ctrl+"), WIN_CTRL },\r
32         { _T("Alt+"), WIN_ALT },\r
33         { _T("Win+"), WIN_WIN },\r
34 };\r
35 static const int MAX_MODIFIER = _countof(Modifiers);\r
36 \r
37 static const KeyName KeyNames[] = {\r
38 //      { VK_LBUTTON,           _T("mouse-1") },                                // does not work well\r
39 //      { VK_RBUTTON,           _T("mouse-3") },                                // does not work well\r
40         { VK_CANCEL,            _T("break") },\r
41 //      { VK_MBUTTON,           _T("mouse-2") },                                // does not work well\r
42         { VK_BACK,                      _T("backspace") },\r
43         { VK_TAB,                       _T("tab") },\r
44         { VK_RETURN,            _T("return") },\r
45         { VK_CAPITAL,           _T("capslock") },\r
46         { VK_KANA,                      _T("kana") },\r
47         { VK_KANJI,                     _T("kanji") },\r
48         { VK_ESCAPE,            _T("escape") },\r
49         { VK_CONVERT,           _T("convert") },\r
50         { VK_NONCONVERT,        _T("nonconvert") },\r
51 //      { VK_SPACE,                     _T("SPC") },                                    // [? ]\r
52         { VK_PRIOR,                     _T("prior") },\r
53         { VK_NEXT,                      _T("next") },\r
54         { VK_END,                       _T("end") },\r
55         { VK_HOME,                      _T("home") },\r
56         { VK_LEFT,                      _T("left") },\r
57         { VK_UP,                        _T("up") },\r
58         { VK_RIGHT,                     _T("right") },\r
59         { VK_DOWN,                      _T("down") },\r
60         { VK_SELECT,            _T("select") },\r
61         { VK_PRINT,                     _T("print") },\r
62         { VK_EXECUTE,           _T("execute") },\r
63         { VK_SNAPSHOT,          _T("printscreen") },                    // work as print\r
64         { VK_INSERT,            _T("insert") },\r
65         { VK_DELETE,            _T("delete") },\r
66         { VK_LWIN,                      _T("lwindow") },\r
67         { VK_RWIN,                      _T("rwindow") },\r
68         { VK_APPS,                      _T("apps") },\r
69         { VK_SLEEP,                     _T("sleep") },\r
70         { VK_NUMPAD0,           _T("kp-0") },\r
71         { VK_NUMPAD1,           _T("kp-1") },\r
72         { VK_NUMPAD2,           _T("kp-2") },\r
73         { VK_NUMPAD3,           _T("kp-3") },\r
74         { VK_NUMPAD4,           _T("kp-4") },\r
75         { VK_NUMPAD5,           _T("kp-5") },\r
76         { VK_NUMPAD6,           _T("kp-6") },\r
77         { VK_NUMPAD7,           _T("kp-7") },\r
78         { VK_NUMPAD8,           _T("kp-8") },\r
79         { VK_NUMPAD9,           _T("kp-9") },\r
80         { VK_MULTIPLY,          _T("kp-multiply") },\r
81         { VK_ADD,                       _T("kp-add") },\r
82         { VK_SUBTRACT,          _T("kp-subtract") },\r
83         { VK_DECIMAL,           _T("kp-decimal") },\r
84         { VK_DIVIDE,            _T("kp-divide") },\r
85 //      { VK_F1,                        _T("f1") },                                             // FIXME\r
86 //      { 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
87         { VK_F3,                        _T("f3") },\r
88         { VK_F4,                        _T("f4") },\r
89         { VK_F5,                        _T("f5") },\r
90         { VK_F6,                        _T("f6") },\r
91         { VK_F7,                        _T("f7") },\r
92         { VK_F8,                        _T("f8") },\r
93         { VK_F9,                        _T("f9") },\r
94         { VK_F10,                       _T("f10") },\r
95         { VK_F11,                       _T("f11") },\r
96         { VK_F12,                       _T("f12") },\r
97         { VK_F13,                       _T("f13") },\r
98         { VK_F14,                       _T("f14") },\r
99         { VK_F15,                       _T("f15") },\r
100         { VK_F16,                       _T("f16") },\r
101         { VK_F17,                       _T("f17") },\r
102         { VK_F18,                       _T("f18") },\r
103         { VK_F19,                       _T("f19") },\r
104         { VK_F20,                       _T("f20") },\r
105         { VK_F21,                       _T("f21") },\r
106         { VK_F22,                       _T("f22") },\r
107         { VK_F23,                       _T("f23") },\r
108         { VK_F24,                       _T("f24") },\r
109         { VK_F1,                        _T("f1") },\r
110         { VK_F2,                        _T("f2") },\r
111         { VK_NUMLOCK,           _T("kp-numlock") },\r
112         { VK_SCROLL,            _T("scroll") },\r
113         { 0xa6,                         _T("browser-back") },                   // VK_BROWSER_BACK\r
114         { 0xa7,                         _T("browser-forward") },                // VK_BROWSER_FORWARD\r
115         { 0xa8,                         _T("browser-refresh") },                // VK_BROWSER_REFRESH\r
116         { 0xa9,                         _T("browser-stop") },                   // VK_BROWSER_STOP\r
117         { 0xaa,                         _T("browser-search") },                 // VK_BROWSER_SEARCH\r
118         { 0xab,                         _T("browser-favorites") },              // VK_BROWSER_FAVORITES\r
119         { 0xac,                         _T("browser-home") },                   // VK_BROWSER_HOME\r
120         { 0xad,                         _T("volume-mute") },                    // VK_VOLUME_MUTE\r
121         { 0xae,                         _T("volume-down") },                    // VK_VOLUME_DOWN\r
122         { 0xaf,                         _T("volume-up") },                              // VK_VOLUME_UP\r
123         { 0xb0,                         _T("media-next-track") },               // VK_MEDIA_NEXT_TRACK\r
124         { 0xb1,                         _T("media-prev-track") },               // VK_MEDIA_PREV_TRACK\r
125         { 0xb2,                         _T("media-stop") },                             // VK_MEDIA_STOP\r
126         { 0xb3,                         _T("media-play-pause") },               // VK_MEDIA_PLAY_PAUSE\r
127         { 0xb4,                         _T("launch-mail") },                    // VK_LAUNCH_MAIL\r
128         { 0xb5,                         _T("launch-media-select") },    // VK_LAUNCH_MEDIA_SELECT\r
129         { 0xb6,                         _T("launch-1") },                               // VK_LAUNCH_APP1\r
130         { 0xb7,                         _T("launch-2") },                               // VK_LAUNCH_APP2\r
131 };\r
132 static const int MAX_KEYNAME = _countof(KeyNames);\r
133 \r
134 static AFX_EXTENSION_MODULE XkeymacsdllDLL = { NULL, NULL };\r
135 \r
136 static HINSTANCE g_hDllInst = NULL;\r
137 static __declspec(thread) HHOOK g_hHookKeyboard = NULL;\r
138 \r
139 extern "C" int APIENTRY\r
140 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
141 {\r
142         g_hDllInst = hInstance;\r
143         \r
144         // Remove this if you use lpReserved\r
145         UNREFERENCED_PARAMETER(lpReserved);\r
146 \r
147         switch (dwReason) {\r
148         case DLL_PROCESS_ATTACH:\r
149                 TRACE0("XKEYMACSDLL.DLL Initializing!\n");\r
150 \r
151                 // Extension DLL one-time initialization\r
152                 if (!AfxInitExtensionModule(XkeymacsdllDLL, hInstance)) {\r
153                         return 0;\r
154                 }\r
155 \r
156                 // Insert this DLL into the resource chain\r
157                 // NOTE: If this Extension DLL is being implicitly linked to by\r
158                 //  an MFC Regular DLL (such as an ActiveX Control)\r
159                 //  instead of an MFC application, then you will want to\r
160                 //  remove this line from DllMain and put it in a separate\r
161                 //  function exported from this Extension DLL.  The Regular DLL\r
162                 //  that uses this Extension DLL should then explicitly call that\r
163                 //  function to initialize this Extension DLL.  Otherwise,\r
164                 //  the CDynLinkLibrary object will not be attached to the\r
165                 //  Regular DLL's resource chain, and serious problems will\r
166                 //  result.\r
167 \r
168                 try {\r
169                         new CDynLinkLibrary(XkeymacsdllDLL);\r
170                 }\r
171                 catch (CMemoryException* e) {\r
172                         e->Delete();\r
173 //                      CUtils::Log("DllMain: 'new' threw an exception");\r
174                 }\r
175                 break;\r
176         case DLL_PROCESS_DETACH:\r
177                 TRACE0("XKEYMACSDLL.DLL Terminating!\n");\r
178                 // Terminate the library before destructors are called\r
179                 AfxTermExtensionModule(XkeymacsdllDLL);\r
180                 // fall through\r
181         case DLL_THREAD_DETACH:\r
182                 CXkeymacsDll::ReleaseKeyboardHook();\r
183                 break;\r
184         }\r
185         return 1;   // ok\r
186 }\r
187 \r
188 //////////////////////////////////////////////////////////////////////\r
189 // CXkeymacsDll Class\r
190 //////////////////////////////////////////////////////////////////////\r
191 \r
192 #include "xkeymacsDll.h"\r
193 #pragma data_seg(".xkmcs")\r
194         bool    CXkeymacsDll::m_bEnableKeyboardHook = false;\r
195         DWORD   CXkeymacsDll::m_nHookAltRelease = 0;\r
196         HHOOK   CXkeymacsDll::m_hHookCallWnd = NULL;\r
197         HHOOK   CXkeymacsDll::m_hHookCallWndRet = NULL;\r
198         HHOOK   CXkeymacsDll::m_hHookGetMessage = NULL;\r
199         HHOOK   CXkeymacsDll::m_hHookShell = NULL;\r
200         BOOL    CXkeymacsDll::m_bRightControl   = FALSE;\r
201         BOOL    CXkeymacsDll::m_bRightAlt               = FALSE;\r
202         BOOL    CXkeymacsDll::m_bRightShift             = FALSE;\r
203         BOOL    CXkeymacsDll::m_bHook                   = TRUE;\r
204         CList<CClipboardSnap *, CClipboardSnap *> CXkeymacsDll::m_oKillRing;\r
205         int             CXkeymacsDll::m_nKillRing = 0;\r
206         BYTE    CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
207         int             CXkeymacsDll::m_nAppID = 0;\r
208         int             CXkeymacsDll::m_nAccelerate = 0;\r
209         int             CXkeymacsDll::m_nKeyboardSpeed = 31;\r
210         HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};\r
211         HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;\r
212         BOOL    CXkeymacsDll::m_bCursor = FALSE;\r
213         TCHAR   CXkeymacsDll::m_M_xTip[128] = "";\r
214         CONFIG  CXkeymacsDll::m_Config = {0};\r
215 #pragma data_seg()\r
216 BOOL CXkeymacsDll::m_bRecordingMacro = FALSE;\r
217 BOOL CXkeymacsDll::m_bDown[MAX_KEY] = {0};\r
218 std::list<KbdMacro> CXkeymacsDll::m_Macro;\r
219 \r
220 BOOL CXkeymacsDll::SaveConfig()\r
221 {\r
222         TCHAR szTmp[MAX_PATH];\r
223         if (!GetTempPath(MAX_PATH, szTmp))\r
224                 return FALSE;\r
225         if (_tmakepath_s(szTmp, NULL, szTmp, _T("xkeymacs"), _T("tmp")))\r
226                 return FALSE;\r
227         HANDLE hFile = CreateFile(szTmp, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);\r
228         if (hFile == INVALID_HANDLE_VALUE)\r
229                 return FALSE;\r
230         DWORD written;\r
231         BOOL res = WriteFile(hFile, &m_Config, sizeof(m_Config), &written, NULL) || written != sizeof(m_Config);\r
232         CloseHandle(hFile);\r
233         return res;\r
234 }\r
235 \r
236 BOOL CXkeymacsDll::LoadConfig()\r
237 {\r
238         TCHAR szTmp[MAX_PATH];\r
239         if (!GetTempPath(MAX_PATH, szTmp))\r
240                 return FALSE;\r
241         if (_tmakepath_s(szTmp, NULL, szTmp, _T("xkeymacs"), _T("tmp")))\r
242                 return FALSE;\r
243         HANDLE hFile = CreateFile(szTmp, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);\r
244         if (hFile == INVALID_HANDLE_VALUE)\r
245                 return FALSE;\r
246         DWORD read;\r
247         BOOL res = ReadFile(hFile, &m_Config, sizeof(m_Config), &read, NULL) && read == sizeof(m_Config);\r
248         CloseHandle(hFile);\r
249         return res;\r
250 }\r
251 \r
252 void CXkeymacsDll::SetConfig(const CONFIG& config)\r
253 {\r
254         m_Config = config;\r
255 }\r
256 \r
257 void CXkeymacsDll::SetHooks()\r
258 {\r
259         m_hHookCallWnd = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProc, g_hDllInst, 0);\r
260         m_hHookCallWndRet = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)CallWndRetProc, g_hDllInst, 0);\r
261         m_hHookGetMessage = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllInst, 0);\r
262         m_hHookShell = SetWindowsHookEx(WH_SHELL, (HOOKPROC)ShellProc, g_hDllInst, 0);\r
263         m_bEnableKeyboardHook = true;\r
264 }\r
265 \r
266 void CXkeymacsDll::SetKeyboardHook()\r
267 {\r
268         if (!g_hHookKeyboard)\r
269                 g_hHookKeyboard = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hDllInst, GetCurrentThreadId());\r
270 }\r
271 \r
272 inline void unhook(HHOOK &hh) {\r
273         if (hh)\r
274                 UnhookWindowsHookEx(hh);\r
275         hh = NULL;\r
276 }\r
277 \r
278 void CXkeymacsDll::ResetHooks() \r
279 {\r
280         ReleaseHooks();\r
281         SetHooks();\r
282 }\r
283 \r
284 void CXkeymacsDll::ReleaseHooks()\r
285 {\r
286         unhook(m_hHookCallWnd);\r
287         unhook(m_hHookCallWndRet);\r
288         unhook(m_hHookGetMessage);\r
289         unhook(m_hHookShell);\r
290         m_bEnableKeyboardHook = false;\r
291 }\r
292 \r
293 void CXkeymacsDll::ReleaseKeyboardHook()\r
294 {\r
295         unhook(g_hHookKeyboard);\r
296 }\r
297 \r
298 void CXkeymacsDll::ToggleKeyboardHookState()\r
299 {\r
300         m_bHook = !m_bHook;\r
301         ShowKeyboardHookState();\r
302 }\r
303 \r
304 void CXkeymacsDll::ShowKeyboardHookState()\r
305 {\r
306         ICONMSG msg = {MAIN_ICON,};\r
307         if (m_bHook) {\r
308                 if (CCommands::IsTemporarilyDisableXKeymacs()) {\r
309                         msg.nState = STATUS_DISABLE_TMP;\r
310                         m_hCurrentCursor = m_hCursor[STATUS_DISABLE_TMP];\r
311                 } else {\r
312                         msg.nState = STATUS_ENABLE;\r
313                         m_hCurrentCursor = m_hCursor[STATUS_ENABLE];\r
314                 }\r
315         } else {\r
316                 msg.nState = STATUS_DISABLE_WOCQ;\r
317         }\r
318         if (m_Config.nSettingStyle[m_nAppID] == SETTING_DISABLE\r
319          || (!_tcsicmp(m_Config.szSpecialApp[m_nAppID], _T("Default"))\r
320           && CUtils::IsDefaultIgnoreApplication())) {\r
321                 msg.nState = STATUS_DISABLE;\r
322                 m_hCurrentCursor = m_hCursor[STATUS_DISABLE];\r
323         }\r
324         SendIconMessage(&msg, 1);\r
325         DoSetCursor();\r
326 }\r
327 \r
328 BOOL CXkeymacsDll::IsKeyboardHook()\r
329 {\r
330         return m_bHook;\r
331 }\r
332 \r
333 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)\r
334 {\r
335         SetKeyboardHook();\r
336         if (nCode < 0)\r
337                 return CallNextHookEx(m_hHookCallWnd, nCode, wParam, lParam);\r
338         const CWPSTRUCT *cwps = reinterpret_cast<CWPSTRUCT *>(lParam);\r
339         switch (cwps->message) {\r
340         case WM_IME_STARTCOMPOSITION:\r
341                 InitKeyboardProc(TRUE);\r
342                 break;\r
343         case WM_IME_ENDCOMPOSITION:\r
344                 InitKeyboardProc(FALSE);\r
345                 break;\r
346         case WM_SETFOCUS:\r
347                 if (cwps->hwnd == GetForegroundWindow()) {\r
348                         InitKeyboardProc(FALSE);\r
349                         ShowKeyboardHookState();\r
350                 }\r
351                 break;\r
352         case WM_NCACTIVATE:\r
353                 if (cwps->wParam && cwps->hwnd == GetForegroundWindow()) {\r
354                         InitKeyboardProc(FALSE);\r
355                         ShowKeyboardHookState();\r
356                 }\r
357                 break;\r
358         }\r
359         return CallNextHookEx(m_hHookCallWnd, nCode, wParam, lParam);\r
360 }\r
361 \r
362 LRESULT CALLBACK CXkeymacsDll::CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)\r
363 {\r
364         if (nCode >= 0) {\r
365                 const CWPRETSTRUCT *cwprets = reinterpret_cast<CWPRETSTRUCT *>(lParam);\r
366                 switch (cwprets->message) {\r
367                 case WM_SETTEXT:\r
368                         if (cwprets->hwnd == GetForegroundWindow())\r
369                                 InitKeyboardProc(FALSE);\r
370                         break;\r
371                 case WM_SETCURSOR:\r
372                         DoSetCursor();\r
373                         break;\r
374                 }\r
375         }\r
376         return CallNextHookEx(m_hHookCallWndRet, nCode, wParam, lParam);\r
377 }\r
378 \r
379 LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)\r
380 {\r
381         const MSG *msg = reinterpret_cast<MSG *>(lParam);\r
382         switch (msg->message) {\r
383         case WM_IME_STARTCOMPOSITION:\r
384                 InitKeyboardProc(TRUE);\r
385                 break;\r
386         case WM_IME_ENDCOMPOSITION:\r
387                 InitKeyboardProc(FALSE);\r
388                 break;\r
389         }\r
390         return CallNextHookEx(m_hHookGetMessage, nCode, wParam, lParam);\r
391 }\r
392 \r
393 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)\r
394 {\r
395         if (nCode == HSHELL_WINDOWACTIVATED) {\r
396                 TCHAR className[256];\r
397                 GetClassName((HWND)wParam, className, 255);\r
398                 if (!_tcsicmp(className, _T("ConsoleWindowClass"))) {\r
399                         InitKeyboardProc(FALSE);\r
400                         ShowKeyboardHookState();\r
401                 }\r
402         }\r
403         return CallNextHookEx( m_hHookShell, nCode, wParam, lParam );\r
404 }\r
405 \r
406 UINT CXkeymacsDll::GetModifierState(BOOL bPhysicalKey)\r
407 {\r
408         UINT result = 0;\r
409         if (IsDown(VK_SHIFT, bPhysicalKey))\r
410                 result |= SHIFT;\r
411         if (IsDown(VK_CONTROL, bPhysicalKey))\r
412                 result |= CONTROL;\r
413         if (IsDown(VK_MENU, bPhysicalKey))\r
414                 result |= META;\r
415         return result;\r
416 }\r
417 \r
418 void CXkeymacsDll::SetModifierState(const UINT after, const UINT before)\r
419 {\r
420         if (after & SHIFT && !(before & SHIFT))\r
421                 DepressKey(VK_SHIFT);\r
422         else if (!(after & SHIFT) && before & SHIFT)\r
423                 ReleaseKey(VK_SHIFT);\r
424 \r
425         if (after & CONTROL && !(before & CONTROL)) {\r
426                 UpdateKeyboardState(VK_CONTROL, 1);\r
427                 DepressKey(VK_CONTROL);\r
428         } else if (!(after & CONTROL) && before & CONTROL) {\r
429                 ReleaseKey(VK_CONTROL);\r
430                 UpdateKeyboardState(VK_CONTROL, 0);\r
431         }\r
432 \r
433         const BOOL bHookApp = CUtils::IsVisualCpp() || CUtils::IsFirefox() || CUtils::IsVisualStudio() || CUtils::IsInternetExplorer();\r
434         if (after & META && !(before & META)) {\r
435                 if (bHookApp)\r
436                         m_nHookAltRelease |= HOOK_ALT_LATER;\r
437                 DepressKey(VK_MENU);\r
438         } else if (!(after & META) && before & META) {\r
439                 if (bHookApp)\r
440                         ++m_nHookAltRelease;\r
441                 ReleaseKey(VK_MENU);\r
442         }\r
443 }\r
444 \r
445 BOOL CXkeymacsDll::UpdateKeyboardState(BYTE bVk, BYTE bState)\r
446 {\r
447         BYTE ks[256] = {'\0'};\r
448         if (!GetKeyboardState(ks))\r
449                 return FALSE;\r
450         ks[bVk] = bState;\r
451         return SetKeyboardState(ks);\r
452 }\r
453 \r
454 BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)\r
455 {\r
456         return bPhysicalKey ? GetAsyncKeyState(bVk) < 0 : GetKeyState(bVk) < 0;\r
457 }\r
458 \r
459 // Do keybd_event\r
460 void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)\r
461 {\r
462         // Set KEYEVENTF_EXTENDEDKEY if needed\r
463         switch (bVk) {\r
464         case VK_CONTROL:\r
465                 if (m_bRightControl)\r
466                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
467                 break;\r
468 \r
469         case VK_MENU:\r
470                 if (m_bRightAlt)\r
471                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
472                 break;\r
473 \r
474         case VK_SHIFT:\r
475                 if (m_bRightShift) {\r
476                         if (CUtils::IsXPorLater())\r
477                                 bVk = VK_RSHIFT;\r
478                         else\r
479                                 dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
480                 }\r
481                 break;\r
482         case VK_PAUSE:\r
483                 if (IsDown(VK_CONTROL, FALSE)) // Break\r
484                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
485                 break;\r
486         case VK_INSERT:\r
487         case VK_DELETE:\r
488         case VK_HOME:\r
489         case VK_END:\r
490         case VK_NEXT:\r
491         case VK_PRIOR:\r
492         case VK_UP:\r
493         case VK_DOWN:\r
494         case VK_RIGHT:\r
495         case VK_LEFT:\r
496         case VK_NUMLOCK:\r
497         case VK_PRINT:\r
498                 dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
499                 break;\r
500         }\r
501 //      CUtils::Log(_T("b: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
502         keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());\r
503 //      CUtils::Log(_T("a: %x, %x, %x, %#hx, %#hx"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
504 }\r
505 \r
506 // the key is being depressed\r
507 void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal) // bVk is virtual-key code, MSDN said\r
508 {\r
509         if (bOriginal) {\r
510 //              CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,\r
511 //                      IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
512 //                      IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
513                 SetOriginal(GetModifierState(), bVk);\r
514         }\r
515         DoKeybd_event(bVk, 0);\r
516 }\r
517 \r
518 // the key is being released\r
519 void CXkeymacsDll::ReleaseKey(BYTE bVk) // bVk is virtual-key code, MSDN said\r
520 {\r
521         DoKeybd_event(bVk, KEYEVENTF_KEYUP);\r
522 }\r
523 \r
524 // bVk down, bVk up\r
525 void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)\r
526 {\r
527         while (n--) {\r
528                 DepressKey(bVk, bOriginal);\r
529                 ReleaseKey(bVk);\r
530         }\r
531 }\r
532 \r
533 void CXkeymacsDll::InitKeyboardProc(BOOL bImeComposition)\r
534 {\r
535         CUtils::SetApplicationName(bImeComposition);\r
536         if (_tcsnicmp(m_Config.szSpecialApp[m_nAppID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_Config.szWindowText[m_nAppID])) {     // PROCESSENTRY32 has only 0xF bytes of Name\r
537                 m_nAppID = -1;\r
538                 for (int nAppID = 0; nAppID < MAX_APP; ++nAppID) {\r
539                         if (_tcsnicmp(m_Config.szSpecialApp[nAppID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_Config.szWindowText[nAppID]))\r
540                                 continue;\r
541                         if (m_nAppID < 0)\r
542                                 m_nAppID = nAppID;\r
543                         else {\r
544                                 const LPCSTR curText = m_Config.szWindowText[m_nAppID];\r
545                                 const LPCSTR newText = m_Config.szWindowText[nAppID];\r
546                                 const int curType = CUtils::GetWindowTextType(curText);\r
547                                 const int newType = CUtils::GetWindowTextType(newText);\r
548                                 if (curType < newType || curType == newType && _tcscmp(curText, newText) <= 0)\r
549                                         m_nAppID = nAppID;\r
550                         }\r
551                 }\r
552                 if (m_nAppID < 0)\r
553                         m_nAppID = GetAppID(_T("Default"), 0);\r
554         }\r
555         if (m_Config.nSettingStyle[m_nAppID] != SETTING_DISABLE &&\r
556                         (_tcsicmp(m_Config.szSpecialApp[m_nAppID], _T("Default")) || !CUtils::IsDefaultIgnoreApplication()) &&\r
557                         !bImeComposition && CUtils::IsDialog() && m_Config.bUseDialogSetting[m_nAppID])\r
558                 // Use Dialog Setting\r
559                 m_nAppID = GetAppID(_T("Dialog"), m_nAppID);\r
560 \r
561         ICONMSG msg[3] = {\r
562                 {CX_ICON, OFF_ICON, ""},\r
563                 {MX_ICON, OFF_ICON, ""},\r
564                 {META_ICON, OFF_ICON, ""}\r
565         };\r
566         SendIconMessage(msg, 3);\r
567         CCommands::SetMark(FALSE);\r
568         CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
569         CCommands::Reset();\r
570 }\r
571 \r
572 int CXkeymacsDll::GetAppID(const LPCSTR szName, const int fallback)\r
573 {\r
574         for (int i = 0; i < MAX_APP; ++i)\r
575                 if (!_tcsicmp(m_Config.szSpecialApp[i], szName))\r
576                         return i;\r
577         return fallback;\r
578 }\r
579 \r
580 LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
581 {\r
582         const BYTE nOrigKey = static_cast<BYTE>(wParam);\r
583         const bool bRelease = (lParam & BEING_RELEASED) != 0;\r
584         const bool bExtended = (lParam & EXTENDED_KEY) != 0;\r
585 \r
586         static BOOL bLocked = FALSE;\r
587         static const BYTE RECURSIVE_KEY = 0x07;\r
588         static int (*fLastCommand)() = NULL;\r
589         static BYTE nOneShotModifier[MAX_KEY] = {'\0'};\r
590         static BOOL bCherryOneShotModifier = FALSE;\r
591 \r
592 //      CUtils::Log(_T("nCode = %#x, nKey = %#x, lParam = %p, %d, %d"), nCode, nOrigKey, lParam, IsDll64, Is64ProcessHwnd(GetForegroundWindow()));\r
593 \r
594         if (!m_bEnableKeyboardHook || CUtils::IsXkeymacs() ||\r
595                         nCode < 0 || nCode == HC_NOREMOVE)\r
596                 return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
597 \r
598 //      CUtils::Log(_T("nKey = %#x, ext = %d, rel = %d, pre = %d, %#hx, %#hx"), nOrigKey,\r
599 //              (lParam & EXTENDED_KEY) ? 1 : 0, (lParam & BEING_RELEASED) ? 1 : 0, (lParam & REPEATED_KEY) ? 1 : 0,\r
600 //              GetKeyState(nOrigKey), GetAsyncKeyState(nOrigKey));\r
601 \r
602         if (nOrigKey == RECURSIVE_KEY) {\r
603                 if (bRelease)\r
604                         goto HOOK_RECURSIVE_KEY;\r
605                 else\r
606                         goto RECURSIVE_COMMAND;\r
607         }\r
608 \r
609         CancelMarkWithShift(nOrigKey, bRelease);\r
610 \r
611         BYTE nKey = nOrigKey;\r
612         switch (nKey) {\r
613         case VK_CONTROL:\r
614                 nKey = bExtended ? VK_RCONTROL : VK_LCONTROL;\r
615                 break;\r
616         case VK_MENU:\r
617                 nKey = bExtended ? VK_RMENU : VK_LMENU;\r
618                 break;\r
619         case VK_SHIFT:\r
620                 nKey = bExtended ? VK_RSHIFT : VK_LSHIFT;\r
621                 break;\r
622         }\r
623 \r
624 #define fCommand(type) (Commands[m_Config.nCommandID[m_nAppID][(type)][nKey]].fCommand)\r
625 #define nFunctionID (m_Config.nFunctionID[m_nAppID][nType][nKey])\r
626 \r
627         if (bRelease) {\r
628                 switch (nOrigKey) {\r
629                 case VK_MENU:\r
630                         if (m_nHookAltRelease) {\r
631                                 if (m_nHookAltRelease & ~HOOK_ALT_LATER)\r
632                                         m_nHookAltRelease--;\r
633                                 else if (m_nHookAltRelease & HOOK_ALT_LATER)\r
634                                         m_nHookAltRelease = 0;\r
635                                 goto HOOK;\r
636                         }\r
637                         // pass through\r
638                 case VK_LWIN:\r
639                 case VK_RWIN:\r
640                 case VK_APPS:\r
641                         for (int i = 0; i < MAX_COMMAND_TYPE; ++i) {\r
642                                 int (*const fCommand)() = fCommand(i);\r
643                                 if (fCommand && !(nOrigKey == VK_MENU && fCommand == CCommands::MetaAlt))\r
644                                         goto HOOK;\r
645                         }\r
646                 }\r
647                 if (nOneShotModifier[nKey]) {\r
648                         ReleaseKey(nOneShotModifier[nKey]);\r
649                         nOneShotModifier[nKey] = 0;\r
650                         if (bCherryOneShotModifier) {\r
651                                 bCherryOneShotModifier = FALSE;\r
652                                 Kdu(nKey);\r
653                         }\r
654                 }\r
655                 goto DO_NOTHING;\r
656         }\r
657 \r
658         if (m_Config.nSettingStyle[m_nAppID] == SETTING_DISABLE)\r
659                 goto DO_NOTHING;\r
660 \r
661         // Do Nothing for Meadow, Mule for Win32, ... if those use default setting.\r
662         if (!_tcsicmp(m_Config.szSpecialApp[m_nAppID], _T("Default")) && CUtils::IsDefaultIgnoreApplication())\r
663                 goto DO_NOTHING;\r
664 \r
665         switch (IsPassThrough(nKey)) {\r
666         case GOTO_DO_NOTHING:\r
667                 goto DO_NOTHING;\r
668         case GOTO_HOOK:\r
669                 goto HOOK;\r
670         case CONTINUE:\r
671                 break;\r
672         }\r
673 \r
674         // set command type\r
675         int nType = IsDown(VK_SHIFT) * SHIFT | IsControl() * CONTROL | IsMeta() * META | CCommands::bC_x() * CONTROLX;\r
676         // Ignore undefined C-x ?\r
677         if (nType & CONTROLX && fCommand(nType) == NULL && nFunctionID < 0) {\r
678                 if (m_Config.bIgnoreUndefinedC_x[m_nAppID]) {\r
679                         CCommands::Reset(GOTO_HOOK);\r
680                         goto HOOK;\r
681                 }\r
682                 nType &= ~CONTROLX;\r
683         }\r
684         // Ignore undefined Meta Ctrl+?\r
685         if (CCommands::bM_() && nType & CONTROL && fCommand(nType) == NULL && nFunctionID < 0) {\r
686                 if (m_Config.bIgnoreUndefinedMetaCtrl[m_nAppID]) {\r
687                         if (CheckOriginal(CONTROL, nKey))\r
688                                 goto DO_NOTHING;\r
689                         CCommands::Reset(GOTO_HOOK);\r
690                         goto HOOK;\r
691                         nType &= ~META;\r
692                 }\r
693         }\r
694 \r
695         int nVirtualCommandType = GetModifierState(FALSE);\r
696         if (nOrigKey == VK_CONTROL)\r
697                 nVirtualCommandType &= ~CONTROL;\r
698         if (nOrigKey == VK_MENU)\r
699                 nVirtualCommandType &= ~META;\r
700         if (CheckOriginal(nVirtualCommandType, nOrigKey)) {\r
701                 goto DO_NOTHING;\r
702         }\r
703 \r
704         int (*const fCommand)() = fCommand(nType);\r
705         if (fCommand == CCommands::EnableOrDisableXKeymacs) {\r
706                 ToggleKeyboardHookState();\r
707                 goto HOOK;\r
708         }\r
709         if (fCommand == CCommands::EnableXKeymacs) {\r
710                 if (!m_bHook)\r
711                         ToggleKeyboardHookState();\r
712                 goto HOOK;\r
713         }\r
714         if (fCommand == CCommands::DisableXKeymacs) {\r
715                 if (m_bHook)\r
716                         ToggleKeyboardHookState();\r
717                 goto HOOK;\r
718         }\r
719         if (!m_bHook)\r
720                 goto DO_NOTHING;\r
721 \r
722         if (CCommands::bM_x() && !bRelease) {\r
723                 static size_t index = 0;\r
724                 static TCHAR szPath[MAX_PATH] = {'\0'};\r
725                 if (fCommand == CCommands::BackwardChar) {\r
726                         if (index)\r
727                                 --index;\r
728                         goto HOOKX;\r
729                 } else if (fCommand == CCommands::BeginningOfLine) {\r
730                         index = 0;\r
731                         goto HOOKX;\r
732                 } else if (fCommand == CCommands::DeleteBackwardChar) {\r
733                         if (index) {\r
734                                 --index;\r
735                                 memmove(szPath + index, szPath + index + 1, MAX_PATH - index);\r
736                                 SetM_xTip(szPath);\r
737                         }\r
738                         goto HOOKX;\r
739                 } else if (fCommand == CCommands::DeleteChar) {\r
740                         if (index < _tcslen(szPath)) {\r
741                                 memmove(szPath + index, szPath + index + 1, MAX_PATH - index);\r
742                                 SetM_xTip(szPath);\r
743                         }\r
744                         goto HOOKX;\r
745                 } else if (fCommand == CCommands::EndOfLine) {\r
746                         index = _tcslen(szPath);\r
747                         goto HOOKX;\r
748                 } else if (fCommand == CCommands::ForwardChar) {\r
749                         if (index < _tcslen(szPath))\r
750                                 ++index;\r
751                         goto HOOKX;\r
752                 } else if (fCommand == CCommands::KeyboardQuit) {\r
753                         CCommands::bM_x(FALSE);\r
754                         index = 0;\r
755                         memset(szPath, 0, sizeof(szPath));\r
756                         goto HOOK;\r
757                 } else if (nKey == VK_RETURN || fCommand == CCommands::Newline) {\r
758                         InvokeM_x(szPath);\r
759                         CCommands::bM_x(FALSE);\r
760                         index = 0;\r
761                         memset(szPath, 0, sizeof(szPath));\r
762                         goto HOOK;\r
763                 } else if (nKey && index < MAX_PATH - 1) {\r
764                         const BOOL bIsShiftDown = IsDown(VK_SHIFT, FALSE);\r
765                         TCHAR nAscii = 0;\r
766                         do { // 1-127\r
767                                 if (a2v(++nAscii) == nKey && bIsShiftDown == IsShift(nAscii)) {\r
768 //                                      CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, nAscii, nAscii);\r
769                                         if (index < _tcslen(szPath))\r
770                                                 memmove(szPath + index + 1, szPath + index, MAX_PATH - index - 1);\r
771                                         szPath[index++] = nAscii;\r
772 //                                      CUtils::Log("M-x: %c(%#04x)", nAscii, nAscii);\r
773                                         SetM_xTip(szPath);\r
774                                         goto HOOKX;\r
775                                 }\r
776                         } while (nAscii != 127);\r
777                 }\r
778         }\r
779 \r
780         if (CCommands::bC_u() && nType == NONE) {\r
781                 if ('0' <= nKey && nKey <= '9') {\r
782                         CCommands::NumericArgument(nKey - '0');\r
783                         goto HOOK0_9;\r
784                 }\r
785                 if (nKey == VK_OEM_MINUS) {\r
786                         CCommands::NumericArgumentMinus();\r
787                         goto HOOK0_9;\r
788                 }\r
789         }\r
790 \r
791 #define OneShotModifier(type, vk, mod) \\r
792         if (fCommand(nType & ~type) == CCommands::OneShotModifier ## mod || \\r
793                         fCommand(nType) == CCommands::OneShotModifier ## mod ## Repeat) { \\r
794                 nOneShotModifier[nKey] = vk; \\r
795                 DepressKey(vk); \\r
796                 bCherryOneShotModifier = TRUE; \\r
797                 goto HOOK; \\r
798         } else if (fCommand(nType & ~CONTROL) == CCommands::OneShotModifier ## mod ## Repeat) { \\r
799                 ReleaseKey(vk); \\r
800                 bCherryOneShotModifier = FALSE; \\r
801                 Kdu(nKey); \\r
802                 goto HOOK; \\r
803         }\r
804 \r
805         OneShotModifier(CONTROL, VK_CONTROL, Ctrl);\r
806         OneShotModifier(META, VK_MENU, Alt);\r
807         OneShotModifier(SHIFT, VK_SHIFT, Shift);\r
808         int i;\r
809         for (i = 0; i < MAX_KEY; ++i)\r
810                 if (nOneShotModifier[i] == nOrigKey)\r
811                         break;\r
812         if (i == MAX_KEY)\r
813                 bCherryOneShotModifier = FALSE;\r
814 \r
815         if (0 <= nFunctionID && nFunctionID < MAX_FUNCTION && m_Config.szFunctionDefinition[nFunctionID][0]) {\r
816                 CallFunction(nFunctionID);\r
817                 CCommands::Reset(GOTO_HOOK);\r
818                 goto HOOK;\r
819         }\r
820 #undef fCommand\r
821 #undef nFunctionID\r
822 \r
823         if (!fCommand) {\r
824                 if (nOrigKey == VK_CONTROL || nOrigKey == VK_MENU || nOrigKey == VK_SHIFT)\r
825                         goto DO_NOTHING;\r
826                 if (!(nType & SHIFT)) {\r
827                         if (CCommands::IsSetMark()) {\r
828                                 if (CCommands::MoveCaret(nKey, nType & CONTROL) != CONTINUE) {\r
829                                         CCommands::ClearNumericArgument();\r
830                                         goto HOOK;\r
831                                 }\r
832                                 CCommands::SetMark(FALSE);\r
833                         }\r
834                 }\r
835                 if (1 < CCommands::GetNumericArgument()) {\r
836                         Kdu(nKey, CCommands::GetNumericArgument());\r
837                         CCommands::ClearNumericArgument();\r
838                         goto HOOK;\r
839                 }\r
840                 goto DO_NOTHING;\r
841         }\r
842 \r
843         if (CCommands::IsTemporarilyDisableXKeymacs()  && fCommand != CCommands::KeyboardQuit) {\r
844                 CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
845                 goto DO_NOTHING;\r
846         }\r
847 \r
848         m_bRightControl = IsDown(VK_RCONTROL, FALSE);\r
849         m_bRightAlt = IsDown(VK_RMENU, FALSE);\r
850         m_bRightShift = IsDown(VK_RSHIFT, FALSE);\r
851 \r
852         if (bLocked)\r
853                 goto HOOK_RECURSIVE_KEY;\r
854         bLocked = TRUE;\r
855         fLastCommand = fCommand;\r
856 RECURSIVE_COMMAND:\r
857         switch (fLastCommand()) {\r
858         case GOTO_DO_NOTHING:\r
859                 bLocked = FALSE;\r
860                 goto DO_NOTHING;\r
861         case GOTO_HOOK:\r
862                 bLocked = FALSE;\r
863                 goto HOOK;\r
864         case GOTO_RECURSIVE:\r
865                 goto RECURSIVE;\r
866         case GOTO_HOOKX:\r
867                 bLocked = FALSE;\r
868                 goto HOOKX;\r
869                 case GOTO_HOOK0_9:\r
870                 bLocked = FALSE;\r
871                 goto HOOK0_9;\r
872         }\r
873 \r
874 DO_NOTHING:\r
875         SetModifierIcons();\r
876         if (m_bRecordingMacro && (!bRelease || m_bDown[wParam])) {\r
877                 KbdMacro m = { nCode, wParam, lParam, TRUE };\r
878                 m_Macro.push_back(m);\r
879                 m_bDown[wParam] |= !bRelease;\r
880         }\r
881         return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
882 \r
883 RECURSIVE:\r
884         Kdu(RECURSIVE_KEY, 1, FALSE);\r
885         goto HOOKX;\r
886 HOOK:\r
887         CCommands::SetLastCommand(fLastCommand);\r
888 HOOK0_9:\r
889 HOOKX:\r
890         SetModifierIcons();\r
891 HOOK_RECURSIVE_KEY:\r
892         return TRUE;\r
893 }\r
894 \r
895 void CXkeymacsDll::SetModifierIcons()\r
896 {\r
897 #define IconState(x) ((x) ? ON_ICON : OFF_ICON)\r
898         ICONMSG msg[6] = {\r
899                 {MX_ICON, IconState(CCommands::bM_x()), ""},\r
900                 {CX_ICON, IconState(CCommands::bC_x()), ""},\r
901                 {META_ICON, IconState(CCommands::bM_()), ""},\r
902                 {SHIFT_ICON, IconState(IsDown(VK_SHIFT, FALSE)), ""},\r
903                 {CTRL_ICON, IconState(IsControl()), ""},\r
904                 {ALT_ICON, IconState(IsDown(VK_MENU, FALSE)), ""}\r
905         };\r
906         _tcscpy_s(msg[0].szTip, m_M_xTip);\r
907         SendIconMessage(msg, 6);\r
908 }\r
909 \r
910 // Clear data of nAppID\r
911 void CXkeymacsDll::Clear(int nAppID)\r
912 {\r
913         if (0 <= nAppID && nAppID < MAX_APP) {\r
914                 ZeroMemory(m_Config.szSpecialApp[nAppID], sizeof(m_Config.szSpecialApp[nAppID]));\r
915                 ZeroMemory(m_Config.nCommandID[nAppID], sizeof(m_Config.nCommandID[nAppID]));\r
916                 m_Config.nKillRingMax[nAppID] = 0;\r
917                 m_Config.bUseDialogSetting[nAppID] = FALSE;\r
918                 m_Config.nSettingStyle[nAppID] = 0;\r
919         } else {\r
920                 ASSERT(0);\r
921         }\r
922 }\r
923 \r
924 BOOL CXkeymacsDll::IsValidKey(BYTE bVk)\r
925 {\r
926         if (bVk == 0xf0) {      // 0xf0: Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.\r
927                 return FALSE;\r
928         }\r
929 \r
930         switch (bVk) {\r
931         case VK_CONTROL:\r
932         case VK_MENU:\r
933         case VK_SHIFT:\r
934                 return FALSE;\r
935         default:\r
936                 break;\r
937         }\r
938 \r
939         return TRUE;\r
940 }\r
941 \r
942 BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)\r
943 {\r
944         BYTE bVk = 0;\r
945         do {\r
946                 if (IsValidKey(bVk) && IsDown(bVk, bPhysicalKey) &&\r
947                                 Commands[m_Config.nCommandID[m_nAppID][NONE][bVk]].fCommand == Modifier)\r
948                         return TRUE;\r
949         } while (++bVk);\r
950         return FALSE;\r
951 }\r
952 \r
953 void CXkeymacsDll::CancelMarkWithShift(BYTE nKey, bool bRelease)\r
954 {\r
955         static bool bShift;\r
956         if (nKey != VK_SHIFT)\r
957                 goto exit;\r
958         BYTE bVk = 0;\r
959         do {\r
960                 if (bVk == VK_SHIFT || VK_LSHIFT || VK_RSHIFT)\r
961                         continue;\r
962                 if (IsDown(bVk, FALSE))\r
963                         goto exit;\r
964         } while (++bVk);\r
965         if (!bRelease) {\r
966                 bShift = TRUE;\r
967                 return;\r
968         }\r
969         if (bShift)\r
970                 CCommands::SetMark(FALSE);\r
971 exit:\r
972         bShift = FALSE;\r
973         return;\r
974 }\r
975 \r
976 BOOL CXkeymacsDll::IsControl()\r
977 {\r
978         return CCommands::bC_() || IsDepressedModifier(CCommands::C_);\r
979 }\r
980 \r
981 BOOL CXkeymacsDll::IsMeta()\r
982 {\r
983         return CCommands::bM_() || IsDepressedModifier(CCommands::MetaAlt);\r
984 }\r
985 \r
986 void CXkeymacsDll::AddKillRing(BOOL bNewData)\r
987 {\r
988         if (m_Config.nKillRingMax[m_nAppID] == 0) {\r
989                 return;\r
990         }\r
991 \r
992         CClipboardSnap *pSnap = new CClipboardSnap;\r
993         if( !pSnap ) return;\r
994 \r
995         BOOL bCapture = pSnap->Capture();\r
996         bCapture = pSnap->Capture();    // for "office drawing shape format". Can CClipboardSnap care this problem?\r
997 \r
998         if( bCapture ) {\r
999                 if (bNewData) {\r
1000                         m_oKillRing.AddHead(pSnap);\r
1001                 } else {\r
1002                         if (m_oKillRing.IsEmpty()) {\r
1003                                 m_oKillRing.AddHead(pSnap);\r
1004                         } else {\r
1005                                 CClipboardSnap *pParent;\r
1006                                 for (pParent = m_oKillRing.GetHead(); pParent->GetNext(); pParent = pParent->GetNext()) {\r
1007                                         ;\r
1008                                 }\r
1009                                 pParent->SetNext(pSnap);\r
1010                         }\r
1011                 }\r
1012         } else {\r
1013                 delete pSnap;\r
1014                 pSnap = NULL;\r
1015         }\r
1016 \r
1017         m_nKillRing = 0;\r
1018 \r
1019         if (m_Config.nKillRingMax[m_nAppID] < m_oKillRing.GetCount()) {\r
1020                 CClipboardSnap *pSnap = m_oKillRing.GetTail();\r
1021                 delete pSnap;\r
1022                 pSnap = NULL;\r
1023                 m_oKillRing.RemoveTail();\r
1024         }\r
1025 }\r
1026 \r
1027 // Return TRUE if there is another data\r
1028 // Return FALSE if there is no more data\r
1029 CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)\r
1030 {\r
1031         if (m_Config.nKillRingMax[m_nAppID] == 0) {\r
1032                 return NULL;\r
1033         }\r
1034 \r
1035         if (m_oKillRing.IsEmpty()) {\r
1036                 return NULL;\r
1037         }\r
1038 \r
1039         m_nKillRing %= m_oKillRing.GetCount();\r
1040 \r
1041         if (!bForce) {\r
1042                 CClipboardSnap oCurrentSnap;\r
1043                 oCurrentSnap.Capture();\r
1044 \r
1045                 CClipboardSnap *pKillRing = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1046                 if (!pKillRing) {\r
1047                         return NULL;\r
1048                 }\r
1049                 for (; pKillRing->GetNext(); pKillRing = pKillRing->GetNext()) {\r
1050                         ;\r
1051                 }\r
1052                 if (*pKillRing != oCurrentSnap) {\r
1053                         return NULL;\r
1054                 }\r
1055         }\r
1056 \r
1057         if (!pSnap) {\r
1058                 pSnap = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1059         }\r
1060         pSnap->Restore();\r
1061 \r
1062         return pSnap->GetNext();\r
1063 }\r
1064 \r
1065 void CXkeymacsDll::SetOriginal(UINT nType, BYTE bVk)\r
1066 {\r
1067         m_nOriginal[nType & ~SHIFT][bVk]++;\r
1068 }\r
1069 \r
1070 int CXkeymacsDll::CheckOriginal(UINT nType, BYTE bVk)\r
1071 {\r
1072         nType &= ~SHIFT;\r
1073         if (m_nOriginal[nType][bVk])\r
1074                 return m_nOriginal[nType][bVk]--;\r
1075         return 0;\r
1076 }\r
1077 \r
1078 void CXkeymacsDll::IncreaseKillRingIndex(int nKillRing)\r
1079 {\r
1080         m_nKillRing += nKillRing;\r
1081 }\r
1082 \r
1083 BOOL CXkeymacsDll::GetEnableCUA()\r
1084 {\r
1085         return m_Config.bEnableCUA[m_nAppID];\r
1086 }\r
1087 \r
1088 void CXkeymacsDll::StartRecordMacro()\r
1089 {\r
1090         if (CCommands::bC_u())\r
1091                 CallMacro();\r
1092         m_bRecordingMacro = TRUE;\r
1093         m_Macro.erase(m_Macro.begin(), m_Macro.end());\r
1094         ZeroMemory(m_bDown, MAX_KEY);\r
1095 }\r
1096 \r
1097 void CXkeymacsDll::EndRecordMacro()\r
1098 {\r
1099         m_bRecordingMacro = FALSE;\r
1100         while (!m_Macro.empty()) { // remove not released push\r
1101                 const KbdMacro& m = m_Macro.back();\r
1102                 if (m.lParam & BEING_RELEASED)\r
1103                         break;\r
1104                 m_Macro.pop_back();\r
1105         }\r
1106 }\r
1107 \r
1108 void CXkeymacsDll::CallMacro()\r
1109 {\r
1110         if (m_bRecordingMacro)\r
1111                 m_bRecordingMacro = FALSE;\r
1112         UINT before = GetModifierState(FALSE);\r
1113         SetModifierState(0, before);\r
1114         for (std::list<KbdMacro>::const_iterator m = m_Macro.begin(); m != m_Macro.end(); ++m)\r
1115                 if (m->lParam & BEING_RELEASED)\r
1116                         ReleaseKey(static_cast<BYTE>(m->wParam));\r
1117                 else\r
1118                         DepressKey(static_cast<BYTE>(m->wParam), m->bOriginal);\r
1119         SetModifierState(before, 0);\r
1120 }\r
1121 \r
1122 BOOL CXkeymacsDll::Is106Keyboard()\r
1123 {\r
1124         return m_Config.b106Keyboard;\r
1125 }\r
1126 \r
1127 int CXkeymacsDll::IsPassThrough(BYTE nKey)\r
1128 {\r
1129         BYTE bVk = 0;\r
1130         do {\r
1131                 if (IsDown(bVk)\r
1132                  && (Commands[m_Config.nCommandID[m_nAppID][NONE][bVk]].fCommand == CCommands::PassThrough)) {\r
1133                         if (bVk == nKey) {\r
1134                                 return GOTO_HOOK;\r
1135                         }\r
1136 \r
1137                         return GOTO_DO_NOTHING;\r
1138                 }\r
1139         } while (++bVk);\r
1140         return CONTINUE;\r
1141 }\r
1142 \r
1143 // call an original command which is defined in dot.xkeymacs\r
1144 void CXkeymacsDll::CallFunction(int nFuncID)\r
1145 {\r
1146         if (nFuncID < 0 || nFuncID >= MAX_FUNCTION)\r
1147                 return;\r
1148         LPCTSTR def = m_Config.szFunctionDefinition[nFuncID];\r
1149         if (!def[0])\r
1150                 return;\r
1151         std::vector<KeyBind> keybinds;\r
1152         const LPCTSTR last = def + _tcslen(def) - 1;\r
1153         if (*def == _T('"') && *last == _T('"')) {\r
1154                 ++def; // skip '"'\r
1155                 while (def < last)\r
1156                         keybinds.push_back(ParseKey(def));\r
1157         } else if (*def == _T('[') && *last == _T(']')) {\r
1158                 while (++def < last) { // skip '[', ']', and ' '\r
1159                         if (*def == _T('?')) { // [?f ?o ?o]\r
1160                                 keybinds.push_back(ParseKey(++def));\r
1161                                 continue;\r
1162                         }\r
1163                         // [VK]\r
1164                         for (int i = 0; i < MAX_KEYNAME; ++i) {\r
1165                                 size_t keylen = _tcslen(KeyNames[i].name);\r
1166                                 if (!_tcsncmp(def, KeyNames[i].name, keylen)) {\r
1167                                         KeyBind keybind = {NONE, KeyNames[i].bVk};\r
1168                                         keybinds.push_back(keybind);\r
1169                                         def += keylen;\r
1170                                         break;\r
1171                                 }\r
1172                         }\r
1173                 }\r
1174         } else\r
1175                 return;\r
1176 \r
1177         BOOL bM_x = FALSE;\r
1178         TCHAR szPath[MAX_PATH] = {'\0'};\r
1179         unsigned int index = 0;\r
1180         BOOL bInitialized = FALSE;\r
1181         UINT before = GetModifierState(FALSE);\r
1182 \r
1183         for (std::vector<KeyBind>::const_iterator p = keybinds.begin(); p != keybinds.end(); ++p) {\r
1184                 const int nType = p->nType;\r
1185                 const BYTE bVk = p->bVk;\r
1186                 int (*fCommand)() = nType < MAX_COMMAND_TYPE ? Commands[m_Config.nCommandID[m_nAppID][nType][bVk]].fCommand : NULL;\r
1187                 if (fCommand) {\r
1188                         if (fCommand == CCommands::ExecuteExtendedCommand)\r
1189                                 bM_x = TRUE;\r
1190                         else if (!bInitialized) {\r
1191                                 SetModifierState(0, before);\r
1192                                 bInitialized = TRUE;\r
1193                         }\r
1194 //                      CUtils::Log("CallFunction: Command Name: %s", Commands[m_Config.nCommandID[m_nAppID][nType][bVk]].szCommandName);\r
1195                         while (fCommand() == GOTO_RECURSIVE)\r
1196                                 ;\r
1197                         continue;\r
1198                 }\r
1199                 if (bM_x) {\r
1200                         if (bVk == VK_RETURN)\r
1201                                 InvokeM_x(szPath);\r
1202                         else if (bVk != 0) {\r
1203                                 TCHAR nAscii = 0;\r
1204                                 do { // 1-127\r
1205                                         if (a2v(++nAscii) == bVk && ((nType & SHIFT) != 0) == IsShift(nAscii)) {\r
1206 //                                              CUtils::Log("M-x: %#X (%c), %#X (%c)", bVk, bVk, nAscii, nAscii);\r
1207                                                 szPath[index++] = nAscii;\r
1208                                                 break;\r
1209                                         }\r
1210                                 } while (nAscii != 127);\r
1211                         }\r
1212                         continue;\r
1213                 }\r
1214                 if (!bInitialized) {\r
1215                         SetModifierState(0, before);\r
1216                         bInitialized = TRUE;\r
1217                 }\r
1218                 if (nType & WIN_WIN)\r
1219                         DepressKey(VK_LWIN);\r
1220                 if (nType & WIN_CTRL)\r
1221                         DepressKey(VK_CONTROL);\r
1222                 if (nType & WIN_ALT)\r
1223                         DepressKey(VK_MENU);\r
1224                 if (nType & SHIFT)\r
1225                         DepressKey(VK_SHIFT);\r
1226                 Kdu(bVk);\r
1227                 const int nNextType = (p + 1) != keybinds.end() ? (p + 1)->nType : 0;\r
1228                 if (nType & SHIFT && !(nNextType & SHIFT))\r
1229                         ReleaseKey(VK_SHIFT);\r
1230                 if (nType & WIN_ALT && !(nNextType & WIN_ALT))\r
1231                         ReleaseKey(VK_MENU);\r
1232                 if (nType & WIN_CTRL && !(nNextType & WIN_CTRL))\r
1233                         ReleaseKey(VK_CONTROL);\r
1234                 if (nType & WIN_WIN && !(nNextType & WIN_WIN))\r
1235                         ReleaseKey(VK_LWIN);\r
1236         }\r
1237 \r
1238         if (bInitialized)\r
1239                 // If this lines is invoked on M-x, a window transition does not work well.\r
1240                 SetModifierState(before, 0);\r
1241         return;\r
1242 }\r
1243 \r
1244 KeyBind CXkeymacsDll::ParseKey(LPCTSTR& def)\r
1245 {\r
1246         KeyBind keybind = {NONE};\r
1247         if (*def == _T('\\')) { // set modifiers\r
1248                 ++def;\r
1249         LOOP:\r
1250                 for (int i = 0; i < MAX_MODIFIER; ++i) {\r
1251                         size_t len = _tcslen(Modifiers[i].name);\r
1252                         if (!_tcsncmp(def, Modifiers[i].name, len)) {\r
1253                                 keybind.nType |= Modifiers[i].id;\r
1254                                 def += len;\r
1255                                 goto LOOP;\r
1256                         }\r
1257                 }\r
1258         }\r
1259         if (IsShift(*def) && !(keybind.nType & (WIN_CTRL | WIN_ALT | WIN_WIN)))\r
1260                 keybind.nType |= SHIFT;\r
1261         int i = 0;\r
1262         for (; i < MAX_KEYNAME; ++i) {\r
1263                 size_t len = _tcslen(KeyNames[i].name);\r
1264                 if (!_tcsncmp(def, KeyNames[i].name, len)) {\r
1265                         def += len;\r
1266                         break;\r
1267                 }\r
1268         }\r
1269         keybind.bVk = i < MAX_KEYNAME ? KeyNames[i].bVk : a2v(*def++);\r
1270         return keybind;\r
1271 }\r
1272 \r
1273 BOOL CXkeymacsDll::IsShift(TCHAR nAscii)\r
1274 {\r
1275         switch (nAscii) {\r
1276         case _T(' '):\r
1277                 return FALSE;\r
1278         case _T('!'):\r
1279         case _T('"'):\r
1280         case _T('#'):\r
1281         case _T('$'):\r
1282         case _T('%'):\r
1283         case _T('&'):\r
1284                 return TRUE;\r
1285         case _T('\''):\r
1286                 return m_Config.b106Keyboard;\r
1287         case _T('('):\r
1288         case _T(')'):\r
1289         case _T('*'):\r
1290         case _T('+'):\r
1291                 return TRUE;\r
1292         case _T(','):\r
1293         case _T('-'):\r
1294         case _T('.'):\r
1295         case _T('/'):\r
1296         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
1297                 return FALSE;\r
1298         case _T(':'):\r
1299                 return !m_Config.b106Keyboard;\r
1300         case _T(';'):\r
1301                 return FALSE;\r
1302         case _T('<'):\r
1303                 return TRUE;\r
1304         case _T('='):\r
1305                 return m_Config.b106Keyboard;\r
1306         case _T('>'):\r
1307         case _T('?'):\r
1308                 return TRUE;\r
1309         case _T('@'):\r
1310                 return !m_Config.b106Keyboard;\r
1311         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
1312         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
1313         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
1314                 return TRUE;\r
1315         case _T('['):\r
1316         case _T('\\'):\r
1317         case _T(']'):\r
1318                 return FALSE;\r
1319         case _T('^'):\r
1320                 return !m_Config.b106Keyboard;\r
1321         case _T('_'):\r
1322                 return TRUE;\r
1323         case _T('`'):\r
1324                 return m_Config.b106Keyboard;\r
1325         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
1326         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
1327         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
1328                 return FALSE;\r
1329         case _T('{'):\r
1330         case _T('|'):\r
1331         case _T('}'):\r
1332         case _T('~'):\r
1333                 return TRUE;\r
1334         default:\r
1335                 return FALSE;\r
1336         }\r
1337 }\r
1338 \r
1339 BYTE CXkeymacsDll::a2v(TCHAR nAscii)\r
1340 {\r
1341         switch (nAscii) {\r
1342         case _T(' '):\r
1343                 return VK_SPACE;\r
1344         case _T('!'):\r
1345                 return '1';\r
1346         case _T('"'):\r
1347                 return m_Config.b106Keyboard ? '2' : (BYTE) 0xde;       // VK_OEM_7\r
1348         case _T('#'):\r
1349                 return '3';\r
1350         case _T('$'):\r
1351                 return '4';\r
1352         case _T('%'):\r
1353                 return '5';\r
1354         case _T('&'):\r
1355                 return m_Config.b106Keyboard ? '6' : '7';\r
1356         case _T('\''):\r
1357                 return m_Config.b106Keyboard ? '7' : (BYTE) 0xde;       // VK_OEM_7\r
1358         case _T('('):\r
1359                 return m_Config.b106Keyboard ? '8' : '9';\r
1360         case _T(')'):\r
1361                 return m_Config.b106Keyboard ? '9' : '0';\r
1362         case _T('*'):\r
1363                 return m_Config.b106Keyboard ? (BYTE) 0xba : '8';       // VK_OEM_1\r
1364         case _T('+'):\r
1365                 return 0xbb;    // VK_OEM_PLUS\r
1366         case _T(','):\r
1367                 return 0xbc;    // VK_OEM_COMMA\r
1368         case _T('-'):\r
1369                 return 0xbd;    // VK_OEM_MINUS\r
1370         case _T('.'):\r
1371                 return 0xbe;    // VK_OEM_PERIOD\r
1372         case _T('/'):\r
1373                 return 0xbf;    // VK_OEM_2\r
1374         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
1375                 return nAscii;\r
1376         case _T(':'):\r
1377                 return 0xba;    // VK_OEM_1\r
1378         case _T(';'):\r
1379                 return m_Config.b106Keyboard ? (BYTE) 0xbb : (BYTE) 0xba;       // VK_OEM_PLUS  VK_OEM_1\r
1380         case _T('<'):\r
1381                 return 0xbc;    // VK_OEM_COMMA\r
1382         case _T('='):\r
1383                 return m_Config.b106Keyboard ? (BYTE) 0xbd : (BYTE) 0xbb;       // VK_OEM_MINUS VK_OEM_PLUS\r
1384         case _T('>'):\r
1385                 return 0xbe;    // VK_OEM_PERIOD\r
1386         case _T('?'):\r
1387                 return 0xbf;    // VK_OEM_2\r
1388         case _T('@'):\r
1389                 return m_Config.b106Keyboard ? (BYTE) 0xc0 : '2';\r
1390         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
1391         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
1392         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
1393                 return nAscii;\r
1394         case _T('['):\r
1395                 return 0xdb;    // VK_OEM_4\r
1396         case _T('\\'):\r
1397                 return 0xdc;    // VK_OEM_5\r
1398         case _T(']'):\r
1399                 return 0xdd;    // VK_OEM_6\r
1400         case _T('^'):\r
1401                 return m_Config.b106Keyboard ? (BYTE) 0xde : '6';       // VK_OEM_7\r
1402         case _T('_'):\r
1403                 return m_Config.b106Keyboard ? (BYTE) 0xe2 : (BYTE) 0xbd;       // VK_OEM_102   VK_OEM_MINUS\r
1404         case _T('`'):\r
1405                 return 0xc0;    // VK_OEM_3\r
1406         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
1407         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
1408         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
1409                 return (BYTE) (nAscii - (_T('a') - _T('A')));\r
1410         case _T('{'):\r
1411                 return 0xdb;    // VK_OEM_4\r
1412         case _T('|'):\r
1413                 return 0xdc;    // VK_OEM_5\r
1414         case _T('}'):\r
1415                 return 0xdd;    // VK_OEM_6\r
1416         case _T('~'):\r
1417                 return m_Config.b106Keyboard ? (BYTE) 0xde : (BYTE) 0xc0;       // VK_OEM_7     VK_OEM_3\r
1418         default:\r
1419                 return 0;\r
1420         }\r
1421 }\r
1422 \r
1423 BOOL CXkeymacsDll::IsMatchWindowText(CString szWindowText)\r
1424 {\r
1425         BOOL bIsMatchWindowText = TRUE;\r
1426 \r
1427         TCHAR szCurrentWindowText[WINDOW_TEXT_LENGTH] = {'\0'};\r
1428         GetWindowText(GetForegroundWindow(), szCurrentWindowText, sizeof(szCurrentWindowText));\r
1429 \r
1430         switch (CUtils::GetWindowTextType(szWindowText)) {\r
1431         case IDS_WINDOW_TEXT_MATCH:                                                             // *foo*\r
1432                 szWindowText.Delete(0);                                                         // Delete first '*'\r
1433                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
1434                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText);\r
1435                 break;\r
1436         case IDS_WINDOW_TEXT_MATCH_FORWARD:                                             // foo*\r
1437                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
1438                 bIsMatchWindowText = 0 == CString(szCurrentWindowText).Find(szWindowText);\r
1439                 break;\r
1440         case IDS_WINDOW_TEXT_MATCH_BACKWARD:                                    // *foo\r
1441                 szWindowText.Delete(0);                                                         // Delete first '*'\r
1442                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText, CString(szCurrentWindowText).GetLength() - szWindowText.GetLength());\r
1443                 break;\r
1444         case IDS_WINDOW_TEXT_MATCH_FULL:                                                // foo\r
1445                 bIsMatchWindowText = szWindowText == CString(szCurrentWindowText);\r
1446                 break;\r
1447         case IDS_WINDOW_TEXT_IGNORE:                                                    // *\r
1448                 bIsMatchWindowText = TRUE;\r
1449                 break;\r
1450         default:\r
1451                 ASSERT(0);\r
1452                 break;\r
1453         }\r
1454 \r
1455 //      CUtils::Log(_T("IsMatchWindowText: %d, _%s_, _%s_"), bIsMatchWindowText, szCurrentWindowText, szWindowText);\r
1456         return bIsMatchWindowText;\r
1457 }\r
1458 \r
1459 void CXkeymacsDll::SetAccelerate(int nAccelerate)\r
1460 {\r
1461         m_nAccelerate = nAccelerate;\r
1462 }\r
1463 \r
1464 int CXkeymacsDll::GetAccelerate()\r
1465 {\r
1466         return m_nAccelerate;\r
1467 }\r
1468 \r
1469 void CXkeymacsDll::SetKeyboardSpeed(int nKeyboardSpeed)\r
1470 {\r
1471         m_nKeyboardSpeed = nKeyboardSpeed;\r
1472 }\r
1473 \r
1474 unsigned int CXkeymacsDll::GetMaxKeyInterval()\r
1475 {\r
1476         // m_nKeyboardSpeed == 0:       slowest repeat rate; approximately  2 characters per second\r
1477         // m_nKeyboardSpeed == 31:      fastest repeat rate; approximately 30 characters per second\r
1478         // 47 ms is max on my machine w/ KeyboardSpeed 31.\r
1479         // 1000 /  2 + 50 = 550\r
1480         // 1000 / 30 + 50 = 83\r
1481         return (unsigned int) (1000.0 / (2.0 + m_nKeyboardSpeed % 32 * 28.0 / 31.0) + 50.0);\r
1482 }\r
1483 \r
1484 void CXkeymacsDll::SetCursorData(HCURSOR hEnable, HCURSOR hDisableTMP, HCURSOR hDisableWOCQ, HICON hDisable, BOOL bEnable)\r
1485 {\r
1486         m_hCursor[STATUS_ENABLE] = hEnable;\r
1487         m_hCursor[STATUS_DISABLE_TMP] = hDisableTMP;\r
1488         m_hCursor[STATUS_DISABLE_WOCQ] = hDisableWOCQ;\r
1489         m_hCursor[STATUS_DISABLE] = hDisable;\r
1490         m_bCursor = bEnable;\r
1491 }\r
1492 \r
1493 void CXkeymacsDll::DoSetCursor()\r
1494 {\r
1495         if (m_bCursor && m_hCurrentCursor) {\r
1496                 ::SetCursor(m_hCurrentCursor);\r
1497         }\r
1498 }\r
1499 \r
1500 BOOL CXkeymacsDll::Get326Compatible()\r
1501 {\r
1502         return m_Config.b326Compatible[m_nAppID];\r
1503 }\r
1504 \r
1505 void CXkeymacsDll::InvokeM_x(const TCHAR *const szPath)\r
1506 {\r
1507 //      CUtils::Log("M-x: szPath=_%s_", szPath);\r
1508         int (*fCommand)() = NULL;\r
1509 \r
1510         for (int i = 0; i < MAX_COMMAND; ++i) {\r
1511                 if (_tcsicmp(szPath, Commands[i].szCommandName) == 0) {\r
1512                         fCommand = Commands[i].fCommand;\r
1513                         break;\r
1514                 }\r
1515         }\r
1516 \r
1517         if (fCommand) {\r
1518 //              CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);\r
1519                 fCommand();\r
1520         } else {\r
1521 //              CUtils::Log("M-x: Path: _%s_", szPath);\r
1522                 ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);\r
1523         }\r
1524 }\r
1525 \r
1526 void CXkeymacsDll::SetM_xTip(const TCHAR *const szPath)\r
1527 {\r
1528         _tcscpy_s(m_M_xTip, "M-x LED");\r
1529         if (szPath && _tcslen(szPath) < 128 - 5)\r
1530                 _stprintf_s(m_M_xTip, "M-x %s", szPath);\r
1531 }\r
1532 \r
1533 BOOL CXkeymacsDll::SendIconMessage(ICONMSG *pMsg, DWORD num)\r
1534 {\r
1535         DWORD ack, read;\r
1536         return CallNamedPipe(ICON_PIPE, pMsg, sizeof(ICONMSG) * num, &ack, sizeof(DWORD), &read, NMPWAIT_NOWAIT);\r
1537 }\r