OSDN Git Service

use boost_1_56_0 and build by VS2013
[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 (ThreadIds::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                                 injectInput(&kid, NULL);\r
293                         }\r
294 \r
295                         m_lastGeneratedKey = i_doPress ? i_key : NULL;\r
296                 }\r
297         }\r
298 \r
299         {\r
300                 Acquire a(&m_log, 1);\r
301                 m_log << _T("\t\t    =>\t");\r
302                 if (isAlreadyReleased)\r
303                         m_log << _T("(already released) ");\r
304         }\r
305         ModifiedKey mkey(i_key);\r
306         mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
307         mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
308         outputToLog(i_key, mkey, 1);\r
309 }\r
310 \r
311 \r
312 // genete event\r
313 void Engine::generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event)\r
314 {\r
315         // generate\r
316         i_c.m_keymap = i_keymap;\r
317         i_c.m_mkey.m_key = i_event;\r
318         if (const Keymap::KeyAssignment *keyAssign =\r
319                                 i_c.m_keymap->searchAssignment(i_c.m_mkey)) {\r
320                 {\r
321                         Acquire a(&m_log, 1);\r
322                         m_log << std::endl << _T("           ")\r
323                         << i_event->getName() << std::endl;\r
324                 }\r
325                 generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
326         }\r
327 }\r
328 \r
329 \r
330 // genete modifier events\r
331 void Engine::generateModifierEvents(const Modifier &i_mod)\r
332 {\r
333         {\r
334                 Acquire a(&m_log, 1);\r
335                 m_log << _T("* Gen Modifiers\t{") << std::endl;\r
336         }\r
337 \r
338         for (int i = Modifier::Type_begin; i < Modifier::Type_BASIC; ++ i) {\r
339                 Keyboard::Mods &mods =\r
340                         m_setting->m_keyboard.getModifiers(static_cast<Modifier::Type>(i));\r
341 \r
342                 if (i_mod.isDontcare(static_cast<Modifier::Type>(i)))\r
343                         // no need to process\r
344                         ;\r
345                 else if (i_mod.isPressed(static_cast<Modifier::Type>(i)))\r
346                         // we have to press this modifier\r
347                 {\r
348                         bool noneIsPressed = true;\r
349                         bool noneIsPressedByAssign = true;\r
350                         for (Keyboard::Mods::iterator i = mods.begin(); i != mods.end(); ++ i) {\r
351                                 if ((*i)->m_isPressedOnWin32)\r
352                                         noneIsPressed = false;\r
353                                 if ((*i)->m_isPressedByAssign)\r
354                                         noneIsPressedByAssign = false;\r
355                         }\r
356                         if (noneIsPressed) {\r
357                                 if (noneIsPressedByAssign)\r
358                                         generateKeyEvent(mods.front(), true, false);\r
359                                 else\r
360                                         for (Keyboard::Mods::iterator\r
361                                                         i = mods.begin(); i != mods.end(); ++ i)\r
362                                                 if ((*i)->m_isPressedByAssign)\r
363                                                         generateKeyEvent((*i), true, false);\r
364                         }\r
365                 }\r
366 \r
367                 else\r
368                         // we have to release this modifier\r
369                 {\r
370                         // avoid such sequences as  "Alt U-ALt" or "Windows U-Windows"\r
371                         if (i == Modifier::Type_Alt || i == Modifier::Type_Windows) {\r
372                                 for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j)\r
373                                         if ((*j) == m_lastGeneratedKey) {\r
374                                                 Keyboard::Mods *mods =\r
375                                                         &m_setting->m_keyboard.getModifiers(Modifier::Type_Shift);\r
376                                                 if (mods->size() == 0)\r
377                                                         mods = &m_setting->m_keyboard.getModifiers(\r
378                                                                            Modifier::Type_Control);\r
379                                                 if (0 < mods->size()) {\r
380                                                         generateKeyEvent(mods->front(), true, false);\r
381                                                         generateKeyEvent(mods->front(), false, false);\r
382                                                 }\r
383                                                 break;\r
384                                         }\r
385                         }\r
386 \r
387                         for (Keyboard::Mods::iterator j = mods.begin(); j != mods.end(); ++ j) {\r
388                                 if ((*j)->m_isPressedOnWin32)\r
389                                         generateKeyEvent((*j), false, false);\r
390                         }\r
391                 }\r
392         }\r
393 \r
394         {\r
395                 Acquire a(&m_log, 1);\r
396                 m_log << _T("\t\t}") << std::endl;\r
397         }\r
398 }\r
399 \r
400 \r
401 // generate keyboard events for action\r
402 void Engine::generateActionEvents(const Current &i_c, const Action *i_a,\r
403                                                                   bool i_doPress)\r
404 {\r
405         switch (i_a->getType()) {\r
406                 // key\r
407         case Action::Type_key: {\r
408                 const ModifiedKey &mkey\r
409                 = reinterpret_cast<ActionKey *>(\r
410                           const_cast<Action *>(i_a))->m_modifiedKey;\r
411 \r
412                 // release\r
413                 if (!i_doPress &&\r
414                                 (mkey.m_modifier.isOn(Modifier::Type_Up) ||\r
415                                  mkey.m_modifier.isDontcare(Modifier::Type_Up)))\r
416                         generateKeyEvent(mkey.m_key, false, true);\r
417 \r
418                 // press\r
419                 else if (i_doPress &&\r
420                                  (mkey.m_modifier.isOn(Modifier::Type_Down) ||\r
421                                   mkey.m_modifier.isDontcare(Modifier::Type_Down))) {\r
422                         Modifier modifier = mkey.m_modifier;\r
423                         modifier.add(i_c.m_mkey.m_modifier);\r
424                         generateModifierEvents(modifier);\r
425                         generateKeyEvent(mkey.m_key, true, true);\r
426                 }\r
427                 break;\r
428         }\r
429 \r
430         // keyseq\r
431         case Action::Type_keySeq: {\r
432                 const ActionKeySeq *aks = reinterpret_cast<const ActionKeySeq *>(i_a);\r
433                 generateKeySeqEvents(i_c, aks->m_keySeq,\r
434                                                          i_doPress ? Part_down : Part_up);\r
435                 break;\r
436         }\r
437 \r
438         // function\r
439         case Action::Type_function: {\r
440                 const ActionFunction *af = reinterpret_cast<const ActionFunction *>(i_a);\r
441                 bool is_up = (!i_doPress &&\r
442                                           (af->m_modifier.isOn(Modifier::Type_Up) ||\r
443                                            af->m_modifier.isDontcare(Modifier::Type_Up)));\r
444                 bool is_down = (i_doPress &&\r
445                                                 (af->m_modifier.isOn(Modifier::Type_Down) ||\r
446                                                  af->m_modifier.isDontcare(Modifier::Type_Down)));\r
447 \r
448                 if (!is_down && !is_up)\r
449                         break;\r
450 \r
451                 {\r
452                         Acquire a(&m_log, 1);\r
453                         m_log << _T("\t\t     >\t") << af->m_functionData;\r
454                 }\r
455 \r
456                 FunctionParam param;\r
457                 param.m_isPressed = i_doPress;\r
458                 param.m_hwnd = m_currentFocusOfThread->m_hwndFocus;\r
459                 param.m_c = i_c;\r
460                 param.m_doesNeedEndl = true;\r
461                 param.m_af = af;\r
462 \r
463                 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Up, !i_doPress);\r
464                 param.m_c.m_mkey.m_modifier.on(Modifier::Type_Down, i_doPress);\r
465 \r
466                 af->m_functionData->exec(this, &param);\r
467 \r
468                 if (param.m_doesNeedEndl) {\r
469                         Acquire a(&m_log, 1);\r
470                         m_log << std::endl;\r
471                 }\r
472                 break;\r
473         }\r
474         }\r
475 }\r
476 \r
477 \r
478 // generate keyboard events for keySeq\r
479 void Engine::generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,\r
480                                                                   Part i_part)\r
481 {\r
482         const KeySeq::Actions &actions = i_keySeq->getActions();\r
483         if (actions.empty())\r
484                 return;\r
485         if (i_part == Part_up)\r
486                 generateActionEvents(i_c, actions[actions.size() - 1], false);\r
487         else {\r
488                 size_t i;\r
489                 for (i = 0 ; i < actions.size() - 1; ++ i) {\r
490                         generateActionEvents(i_c, actions[i], true);\r
491                         generateActionEvents(i_c, actions[i], false);\r
492                 }\r
493                 generateActionEvents(i_c, actions[i], true);\r
494                 if (i_part == Part_all)\r
495                         generateActionEvents(i_c, actions[i], false);\r
496         }\r
497 }\r
498 \r
499 \r
500 // generate keyboard events for current key\r
501 void Engine::generateKeyboardEvents(const Current &i_c)\r
502 {\r
503         if (++ m_generateKeyboardEventsRecursionGuard ==\r
504                         MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT) {\r
505                 Acquire a(&m_log);\r
506                 m_log << _T("error: too deep keymap recursion.  there may be a loop.")\r
507                 << std::endl;\r
508                 return;\r
509         }\r
510 \r
511         const Keymap::KeyAssignment *keyAssign\r
512         = i_c.m_keymap->searchAssignment(i_c.m_mkey);\r
513         if (!keyAssign) {\r
514                 const KeySeq *keySeq = i_c.m_keymap->getDefaultKeySeq();\r
515                 ASSERT( keySeq );\r
516                 generateKeySeqEvents(i_c, keySeq, i_c.isPressed() ? Part_down : Part_up);\r
517         } else {\r
518                 if (keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Up) ||\r
519                                 keyAssign->m_modifiedKey.m_modifier.isOn(Modifier::Type_Down))\r
520                         generateKeySeqEvents(i_c, keyAssign->m_keySeq, Part_all);\r
521                 else\r
522                         generateKeySeqEvents(i_c, keyAssign->m_keySeq,\r
523                                                                  i_c.isPressed() ? Part_down : Part_up);\r
524         }\r
525         m_generateKeyboardEventsRecursionGuard --;\r
526 }\r
527 \r
528 \r
529 // generate keyboard events for current key\r
530 void Engine::beginGeneratingKeyboardEvents(\r
531         const Current &i_c, bool i_isModifier)\r
532 {\r
533         //             (1)             (2)             (3)  (4)   (1)\r
534         // up/down:    D-              U-              D-   U-    D-\r
535         // keymap:     m_currentKeymap m_currentKeymap X    X     m_currentKeymap\r
536         // memo:       &Prefix(X)      ...             ...  ...   ...\r
537         // m_isPrefix: false           true            true false false\r
538 \r
539         Current cnew(i_c);\r
540 \r
541         bool isPhysicallyPressed\r
542         = cnew.m_mkey.m_modifier.isPressed(Modifier::Type_Down);\r
543 \r
544         // substitute\r
545         ModifiedKey mkey = m_setting->m_keyboard.searchSubstitute(cnew.m_mkey);\r
546         if (mkey.m_key) {\r
547                 cnew.m_mkey = mkey;\r
548                 if (isPhysicallyPressed) {\r
549                         cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
550                         cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
551                 } else {\r
552                         cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
553                         cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
554                 }\r
555                 for (int i = Modifier::Type_begin; i != Modifier::Type_end; ++ i) {\r
556                         Modifier::Type type = static_cast<Modifier::Type>(i);\r
557                         if (cnew.m_mkey.m_modifier.isDontcare(type) &&\r
558                                         !i_c.m_mkey.m_modifier.isDontcare(type))\r
559                                 cnew.m_mkey.m_modifier.press(\r
560                                         type, i_c.m_mkey.m_modifier.isPressed(type));\r
561                 }\r
562 \r
563                 {\r
564                         Acquire a(&m_log, 1);\r
565                         m_log << _T("* substitute") << std::endl;\r
566                 }\r
567                 outputToLog(mkey.m_key, cnew.m_mkey, 1);\r
568         }\r
569 \r
570         // for prefix key\r
571         const Keymap *tmpKeymap = m_currentKeymap;\r
572         if (i_isModifier || !m_isPrefix) ;\r
573         else if (isPhysicallyPressed)                   // when (3)\r
574                 m_isPrefix = false;\r
575         else if (!isPhysicallyPressed)          // when (2)\r
576                 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
577 \r
578         // for m_emacsEditKillLine function\r
579         m_emacsEditKillLine.m_doForceReset = !i_isModifier;\r
580 \r
581         // generate key event !\r
582         m_generateKeyboardEventsRecursionGuard = 0;\r
583         if (isPhysicallyPressed)\r
584                 generateEvents(cnew, cnew.m_keymap, &Event::before_key_down);\r
585         generateKeyboardEvents(cnew);\r
586         if (!isPhysicallyPressed)\r
587                 generateEvents(cnew, cnew.m_keymap, &Event::after_key_up);\r
588 \r
589         // for m_emacsEditKillLine function\r
590         if (m_emacsEditKillLine.m_doForceReset)\r
591                 m_emacsEditKillLine.reset();\r
592 \r
593         // for prefix key\r
594         if (i_isModifier)\r
595                 ;\r
596         else if (!m_isPrefix)                           // when (1), (4)\r
597                 m_currentKeymap = m_currentFocusOfThread->m_keymaps.front();\r
598         else if (!isPhysicallyPressed)          // when (2)\r
599                 m_currentKeymap = tmpKeymap;\r
600 }\r
601 \r
602 \r
603 unsigned int Engine::injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw)\r
604 {\r
605         if (i_kid->Flags & KEYBOARD_INPUT_DATA::E1) {\r
606                 INPUT kid[2];\r
607                 int count = 1;\r
608 \r
609                 kid[0].type = INPUT_MOUSE;\r
610                 kid[0].mi.dx = 0;\r
611                 kid[0].mi.dy = 0;\r
612                 kid[0].mi.time = 0;\r
613                 kid[0].mi.mouseData = 0;\r
614                 kid[0].mi.dwExtraInfo = 0;\r
615                 switch (i_kid->MakeCode) {\r
616                 case 1:\r
617                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
618                                 kid[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;\r
619                         } else {\r
620                                 kid[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;\r
621                         }\r
622                         break;\r
623                 case 2:\r
624                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
625                                 kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;\r
626                         } else {\r
627                                 kid[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;\r
628                         }\r
629                         break;\r
630                 case 3:\r
631                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
632                                 kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEUP;\r
633                         } else {\r
634                                 kid[0].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;\r
635                         }\r
636                         break;\r
637                 case 4:\r
638                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
639                                 return 1;\r
640                         } else {\r
641                                 kid[0].mi.mouseData = WHEEL_DELTA;\r
642                                 kid[0].mi.dwFlags = MOUSEEVENTF_WHEEL;\r
643                         }\r
644                         break;\r
645                 case 5:\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 6:\r
654                         kid[0].mi.mouseData = XBUTTON1;\r
655                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
656                                 kid[0].mi.dwFlags = MOUSEEVENTF_XUP;\r
657                         } else {\r
658                                 kid[0].mi.dwFlags = MOUSEEVENTF_XDOWN;\r
659                         }\r
660                         break;\r
661                 case 7:\r
662                         kid[0].mi.mouseData = XBUTTON2;\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 8:\r
670                         if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
671                                 return 1;\r
672                         } else {\r
673                                 kid[0].mi.mouseData = WHEEL_DELTA;\r
674                                 kid[0].mi.dwFlags = MOUSEEVENTF_HWHEEL;\r
675                         }\r
676                         break;\r
677                 case 9:\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                 default:\r
686                         return 1;\r
687                         break;\r
688                 }\r
689                 if (!(i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) &&\r
690                         i_kid->MakeCode != 4 && i_kid->MakeCode != 5 &&\r
691                         i_kid->MakeCode != 8 && i_kid->MakeCode != 9) {\r
692                         HWND hwnd;\r
693                         POINT pt;\r
694 \r
695                         if (GetCursorPos(&pt) && (hwnd = WindowFromPoint(pt))) {\r
696                                 _TCHAR className[GANA_MAX_ATOM_LENGTH];\r
697                                 if (GetClassName(hwnd, className, NUMBER_OF(className))) {\r
698                                         if (_tcsicmp(className, _T("ConsoleWindowClass")) == 0) {\r
699                                                 SetForegroundWindow(hwnd);\r
700                                         }\r
701                                 }\r
702                         }\r
703                         if (m_dragging) {\r
704                                 kid[0].mi.dx = 65535 * m_msllHookCurrent.pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
705                                 kid[0].mi.dy = 65535 * m_msllHookCurrent.pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
706                                 kid[0].mi.dwFlags |= MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;\r
707 \r
708                                 kid[1].type = INPUT_MOUSE;\r
709                                 kid[1].mi.dx = 65535 * pt.x / GetSystemMetrics(SM_CXVIRTUALSCREEN);\r
710                                 kid[1].mi.dy = 65535 * pt.y / GetSystemMetrics(SM_CYVIRTUALSCREEN);\r
711                                 kid[1].mi.time = 0;\r
712                                 kid[1].mi.mouseData = 0;\r
713                                 kid[1].mi.dwExtraInfo = 0;\r
714                                 kid[1].mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK;\r
715 \r
716                                 count = 2;\r
717                         }\r
718                 }\r
719                 SendInput(count, &kid[0], sizeof(kid[0]));\r
720         } else {\r
721                 INPUT kid;\r
722 \r
723                 kid.type = INPUT_KEYBOARD;\r
724                 kid.ki.wVk = 0;\r
725                 kid.ki.wScan = i_kid->MakeCode;\r
726                 kid.ki.dwFlags = KEYEVENTF_SCANCODE;\r
727                 kid.ki.time = i_kidRaw ? i_kidRaw->time : 0;\r
728                 kid.ki.dwExtraInfo = i_kidRaw ? i_kidRaw->dwExtraInfo : 0;\r
729                 if (i_kid->Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
730                         kid.ki.dwFlags |= KEYEVENTF_KEYUP;\r
731                 }\r
732                 if (i_kid->Flags & KEYBOARD_INPUT_DATA::E0) {\r
733                         kid.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;\r
734                 }\r
735                 SendInput(1, &kid, sizeof(kid));\r
736         }\r
737         return 1;\r
738 }\r
739 \r
740 \r
741 // pop all pressed key on win32\r
742 void Engine::keyboardResetOnWin32()\r
743 {\r
744         for (Keyboard::KeyIterator\r
745                         i = m_setting->m_keyboard.getKeyIterator();  *i; ++ i) {\r
746                 if ((*i)->m_isPressedOnWin32)\r
747                         generateKeyEvent((*i), false, true);\r
748         }\r
749 }\r
750 \r
751 \r
752 unsigned int WINAPI Engine::keyboardDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)\r
753 {\r
754         return i_this->keyboardDetour(reinterpret_cast<KBDLLHOOKSTRUCT*>(i_lParam));\r
755 }\r
756 \r
757 unsigned int Engine::keyboardDetour(KBDLLHOOKSTRUCT *i_kid)\r
758 {\r
759 #if 0\r
760         Acquire a(&m_log, 1);\r
761         m_log << std::hex\r
762         << _T("keyboardDetour: vkCode=") << i_kid->vkCode\r
763         << _T(" scanCode=") << i_kid->scanCode\r
764         << _T(" flags=") << i_kid->flags << std::endl;\r
765 #endif\r
766         if ((i_kid->flags & LLKHF_INJECTED) || !m_isEnabled) {\r
767                 return 0;\r
768         } else {\r
769                 Key key;\r
770                 KEYBOARD_INPUT_DATA kid;\r
771 \r
772                 kid.UnitId = 0;\r
773                 kid.MakeCode = i_kid->scanCode;\r
774                 kid.Flags = 0;\r
775                 if (i_kid->flags & LLKHF_UP) {\r
776                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
777                 }\r
778                 if (i_kid->flags & LLKHF_EXTENDED) {\r
779                         kid.Flags |= KEYBOARD_INPUT_DATA::E0;\r
780                 }\r
781                 kid.Reserved = 0;\r
782                 kid.ExtraInformation = 0;\r
783 \r
784                 WaitForSingleObject(m_queueMutex, INFINITE);\r
785                 m_inputQueue->push_back(kid);\r
786                 SetEvent(m_readEvent);\r
787                 ReleaseMutex(m_queueMutex);\r
788                 return 1;\r
789         }\r
790 }\r
791 \r
792 unsigned int WINAPI Engine::mouseDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam)\r
793 {\r
794         return i_this->mouseDetour(i_wParam, reinterpret_cast<MSLLHOOKSTRUCT*>(i_lParam));\r
795 }\r
796 \r
797 unsigned int Engine::mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid)\r
798 {\r
799         if (i_mid->flags & LLMHF_INJECTED || !m_isEnabled || !m_setting || !m_setting->m_mouseEvent) {\r
800                 return 0;\r
801         } else {\r
802                 KEYBOARD_INPUT_DATA kid;\r
803 \r
804                 kid.UnitId = 0;\r
805                 kid.Flags = KEYBOARD_INPUT_DATA::E1;\r
806                 kid.Reserved = 0;\r
807                 kid.ExtraInformation = 0;\r
808                 switch (i_message) {\r
809                 case WM_LBUTTONUP:\r
810                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
811                 case WM_LBUTTONDOWN:\r
812                         kid.MakeCode = 1;\r
813                         break;\r
814                 case WM_RBUTTONUP:\r
815                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
816                 case WM_RBUTTONDOWN:\r
817                         kid.MakeCode = 2;\r
818                         break;\r
819                 case WM_MBUTTONUP:\r
820                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
821                 case WM_MBUTTONDOWN:\r
822                         kid.MakeCode = 3;\r
823                         break;\r
824                 case WM_MOUSEWHEEL:\r
825                         if (i_mid->mouseData & (1<<31)) {\r
826                                 kid.MakeCode = 5;\r
827                         } else {\r
828                                 kid.MakeCode = 4;\r
829                         }\r
830                         break;\r
831                 case WM_XBUTTONUP:\r
832                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
833                 case WM_XBUTTONDOWN:\r
834                         switch ((i_mid->mouseData >> 16) & 0xFFFFU) {\r
835                         case XBUTTON1:\r
836                                 kid.MakeCode = 6;\r
837                                 break;\r
838                         case XBUTTON2:\r
839                                 kid.MakeCode = 7;\r
840                                 break;\r
841                         default:\r
842                                 return 0;\r
843                                 break;\r
844                         }\r
845                         break;\r
846                 case WM_MOUSEHWHEEL:\r
847                         if (i_mid->mouseData & (1<<31)) {\r
848                                 kid.MakeCode = 9;\r
849                         } else {\r
850                                 kid.MakeCode = 8;\r
851                         }\r
852                         break;\r
853                 case WM_MOUSEMOVE: {\r
854                         LONG dx = i_mid->pt.x - g_hookData->m_mousePos.x;\r
855                         LONG dy = i_mid->pt.y - g_hookData->m_mousePos.y;\r
856                         HWND target = reinterpret_cast<HWND>(g_hookData->m_hwndMouseHookTarget);\r
857 \r
858                         LONG dr = 0;\r
859                         dr += (i_mid->pt.x - m_msllHookCurrent.pt.x) * (i_mid->pt.x - m_msllHookCurrent.pt.x);\r
860                         dr += (i_mid->pt.y - m_msllHookCurrent.pt.y) * (i_mid->pt.y - m_msllHookCurrent.pt.y);\r
861                         if (m_buttonPressed && !m_dragging && m_setting->m_dragThreshold &&\r
862                                 (m_setting->m_dragThreshold * m_setting->m_dragThreshold < dr)) {\r
863                                 kid.MakeCode = 0;\r
864                                 WaitForSingleObject(m_queueMutex, INFINITE);\r
865                                 m_dragging = true;\r
866                                 m_inputQueue->push_back(kid);\r
867                                 SetEvent(m_readEvent);\r
868                                 ReleaseMutex(m_queueMutex);\r
869                         }\r
870 \r
871                         switch (g_hookData->m_mouseHookType) {\r
872                         case MouseHookType_Wheel:\r
873                                 // For this type, g_hookData->m_mouseHookParam means\r
874                                 // translate rate mouse move to wheel.\r
875                                 mouse_event(MOUSEEVENTF_WHEEL, 0, 0,\r
876                                                         g_hookData->m_mouseHookParam * dy, 0);\r
877                                 return 1;\r
878                                 break;\r
879                         case MouseHookType_WindowMove: {\r
880                                 RECT curRect;\r
881 \r
882                                 if (!GetWindowRect(target, &curRect))\r
883                                         return 0;\r
884 \r
885                                 // g_hookData->m_mouseHookParam < 0 means\r
886                                 // target window to move is MDI.\r
887                                 if (g_hookData->m_mouseHookParam < 0) {\r
888                                         HWND parent = GetParent(target);\r
889                                         POINT p = {curRect.left, curRect.top};\r
890 \r
891                                         if (parent == NULL || !ScreenToClient(parent, &p))\r
892                                                 return 0;\r
893 \r
894                                         curRect.left = p.x;\r
895                                         curRect.top = p.y;\r
896                                 }\r
897 \r
898                                 SetWindowPos(target, NULL,\r
899                                                          curRect.left + dx,\r
900                                                          curRect.top + dy,\r
901                                                          0, 0,\r
902                                                          SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE |\r
903                                                          SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);\r
904                                 g_hookData->m_mousePos = i_mid->pt;\r
905                                 return 0;\r
906                                 break;\r
907                         }\r
908                         case MouseHookType_None:\r
909                         default:\r
910                                 return 0;\r
911                                 break;\r
912                         }\r
913                 }\r
914                 case WM_LBUTTONDBLCLK:\r
915                 case WM_RBUTTONDBLCLK:\r
916                 case WM_MBUTTONDBLCLK:\r
917                 case WM_XBUTTONDBLCLK:\r
918                 default:\r
919                         return 0;\r
920                         break;\r
921                 }\r
922 \r
923                 WaitForSingleObject(m_queueMutex, INFINITE);\r
924 \r
925                 if (kid.Flags & KEYBOARD_INPUT_DATA::BREAK) {\r
926                         m_buttonPressed = false;\r
927                         if (m_dragging) {\r
928                                 KEYBOARD_INPUT_DATA kid2;\r
929 \r
930                                 m_dragging = false;\r
931                                 kid2.UnitId = 0;\r
932                                 kid2.Flags = KEYBOARD_INPUT_DATA::E1 | KEYBOARD_INPUT_DATA::BREAK;\r
933                                 kid2.Reserved = 0;\r
934                                 kid2.ExtraInformation = 0;\r
935                                 kid2.MakeCode = 0;\r
936                                 m_inputQueue->push_back(kid2);\r
937                         }\r
938                 } else if (i_message != WM_MOUSEWHEEL && i_message != WM_MOUSEHWHEEL) {\r
939                         m_buttonPressed = true;\r
940                         m_msllHookCurrent = *i_mid;\r
941                 }\r
942 \r
943                 m_inputQueue->push_back(kid);\r
944 \r
945                 if (i_message == WM_MOUSEWHEEL || i_message == WM_MOUSEHWHEEL) {\r
946                         kid.UnitId = 0;\r
947                         kid.Flags |= KEYBOARD_INPUT_DATA::BREAK;\r
948                         kid.Reserved = 0;\r
949                         kid.ExtraInformation = 0;\r
950                         m_inputQueue->push_back(kid);\r
951                 }\r
952 \r
953                 SetEvent(m_readEvent);\r
954                 ReleaseMutex(m_queueMutex);\r
955 \r
956                 return 1;\r
957         }\r
958 }\r
959 \r
960 // keyboard handler thread\r
961 unsigned int WINAPI Engine::keyboardHandler(void *i_this)\r
962 {\r
963         reinterpret_cast<Engine *>(i_this)->keyboardHandler();\r
964         _endthreadex(0);\r
965         return 0;\r
966 }\r
967 void Engine::keyboardHandler()\r
968 {\r
969         // loop\r
970         Key key;\r
971         while (1) {\r
972                 KEYBOARD_INPUT_DATA kid;\r
973 \r
974                 WaitForSingleObject(m_queueMutex, INFINITE);\r
975                 while (SignalObjectAndWait(m_queueMutex, m_readEvent, INFINITE, true) == WAIT_OBJECT_0) {\r
976                         if (m_inputQueue == NULL) {\r
977                                 ReleaseMutex(m_queueMutex);\r
978                                 return;\r
979                         }\r
980 \r
981                         if (m_inputQueue->empty()) {\r
982                                 ResetEvent(m_readEvent);\r
983                                 continue;\r
984                         }\r
985 \r
986                         kid = m_inputQueue->front();\r
987                         m_inputQueue->pop_front();\r
988                         if (m_inputQueue->empty()) {\r
989                                 ResetEvent(m_readEvent);\r
990                         }\r
991 \r
992                         break;\r
993 \r
994 #if 0\r
995                         case WAIT_OBJECT_0 + NUMBER_OF(handles): {\r
996                                 MSG message;\r
997 \r
998                                 while (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {\r
999                                         switch (message.message) {\r
1000                                         case WM_APP + 201: {\r
1001                                                 if (message.wParam) {\r
1002                                                         m_currentLock.on(Modifier::Type_Touchpad);\r
1003                                                         m_currentLock.on(Modifier::Type_TouchpadSticky);\r
1004                                                 } else\r
1005                                                         m_currentLock.off(Modifier::Type_Touchpad);\r
1006                                                 Acquire a(&m_log, 1);\r
1007                                                 m_log << _T("touchpad: ") << message.wParam\r
1008                                                 << _T(".") << (message.lParam & 0xffff)\r
1009                                                 << _T(".") << (message.lParam >> 16 & 0xffff)\r
1010                                                 << std::endl;\r
1011                                                 break;\r
1012                                         }\r
1013                                         default:\r
1014                                                 break;\r
1015                                         }\r
1016                                 }\r
1017                                 goto rewait;\r
1018                         }\r
1019 #endif\r
1020                 }\r
1021                 ReleaseMutex(m_queueMutex);\r
1022 \r
1023                 checkFocusWindow();\r
1024 \r
1025                 if (!m_setting ||       // m_setting has not been loaded\r
1026                                 !m_isEnabled) { // disabled\r
1027                         if (m_isLogMode) {\r
1028                                 Key key;\r
1029                                 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
1030                                 outputToLog(&key, ModifiedKey(), 0);\r
1031                                 if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
1032                                         // through mouse event even if log mode\r
1033                                         injectInput(&kid, NULL);\r
1034                                 }\r
1035                         } else {\r
1036                                 injectInput(&kid, NULL);\r
1037                         }\r
1038                         updateLastPressedKey(NULL);\r
1039                         continue;\r
1040                 }\r
1041 \r
1042                 Acquire a(&m_cs);\r
1043 \r
1044                 if (!m_currentFocusOfThread ||\r
1045                                 !m_currentKeymap) {\r
1046                         injectInput(&kid, NULL);\r
1047                         Acquire a(&m_log, 0);\r
1048                         if (!m_currentFocusOfThread)\r
1049                                 m_log << _T("internal error: m_currentFocusOfThread == NULL")\r
1050                                 << std::endl;\r
1051                         if (!m_currentKeymap)\r
1052                                 m_log << _T("internal error: m_currentKeymap == NULL")\r
1053                                 << std::endl;\r
1054                         updateLastPressedKey(NULL);\r
1055                         continue;\r
1056                 }\r
1057 \r
1058                 Current c;\r
1059                 c.m_keymap = m_currentKeymap;\r
1060                 c.m_i = m_currentFocusOfThread->m_keymaps.begin();\r
1061 \r
1062                 // search key\r
1063                 key.addScanCode(ScanCode(kid.MakeCode, kid.Flags));\r
1064                 c.m_mkey = m_setting->m_keyboard.searchKey(key);\r
1065                 if (!c.m_mkey.m_key) {\r
1066                         c.m_mkey.m_key = m_setting->m_keyboard.searchPrefixKey(key);\r
1067                         if (c.m_mkey.m_key)\r
1068                                 continue;\r
1069                 }\r
1070 \r
1071                 // press the key and update counter\r
1072                 bool isPhysicallyPressed\r
1073                 = !(key.getScanCodes()[0].m_flags & ScanCode::BREAK);\r
1074                 if (c.m_mkey.m_key) {\r
1075                         if (!c.m_mkey.m_key->m_isPressed && isPhysicallyPressed)\r
1076                                 ++ m_currentKeyPressCount;\r
1077                         else if (c.m_mkey.m_key->m_isPressed && !isPhysicallyPressed)\r
1078                                 -- m_currentKeyPressCount;\r
1079                         c.m_mkey.m_key->m_isPressed = isPhysicallyPressed;\r
1080                 }\r
1081 \r
1082                 // create modifiers\r
1083                 c.m_mkey.m_modifier = getCurrentModifiers(c.m_mkey.m_key,\r
1084                                                           isPhysicallyPressed);\r
1085                 Keymap::AssignMode am;\r
1086                 bool isModifier = fixModifierKey(&c.m_mkey, &am);\r
1087                 if (m_isPrefix) {\r
1088                         if (isModifier && m_doesIgnoreModifierForPrefix)\r
1089                                 am = Keymap::AM_true;\r
1090                         if (m_doesEditNextModifier) {\r
1091                                 Modifier modifier = m_modifierForNextKey;\r
1092                                 modifier.add(c.m_mkey.m_modifier);\r
1093                                 c.m_mkey.m_modifier = modifier;\r
1094                         }\r
1095                 }\r
1096 \r
1097                 if (m_isLogMode) {\r
1098                         outputToLog(&key, c.m_mkey, 0);\r
1099                         if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
1100                                 // through mouse event even if log mode\r
1101                                 injectInput(&kid, NULL);\r
1102                         }\r
1103                 } else if (am == Keymap::AM_true) {\r
1104                         {\r
1105                                 Acquire a(&m_log, 1);\r
1106                                 m_log << _T("* true modifier") << std::endl;\r
1107                         }\r
1108                         // true modifier doesn't generate scan code\r
1109                         outputToLog(&key, c.m_mkey, 1);\r
1110                 } else if (am == Keymap::AM_oneShot || am == Keymap::AM_oneShotRepeatable) {\r
1111                         {\r
1112                                 Acquire a(&m_log, 1);\r
1113                                 if (am == Keymap::AM_oneShot)\r
1114                                         m_log << _T("* one shot modifier") << std::endl;\r
1115                                 else\r
1116                                         m_log << _T("* one shot repeatable modifier") << std::endl;\r
1117                         }\r
1118                         // oneShot modifier doesn't generate scan code\r
1119                         outputToLog(&key, c.m_mkey, 1);\r
1120                         if (isPhysicallyPressed) {\r
1121                                 if (am == Keymap::AM_oneShotRepeatable  // the key is repeating\r
1122                                                 && m_oneShotKey.m_key == c.m_mkey.m_key) {\r
1123                                         if (m_oneShotRepeatableRepeatCount <\r
1124                                                         m_setting->m_oneShotRepeatableDelay) {\r
1125                                                 ; // delay\r
1126                                         } else {\r
1127                                                 Current cnew = c;\r
1128                                                 beginGeneratingKeyboardEvents(cnew, false);\r
1129                                         }\r
1130                                         ++ m_oneShotRepeatableRepeatCount;\r
1131                                 } else {\r
1132                                         m_oneShotKey = c.m_mkey;\r
1133                                         m_oneShotRepeatableRepeatCount = 0;\r
1134                                 }\r
1135                         } else {\r
1136                                 if (m_oneShotKey.m_key) {\r
1137                                         Current cnew = c;\r
1138                                         cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
1139                                         cnew.m_mkey.m_modifier.off(Modifier::Type_Up);\r
1140                                         cnew.m_mkey.m_modifier.on(Modifier::Type_Down);\r
1141                                         beginGeneratingKeyboardEvents(cnew, false);\r
1142 \r
1143                                         cnew = c;\r
1144                                         cnew.m_mkey.m_modifier = m_oneShotKey.m_modifier;\r
1145                                         cnew.m_mkey.m_modifier.on(Modifier::Type_Up);\r
1146                                         cnew.m_mkey.m_modifier.off(Modifier::Type_Down);\r
1147                                         beginGeneratingKeyboardEvents(cnew, false);\r
1148                                 }\r
1149                                 m_oneShotKey.m_key = NULL;\r
1150                                 m_oneShotRepeatableRepeatCount = 0;\r
1151                         }\r
1152                 } else if (c.m_mkey.m_key) {\r
1153                         // normal key\r
1154                         outputToLog(&key, c.m_mkey, 1);\r
1155                         if (isPhysicallyPressed)\r
1156                                 m_oneShotKey.m_key = NULL;\r
1157                         beginGeneratingKeyboardEvents(c, isModifier);\r
1158                 } else {\r
1159                         // undefined key\r
1160                         if (kid.Flags & KEYBOARD_INPUT_DATA::E1) {\r
1161                                 // through mouse event even if undefined for fail safe\r
1162                                 injectInput(&kid, NULL);\r
1163                         }\r
1164                 }\r
1165 \r
1166                 // if counter is zero, reset modifiers and keys on win32\r
1167                 if (m_currentKeyPressCount <= 0) {\r
1168                         {\r
1169                                 Acquire a(&m_log, 1);\r
1170                                 m_log << _T("* No key is pressed") << std::endl;\r
1171                         }\r
1172                         generateModifierEvents(Modifier());\r
1173                         if (0 < m_currentKeyPressCountOnWin32)\r
1174                                 keyboardResetOnWin32();\r
1175                         m_currentKeyPressCount = 0;\r
1176                         m_currentKeyPressCountOnWin32 = 0;\r
1177                         m_oneShotKey.m_key = NULL;\r
1178                         if (m_currentLock.isOn(Modifier::Type_Touchpad) == false)\r
1179                                 m_currentLock.off(Modifier::Type_TouchpadSticky);\r
1180                 }\r
1181 \r
1182                 key.initialize();\r
1183                 updateLastPressedKey(isPhysicallyPressed ? c.m_mkey.m_key : NULL);\r
1184         }\r
1185 }\r
1186 \r
1187 \r
1188 Engine::Engine(tomsgstream &i_log)\r
1189                 : m_hwndAssocWindow(NULL),\r
1190                 m_setting(NULL),\r
1191                 m_buttonPressed(false),\r
1192                 m_dragging(false),\r
1193                 m_keyboardHandler(installKeyboardHook, Engine::keyboardDetour),\r
1194                 m_mouseHandler(installMouseHook, Engine::mouseDetour),\r
1195                 m_inputQueue(NULL),\r
1196                 m_readEvent(NULL),\r
1197                 m_queueMutex(NULL),\r
1198                 m_sts4mayu(NULL),\r
1199                 m_cts4mayu(NULL),\r
1200                 m_isLogMode(false),\r
1201                 m_isEnabled(true),\r
1202                 m_isSynchronizing(false),\r
1203                 m_eSync(NULL),\r
1204                 m_generateKeyboardEventsRecursionGuard(0),\r
1205                 m_currentKeyPressCount(0),\r
1206                 m_currentKeyPressCountOnWin32(0),\r
1207                 m_lastGeneratedKey(NULL),\r
1208                 m_oneShotRepeatableRepeatCount(0),\r
1209                 m_isPrefix(false),\r
1210                 m_currentKeymap(NULL),\r
1211                 m_currentFocusOfThread(NULL),\r
1212                 m_hwndFocus(NULL),\r
1213                 m_afShellExecute(NULL),\r
1214                 m_variable(0),\r
1215                 m_log(i_log) {\r
1216         BOOL (WINAPI *pChangeWindowMessageFilter)(UINT, DWORD) =\r
1217                 reinterpret_cast<BOOL (WINAPI*)(UINT, DWORD)>(GetProcAddress(GetModuleHandle(_T("user32.dll")), "ChangeWindowMessageFilter"));\r
1218 \r
1219         if(pChangeWindowMessageFilter != NULL) {\r
1220                 pChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);\r
1221         }\r
1222 \r
1223         for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
1224                 m_lastPressedKey[i] = NULL;\r
1225 \r
1226         // set default lock state\r
1227         for (int i = 0; i < Modifier::Type_end; ++ i)\r
1228                 m_currentLock.dontcare(static_cast<Modifier::Type>(i));\r
1229         for (int i = Modifier::Type_Lock0; i <= Modifier::Type_Lock9; ++ i)\r
1230                 m_currentLock.release(static_cast<Modifier::Type>(i));\r
1231 \r
1232         // create event for sync\r
1233         CHECK_TRUE( m_eSync = CreateEvent(NULL, FALSE, FALSE, NULL) );\r
1234         // create named pipe for &SetImeString\r
1235         m_hookPipe = CreateNamedPipe(addSessionId(HOOK_PIPE_NAME).c_str(),\r
1236                                                                  PIPE_ACCESS_OUTBOUND,\r
1237                                                                  PIPE_TYPE_BYTE, 1,\r
1238                                                                  0, 0, 0, NULL);\r
1239         StrExprArg::setEngine(this);\r
1240 \r
1241         m_msllHookCurrent.pt.x = 0;\r
1242         m_msllHookCurrent.pt.y = 0;\r
1243         m_msllHookCurrent.mouseData = 0;\r
1244         m_msllHookCurrent.flags = 0;\r
1245         m_msllHookCurrent.time = 0;\r
1246         m_msllHookCurrent.dwExtraInfo = 0;\r
1247 }\r
1248 \r
1249 \r
1250 \r
1251 \r
1252 // start keyboard handler thread\r
1253 void Engine::start() {\r
1254         m_keyboardHandler.start(this);\r
1255         m_mouseHandler.start(this);\r
1256 \r
1257         CHECK_TRUE( m_inputQueue = new std::deque<KEYBOARD_INPUT_DATA> );\r
1258         CHECK_TRUE( m_queueMutex = CreateMutex(NULL, FALSE, NULL) );\r
1259         CHECK_TRUE( m_readEvent = CreateEvent(NULL, TRUE, FALSE, NULL) );\r
1260         m_ol.Offset = 0;\r
1261         m_ol.OffsetHigh = 0;\r
1262         m_ol.hEvent = m_readEvent;\r
1263 \r
1264         CHECK_TRUE( m_threadHandle = (HANDLE)_beginthreadex(NULL, 0, keyboardHandler, this, 0, &m_threadId) );\r
1265 }\r
1266 \r
1267 \r
1268 // stop keyboard handler thread\r
1269 void Engine::stop() {\r
1270         m_mouseHandler.stop();\r
1271         m_keyboardHandler.stop();\r
1272 \r
1273         WaitForSingleObject(m_queueMutex, INFINITE);\r
1274         delete m_inputQueue;\r
1275         m_inputQueue = NULL;\r
1276         SetEvent(m_readEvent);\r
1277         ReleaseMutex(m_queueMutex);\r
1278 \r
1279         WaitForSingleObject(m_threadHandle, 2000);\r
1280         CHECK_TRUE( CloseHandle(m_threadHandle) );\r
1281         m_threadHandle = NULL;\r
1282 \r
1283         CHECK_TRUE( CloseHandle(m_readEvent) );\r
1284         m_readEvent = NULL;\r
1285 \r
1286         for (ThreadIds::iterator i = m_attachedThreadIds.begin();\r
1287                  i != m_attachedThreadIds.end(); i++) {\r
1288                  PostThreadMessage(*i, WM_NULL, 0, 0);\r
1289         }\r
1290 }\r
1291 \r
1292 \r
1293 bool Engine::prepairQuit() {\r
1294         // terminate and unload DLL for ThumbSense support if loaded\r
1295         manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
1296                                   false, &m_sts4mayu);\r
1297         manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
1298                                   false, &m_cts4mayu);\r
1299         return true;\r
1300 }\r
1301 \r
1302 \r
1303 Engine::~Engine() {\r
1304         CHECK_TRUE( CloseHandle(m_eSync) );\r
1305 \r
1306         // destroy named pipe for &SetImeString\r
1307         if (m_hookPipe && m_hookPipe != INVALID_HANDLE_VALUE) {\r
1308                 DisconnectNamedPipe(m_hookPipe);\r
1309                 CHECK_TRUE( CloseHandle(m_hookPipe) );\r
1310         }\r
1311 }\r
1312 \r
1313 \r
1314 void Engine::manageTs4mayu(TCHAR *i_ts4mayuDllName,\r
1315                                                    TCHAR *i_dependDllName,\r
1316                                                    bool i_load, HMODULE *i_pTs4mayu) {\r
1317         Acquire a(&m_log, 0);\r
1318 \r
1319         if (i_load == false) {\r
1320                 if (*i_pTs4mayu) {\r
1321                         bool (WINAPI *pTs4mayuTerm)();\r
1322 \r
1323                         pTs4mayuTerm = (bool (WINAPI*)())GetProcAddress(*i_pTs4mayu, "ts4mayuTerm");\r
1324                         if (pTs4mayuTerm() == true)\r
1325                                 FreeLibrary(*i_pTs4mayu);\r
1326                         *i_pTs4mayu = NULL;\r
1327                         m_log << i_ts4mayuDllName <<_T(" unloaded") << std::endl;\r
1328                 }\r
1329         } else {\r
1330                 if (*i_pTs4mayu) {\r
1331                         m_log << i_ts4mayuDllName << _T(" already loaded") << std::endl;\r
1332                 } else {\r
1333                         if (SearchPath(NULL, i_dependDllName, NULL, 0, NULL, NULL) == 0) {\r
1334                                 m_log << _T("load ") << i_ts4mayuDllName\r
1335                                 << _T(" failed: can't find ") << i_dependDllName\r
1336                                 << std::endl;\r
1337                         } else {\r
1338                                 *i_pTs4mayu = LoadLibrary(i_ts4mayuDllName);\r
1339                                 if (*i_pTs4mayu == NULL) {\r
1340                                         m_log << _T("load ") << i_ts4mayuDllName\r
1341                                         << _T(" failed: can't find it") << std::endl;\r
1342                                 } else {\r
1343                                         bool (WINAPI *pTs4mayuInit)(UINT);\r
1344 \r
1345                                         pTs4mayuInit = (bool (WINAPI*)(UINT))GetProcAddress(*i_pTs4mayu, "ts4mayuInit");\r
1346                                         if (pTs4mayuInit(m_threadId) == true)\r
1347                                                 m_log << i_ts4mayuDllName <<_T(" loaded") << std::endl;\r
1348                                         else\r
1349                                                 m_log << i_ts4mayuDllName\r
1350                                                 <<_T(" load failed: can't initialize") << std::endl;\r
1351                                 }\r
1352                         }\r
1353                 }\r
1354         }\r
1355 }\r
1356 \r
1357 \r
1358 // set m_setting\r
1359 bool Engine::setSetting(Setting *i_setting) {\r
1360         Acquire a(&m_cs);\r
1361         if (m_isSynchronizing)\r
1362                 return false;\r
1363 \r
1364         if (m_setting) {\r
1365                 for (Keyboard::KeyIterator i = m_setting->m_keyboard.getKeyIterator();\r
1366                                 *i; ++ i) {\r
1367                         Key *key = i_setting->m_keyboard.searchKey(*(*i));\r
1368                         if (key) {\r
1369                                 key->m_isPressed = (*i)->m_isPressed;\r
1370                                 key->m_isPressedOnWin32 = (*i)->m_isPressedOnWin32;\r
1371                                 key->m_isPressedByAssign = (*i)->m_isPressedByAssign;\r
1372                         }\r
1373                 }\r
1374                 if (m_lastGeneratedKey)\r
1375                         m_lastGeneratedKey =\r
1376                                 i_setting->m_keyboard.searchKey(*m_lastGeneratedKey);\r
1377                 for (size_t i = 0; i < NUMBER_OF(m_lastPressedKey); ++ i)\r
1378                         if (m_lastPressedKey[i])\r
1379                                 m_lastPressedKey[i] =\r
1380                                         i_setting->m_keyboard.searchKey(*m_lastPressedKey[i]);\r
1381         }\r
1382 \r
1383         m_setting = i_setting;\r
1384 \r
1385         manageTs4mayu(_T("sts4mayu.dll"), _T("SynCOM.dll"),\r
1386                                   m_setting->m_sts4mayu, &m_sts4mayu);\r
1387         manageTs4mayu(_T("cts4mayu.dll"), _T("TouchPad.dll"),\r
1388                                   m_setting->m_cts4mayu, &m_cts4mayu);\r
1389 \r
1390         g_hookData->m_correctKanaLockHandling = m_setting->m_correctKanaLockHandling;\r
1391         if (m_currentFocusOfThread) {\r
1392                 for (FocusOfThreads::iterator i = m_focusOfThreads.begin();\r
1393                                 i != m_focusOfThreads.end(); i ++) {\r
1394                         FocusOfThread *fot = &(*i).second;\r
1395                         m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
1396                                                                                           fot->m_className, fot->m_titleName);\r
1397                 }\r
1398         }\r
1399         m_setting->m_keymaps.searchWindow(&m_globalFocus.m_keymaps, _T(""), _T(""));\r
1400         if (m_globalFocus.m_keymaps.empty()) {\r
1401                 Acquire a(&m_log, 0);\r
1402                 m_log << _T("internal error: m_globalFocus.m_keymap is empty")\r
1403                 << std::endl;\r
1404         }\r
1405         m_currentFocusOfThread = &m_globalFocus;\r
1406         setCurrentKeymap(m_globalFocus.m_keymaps.front());\r
1407         m_hwndFocus = NULL;\r
1408         return true;\r
1409 }\r
1410 \r
1411 \r
1412 void Engine::checkShow(HWND i_hwnd) {\r
1413         // update show style of window\r
1414         // this update should be done in hook DLL, but to\r
1415         // avoid update-loss for some applications(such as\r
1416         // cmd.exe), we update here.\r
1417         bool isMaximized = false;\r
1418         bool isMinimized = false;\r
1419         bool isMDIMaximized = false;\r
1420         bool isMDIMinimized = false;\r
1421         while (i_hwnd) {\r
1422 #ifdef MAYU64\r
1423                 LONG_PTR exStyle = GetWindowLongPtr(i_hwnd, GWL_EXSTYLE);\r
1424 #else\r
1425                 LONG exStyle = GetWindowLong(i_hwnd, GWL_EXSTYLE);\r
1426 #endif\r
1427                 if (exStyle & WS_EX_MDICHILD) {\r
1428                         WINDOWPLACEMENT placement;\r
1429                         placement.length = sizeof(WINDOWPLACEMENT);\r
1430                         if (GetWindowPlacement(i_hwnd, &placement)) {\r
1431                                 switch (placement.showCmd) {\r
1432                                 case SW_SHOWMAXIMIZED:\r
1433                                         isMDIMaximized = true;\r
1434                                         break;\r
1435                                 case SW_SHOWMINIMIZED:\r
1436                                         isMDIMinimized = true;\r
1437                                         break;\r
1438                                 case SW_SHOWNORMAL:\r
1439                                 default:\r
1440                                         break;\r
1441                                 }\r
1442                         }\r
1443                 }\r
1444 \r
1445 #ifdef MAYU64\r
1446                 LONG_PTR style = GetWindowLongPtr(i_hwnd, GWL_STYLE);\r
1447 #else\r
1448                 LONG style = GetWindowLong(i_hwnd, GWL_STYLE);\r
1449 #endif\r
1450                 if ((style & WS_CHILD) == 0) {\r
1451                         WINDOWPLACEMENT placement;\r
1452                         placement.length = sizeof(WINDOWPLACEMENT);\r
1453                         if (GetWindowPlacement(i_hwnd, &placement)) {\r
1454                                 switch (placement.showCmd) {\r
1455                                 case SW_SHOWMAXIMIZED:\r
1456                                         isMaximized = true;\r
1457                                         break;\r
1458                                 case SW_SHOWMINIMIZED:\r
1459                                         isMinimized = true;\r
1460                                         break;\r
1461                                 case SW_SHOWNORMAL:\r
1462                                 default:\r
1463                                         break;\r
1464                                 }\r
1465                         }\r
1466                 }\r
1467                 i_hwnd = GetParent(i_hwnd);\r
1468         }\r
1469         setShow(isMDIMaximized, isMDIMinimized, true);\r
1470         setShow(isMaximized, isMinimized, false);\r
1471 }\r
1472 \r
1473 \r
1474 // focus\r
1475 bool Engine::setFocus(HWND i_hwndFocus, DWORD i_threadId,\r
1476                                           const tstringi &i_className, const tstringi &i_titleName,\r
1477                                           bool i_isConsole) {\r
1478         Acquire a(&m_cs);\r
1479         if (m_isSynchronizing)\r
1480                 return false;\r
1481         if (i_hwndFocus == NULL)\r
1482                 return true;\r
1483 \r
1484         // remove newly created thread's id from m_detachedThreadIds\r
1485         if (!m_detachedThreadIds.empty()) {\r
1486                 ThreadIds::iterator i;\r
1487                 bool retry;\r
1488                 do {\r
1489                         retry = false;\r
1490                         for (i = m_detachedThreadIds.begin();\r
1491                                         i != m_detachedThreadIds.end(); ++ i)\r
1492                                 if (*i == i_threadId) {\r
1493                                         m_detachedThreadIds.erase(i);\r
1494                                         retry = true;\r
1495                                         break;\r
1496                                 }\r
1497                 } while (retry);\r
1498         }\r
1499 \r
1500         FocusOfThread *fot;\r
1501         FocusOfThreads::iterator i = m_focusOfThreads.find(i_threadId);\r
1502         if (i != m_focusOfThreads.end()) {\r
1503                 fot = &(*i).second;\r
1504                 if (fot->m_hwndFocus == i_hwndFocus &&\r
1505                                 fot->m_isConsole == i_isConsole &&\r
1506                                 fot->m_className == i_className &&\r
1507                                 fot->m_titleName == i_titleName)\r
1508                         return true;\r
1509         } else {\r
1510                 i = m_focusOfThreads.insert(\r
1511                                 FocusOfThreads::value_type(i_threadId, FocusOfThread())).first;\r
1512                 fot = &(*i).second;\r
1513                 fot->m_threadId = i_threadId;\r
1514         }\r
1515         fot->m_hwndFocus = i_hwndFocus;\r
1516         fot->m_isConsole = i_isConsole;\r
1517         fot->m_className = i_className;\r
1518         fot->m_titleName = i_titleName;\r
1519 \r
1520         if (m_setting) {\r
1521                 m_setting->m_keymaps.searchWindow(&fot->m_keymaps,\r
1522                                                                                   i_className, i_titleName);\r
1523                 ASSERT(0 < fot->m_keymaps.size());\r
1524         } else\r
1525                 fot->m_keymaps.clear();\r
1526         checkShow(i_hwndFocus);\r
1527         return true;\r
1528 }\r
1529 \r
1530 \r
1531 // lock state\r
1532 bool Engine::setLockState(bool i_isNumLockToggled,\r
1533                                                   bool i_isCapsLockToggled,\r
1534                                                   bool i_isScrollLockToggled,\r
1535                                                   bool i_isKanaLockToggled,\r
1536                                                   bool i_isImeLockToggled,\r
1537                                                   bool i_isImeCompToggled) {\r
1538         Acquire a(&m_cs);\r
1539         if (m_isSynchronizing)\r
1540                 return false;\r
1541         m_currentLock.on(Modifier::Type_NumLock, i_isNumLockToggled);\r
1542         m_currentLock.on(Modifier::Type_CapsLock, i_isCapsLockToggled);\r
1543         m_currentLock.on(Modifier::Type_ScrollLock, i_isScrollLockToggled);\r
1544         m_currentLock.on(Modifier::Type_KanaLock, i_isKanaLockToggled);\r
1545         m_currentLock.on(Modifier::Type_ImeLock, i_isImeLockToggled);\r
1546         m_currentLock.on(Modifier::Type_ImeComp, i_isImeCompToggled);\r
1547         return true;\r
1548 }\r
1549 \r
1550 \r
1551 // show\r
1552 bool Engine::setShow(bool i_isMaximized, bool i_isMinimized,\r
1553                                          bool i_isMDI) {\r
1554         Acquire a(&m_cs);\r
1555         if (m_isSynchronizing)\r
1556                 return false;\r
1557         Acquire b(&m_log, 1);\r
1558         Modifier::Type max, min;\r
1559         if (i_isMDI == true) {\r
1560                 max = Modifier::Type_MdiMaximized;\r
1561                 min = Modifier::Type_MdiMinimized;\r
1562         } else {\r
1563                 max = Modifier::Type_Maximized;\r
1564                 min = Modifier::Type_Minimized;\r
1565         }\r
1566         m_currentLock.on(max, i_isMaximized);\r
1567         m_currentLock.on(min, i_isMinimized);\r
1568         m_log << _T("Set show to ") << (i_isMaximized ? _T("Maximized") :\r
1569                                                                         i_isMinimized ? _T("Minimized") : _T("Normal"));\r
1570         if (i_isMDI == true) {\r
1571                 m_log << _T(" (MDI)");\r
1572         }\r
1573         m_log << std::endl;\r
1574         return true;\r
1575 }\r
1576 \r
1577 \r
1578 // sync\r
1579 bool Engine::syncNotify() {\r
1580         Acquire a(&m_cs);\r
1581         if (!m_isSynchronizing)\r
1582                 return false;\r
1583         CHECK_TRUE( SetEvent(m_eSync) );\r
1584         return true;\r
1585 }\r
1586 \r
1587 \r
1588 // thread attach notify\r
1589 bool Engine::threadAttachNotify(DWORD i_threadId) {\r
1590         Acquire a(&m_cs);\r
1591         m_attachedThreadIds.push_back(i_threadId);\r
1592         return true;\r
1593 }\r
1594 \r
1595 \r
1596 // thread detach notify\r
1597 bool Engine::threadDetachNotify(DWORD i_threadId) {\r
1598         Acquire a(&m_cs);\r
1599         m_detachedThreadIds.push_back(i_threadId);\r
1600         m_attachedThreadIds.erase(remove(m_attachedThreadIds.begin(), m_attachedThreadIds.end(), i_threadId),\r
1601                                                           m_attachedThreadIds.end());\r
1602         return true;\r
1603 }\r
1604 \r
1605 \r
1606 // get help message\r
1607 void Engine::getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle) {\r
1608         Acquire a(&m_cs);\r
1609         *o_helpMessage = m_helpMessage;\r
1610         *o_helpTitle = m_helpTitle;\r
1611 }\r
1612 \r
1613 \r
1614 unsigned int WINAPI Engine::InputHandler::run(void *i_this)\r
1615 {\r
1616         reinterpret_cast<InputHandler*>(i_this)->run();\r
1617         _endthreadex(0);\r
1618         return 0;\r
1619 }\r
1620 \r
1621 Engine::InputHandler::InputHandler(INSTALL_HOOK i_installHook, INPUT_DETOUR i_inputDetour)\r
1622         : m_installHook(i_installHook), m_inputDetour(i_inputDetour)\r
1623 {\r
1624         CHECK_TRUE(m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL));\r
1625         CHECK_TRUE(m_hThread = (HANDLE)_beginthreadex(NULL, 0, run, this, CREATE_SUSPENDED, &m_threadId));\r
1626 }\r
1627 \r
1628 Engine::InputHandler::~InputHandler()\r
1629 {\r
1630         CloseHandle(m_hEvent);\r
1631 }\r
1632 \r
1633 void Engine::InputHandler::run()\r
1634 {\r
1635         MSG msg;\r
1636 \r
1637         CHECK_FALSE(m_installHook(m_inputDetour, m_engine, true));\r
1638         PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);\r
1639         SetEvent(m_hEvent);\r
1640 \r
1641         while (GetMessage(&msg, NULL, 0, 0)) {\r
1642                 // nothing to do...\r
1643         }\r
1644 \r
1645         CHECK_FALSE(m_installHook(m_inputDetour, m_engine, false));\r
1646 \r
1647         return;\r
1648 }\r
1649 \r
1650 int Engine::InputHandler::start(Engine *i_engine)\r
1651 {\r
1652         m_engine = i_engine;\r
1653         ResumeThread(m_hThread);\r
1654         WaitForSingleObject(m_hEvent, INFINITE);\r
1655         return 0;\r
1656 }\r
1657 \r
1658 int Engine::InputHandler::stop()\r
1659 {\r
1660         PostThreadMessage(m_threadId, WM_QUIT, 0, 0);\r
1661         WaitForSingleObject(m_hThread, INFINITE);\r
1662         return 0;\r
1663 }\r