OSDN Git Service

2317a363ad08c13c17cef141dd0df1137bca64ec
[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 \r
12 #ifdef _DEBUG\r
13 #define new DEBUG_NEW\r
14 #undef THIS_FILE\r
15 static char THIS_FILE[] = __FILE__;\r
16 #endif\r
17 \r
18 struct KbdMacro\r
19 {\r
20         int nCode;\r
21         WPARAM wParam;\r
22         LPARAM lParam;\r
23         BOOL bOriginal;\r
24 };\r
25 \r
26 struct Modifier {\r
27         LPCTSTR name;\r
28         int id;\r
29 };\r
30 \r
31 static const Modifier Modifiers[] = {\r
32 //      { _T("A-"), ALT },\r
33         { _T("C-"), CONTROL},\r
34 //      { _T("H-"), HYPER },\r
35         { _T("M-"), META },\r
36         { _T("S-"), SHIFT },\r
37 //      { _T("s-"), SUPER },\r
38         { _T("Ctrl+"), WIN_CTRL },\r
39         { _T("Alt+"), WIN_ALT },\r
40         { _T("Win+"), WIN_WIN },\r
41 };\r
42 \r
43 static const KeyName ControlCharacters[] = {\r
44 //      { VK_LBUTTON,           _T("mouse-1") },                                // does not work well\r
45 //      { VK_RBUTTON,           _T("mouse-3") },                                // does not work well\r
46         { VK_CANCEL,            _T("break") },\r
47 //      { VK_MBUTTON,           _T("mouse-2") },                                // does not work well\r
48         { VK_BACK,                      _T("backspace") },\r
49         { VK_TAB,                       _T("tab") },\r
50         { VK_RETURN,            _T("return") },\r
51         { VK_CAPITAL,           _T("capslock") },\r
52         { VK_KANA,                      _T("kana") },\r
53         { VK_KANJI,                     _T("kanji") },\r
54         { VK_ESCAPE,            _T("escape") },\r
55         { VK_CONVERT,           _T("convert") },\r
56         { VK_NONCONVERT,        _T("nonconvert") },\r
57 //      { VK_SPACE,                     _T("SPC") },                                    // [? ]\r
58         { VK_PRIOR,                     _T("prior") },\r
59         { VK_NEXT,                      _T("next") },\r
60         { VK_END,                       _T("end") },\r
61         { VK_HOME,                      _T("home") },\r
62         { VK_LEFT,                      _T("left") },\r
63         { VK_UP,                        _T("up") },\r
64         { VK_RIGHT,                     _T("right") },\r
65         { VK_DOWN,                      _T("down") },\r
66         { VK_SELECT,            _T("select") },\r
67         { VK_PRINT,                     _T("print") },\r
68         { VK_EXECUTE,           _T("execute") },\r
69         { VK_SNAPSHOT,          _T("printscreen") },                    // work as print\r
70         { VK_INSERT,            _T("insert") },\r
71         { VK_DELETE,            _T("delete") },\r
72         { VK_LWIN,                      _T("lwindow") },\r
73         { VK_RWIN,                      _T("rwindow") },\r
74         { VK_APPS,                      _T("apps") },\r
75         { VK_SLEEP,                     _T("sleep") },\r
76         { VK_NUMPAD0,           _T("kp-0") },\r
77         { VK_NUMPAD1,           _T("kp-1") },\r
78         { VK_NUMPAD2,           _T("kp-2") },\r
79         { VK_NUMPAD3,           _T("kp-3") },\r
80         { VK_NUMPAD4,           _T("kp-4") },\r
81         { VK_NUMPAD5,           _T("kp-5") },\r
82         { VK_NUMPAD6,           _T("kp-6") },\r
83         { VK_NUMPAD7,           _T("kp-7") },\r
84         { VK_NUMPAD8,           _T("kp-8") },\r
85         { VK_NUMPAD9,           _T("kp-9") },\r
86         { VK_MULTIPLY,          _T("kp-multiply") },\r
87         { VK_ADD,                       _T("kp-add") },\r
88         { VK_SUBTRACT,          _T("kp-subtract") },\r
89         { VK_DECIMAL,           _T("kp-decimal") },\r
90         { VK_DIVIDE,            _T("kp-divide") },\r
91 //      { VK_F1,                        _T("f1") },                                             // FIXME\r
92 //      { VK_F2,                        _T("f2") },                                             // Move at the end of definition of funcgtion keys to keep away confliction f1/f2 and f1?/f2? by _tcsncmp() i.e. strncmp()\r
93         { VK_F3,                        _T("f3") },\r
94         { VK_F4,                        _T("f4") },\r
95         { VK_F5,                        _T("f5") },\r
96         { VK_F6,                        _T("f6") },\r
97         { VK_F7,                        _T("f7") },\r
98         { VK_F8,                        _T("f8") },\r
99         { VK_F9,                        _T("f9") },\r
100         { VK_F10,                       _T("f10") },\r
101         { VK_F11,                       _T("f11") },\r
102         { VK_F12,                       _T("f12") },\r
103         { VK_F13,                       _T("f13") },\r
104         { VK_F14,                       _T("f14") },\r
105         { VK_F15,                       _T("f15") },\r
106         { VK_F16,                       _T("f16") },\r
107         { VK_F17,                       _T("f17") },\r
108         { VK_F18,                       _T("f18") },\r
109         { VK_F19,                       _T("f19") },\r
110         { VK_F20,                       _T("f20") },\r
111         { VK_F21,                       _T("f21") },\r
112         { VK_F22,                       _T("f22") },\r
113         { VK_F23,                       _T("f23") },\r
114         { VK_F24,                       _T("f24") },\r
115         { VK_F1,                        _T("f1") },\r
116         { VK_F2,                        _T("f2") },\r
117         { VK_NUMLOCK,           _T("kp-numlock") },\r
118         { VK_SCROLL,            _T("scroll") },\r
119         { 0xa6,                         _T("browser-back") },                   // VK_BROWSER_BACK\r
120         { 0xa7,                         _T("browser-forward") },                // VK_BROWSER_FORWARD\r
121         { 0xa8,                         _T("browser-refresh") },                // VK_BROWSER_REFRESH\r
122         { 0xa9,                         _T("browser-stop") },                   // VK_BROWSER_STOP\r
123         { 0xaa,                         _T("browser-search") },                 // VK_BROWSER_SEARCH\r
124         { 0xab,                         _T("browser-favorites") },              // VK_BROWSER_FAVORITES\r
125         { 0xac,                         _T("browser-home") },                   // VK_BROWSER_HOME\r
126         { 0xad,                         _T("volume-mute") },                    // VK_VOLUME_MUTE\r
127         { 0xae,                         _T("volume-down") },                    // VK_VOLUME_DOWN\r
128         { 0xaf,                         _T("volume-up") },                              // VK_VOLUME_UP\r
129         { 0xb0,                         _T("media-next-track") },               // VK_MEDIA_NEXT_TRACK\r
130         { 0xb1,                         _T("media-prev-track") },               // VK_MEDIA_PREV_TRACK\r
131         { 0xb2,                         _T("media-stop") },                             // VK_MEDIA_STOP\r
132         { 0xb3,                         _T("media-play-pause") },               // VK_MEDIA_PLAY_PAUSE\r
133         { 0xb4,                         _T("launch-mail") },                    // VK_LAUNCH_MAIL\r
134         { 0xb5,                         _T("launch-media-select") },    // VK_LAUNCH_MEDIA_SELECT\r
135         { 0xb6,                         _T("launch-1") },                               // VK_LAUNCH_APP1\r
136         { 0xb7,                         _T("launch-2") },                               // VK_LAUNCH_APP2\r
137 };\r
138 \r
139 static AFX_EXTENSION_MODULE XkeymacsdllDLL = { NULL, NULL };\r
140 \r
141 static __declspec(thread) HINSTANCE g_hDllInst = NULL;\r
142 static __declspec(thread) HHOOK g_hHookKeyboard = NULL;\r
143 \r
144 extern "C" int APIENTRY\r
145 DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)\r
146 {\r
147         g_hDllInst = hInstance;\r
148         \r
149         // Remove this if you use lpReserved\r
150         UNREFERENCED_PARAMETER(lpReserved);\r
151 \r
152         switch (dwReason) {\r
153         case DLL_PROCESS_ATTACH:\r
154                 TRACE0("XKEYMACSDLL.DLL Initializing!\n");\r
155                 \r
156                 // Extension DLL one-time initialization\r
157                 if (!AfxInitExtensionModule(XkeymacsdllDLL, hInstance)) {\r
158                         return 0;\r
159                 }\r
160 \r
161                 // Insert this DLL into the resource chain\r
162                 // NOTE: If this Extension DLL is being implicitly linked to by\r
163                 //  an MFC Regular DLL (such as an ActiveX Control)\r
164                 //  instead of an MFC application, then you will want to\r
165                 //  remove this line from DllMain and put it in a separate\r
166                 //  function exported from this Extension DLL.  The Regular DLL\r
167                 //  that uses this Extension DLL should then explicitly call that\r
168                 //  function to initialize this Extension DLL.  Otherwise,\r
169                 //  the CDynLinkLibrary object will not be attached to the\r
170                 //  Regular DLL's resource chain, and serious problems will\r
171                 //  result.\r
172 \r
173                 try {\r
174                         new CDynLinkLibrary(XkeymacsdllDLL);\r
175                 }\r
176                 catch (CMemoryException* e) {\r
177                         e->Delete();\r
178 //                      CUtils::Log("DllMain: 'new' threw an exception");\r
179                 }\r
180         case DLL_THREAD_ATTACH:\r
181                 CXkeymacsDll::SetKeyboardHook();\r
182                 break;\r
183         case DLL_PROCESS_DETACH:\r
184                 TRACE0("XKEYMACSDLL.DLL Terminating!\n");\r
185                 // Terminate the library before destructors are called\r
186                 AfxTermExtensionModule(XkeymacsdllDLL);\r
187         case DLL_THREAD_DETACH:\r
188                 CXkeymacsDll::ReleaseKeyboardHook();\r
189         }\r
190         return 1;   // ok\r
191 }\r
192 \r
193 //////////////////////////////////////////////////////////////////////\r
194 // CXkeymacsDll Class\r
195 //////////////////////////////////////////////////////////////////////\r
196 \r
197 #include "xkeymacsDll.h"\r
198 #pragma data_seg(".xkmcs")\r
199         BOOL    CXkeymacsDll::m_bEnableKeyboardHook = FALSE;\r
200         HHOOK   CXkeymacsDll::m_hHookCallWnd = NULL;\r
201         HHOOK   CXkeymacsDll::m_hHookCallWndRet = NULL;\r
202         HHOOK   CXkeymacsDll::m_hHookGetMessage = NULL;\r
203         HHOOK   CXkeymacsDll::m_hHookShell = NULL;\r
204         int             CXkeymacsDll::m_nCommandID[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
205         BOOL    CXkeymacsDll::m_bAtIbeamCursorOnly[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
206         int             CXkeymacsDll::m_nFunctionID[MAX_APP][MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
207         TCHAR   CXkeymacsDll::m_szSpecialApp[MAX_APP][CLASS_NAME_LENGTH] = {'\0'};\r
208         TCHAR   CXkeymacsDll::m_szWindowText[MAX_APP][WINDOW_TEXT_LENGTH] = {'\0'};\r
209         BOOL    CXkeymacsDll::m_bRightControl   = FALSE;\r
210         BOOL    CXkeymacsDll::m_bRightAlt               = FALSE;\r
211         BOOL    CXkeymacsDll::m_bRightShift             = FALSE;\r
212         BOOL    CXkeymacsDll::m_bHook                   = TRUE;\r
213         BOOL    CXkeymacsDll::m_bDefiningMacro  = FALSE;\r
214         DWORD   CXkeymacsDll::m_dwOldMessage[MAX_ICON_TYPE] = {'\0'};\r
215         NOTIFYICONDATA CXkeymacsDll::m_stNtfyIcon[MAX_ICON_TYPE] = {'\0'};\r
216         NOTIFYICONDATA CXkeymacsDll::m_stOldNtfyIcon[MAX_ICON_TYPE] = {'\0'};\r
217         HICON   CXkeymacsDll::m_hIcon[MAX_ICON_TYPE][MAX_STATUS] = {'\0'};\r
218         BOOL    CXkeymacsDll::m_bIcon[MAX_ICON_TYPE] = {'\0'};\r
219         int             CXkeymacsDll::m_nKillRingMax[MAX_APP] = {'\0'};\r
220         BOOL    CXkeymacsDll::m_bUseDialogSetting[MAX_APP] = {'\0'};\r
221         CList<CClipboardSnap *, CClipboardSnap *> CXkeymacsDll::m_oKillRing;\r
222         CObList CXkeymacsDll::m_Macro;\r
223         int             CXkeymacsDll::m_nKillRing = 0;\r
224         int             CXkeymacsDll::m_nOriginal[MAX_COMMAND_TYPE][MAX_KEY] = {'\0'};\r
225         int             CXkeymacsDll::m_nApplicationID = 0;\r
226         int             CXkeymacsDll::m_nSettingStyle[MAX_APP] = {'\0'};\r
227         BOOL    CXkeymacsDll::m_bIgnoreUndefinedMetaCtrl[MAX_APP] = {'\0'};\r
228         BOOL    CXkeymacsDll::m_bIgnoreUndefinedC_x[MAX_APP] = {'\0'};\r
229 //      int             CXkeymacsDll::m_nPassThrough = 0;\r
230         TCHAR   CXkeymacsDll::m_szApplicationName[MAX_PATH] = {'\0'};\r
231         TCHAR   CXkeymacsDll::m_szOldApplicationName[MAX_PATH] = {'\0'};\r
232         BOOL    CXkeymacsDll::m_bEnableCUA[MAX_APP] = {'\0'};\r
233         TCHAR   CXkeymacsDll::m_szFunctionDefinition[MAX_FUNCTION][MAX_DEFINITION] = {'\0'};\r
234         int             CXkeymacsDll::m_nAccelerate = 0;\r
235         int             CXkeymacsDll::m_nKeyboardSpeed = 31;\r
236         HCURSOR CXkeymacsDll::m_hCursor[MAX_STATUS] = {'\0'};\r
237         HCURSOR CXkeymacsDll::m_hCurrentCursor = NULL;\r
238         BOOL    CXkeymacsDll::m_bCursor = FALSE;\r
239         BOOL    CXkeymacsDll::m_b326Compatible[MAX_APP] = {'\0'};\r
240         BOOL    CXkeymacsDll::m_b106Keyboard = FALSE;\r
241 #pragma data_seg()\r
242 \r
243 //////////////////////////////////////////////////////////////////////\r
244 // Construction/Destruction\r
245 //////////////////////////////////////////////////////////////////////\r
246 \r
247 CXkeymacsDll::CXkeymacsDll()\r
248 {\r
249         CUtils::InitCUtils();\r
250 }\r
251 \r
252 CXkeymacsDll::~CXkeymacsDll()\r
253 {\r
254 \r
255 }\r
256 \r
257 int CXkeymacsDll::ModifyShell_NotifyIcon(ICON_TYPE icon, BOOL bNewStatus, BOOL bForce)\r
258 {\r
259         if (m_stNtfyIcon[icon].hIcon == (bNewStatus ? m_hIcon[icon][ON_ICON] : m_hIcon[icon][OFF_ICON])) {\r
260                 if (!bForce) {\r
261                         return TRUE;\r
262                 }\r
263         } else {\r
264                 m_stNtfyIcon[icon].hIcon = (bNewStatus ? m_hIcon[icon][ON_ICON] : m_hIcon[icon][OFF_ICON]);\r
265         }\r
266         return DoShell_NotifyIcon(icon, NIM_MODIFY);\r
267 }\r
268 \r
269 void CXkeymacsDll::SetNotifyIconData(ICON_TYPE icon, NOTIFYICONDATA stNtfyIcon, HICON hEnable, HICON hDisableTMP, HICON hDisableWOCQ, HICON hDisable, BOOL bEnable)\r
270 {\r
271         m_hIcon[icon][STATUS_ENABLE] = hEnable;\r
272         m_hIcon[icon][STATUS_DISABLE_TMP] = hDisableTMP;\r
273         m_hIcon[icon][STATUS_DISABLE_WOCQ] = hDisableWOCQ;\r
274         m_hIcon[icon][STATUS_DISABLE] = hDisable;\r
275         m_bIcon[icon] = bEnable;\r
276         m_stNtfyIcon[icon] = stNtfyIcon;\r
277         AddShell_NotifyIcon(icon);\r
278 }\r
279 \r
280 void CXkeymacsDll::SetNotifyIconData(ICON_TYPE icon, NOTIFYICONDATA stNtfyIcon, HICON hOn, HICON hOff, BOOL bEnable)\r
281 {\r
282         m_hIcon[icon][ON_ICON] = hOn;\r
283         m_hIcon[icon][OFF_ICON] = hOff;\r
284         m_bIcon[icon] = bEnable;\r
285         m_stNtfyIcon[icon] = stNtfyIcon;\r
286         AddShell_NotifyIcon(icon);\r
287 }\r
288 \r
289 void CXkeymacsDll::EnableShell_NotifyIcon(ICON_TYPE icon, BOOL bEnable)\r
290 {\r
291         DeleteShell_NotifyIcon(icon);\r
292         m_bIcon[icon] = bEnable;\r
293         AddShell_NotifyIcon(icon);\r
294 }\r
295 \r
296 \r
297 BOOL CXkeymacsDll::DoShell_NotifyIcon(ICON_TYPE icon, DWORD dwMessage)\r
298 {\r
299         if (m_bIcon[icon]\r
300          &&     (m_dwOldMessage[icon] != dwMessage\r
301           || memcmp(&m_stOldNtfyIcon[icon], &m_stNtfyIcon[icon], sizeof(m_stNtfyIcon[icon])))) {\r
302                 m_dwOldMessage[icon] = dwMessage;\r
303                 m_stOldNtfyIcon[icon] = m_stNtfyIcon[icon];\r
304 \r
305                 BOOL rc = FALSE;\r
306                 for (int retry_count = 0; retry_count < 20; ++retry_count) { // retry for timeout\r
307                         rc = Shell_NotifyIcon(dwMessage, &m_stNtfyIcon[icon]);\r
308                         if (dwMessage != NIM_ADD || rc || (GetLastError() != ERROR_TIMEOUT && 5 < retry_count)) {\r
309                                 break;\r
310                         }\r
311                         Sleep(1000); // 1sec\r
312                         if ((rc = Shell_NotifyIcon(NIM_MODIFY, &m_stNtfyIcon[icon])) != FALSE) {\r
313                                 break; // ERROR_TIMEOUT was returned but the icon was also added.\r
314                         }\r
315                 }\r
316                 return rc;\r
317         } else {\r
318                 return TRUE;\r
319         }\r
320 }\r
321 \r
322 void CXkeymacsDll::AddShell_NotifyIcon(ICON_TYPE icon)\r
323 {\r
324         DoShell_NotifyIcon(icon, NIM_ADD);\r
325 }\r
326 \r
327 void CXkeymacsDll::DeleteShell_NotifyIcon(ICON_TYPE icon)\r
328 {\r
329         DoShell_NotifyIcon(icon, NIM_DELETE);\r
330 }\r
331 \r
332 // set hooks\r
333 void CXkeymacsDll::SetHooks()\r
334 {\r
335         m_bEnableKeyboardHook = TRUE;\r
336         m_hHookCallWnd = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProc, g_hDllInst, 0);\r
337         m_hHookCallWndRet = SetWindowsHookEx(WH_CALLWNDPROCRET, (HOOKPROC)CallWndRetProc, g_hDllInst, 0);\r
338         m_hHookGetMessage = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)GetMsgProc, g_hDllInst, 0);\r
339         m_hHookShell = SetWindowsHookEx(WH_SHELL, (HOOKPROC)ShellProc, g_hDllInst, 0);\r
340 }\r
341 \r
342 void CXkeymacsDll::SetKeyboardHook()\r
343 {\r
344         if (!g_hHookKeyboard)\r
345                 SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, g_hDllInst, GetCurrentThreadId());\r
346 }\r
347 \r
348 // release hooks\r
349 void CXkeymacsDll::ReleaseHooks()\r
350 {\r
351         m_bEnableKeyboardHook = FALSE;\r
352         if (m_hHookCallWnd)\r
353                 UnhookWindowsHookEx(m_hHookCallWnd);\r
354         m_hHookCallWnd = NULL;\r
355         if (m_hHookCallWndRet)\r
356                 UnhookWindowsHookEx(m_hHookCallWndRet);\r
357         m_hHookCallWndRet = NULL;\r
358         if (m_hHookGetMessage)\r
359                 UnhookWindowsHookEx(m_hHookGetMessage);\r
360         m_hHookGetMessage = NULL;\r
361         if (m_hHookShell)\r
362                 UnhookWindowsHookEx(m_hHookShell);\r
363         m_hHookShell = NULL;\r
364 }\r
365 \r
366 void CXkeymacsDll::ReleaseKeyboardHook()\r
367 {\r
368         if (g_hHookKeyboard)\r
369                 UnhookWindowsHookEx(g_hHookKeyboard);\r
370         g_hHookKeyboard = NULL;\r
371 }\r
372 \r
373 void CXkeymacsDll::SetKeyboardHookFlag(BOOL bFlag)\r
374 {\r
375         m_bHook = bFlag;\r
376 \r
377         if (m_bHook) {\r
378                 if (CCommands::IsTemporarilyDisableXKeymacs()) {\r
379                         m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_DISABLE_TMP];\r
380                         m_hCurrentCursor = m_hCursor[STATUS_DISABLE_TMP];\r
381                 } else {\r
382                         m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_ENABLE];\r
383                         m_hCurrentCursor = m_hCursor[STATUS_ENABLE];\r
384                 }\r
385         } else {\r
386                 m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_DISABLE_WOCQ];\r
387                 m_hCurrentCursor = m_hCursor[STATUS_DISABLE_WOCQ];\r
388         }\r
389         if (m_nSettingStyle[m_nApplicationID] == SETTING_DISABLE\r
390          || (!_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Default"))\r
391           && CUtils::IsDefaultIgnoreApplication())) {\r
392                 m_stNtfyIcon[MAIN_ICON].hIcon = m_hIcon[MAIN_ICON][STATUS_DISABLE];\r
393                 m_hCurrentCursor = m_hCursor[STATUS_DISABLE];\r
394         }\r
395         DoShell_NotifyIcon(MAIN_ICON, NIM_MODIFY);\r
396         DoSetCursor();\r
397 }\r
398 \r
399 // if be keyboard hook, return TRUE\r
400 BOOL CXkeymacsDll::IsKeyboardHook()\r
401 {\r
402         if (m_bHook) {\r
403                 return TRUE;\r
404         }\r
405 \r
406         return FALSE;\r
407 }\r
408 \r
409 void CXkeymacsDll::LogCallWndProcMessage(WPARAM wParam, LPARAM lParam)\r
410 {\r
411         CWPSTRUCT &cwps = *(CWPSTRUCT *)lParam;\r
412 \r
413         switch (cwps.message) {\r
414         case WM_PAINT:                                  // 0x000F\r
415         case WM_MDIGETACTIVE:                   // 0x0229\r
416         case 0x0403:\r
417         case 0x0407:\r
418         case 0x0418:\r
419         case 0x043F:\r
420         case 0x0440:\r
421                 break;\r
422         case WM_CREATE:                                 // 0x0001\r
423 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_CREATE"));\r
424                 break;\r
425         case WM_DESTROY:                                // 0x0002\r
426 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_DESTROY"));\r
427                 break;\r
428         case WM_MOVE:                                   // 0x0003\r
429 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_MOVE");)\r
430                 break;\r
431         case WM_SIZE:                                   // 0x0005\r
432 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_SIZE"));\r
433                 break;\r
434         case WM_GETTEXT:                                // 0x000D\r
435 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_GETTEXT"));\r
436                 break;\r
437         case WM_ERASEBKGND:                             // 0x0014\r
438 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_ERASEBKGND"));\r
439                 break;\r
440         case WM_WINDOWPOSCHANGING:              // 0x0046\r
441 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_WINDOWPOSCHANGING"));\r
442                 break;\r
443         case WM_WINDOWPOSCHANGED:               // 0x0047\r
444 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_WINDOWPOSCHANGED"));\r
445                 break;\r
446         case WM_COPYDATA:                               // 0x004A\r
447 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_COPYDATA"));\r
448                 break;\r
449         case WM_NCCREATE:                               // 0x0081\r
450 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCCREATE"));\r
451                 break;\r
452         case WM_NCDESTROY:                              // 0x0082\r
453 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCDESTROY"));\r
454                 break;\r
455         case WM_NCCALCSIZE:                             // 0x0083\r
456 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCCALCSIZE"));\r
457                 break;\r
458         case WM_NCPAINT:                                // 0x0085\r
459 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_NCPAINT"));\r
460                 break;\r
461         case WM_IME_STARTCOMPOSITION:   // 0x010D\r
462 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_STARTCOMPOSITION"));\r
463                 break;\r
464         case WM_IME_ENDCOMPOSITION:             // 0x010E\r
465 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_ENDCOMPOSITION"));\r
466                 break;\r
467         case WM_IME_KEYLAST:                    // 0x010F\r
468 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_KEYLAST"));\r
469                 break;\r
470         case WM_COMMAND:                                // 0x0111\r
471 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_COMMAND"));\r
472                 break;\r
473         case WM_CTLCOLOREDIT:                   // 0x0133\r
474 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_CTLCOLOREDIT"));\r
475                 break;\r
476         case WM_POWERBROADCAST:                 // 0x0218\r
477 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_POWERBROADCAST"));\r
478                 switch (wParam) {\r
479                 case PBT_APMQUERYSUSPEND:               // 0x0000\r
480 //                      CUtils::Log(_T("PBT_APMQUERYSUSPEND"));\r
481                         break;\r
482                 case PBT_APMQUERYSTANDBY:               // 0x0001\r
483 //                      CUtils::Log(_T("PBT_APMQUERYSTANDBY"));\r
484                         break;\r
485                 case PBT_APMQUERYSUSPENDFAILED: // 0x0002\r
486 //                      CUtils::Log(_T("PBT_APMQUERYSUSPENDFAILED"));\r
487                         break;\r
488                 case PBT_APMQUERYSTANDBYFAILED: // 0x0003\r
489 //                      CUtils::Log(_T("PBT_APMQUERYSTANDBYFAILED"));\r
490                         break;\r
491                 case PBT_APMSUSPEND:                    // 0x0004\r
492 //                      CUtils::Log(_T("PBT_APMSUSPEND"));\r
493                         break;\r
494                 case PBT_APMSTANDBY:                    // 0x0005\r
495 //                      CUtils::Log(_T("PBT_APMSTANDBY"));\r
496                         break;\r
497                 case PBT_APMRESUMECRITICAL:             // 0x0006\r
498 //                      CUtils::Log(_T("PBT_APMRESUMECRITICAL"));\r
499                         break;\r
500                 case PBT_APMRESUMESUSPEND:              // 0x0007\r
501 //                      CUtils::Log(_T("PBT_APMRESUMESUSPEND"));\r
502                         break;\r
503                 case PBT_APMRESUMESTANDBY:              // 0x0008\r
504 //                      CUtils::Log(_T("PBT_APMRESUMESTANDBY"));\r
505                         break;\r
506                 case PBT_APMBATTERYLOW:                 // 0x0009\r
507 //                      CUtils::Log(_T("PBT_APMBATTERYLOW"));\r
508                         break;\r
509                 case PBT_APMPOWERSTATUSCHANGE:  // 0x000A\r
510 //                      CUtils::Log(_T("PBT_APMPOWERSTATUSCHANGE"));\r
511                         break;\r
512                 case PBT_APMOEMEVENT:                   // 0x000B\r
513 //                      CUtils::Log(_T("PBT_APMOEMEVENT"));\r
514                         break;\r
515                 case PBT_APMRESUMEAUTOMATIC:    // 0x0012\r
516 //                      CUtils::Log(_T("PBT_APMRESUMEAUTOMATIC"));\r
517                         break;\r
518                 default:\r
519 //                      CUtils::Log(_T("PBT_OTHERS: %d"), wParam);\r
520                         break;\r
521                 }\r
522                 break;\r
523         case WM_IME_NOTIFY:                             // 0x0282\r
524 //              CUtils::Log(_T("CallWndProc: cwps.message = WM_IME_NOTIFY"));\r
525                 break;\r
526         default:\r
527 //              CUtils::Log(_T("CallWndProc: cwps.message = 0x%04X"), cwps.message);\r
528                 break;\r
529         }\r
530 }\r
531 \r
532 LRESULT CALLBACK CXkeymacsDll::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)\r
533 {\r
534 //      LogCallWndProcMessage(wParam, lParam);\r
535 \r
536         if (0 <= nCode) {\r
537                 CWPSTRUCT &cwps = *(CWPSTRUCT *)lParam;\r
538                 switch (cwps.message) {\r
539                 case WM_IME_STARTCOMPOSITION:\r
540                         InitKeyboardProc(TRUE);\r
541                         break;\r
542                 case WM_IME_ENDCOMPOSITION:\r
543                         InitKeyboardProc(FALSE);\r
544                         break;\r
545                 case WM_SETFOCUS:\r
546                         if (cwps.hwnd == GetForegroundWindow()) {\r
547                                 InitKeyboardProc(FALSE);\r
548                                 SetKeyboardHookFlag(m_bHook);\r
549                         }\r
550                         break;\r
551                 case WM_NCACTIVATE:\r
552                         if (cwps.wParam) {\r
553                                 if (cwps.hwnd == GetForegroundWindow()) {\r
554                                         InitKeyboardProc(FALSE);\r
555                                         SetKeyboardHookFlag(m_bHook);\r
556                                 }\r
557                         }\r
558                         break;\r
559                 case WM_POWERBROADCAST:\r
560                         switch (wParam) {\r
561                         case PBT_APMRESUMECRITICAL: // 0x0006\r
562                         case PBT_APMRESUMESUSPEND:  // 0x0007\r
563                         case PBT_APMRESUMESTANDBY:  // 0x0008\r
564                                 ReleaseHooks();\r
565                                 SetHooks();\r
566                                 break;\r
567                         default:\r
568                                 break;\r
569                         }\r
570                         break;\r
571                 default:\r
572                         break;\r
573                 }\r
574         }\r
575         return CallNextHookEx(m_hHookCallWnd, nCode, wParam, lParam);\r
576 }\r
577 \r
578 LRESULT CALLBACK CXkeymacsDll::CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)\r
579 {\r
580         if (0 <= nCode) {\r
581                 CWPRETSTRUCT &cwprets = *(CWPRETSTRUCT *)lParam;\r
582                 switch (cwprets.message) {\r
583                 case WM_SETTEXT:\r
584                         if (cwprets.hwnd == GetForegroundWindow()) {\r
585                                 InitKeyboardProc(FALSE);\r
586                         }\r
587                         break;\r
588                 case WM_SETCURSOR:\r
589                         DoSetCursor();\r
590                         break;\r
591                 default:\r
592                         break;\r
593                 }\r
594         }\r
595         return CallNextHookEx(m_hHookCallWndRet, nCode, wParam, lParam);\r
596 }\r
597 \r
598 LRESULT CALLBACK CXkeymacsDll::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)\r
599 {\r
600         MSG &msg = (*(MSG *)lParam);\r
601 \r
602         switch (msg.message) {\r
603         case WM_IME_STARTCOMPOSITION:\r
604                 InitKeyboardProc(TRUE);\r
605                 break;\r
606         case WM_IME_ENDCOMPOSITION:\r
607                 InitKeyboardProc(FALSE);\r
608                 break;\r
609         }\r
610         return CallNextHookEx(m_hHookGetMessage, nCode, wParam, lParam);\r
611 }\r
612 \r
613 LRESULT CALLBACK CXkeymacsDll::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)\r
614 {\r
615         switch (nCode) {\r
616         case HSHELL_WINDOWACTIVATED:\r
617         {\r
618                 TCHAR className[256];\r
619                 ::GetClassName((HWND)wParam, className, 255);\r
620                 if (!_tcsicmp(className, _T("ConsoleWindowClass"))) {\r
621                         InitKeyboardProc(FALSE);\r
622                         SetKeyboardHookFlag(m_bHook);\r
623                 }\r
624                 break;\r
625         }\r
626         default:\r
627                 break;\r
628         }\r
629         return CallNextHookEx( m_hHookShell, nCode, wParam, lParam );\r
630 }\r
631 \r
632 // return true if the key is down\r
633 BOOL CXkeymacsDll::IsDown(BYTE bVk, BOOL bPhysicalKey)\r
634 {\r
635         if (bPhysicalKey) {\r
636                 return GetKeyState(bVk) < 0;\r
637         } else {\r
638                 return GetAsyncKeyState(bVk) < 0;\r
639         }\r
640 }\r
641 \r
642 // Do keybd_event\r
643 void CXkeymacsDll::DoKeybd_event(BYTE bVk, DWORD dwFlags)\r
644 {\r
645         // Set KEYEVENTF_EXTENDEDKEY if needed\r
646         switch (bVk) {\r
647         case VK_CONTROL:\r
648                 if (m_bRightControl) {          // Right Ctrl\r
649                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
650                 }\r
651                 break;\r
652 \r
653         case VK_MENU:\r
654                 if (m_bRightAlt) {                      // Right Alt\r
655                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
656 //                      CUtils::Log("Right Alt %d", dwFlags);\r
657 //              } else {\r
658 //                      CUtils::Log("Left Alt %d", dwFlags);\r
659                 }\r
660                 break;\r
661 \r
662         case VK_SHIFT:\r
663                 if (m_bRightShift) {            // Right Shift\r
664                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
665                 }\r
666                 break;\r
667 \r
668         case VK_PAUSE:\r
669                 if (IsDown(VK_CONTROL)) {       // Break\r
670                         dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
671                 }\r
672                 break;\r
673 \r
674         case VK_INSERT:\r
675         case VK_DELETE:\r
676         case VK_HOME:\r
677         case VK_END:\r
678         case VK_NEXT:\r
679         case VK_PRIOR:\r
680         case VK_UP:\r
681         case VK_DOWN:\r
682         case VK_RIGHT:\r
683         case VK_LEFT:\r
684         case VK_NUMLOCK:\r
685         case VK_PRINT:\r
686                 dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
687                 break;\r
688 \r
689         default:\r
690                 break;\r
691         }\r
692 \r
693 //      CUtils::Log(_T("b: %x, %x, %x, %#x, %#x"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
694         keybd_event(bVk, 0, dwFlags, GetMessageExtraInfo());\r
695 //      CUtils::Log(_T("a: %x, %x, %x, %#x, %#x"), bVk, dwFlags, GetMessageExtraInfo(), GetKeyState(bVk), GetAsyncKeyState(bVk));\r
696 }\r
697 \r
698 // the key is being depressed\r
699 void CXkeymacsDll::DepressKey(BYTE bVk, BOOL bOriginal) // bVk is virtual-key code, MSDN said\r
700 {\r
701         if (bOriginal) {\r
702 //              CUtils::Log(_T("i: %x, %d, %d, %d, %d, %d, %d, %d, %d"), bVk,\r
703 //                      IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
704 //                      IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
705 \r
706                 int nCommandType = NONE;\r
707                 if (IsDown(VK_CONTROL, FALSE)) {\r
708                         nCommandType |= CONTROL;\r
709                 }\r
710                 if (IsDown(VK_MENU, FALSE)) {\r
711                         nCommandType |= META;\r
712                 }\r
713                 Original(nCommandType, bVk, 1);\r
714         }\r
715 \r
716         DoKeybd_event(bVk, 0);\r
717 }\r
718 \r
719 // the key is being released\r
720 void CXkeymacsDll::ReleaseKey(BYTE bVk) // bVk is virtual-key code, MSDN said\r
721 {\r
722         DoKeybd_event(bVk, KEYEVENTF_KEYUP);\r
723 }\r
724 \r
725 // bVk down, bVk up\r
726 void CXkeymacsDll::Kdu(BYTE bVk, DWORD n, BOOL bOriginal)\r
727 {\r
728         while (n--) {\r
729                 DepressKey(bVk, bOriginal);\r
730                 ReleaseKey(bVk);\r
731         }\r
732 }\r
733 \r
734 void CXkeymacsDll::InitKeyboardProc(BOOL bImeComposition)\r
735 {\r
736         if (CUtils::IsFindDialog()) {\r
737                 static BOOL bImeCompositionOld = FALSE;\r
738                 if (!bImeComposition\r
739                  && bImeCompositionOld) {\r
740                         DepressKey(VK_END);\r
741                         ReleaseKey(VK_END);\r
742                 }\r
743                 bImeCompositionOld = bImeComposition;\r
744         }\r
745 \r
746         CUtils::SetApplicationName(bImeComposition);\r
747 \r
748         if (_tcsnicmp(m_szSpecialApp[m_nApplicationID], CUtils::GetApplicationName(), 0xF) || !IsMatchWindowText(m_szWindowText[m_nApplicationID])) {   // PROCESSENTRY32 has only 0xF bytes of Name\r
749                 m_nApplicationID = -1;\r
750 \r
751                 for (int nApplicationID = 0; nApplicationID < MAX_APP; ++nApplicationID) {\r
752                         if (!_tcsnicmp(m_szSpecialApp[nApplicationID], CUtils::GetApplicationName(), 0xF) && IsMatchWindowText(m_szWindowText[nApplicationID])) {\r
753 \r
754                                 if (m_nApplicationID < 0\r
755                                  || CUtils::GetWindowTextType(m_szWindowText[m_nApplicationID]) < CUtils::GetWindowTextType(m_szWindowText[nApplicationID])\r
756                                  || CUtils::GetWindowTextType(m_szWindowText[m_nApplicationID]) == CUtils::GetWindowTextType(m_szWindowText[nApplicationID])\r
757                                  && _tcscmp(m_szWindowText[m_nApplicationID], m_szWindowText[nApplicationID]) <= 0) {\r
758                                         m_nApplicationID = nApplicationID;\r
759                                 }\r
760                         }\r
761                 }\r
762 \r
763                 if (m_nApplicationID < 0) {\r
764                         for (int nApplicationID = 0; nApplicationID < MAX_APP; ++nApplicationID) {\r
765                                 if (!_tcsicmp(m_szSpecialApp[nApplicationID], _T("Default"))) {\r
766                                         m_nApplicationID = nApplicationID;\r
767                                         break;\r
768                                 }\r
769                         }\r
770 \r
771                         if (m_nApplicationID < 0) {\r
772                                 m_nApplicationID = 0;\r
773                         }\r
774                 }\r
775         }\r
776 \r
777         if (m_nSettingStyle[m_nApplicationID] != SETTING_DISABLE\r
778          && (_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Default")) || !CUtils::IsDefaultIgnoreApplication())\r
779          && !bImeComposition\r
780          && CUtils::IsDialog()) {\r
781                 // Use Dialog Setting\r
782                 if (m_bUseDialogSetting[m_nApplicationID]) {\r
783                         int nOriginalApplicationID = m_nApplicationID;\r
784                         for (m_nApplicationID = 0; m_nApplicationID < MAX_APP; ++m_nApplicationID) {\r
785                                 if (!_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Dialog"))) {\r
786                                         break;\r
787                                 }\r
788                         }\r
789                         if (m_nApplicationID == MAX_APP) {\r
790                                 m_nApplicationID = nOriginalApplicationID;\r
791                         }\r
792                 }\r
793         }\r
794 \r
795         ModifyShell_NotifyIcon(CX_ICON, FALSE);\r
796         ModifyShell_NotifyIcon(MX_ICON, FALSE);\r
797         ModifyShell_NotifyIcon(META_ICON, FALSE);\r
798         CCommands::SetMark(FALSE);\r
799         CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
800         CCommands::Reset();\r
801 }\r
802 \r
803 // emulate emacs        // cf virtual-key code\r
804 LRESULT CALLBACK CXkeymacsDll::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
805 {\r
806         ASSERT(0 <= wParam && wParam <= UCHAR_MAX);\r
807 \r
808         int nCommandType = NONE;\r
809         BYTE nKey = (BYTE)wParam;\r
810 \r
811         static BOOL bLocked = FALSE;\r
812         static const BYTE RECURSIVE_KEY = 0x07;\r
813         static int (*fCommand)() = NULL;\r
814         static BYTE nOneShotModifier[MAX_KEY] = {'\0'};\r
815         static BOOL bCherryOneShotModifier = FALSE;\r
816 \r
817 //      CUtils::Log(_T("nCode = %#x, nKey = %#x, lParam = %#x"), nCode, nKey, lParam);\r
818 \r
819         if (!m_bEnableKeyboardHook)\r
820                 return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
821 \r
822         if (nCode < 0 || nCode == HC_NOREMOVE) {\r
823                 goto DO_NOTHING;\r
824         }\r
825 \r
826         if (nKey == RECURSIVE_KEY) {\r
827                 if (lParam & BEING_RELEASED) {\r
828                         goto HOOK_RECURSIVE_KEY;\r
829                 } else {\r
830                         goto RECURSIVE_COMMAND;\r
831                 }\r
832         }\r
833 \r
834         {\r
835                 static BOOL bShift = FALSE;\r
836                 if (IsDepressedShiftKeyOnly(nKey)) {\r
837                         if (lParam & BEING_RELEASED) {\r
838                                 if (bShift) {\r
839                                         CCommands::SetMark(FALSE);\r
840                                 }\r
841                         } else {\r
842                                 bShift = TRUE;\r
843                         }\r
844                 } else {\r
845                         bShift = FALSE;\r
846                 }\r
847         }\r
848 \r
849         switch (nKey) {\r
850         case VK_CONTROL:\r
851                 if (lParam & EXTENDED_KEY) {\r
852                         nKey = VK_RCONTROL;\r
853                 } else {\r
854                         nKey = VK_LCONTROL;\r
855                 }\r
856                 break;\r
857         case VK_MENU:\r
858                 if (lParam & EXTENDED_KEY) {\r
859                         nKey = VK_RMENU;\r
860                 } else {\r
861                         nKey = VK_LMENU;\r
862                 }\r
863                 break;\r
864         case VK_SHIFT:\r
865                 if (lParam & EXTENDED_KEY) {\r
866                         nKey = VK_RSHIFT;\r
867                 } else {\r
868                         nKey = VK_LSHIFT;\r
869                 }\r
870                 break;\r
871         default:\r
872                 break;\r
873         }\r
874 \r
875         if (lParam & BEING_RELEASED) {\r
876                 if (nKey == VK_MENU\r
877                  || nKey == VK_LWIN\r
878                  || nKey == VK_RWIN\r
879                  || nKey == VK_APPS\r
880                  || nKey == VK_LMENU\r
881                  || nKey == VK_RMENU) {\r
882                         for (int i = 0; i < MAX_COMMAND_TYPE; ++i) {\r
883                                 if (Commands[m_nCommandID[m_nApplicationID][i][nKey]].fCommand\r
884                                  && (Commands[m_nCommandID[m_nApplicationID][i][nKey]].fCommand != CCommands::MetaAlt\r
885                                   || nKey != VK_MENU && nKey != VK_LMENU && nKey != VK_RMENU)) {\r
886                                         goto HOOK;\r
887                                 }\r
888                         }\r
889                 }\r
890 \r
891                 if (nOneShotModifier[nKey]) {\r
892                         ReleaseKey(nOneShotModifier[nKey]);\r
893                         nOneShotModifier[nKey] = 0;\r
894 \r
895                         if (bCherryOneShotModifier) {\r
896                                 bCherryOneShotModifier = FALSE;\r
897                                 Kdu(nKey);\r
898                         }\r
899                 }\r
900 \r
901                 goto DO_NOTHING;\r
902         }\r
903 \r
904         if (m_nSettingStyle[m_nApplicationID] == SETTING_DISABLE) {\r
905                 goto DO_NOTHING;\r
906         }\r
907 \r
908         // Do Nothing for Meadow, Mule for Win32, ... if those use default setting.\r
909         if (!_tcsicmp(m_szSpecialApp[m_nApplicationID], _T("Default"))\r
910          && CUtils::IsDefaultIgnoreApplication()) {\r
911                 goto DO_NOTHING;\r
912         }\r
913 \r
914         switch (IsPassThrough(nKey)) {\r
915         case GOTO_DO_NOTHING:\r
916                 goto DO_NOTHING;\r
917         case GOTO_HOOK:\r
918                 goto HOOK;\r
919         case CONTINUE:\r
920                 break;\r
921         default:\r
922                 ASSERT(0);\r
923                 break;\r
924         }\r
925 \r
926         // set command type\r
927         {\r
928                 nCommandType = NONE;\r
929                 if (IsDown(VK_SHIFT, FALSE)) {\r
930                         nCommandType |= SHIFT;\r
931                 }\r
932                 if (IsControl()) {\r
933                         nCommandType |= CONTROL;\r
934                 }\r
935                 if (IsMeta()) {\r
936                         nCommandType |= META;\r
937                 }\r
938                 if (CCommands::bC_x()) {\r
939                         nCommandType |= CONTROLX;\r
940                 }\r
941 \r
942                 // Ignore undefined C-x ?\r
943                 if (nCommandType & CONTROLX) {\r
944                         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == NULL\r
945                          && m_nFunctionID[m_nApplicationID][nCommandType][nKey] < 0) {\r
946                                 if (m_bIgnoreUndefinedC_x[m_nApplicationID]) {\r
947                                         CCommands::Reset(GOTO_HOOK);\r
948                                         goto HOOK;\r
949                                 }\r
950                                 nCommandType &= ~CONTROLX;\r
951                         }\r
952                 }\r
953 \r
954                 // Ignore undefined Meta Ctrl+?\r
955                 if (CCommands::bM_() && (nCommandType & CONTROL)) {\r
956                         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == NULL\r
957                          && m_nFunctionID[m_nApplicationID][nCommandType][nKey] < 0) {\r
958                                 if (m_bIgnoreUndefinedMetaCtrl[m_nApplicationID]) {\r
959                                         if (Original(CONTROL, nKey)) {\r
960                                                 Original(CONTROL, nKey, -1);\r
961                                                 goto DO_NOTHING;\r
962                                         }\r
963                                         CCommands::Reset(GOTO_HOOK);\r
964                                         goto HOOK;\r
965                                 }\r
966                                 nCommandType &= ~META;\r
967                         }\r
968                 }\r
969         }\r
970 \r
971         {\r
972 //              CUtils::Log(_T("o: %x, %d, %d, %d, %d, %d, %d, %d, %d"), (BYTE)wParam,\r
973 //                      IsDown(VK_CONTROL), IsDown(VK_CONTROL, FALSE), IsDepressedModifier(CCommands::C_), IsDepressedModifier(CCommands::C_, FALSE),\r
974 //                      IsDown(VK_MENU), IsDown(VK_MENU, FALSE), IsDepressedModifier(CCommands::MetaAlt), IsDepressedModifier(CCommands::MetaAlt, FALSE));\r
975 \r
976                 BYTE nKey = (BYTE)wParam; // VK_CONTROL is needed instead of VK_RCONTROL and VK_LCONTROL in this block just for Original()\r
977                 int nVirtualCommandType = NONE;\r
978                 if (IsDown(VK_CONTROL) && nKey != VK_CONTROL) {\r
979                         nVirtualCommandType |= CONTROL;\r
980                 }\r
981                 if (IsDown(VK_MENU) && nKey != VK_MENU) {\r
982                         nVirtualCommandType |= META;\r
983                 }\r
984                 if (Original(nVirtualCommandType, nKey)) {\r
985                         Original(nVirtualCommandType, nKey, -1);\r
986                         goto DO_NOTHING;\r
987                 }\r
988         }\r
989 \r
990         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EnableOrDisableXKeymacs) {\r
991                 SetKeyboardHookFlag(!m_bHook);\r
992                 goto HOOK;\r
993         }\r
994         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EnableXKeymacs) {\r
995                 if (!m_bHook) {\r
996                         SetKeyboardHookFlag(!m_bHook);\r
997                 }\r
998                 goto HOOK;\r
999         }\r
1000         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DisableXKeymacs) {\r
1001                 if (m_bHook) {\r
1002                         SetKeyboardHookFlag(!m_bHook);\r
1003                 }\r
1004                 goto HOOK;\r
1005         }\r
1006         if (!m_bHook) {\r
1007                 goto DO_NOTHING;\r
1008         }\r
1009 \r
1010         if (CCommands::bM_x()) {\r
1011                 static unsigned int index = 0;\r
1012                 static TCHAR szPath[MAX_PATH] = {'\0'};\r
1013 \r
1014                 if (lParam & BEING_RELEASED) {\r
1015                         // ignore\r
1016                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::BackwardChar) {\r
1017                         if (index) {\r
1018                                 --index;\r
1019                         }\r
1020                         goto HOOKX;\r
1021                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::BeginningOfLine) {\r
1022                         index = 0;\r
1023                         goto HOOKX;\r
1024                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DeleteBackwardChar) {\r
1025                         if (index) {\r
1026                                 --index;\r
1027                                 memmove(&szPath[index], &szPath[index + 1], _tcslen(szPath) - index);\r
1028                                 ModifyM_xTip(szPath);\r
1029                         }\r
1030                         goto HOOKX;\r
1031                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::DeleteChar) {\r
1032                         if (index < _tcslen(szPath)) {\r
1033                                 memmove(&szPath[index], &szPath[index + 1], _tcslen(szPath) - index);\r
1034                                 ModifyM_xTip(szPath);\r
1035                         }\r
1036                         goto HOOKX;\r
1037                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::EndOfLine) {\r
1038                         index = _tcslen(szPath);\r
1039                         goto HOOKX;\r
1040                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::ForwardChar) {\r
1041                         if (index < _tcslen(szPath)) {\r
1042                                 ++index;\r
1043                         }\r
1044                         goto HOOKX;\r
1045                 } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::KeyboardQuit) {\r
1046                         CCommands::bM_x(FALSE);\r
1047                         index = 0;\r
1048                         memset(szPath, 0, sizeof(szPath));\r
1049                         goto HOOK;\r
1050                 } else if (nKey == VK_RETURN\r
1051                                 || Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::Newline) {\r
1052                         InvokeM_x(szPath);\r
1053 \r
1054                         CCommands::bM_x(FALSE);\r
1055                         index = 0;\r
1056                         memset(szPath, 0, sizeof(szPath));\r
1057                         goto HOOK;\r
1058                 } else if (index < MAX_PATH - 1) {\r
1059                         const BOOL bIsShiftDown = CXkeymacsDll::IsDown(VK_SHIFT);\r
1060                         for (TCHAR nAscii = 1; nAscii != 0; ++nAscii) { // repeat until overflow\r
1061                                 if (nKey != 0 && a2v(nAscii) == nKey && bIsShiftDown == IsShift(nAscii)) {\r
1062 //                                      CUtils::Log("M-x: %#X (%c), %#X (%c)", nKey, nKey, nAscii, nAscii);\r
1063                                         if (index < _tcslen(szPath)) {\r
1064                                                 memmove(&szPath[index + 1], &szPath[index], __min(_tcslen(szPath) - index, MAX_PATH - (index + 1) - 1));\r
1065                                         }\r
1066                                         szPath[index++] = nAscii;\r
1067 //                                      CUtils::Log("M-x: %c(%#04x)", nAscii, nAscii);\r
1068                                         ModifyM_xTip(szPath);\r
1069                                         goto HOOKX;\r
1070                                 }\r
1071                         }\r
1072                 }\r
1073         }\r
1074 \r
1075         if (CCommands::bC_u()) {\r
1076                 if ((nCommandType == NONE) && ('0' <= nKey) && (nKey <= '9')) {\r
1077                         CCommands::NumericArgument(nKey - '0');\r
1078                         goto HOOK0_9;\r
1079                 }\r
1080                 if ((nCommandType == NONE) && (nKey == 0xBD)) {\r
1081                         CCommands::NumericArgumentMinus();\r
1082                         goto HOOK0_9;\r
1083                 }\r
1084         }\r
1085 \r
1086         if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~CONTROL][nKey]].fCommand == CCommands::OneShotModifierCtrl) {\r
1087                 nOneShotModifier[nKey] = VK_LCONTROL;\r
1088                 DepressKey(nOneShotModifier[nKey]);\r
1089                 bCherryOneShotModifier = TRUE;\r
1090                 goto HOOK;\r
1091         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierCtrlRepeat) {\r
1092                 nOneShotModifier[nKey] = VK_LCONTROL;\r
1093                 DepressKey(nOneShotModifier[nKey]);\r
1094                 bCherryOneShotModifier = TRUE;\r
1095                 goto HOOK;\r
1096         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~CONTROL][nKey]].fCommand == CCommands::OneShotModifierCtrlRepeat) {\r
1097                 ReleaseKey(nOneShotModifier[nKey]);\r
1098                 bCherryOneShotModifier = FALSE;\r
1099                 Kdu(nKey);\r
1100                 goto HOOK;\r
1101         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~META][nKey]].fCommand == CCommands::OneShotModifierAlt) {\r
1102                 nOneShotModifier[nKey] = VK_LMENU;\r
1103                 DepressKey(nOneShotModifier[nKey]);\r
1104                 bCherryOneShotModifier = TRUE;\r
1105                 goto HOOK;\r
1106         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierAltRepeat) {\r
1107                 nOneShotModifier[nKey] = VK_LMENU;\r
1108                 DepressKey(nOneShotModifier[nKey]);\r
1109                 bCherryOneShotModifier = TRUE;\r
1110                 goto HOOK;\r
1111         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~META][nKey]].fCommand == CCommands::OneShotModifierAltRepeat) {\r
1112                 ReleaseKey(nOneShotModifier[nKey]);\r
1113                 bCherryOneShotModifier = FALSE;\r
1114                 Kdu(nKey);\r
1115                 goto HOOK;\r
1116         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~SHIFT][nKey]].fCommand == CCommands::OneShotModifierShift) {\r
1117                 nOneShotModifier[nKey] = VK_SHIFT;\r
1118                 DepressKey(nOneShotModifier[nKey]);\r
1119                 bCherryOneShotModifier = TRUE;\r
1120                 goto HOOK;\r
1121         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand == CCommands::OneShotModifierShiftRepeat) {\r
1122                 nOneShotModifier[nKey] = VK_SHIFT;\r
1123                 DepressKey(nOneShotModifier[nKey]);\r
1124                 bCherryOneShotModifier = TRUE;\r
1125                 goto HOOK;\r
1126         } else if (Commands[m_nCommandID[m_nApplicationID][nCommandType & ~SHIFT][nKey]].fCommand == CCommands::OneShotModifierShiftRepeat) {\r
1127                 ReleaseKey(nOneShotModifier[nKey]);\r
1128                 bCherryOneShotModifier = FALSE;\r
1129                 Kdu(nKey);\r
1130                 goto HOOK;\r
1131         } else {\r
1132                 for (int i = 0; i < MAX_KEY; ++i) {\r
1133                         if (nOneShotModifier[i] == nKey) {\r
1134                                 break;\r
1135                         }\r
1136                 }\r
1137                 if (i == MAX_KEY) {\r
1138                         bCherryOneShotModifier = FALSE;\r
1139                 }\r
1140         }\r
1141 \r
1142         if (0 <= m_nFunctionID[m_nApplicationID][nCommandType][nKey]\r
1143          && m_nFunctionID[m_nApplicationID][nCommandType][nKey] < MAX_FUNCTION\r
1144          && _tcslen(m_szFunctionDefinition[m_nFunctionID[m_nApplicationID][nCommandType][nKey]])) {\r
1145                 CallFunction(m_nFunctionID[m_nApplicationID][nCommandType][nKey]);\r
1146                 CCommands::Reset(GOTO_HOOK);\r
1147                 goto HOOK;\r
1148         }\r
1149 \r
1150         if (!Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand) {\r
1151                 if (nKey == VK_CONTROL\r
1152                  || nKey == VK_LCONTROL\r
1153                  || nKey == VK_RCONTROL\r
1154                  || nKey == VK_MENU\r
1155                  || nKey == VK_LMENU\r
1156                  || nKey == VK_RMENU\r
1157                  || nKey == VK_SHIFT\r
1158                  || nKey == VK_LSHIFT\r
1159                  || nKey == VK_RSHIFT) {\r
1160                         goto DO_NOTHING;\r
1161                 }\r
1162 \r
1163                 if (!(nCommandType & SHIFT)) {\r
1164                         if (CCommands::IsSetMark()) {\r
1165                                 if (CCommands::MoveCaret(nKey, nCommandType & CONTROL) != CONTINUE) {\r
1166                                         CCommands::ClearNumericArgument();\r
1167                                         goto HOOK;\r
1168                                 }\r
1169                                 CCommands::SetMark(FALSE);\r
1170                         }\r
1171                 }\r
1172 \r
1173                 if (1 < CCommands::GetNumericArgument()) {\r
1174                         Kdu(nKey, CCommands::GetNumericArgument());\r
1175                         CCommands::ClearNumericArgument();\r
1176                         goto HOOK;\r
1177                 }\r
1178 \r
1179                 goto DO_NOTHING;\r
1180         }\r
1181 \r
1182         if (CCommands::IsTemporarilyDisableXKeymacs()\r
1183          && Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand != CCommands::KeyboardQuit) {\r
1184                 CCommands::SetTemporarilyDisableXKeymacs(FALSE);\r
1185                 goto DO_NOTHING;\r
1186         }\r
1187 \r
1188         if (m_bAtIbeamCursorOnly[m_nApplicationID][nCommandType][nKey]) {\r
1189                 CURSORINFO cursorinfo = { sizeof(cursorinfo) };\r
1190                 if (GetCursorInfo(&cursorinfo) && cursorinfo.flags && cursorinfo.hCursor != LoadCursor(NULL, IDC_IBEAM)) {\r
1191                         goto DO_NOTHING;\r
1192                 }\r
1193         }\r
1194 \r
1195         m_bRightControl = IsDown(VK_RCONTROL);\r
1196         m_bRightAlt             = IsDown(VK_RMENU);\r
1197         m_bRightShift   = IsDown(VK_RSHIFT);\r
1198 \r
1199         if (!bLocked) {\r
1200                 bLocked = TRUE;\r
1201                 fCommand = Commands[m_nCommandID[m_nApplicationID][nCommandType][nKey]].fCommand;\r
1202 RECURSIVE_COMMAND:\r
1203                 switch (fCommand()) {\r
1204                 case GOTO_DO_NOTHING:\r
1205                         bLocked = FALSE;\r
1206                         goto DO_NOTHING;\r
1207                 case GOTO_HOOK:\r
1208                         bLocked = FALSE;\r
1209                         goto HOOK;\r
1210                 case GOTO_RECURSIVE:\r
1211                         goto RECURSIVE;\r
1212                 case GOTO_HOOKX:\r
1213                         bLocked = FALSE;\r
1214                         goto HOOKX;\r
1215                 case GOTO_HOOK0_9:\r
1216                         bLocked = FALSE;\r
1217                         goto HOOK0_9;\r
1218                 default:\r
1219                         ASSERT(0);\r
1220                         bLocked = FALSE;\r
1221                         goto DO_NOTHING;\r
1222                 }\r
1223         } else {\r
1224                 goto HOOK_RECURSIVE_KEY;\r
1225         }\r
1226 \r
1227 DO_NOTHING:\r
1228         ModifyShell_NotifyIcon(SHIFT_ICON, IsDown(VK_SHIFT));\r
1229         ModifyShell_NotifyIcon(CTRL_ICON, IsControl());\r
1230         ModifyShell_NotifyIcon(ALT_ICON, IsDown(VK_MENU));\r
1231 \r
1232         {\r
1233                 static BOOL bDefiningMacro = FALSE;\r
1234                 if (m_bDefiningMacro) {\r
1235                         static BOOL bDown[MAX_KEY] = {'\0'};\r
1236 \r
1237                         if (!bDefiningMacro) {\r
1238                                 while (m_Macro.GetHeadPosition()) {\r
1239                                         void *p = m_Macro.GetAt(m_Macro.GetHeadPosition());\r
1240                                         m_Macro.RemoveHead();\r
1241                                         delete p;\r
1242                                         p = NULL;\r
1243                                 }\r
1244                                 memset(bDown, 0, sizeof(bDown));\r
1245                         }\r
1246 \r
1247                         if ((!(lParam & BEING_RELEASED)) || bDown[wParam]) {\r
1248                                 try {\r
1249                                         KbdMacro *pKbdMacro = new KbdMacro;\r
1250                                         if (pKbdMacro) {\r
1251                                                 pKbdMacro->nCode = nCode;\r
1252                                                 pKbdMacro->wParam = wParam;\r
1253                                                 pKbdMacro->lParam = lParam;\r
1254                                                 pKbdMacro->bOriginal = TRUE;\r
1255                                                 m_Macro.AddTail((CObject *)pKbdMacro);\r
1256                                         }\r
1257                                 }\r
1258                                 catch (CMemoryException* e) {\r
1259                                         e->Delete();\r
1260 //                                      CUtils::Log("KeyboardProc: 'new' threw an exception");\r
1261                                 }\r
1262                                 if (!(lParam & BEING_RELEASED)) {\r
1263                                         bDown[wParam] = TRUE;\r
1264                                 }\r
1265                         }\r
1266                 }\r
1267                 bDefiningMacro = m_bDefiningMacro;\r
1268         }\r
1269 \r
1270         return CallNextHookEx(g_hHookKeyboard, nCode, wParam, lParam);\r
1271 \r
1272 RECURSIVE:\r
1273         Kdu(RECURSIVE_KEY, 1, FALSE);\r
1274         ModifyShell_NotifyIcon(SHIFT_ICON, IsDown(VK_SHIFT));\r
1275         ModifyShell_NotifyIcon(CTRL_ICON, IsControl());\r
1276         ModifyShell_NotifyIcon(ALT_ICON, IsDown(VK_MENU));\r
1277         return TRUE;\r
1278 \r
1279 HOOK:\r
1280         CCommands::SetLastCommand(fCommand);\r
1281 HOOK0_9:\r
1282 HOOKX:\r
1283         ModifyShell_NotifyIcon(SHIFT_ICON, IsDown(VK_SHIFT));\r
1284         ModifyShell_NotifyIcon(CTRL_ICON, IsControl());\r
1285         ModifyShell_NotifyIcon(ALT_ICON, IsDown(VK_MENU));\r
1286 HOOK_RECURSIVE_KEY:\r
1287         return TRUE;\r
1288 }\r
1289 \r
1290 //////////////////////////////////////////////////////////////////////\r
1291 // CXkeymacsData Class\r
1292 //////////////////////////////////////////////////////////////////////\r
1293 \r
1294 //////////////////////////////////////////////////////////////////////\r
1295 // Construction/Destruction\r
1296 //////////////////////////////////////////////////////////////////////\r
1297 \r
1298 CXkeymacsData::CXkeymacsData()\r
1299 {\r
1300         ClearAll();\r
1301 }\r
1302 \r
1303 CXkeymacsData::~CXkeymacsData()\r
1304 {\r
1305 \r
1306 }\r
1307 \r
1308 // set application name\r
1309 void CXkeymacsData::SetApplicationName(LPCTSTR lpszApplicationName)\r
1310 {\r
1311         m_strApplicationName.Format(lpszApplicationName);\r
1312 }\r
1313 \r
1314 // return application name\r
1315 CString CXkeymacsData::GetApplicationName()\r
1316 {\r
1317         return m_strApplicationName;\r
1318 }\r
1319 \r
1320 // set hook or not\r
1321 void CXkeymacsData::SetCommandID(int nCommandType, int nKey, int nCommandID)\r
1322 {\r
1323         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1324         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1325 \r
1326         m_nCommandID[nCommandType][nKey] = nCommandID;\r
1327 }\r
1328 \r
1329 // return hook or not\r
1330 int CXkeymacsData::GetCommandID(int nCommandType, int nKey)\r
1331 {\r
1332         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1333         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1334 \r
1335         return m_nCommandID[nCommandType][nKey];\r
1336 }\r
1337 \r
1338 // set hook at ibeam cursor only or not\r
1339 void CXkeymacsData::SetAtIbeamCursorOnly(int nCommandType, int nKey, BOOL bAtIbeamCursorOnly)\r
1340 {\r
1341         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1342         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1343 \r
1344         m_bAtIbeamCursorOnly[nCommandType][nKey] = bAtIbeamCursorOnly;\r
1345 }\r
1346 \r
1347 // get hook at ibeam cursor only or not\r
1348 BOOL CXkeymacsData::GetAtIbeamCursorOnly(int nCommandType, int nKey)\r
1349 {\r
1350         ASSERT(0 <= nCommandType        || nCommandType < MAX_COMMAND_TYPE);\r
1351         ASSERT(0 <= nKey                        || nKey                 < MAX_KEY);\r
1352 \r
1353         return m_bAtIbeamCursorOnly[nCommandType][nKey];\r
1354 }\r
1355 \r
1356 // clear all data\r
1357 void CXkeymacsData::ClearAll()\r
1358 {\r
1359         ZeroMemory(m_nCommandID, sizeof(m_nCommandID));\r
1360         ZeroMemory(m_bAtIbeamCursorOnly, sizeof(m_bAtIbeamCursorOnly));\r
1361         m_strApplicationName.Empty();\r
1362 }\r
1363 \r
1364 void CXkeymacsDll::SetApplicationName(int nApplicationID, CString szApplicationName)\r
1365 {\r
1366         ZeroMemory(m_szSpecialApp[nApplicationID], sizeof(m_szSpecialApp[nApplicationID]));\r
1367         _tcsncpy(m_szSpecialApp[nApplicationID], szApplicationName, sizeof(m_szSpecialApp[nApplicationID]));\r
1368 }\r
1369 \r
1370 void CXkeymacsDll::SetWindowText(int nApplicationID, CString szWindowText)\r
1371 {\r
1372         ZeroMemory(m_szWindowText[nApplicationID], sizeof(m_szWindowText[nApplicationID]));\r
1373         _tcsncpy(m_szWindowText[nApplicationID], szWindowText, sizeof(m_szWindowText[nApplicationID]));\r
1374 }\r
1375 \r
1376 void CXkeymacsDll::SetCommandID(int nApplicationID, int nCommandType, int nKey, int nCommandID)\r
1377 {\r
1378         m_nCommandID[nApplicationID][nCommandType][nKey] = nCommandID;\r
1379 }\r
1380 \r
1381 void CXkeymacsDll::SetAtIbeamCursorOnly(int nApplicationID, int nCommandType, int nKey, BOOL bAtIbeamCursorOnly)\r
1382 {\r
1383         m_bAtIbeamCursorOnly[nApplicationID][nCommandType][nKey] = bAtIbeamCursorOnly;\r
1384 }\r
1385 \r
1386 void CXkeymacsDll::SetKillRingMax(int nApplicationID, int nKillRingMax)\r
1387 {\r
1388         m_nKillRingMax[nApplicationID] = nKillRingMax;\r
1389 }\r
1390 \r
1391 void CXkeymacsDll::SetUseDialogSetting(int nApplicationID, BOOL bUseDialogSetting)\r
1392 {\r
1393         m_bUseDialogSetting[nApplicationID] = bUseDialogSetting;\r
1394 }\r
1395 \r
1396 // Clear data of nApplicationID\r
1397 void CXkeymacsDll::Clear(int nApplicationID)\r
1398 {\r
1399         if (0 <= nApplicationID && nApplicationID < MAX_APP) {\r
1400                 ZeroMemory(m_szSpecialApp[nApplicationID], sizeof(m_szSpecialApp[nApplicationID]));\r
1401                 ZeroMemory(m_nCommandID[nApplicationID], sizeof(m_nCommandID[nApplicationID]));\r
1402                 ZeroMemory(m_bAtIbeamCursorOnly[nApplicationID], sizeof(m_bAtIbeamCursorOnly[nApplicationID]));\r
1403                 m_nKillRingMax[nApplicationID] = 0;\r
1404                 m_bUseDialogSetting[nApplicationID] = FALSE;\r
1405                 m_nSettingStyle[nApplicationID] = 0;\r
1406         } else {\r
1407                 ASSERT(0);\r
1408         }\r
1409 }\r
1410 \r
1411 void CXkeymacsData::SetApplicationTitle(LPCTSTR lpszApplicationTitle)\r
1412 {\r
1413         m_strApplicationTitle.Format(lpszApplicationTitle);\r
1414 \r
1415         // delete white space at the end of the application title.\r
1416         while (!m_strApplicationTitle.IsEmpty()\r
1417                 && _istspace(m_strApplicationTitle.GetAt(m_strApplicationTitle.GetLength() - 1))) {\r
1418                 m_strApplicationTitle.Delete(m_strApplicationTitle.GetLength() - 1);\r
1419         }\r
1420 }\r
1421 \r
1422 CString CXkeymacsData::GetApplicationTitle()\r
1423 {\r
1424         return m_strApplicationTitle;\r
1425 }\r
1426 \r
1427 void CXkeymacsData::SetKillRingMax(int nKillRingMax)\r
1428 {\r
1429         m_nKillRingMax = nKillRingMax;\r
1430 }\r
1431 \r
1432 int CXkeymacsData::GetKillRingMax()\r
1433 {\r
1434         return m_nKillRingMax;\r
1435 }\r
1436 \r
1437 BOOL CXkeymacsDll::IsValidKey(BYTE bVk)\r
1438 {\r
1439         if (bVk == 0xf0) {      // 0xf0: Eisu key. GetAsyncKeyState returns the wrong state of Eisu key.\r
1440                 return FALSE;\r
1441         }\r
1442 \r
1443         switch (bVk) {\r
1444         case VK_CONTROL:\r
1445         case VK_MENU:\r
1446         case VK_SHIFT:\r
1447                 return FALSE;\r
1448         default:\r
1449                 break;\r
1450         }\r
1451 \r
1452         return TRUE;\r
1453 }\r
1454 \r
1455 BOOL CXkeymacsDll::IsDepressedModifier(int (__cdecl *Modifier)(void), BOOL bPhysicalKey)\r
1456 {\r
1457         BYTE bVk = 0;\r
1458         do {\r
1459                 if (IsValidKey(bVk)\r
1460                  && IsDown(bVk, bPhysicalKey)\r
1461                  && Commands[m_nCommandID[m_nApplicationID][NONE][bVk]].fCommand == Modifier) {\r
1462                         return TRUE;\r
1463                 }\r
1464         } while (++bVk);\r
1465         return FALSE;\r
1466 }\r
1467 \r
1468 BOOL CXkeymacsDll::IsDepressedShiftKeyOnly(BYTE nKey)\r
1469 {\r
1470         if (nKey != VK_SHIFT\r
1471          && nKey != VK_LSHIFT\r
1472          && nKey != VK_RSHIFT) {\r
1473                 return FALSE;\r
1474         }\r
1475 \r
1476         BYTE bVk = 0;\r
1477         do {\r
1478                 if (bVk == VK_SHIFT\r
1479                  || bVk == VK_LSHIFT\r
1480                  || bVk == VK_RSHIFT) {\r
1481                         continue;\r
1482                 }\r
1483 \r
1484                 if (IsDown(bVk)) {\r
1485                         return FALSE;\r
1486                 }\r
1487         } while (++bVk);\r
1488         return TRUE;\r
1489 }\r
1490 \r
1491 BOOL CXkeymacsDll::IsControl()\r
1492 {\r
1493         return CCommands::bC_() || IsDepressedModifier(CCommands::C_, FALSE);\r
1494 }\r
1495 \r
1496 BOOL CXkeymacsDll::IsMeta()\r
1497 {\r
1498         return CCommands::bM_() || IsDepressedModifier(CCommands::MetaAlt, FALSE);\r
1499 }\r
1500 \r
1501 void CXkeymacsDll::AddKillRing(BOOL bNewData)\r
1502 {\r
1503         if (m_nKillRingMax[m_nApplicationID] == 0) {\r
1504                 return;\r
1505         }\r
1506 \r
1507         CClipboardSnap *pSnap = new CClipboardSnap;\r
1508         if( !pSnap ) return;\r
1509 \r
1510         BOOL bCapture = pSnap->Capture();\r
1511         bCapture = pSnap->Capture();    // for "office drawing shape format". Can CClipboardSnap care this problem?\r
1512 \r
1513         if( bCapture ) {\r
1514                 if (bNewData) {\r
1515                         m_oKillRing.AddHead(pSnap);\r
1516                 } else {\r
1517                         if (m_oKillRing.IsEmpty()) {\r
1518                                 m_oKillRing.AddHead(pSnap);\r
1519                         } else {\r
1520                                 for (CClipboardSnap *pParent = m_oKillRing.GetHead(); pParent->GetNext(); pParent = pParent->GetNext()) {\r
1521                                         ;\r
1522                                 }\r
1523                                 pParent->SetNext(pSnap);\r
1524                         }\r
1525                 }\r
1526         } else {\r
1527                 delete pSnap;\r
1528                 pSnap = NULL;\r
1529         }\r
1530 \r
1531         m_nKillRing = 0;\r
1532 \r
1533         if (m_nKillRingMax[m_nApplicationID] < m_oKillRing.GetCount()) {\r
1534                 CClipboardSnap *pSnap = m_oKillRing.GetTail();\r
1535                 delete pSnap;\r
1536                 pSnap = NULL;\r
1537                 m_oKillRing.RemoveTail();\r
1538         }\r
1539 }\r
1540 \r
1541 // Return TRUE if there is another data\r
1542 // Return FALSE if there is no more data\r
1543 CClipboardSnap* CXkeymacsDll::GetKillRing(CClipboardSnap* pSnap, BOOL bForce)\r
1544 {\r
1545         if (m_nKillRingMax[m_nApplicationID] == 0) {\r
1546                 return NULL;\r
1547         }\r
1548 \r
1549         if (m_oKillRing.IsEmpty()) {\r
1550                 return NULL;\r
1551         }\r
1552 \r
1553         m_nKillRing %= m_oKillRing.GetCount();\r
1554 \r
1555         if (!bForce) {\r
1556                 CClipboardSnap oCurrentSnap;\r
1557                 oCurrentSnap.Capture();\r
1558 \r
1559                 CClipboardSnap *pKillRing = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1560                 if (!pKillRing) {\r
1561                         return NULL;\r
1562                 }\r
1563                 for (; pKillRing->GetNext(); pKillRing = pKillRing->GetNext()) {\r
1564                         ;\r
1565                 }\r
1566                 if (*pKillRing != oCurrentSnap) {\r
1567                         return NULL;\r
1568                 }\r
1569         }\r
1570 \r
1571         if (!pSnap) {\r
1572                 pSnap = m_oKillRing.GetAt(m_oKillRing.FindIndex(m_nKillRing));\r
1573         }\r
1574         pSnap->Restore();\r
1575 \r
1576         return pSnap->GetNext();\r
1577 }\r
1578 \r
1579 void CXkeymacsDll::Original(int nCommandType, BYTE bVk, int nOriginal)\r
1580 {\r
1581         nCommandType &= ~SHIFT;\r
1582 \r
1583         switch (bVk) {\r
1584         case VK_CONTROL:\r
1585                 bVk = VK_LCONTROL;\r
1586                 break;\r
1587         case VK_MENU:\r
1588                 bVk = VK_LMENU;\r
1589                 break;\r
1590         case VK_SHIFT:\r
1591                 bVk = VK_LSHIFT;\r
1592                 break;\r
1593         default:\r
1594                 break;\r
1595         }\r
1596 \r
1597         m_nOriginal[nCommandType][bVk] += nOriginal;\r
1598 }\r
1599 \r
1600 int CXkeymacsDll::Original(int nCommandType, BYTE bVk)\r
1601 {\r
1602         nCommandType &= ~SHIFT;\r
1603 \r
1604         switch (bVk) {\r
1605         case VK_CONTROL:\r
1606                 bVk = VK_LCONTROL;\r
1607                 break;\r
1608         case VK_MENU:\r
1609                 bVk = VK_LMENU;\r
1610                 break;\r
1611         case VK_SHIFT:\r
1612                 bVk = VK_LSHIFT;\r
1613                 break;\r
1614         default:\r
1615                 break;\r
1616         }\r
1617 \r
1618         return m_nOriginal[nCommandType][bVk];\r
1619 }\r
1620 \r
1621 void CXkeymacsDll::IncreaseKillRingIndex(int nKillRing)\r
1622 {\r
1623         m_nKillRing += nKillRing;\r
1624 }\r
1625 \r
1626 // nobody use\r
1627 int CXkeymacsDll::GetMickey(int nDifferential, int nThreshold1, int nThreshold2, int nAcceleration, int nSpeed)\r
1628 {\r
1629         nDifferential = nDifferential * 10 / nSpeed;\r
1630 \r
1631         switch (nAcceleration) {\r
1632         case 2:\r
1633                 if (nThreshold2 < fabs((double)(nDifferential / 4))) {\r
1634                         nDifferential /= 4;\r
1635                         break;\r
1636                 }\r
1637                 // Do NOT write break; here.\r
1638         case 1:\r
1639                 if (nThreshold1 < fabs((double)(nDifferential / 2))) {\r
1640                         nDifferential /= 2;\r
1641                 }\r
1642                 break;\r
1643         case 0:\r
1644                 break;\r
1645         default:\r
1646                 ASSERT(0);\r
1647                 break;\r
1648         }\r
1649 \r
1650         return nDifferential;\r
1651 }\r
1652 \r
1653 \r
1654 int CXkeymacsData::GetSettingStyle()\r
1655 {\r
1656         return m_nSettingStyle;\r
1657 }\r
1658 \r
1659 void CXkeymacsData::SetSettingStyle(int nSettingStyle)\r
1660 {\r
1661         m_nSettingStyle = nSettingStyle;\r
1662 }\r
1663 \r
1664 void CXkeymacsDll::SetSettingStyle(int nApplicationID, int nSettingStyle)\r
1665 {\r
1666         m_nSettingStyle[nApplicationID] = nSettingStyle;\r
1667 }\r
1668 \r
1669 void CXkeymacsData::SetIgnoreUndefinedMetaCtrl(BOOL bIgnoreUndefinedMetaCtrl)\r
1670 {\r
1671         m_bIgnoreUndefinedMetaCtrl = bIgnoreUndefinedMetaCtrl;\r
1672 }\r
1673 \r
1674 BOOL CXkeymacsData::GetIgnoreUndefinedMetaCtrl()\r
1675 {\r
1676         return m_bIgnoreUndefinedMetaCtrl;\r
1677 }\r
1678 \r
1679 void CXkeymacsDll::SetIgnoreUndefinedMetaCtrl(int nApplicationID, BOOL bIgnoreUndefinedMetaCtrl)\r
1680 {\r
1681         m_bIgnoreUndefinedMetaCtrl[nApplicationID] = bIgnoreUndefinedMetaCtrl;\r
1682 }\r
1683 \r
1684 void CXkeymacsData::SetIgnoreUndefinedC_x(BOOL bIgnoreUndefinedC_x)\r
1685 {\r
1686         m_bIgnoreUndefinedC_x = bIgnoreUndefinedC_x;\r
1687 }\r
1688 \r
1689 BOOL CXkeymacsData::GetIgnoreUndefinedC_x()\r
1690 {\r
1691         return m_bIgnoreUndefinedC_x;\r
1692 }\r
1693 \r
1694 void CXkeymacsDll::SetIgnoreUndefinedC_x(int nApplicationID, BOOL bIgnoreUndefinedC_x)\r
1695 {\r
1696         m_bIgnoreUndefinedC_x[nApplicationID] = bIgnoreUndefinedC_x;\r
1697 }\r
1698 \r
1699 void CXkeymacsData::SetEnableCUA(BOOL bEnableCUA)\r
1700 {\r
1701         m_bEnableCUA = bEnableCUA;\r
1702 }\r
1703 \r
1704 BOOL CXkeymacsData::GetEnableCUA()\r
1705 {\r
1706         return m_bEnableCUA;\r
1707 }\r
1708 \r
1709 void CXkeymacsDll::SetEnableCUA(int nApplicationID, BOOL bEnableCUA)\r
1710 {\r
1711         m_bEnableCUA[nApplicationID] = bEnableCUA;\r
1712 }\r
1713 \r
1714 BOOL CXkeymacsDll::GetEnableCUA()\r
1715 {\r
1716         return m_bEnableCUA[m_nApplicationID];\r
1717 }\r
1718 \r
1719 void CXkeymacsData::SetUseDialogSetting(BOOL bUseDialogSetting)\r
1720 {\r
1721         m_bUseDialogSetting = bUseDialogSetting;\r
1722 }\r
1723 \r
1724 BOOL CXkeymacsData::GetUseDialogSetting()\r
1725 {\r
1726         return m_bUseDialogSetting;\r
1727 }\r
1728 \r
1729 void CXkeymacsDll::DefiningMacro(BOOL bDefiningMacro)\r
1730 {\r
1731         m_bDefiningMacro = bDefiningMacro;\r
1732 \r
1733         if (bDefiningMacro) {   // start-kbd-macro\r
1734                 if (CCommands::bC_u()) {\r
1735                         ReleaseKey(VK_SHIFT);\r
1736                         CallMacro();\r
1737                 }\r
1738         } else {                                // end-kbd-macro\r
1739                 while (!m_Macro.IsEmpty()) {\r
1740                         KbdMacro *pKbdMacro = (KbdMacro *)m_Macro.GetTail();\r
1741                         if (pKbdMacro->lParam & BEING_RELEASED) {\r
1742                                 break;\r
1743                         } else {\r
1744                                 m_Macro.RemoveTail();\r
1745                                 delete pKbdMacro;\r
1746                                 pKbdMacro = NULL;\r
1747                         }\r
1748                 }\r
1749 \r
1750 //              CUtils::Log(_T("Macro MemMap: start"));\r
1751                 if (!m_Macro.IsEmpty()) {\r
1752                         static HANDLE hMacro = NULL;\r
1753                         if (!hMacro) {\r
1754                                 hMacro = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 0x3000, _T("macro"));\r
1755                         }\r
1756                         if (hMacro) {\r
1757 //                              CUtils::Log(_T("Macro MemMap: 1"));\r
1758                                 PVOID pView = MapViewOfFile(hMacro, FILE_MAP_ALL_ACCESS, 0, 0, 0);\r
1759 //                              CUtils::Log(_T("Macro MemMap: 2"));\r
1760                                 if (pView) {\r
1761 //                                      CUtils::Log(_T("Macro MemMap: 2.5"));\r
1762                                         for (int i = 0; i < m_Macro.GetCount(); ++i) {\r
1763 //                                              CUtils::Log(_T("Macro MemMap: 3-1 %d"), i);\r
1764                                                 KbdMacro *pKbdMacro = (KbdMacro *)m_Macro.GetAt(m_Macro.FindIndex(i));\r
1765 //                                              CUtils::Log(_T("Macro MemMap: 3-2 %d"), i);\r
1766                                                 memcpy((LPTSTR) pView + i * sizeof(KbdMacro), pKbdMacro, sizeof(KbdMacro));\r
1767 //                                              CUtils::Log(_T("Macro MemMap: 3-3 %d"), i);\r
1768                                         }\r
1769 //                                      CUtils::Log(_T("Macro MemMap: 4"));\r
1770                                         UnmapViewOfFile(pView);\r
1771 //                                      CUtils::Log(_T("Macro MemMap: 5"));\r
1772                                 } else {\r
1773 //                                      CUtils::Log(_T("Macro MemMpa: error: %d"), GetLastError());\r
1774                                 }\r
1775                         } else {\r
1776 //                              CUtils::Log(_T("Macro MemMap: 6"));\r
1777                                 ASSERT(0);\r
1778                         }\r
1779                 }\r
1780         }\r
1781 }\r
1782 \r
1783 BOOL CXkeymacsDll::DefiningMacro()\r
1784 {\r
1785         return m_bDefiningMacro;\r
1786 }\r
1787 \r
1788 /**/ \r
1789 void CXkeymacsDll::CallMacro()\r
1790 {\r
1791         BOOL bIsCtrlDown = IsDown(VK_CONTROL);\r
1792         if (bIsCtrlDown) {\r
1793                 ReleaseKey(VK_CONTROL);\r
1794         }\r
1795         BOOL bIsAltDown = IsDown(VK_MENU);\r
1796         if (bIsAltDown) {\r
1797                 ReleaseKey(VK_MENU);\r
1798         }\r
1799         BOOL bIsShiftDown = IsDown(VK_SHIFT);\r
1800         if (bIsShiftDown) {\r
1801                 ReleaseKey(VK_SHIFT);\r
1802         }\r
1803 \r
1804         for (POSITION pos = m_Macro.GetHeadPosition(); pos; ) {\r
1805                 KbdMacro *pKbdMacro = (KbdMacro *)m_Macro.GetNext(pos);\r
1806                 if (pKbdMacro->lParam & BEING_RELEASED) {\r
1807                         ReleaseKey((BYTE)pKbdMacro->wParam);\r
1808                 } else {\r
1809                         DepressKey((BYTE)pKbdMacro->wParam, pKbdMacro->bOriginal);\r
1810                 }\r
1811         }\r
1812 \r
1813         if (bIsCtrlDown) {\r
1814                 DepressKey(VK_CONTROL);\r
1815         }\r
1816         if (bIsAltDown) {\r
1817                 DepressKey(VK_MENU);\r
1818         }\r
1819         if (bIsShiftDown) {\r
1820                 DepressKey(VK_SHIFT);\r
1821         }\r
1822 }\r
1823 \r
1824 /*\r
1825 void CXkeymacsDll::CallMacro()  // for debug\r
1826 {\r
1827         CString sz;\r
1828         for (POSITION pos = m_Macro.GetHeadPosition(); pos; ) {\r
1829                 KbdMacro_t *pKbdMacro = (KbdMacro_t *)m_Macro.GetNext(pos);\r
1830                 if (pKbdMacro->lParam & BEING_RELEASED) {\r
1831                         CString t;\r
1832                         t.Format(_T("0x%xu "), pKbdMacro->wParam);\r
1833                         sz += t;\r
1834                 } else {\r
1835                         CString t;\r
1836                         t.Format(_T("0x%xd "), pKbdMacro->wParam);\r
1837                         sz += t;\r
1838                 }\r
1839         }\r
1840 //      CUtils::Log(sz);\r
1841 }\r
1842 */\r
1843 \r
1844 void CXkeymacsDll::Set106Keyboard(BOOL b106Keyboard)\r
1845 {\r
1846         m_b106Keyboard = b106Keyboard;\r
1847 }\r
1848 \r
1849 BOOL CXkeymacsDll::Is106Keyboard()\r
1850 {\r
1851         return m_b106Keyboard;\r
1852 }\r
1853 \r
1854 int CXkeymacsDll::IsPassThrough(BYTE nKey)\r
1855 {\r
1856         BYTE bVk = 0;\r
1857         do {\r
1858                 if (IsDown(bVk)\r
1859                  && (Commands[m_nCommandID[m_nApplicationID][NONE][bVk]].fCommand == CCommands::PassThrough)) {\r
1860                         if (bVk == nKey) {\r
1861                                 return GOTO_HOOK;\r
1862                         }\r
1863 \r
1864                         return GOTO_DO_NOTHING;\r
1865                 }\r
1866         } while (++bVk);\r
1867         return CONTINUE;\r
1868 }\r
1869 \r
1870 void CXkeymacsDll::SetKeyboardHookFlag()\r
1871 {\r
1872         SetKeyboardHookFlag(m_bHook);\r
1873 }\r
1874 \r
1875 void CXkeymacsDll::SetFunctionKey(int nFunctionID, int nApplicationID, int nCommandType, int nKey)\r
1876 {\r
1877         if (nApplicationID      < 0 || MAX_APP                  <= nApplicationID\r
1878          || nCommandType        < 0 || MAX_COMMAND_TYPE <= nCommandType\r
1879          || nKey                        < 0 || MAX_KEY                  <= nKey) {\r
1880                 return;\r
1881         }\r
1882 \r
1883         m_nFunctionID[nApplicationID][nCommandType][nKey] = nFunctionID;\r
1884 }\r
1885 \r
1886 void CXkeymacsDll::ClearFunctionDefinition()\r
1887 {\r
1888         memset(m_nFunctionID, -1, sizeof(m_nFunctionID));\r
1889         memset(m_szFunctionDefinition, 0, sizeof(m_szFunctionDefinition));\r
1890 }\r
1891 \r
1892 void CXkeymacsDll::SetFunctionDefinition(int nFunctionID, CString szDefinition)\r
1893 {\r
1894         if (nFunctionID < 0 || MAX_FUNCTION <= nFunctionID) {\r
1895                 return;\r
1896         }\r
1897 \r
1898         memset(m_szFunctionDefinition[nFunctionID], 0, sizeof(m_szFunctionDefinition[nFunctionID]));\r
1899         _stprintf(m_szFunctionDefinition[nFunctionID], _T("%s"), szDefinition);\r
1900 \r
1901         return;\r
1902 \r
1903 }\r
1904 \r
1905 // call an original command which is defined in dot.xkeymacs\r
1906 void CXkeymacsDll::CallFunction(int nFunctionID)\r
1907 {\r
1908         CArray<KeyBind, KeyBind> keybinds;\r
1909 \r
1910         if (nFunctionID < 0 || MAX_FUNCTION <= nFunctionID || !_tcslen(m_szFunctionDefinition[nFunctionID])) {\r
1911                 return;\r
1912         }\r
1913 \r
1914         BOOL bIsCtrlDown = CXkeymacsDll::IsDown(VK_CONTROL);\r
1915         BOOL bIsAltDown = CXkeymacsDll::IsDown(VK_MENU);\r
1916         BOOL bIsShiftDown = CXkeymacsDll::IsDown(VK_SHIFT);\r
1917 \r
1918         if (m_szFunctionDefinition[nFunctionID][0] == _T('"') && m_szFunctionDefinition[nFunctionID][_tcslen(m_szFunctionDefinition[nFunctionID]) - 1] == _T('"')) {\r
1919                 for (unsigned int i = 1; i < _tcslen(m_szFunctionDefinition[nFunctionID]) - 1; ++i) {   // skip '"'\r
1920                         keybinds.Add(ParseKey(nFunctionID, i));\r
1921                 }\r
1922         } else if (m_szFunctionDefinition[nFunctionID][0] == _T('[') && m_szFunctionDefinition[nFunctionID][_tcslen(m_szFunctionDefinition[nFunctionID]) - 1] == _T(']')) {\r
1923                 for (unsigned int i = 1; i < _tcslen(m_szFunctionDefinition[nFunctionID]) - 1; ++i) {   // skip '[' and ']'\r
1924                         if (m_szFunctionDefinition[nFunctionID][i] == _T('?')) {        // [?f ?o ?o]\r
1925                                 ++i;\r
1926                                 keybinds.Add(ParseKey(nFunctionID, i));\r
1927                         } else {                                                                                                // [ControlCharacter]\r
1928                                 for (int nKeyID = 0; nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0]); ++nKeyID) {\r
1929                                         if (!_tcsncmp(m_szFunctionDefinition[nFunctionID] + i, ControlCharacters[nKeyID].name, _tcslen(ControlCharacters[nKeyID].name))) {\r
1930                                                 KeyBind keybind = {NONE, ControlCharacters[nKeyID].bVk};\r
1931                                                 keybinds.Add(keybind);\r
1932                                                 i += _tcslen(ControlCharacters[nKeyID].name);\r
1933                                                 break;\r
1934                                         }\r
1935                                 }\r
1936                         }\r
1937                 }\r
1938         } else {\r
1939                 return;\r
1940         }\r
1941 \r
1942         BOOL bM_x = FALSE;\r
1943         TCHAR szPath[MAX_PATH] = {'\0'};\r
1944         unsigned int index = 0;\r
1945         BOOL bInitialized = FALSE;\r
1946 \r
1947         for (int i = 0; i < keybinds.GetSize(); ++i) {\r
1948                 const int nCommandType = keybinds.GetAt(i).nCommandType;\r
1949                 const BYTE bVk = keybinds.GetAt(i).bVk;\r
1950 \r
1951                 if (nCommandType < MAX_COMMAND_TYPE && Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand) {\r
1952                         if (Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand == CCommands::ExecuteExtendedCommand) {\r
1953                                 bM_x = TRUE;\r
1954                         } else if (!bInitialized) {\r
1955                                 if (bIsCtrlDown) {\r
1956                                         CUtils::UpdateKeyboardState(VK_CONTROL, 0);\r
1957                                         ReleaseKey(VK_CONTROL);\r
1958                                 }\r
1959 \r
1960                                 if (bIsAltDown) {\r
1961                                         ReleaseKey(VK_MENU);\r
1962                                 }\r
1963 \r
1964                                 if (bIsShiftDown) {\r
1965                                         ReleaseKey(VK_SHIFT);\r
1966                                 }\r
1967 \r
1968                                 bInitialized = TRUE;\r
1969                         }\r
1970 //                      CUtils::Log("CallFunction: Command Name: %s", Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].szCommandName);\r
1971                         while (Commands[m_nCommandID[m_nApplicationID][nCommandType][bVk]].fCommand() == GOTO_RECURSIVE) {\r
1972                                 ;\r
1973                         }\r
1974                 } else if (bM_x) {\r
1975                         if (bVk == VK_RETURN) {\r
1976                                 InvokeM_x(szPath);\r
1977                         } else {\r
1978                                 for (TCHAR nAscii = 1; nAscii != 0; ++nAscii) { // repeat until overflow\r
1979                                         if (bVk != 0 && a2v(nAscii) == bVk && ((nCommandType & SHIFT) != 0) == IsShift(nAscii)) {\r
1980 //                                              CUtils::Log("M-x: %#X (%c), %#X (%c)", bVk, bVk, nAscii, nAscii);\r
1981                                                 szPath[index++] = nAscii;\r
1982                                                 break;\r
1983                                         }\r
1984                                 }\r
1985                         }\r
1986                 } else {\r
1987                         if (!bInitialized) {\r
1988                                 if (bIsCtrlDown) {\r
1989                                         CUtils::UpdateKeyboardState(VK_CONTROL, 0);\r
1990                                         ReleaseKey(VK_CONTROL);\r
1991                                 }\r
1992 \r
1993                                 if (bIsAltDown) {\r
1994                                         ReleaseKey(VK_MENU);\r
1995                                 }\r
1996 \r
1997                                 if (bIsShiftDown) {\r
1998                                         ReleaseKey(VK_SHIFT);\r
1999                                 }\r
2000 \r
2001                                 bInitialized = TRUE;\r
2002                         }\r
2003                         if (nCommandType & WIN_WIN) {\r
2004                                 DepressKey(VK_LWIN);\r
2005                         }\r
2006                         if (nCommandType & WIN_CTRL) {\r
2007                                 DepressKey(VK_CONTROL);\r
2008                         }\r
2009                         if (nCommandType & WIN_ALT) {\r
2010                                 DepressKey(VK_MENU);\r
2011                         }\r
2012                         if (nCommandType & SHIFT) {\r
2013                                 DepressKey(VK_SHIFT);\r
2014                         }\r
2015 \r
2016                         Kdu(bVk);\r
2017 \r
2018                         if (nCommandType & SHIFT && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & SHIFT))) {\r
2019                                 ReleaseKey(VK_SHIFT);\r
2020                         }\r
2021                         if (nCommandType & WIN_ALT && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_ALT))) {\r
2022                                 ReleaseKey(VK_MENU);\r
2023                         }\r
2024                         if (nCommandType & WIN_CTRL && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_CTRL))) {\r
2025                                 ReleaseKey(VK_CONTROL);\r
2026                         }\r
2027                         if (nCommandType & WIN_WIN && (keybinds.GetSize() <= i + 1 || !(keybinds.GetAt(i + 1).nCommandType & WIN_WIN))) {\r
2028                                 ReleaseKey(VK_LWIN);\r
2029                         }\r
2030                 }\r
2031         }\r
2032 \r
2033         keybinds.RemoveAll();\r
2034 \r
2035         if (bInitialized) {\r
2036                 // If these lines are invoked at M-x, a window transition does not work well.\r
2037 \r
2038                 if (bIsShiftDown) {\r
2039                         DepressKey(VK_SHIFT);\r
2040                 }\r
2041 \r
2042                 if (bIsAltDown) {\r
2043                         DepressKey(VK_MENU);\r
2044                 }\r
2045 \r
2046                 if (bIsCtrlDown) {\r
2047                         DepressKey(VK_CONTROL);\r
2048                         CUtils::UpdateKeyboardState(VK_CONTROL, 1);\r
2049                 }\r
2050         }\r
2051         return;\r
2052 }\r
2053 \r
2054 KeyBind CXkeymacsDll::ParseKey(const int nFunctionID, unsigned int &i)\r
2055 {\r
2056         KeyBind keybind = {NONE};\r
2057 \r
2058         if (m_szFunctionDefinition[nFunctionID][i] == _T('\\')) {\r
2059                 ++i;\r
2060                 BOOL bFound = FALSE;\r
2061                 do {\r
2062                         bFound = FALSE;\r
2063                         for (int ModifierID = 0; ModifierID < sizeof(Modifiers) / sizeof(Modifiers[0]); ++ModifierID) {\r
2064                                 if (!_tcsncmp(m_szFunctionDefinition[nFunctionID] + i, Modifiers[ModifierID].name, _tcslen(Modifiers[ModifierID].name))\r
2065                                  && _tcslen(Modifiers[ModifierID].name) < _tcslen(m_szFunctionDefinition[nFunctionID] + i)) {\r
2066                                         keybind.nCommandType |= Modifiers[ModifierID].id;\r
2067                                         i+= _tcslen(Modifiers[ModifierID].name);\r
2068                                         bFound = TRUE;\r
2069                                 }\r
2070                         }\r
2071                 } while (bFound);\r
2072         }\r
2073         if (IsShift(m_szFunctionDefinition[nFunctionID][i]) && !(keybind.nCommandType & (WIN_CTRL | WIN_ALT | WIN_WIN))) {\r
2074                 keybind.nCommandType |= SHIFT;\r
2075         }\r
2076 \r
2077         for (int nKeyID = 0; nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0]); ++nKeyID) {\r
2078                 if (!_tcsncmp(m_szFunctionDefinition[nFunctionID] + i, ControlCharacters[nKeyID].name, _tcslen(ControlCharacters[nKeyID].name))) {\r
2079                         i += _tcslen(ControlCharacters[nKeyID].name);\r
2080                         break;\r
2081                 }\r
2082         }\r
2083         if (nKeyID < sizeof(ControlCharacters) / sizeof(ControlCharacters[0])) {\r
2084                 keybind.bVk = ControlCharacters[nKeyID].bVk;\r
2085         } else {\r
2086                 keybind.bVk = a2v(m_szFunctionDefinition[nFunctionID][i]);\r
2087         }\r
2088 \r
2089         return keybind;\r
2090 }\r
2091 \r
2092 BOOL CXkeymacsDll::IsShift(TCHAR nAscii)\r
2093 {\r
2094         switch (nAscii) {\r
2095         case _T(' '):\r
2096                 return FALSE;\r
2097         case _T('!'):\r
2098         case _T('"'):\r
2099         case _T('#'):\r
2100         case _T('$'):\r
2101         case _T('%'):\r
2102         case _T('&'):\r
2103                 return TRUE;\r
2104         case _T('\''):\r
2105                 return m_b106Keyboard;\r
2106         case _T('('):\r
2107         case _T(')'):\r
2108         case _T('*'):\r
2109         case _T('+'):\r
2110                 return TRUE;\r
2111         case _T(','):\r
2112         case _T('-'):\r
2113         case _T('.'):\r
2114         case _T('/'):\r
2115         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
2116                 return FALSE;\r
2117         case _T(':'):\r
2118                 return !m_b106Keyboard;\r
2119         case _T(';'):\r
2120                 return FALSE;\r
2121         case _T('<'):\r
2122                 return TRUE;\r
2123         case _T('='):\r
2124                 return m_b106Keyboard;\r
2125         case _T('>'):\r
2126         case _T('?'):\r
2127                 return TRUE;\r
2128         case _T('@'):\r
2129                 return !m_b106Keyboard;\r
2130         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
2131         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
2132         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
2133                 return TRUE;\r
2134         case _T('['):\r
2135         case _T('\\'):\r
2136         case _T(']'):\r
2137                 return FALSE;\r
2138         case _T('^'):\r
2139                 return !m_b106Keyboard;\r
2140         case _T('_'):\r
2141                 return TRUE;\r
2142         case _T('`'):\r
2143                 return m_b106Keyboard;\r
2144         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
2145         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
2146         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
2147                 return FALSE;\r
2148         case _T('{'):\r
2149         case _T('|'):\r
2150         case _T('}'):\r
2151         case _T('~'):\r
2152                 return TRUE;\r
2153         default:\r
2154                 return FALSE;\r
2155         }\r
2156 }\r
2157 \r
2158 BYTE CXkeymacsDll::a2v(TCHAR nAscii)\r
2159 {\r
2160         switch (nAscii) {\r
2161         case _T(' '):\r
2162                 return VK_SPACE;\r
2163         case _T('!'):\r
2164                 return '1';\r
2165         case _T('"'):\r
2166                 return m_b106Keyboard ? '2' : (BYTE) 0xde;      // VK_OEM_7\r
2167         case _T('#'):\r
2168                 return '3';\r
2169         case _T('$'):\r
2170                 return '4';\r
2171         case _T('%'):\r
2172                 return '5';\r
2173         case _T('&'):\r
2174                 return m_b106Keyboard ? '6' : '7';\r
2175         case _T('\''):\r
2176                 return m_b106Keyboard ? '7' : (BYTE) 0xde;      // VK_OEM_7\r
2177         case _T('('):\r
2178                 return m_b106Keyboard ? '8' : '9';\r
2179         case _T(')'):\r
2180                 return m_b106Keyboard ? '9' : '0';\r
2181         case _T('*'):\r
2182                 return m_b106Keyboard ? (BYTE) 0xba : '8';      // VK_OEM_1\r
2183         case _T('+'):\r
2184                 return 0xbb;    // VK_OEM_PLUS\r
2185         case _T(','):\r
2186                 return 0xbc;    // VK_OEM_COMMA\r
2187         case _T('-'):\r
2188                 return 0xbd;    // VK_OEM_MINUS\r
2189         case _T('.'):\r
2190                 return 0xbe;    // VK_OEM_PERIOD\r
2191         case _T('/'):\r
2192                 return 0xbf;    // VK_OEM_2\r
2193         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
2194                 return nAscii;\r
2195         case _T(':'):\r
2196                 return 0xba;    // VK_OEM_1\r
2197         case _T(';'):\r
2198                 return m_b106Keyboard ? (BYTE) 0xbb : (BYTE) 0xba;      // VK_OEM_PLUS  VK_OEM_1\r
2199         case _T('<'):\r
2200                 return 0xbc;    // VK_OEM_COMMA\r
2201         case _T('='):\r
2202                 return m_b106Keyboard ? (BYTE) 0xbd : (BYTE) 0xbb;      // VK_OEM_MINUS VK_OEM_PLUS\r
2203         case _T('>'):\r
2204                 return 0xbe;    // VK_OEM_PERIOD\r
2205         case _T('?'):\r
2206                 return 0xbf;    // VK_OEM_2\r
2207         case _T('@'):\r
2208                 return m_b106Keyboard ? (BYTE) 0xc0 : '2';\r
2209         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
2210         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
2211         case _T('U'): case _T('V'): case _T('W'): case _T('X'): case _T('Y'): case _T('Z'): \r
2212                 return nAscii;\r
2213         case _T('['):\r
2214                 return 0xdb;    // VK_OEM_4\r
2215         case _T('\\'):\r
2216                 return 0xdc;    // VK_OEM_5\r
2217         case _T(']'):\r
2218                 return 0xdd;    // VK_OEM_6\r
2219         case _T('^'):\r
2220                 return m_b106Keyboard ? (BYTE) 0xde : '6';      // VK_OEM_7\r
2221         case _T('_'):\r
2222                 return m_b106Keyboard ? (BYTE) 0xe2 : (BYTE) 0xbd;      // VK_OEM_102   VK_OEM_MINUS\r
2223         case _T('`'):\r
2224                 return 0xc0;    // VK_OEM_3\r
2225         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
2226         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
2227         case _T('u'): case _T('v'): case _T('w'): case _T('x'): case _T('y'): case _T('z'): \r
2228                 return (BYTE) (nAscii - (_T('a') - _T('A')));\r
2229         case _T('{'):\r
2230                 return 0xdb;    // VK_OEM_4\r
2231         case _T('|'):\r
2232                 return 0xdc;    // VK_OEM_5\r
2233         case _T('}'):\r
2234                 return 0xdd;    // VK_OEM_6\r
2235         case _T('~'):\r
2236                 return m_b106Keyboard ? (BYTE) 0xde : (BYTE) 0xc0;      // VK_OEM_7     VK_OEM_3\r
2237         default:\r
2238                 return 0;\r
2239         }\r
2240 }\r
2241 \r
2242 void CXkeymacsDll::DeleteAllShell_NotifyIcon()\r
2243 {\r
2244         for (int icon = 0; icon < MAX_ICON_TYPE; ++icon) {\r
2245                 DeleteShell_NotifyIcon((ICON_TYPE)icon);\r
2246         }\r
2247 }\r
2248 \r
2249 void CXkeymacsDll::AddAllShell_NotifyIcon()\r
2250 {\r
2251         for (int icon = 0; icon < MAX_ICON_TYPE; ++icon) {\r
2252                 AddShell_NotifyIcon((ICON_TYPE)icon);\r
2253         }\r
2254 }\r
2255 \r
2256 void CXkeymacsData::SetWindowText(LPCTSTR lpszWindowText)\r
2257 {\r
2258         m_nWindowTextType = CUtils::GetWindowTextType(lpszWindowText);\r
2259         if (m_nWindowTextType == IDS_WINDOW_TEXT_IGNORE) {\r
2260                 m_strWindowText = _T('*');\r
2261         } else {\r
2262                 m_strWindowText.Format(lpszWindowText);\r
2263         }\r
2264 }\r
2265 \r
2266 CString CXkeymacsData::GetWindowText()\r
2267 {\r
2268         return m_strWindowText;\r
2269 }\r
2270 \r
2271 void CXkeymacsData::SetWindowTextType(int nWindowTextType)\r
2272 {\r
2273         m_nWindowTextType = nWindowTextType;\r
2274 }\r
2275 \r
2276 int CXkeymacsData::GetWindowTextType()\r
2277 {\r
2278         return m_nWindowTextType;\r
2279 }\r
2280 \r
2281 BOOL CXkeymacsDll::IsMatchWindowText(CString szWindowText)\r
2282 {\r
2283         BOOL bIsMatchWindowText = TRUE;\r
2284 \r
2285         TCHAR szCurrentWindowText[0x100] = {'\0'};\r
2286         GetWindowText(GetForegroundWindow(), szCurrentWindowText, sizeof(szCurrentWindowText));\r
2287 \r
2288         switch (CUtils::GetWindowTextType(szWindowText)) {\r
2289         case IDS_WINDOW_TEXT_MATCH:                                                             // *foo*\r
2290                 szWindowText.Delete(0);                                                         // Delete first '*'\r
2291                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
2292                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText);\r
2293                 break;\r
2294         case IDS_WINDOW_TEXT_MATCH_FORWARD:                                             // foo*\r
2295                 szWindowText.Delete(szWindowText.GetLength() - 1);      // Delete last '*'\r
2296                 bIsMatchWindowText = 0 == CString(szCurrentWindowText).Find(szWindowText);\r
2297                 break;\r
2298         case IDS_WINDOW_TEXT_MATCH_BACKWARD:                                    // *foo\r
2299                 szWindowText.Delete(0);                                                         // Delete first '*'\r
2300                 bIsMatchWindowText = 0 <= CString(szCurrentWindowText).Find(szWindowText, CString(szCurrentWindowText).GetLength() - szWindowText.GetLength());\r
2301                 break;\r
2302         case IDS_WINDOW_TEXT_MATCH_FULL:                                                // foo\r
2303                 bIsMatchWindowText = szWindowText == CString(szCurrentWindowText);\r
2304                 break;\r
2305         case IDS_WINDOW_TEXT_IGNORE:                                                    // *\r
2306                 bIsMatchWindowText = TRUE;\r
2307                 break;\r
2308         default:\r
2309                 ASSERT(0);\r
2310                 break;\r
2311         }\r
2312 \r
2313 //      CUtils::Log(_T("IsMatchWindowText: %d, _%s_, _%s_"), bIsMatchWindowText, szCurrentWindowText, szWindowText);\r
2314         return bIsMatchWindowText;\r
2315 }\r
2316 \r
2317 void CXkeymacsDll::SetAccelerate(int nAccelerate)\r
2318 {\r
2319         m_nAccelerate = nAccelerate;\r
2320 }\r
2321 \r
2322 int CXkeymacsDll::GetAccelerate()\r
2323 {\r
2324         return m_nAccelerate;\r
2325 }\r
2326 \r
2327 void CXkeymacsDll::SetKeyboardSpeed(int nKeyboardSpeed)\r
2328 {\r
2329         m_nKeyboardSpeed = nKeyboardSpeed;\r
2330 }\r
2331 \r
2332 unsigned int CXkeymacsDll::GetMaxKeyInterval()\r
2333 {\r
2334         // m_nKeyboardSpeed == 0:       slowest repeat rate; approximately  2 characters per second\r
2335         // m_nKeyboardSpeed == 31:      fastest repeat rate; approximately 30 characters per second\r
2336         // 47 ms is max on my machine w/ KeyboardSpeed 31.\r
2337         // 1000 /  2 + 50 = 550\r
2338         // 1000 / 30 + 50 = 83\r
2339         return (unsigned int) (1000.0 / (2.0 + m_nKeyboardSpeed % 32 * 28.0 / 31.0) + 50.0);\r
2340 }\r
2341 \r
2342 void CXkeymacsDll::SetCursorData(HCURSOR hEnable, HCURSOR hDisableTMP, HCURSOR hDisableWOCQ, HICON hDisable, BOOL bEnable)\r
2343 {\r
2344         m_hCursor[STATUS_ENABLE] = hEnable;\r
2345         m_hCursor[STATUS_DISABLE_TMP] = hDisableTMP;\r
2346         m_hCursor[STATUS_DISABLE_WOCQ] = hDisableWOCQ;\r
2347         m_hCursor[STATUS_DISABLE] = hDisable;\r
2348         m_bCursor = bEnable;\r
2349 }\r
2350 \r
2351 void CXkeymacsDll::DoSetCursor()\r
2352 {\r
2353         if (m_bCursor && m_hCurrentCursor) {\r
2354                 ::SetCursor(m_hCurrentCursor);\r
2355         }\r
2356 }\r
2357 \r
2358 BOOL CXkeymacsData::Get326Compatible()\r
2359 {\r
2360         return m_b326Compatible;\r
2361 }\r
2362 \r
2363 void CXkeymacsData::Set326Compatible(BOOL b326Compatible)\r
2364 {\r
2365         m_b326Compatible = b326Compatible;\r
2366 }\r
2367 \r
2368 void CXkeymacsDll::Set326Compatible(int nApplicationID, BOOL b326Compatible)\r
2369 {\r
2370         m_b326Compatible[nApplicationID] = b326Compatible;\r
2371 }\r
2372 \r
2373 BOOL CXkeymacsDll::Get326Compatible()\r
2374 {\r
2375         return m_b326Compatible[m_nApplicationID];\r
2376 }\r
2377 \r
2378 void CXkeymacsDll::InvokeM_x(const TCHAR *const szPath)\r
2379 {\r
2380 //      CUtils::Log("M-x: szPath=_%s_", szPath);\r
2381         int (*fCommand)() = NULL;\r
2382 \r
2383         for (int i = 0; i < MAX_COMMAND; ++i) {\r
2384                 if (_tcsicmp(szPath, Commands[i].szCommandName) == 0) {\r
2385                         fCommand = Commands[i].fCommand;\r
2386                         break;\r
2387                 }\r
2388         }\r
2389 \r
2390         if (fCommand) {\r
2391 //              CUtils::Log("M-x: Command: _%s_", Commands[i].szCommandName);\r
2392                 fCommand();\r
2393         } else {\r
2394 //              CUtils::Log("M-x: Path: _%s_", szPath);\r
2395                 ShellExecute(NULL, NULL, szPath, NULL, NULL, SW_SHOWNORMAL);\r
2396         }\r
2397 }\r
2398 \r
2399 void CXkeymacsDll::ModifyM_xTip(const TCHAR *const szPath)\r
2400 {\r
2401         if (szPath) {\r
2402                 if (_tcslen(szPath) < sizeof(m_stNtfyIcon[MX_ICON].szTip) / sizeof(m_stNtfyIcon[MX_ICON].szTip[0]) - 5) {\r
2403                         memset(m_stNtfyIcon[MX_ICON].szTip, 0, sizeof(m_stNtfyIcon[MX_ICON].szTip));\r
2404                         _stprintf(m_stNtfyIcon[MX_ICON].szTip, "M-x %s", szPath);\r
2405                 }\r
2406         } else {\r
2407                 memset(m_stNtfyIcon[MX_ICON].szTip, 0, sizeof(m_stNtfyIcon[MX_ICON].szTip));\r
2408                 _stprintf(m_stNtfyIcon[MX_ICON].szTip, "M-x LED");\r
2409         }\r
2410 \r
2411         ModifyShell_NotifyIcon(MX_ICON, CCommands::bM_x(), TRUE);\r
2412 }\r