OSDN Git Service

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