OSDN Git Service

through mouse event even if it isn't defined in .mayu for fail safe
[yamy/yamy.git] / engine.cpp
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\r
2 // engine.cpp\r
3 \r
4 \r
5 #include "misc.h"\r
6 \r
7 #include "engine.h"\r
8 #include "errormessage.h"\r
9 #include "hook.h"\r
10 #include "mayurc.h"\r
11 #include "windowstool.h"\r
12 \r
13 #include <iomanip>\r
14 \r
15 #include <process.h>\r
16 \r
17 \r
18 // check focus window\r
19 void Engine::checkFocusWindow()\r
20 {\r
21         int count = 0;\r
22 \r
23 restart:\r
24         count ++;\r
25 \r
26         HWND hwndFore = GetForegroundWindow();\r
27         DWORD threadId = GetWindowThreadProcessId(hwndFore, NULL);\r
28 \r
29         if (hwndFore) {\r
30                 {\r
31                         Acquire a(&m_cs);\r
32                         if (m_currentFocusOfThread &&\r
33                                         m_currentFocusOfThread->m_threadId == threadId &&\r
34                                         m_currentFocusOfThread->m_hwndFocus == m_hwndFocus)\r
35                                 return;\r
36 \r
37                         m_emacsEditKillLine.reset();\r
38 \r
39                         // erase dead thread\r
40                         if (!m_detachedThreadIds.empty()) {\r
41                                 for (DetachedThreadIds::iterator i = m_detachedThreadIds.begin();\r
42                                                 i != m_detachedThreadIds.end(); i ++) {\r
43                                         FocusOfThreads::iterator j = m_focusOfThreads.find((*i));\r
44                                         if (j != m_focusOfThreads.end()) {\r
45                                                 FocusOfThread *fot = &((*j).second);\r
46                                                 Acquire a(&m_log, 1);\r
47                                                 m_log << _T("RemoveThread") << std::endl;\r
48                                                 m_log << _T("\tHWND:\t") << std::hex << (int)fot->m_hwndFocus\r
49                                                 << std::dec << std::endl;\r
50                                                 m_log << _T("\tTHREADID:") << fot->m_threadId << std::endl;\r
51                                                 m_log << _T("\tCLASS:\t") << fot->m_className << std::endl;\r
52                                                 m_log << _T("\tTITLE:\t") << fot->m_titleName << std::endl;\r
53                                                 m_log << std::endl;\r
54                                                 m_focusOfThreads.erase(j);\r
55                                         }\r
56                                 }\r
57                                 m_detachedThreadIds.erase\r
58                                 (m_detachedThreadIds.begin(), m_detachedThreadIds.end());\r
59                         }\r
60 \r
61                         FocusOfThreads::iterator i = m_focusOfThreads.find(threadId);\r
62                         if (i != m_focusOfThreads.end()) {\r
63                                 m_currentFocusOfThread = &((*i).second);\r
64                                 if (!m_currentFocusOfThread->m_isConsole || 2 <= count) {\r
65                                         if (m_currentFocusOfThread->m_keymaps.empty())\r
66                                                 setCurrentKeymap(NULL);\r
67                                         else\r
68                                                 setCurrentKeymap(*m_currentFocusOfThread->m_keymaps.begin());\r
69                                         m_hwndFocus = m_currentFocusOfThread->m_hwndFocus;\r
70                                         checkShow(m_hwndFocus);\r
71 \r
72                                         Acquire a(&m_log, 1);\r
73                                         m_log << _T("FocusChanged") << std::endl;\r
74                                         m_log << _T("\tHWND:\t")\r
75                                         << std::hex << (int)m_currentFocusOfThread->m_hwndFocus\r
76                                         << std::dec << std::endl;\r
77                                         m_log << _T("\tTHREADID:")\r
78                                         << m_currentFocusOfThread->m_threadId << std::endl;\r
79                                         m_log << _T("\tCLASS:\t")\r
80                                         << m_currentFocusOfThread->m_className << std::endl;\r
81                                         m_log << _T("\tTITLE:\t")\r
82                                         << m_currentFocusOfThread->m_titleName << std::endl;\r
83                                         m_log << std::endl;\r
84                                         return;\r
85                                 }\r
86                         }\r
87                 }\r
88 \r
89                 _TCHAR className[GANA_MAX_ATOM_LENGTH];\r
90                 if (GetClassName(hwndFore, className, NUMBER_OF(className))) {\r
91                         if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {\r
92                                 _TCHAR titleName[1024];\r
93                                 if (GetWindowText(hwndFore, titleName, NUMBER_OF(titleName)) == 0)\r
94                                         titleName[0] = _T('\0');\r
95                                 setFocus(hwndFore, threadId, className, titleName, true);\r
96                                 Acquire a(&m_log, 1);\r
97                                 m_log << _T("HWND:\t") << std::hex << reinterpret_cast<int>(hwndFore)\r
98                                 << std::dec << std::endl;\r
99                                 m_log << _T("THREADID:") << threadId << std::endl;\r
100                                 m_log << _T("CLASS:\t") << className << std::endl;\r
101                                 m_log << _T("TITLE:\t") << titleName << std::endl << std::endl;\r
102                                 goto restart;\r
103                         }\r
104                 }\r
105         }\r
106 \r
107         Acquire a(&m_cs);\r
108         if (m_globalFocus.m_keymaps.empty()) {\r
109                 Acquire a(&m_log, 1);\r
110                 m_log << _T("NO GLOBAL FOCUS") << std::endl;\r
111                 m_currentFocusOfThread = NULL;\r
112                 setCurrentKeymap(NULL);\r
113         } else {\r
114                 if (m_currentFocusOfThread != &m_globalFocus) {\r
115                         Acquire a(&m_log, 1);\r
116                         m_log << _T("GLOBAL FOCUS") << std::endl;\r
117                         m_currentFocusOfThread = &m_globalFocus;\r
118                         setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
119                 }\r
120         }\r
121         m_hwndFocus = NULL;\r
122 }\r
123 \r
124 \r
125 \r
126 // is modifier pressed ?\r
127 bool Engine::isPressed(Modifier::Type i_mt)\r
128 {\r
129         const Keymap::ModAssignments &ma = m_currentKeymap->getModAssignments(i_mt);\r
130         for (Keymap::ModAssignments::const_iterator i = ma.begin();\r
131                         i != ma.end(); ++ i)\r
132                 if ((*i).m_key->m_isPressed)\r
133                         return true;\r
134         return false;\r
135 }\r
136 \r
137 \r
138 // fix modifier key (if fixed, return true)\r
139 bool Engine::fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am)\r
140 {\r
141         // for all modifier ...\r
142         for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {\r
143                 // get modifier assignments (list of modifier keys)\r
144                 const Keymap::ModAssignments &ma =\r
145                         m_currentKeymap->getModAssignments(static_cast<Modifier::Type>(i));\r
146 \r
147                 for (Keymap::ModAssignments::const_iterator\r
148                                 j = ma.begin(); j != ma.end(); ++ j)\r
149                         if (io_mkey->m_key == (*j).m_key) { // is io_mkey a modifier ?\r
150                                 {\r
151                                         Acquire a(&m_log, 1);\r
152                                         m_log << _T("* Modifier Key") << std::endl;\r
153                                 }\r
154                                 // set dontcare for this modifier\r
155                                 io_mkey->m_modifier.dontcare(static_cast<Modifier::Type>(i));\r
156                                 *o_am = (*j).m_assignMode;\r
157                                 return true;\r
158                         }\r
159         }\r
160         *o_am = Keymap::AM_notModifier;\r
161         return false;\r
162 }\r
163 \r
164 \r
165 // output to m_log\r
166 void Engine::outputToLog(const Key *i_key, const ModifiedKey &i_mkey,\r
167                                                  int i_debugLevel)\r
168 {\r
169         size_t i;\r
170         Acquire a(&m_log, i_debugLevel);\r
171 \r
172         // output scan codes\r
173         for (i = 0; i < i_key->getScanCodesSize(); ++ i) {\r
174                 if (i_key->getScanCodes()[i].m_flags & ScanCode::E0) m_log << _T("E0-");\r
175                 if (i_key->getScanCodes()[i].m_flags & ScanCode::E1) m_log << _T("E1-");\r
176                 if (!(i_key->getScanCodes()[i].m_flags & ScanCode::E0E1))\r
177                         m_log << _T("   ");\r
178                 m_log << _T("0x") << std::hex << std::setw(2) << std::setfill(_T('0'))\r
179                 << static_cast<int>(i_key->getScanCodes()[i].m_scan)\r
180                 << std::dec << _T(" ");\r
181         }\r
182 \r
183         if (!i_mkey.m_key) { // key corresponds to no phisical key\r
184                 m_log << std::endl;\r
185                 return;\r
186         }\r
187 \r
188         m_log << _T("  ") << i_mkey << std::endl;\r
189 }\r
190 \r
191 \r
192 // describe bindings\r
193 void Engine::describeBindings()\r
194 {\r
195         Acquire a(&m_log, 0);\r
196 \r
197         Keymap::DescribeParam dp;\r
198         for (KeymapPtrList::iterator i = m_currentFocusOfThread->m_keymaps.begin();\r
199                         i != m_currentFocusOfThread->m_keymaps.end(); ++ i)\r
200                 (*i)->describe(m_log, &dp);\r
201         m_log << std::endl;\r
202 }\r
203 \r
204 \r
205 // update m_lastPressedKey\r
206 void Engine::updateLastPressedKey(Key *i_key)\r
207 {\r
208         m_lastPressedKey[1] = m_lastPressedKey[0];\r
209         m_lastPressedKey[0] = i_key;\r
210 }\r
211 \r
212 // set current keymap\r
213 void Engine::setCurrentKeymap(const Keymap *i_keymap, bool i_doesAddToHistory)\r
214 {\r
215         if (i_doesAddToHistory) {\r
216                 m_keymapPrefixHistory.push_back(const_cast<Keymap *>(m_currentKeymap));\r
217                 if (MAX_KEYMAP_PREFIX_HISTORY < m_keymapPrefixHistory.size())\r
218                         m_keymapPrefixHistory.pop_front();\r
219         } else\r
220                 m_keymapPrefixHistory.clear();\r
221         m_currentKeymap = i_keymap;\r
222 }\r
223 \r
224 \r
225 // get current modifiers\r
226 Modifier Engine::getCurrentModifiers(Key *i_key, bool i_isPressed)\r
227 {\r
228         Modifier cmods;\r
229         cmods.add(m_currentLock);\r
230 \r
231         cmods.press(Modifier::Type_Shift  , isPressed(Modifier::Type_Shift  ));\r
232         cmods.press(Modifier::Type_Alt    , isPressed(Modifier::Type_Alt    ));\r
233         cmods.press(Modifier::Type_Control, isPressed(Modifier::Type_Control));\r
234         cmods.press(Modifier::Type_Windows, isPressed(Modifier::Type_Windows));\r
235         cmods.press(Modifier::Type_Up     , !i_isPressed);\r
236         cmods.press(Modifier::Type_Down   , i_isPressed);\r
237 \r
238         cmods.press(Modifier::Type_Repeat , false);\r
239         if (m_lastPressedKey[0] == i_key) {\r
240                 if (i_isPressed)\r
241                         cmods.press(Modifier::Type_Repeat, true);\r
242                 else\r
243                         if (m_lastPressedKey[1] == i_key)\r
244                                 cmods.press(Modifier::Type_Repeat, true);\r
245         }\r
246 \r
247         for (int i = Modifier::Type_Mod0; i <= Modifier::Type_Mod9; ++ i)\r
248                 cmods.press(static_cast<Modifier::Type>(i),\r
249                                         isPressed(static_cast<Modifier::Type>(i)));\r
250 \r
251         return cmods;\r
252 }\r
253 \r
254 \r
255 // generate keyboard event for a key\r
256 void Engine::generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign)\r
257 {\r
258         // check if key is event\r
259         bool isEvent = false;\r
260         for (Key **e = Event::events; *e; ++ e)\r
261                 if (*e == i_key) {\r
262                         isEvent = true;\r
263                         break;\r
264                 }\r
265 \r
266         bool isAlreadyReleased = false;\r
267 \r
268         if (!isEvent) {\r
269                 if (i_doPress && !i_key->m_isPressedOnWin32)\r
270                         ++ m_currentKeyPressCountOnWin32;\r
271                 else if (!i_doPress) {\r
272                         if (i_key->m_isPressedOnWin32)\r
273                                 -- m_currentKeyPressCountOnWin32;\r
274                         else\r
275                                 isAlreadyReleased = true;\r
276                 }\r
277                 i_key->m_isPressedOnWin32 = i_doPress;\r
278 \r
279                 if (i_isByAssign)\r
280                         i_key->m_isPressedByAssign = i_doPress;\r
281 \r
282                 Key *sync = m_setting->m_keyboard.getSyncKey();\r
283 \r
284                 if (!isAlreadyReleased || i_key == sync) {\r
285                         KEYBOARD_INPUT_DATA kid = { 0, 0, 0, 0, 0 };\r
286                         const ScanCode *sc = i_key->getScanCodes();\r
287                         for (size_t i = 0; i < i_key->getScanCodesSize(); ++ i) {\r
288                                 kid.MakeCode = sc[i].m_scan;\r
289                                 kid.Flags = sc[i].m_flags;\r
290                                 if (!i_doPress)\r
291                                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
292 #ifdef NO_DRIVER\r
293                                 injectInput(&kid, NULL);\r
294 #else // !NO_DRIVER\r
295                                 DWORD len;\r
296                                 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
297                                 CHECK_TRUE( GetOverlappedResult(m_device, &m_ol, &len, TRUE) );\r
298 #endif // !NO_DRIVER\r
299                         }\r
300 \r
301                         m_lastGeneratedKey = i_doPress ? i_key : NULL;\r
302                 }\r
303         }\r
304 \r
305         {\r
306                 Acquire a(&m_log, 1);\r
307                 m_log << _T("\t\t    =>\t");\r
308                 if (isAlreadyReleased)\r
309                         m_log << _T("(already released) ");\r
310         }\r
311         ModifiedKey mkey(i_key);\r
312         mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
313         mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
314         outputToLog(i_key, mkey, 1);\r
315 }\r
316 \r
317 \r
318 // genete event\r
319 void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)\r
320 {\r
321         // generate\r
322         i_c.m_keymap = i_keymap;\r
323         i_c.m_mkey.m_key = i_event;\r
324         if (const Keymap::KeyAssignment *keyAssign =\r
325                                 i_c.m_keymap->searchAssignment(i_c.m_mkey)) {\r
326                 {\r
327                         Acquire a(&m_log, 1);\r
328                         m_log << std::endl << _T("           ")\r
329                         << i_event->getName() << std::endl;\r
330                 }\r
331                 generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
332         }\r
333 }\r
334 \r
335 \r
336 // genete modifier events\r
337 void Engine::generateModifierEvents(const Modifier &i_mod)\r
338 {\r
339         {\r
340                 Acquire a(&m_log, 1);\r
341                 m_log << _T("* Gen Modifiers\t{") << std::endl;\r
342         }\r
343 \r
344         for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i) {\r
345                 Keyboard::Mods &mods =\r
346                         m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));\r
347 \r
348                 if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))\r
349                         // no need to process\r
350                         ;\r
351                 else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))\r
352                         // we have to press this modifier\r
353                 {\r
354                         bool noneIsPressed = true;\r
355                         bool noneIsPressedByAssign = true;\r
356                         for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i) {\r
357                                 if ((*i)->m_isPressedOnWin32)\r
358                                         noneIsPressed = false;\r
359                                 if ((*i)->m_isPressedByAssign)\r
360                                         noneIsPressedByAssign = false;\r
361                         }\r
362                         if (noneIsPressed) {\r
363                                 if (noneIsPressedByAssign)\r
364                                         generateKeyEvent(mods.front(), true, false);\r
365                                 else\r
366                                         for (Keyboard::Mods::iterator\r
367                                                         i = mods.begin(); i != mods.end(); ++ i)\r
368                                                 if ((*i)->m_isPressedByAssign)\r
369                                                         generateKeyEvent((*i), true, false);\r
370                         }\r
371                 }\r
372 \r
373                 else\r
374                         // we have to release this modifier\r
375                 {\r
376                         // avoid such sequences as  "Alt U-ALt" or "Windows U-Windows"\r
377                         if (i == Modifier::Type_Alt || i == Modifier::Type_Windows) {\r
378                                 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)\r
379                                         if ((*j) == m_lastGeneratedKey) {\r
380                                                 Keyboard::Mods *mods =\r
381                                                         &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);\r
382                                                 if (mods->size() == 0)\r
383                                                         mods = &m_setting->m_keyboard.getModifiers(\r
384                                                                            Modifier::Type_Control);\r
385                                                 if (0 < mods->size()) {\r
386                                                         generateKeyEvent(mods->front(), true, false);\r
387                                                         generateKeyEvent(mods->front(), false, false);\r
388                                                 }\r
389                                                 break;\r
390                                         }\r
391                         }\r
392 \r
393                         for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j) {\r
394                                 if ((*j)->m_isPressedOnWin32)\r
395                                         generateKeyEvent((*j), false, false);\r
396                         }\r
397                 }\r
398         }\r
399 \r
400         {\r
401                 Acquire a(&m_log, 1);\r
402                 m_log << _T("\t\t}") << std::endl;\r
403         }\r
404 }\r
405 \r
406 \r
407 // generate keyboard events for action\r
408 void Engine::generateActionEvents(const Current &i_c, const Action *i_a,\r
409                                                                   bool i_doPress)\r
410 {\r
411         switch (i_a->getType()) {\r
412                 // key\r
413         case Action::Type_key: {\r
414                 const ModifiedKey &mkey\r
415                 = reinterpret_cast<ActionKey *>(\r
416                           const_cast<Action *>(i_a))->m_modifiedKey;\r
417 \r
418                 // release\r
419                 if (!i_doPress &&\r
420                                 (mkey.m_modifier.isOn(Modifier::Type_Up) ||\r
421                                  mkey.m_modifier.isDontcare(Modifier::Type_Up)))\r
422                         generateKeyEvent(mkey.m_key, false, true);\r
423 \r
424                 // press\r
425                 else if (i_doPress &&\r
426                                  (mkey.m_modifier.isOn(Modifier::Type_Down) ||\r
427                                   mkey.m_modifier.isDontcare(Modifier::Type_Down))) {\r
428                         Modifier modifier = mkey.m_modifier;\r
429                         modifier.add(i_c.m_mkey.m_modifier);\r
430                         generateModifierEvents(modifier);\r
431                         generateKeyEvent(mkey.m_key, true, true);\r
432                 }\r
433                 break;\r
434         }\r
435 \r
436         // keyseq\r
437         case Action::Type_keySeq: {\r
438                 const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);\r
439                 generateKeySeqEvents(i_c, aks->m_keySeq,\r
440                                                          i_doPress ? Part_down : Part_up);\r
441                 break;\r
442         }\r
443 \r
444         // function\r
445         case Action::Type_function: {\r
446                 const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);\r
447                 bool is_up = (!i_doPress &&\r
448                                           (af->m_modifier.isOn(Modifier::Type_Up) ||\r
449                                            af->m_modifier.isDontcare(Modifier::Type_Up)));\r
450                 bool is_down = (i_doPress &&\r
451                                                 (af->m_modifier.isOn(Modifier::Type_Down) ||\r
452                                                  af->m_modifier.isDontcare(Modifier::Type_Down)));\r
453 \r
454                 if (!is_down && !is_up)\r
455                         break;\r
456 \r
457                 {\r
458                         Acquire a(&m_log, 1);\r
459                         m_log << _T("\t\t     >\t") << af->m_functionData;\r
460                 }\r
461 \r
462                 FunctionParam param;\r
463                 param.m_isPressed = i_doPress;\r
464                 param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;\r
465                 param.m_c = i_c;\r
466                 param.m_doesNeedEndl = true;\r
467                 param.m_af = af;\r
468 \r
469                 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
470                 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
471 \r
472                 af->m_functionData->exec(this, &param);\r
473 \r
474                 if (param.m_doesNeedEndl) {\r
475                         Acquire a(&m_log, 1);\r
476                         m_log << std::endl;\r
477                 }\r
478                 break;\r
479         }\r
480         }\r
481 }\r
482 \r
483 \r
484 // generate keyboard events for keySeq\r
485 void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,\r
486                                                                   Part i_part)\r
487 {\r
488         const KeySeq::Actions &actions = i_keySeq->getActions();\r
489         if (actions.empty())\r
490                 return;\r
491         if (i_part == Part_up)\r
492                 generateActionEvents(i_c, actions[actions.size() - 1], false);\r
493         else {\r
494                 size_t i;\r
495                 for (i = 0 ; i < actions.size() - 1; ++ i) {\r
496                         generateActionEvents(i_c, actions[i], true);\r
497                         generateActionEvents(i_c, actions[i], false);\r
498                 }\r
499                 generateActionEvents(i_c, actions[i], true);\r
500                 if (i_part == Part_all)\r
501                         generateActionEvents(i_c, actions[i], false);\r
502         }\r
503 }\r
504 \r
505 \r
506 // generate keyboard events for current key\r
507 void Engine::generateKeyboardEvents(const Current &i_c)\r
508 {\r
509         if (++ m_generateKeyboardEventsRecursionGuard ==\r
510                         MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT) {\r
511                 Acquire a(&m_log);\r
512                 m_log << _T("error: too deep keymap recursion.  there may be a loop.")\r
513                 << std::endl;\r
514                 return;\r
515         }\r
516 \r
517         const Keymap::KeyAssignment *keyAssign\r
518         = i_c.m_keymap->searchAssignment(i_c.m_mkey);\r
519         if (!keyAssign) {\r
520                 const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();\r
521                 ASSERT( keySeq );\r
522                 generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);\r
523         } else {\r
524                 if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||\r
525                                 keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))\r
526                         generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
527                 else\r
528                         generateKeySeqEvents(i_c, keyAssign->m_keySeq,\r
529                                                                  i_c.isPressed() ? Part_down : Part_up);\r
530         }\r
531         m_generateKeyboardEventsRecursionGuard --;\r
532 }\r
533 \r
534 \r
535 // generate keyboard events for current key\r
536 void Engine::beginGeneratingKeyboardEvents(\r
537         const Current &i_c, bool i_isModifier)\r
538 {\r
539         //             (1)             (2)             (3)  (4)   (1)\r
540         // up/down:    D-              U-              D-   U-    D-\r
541         // keymap:     m_currentKeymap m_currentKeymap X    X     m_currentKeymap\r
542         // memo:       &Prefix(X)      ...             ...  ...   ...\r
543         // m_isPrefix: false           true            true false false\r
544 \r
545         Current cnew(i_c);\r
546 \r
547         bool isPhysicallyPressed\r
548         = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);\r
549 \r
550         // substitute\r
551         ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);\r
552         if (mkey.m_key) {\r
553                 cnew.m_mkey = mkey;\r
554                 if (isPhysicallyPressed) {\r
555                         cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
556                         cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
557                 } else {\r
558                         cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
559                         cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
560                 }\r
561                 for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {\r
562                         Modifier::Type type = static_cast<Modifier::Type>(i);\r
563                         if (cnew.m_mkey.m_modifier.isDontcare(type) &&\r
564                                         !i_c.m_mkey.m_modifier.isDontcare(type))\r
565                                 cnew.m_mkey.m_modifier.press(\r
566                                         type, i_c.m_mkey.m_modifier.isPressed(type));\r
567                 }\r
568 \r
569                 {\r
570                         Acquire a(&m_log, 1);\r
571                         m_log << _T("* substitute") << std::endl;\r
572                 }\r
573                 outputToLog(mkey.m_key, cnew.m_mkey, 1);\r
574         }\r
575 \r
576         // for prefix key\r
577         const Keymap *tmpKeymap = m_currentKeymap;\r
578         if (i_isModifier || !m_isPrefix) ;\r
579         else if (isPhysicallyPressed)                   // when (3)\r
580                 m_isPrefix = false;\r
581         else if (!isPhysicallyPressed)          // when (2)\r
582                 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
583 \r
584         // for m_emacsEditKillLine function\r
585         m_emacsEditKillLine.m_doForceReset = !i_isModifier;\r
586 \r
587         // generate key event !\r
588         m_generateKeyboardEventsRecursionGuard = 0;\r
589         if (isPhysicallyPressed)\r
590                 generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);\r
591         generateKeyboardEvents(cnew);\r
592         if (!isPhysicallyPressed)\r
593                 generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);\r
594 \r
595         // for m_emacsEditKillLine function\r
596         if (m_emacsEditKillLine.m_doForceReset)\r
597                 m_emacsEditKillLine.reset();\r
598 \r
599         // for prefix key\r
600         if (i_isModifier)\r
601                 ;\r
602         else if (!m_isPrefix)                           // when (1), (4)\r
603                 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
604         else if (!isPhysicallyPressed)          // when (2)\r
605                 m_currentKeymap = tmpKeymap;\r
606 }\r
607 \r
608 \r
609 #ifdef NO_DRIVER\r
610 unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)\r
611 {\r
612         if (i_kid->Flags & KEYBOARD_INPUT_DATA::E1) {\r
613                 Acquire a(&m_cskidq);\r
614                 INPUT kid[2];\r
615                 int count = 1;\r
616 \r
617                 kid[0].type = INPUT_MOUSE;\r
618                 kid[0].mi.dx = 0;\r
619                 kid[0].mi.dy = 0;\r
620                 kid[0].mi.time = 0;\r
621                 kid[0].mi.mouseData = 0;\r
622                 kid[0].mi.dwExtraInfo = 0;\r
623                 switch (i_kid->MakeCode) {\r
624                 case 1:\r
625                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
626                                 kid[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;\r
627                         } else {\r
628                                 kid[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;\r
629                         }\r
630                         break;\r
631                 case 2:\r
632                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
633                                 kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;\r
634                         } else {\r
635                                 kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;\r
636                         }\r
637                         break;\r
638                 case 3:\r
639                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
640                                 kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEUP;\r
641                         } else {\r
642                                 kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;\r
643                         }\r
644                         break;\r
645                 case 4:\r
646                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
647                                 return 1;\r
648                         } else {\r
649                                 kid[0].mi.mouseData = WHEEL_DELTA;\r
650                                 kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;\r
651                         }\r
652                         break;\r
653                 case 5:\r
654                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
655                                 return 1;\r
656                         } else {\r
657                                 kid[0].mi.mouseData = -WHEEL_DELTA;\r
658                                 kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;\r
659                         }\r
660                         break;\r
661                 case 6:\r
662                         kid[0].mi.mouseData = XBUTTON1;\r
663                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
664                                 kid[0].mi.dwFlags = MOUSEEVENTF_XUP;\r
665                         } else {\r
666                                 kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;\r
667                         }\r
668                         break;\r
669                 case 7:\r
670                         kid[0].mi.mouseData = XBUTTON2;\r
671                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
672                                 kid[0].mi.dwFlags = MOUSEEVENTF_XUP;\r
673                         } else {\r
674                                 kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;\r
675                         }\r
676                         break;\r
677                 case 8:\r
678                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
679                                 return 1;\r
680                         } else {\r
681                                 kid[0].mi.mouseData = WHEEL_DELTA;\r
682                                 kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;\r
683                         }\r
684                         break;\r
685                 case 9:\r
686                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
687                                 return 1;\r
688                         } else {\r
689                                 kid[0].mi.mouseData = -WHEEL_DELTA;\r
690                                 kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;\r
691                         }\r
692                         break;\r
693                 default:\r
694                         return 1;\r
695                         break;\r
696                 }\r
697                 if (!(i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) &&\r
698                         i_kid->MakeCode != 4 && i_kid->MakeCode != 5 &&\r
699                         i_kid->MakeCode != 8 && i_kid->MakeCode != 9) {\r
700                         HWND hwnd;\r
701                         POINT pt;\r
702 \r
703                         if (GetCursorPos(&pt) && (hwnd = WindowFromPoint(pt))) {\r
704                                 _TCHAR className[GANA_MAX_ATOM_LENGTH];\r
705                                 if (GetClassName(hwnd, className, NUMBER_OF(className))) {\r
706                                         if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {\r
707                                                 SetForegroundWindow(hwnd);\r
708                                         }\r
709                                 }\r
710                         }\r
711                         if (m_dragging) {\r
712                                 kid[0].mi.dx = 65535 * m_msllHookCurrent.pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
713                                 kid[0].mi.dy = 65535 * m_msllHookCurrent.pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
714                                 kid[0].mi.dwFlags |= MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;\r
715 \r
716                                 kid[1].type = INPUT_MOUSE;\r
717                                 kid[1].mi.dx = 65535 * pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
718                                 kid[1].mi.dy = 65535 * pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
719                                 kid[1].mi.time = 0;\r
720                                 kid[1].mi.mouseData = 0;\r
721                                 kid[1].mi.dwExtraInfo = 0;\r
722                                 kid[1].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;\r
723 \r
724                                 count = 2;\r
725                         }\r
726                 }\r
727                 SendInput(count, &kid[0], sizeof(kid[0]));\r
728         } else {\r
729                 INPUT kid;\r
730 \r
731                 kid.type = INPUT_KEYBOARD;\r
732                 kid.ki.wVk = 0;\r
733                 kid.ki.wScan = i_kid->MakeCode;\r
734                 kid.ki.dwFlags = KEYEVENTF_SCANCODE;\r
735                 kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;\r
736                 kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;\r
737                 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
738                         kid.ki.dwFlags |= KEYEVENTF_KEYUP;\r
739                 }\r
740                 if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0) {\r
741                         kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
742                 }\r
743                 SendInput(1, &kid, sizeof(kid));\r
744         }\r
745         return 1;\r
746 }\r
747 #endif // NO_DRIVER\r
748 \r
749 \r
750 // pop all pressed key on win32\r
751 void Engine::keyboardResetOnWin32()\r
752 {\r
753         for (Keyboard::KeyIterator\r
754                         i = m_setting->m_keyboard.getKeyIterator();  *i; ++ i) {\r
755                 if ((*i)->m_isPressedOnWin32)\r
756                         generateKeyEvent((*i), false, true);\r
757         }\r
758 }\r
759 \r
760 \r
761 #ifdef NO_DRIVER\r
762 unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)\r
763 {\r
764         return i_this->keyboardDetour(reinterpret_cast<KBDLLHOOKSTRUCT*>(i_lParam));\r
765 }\r
766 \r
767 unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)\r
768 {\r
769 #if 0\r
770         Acquire a(&m_log, 1);\r
771         m_log << std::hex\r
772         << _T("keyboardDetour: vkCode=") << i_kid->vkCode\r
773         << _T(" scanCode=") << i_kid->scanCode\r
774         << _T(" flags=") << i_kid->flags << std::endl;\r
775 #endif\r
776         if (i_kid->flags & LLKHF_INJECTED) {\r
777                 return 0;\r
778         } else {\r
779                 Key key;\r
780                 KEYBOARD_INPUT_DATA kid;\r
781 \r
782                 kid.UnitId = 0;\r
783                 kid.MakeCode = i_kid->scanCode;\r
784                 kid.Flags = 0;\r
785                 if (i_kid->flags & LLKHF_UP) {\r
786                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
787                 }\r
788                 if (i_kid->flags & LLKHF_EXTENDED) {\r
789                         kid.Flags |= KEYBOARD_INPUT_DATA::E0;\r
790                 }\r
791                 kid.Reserved = 0;\r
792                 kid.ExtraInformation = 0;\r
793 \r
794                 Acquire a(&m_cskidq);\r
795                 m_kidq.push_back(kid);\r
796                 SetEvent(m_readEvent);\r
797                 return 1;\r
798         }\r
799 }\r
800 \r
801 unsigned int WINAPI Engine::mouseDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)\r
802 {\r
803         return i_this->mouseDetour(i_wParam, reinterpret_cast<MSLLHOOKSTRUCT*>(i_lParam));\r
804 }\r
805 \r
806 unsigned int Engine::mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid)\r
807 {\r
808         if (i_mid->flags & LLMHF_INJECTED || !m_setting || !m_setting->m_mouseEvent) {\r
809                 return 0;\r
810         } else {\r
811                 KEYBOARD_INPUT_DATA kid;\r
812 \r
813                 kid.UnitId = 0;\r
814                 kid.Flags = KEYBOARD_INPUT_DATA::E1;\r
815                 kid.Reserved = 0;\r
816                 kid.ExtraInformation = 0;\r
817                 switch (i_message) {\r
818                 case WM_LBUTTONUP:\r
819                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
820                 case WM_LBUTTONDOWN:\r
821                         kid.MakeCode = 1;\r
822                         break;\r
823                 case WM_RBUTTONUP:\r
824                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
825                 case WM_RBUTTONDOWN:\r
826                         kid.MakeCode = 2;\r
827                         break;\r
828                 case WM_MBUTTONUP:\r
829                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
830                 case WM_MBUTTONDOWN:\r
831                         kid.MakeCode = 3;\r
832                         break;\r
833                 case WM_MOUSEWHEEL:\r
834                         if (i_mid->mouseData & (1<<31)) {\r
835                                 kid.MakeCode = 5;\r
836                         } else {\r
837                                 kid.MakeCode = 4;\r
838                         }\r
839                         break;\r
840                 case WM_XBUTTONUP:\r
841                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
842                 case WM_XBUTTONDOWN:\r
843                         switch ((i_mid->mouseData >> 16) & 0xFFFFU) {\r
844                         case XBUTTON1:\r
845                                 kid.MakeCode = 6;\r
846                                 break;\r
847                         case XBUTTON2:\r
848                                 kid.MakeCode = 7;\r
849                                 break;\r
850                         default:\r
851                                 return 0;\r
852                                 break;\r
853                         }\r
854                         break;\r
855                 case WM_MOUSEHWHEEL:\r
856                         if (i_mid->mouseData & (1<<31)) {\r
857                                 kid.MakeCode = 9;\r
858                         } else {\r
859                                 kid.MakeCode = 8;\r
860                         }\r
861                         break;\r
862                 case WM_MOUSEMOVE: {\r
863                         LONG dx = i_mid->pt.x - g_hookData->m_mousePos.x;\r
864                         LONG dy = i_mid->pt.y - g_hookData->m_mousePos.y;\r
865                         HWND target = reinterpret_cast<HWND>(g_hookData->m_hwndMouseHookTarget);\r
866 \r
867                         LONG dr = 0;\r
868                         dr += (i_mid->pt.x - m_msllHookCurrent.pt.x) * (i_mid->pt.x - m_msllHookCurrent.pt.x);\r
869                         dr += (i_mid->pt.y - m_msllHookCurrent.pt.y) * (i_mid->pt.y - m_msllHookCurrent.pt.y);\r
870                         if (m_buttonPressed && !m_dragging && m_setting->m_dragThreshold &&\r
871                                 (m_setting->m_dragThreshold * m_setting->m_dragThreshold < dr)) {\r
872                                 Acquire a(&m_cskidq);\r
873 \r
874                                 m_dragging = true;\r
875                                 kid.MakeCode = 0;\r
876                                 m_kidq.push_back(kid);\r
877                                 SetEvent(m_readEvent);\r
878                         }\r
879 \r
880                         switch (g_hookData->m_mouseHookType) {\r
881                         case MouseHookType_Wheel:\r
882                                 // For this type, g_hookData->m_mouseHookParam means\r
883                                 // translate rate mouse move to wheel.\r
884                                 mouse_event(MOUSEEVENTF_WHEEL, 0, 0,\r
885                                                         g_hookData->m_mouseHookParam * dy, 0);\r
886                                 return 1;\r
887                                 break;\r
888                         case MouseHookType_WindowMove: {\r
889                                 RECT curRect;\r
890 \r
891                                 if (!GetWindowRect(target, &curRect))\r
892                                         return 0;\r
893 \r
894                                 // g_hookData->m_mouseHookParam < 0 means\r
895                                 // target window to move is MDI.\r
896                                 if (g_hookData->m_mouseHookParam < 0) {\r
897                                         HWND parent = GetParent(target);\r
898                                         POINT p = {curRect.left, curRect.top};\r
899 \r
900                                         if (parent == NULL || !ScreenToClient(parent, &p))\r
901                                                 return 0;\r
902 \r
903                                         curRect.left = p.x;\r
904                                         curRect.top = p.y;\r
905                                 }\r
906 \r
907                                 SetWindowPos(target, NULL,\r
908                                                          curRect.left + dx,\r
909                                                          curRect.top + dy,\r
910                                                          0, 0,\r
911                                                          SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE |\r
912                                                          SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);\r
913                                 g_hookData->m_mousePos = i_mid->pt;\r
914                                 return 0;\r
915                                 break;\r
916                         }\r
917                         case MouseHookType_None:\r
918                         default:\r
919                                 return 0;\r
920                                 break;\r
921                         }\r
922                 }\r
923                 case WM_LBUTTONDBLCLK:\r
924                 case WM_RBUTTONDBLCLK:\r
925                 case WM_MBUTTONDBLCLK:\r
926                 case WM_XBUTTONDBLCLK:\r
927                 default:\r
928                         return 0;\r
929                         break;\r
930                 }\r
931 \r
932                 Acquire a(&m_cskidq);\r
933 \r
934                 if (kid.Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
935                         m_buttonPressed = false;\r
936                         if (m_dragging) {\r
937                                 KEYBOARD_INPUT_DATA kid2;\r
938 \r
939                                 m_dragging = false;\r
940                                 kid2.UnitId = 0;\r
941                                 kid2.Flags = KEYBOARD_INPUT_DATA::E1 | KEYBOARD_INPUT_DATA::BREAK;\r
942                                 kid2.Reserved = 0;\r
943                                 kid2.ExtraInformation = 0;\r
944                                 kid2.MakeCode = 0;\r
945                                 m_kidq.push_back(kid2);\r
946                                 SetEvent(m_readEvent);\r
947                         }\r
948                 } else if (i_message != WM_MOUSEWHEEL && i_message != WM_MOUSEHWHEEL) {\r
949                         m_buttonPressed = true;\r
950                         m_msllHookCurrent = *i_mid;\r
951                 }\r
952 \r
953                 m_kidq.push_back(kid);\r
954                 SetEvent(m_readEvent);\r
955 \r
956                 if (i_message == WM_MOUSEWHEEL || i_message == WM_MOUSEHWHEEL) {\r
957                         kid.UnitId = 0;\r
958                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
959                         kid.Reserved = 0;\r
960                         kid.ExtraInformation = 0;\r
961                         m_kidq.push_back(kid);\r
962                         SetEvent(m_readEvent);\r
963                 }\r
964 \r
965                 return 1;\r
966         }\r
967 }\r
968 #endif // NO_DRIVER\r
969 \r
970 // keyboard handler thread\r
971 unsigned int WINAPI Engine::keyboardHandler(void *i_this)\r
972 {\r
973         reinterpret_cast<Engine *>(i_this)->keyboardHandler();\r
974         _endthreadex(0);\r
975         return 0;\r
976 }\r
977 void Engine::keyboardHandler()\r
978 {\r
979         // initialize ok\r
980         CHECK_TRUE( SetEvent(m_threadEvent) );\r
981 \r
982         // loop\r
983         Key key;\r
984         while (!m_doForceTerminate) {\r
985                 KEYBOARD_INPUT_DATA kid;\r
986 \r
987 #ifndef NO_DRIVER\r
988                 DWORD len;\r
989 #endif // !NO_DRIVER\r
990                 {\r
991                         Acquire a(&m_log, 1);\r
992                         m_log << _T("begin ReadFile();") << std::endl;\r
993                 }\r
994 #ifdef NO_DRIVER\r
995                 if (1) {\r
996 #else // !NO_DRIVER\r
997                 if (!ReadFile(m_device, &kid, sizeof(kid), &len, &m_ol)) {\r
998                         if (GetLastError() != ERROR_IO_PENDING)\r
999                                 continue;\r
1000 #endif // !NO_DRIVER\r
1001 \r
1002                         HANDLE handles[] = { m_readEvent, m_interruptThreadEvent };\r
1003 rewait:\r
1004                         switch (MsgWaitForMultipleObjects(NUMBER_OF(handles), &handles[0],\r
1005                                                                                           FALSE, INFINITE, QS_POSTMESSAGE)) {\r
1006                         case WAIT_OBJECT_0:                     // m_readEvent\r
1007 #ifdef NO_DRIVER\r
1008                                 {\r
1009                                         Acquire a(&m_cskidq);\r
1010                                         if (m_kidq.empty()) {\r
1011                                                 goto rewait;\r
1012                                         }\r
1013                                         kid = m_kidq.front();\r
1014                                         m_kidq.pop_front();\r
1015                                         if (!m_kidq.empty()) {\r
1016                                                 SetEvent(m_readEvent);\r
1017                                         }\r
1018                                 }\r
1019 #else // !NO_DRIVER\r
1020                                 if (!GetOverlappedResult(m_device, &m_ol, &len, FALSE))\r
1021                                         continue;\r
1022 #endif // !NO_DRIVER\r
1023                                 break;\r
1024 \r
1025                         case WAIT_OBJECT_0 + 1:                 // m_interruptThreadEvent\r
1026                                 CancelIo(m_device);\r
1027                                 switch (m_interruptThreadReason) {\r
1028                                 default: {\r
1029                                         ASSERT( false );\r
1030                                         Acquire a(&m_log, 0);\r
1031                                         m_log << _T("internal error: m_interruptThreadReason == ")\r
1032                                         << m_interruptThreadReason << std::endl;\r
1033                                         break;\r
1034                                 }\r
1035 \r
1036                                 case InterruptThreadReason_Terminate:\r
1037                                         goto break_while;\r
1038 \r
1039                                 case InterruptThreadReason_Pause: {\r
1040                                         CHECK_TRUE( SetEvent(m_threadEvent) );\r
1041                                         while (WaitForMultipleObjects(1, &m_interruptThreadEvent,\r
1042                                                                                                   FALSE, INFINITE) != WAIT_OBJECT_0)\r
1043                                                 ;\r
1044                                         switch (m_interruptThreadReason) {\r
1045                                         case InterruptThreadReason_Terminate:\r
1046                                                 goto break_while;\r
1047 \r
1048                                         case InterruptThreadReason_Resume:\r
1049                                                 break;\r
1050 \r
1051                                         default:\r
1052                                                 ASSERT( false );\r
1053                                                 break;\r
1054                                         }\r
1055                                         CHECK_TRUE( SetEvent(m_threadEvent) );\r
1056                                         break;\r
1057                                 }\r
1058                                 }\r
1059                                 break;\r
1060 \r
1061                         case WAIT_OBJECT_0 + NUMBER_OF(handles): {\r
1062                                 MSG message;\r
1063 \r
1064                                 while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {\r
1065                                         switch (message.message) {\r
1066                                         case WM_APP + 201: {\r
1067                                                 if (message.wParam) {\r
1068                                                         m_currentLock.on(Modifier::Type_Touchpad);\r
1069                                                         m_currentLock.on(Modifier::Type_TouchpadSticky);\r
1070                                                 } else\r
1071                                                         m_currentLock.off(Modifier::Type_Touchpad);\r
1072                                                 Acquire a(&m_log, 1);\r
1073                                                 m_log << _T("touchpad: ") << message.wParam\r
1074                                                 << _T(".") << (message.lParam & 0xffff)\r
1075                                                 << _T(".") << (message.lParam >> 16 & 0xffff)\r
1076                                                 << std::endl;\r
1077                                                 break;\r
1078                                         }\r
1079                                         default:\r
1080                                                 break;\r
1081                                         }\r
1082                                 }\r
1083                                 goto rewait;\r
1084                         }\r
1085 \r
1086                         default:\r
1087                                 ASSERT( false );\r
1088                                 continue;\r
1089                         }\r
1090                 }\r
1091                 {\r
1092                         Acquire a(&m_log, 1);\r
1093                         m_log << _T("end ReadFile();") << std::endl;\r
1094                 }\r
1095 \r
1096                 checkFocusWindow();\r
1097 \r
1098                 if (!m_setting ||       // m_setting has not been loaded\r
1099                                 !m_isEnabled) { // disabled\r
1100                         if (m_isLogMode) {\r
1101                                 Key key;\r
1102                                 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
1103                                 outputToLog(&key, ModifiedKey(), 0);\r
1104                                 if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
1105                                         // through mouse event even if log mode\r
1106                                         injectInput(&kid, NULL);\r
1107                                 }\r
1108                         } else {\r
1109 #ifdef NO_DRIVER\r
1110                                 injectInput(&kid, NULL);\r
1111 #else // !NO_DRIVER\r
1112                                 WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
1113                                 GetOverlappedResult(m_device, &m_ol, &len, TRUE);\r
1114 #endif // !NO_DRIVER\r
1115                         }\r
1116                         updateLastPressedKey(NULL);\r
1117                         continue;\r
1118                 }\r
1119 \r
1120                 Acquire a(&m_cs);\r
1121 \r
1122                 if (!m_currentFocusOfThread ||\r
1123                                 !m_currentKeymap) {\r
1124 #ifdef NO_DRIVER\r
1125                         injectInput(&kid, NULL);\r
1126 #else\r
1127                         WriteFile(m_device, &kid, sizeof(kid), &len, &m_ol);\r
1128                         GetOverlappedResult(m_device, &m_ol, &len, TRUE);\r
1129 #endif // !NO_DRIVER\r
1130                         Acquire a(&m_log, 0);\r
1131                         if (!m_currentFocusOfThread)\r
1132                                 m_log << _T("internal error: m_currentFocusOfThread == NULL")\r
1133                                 << std::endl;\r
1134                         if (!m_currentKeymap)\r
1135                                 m_log << _T("internal error: m_currentKeymap == NULL")\r
1136                                 << std::endl;\r
1137                         updateLastPressedKey(NULL);\r
1138                         continue;\r
1139                 }\r
1140 \r
1141                 Current c;\r
1142                 c.m_keymap = m_currentKeymap;\r
1143                 c.m_i = m_currentFocusOfThread->m_keymaps.begin();\r
1144 \r
1145                 // search key\r
1146                 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
1147                 c.m_mkey = m_setting->m_keyboard.searchKey(key);\r
1148                 if (!c.m_mkey.m_key) {\r
1149                         c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);\r
1150                         if (c.m_mkey.m_key)\r
1151                                 continue;\r
1152                 }\r
1153 \r
1154                 // press the key and update counter\r
1155                 bool isPhysicallyPressed\r
1156                 = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);\r
1157                 if (c.m_mkey.m_key) {\r
1158                         if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)\r
1159                                 ++ m_currentKeyPressCount;\r
1160                         else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)\r
1161                                 -- m_currentKeyPressCount;\r
1162                         c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;\r
1163                 }\r
1164 \r
1165                 // create modifiers\r
1166                 c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,\r
1167                                                           isPhysicallyPressed);\r
1168                 Keymap::AssignMode am;\r
1169                 bool isModifier = fixModifierKey(&c.m_mkey, &am);\r
1170                 if (m_isPrefix) {\r
1171                         if (isModifier && m_doesIgnoreModifierForPrefix)\r
1172                                 am = Keymap::AM_true;\r
1173                         if (m_doesEditNextModifier) {\r
1174                                 Modifier modifier = m_modifierForNextKey;\r
1175                                 modifier.add(c.m_mkey.m_modifier);\r
1176                                 c.m_mkey.m_modifier = modifier;\r
1177                         }\r
1178                 }\r
1179 \r
1180                 if (m_isLogMode) {\r
1181                         outputToLog(&key, c.m_mkey, 0);\r
1182                         if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
1183                                 // through mouse event even if log mode\r
1184                                 injectInput(&kid, NULL);\r
1185                         }\r
1186                 } else if (am == Keymap::AM_true) {\r
1187                         {\r
1188                                 Acquire a(&m_log, 1);\r
1189                                 m_log << _T("* true modifier") << std::endl;\r
1190                         }\r
1191                         // true modifier doesn't generate scan code\r
1192                         outputToLog(&key, c.m_mkey, 1);\r
1193                 } else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable) {\r
1194                         {\r
1195                                 Acquire a(&m_log, 1);\r
1196                                 if (am == Keymap::AM_oneShot)\r
1197                                         m_log << _T("* one shot modifier") << std::endl;\r
1198                                 else\r
1199                                         m_log << _T("* one shot repeatable modifier") << std::endl;\r
1200                         }\r
1201                         // oneShot modifier doesn't generate scan code\r
1202                         outputToLog(&key, c.m_mkey, 1);\r
1203                         if (isPhysicallyPressed) {\r
1204                                 if (am == Keymap::AM_oneShotRepeatable  // the key is repeating\r
1205                                                 && m_oneShotKey.m_key == c.m_mkey.m_key) {\r
1206                                         if (m_oneShotRepeatableRepeatCount <\r
1207                                                         m_setting->m_oneShotRepeatableDelay) {\r
1208                                                 ; // delay\r
1209                                         } else {\r
1210                                                 Current cnew = c;\r
1211                                                 beginGeneratingKeyboardEvents(cnew, false);\r
1212                                         }\r
1213                                         ++ m_oneShotRepeatableRepeatCount;\r
1214                                 } else {\r
1215                                         m_oneShotKey = c.m_mkey;\r
1216                                         m_oneShotRepeatableRepeatCount = 0;\r
1217                                 }\r
1218                         } else {\r
1219                                 if (m_oneShotKey.m_key) {\r
1220                                         Current cnew = c;\r
1221                                         cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
1222                                         cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
1223                                         cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
1224                                         beginGeneratingKeyboardEvents(cnew, false);\r
1225 \r
1226                                         cnew = c;\r
1227                                         cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
1228                                         cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
1229                                         cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
1230                                         beginGeneratingKeyboardEvents(cnew, false);\r
1231                                 }\r
1232                                 m_oneShotKey.m_key = NULL;\r
1233                                 m_oneShotRepeatableRepeatCount = 0;\r
1234                         }\r
1235                 } else if (c.m_mkey.m_key) {\r
1236                         // normal key\r
1237                         outputToLog(&key, c.m_mkey, 1);\r
1238                         if (isPhysicallyPressed)\r
1239                                 m_oneShotKey.m_key = NULL;\r
1240                         beginGeneratingKeyboardEvents(c, isModifier);\r
1241                 } else {\r
1242                         // undefined key\r
1243                         if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
1244                                 // through mouse event even if undefined for fail safe\r
1245                                 injectInput(&kid, NULL);\r
1246                         }\r
1247                 }\r
1248 \r
1249                 // if counter is zero, reset modifiers and keys on win32\r
1250                 if (m_currentKeyPressCount <= 0) {\r
1251                         {\r
1252                                 Acquire a(&m_log, 1);\r
1253                                 m_log << _T("* No key is pressed") << std::endl;\r
1254                         }\r
1255                         generateModifierEvents(Modifier());\r
1256                         if (0 < m_currentKeyPressCountOnWin32)\r
1257                                 keyboardResetOnWin32();\r
1258                         m_currentKeyPressCount = 0;\r
1259                         m_currentKeyPressCountOnWin32 = 0;\r
1260                         m_oneShotKey.m_key = NULL;\r
1261                         if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)\r
1262                                 m_currentLock.off(Modifier::Type_TouchpadSticky);\r
1263                 }\r
1264 \r
1265                 key.initialize();\r
1266                 updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);\r
1267         }\r
1268 break_while:\r
1269         CHECK_TRUE( SetEvent(m_threadEvent) );\r
1270 }\r
1271 \r
1272 \r
1273 Engine::Engine(tomsgstream &i_log)\r
1274                 : m_hwndAssocWindow(NULL),\r
1275                 m_setting(NULL),\r
1276                 m_device(INVALID_HANDLE_VALUE),\r
1277                 m_didMayuStartDevice(false),\r
1278                 m_threadEvent(NULL),\r
1279                 m_mayudVersion(_T("unknown")),\r
1280                 m_buttonPressed(false),\r
1281                 m_dragging(false),\r
1282                 m_keyboardHandler(installKeyboardHook, Engine::keyboardDetour),\r
1283                 m_mouseHandler(installMouseHook, Engine::mouseDetour),\r
1284                 m_readEvent(NULL),\r
1285                 m_interruptThreadEvent(NULL),\r
1286                 m_sts4mayu(NULL),\r
1287                 m_cts4mayu(NULL),\r
1288                 m_doForceTerminate(false),\r
1289                 m_isLogMode(false),\r
1290                 m_isEnabled(true),\r
1291                 m_isSynchronizing(false),\r
1292                 m_eSync(NULL),\r
1293                 m_generateKeyboardEventsRecursionGuard(0),\r
1294                 m_currentKeyPressCount(0),\r
1295                 m_currentKeyPressCountOnWin32(0),\r
1296                 m_lastGeneratedKey(NULL),\r
1297                 m_oneShotRepeatableRepeatCount(0),\r
1298                 m_isPrefix(false),\r
1299                 m_currentKeymap(NULL),\r
1300                 m_currentFocusOfThread(NULL),\r
1301                 m_hwndFocus(NULL),\r
1302                 m_afShellExecute(NULL),\r
1303                 m_variable(0),\r
1304                 m_log(i_log) {\r
1305         for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
1306                 m_lastPressedKey[i] = NULL;\r
1307 \r
1308         // set default lock state\r
1309         for (int i = 0; i < Modifier::Type_end; ++ i)\r
1310                 m_currentLock.dontcare(static_cast<Modifier::Type>(i));\r
1311         for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)\r
1312                 m_currentLock.release(static_cast<Modifier::Type>(i));\r
1313 \r
1314 #ifndef NO_DRIVER\r
1315         if (!open()) {\r
1316                 throw ErrorMessage() << loadString(IDS_driverNotInstalled);\r
1317         }\r
1318 #endif // !NO_DRIVER\r
1319 \r
1320 #ifndef NO_DRIVER\r
1321         {\r
1322                 TCHAR versionBuf[256];\r
1323                 DWORD length = 0;\r
1324 \r
1325                 if (DeviceIoControl(m_device, IOCTL_MAYU_GET_VERSION, NULL, 0,\r
1326                                                         versionBuf, sizeof(versionBuf), &length, NULL)\r
1327                                 && length\r
1328                                 && length < sizeof(versionBuf))                 // fail safe\r
1329                         m_mayudVersion = tstring(versionBuf, length / 2);\r
1330         }\r
1331 #endif // !NO_DRIVER\r
1332         // create event for sync\r
1333         CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1334         // create named pipe for &SetImeString\r
1335         m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),\r
1336                                                                  PIPE_ACCESS_OUTBOUND,\r
1337                                                                  PIPE_TYPE_BYTE, 1,\r
1338                                                                  0, 0, 0, NULL);\r
1339         StrExprArg::setEngine(this);\r
1340 \r
1341         m_msllHookCurrent.pt.x = 0;\r
1342         m_msllHookCurrent.pt.y = 0;\r
1343         m_msllHookCurrent.mouseData = 0;\r
1344         m_msllHookCurrent.flags = 0;\r
1345         m_msllHookCurrent.time = 0;\r
1346         m_msllHookCurrent.dwExtraInfo = 0;\r
1347 }\r
1348 \r
1349 \r
1350 // open mayu device\r
1351 bool Engine::open() {\r
1352         // open mayu m_device\r
1353 #ifndef NO_DRIVER\r
1354         m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,\r
1355                                                   0, NULL, OPEN_EXISTING,\r
1356                                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);\r
1357 #endif // !NO_DRIVER\r
1358 \r
1359         if (m_device != INVALID_HANDLE_VALUE) {\r
1360                 return true;\r
1361         }\r
1362 \r
1363 #ifndef NO_DRIVER\r
1364         // start mayud\r
1365         SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
1366         if (hscm) {\r
1367                 SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_START);\r
1368                 if (hs) {\r
1369                         StartService(hs, 0, NULL);\r
1370                         CloseServiceHandle(hs);\r
1371                         m_didMayuStartDevice = true;\r
1372                 }\r
1373                 CloseServiceHandle(hscm);\r
1374         }\r
1375 \r
1376         // open mayu m_device\r
1377         m_device = CreateFile(MAYU_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,\r
1378                                                   0, NULL, OPEN_EXISTING,\r
1379                                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);\r
1380 #endif // !NO_DRIVER\r
1381         return (m_device != INVALID_HANDLE_VALUE);\r
1382 }\r
1383 \r
1384 \r
1385 // close mayu device\r
1386 void Engine::close() {\r
1387         if (m_device != INVALID_HANDLE_VALUE) {\r
1388 #ifndef NO_DRIVER\r
1389                 CHECK_TRUE( CloseHandle(m_device) );\r
1390 #endif // !NO_DRIVER\r
1391         }\r
1392         m_device = INVALID_HANDLE_VALUE;\r
1393 }\r
1394 \r
1395 \r
1396 // start keyboard handler thread\r
1397 void Engine::start() {\r
1398         m_keyboardHandler.start(this);\r
1399         m_mouseHandler.start(this);\r
1400         CHECK_TRUE( m_threadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1401 \r
1402         CHECK_TRUE( m_readEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1403         CHECK_TRUE( m_interruptThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1404         m_ol.Offset = 0;\r
1405         m_ol.OffsetHigh = 0;\r
1406         m_ol.hEvent = m_readEvent;\r
1407 \r
1408         CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );\r
1409         CHECK( WAIT_OBJECT_0 ==, WaitForSingleObject(m_threadEvent, INFINITE) );\r
1410 }\r
1411 \r
1412 \r
1413 // stop keyboard handler thread\r
1414 void Engine::stop() {\r
1415         if (m_threadEvent) {\r
1416                 m_doForceTerminate = true;\r
1417                 do {\r
1418                         m_interruptThreadReason = InterruptThreadReason_Terminate;\r
1419                         SetEvent(m_interruptThreadEvent);\r
1420                         //DWORD buf;\r
1421                         //M_DeviceIoControl(m_device, IOCTL_MAYU_DETOUR_CANCEL,\r
1422                         //                &buf, sizeof(buf), &buf, sizeof(buf), &buf, NULL);\r
1423 \r
1424                         // wait for message handler thread terminate\r
1425                 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
1426                 CHECK_TRUE( CloseHandle(m_threadEvent) );\r
1427                 m_threadEvent = NULL;\r
1428                 WaitForSingleObject(m_threadHandle, 100);\r
1429                 CHECK_TRUE( CloseHandle(m_threadHandle) );\r
1430                 m_threadHandle = NULL;\r
1431 \r
1432                 // stop mayud\r
1433                 if (m_didMayuStartDevice) {\r
1434                         SC_HANDLE hscm = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);\r
1435                         if (hscm) {\r
1436                                 SC_HANDLE hs = OpenService(hscm, MAYU_DRIVER_NAME, SERVICE_STOP);\r
1437                                 if (hs) {\r
1438                                         SERVICE_STATUS ss;\r
1439                                         ControlService(hs, SERVICE_CONTROL_STOP, &ss);\r
1440                                         CloseServiceHandle(hs);\r
1441                                 }\r
1442                                 CloseServiceHandle(hscm);\r
1443                         }\r
1444                 }\r
1445 \r
1446                 CHECK_TRUE( CloseHandle(m_readEvent) );\r
1447                 m_readEvent = NULL;\r
1448                 CHECK_TRUE( CloseHandle(m_interruptThreadEvent) );\r
1449                 m_interruptThreadEvent = NULL;\r
1450         }\r
1451         m_mouseHandler.stop();\r
1452         m_keyboardHandler.stop();\r
1453 }\r
1454 \r
1455 bool Engine::pause() {\r
1456         if (m_device != INVALID_HANDLE_VALUE) {\r
1457                 do {\r
1458                         m_interruptThreadReason = InterruptThreadReason_Pause;\r
1459                         SetEvent(m_interruptThreadEvent);\r
1460                 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
1461 #ifndef NO_DRIVER\r
1462                 close();\r
1463 #endif // !NO_DRIVER\r
1464         }\r
1465         return true;\r
1466 }\r
1467 \r
1468 \r
1469 bool Engine::resume() {\r
1470         if (m_device == INVALID_HANDLE_VALUE) {\r
1471 #ifndef NO_DRIVER\r
1472                 if (!open()) {\r
1473                         return false;                           // FIXME\r
1474                 }\r
1475 #endif // !NO_DRIVER\r
1476                 do {\r
1477                         m_interruptThreadReason = InterruptThreadReason_Resume;\r
1478                         SetEvent(m_interruptThreadEvent);\r
1479                 } while (WaitForSingleObject(m_threadEvent, 100) != WAIT_OBJECT_0);\r
1480         }\r
1481         return true;\r
1482 }\r
1483 \r
1484 \r
1485 bool Engine::prepairQuit() {\r
1486         // terminate and unload DLL for ThumbSense support if loaded\r
1487         manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
1488                                   false, &m_sts4mayu);\r
1489         manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
1490                                   false, &m_cts4mayu);\r
1491         return true;\r
1492 }\r
1493 \r
1494 \r
1495 Engine::~Engine() {\r
1496         stop();\r
1497         CHECK_TRUE( CloseHandle(m_eSync) );\r
1498 \r
1499         // close m_device\r
1500 #ifndef NO_DRIVER\r
1501         close();\r
1502 #endif // !NO_DRIVER\r
1503         // destroy named pipe for &SetImeString\r
1504         if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE) {\r
1505                 DisconnectNamedPipe(m_hookPipe);\r
1506                 CHECK_TRUE( CloseHandle(m_hookPipe) );\r
1507         }\r
1508 }\r
1509 \r
1510 \r
1511 void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,\r
1512                                                    TCHAR *i_dependDllName,\r
1513                                                    bool i_load, HMODULE *i_pTs4mayu) {\r
1514         Acquire a(&m_log, 0);\r
1515 \r
1516         if (i_load == false) {\r
1517                 if (*i_pTs4mayu) {\r
1518                         bool (WINAPI *pTs4mayuTerm)();\r
1519 \r
1520                         pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");\r
1521                         if (pTs4mayuTerm() == true)\r
1522                                 FreeLibrary(*i_pTs4mayu);\r
1523                         *i_pTs4mayu = NULL;\r
1524                         m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;\r
1525                 }\r
1526         } else {\r
1527                 if (*i_pTs4mayu) {\r
1528                         m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;\r
1529                 } else {\r
1530                         if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0) {\r
1531                                 m_log << _T("load ") << i_ts4mayuDllName\r
1532                                 << _T(" failed: can't find ") << i_dependDllName\r
1533                                 << std::endl;\r
1534                         } else {\r
1535                                 *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);\r
1536                                 if (*i_pTs4mayu == NULL) {\r
1537                                         m_log << _T("load ") << i_ts4mayuDllName\r
1538                                         << _T(" failed: can't find it") << std::endl;\r
1539                                 } else {\r
1540                                         bool (WINAPI *pTs4mayuInit)(UINT);\r
1541 \r
1542                                         pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");\r
1543                                         if (pTs4mayuInit(m_threadId) == true)\r
1544                                                 m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;\r
1545                                         else\r
1546                                                 m_log << i_ts4mayuDllName\r
1547                                                 <<_T(" load failed: can't initialize") << std::endl;\r
1548                                 }\r
1549                         }\r
1550                 }\r
1551         }\r
1552 }\r
1553 \r
1554 \r
1555 // set m_setting\r
1556 bool Engine::setSetting(Setting *i_setting) {\r
1557         Acquire a(&m_cs);\r
1558         if (m_isSynchronizing)\r
1559                 return false;\r
1560 \r
1561         if (m_setting) {\r
1562                 for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();\r
1563                                 *i; ++ i) {\r
1564                         Key *key = i_setting->m_keyboard.searchKey(*(*i));\r
1565                         if (key) {\r
1566                                 key->m_isPressed = (*i)->m_isPressed;\r
1567                                 key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;\r
1568                                 key->m_isPressedByAssign = (*i)->m_isPressedByAssign;\r
1569                         }\r
1570                 }\r
1571                 if (m_lastGeneratedKey)\r
1572                         m_lastGeneratedKey =\r
1573                                 i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);\r
1574                 for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
1575                         if (m_lastPressedKey[i])\r
1576                                 m_lastPressedKey[i] =\r
1577                                         i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);\r
1578         }\r
1579 \r
1580         m_setting = i_setting;\r
1581 \r
1582         manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
1583                                   m_setting->m_sts4mayu, &m_sts4mayu);\r
1584         manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
1585                                   m_setting->m_cts4mayu, &m_cts4mayu);\r
1586 \r
1587         g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;\r
1588         if (m_currentFocusOfThread) {\r
1589                 for (FocusOfThreads::iterator i = m_focusOfThreads.begin();\r
1590                                 i != m_focusOfThreads.end(); i ++) {\r
1591                         FocusOfThread *fot = &(*i).second;\r
1592                         m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
1593                                                                                           fot->m_className, fot->m_titleName);\r
1594                 }\r
1595         }\r
1596         m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));\r
1597         if (m_globalFocus.m_keymaps.empty()) {\r
1598                 Acquire a(&m_log, 0);\r
1599                 m_log << _T("internal error: m_globalFocus.m_keymap is empty")\r
1600                 << std::endl;\r
1601         }\r
1602         m_currentFocusOfThread = &m_globalFocus;\r
1603         setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
1604         m_hwndFocus = NULL;\r
1605         return true;\r
1606 }\r
1607 \r
1608 \r
1609 void Engine::checkShow(HWND i_hwnd) {\r
1610         // update show style of window\r
1611         // this update should be done in hook DLL, but to\r
1612         // avoid update-loss for some applications(such as\r
1613         // cmd.exe), we update here.\r
1614         bool isMaximized = false;\r
1615         bool isMinimized = false;\r
1616         bool isMDIMaximized = false;\r
1617         bool isMDIMinimized = false;\r
1618         while (i_hwnd) {\r
1619 #ifdef MAYU64\r
1620                 LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);\r
1621 #else\r
1622                 LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);\r
1623 #endif\r
1624                 if (exStyle & WS_EX_MDICHILD) {\r
1625                         WINDOWPLACEMENT placement;\r
1626                         placement.length = sizeof(WINDOWPLACEMENT);\r
1627                         if (GetWindowPlacement(i_hwnd, &placement)) {\r
1628                                 switch (placement.showCmd) {\r
1629                                 case SW_SHOWMAXIMIZED:\r
1630                                         isMDIMaximized = true;\r
1631                                         break;\r
1632                                 case SW_SHOWMINIMIZED:\r
1633                                         isMDIMinimized = true;\r
1634                                         break;\r
1635                                 case SW_SHOWNORMAL:\r
1636                                 default:\r
1637                                         break;\r
1638                                 }\r
1639                         }\r
1640                 }\r
1641 \r
1642 #ifdef MAYU64\r
1643                 LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
1644 #else\r
1645                 LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
1646 #endif\r
1647                 if ((style & WS_CHILD) == 0) {\r
1648                         WINDOWPLACEMENT placement;\r
1649                         placement.length = sizeof(WINDOWPLACEMENT);\r
1650                         if (GetWindowPlacement(i_hwnd, &placement)) {\r
1651                                 switch (placement.showCmd) {\r
1652                                 case SW_SHOWMAXIMIZED:\r
1653                                         isMaximized = true;\r
1654                                         break;\r
1655                                 case SW_SHOWMINIMIZED:\r
1656                                         isMinimized = true;\r
1657                                         break;\r
1658                                 case SW_SHOWNORMAL:\r
1659                                 default:\r
1660                                         break;\r
1661                                 }\r
1662                         }\r
1663                 }\r
1664                 i_hwnd = GetParent(i_hwnd);\r
1665         }\r
1666         setShow(isMDIMaximized, isMDIMinimized, true);\r
1667         setShow(isMaximized, isMinimized, false);\r
1668 }\r
1669 \r
1670 \r
1671 // focus\r
1672 bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId,\r
1673                                           const tstringi &i_className, const tstringi &i_titleName,\r
1674                                           bool i_isConsole) {\r
1675         Acquire a(&m_cs);\r
1676         if (m_isSynchronizing)\r
1677                 return false;\r
1678         if (i_hwndFocus == NULL)\r
1679                 return true;\r
1680 \r
1681         // remove newly created thread's id from m_detachedThreadIds\r
1682         if (!m_detachedThreadIds.empty()) {\r
1683                 DetachedThreadIds::iterator i;\r
1684                 bool retry;\r
1685                 do {\r
1686                         retry = false;\r
1687                         for (i = m_detachedThreadIds.begin();\r
1688                                         i != m_detachedThreadIds.end(); ++ i)\r
1689                                 if (*i == i_threadId) {\r
1690                                         m_detachedThreadIds.erase(i);\r
1691                                         retry = true;\r
1692                                         break;\r
1693                                 }\r
1694                 } while (retry);\r
1695         }\r
1696 \r
1697         FocusOfThread *fot;\r
1698         FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);\r
1699         if (i != m_focusOfThreads.end()) {\r
1700                 fot = &(*i).second;\r
1701                 if (fot->m_hwndFocus == i_hwndFocus &&\r
1702                                 fot->m_isConsole == i_isConsole &&\r
1703                                 fot->m_className == i_className &&\r
1704                                 fot->m_titleName == i_titleName)\r
1705                         return true;\r
1706         } else {\r
1707                 i = m_focusOfThreads.insert(\r
1708                                 FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;\r
1709                 fot = &(*i).second;\r
1710                 fot->m_threadId = i_threadId;\r
1711         }\r
1712         fot->m_hwndFocus = i_hwndFocus;\r
1713         fot->m_isConsole = i_isConsole;\r
1714         fot->m_className = i_className;\r
1715         fot->m_titleName = i_titleName;\r
1716 \r
1717         if (m_setting) {\r
1718                 m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
1719                                                                                   i_className, i_titleName);\r
1720                 ASSERT(0 < fot->m_keymaps.size());\r
1721         } else\r
1722                 fot->m_keymaps.clear();\r
1723         checkShow(i_hwndFocus);\r
1724         return true;\r
1725 }\r
1726 \r
1727 \r
1728 // lock state\r
1729 bool Engine::setLockState(bool i_isNumLockToggled,\r
1730                                                   bool i_isCapsLockToggled,\r
1731                                                   bool i_isScrollLockToggled,\r
1732                                                   bool i_isKanaLockToggled,\r
1733                                                   bool i_isImeLockToggled,\r
1734                                                   bool i_isImeCompToggled) {\r
1735         Acquire a(&m_cs);\r
1736         if (m_isSynchronizing)\r
1737                 return false;\r
1738         m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);\r
1739         m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);\r
1740         m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);\r
1741         m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);\r
1742         m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);\r
1743         m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);\r
1744         return true;\r
1745 }\r
1746 \r
1747 \r
1748 // show\r
1749 bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,\r
1750                                          bool i_isMDI) {\r
1751         Acquire a(&m_cs);\r
1752         if (m_isSynchronizing)\r
1753                 return false;\r
1754         Acquire b(&m_log, 1);\r
1755         Modifier::Type max, min;\r
1756         if (i_isMDI == true) {\r
1757                 max = Modifier::Type_MdiMaximized;\r
1758                 min = Modifier::Type_MdiMinimized;\r
1759         } else {\r
1760                 max = Modifier::Type_Maximized;\r
1761                 min = Modifier::Type_Minimized;\r
1762         }\r
1763         m_currentLock.on(max, i_isMaximized);\r
1764         m_currentLock.on(min, i_isMinimized);\r
1765         m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :\r
1766                                                                         i_isMinimized ? _T("Minimized") : _T("Normal"));\r
1767         if (i_isMDI == true) {\r
1768                 m_log << _T(" (MDI)");\r
1769         }\r
1770         m_log << std::endl;\r
1771         return true;\r
1772 }\r
1773 \r
1774 \r
1775 // sync\r
1776 bool Engine::syncNotify() {\r
1777         Acquire a(&m_cs);\r
1778         if (!m_isSynchronizing)\r
1779                 return false;\r
1780         CHECK_TRUE( SetEvent(m_eSync) );\r
1781         return true;\r
1782 }\r
1783 \r
1784 \r
1785 // thread detach notify\r
1786 bool Engine::threadDetachNotify(DWORD i_threadId) {\r
1787         Acquire a(&m_cs);\r
1788         m_detachedThreadIds.push_back(i_threadId);\r
1789         return true;\r
1790 }\r
1791 \r
1792 \r
1793 // get help message\r
1794 void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle) {\r
1795         Acquire a(&m_cs);\r
1796         *o_helpMessage = m_helpMessage;\r
1797         *o_helpTitle = m_helpTitle;\r
1798 }\r
1799 \r
1800 \r
1801 // command notify\r
1802 void Engine::commandNotify(\r
1803         HWND i_hwnd, UINT i_message, WPARAM i_wParam, LPARAM i_lParam) {\r
1804         Acquire b(&m_log, 0);\r
1805         HWND hf = m_hwndFocus;\r
1806         if (!hf)\r
1807                 return;\r
1808 \r
1809         if (GetWindowThreadProcessId(hf, NULL) ==\r
1810                         GetWindowThreadProcessId(m_hwndAssocWindow, NULL))\r
1811                 return; // inhibit the investigation of MADO TSUKAI NO YUUTSU\r
1812 \r
1813         const _TCHAR *target = NULL;\r
1814         int number_target = 0;\r
1815 \r
1816         if (i_hwnd == hf)\r
1817                 target = _T("ToItself");\r
1818         else if (i_hwnd == GetParent(hf))\r
1819                 target = _T("ToParentWindow");\r
1820         else {\r
1821                 // Function::toMainWindow\r
1822                 HWND h = hf;\r
1823                 while (true) {\r
1824                         HWND p = GetParent(h);\r
1825                         if (!p)\r
1826                                 break;\r
1827                         h = p;\r
1828                 }\r
1829                 if (i_hwnd == h)\r
1830                         target = _T("ToMainWindow");\r
1831                 else {\r
1832                         // Function::toOverlappedWindow\r
1833                         HWND h = hf;\r
1834                         while (h) {\r
1835 #ifdef MAYU64\r
1836                                 LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);\r
1837 #else\r
1838                                 LONG style = GetWindowLong(h, GWL_STYLE);\r
1839 #endif\r
1840                                 if ((style & WS_CHILD) == 0)\r
1841                                         break;\r
1842                                 h = GetParent(h);\r
1843                         }\r
1844                         if (i_hwnd == h)\r
1845                                 target = _T("ToOverlappedWindow");\r
1846                         else {\r
1847                                 // number\r
1848                                 HWND h = hf;\r
1849                                 for (number_target = 0; h; number_target ++, h = GetParent(h))\r
1850                                         if (i_hwnd == h)\r
1851                                                 break;\r
1852                                 return;\r
1853                         }\r
1854                 }\r
1855         }\r
1856 \r
1857         m_log << _T("&PostMessage(");\r
1858         if (target)\r
1859                 m_log << target;\r
1860         else\r
1861                 m_log << number_target;\r
1862         m_log << _T(", ") << i_message\r
1863         << _T(", 0x") << std::hex << i_wParam\r
1864         << _T(", 0x") << i_lParam << _T(") # hwnd = ")\r
1865         << reinterpret_cast<int>(i_hwnd) << _T(", ")\r
1866         << _T("message = ") << std::dec;\r
1867         if (i_message == WM_COMMAND)\r
1868                 m_log << _T("WM_COMMAND, ");\r
1869         else if (i_message == WM_SYSCOMMAND)\r
1870                 m_log << _T("WM_SYSCOMMAND, ");\r
1871         else\r
1872                 m_log << i_message << _T(", ");\r
1873         m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")\r
1874         << _T("wID = ") << LOWORD(i_wParam) << _T(", ")\r
1875         << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;\r
1876 }\r
1877 \r
1878 unsigned int WINAPI Engine::InputHandler::run(void *i_this)\r
1879 {\r
1880         reinterpret_cast<InputHandler*>(i_this)->run();\r
1881         _endthreadex(0);\r
1882         return 0;\r
1883 }\r
1884 \r
1885 Engine::InputHandler::InputHandler(INSTALL_HOOK i_installHook, INPUT_DETOUR i_inputDetour)\r
1886         : m_installHook(i_installHook), m_inputDetour(i_inputDetour)\r
1887 {\r
1888         CHECK_TRUE(m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL));\r
1889         CHECK_TRUE(m_hThread = (HANDLE)_beginthreadex(NULL, 0, run, this, CREATE_SUSPENDED, &m_threadId));\r
1890 }\r
1891 \r
1892 Engine::InputHandler::~InputHandler()\r
1893 {\r
1894         CloseHandle(m_hEvent);\r
1895 }\r
1896 \r
1897 void Engine::InputHandler::run()\r
1898 {\r
1899         MSG msg;\r
1900 \r
1901         CHECK_FALSE(m_installHook(m_inputDetour, m_engine, true));\r
1902         PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);\r
1903         SetEvent(m_hEvent);\r
1904 \r
1905         while (GetMessage(&msg, NULL, 0, 0)) {\r
1906                 // nothing to do...\r
1907         }\r
1908 \r
1909         CHECK_FALSE(m_installHook(m_inputDetour, m_engine, false));\r
1910 \r
1911         return;\r
1912 }\r
1913 \r
1914 int Engine::InputHandler::start(Engine *i_engine)\r
1915 {\r
1916         m_engine = i_engine;\r
1917         ResumeThread(m_hThread);\r
1918         WaitForSingleObject(m_hEvent, INFINITE);\r
1919         return 0;\r
1920 }\r
1921 \r
1922 int Engine::InputHandler::stop()\r
1923 {\r
1924         PostThreadMessage(m_threadId, WM_QUIT, 0, 0);\r
1925         WaitForSingleObject(m_hThread, INFINITE);\r
1926         return 0;\r
1927 }\r