1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\r
8 # include "multithread.h"
\r
9 # include "setting.h"
\r
10 # include "msgstream.h"
\r
18 WM_APP_engineNotify = WM_APP + 110,
\r
24 EngineNotify_shellExecute, ///
\r
25 EngineNotify_loadSetting, ///
\r
26 EngineNotify_showDlg, ///
\r
27 EngineNotify_helpMessage, ///
\r
28 EngineNotify_setForegroundWindow, ///
\r
29 EngineNotify_clearLog, ///
\r
38 MAX_GENERATE_KEYBOARD_EVENTS_RECURSION_COUNT = 64, ///
\r
39 MAX_KEYMAP_PREFIX_HISTORY = 64, ///
\r
42 typedef Keymaps::KeymapPtrList KeymapPtrList; ///
\r
44 /// focus of a thread
\r
48 DWORD m_threadId; /// thread id
\r
49 HWND m_hwndFocus; /** window that has focus on
\r
51 tstringi m_className; /// class name of hwndFocus
\r
52 tstringi m_titleName; /// title name of hwndFocus
\r
53 bool m_isConsole; /// is hwndFocus console ?
\r
54 KeymapPtrList m_keymaps; /// keymaps
\r
58 FocusOfThread() : m_threadId(0), m_hwndFocus(NULL), m_isConsole(false) { }
\r
60 typedef std::map<DWORD /*ThreadId*/, FocusOfThread> FocusOfThreads; ///
\r
62 typedef std::list<DWORD /*ThreadId*/> DetachedThreadIds; ///
\r
64 /// current status in generateKeyboardEvents
\r
68 const Keymap *m_keymap; /// current keymap
\r
69 ModifiedKey m_mkey; /// current processing key that user inputed
\r
70 /// index in currentFocusOfThread->keymaps
\r
71 Keymaps::KeymapPtrList::iterator m_i;
\r
75 bool isPressed() const {
\r
76 return m_mkey.m_modifier.isOn(Modifier::Type_Down);
\r
80 friend class FunctionParam;
\r
90 class EmacsEditKillLine
\r
92 tstring m_buf; /// previous kill-line contents
\r
95 bool m_doForceReset; ///
\r
99 HGLOBAL makeNewKillLineBuf(const _TCHAR *i_data, int *i_retval);
\r
106 /** EmacsEditKillLineFunc.
\r
107 clear the contents of the clopboard
\r
108 at that time, confirm if it is the result of the previous kill-line
\r
111 /// EmacsEditKillLinePred
\r
115 /// window positon for &WindowHMaximize, &WindowVMaximize
\r
116 class WindowPosition
\r
134 WindowPosition(HWND i_hwnd, const RECT &i_rc, Mode i_mode)
\r
135 : m_hwnd(i_hwnd), m_rc(i_rc), m_mode(i_mode) { }
\r
137 typedef std::list<WindowPosition> WindowPositions;
\r
139 typedef std::list<HWND> WindowsWithAlpha; /// windows for &WindowSetAlpha
\r
141 enum InterruptThreadReason {
\r
142 InterruptThreadReason_Terminate,
\r
143 InterruptThreadReason_Pause,
\r
144 InterruptThreadReason_Resume,
\r
148 class InputHandler {
\r
150 typedef int (*INSTALL_HOOK)(KEYBOARD_DETOUR i_keyboardDetour, Engine *i_engine, bool i_install);
\r
152 static unsigned int WINAPI run(void *i_this);
\r
154 InputHandler(INSTALL_HOOK i_installHook);
\r
160 int start(Engine *i_engine);
\r
165 unsigned m_threadId;
\r
168 INSTALL_HOOK m_installHook;
\r
173 CriticalSection m_cs; /// criticalSection
\r
176 HWND m_hwndAssocWindow; /** associated window (we post
\r
178 Setting * volatile m_setting; /// setting
\r
180 // engine thread state
\r
181 HANDLE m_device; /// mayu device
\r
182 bool m_didMayuStartDevice; /** Did the mayu start the
\r
184 HANDLE m_threadEvent; /** 1. thread has been started
\r
185 2. thread is about to end*/
\r
186 HANDLE m_threadHandle;
\r
187 unsigned m_threadId;
\r
188 tstring m_mayudVersion; /// version of mayud.sys
\r
190 std::deque<KEYBOARD_INPUT_DATA> m_kidq;
\r
191 CriticalSection m_cskidq;
\r
192 InputHandler m_keyboardHandler;
\r
193 InputHandler m_mouseHandler;
\r
194 #endif // NO_DRIVER
\r
195 HANDLE m_readEvent; /** reading from mayu device
\r
196 has been completed */
\r
197 HANDLE m_interruptThreadEvent; /// interrupt thread event
\r
198 volatile InterruptThreadReason
\r
199 m_interruptThreadReason; /// interrupt thread reason
\r
200 OVERLAPPED m_ol; /** for async read/write of
\r
202 HANDLE m_hookPipe; /// named pipe for &SetImeString
\r
203 HMODULE m_sts4mayu; /// DLL module for ThumbSense
\r
204 HMODULE m_cts4mayu; /// DLL module for ThumbSense
\r
205 bool volatile m_doForceTerminate; /// terminate engine thread
\r
206 bool volatile m_isLogMode; /// is logging mode ?
\r
207 bool volatile m_isEnabled; /// is enabled ?
\r
208 bool volatile m_isSynchronizing; /// is synchronizing ?
\r
209 HANDLE m_eSync; /// event for synchronization
\r
210 int m_generateKeyboardEventsRecursionGuard; /** guard against too many
\r
213 // current key state
\r
214 Modifier m_currentLock; /// current lock key's state
\r
215 int m_currentKeyPressCount; /** how many keys are pressed
\r
217 int m_currentKeyPressCountOnWin32; /** how many keys are pressed
\r
219 Key *m_lastGeneratedKey; /// last generated key
\r
220 Key *m_lastPressedKey[2]; /// last pressed key
\r
221 ModifiedKey m_oneShotKey; /// one shot key
\r
222 unsigned int m_oneShotRepeatableRepeatCount; /// repeat count of one shot key
\r
223 bool m_isPrefix; /// is prefix ?
\r
224 bool m_doesIgnoreModifierForPrefix; /** does ignore modifier key
\r
226 bool m_doesEditNextModifier; /** does edit next user input
\r
227 key's modifier ? */
\r
228 Modifier m_modifierForNextKey; /** modifier for next key if
\r
231 /** current keymaps.
\r
233 <dt>when &OtherWindowClass
\r
234 <dd>currentKeymap becoms currentKeymaps[++ Current::i]
\r
235 <dt>when &KeymapParent
\r
236 <dd>currentKeymap becoms currentKeyamp->parentKeymap
\r
238 <dd>currentKeyamp becoms *Current::i
\r
241 const Keymap * volatile m_currentKeymap; /// current keymap
\r
242 FocusOfThreads /*volatile*/ m_focusOfThreads; ///
\r
243 FocusOfThread * volatile m_currentFocusOfThread; ///
\r
244 FocusOfThread m_globalFocus; ///
\r
245 HWND m_hwndFocus; /// current focus window
\r
246 DetachedThreadIds m_detachedThreadIds; ///
\r
249 KeymapPtrList m_keymapPrefixHistory; /// for &KeymapPrevPrefix
\r
250 EmacsEditKillLine m_emacsEditKillLine; /// for &EmacsEditKillLine
\r
251 const ActionFunction *m_afShellExecute; /// for &ShellExecute
\r
253 WindowPositions m_windowPositions; ///
\r
254 WindowsWithAlpha m_windowsWithAlpha; ///
\r
256 tstring m_helpMessage; /// for &HelpMessage
\r
257 tstring m_helpTitle; /// for &HelpMessage
\r
258 int m_variable; /// for &Variable,
\r
262 tomsgstream &m_log; /** log stream (output to log
\r
267 /// keyboard handler thread
\r
268 static unsigned int WINAPI keyboardDetour(Engine *i_this, KBDLLHOOKSTRUCT *i_kid);
\r
271 unsigned int keyboardDetour(KBDLLHOOKSTRUCT *i_kid);
\r
273 unsigned int injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw);
\r
274 #endif // NO_DRIVER
\r
277 /// keyboard handler thread
\r
278 static unsigned int WINAPI keyboardHandler(void *i_this);
\r
280 void keyboardHandler();
\r
282 /// check focus window
\r
283 void checkFocusWindow();
\r
284 /// is modifier pressed ?
\r
285 bool isPressed(Modifier::Type i_mt);
\r
286 /// fix modifier key
\r
287 bool fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am);
\r
290 void outputToLog(const Key *i_key, const ModifiedKey &i_mkey,
\r
293 /// genete modifier events
\r
294 void generateModifierEvents(const Modifier &i_mod);
\r
297 void generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event);
\r
299 /// generate keyboard event
\r
300 void generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign);
\r
302 void generateActionEvents(const Current &i_c, const Action *i_a,
\r
305 void generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,
\r
308 void generateKeyboardEvents(const Current &i_c);
\r
310 void beginGeneratingKeyboardEvents(const Current &i_c, bool i_isModifier);
\r
312 /// pop all pressed key on win32
\r
313 void keyboardResetOnWin32();
\r
315 /// get current modifiers
\r
316 Modifier getCurrentModifiers(Key *i_key, bool i_isPressed);
\r
318 /// describe bindings
\r
319 void describeBindings();
\r
321 /// update m_lastPressedKey
\r
322 void updateLastPressedKey(Key *i_key);
\r
324 /// set current keymap
\r
325 void setCurrentKeymap(const Keymap *i_keymap,
\r
326 bool i_doesAddToHistory = false);
\r
327 /** open mayu device
\r
328 @return true if mayu device successfully is opened
\r
332 /// close mayu device
\r
335 /// load/unload [sc]ts4mayu.dll
\r
336 void manageTs4mayu(TCHAR *i_ts4mayuDllName, TCHAR *i_dependDllName,
\r
337 bool i_load, HMODULE *i_pTs4mayu);
\r
340 // BEGINING OF FUNCTION DEFINITION
\r
341 /// send a default key to Windows
\r
342 void funcDefault(FunctionParam *i_param);
\r
343 /// use a corresponding key of a parent keymap
\r
344 void funcKeymapParent(FunctionParam *i_param);
\r
345 /// use a corresponding key of a current window
\r
346 void funcKeymapWindow(FunctionParam *i_param);
\r
347 /// use a corresponding key of the previous prefixed keymap
\r
348 void funcKeymapPrevPrefix(FunctionParam *i_param, int i_previous);
\r
349 /// use a corresponding key of an other window class, or use a default key
\r
350 void funcOtherWindowClass(FunctionParam *i_param);
\r
352 void funcPrefix(FunctionParam *i_param, const Keymap *i_keymap,
\r
353 BooleanType i_doesIgnoreModifiers = BooleanType_true);
\r
354 /// other keymap's key
\r
355 void funcKeymap(FunctionParam *i_param, const Keymap *i_keymap);
\r
357 void funcSync(FunctionParam *i_param);
\r
359 void funcToggle(FunctionParam *i_param, ModifierLockType i_lock,
\r
360 ToggleType i_toggle = ToggleType_toggle);
\r
361 /// edit next user input key's modifier
\r
362 void funcEditNextModifier(FunctionParam *i_param,
\r
363 const Modifier &i_modifier);
\r
365 void funcVariable(FunctionParam *i_param, int i_mag, int i_inc);
\r
367 void funcRepeat(FunctionParam *i_param, const KeySeq *i_keySeq,
\r
369 /// undefined (bell)
\r
370 void funcUndefined(FunctionParam *i_param);
\r
372 void funcIgnore(FunctionParam *i_param);
\r
374 void funcPostMessage(FunctionParam *i_param, ToWindowType i_window,
\r
375 UINT i_message, WPARAM i_wParam, LPARAM i_lParam);
\r
377 void funcShellExecute(FunctionParam *i_param, const StrExprArg &i_operation,
\r
378 const StrExprArg &i_file, const StrExprArg &i_parameters,
\r
379 const StrExprArg &i_directory,
\r
380 ShowCommandType i_showCommand);
\r
381 /// SetForegroundWindow
\r
382 void funcSetForegroundWindow(FunctionParam *i_param,
\r
383 const tregex &i_windowClassName,
\r
384 LogicalOperatorType i_logicalOp
\r
385 = LogicalOperatorType_and,
\r
386 const tregex &i_windowTitleName
\r
387 = tregex(_T(".*")));
\r
389 void funcLoadSetting(FunctionParam *i_param,
\r
390 const StrExprArg &i_name = StrExprArg());
\r
392 void funcVK(FunctionParam *i_param, VKey i_vkey);
\r
394 void funcWait(FunctionParam *i_param, int i_milliSecond);
\r
395 /// investigate WM_COMMAND, WM_SYSCOMMAND
\r
396 void funcInvestigateCommand(FunctionParam *i_param);
\r
397 /// show mayu dialog box
\r
398 void funcMayuDialog(FunctionParam *i_param, MayuDialogType i_dialog,
\r
399 ShowCommandType i_showCommand);
\r
400 /// describe bindings
\r
401 void funcDescribeBindings(FunctionParam *i_param);
\r
402 /// show help message
\r
403 void funcHelpMessage(FunctionParam *i_param,
\r
404 const StrExprArg &i_title = StrExprArg(),
\r
405 const StrExprArg &i_message = StrExprArg());
\r
407 void funcHelpVariable(FunctionParam *i_param, const StrExprArg &i_title);
\r
409 void funcWindowRaise(FunctionParam *i_param,
\r
410 TargetWindowType i_twt = TargetWindowType_overlapped);
\r
412 void funcWindowLower(FunctionParam *i_param,
\r
413 TargetWindowType i_twt = TargetWindowType_overlapped);
\r
414 /// minimize window
\r
415 void funcWindowMinimize(FunctionParam *i_param, TargetWindowType i_twt
\r
416 = TargetWindowType_overlapped);
\r
417 /// maximize window
\r
418 void funcWindowMaximize(FunctionParam *i_param, TargetWindowType i_twt
\r
419 = TargetWindowType_overlapped);
\r
420 /// maximize window horizontally
\r
421 void funcWindowHMaximize(FunctionParam *i_param, TargetWindowType i_twt
\r
422 = TargetWindowType_overlapped);
\r
423 /// maximize window virtically
\r
424 void funcWindowVMaximize(FunctionParam *i_param, TargetWindowType i_twt
\r
425 = TargetWindowType_overlapped);
\r
426 /// maximize window virtically or horizontally
\r
427 void funcWindowHVMaximize(FunctionParam *i_param, BooleanType i_isHorizontal,
\r
428 TargetWindowType i_twt
\r
429 = TargetWindowType_overlapped);
\r
431 void funcWindowMove(FunctionParam *i_param, int i_dx, int i_dy,
\r
432 TargetWindowType i_twt
\r
433 = TargetWindowType_overlapped);
\r
434 /// move window to ...
\r
435 void funcWindowMoveTo(FunctionParam *i_param, GravityType i_gravityType,
\r
436 int i_dx, int i_dy, TargetWindowType i_twt
\r
437 = TargetWindowType_overlapped);
\r
438 /// move window visibly
\r
439 void funcWindowMoveVisibly(FunctionParam *i_param,
\r
440 TargetWindowType i_twt
\r
441 = TargetWindowType_overlapped);
\r
442 /// move window to other monitor
\r
443 void funcWindowMonitorTo(FunctionParam *i_param,
\r
444 WindowMonitorFromType i_fromType, int i_monitor,
\r
445 BooleanType i_adjustPos = BooleanType_true,
\r
446 BooleanType i_adjustSize = BooleanType_false);
\r
447 /// move window to other monitor
\r
448 void funcWindowMonitor(FunctionParam *i_param, int i_monitor,
\r
449 BooleanType i_adjustPos = BooleanType_true,
\r
450 BooleanType i_adjustSize = BooleanType_false);
\r
452 void funcWindowClingToLeft(FunctionParam *i_param,
\r
453 TargetWindowType i_twt
\r
454 = TargetWindowType_overlapped);
\r
456 void funcWindowClingToRight(FunctionParam *i_param,
\r
457 TargetWindowType i_twt
\r
458 = TargetWindowType_overlapped);
\r
460 void funcWindowClingToTop(FunctionParam *i_param,
\r
461 TargetWindowType i_twt
\r
462 = TargetWindowType_overlapped);
\r
464 void funcWindowClingToBottom(FunctionParam *i_param,
\r
465 TargetWindowType i_twt
\r
466 = TargetWindowType_overlapped);
\r
468 void funcWindowClose(FunctionParam *i_param,
\r
469 TargetWindowType i_twt = TargetWindowType_overlapped);
\r
470 /// toggle top-most flag of the window
\r
471 void funcWindowToggleTopMost(FunctionParam *i_param);
\r
472 /// identify the window
\r
473 void funcWindowIdentify(FunctionParam *i_param);
\r
474 /// set alpha blending parameter to the window
\r
475 void funcWindowSetAlpha(FunctionParam *i_param, int i_alpha);
\r
476 /// redraw the window
\r
477 void funcWindowRedraw(FunctionParam *i_param);
\r
478 /// resize window to
\r
479 void funcWindowResizeTo(FunctionParam *i_param, int i_width, int i_height,
\r
480 TargetWindowType i_twt
\r
481 = TargetWindowType_overlapped);
\r
482 /// move the mouse cursor
\r
483 void funcMouseMove(FunctionParam *i_param, int i_dx, int i_dy);
\r
484 /// send a mouse-wheel-message to Windows
\r
485 void funcMouseWheel(FunctionParam *i_param, int i_delta);
\r
486 /// convert the contents of the Clipboard to upper case or lower case
\r
487 void funcClipboardChangeCase(FunctionParam *i_param,
\r
488 BooleanType i_doesConvertToUpperCase);
\r
489 /// convert the contents of the Clipboard to upper case
\r
490 void funcClipboardUpcaseWord(FunctionParam *i_param);
\r
491 /// convert the contents of the Clipboard to lower case
\r
492 void funcClipboardDowncaseWord(FunctionParam *i_param);
\r
493 /// set the contents of the Clipboard to the string
\r
494 void funcClipboardCopy(FunctionParam *i_param, const StrExprArg &i_text);
\r
496 void funcEmacsEditKillLinePred(FunctionParam *i_param,
\r
497 const KeySeq *i_keySeq1,
\r
498 const KeySeq *i_keySeq2);
\r
500 void funcEmacsEditKillLineFunc(FunctionParam *i_param);
\r
502 void funcLogClear(FunctionParam *i_param);
\r
504 void funcRecenter(FunctionParam *i_param);
\r
506 void funcDirectSSTP(FunctionParam *i_param,
\r
507 const tregex &i_name,
\r
508 const StrExprArg &i_protocol,
\r
509 const std::list<tstringq> &i_headers);
\r
511 void funcPlugIn(FunctionParam *i_param,
\r
512 const StrExprArg &i_dllName,
\r
513 const StrExprArg &i_funcName = StrExprArg(),
\r
514 const StrExprArg &i_funcParam = StrExprArg(),
\r
515 BooleanType i_doesCreateThread = BooleanType_false);
\r
516 /// set IME open status
\r
517 void funcSetImeStatus(FunctionParam *i_param, ToggleType i_toggle = ToggleType_toggle);
\r
518 /// set string to IME
\r
519 void funcSetImeString(FunctionParam *i_param, const StrExprArg &i_data);
\r
520 /// enter to mouse event hook mode
\r
521 void funcMouseHook(FunctionParam *i_param, MouseHookType i_hookType, int i_hookParam);
\r
523 // END OF FUNCTION DEFINITION
\r
524 # define FUNCTION_FRIEND
\r
525 # include "functions.h"
\r
526 # undef FUNCTION_FRIEND
\r
530 Engine(tomsgstream &i_log);
\r
534 /// start/stop keyboard handler thread
\r
539 /// pause keyboard handler thread and close device
\r
542 /// resume keyboard handler thread and re-open device
\r
545 /// do some procedure before quit which must be done synchronously
\r
546 /// (i.e. not on WM_QUIT)
\r
547 bool prepairQuit();
\r
550 void enableLogMode(bool i_isLogMode = true) {
\r
551 m_isLogMode = i_isLogMode;
\r
554 void disableLogMode() {
\r
555 m_isLogMode = false;
\r
558 /// enable/disable engine
\r
559 void enable(bool i_isEnabled = true) {
\r
560 m_isEnabled = i_isEnabled;
\r
564 m_isEnabled = false;
\r
567 bool getIsEnabled() const {
\r
568 return m_isEnabled;
\r
571 /// associated window
\r
572 void setAssociatedWndow(HWND i_hwnd) {
\r
573 m_hwndAssocWindow = i_hwnd;
\r
576 /// associated window
\r
577 HWND getAssociatedWndow() const {
\r
578 return m_hwndAssocWindow;
\r
582 bool setSetting(Setting *i_setting);
\r
585 bool setFocus(HWND i_hwndFocus, DWORD i_threadId,
\r
586 const tstringi &i_className,
\r
587 const tstringi &i_titleName, bool i_isConsole);
\r
590 bool setLockState(bool i_isNumLockToggled, bool i_isCapsLockToggled,
\r
591 bool i_isScrollLockToggled, bool i_isKanaLockToggled,
\r
592 bool i_isImeLockToggled, bool i_isImeCompToggled);
\r
595 void checkShow(HWND i_hwnd);
\r
596 bool setShow(bool i_isMaximized, bool i_isMinimized, bool i_isMDI);
\r
601 /// thread detach notify
\r
602 bool threadDetachNotify(DWORD i_threadId);
\r
605 void shellExecute();
\r
607 /// get help message
\r
608 void getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle);
\r
611 void commandNotify(HWND i_hwnd, UINT i_message, WPARAM i_wParam,
\r
614 /// get current window class name
\r
615 const tstringi &getCurrentWindowClassName() const {
\r
616 return m_currentFocusOfThread->m_className;
\r
619 /// get current window title name
\r
620 const tstringi &getCurrentWindowTitleName() const {
\r
621 return m_currentFocusOfThread->m_titleName;
\r
624 /// get mayud version
\r
625 const tstring &getMayudVersion() const {
\r
626 return m_mayudVersion;
\r
632 class FunctionParam
\r
635 bool m_isPressed; /// is key pressed ?
\r
637 Engine::Current m_c; /// new context
\r
638 bool m_doesNeedEndl; /// need endl ?
\r
639 const ActionFunction *m_af; ///
\r
643 #endif // !_ENGINE_H
\r