OSDN Git Service

introduce pseudo key event "Drag",
[yamy/yamy.git] / hook.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
2 // hook.cpp\r
3 \r
4 \r
5 #define _HOOK_CPP\r
6 \r
7 #include "misc.h"\r
8 \r
9 #include "hook.h"\r
10 #include "stringtool.h"\r
11 \r
12 #include <locale.h>\r
13 #include <imm.h>\r
14 #include <richedit.h>\r
15 \r
16 \r
17 ///\r
18 #define HOOK_DATA_NAME _T("{08D6E55C-5103-4e00-8209-A1C4AB13BBEF}") _T(VERSION)\r
19 #ifdef _WIN64\r
20 #define HOOK_DATA_NAME_ARCH _T("{290C0D51-8AEE-403d-9172-E43D46270996}") _T(VERSION)\r
21 #else // !_WIN64\r
22 #define HOOK_DATA_NAME_ARCH _T("{716A5DEB-CB02-4438-ABC8-D00E48673E45}") _T(VERSION)\r
23 #endif // !_WIN64\r
24 \r
25 // Some applications use different values for below messages\r
26 // when double click of title bar.\r
27 #define SC_MAXIMIZE2 (SC_MAXIMIZE + 2)\r
28 #define SC_MINIMIZE2 (SC_MINIMIZE + 2)\r
29 #define SC_RESTORE2 (SC_RESTORE + 2)\r
30 \r
31 // Debug Macros\r
32 #ifdef NDEBUG\r
33 #define HOOK_RPT0(msg)\r
34 #define HOOK_RPT1(msg, arg1)\r
35 #define HOOK_RPT2(msg, arg1, arg2)\r
36 #define HOOK_RPT3(msg, arg1, arg2, arg3)\r
37 #define HOOK_RPT4(msg, arg1, arg2, arg3, arg4)\r
38 #define HOOK_RPT5(msg, arg1, arg2, arg3, arg4, arg5)\r
39 #else\r
40 #define HOOK_RPT0(msg) if (g.m_isLogging) { _RPT0(_CRT_WARN, msg); }\r
41 #define HOOK_RPT1(msg, arg1) if (g.m_isLogging) { _RPT1(_CRT_WARN, msg, arg1); }\r
42 #define HOOK_RPT2(msg, arg1, arg2) if (g.m_isLogging) { _RPT2(_CRT_WARN, msg, arg1, arg2); }\r
43 #define HOOK_RPT3(msg, arg1, arg2, arg3) if (g.m_isLogging) { _RPT3(_CRT_WARN, msg, arg1, arg2, arg3); }\r
44 #define HOOK_RPT4(msg, arg1, arg2, arg3, arg4) if (g.m_isLogging) { _RPT4(_CRT_WARN, msg, arg1, arg2, arg3, arg4); }\r
45 #define HOOK_RPT5(msg, arg1, arg2, arg3, arg4, arg5) if (g.m_isLogging) { _RPT5(_CRT_WARN, msg, arg1, arg2, arg3, arg4, arg5); }\r
46 #endif\r
47 \r
48 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
49 // Global Variables\r
50 \r
51 \r
52 DllExport HookData *g_hookData;                 ///\r
53 \r
54 ///\r
55 class HookDataArch\r
56 {\r
57 public:\r
58         HHOOK m_hHookGetMessage;                        ///\r
59         HHOOK m_hHookCallWndProc;                       ///\r
60 };\r
61 \r
62 static HookDataArch *s_hookDataArch;\r
63 \r
64 struct Globals {\r
65         HANDLE m_hHookData;                             ///\r
66         HANDLE m_hHookDataArch;                 ///\r
67         HWND m_hwndFocus;                               ///\r
68         HINSTANCE m_hInstDLL;                           ///\r
69         bool m_isInMenu;                                ///\r
70         UINT m_WM_MAYU_MESSAGE;                 ///\r
71         bool m_isImeLock;                               ///\r
72         bool m_isImeCompositioning;                     ///\r
73         HHOOK m_hHookMouseProc;                 ///\r
74 #ifdef NO_DRIVER\r
75         HHOOK m_hHookKeyboardProc;                      ///\r
76         INPUT_DETOUR m_keyboardDetour;\r
77         INPUT_DETOUR m_mouseDetour;\r
78         Engine *m_engine;\r
79 #endif // NO_DRIVER\r
80         DWORD m_hwndTaskTray;                           ///\r
81         HANDLE m_hMailslot;\r
82         bool m_isInitialized;\r
83 #ifndef NDEBUG\r
84         bool m_isLogging;\r
85         _TCHAR m_moduleName[GANA_MAX_PATH];\r
86 #endif // !NDEBUG\r
87 };\r
88 \r
89 static Globals g;\r
90 \r
91 \r
92 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
93 // Prototypes\r
94 \r
95 \r
96 static void notifyThreadDetach();\r
97 static void notifyShow(NotifyShow::Show i_show, bool i_isMDI);\r
98 static void notifyLog(_TCHAR *i_msg);\r
99 static bool mapHookData();\r
100 static void unmapHookData();\r
101 static bool initialize();\r
102 \r
103 \r
104 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
105 // Functions\r
106 \r
107 bool initialize()\r
108 {\r
109 #ifndef NDEBUG\r
110         _TCHAR path[GANA_MAX_PATH];\r
111         GetModuleFileName(NULL, path, GANA_MAX_PATH);\r
112         _tsplitpath_s(path, NULL, 0, NULL, 0, g.m_moduleName, GANA_MAX_PATH, NULL, 0);\r
113         if (_tcsncmp(g.m_moduleName, _T("Dbgview"), sizeof(_T("Dbgview"))/sizeof(_TCHAR)) != 0 &&\r
114                         _tcsncmp(g.m_moduleName, _T("windbg"), sizeof(_T("windbg"))/sizeof(_TCHAR)) != 0) {\r
115                 g.m_isLogging = true;\r
116         }\r
117 #endif // !NDEBUG\r
118 #ifdef USE_MAILSLOT\r
119         g.m_hMailslot =\r
120                 CreateFile(NOTIFY_MAILSLOT_NAME, GENERIC_WRITE,\r
121                                    FILE_SHARE_READ | FILE_SHARE_WRITE,\r
122                                    (SECURITY_ATTRIBUTES *)NULL, OPEN_EXISTING,\r
123                                    FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);\r
124         if (g.m_hMailslot == INVALID_HANDLE_VALUE) {\r
125                 HOOK_RPT2("MAYU: %S create mailslot failed(0x%08x)\r\n", g.m_moduleName, GetLastError());\r
126         } else {\r
127                 HOOK_RPT1("MAYU: %S create mailslot successed\r\n", g.m_moduleName);\r
128         }\r
129 #endif //USE_MAILSLOT\r
130         if (!mapHookData())\r
131                 return false;\r
132         _tsetlocale(LC_ALL, _T(""));\r
133         g.m_WM_MAYU_MESSAGE =\r
134                 RegisterWindowMessage(addSessionId(WM_MAYU_MESSAGE_NAME).c_str());\r
135         g.m_hwndTaskTray = g_hookData->m_hwndTaskTray;\r
136         g.m_isInitialized = true;\r
137         return true;\r
138 }\r
139 \r
140 /// EntryPoint\r
141 BOOL WINAPI DllMain(HINSTANCE i_hInstDLL, DWORD i_fdwReason,\r
142                                         LPVOID /* i_lpvReserved */)\r
143 {\r
144         switch (i_fdwReason) {\r
145         case DLL_PROCESS_ATTACH: {\r
146 #ifndef NDEBUG\r
147                 g.m_isLogging = false;\r
148 #endif // !NDEBUG\r
149                 g.m_isInitialized = false;\r
150                 g.m_hInstDLL = i_hInstDLL;\r
151                 break;\r
152         }\r
153         case DLL_THREAD_ATTACH:\r
154                 break;\r
155         case DLL_PROCESS_DETACH:\r
156                 notifyThreadDetach();\r
157                 unmapHookData();\r
158 #ifdef USE_MAILSLOT\r
159                 if (g.m_hMailslot != INVALID_HANDLE_VALUE) {\r
160                         CloseHandle(g.m_hMailslot);\r
161                         g.m_hMailslot = INVALID_HANDLE_VALUE;\r
162                 }\r
163 #endif //USE_MAILSLOT\r
164                 break;\r
165         case DLL_THREAD_DETACH:\r
166                 notifyThreadDetach();\r
167                 break;\r
168         default:\r
169                 break;\r
170         }\r
171         return TRUE;\r
172 }\r
173 \r
174 \r
175 /// map hook data\r
176 static bool mapHookData()\r
177 {\r
178         g.m_hHookData = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,\r
179                                                                           0, sizeof(HookData),\r
180                                                                           addSessionId(HOOK_DATA_NAME).c_str());\r
181         if (!g.m_hHookData) {\r
182                 unmapHookData();\r
183                 return false;\r
184         }\r
185 \r
186         g_hookData =\r
187                 (HookData *)MapViewOfFile(g.m_hHookData, FILE_MAP_READ | FILE_MAP_WRITE,\r
188                                                                   0, 0, sizeof(HookData));\r
189         if (!g_hookData) {\r
190                 unmapHookData();\r
191                 return false;\r
192         }\r
193 \r
194         g.m_hHookDataArch = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,\r
195                                                                                   0, sizeof(HookDataArch),\r
196                                                                                   addSessionId(HOOK_DATA_NAME_ARCH).c_str());\r
197         if (!g.m_hHookDataArch) {\r
198                 unmapHookData();\r
199                 return false;\r
200         }\r
201 \r
202         s_hookDataArch =\r
203                 (HookDataArch *)MapViewOfFile(g.m_hHookDataArch, FILE_MAP_READ | FILE_MAP_WRITE,\r
204                                                                           0, 0, sizeof(HookDataArch));\r
205         if (!s_hookDataArch) {\r
206                 unmapHookData();\r
207                 return false;\r
208         }\r
209 \r
210         return true;\r
211 }\r
212 \r
213 \r
214 /// unmap hook data\r
215 static void unmapHookData()\r
216 {\r
217         if (g_hookData)\r
218                 UnmapViewOfFile(g_hookData);\r
219         g_hookData = NULL;\r
220         if (g.m_hHookData)\r
221                 CloseHandle(g.m_hHookData);\r
222         g.m_hHookData = NULL;\r
223         if (s_hookDataArch)\r
224                 UnmapViewOfFile(s_hookDataArch);\r
225         s_hookDataArch = NULL;\r
226         if (g.m_hHookDataArch)\r
227                 CloseHandle(g.m_hHookDataArch);\r
228         g.m_hHookDataArch = NULL;\r
229 }\r
230 \r
231 \r
232 /// notify\r
233 DllExport bool notify(void *i_data, size_t i_dataSize)\r
234 {\r
235         COPYDATASTRUCT cd;\r
236 #ifdef MAYU64\r
237         DWORD_PTR result;\r
238 #else  // MAYU64\r
239         DWORD result;\r
240 #endif // MAYU64\r
241 \r
242 #ifdef USE_MAILSLOT\r
243         DWORD len;\r
244         if (g.m_hMailslot != INVALID_HANDLE_VALUE) {\r
245                 BOOL ret;\r
246                 ret = WriteFile(g.m_hMailslot, i_data, i_dataSize, &len, NULL);\r
247 #ifndef NDEBUG\r
248                 if (ret == 0) {\r
249                         HOOK_RPT2("MAYU: %S WriteFile to mailslot failed(0x%08x)\r\n", g.m_moduleName, GetLastError());\r
250                 } else {\r
251                         HOOK_RPT1("MAYU: %S WriteFile to mailslot successed\r\n", g.m_moduleName);\r
252                 }\r
253 #endif // !NDEBUG\r
254         }\r
255 #else // !USE_MAILSLOT\r
256         cd.dwData = reinterpret_cast<Notify *>(i_data)->m_type;\r
257         cd.cbData = i_dataSize;\r
258         cd.lpData = i_data;\r
259         if (g.m_hwndTaskTray == 0)\r
260                 return false;\r
261         if (!SendMessageTimeout(reinterpret_cast<HWND>(g.m_hwndTaskTray),\r
262                                                         WM_COPYDATA, NULL, reinterpret_cast<LPARAM>(&cd),\r
263                                                         SMTO_ABORTIFHUNG | SMTO_NORMAL, 5000, &result)) {\r
264                 _RPT0(_CRT_WARN, "MAYU: SendMessageTimeout() timeouted\r\n");\r
265                 return false;\r
266         }\r
267 #endif // !USE_MAILSLOT\r
268         return true;\r
269 }\r
270 \r
271 \r
272 /// get class name and title name\r
273 static void getClassNameTitleName(HWND i_hwnd, bool i_isInMenu,\r
274                                                                   tstringi *o_className,\r
275                                                                   tstring *o_titleName)\r
276 {\r
277         tstringi &className = *o_className;\r
278         tstring &titleName = *o_titleName;\r
279 \r
280         bool isTheFirstTime = true;\r
281 \r
282         if (i_isInMenu) {\r
283                 className = titleName = _T("MENU");\r
284                 isTheFirstTime = false;\r
285         }\r
286 \r
287         while (true) {\r
288                 _TCHAR buf[MAX(GANA_MAX_PATH, GANA_MAX_ATOM_LENGTH)];\r
289 \r
290                 // get class name\r
291                 if (i_hwnd)\r
292                         GetClassName(i_hwnd, buf, NUMBER_OF(buf));\r
293                 else\r
294                         GetModuleFileName(GetModuleHandle(NULL), buf, NUMBER_OF(buf));\r
295                 buf[NUMBER_OF(buf) - 1] = _T('\0');\r
296                 if (isTheFirstTime)\r
297                         className = buf;\r
298                 else\r
299                         className = tstringi(buf) + _T(":") + className;\r
300 \r
301                 // get title name\r
302                 if (i_hwnd) {\r
303                         GetWindowText(i_hwnd, buf, NUMBER_OF(buf));\r
304                         buf[NUMBER_OF(buf) - 1] = _T('\0');\r
305                         for (_TCHAR *b = buf; *b; ++ b)\r
306                                 if (_istlead(*b) && b[1])\r
307                                         b ++;\r
308                                 else if (_istcntrl(*b))\r
309                                         *b = _T('?');\r
310                 }\r
311                 if (isTheFirstTime)\r
312                         titleName = buf;\r
313                 else\r
314                         titleName = tstring(buf) + _T(":") + titleName;\r
315 \r
316                 // next loop or exit\r
317                 if (!i_hwnd)\r
318                         break;\r
319                 i_hwnd = GetParent(i_hwnd);\r
320                 isTheFirstTime = false;\r
321         }\r
322 }\r
323 \r
324 \r
325 /// update show\r
326 static void updateShow(HWND i_hwnd, NotifyShow::Show i_show)\r
327 {\r
328         bool isMDI = false;\r
329 \r
330         if (!i_hwnd)\r
331                 return;\r
332 \r
333 #ifdef MAYU64\r
334         LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
335 #else\r
336         LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
337 #endif\r
338         if (!(style & WS_MAXIMIZEBOX) && !(style & WS_MAXIMIZEBOX))\r
339                 return; // ignore window that has neither maximize or minimize button\r
340 \r
341         if (style & WS_CHILD) {\r
342 #ifdef MAYU64\r
343                 LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);\r
344 #else\r
345                 LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);\r
346 #endif\r
347                 if (exStyle & WS_EX_MDICHILD) {\r
348                         isMDI = true;\r
349                 } else\r
350                         return; // ignore non-MDI child window case\r
351         }\r
352 \r
353         notifyShow(i_show, isMDI);\r
354 }\r
355 \r
356 \r
357 /// notify WM_Targetted\r
358 static void notifyName(HWND i_hwnd, Notify::Type i_type = Notify::Type_name)\r
359 {\r
360         tstringi className;\r
361         tstring titleName;\r
362         getClassNameTitleName(i_hwnd, g.m_isInMenu, &className, &titleName);\r
363 \r
364         NotifySetFocus *nfc = new NotifySetFocus;\r
365         nfc->m_type = i_type;\r
366         nfc->m_threadId = GetCurrentThreadId();\r
367         nfc->m_hwnd = reinterpret_cast<DWORD>(i_hwnd);\r
368         tcslcpy(nfc->m_className, className.c_str(), NUMBER_OF(nfc->m_className));\r
369         tcslcpy(nfc->m_titleName, titleName.c_str(), NUMBER_OF(nfc->m_titleName));\r
370 \r
371         notify(nfc, sizeof(*nfc));\r
372         delete nfc;\r
373 }\r
374 \r
375 \r
376 /// notify WM_SETFOCUS\r
377 static void notifySetFocus(bool i_doesForce = false)\r
378 {\r
379         HWND hwnd = GetFocus();\r
380         if (i_doesForce || hwnd != g.m_hwndFocus) {\r
381                 g.m_hwndFocus = hwnd;\r
382                 notifyName(hwnd, Notify::Type_setFocus);\r
383         }\r
384 }\r
385 \r
386 \r
387 /// notify sync\r
388 static void notifySync()\r
389 {\r
390         Notify n;\r
391         n.m_type = Notify::Type_sync;\r
392         notify(&n, sizeof(n));\r
393 }\r
394 \r
395 \r
396 /// notify DLL_THREAD_DETACH\r
397 static void notifyThreadDetach()\r
398 {\r
399         NotifyThreadDetach ntd;\r
400         ntd.m_type = Notify::Type_threadDetach;\r
401         ntd.m_threadId = GetCurrentThreadId();\r
402         notify(&ntd, sizeof(ntd));\r
403 }\r
404 \r
405 \r
406 /// notify WM_COMMAND, WM_SYSCOMMAND\r
407 static void notifyCommand(\r
408         HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam)\r
409 {\r
410 #ifndef _WIN64\r
411         if (g_hookData->m_doesNotifyCommand) {\r
412                 NotifyCommand ntc;\r
413                 ntc.m_type = Notify::Type_command;\r
414                 ntc.m_hwnd = i_hwnd;\r
415                 ntc.m_message = i_message;\r
416                 ntc.m_wParam = i_wParam;\r
417                 ntc.m_lParam = i_lParam;\r
418                 notify(&ntc, sizeof(ntc));\r
419         }\r
420 #endif\r
421 }\r
422 \r
423 \r
424 /// notify show of current window\r
425 static void notifyShow(NotifyShow::Show i_show, bool i_isMDI)\r
426 {\r
427         NotifyShow ns;\r
428         ns.m_type = Notify::Type_show;\r
429         ns.m_show = i_show;\r
430         ns.m_isMDI = i_isMDI;\r
431         notify(&ns, sizeof(ns));\r
432 }\r
433 \r
434 \r
435 /// notify log\r
436 static void notifyLog(_TCHAR *i_msg)\r
437 {\r
438         NotifyLog nl;\r
439         nl.m_type = Notify::Type_log;\r
440         tcslcpy(nl.m_msg, i_msg, NUMBER_OF(nl.m_msg));\r
441         notify(&nl, sizeof(nl));\r
442 }\r
443 \r
444 \r
445 /// &Recenter\r
446 static void funcRecenter(HWND i_hwnd)\r
447 {\r
448         _TCHAR buf[MAX(GANA_MAX_PATH, GANA_MAX_ATOM_LENGTH)];\r
449         GetClassName(i_hwnd, buf, NUMBER_OF(buf));\r
450         bool isEdit;\r
451         if (_tcsicmp(buf, _T("Edit")) == 0)\r
452                 isEdit = true;\r
453         else if (_tcsnicmp(buf, _T("RichEdit"), 8) == 0)\r
454                 isEdit = false;\r
455         else\r
456                 return; // this function only works for Edit control\r
457 \r
458 #ifdef MAYU64\r
459         LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
460 #else\r
461         LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
462 #endif\r
463         if (!(style & ES_MULTILINE))\r
464                 return; // this function only works for multi line Edit control\r
465 \r
466         RECT rc;\r
467         GetClientRect(i_hwnd, &rc);\r
468         POINTL p = { (rc.right + rc.left) / 2, (rc.top + rc.bottom) / 2 };\r
469         int line;\r
470         if (isEdit) {\r
471                 line = SendMessage(i_hwnd, EM_CHARFROMPOS, 0, MAKELPARAM(p.x, p.y));\r
472                 line = HIWORD(line);\r
473         } else {\r
474                 int ci = SendMessage(i_hwnd, EM_CHARFROMPOS, 0, (LPARAM)&p);\r
475                 line = SendMessage(i_hwnd, EM_EXLINEFROMCHAR, 0, ci);\r
476         }\r
477         int caretLine = SendMessage(i_hwnd, EM_LINEFROMCHAR, -1, 0);\r
478         SendMessage(i_hwnd, EM_LINESCROLL, 0, caretLine - line);\r
479 }\r
480 \r
481 \r
482 // &SetImeStatus\r
483 static void funcSetImeStatus(HWND i_hwnd, int i_status)\r
484 {\r
485         HIMC hIMC;\r
486 \r
487         hIMC = ImmGetContext(i_hwnd);\r
488         if (hIMC == INVALID_HANDLE_VALUE)\r
489                 return;\r
490 \r
491         if (i_status < 0)\r
492                 i_status = !ImmGetOpenStatus(hIMC);\r
493 \r
494         ImmSetOpenStatus(hIMC, i_status);\r
495         ImmReleaseContext(i_hwnd, hIMC);\r
496 }\r
497 \r
498 \r
499 // &SetImeString\r
500 static void funcSetImeString(HWND i_hwnd, int i_size)\r
501 {\r
502         _TCHAR *buf = new _TCHAR(i_size);\r
503         DWORD len = 0;\r
504         _TCHAR ImeDesc[GANA_MAX_ATOM_LENGTH];\r
505         UINT ImeDescLen;\r
506         DWORD error;\r
507         DWORD denom = 1;\r
508         HANDLE hPipe\r
509         = CreateFile(addSessionId(HOOK_PIPE_NAME).c_str(), GENERIC_READ,\r
510                                  FILE_SHARE_READ, (SECURITY_ATTRIBUTES *)NULL,\r
511                                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);\r
512         error = ReadFile(hPipe, buf, i_size, &len, NULL);\r
513         CloseHandle(hPipe);\r
514 \r
515         ImeDescLen = ImmGetDescription(GetKeyboardLayout(0),\r
516                                                                    ImeDesc, sizeof(ImeDesc));\r
517         if (_tcsncmp(ImeDesc, _T("SKKIME"), ImeDescLen) > 0)\r
518                 denom = sizeof(_TCHAR);\r
519 \r
520         HIMC hIMC = ImmGetContext(i_hwnd);\r
521         if (hIMC == INVALID_HANDLE_VALUE)\r
522                 return;\r
523 \r
524         int status = ImmGetOpenStatus(hIMC);\r
525         ImmSetCompositionString(hIMC, SCS_SETSTR, buf, len / denom, NULL, 0);\r
526         delete buf;\r
527         ImmNotifyIME(hIMC, NI_COMPOSITIONSTR, CPS_COMPLETE, 0);\r
528         if (!status)\r
529                 ImmSetOpenStatus(hIMC, status);\r
530         ImmReleaseContext(i_hwnd, hIMC);\r
531 }\r
532 \r
533 /// notify lock state\r
534 /*DllExport*/\r
535 void notifyLockState(int i_cause)\r
536 {\r
537         NotifyLockState n;\r
538         n.m_type = Notify::Type_lockState;\r
539         n.m_isNumLockToggled = !!(GetKeyState(VK_NUMLOCK) & 1);\r
540         n.m_isCapsLockToggled = !!(GetKeyState(VK_CAPITAL) & 1);\r
541         n.m_isScrollLockToggled = !!(GetKeyState(VK_SCROLL) & 1);\r
542         n.m_isKanaLockToggled = !!(GetKeyState(VK_KANA) & 1);\r
543         n.m_isImeLockToggled = g.m_isImeLock;\r
544         n.m_isImeCompToggled = g.m_isImeCompositioning;\r
545         n.m_debugParam = i_cause;\r
546         notify(&n, sizeof(n));\r
547 }\r
548 \r
549 DllExport void notifyLockState()\r
550 {\r
551         notifyLockState(9);\r
552 }\r
553 \r
554 \r
555 /// hook of GetMessage\r
556 LRESULT CALLBACK getMessageProc(int i_nCode, WPARAM i_wParam, LPARAM i_lParam)\r
557 {\r
558         if (!g.m_isInitialized)\r
559                 initialize();\r
560 \r
561         if (!g_hookData)\r
562                 return 0;\r
563 \r
564         MSG &msg = (*(MSG *)i_lParam);\r
565 \r
566         if (i_wParam != PM_REMOVE)\r
567                 goto finally;\r
568 \r
569         switch (msg.message) {\r
570         case WM_COMMAND:\r
571         case WM_SYSCOMMAND:\r
572                 notifyCommand(msg.hwnd, msg.message, msg.wParam, msg.lParam);\r
573                 break;\r
574         case WM_KEYDOWN:\r
575         case WM_KEYUP:\r
576         case WM_SYSKEYDOWN:\r
577         case WM_SYSKEYUP: {\r
578                 if (HIMC hIMC = ImmGetContext(msg.hwnd)) {\r
579                         bool prev = g.m_isImeLock;\r
580                         g.m_isImeLock = !!ImmGetOpenStatus(hIMC);\r
581                         ImmReleaseContext(msg.hwnd, hIMC);\r
582                         if (prev != g.m_isImeLock) {\r
583                                 notifyLockState(1);\r
584                         }\r
585                 }\r
586                 int nVirtKey = (int)msg.wParam;\r
587                 // int repeatCount = (msg.lParam & 0xffff);\r
588                 BYTE scanCode   = (BYTE)((msg.lParam >> 16) & 0xff);\r
589                 bool isExtended = !!(msg.lParam & (1 << 24));\r
590                 // bool isAltDown  = !!(msg.lParam & (1 << 29));\r
591                 // bool isKeyup    = !!(msg.lParam & (1 << 31));\r
592 \r
593                 if (nVirtKey == VK_CAPITAL ||\r
594                                 nVirtKey == VK_NUMLOCK ||\r
595                                 nVirtKey == VK_KANA ||\r
596                                 nVirtKey == VK_SCROLL)\r
597                         notifyLockState(2);\r
598                 else if (scanCode == g_hookData->m_syncKey &&\r
599                                  isExtended == g_hookData->m_syncKeyIsExtended)\r
600                         notifySync();\r
601                 break;\r
602         }\r
603         case WM_IME_STARTCOMPOSITION:\r
604                 g.m_isImeCompositioning = true;\r
605                 notifyLockState(3);\r
606                 break;\r
607         case WM_IME_ENDCOMPOSITION:\r
608                 g.m_isImeCompositioning = false;\r
609                 notifyLockState(4);\r
610                 break;\r
611         default:\r
612                 if (i_wParam == PM_REMOVE && msg.message == g.m_WM_MAYU_MESSAGE) {\r
613                         switch (msg.wParam) {\r
614                         case MayuMessage_notifyName:\r
615                                 notifyName(msg.hwnd);\r
616                                 break;\r
617                         case MayuMessage_funcRecenter:\r
618                                 funcRecenter(msg.hwnd);\r
619                                 break;\r
620                         case MayuMessage_funcSetImeStatus:\r
621                                 funcSetImeStatus(msg.hwnd, msg.lParam);\r
622                                 break;\r
623                         case MayuMessage_funcSetImeString:\r
624                                 funcSetImeString(msg.hwnd, msg.lParam);\r
625                                 break;\r
626                         }\r
627                 }\r
628                 break;\r
629         }\r
630 finally:\r
631         return CallNextHookEx(s_hookDataArch->m_hHookGetMessage,\r
632                                                   i_nCode, i_wParam, i_lParam);\r
633 }\r
634 \r
635 \r
636 /// hook of SendMessage\r
637 LRESULT CALLBACK callWndProc(int i_nCode, WPARAM i_wParam, LPARAM i_lParam)\r
638 {\r
639         if (!g.m_isInitialized)\r
640                 initialize();\r
641 \r
642         if (!g_hookData)\r
643                 return 0;\r
644 \r
645         CWPSTRUCT &cwps = *(CWPSTRUCT *)i_lParam;\r
646 \r
647         if (0 <= i_nCode) {\r
648                 switch (cwps.message) {\r
649                 case WM_ACTIVATEAPP:\r
650                 case WM_NCACTIVATE:\r
651                         if (i_wParam)\r
652                                 notifySetFocus();\r
653                         break;\r
654                 case WM_SYSCOMMAND:\r
655                         switch (cwps.wParam) {\r
656                         case SC_MAXIMIZE:\r
657                         case SC_MAXIMIZE2:\r
658                                 updateShow(cwps.hwnd, NotifyShow::Show_Maximized);\r
659                                 break;\r
660                         case SC_MINIMIZE:\r
661                         case SC_MINIMIZE2:\r
662                                 updateShow(cwps.hwnd, NotifyShow::Show_Minimized);\r
663                                 break;\r
664                         case SC_RESTORE:\r
665                         case SC_RESTORE2:\r
666                                 updateShow(cwps.hwnd, NotifyShow::Show_Normal);\r
667                                 break;\r
668                         default:\r
669                                 break;\r
670                         }\r
671                         /* through below */\r
672                 case WM_COMMAND:\r
673                         notifyCommand(cwps.hwnd, cwps.message, cwps.wParam, cwps.lParam);\r
674                         break;\r
675                 case WM_SIZE:\r
676                         switch (cwps.wParam) {\r
677                         case SIZE_MAXIMIZED:\r
678                                 updateShow(cwps.hwnd, NotifyShow::Show_Maximized);\r
679                                 break;\r
680                         case SIZE_MINIMIZED:\r
681                                 updateShow(cwps.hwnd, NotifyShow::Show_Minimized);\r
682                                 break;\r
683                         case SIZE_RESTORED:\r
684                                 updateShow(cwps.hwnd, NotifyShow::Show_Normal);\r
685                                 break;\r
686                         default:\r
687                                 break;\r
688                         }\r
689                         break;\r
690                 case WM_MOUSEACTIVATE:\r
691                         notifySetFocus();\r
692                         break;\r
693                 case WM_ACTIVATE:\r
694                         if (LOWORD(cwps.wParam) != WA_INACTIVE) {\r
695                                 notifySetFocus();\r
696                                 if (HIWORD(cwps.wParam)) { // check minimized flag\r
697                                         // minimized flag on\r
698                                         notifyShow(NotifyShow::Show_Minimized, false);\r
699                                         //notifyShow(NotifyShow::Show_Normal, true);\r
700                                 }\r
701                         }\r
702                         break;\r
703                 case WM_ENTERMENULOOP:\r
704                         g.m_isInMenu = true;\r
705                         notifySetFocus(true);\r
706                         break;\r
707                 case WM_EXITMENULOOP:\r
708                         g.m_isInMenu = false;\r
709                         notifySetFocus(true);\r
710                         break;\r
711                 case WM_SETFOCUS:\r
712                         g.m_isInMenu = false;\r
713                         // for kana\r
714                         if (g_hookData->m_correctKanaLockHandling) {\r
715                                 if (HIMC hIMC = ImmGetContext(cwps.hwnd)) {\r
716                                         bool status = !!ImmGetOpenStatus(hIMC);\r
717                                         // this code set the VK_KANA state correctly.\r
718                                         ImmSetOpenStatus(hIMC, !status);\r
719                                         ImmSetOpenStatus(hIMC, status);\r
720                                         ImmReleaseContext(cwps.hwnd, hIMC);\r
721                                 }\r
722                         }\r
723                         notifySetFocus();\r
724                         notifyLockState(5);\r
725                         break;\r
726                 case WM_IME_STARTCOMPOSITION:\r
727                         g.m_isImeCompositioning = true;\r
728                         notifyLockState(6);\r
729                         break;\r
730                 case WM_IME_ENDCOMPOSITION:\r
731                         g.m_isImeCompositioning = false;\r
732                         notifyLockState(7);\r
733                         break;\r
734                 case WM_IME_NOTIFY:\r
735                         if (cwps.wParam == IMN_SETOPENSTATUS)\r
736                                 if (HIMC hIMC = ImmGetContext(cwps.hwnd)) {\r
737                                         g.m_isImeLock = !!ImmGetOpenStatus(hIMC);\r
738                                         ImmReleaseContext(cwps.hwnd, hIMC);\r
739                                         notifyLockState(8);\r
740                                 }\r
741                         break;\r
742                 }\r
743         }\r
744         return CallNextHookEx(s_hookDataArch->m_hHookCallWndProc, i_nCode,\r
745                                                   i_wParam, i_lParam);\r
746 }\r
747 \r
748 \r
749 static LRESULT CALLBACK lowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)\r
750 {\r
751         if (!g.m_isInitialized)\r
752                 initialize();\r
753 \r
754         if (!g_hookData || nCode < 0)\r
755                 goto through;\r
756 \r
757         if (g.m_mouseDetour && g.m_engine) {\r
758                 unsigned int result;\r
759                 result = g.m_mouseDetour(g.m_engine, wParam, lParam);\r
760                 if (result) {\r
761                         return 1;\r
762                 }\r
763         }\r
764 \r
765 through:\r
766         return CallNextHookEx(g.m_hHookMouseProc,\r
767                                                   nCode, wParam, lParam);\r
768 }\r
769 \r
770 \r
771 #ifdef NO_DRIVER\r
772 static LRESULT CALLBACK lowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)\r
773 {\r
774         KBDLLHOOKSTRUCT *pKbll = (KBDLLHOOKSTRUCT*)lParam;\r
775 \r
776         if (!g.m_isInitialized)\r
777                 initialize();\r
778 \r
779         if (!g_hookData || nCode < 0)\r
780                 goto through;\r
781 \r
782         if (g.m_keyboardDetour && g.m_engine) {\r
783                 unsigned int result;\r
784                 result = g.m_keyboardDetour(g.m_engine, wParam, lParam);\r
785                 if (result) {\r
786                         return 1;\r
787                 }\r
788         }\r
789 through:\r
790         return CallNextHookEx(g.m_hHookKeyboardProc,\r
791                                                   nCode, wParam, lParam);\r
792 }\r
793 #endif // NO_DRIVER\r
794 \r
795 \r
796 /// install message hook\r
797 DllExport int installMessageHook()\r
798 {\r
799         if (!g.m_isInitialized)\r
800                 initialize();\r
801 \r
802         g.m_hwndTaskTray = g_hookData->m_hwndTaskTray;\r
803         s_hookDataArch->m_hHookGetMessage =\r
804                 SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)getMessageProc,\r
805                                                  g.m_hInstDLL, 0);\r
806         s_hookDataArch->m_hHookCallWndProc =\r
807                 SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)callWndProc, g.m_hInstDLL, 0);\r
808         return 0;\r
809 }\r
810 \r
811 \r
812 /// uninstall message hook\r
813 DllExport int uninstallMessageHook()\r
814 {\r
815         if (s_hookDataArch->m_hHookGetMessage)\r
816                 UnhookWindowsHookEx(s_hookDataArch->m_hHookGetMessage);\r
817         s_hookDataArch->m_hHookGetMessage = NULL;\r
818         if (s_hookDataArch->m_hHookCallWndProc)\r
819                 UnhookWindowsHookEx(s_hookDataArch->m_hHookCallWndProc);\r
820         s_hookDataArch->m_hHookCallWndProc = NULL;\r
821         g.m_hwndTaskTray = 0;\r
822         return 0;\r
823 }\r
824 \r
825 \r
826 /// install keyboard hook\r
827 DllExport int installKeyboardHook(INPUT_DETOUR i_keyboardDetour, Engine *i_engine, bool i_install)\r
828 {\r
829 #ifdef NO_DRIVER\r
830         if (i_install) {\r
831                 if (!g.m_isInitialized)\r
832                         initialize();\r
833 \r
834                 g.m_keyboardDetour = i_keyboardDetour;\r
835                 g.m_engine = i_engine;\r
836                 g.m_hHookKeyboardProc =\r
837                         SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)lowLevelKeyboardProc,\r
838                                                          g.m_hInstDLL, 0);\r
839         } else {\r
840                 if (g.m_hHookKeyboardProc)\r
841                         UnhookWindowsHookEx(g.m_hHookKeyboardProc);\r
842                 g.m_hHookKeyboardProc = NULL;\r
843         }\r
844 #endif // NO_DRIVER\r
845         return 0;\r
846 }\r
847 \r
848 \r
849 /// install mouse hook\r
850 DllExport int installMouseHook(INPUT_DETOUR i_mouseDetour, Engine *i_engine, bool i_install)\r
851 {\r
852         if (i_install) {\r
853                 if (!g.m_isInitialized)\r
854                         initialize();\r
855 \r
856                 g.m_mouseDetour = i_mouseDetour;\r
857                 g.m_engine = i_engine;\r
858                 g_hookData->m_mouseHookType = MouseHookType_None;\r
859                 g.m_hHookMouseProc =\r
860                         SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)lowLevelMouseProc,\r
861                                                          g.m_hInstDLL, 0);\r
862         } else {\r
863                 if (g.m_hHookMouseProc)\r
864                         UnhookWindowsHookEx(g.m_hHookMouseProc);\r
865                 g.m_hHookMouseProc = NULL;\r
866         }\r
867         return 0;\r
868 }\r