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)(INPUT_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, INPUT_DETOUR i_inputDetour);
\r
160 int start(Engine *i_engine);
\r
165 unsigned m_threadId;
\r
168 INSTALL_HOOK m_installHook;
\r
169 INPUT_DETOUR m_inputDetour;
\r
174 CriticalSection m_cs; /// criticalSection
\r
177 HWND m_hwndAssocWindow; /** associated window (we post
\r
179 Setting * volatile m_setting; /// setting
\r
181 // engine thread state
\r
182 HANDLE m_threadHandle;
\r
183 unsigned m_threadId;
\r
184 std::deque<KEYBOARD_INPUT_DATA> *m_inputQueue;
\r
185 HANDLE m_queueMutex;
\r
186 MSLLHOOKSTRUCT m_msllHookCurrent;
\r
187 bool m_buttonPressed;
\r
189 InputHandler m_keyboardHandler;
\r
190 InputHandler m_mouseHandler;
\r
191 HANDLE m_readEvent; /** reading from mayu device
\r
192 has been completed */
\r
193 OVERLAPPED m_ol; /** for async read/write of
\r
195 HANDLE m_hookPipe; /// named pipe for &SetImeString
\r
196 HMODULE m_sts4mayu; /// DLL module for ThumbSense
\r
197 HMODULE m_cts4mayu; /// DLL module for ThumbSense
\r
198 bool volatile m_isLogMode; /// is logging mode ?
\r
199 bool volatile m_isEnabled; /// is enabled ?
\r
200 bool volatile m_isSynchronizing; /// is synchronizing ?
\r
201 HANDLE m_eSync; /// event for synchronization
\r
202 int m_generateKeyboardEventsRecursionGuard; /** guard against too many
\r
205 // current key state
\r
206 Modifier m_currentLock; /// current lock key's state
\r
207 int m_currentKeyPressCount; /** how many keys are pressed
\r
209 int m_currentKeyPressCountOnWin32; /** how many keys are pressed
\r
211 Key *m_lastGeneratedKey; /// last generated key
\r
212 Key *m_lastPressedKey[2]; /// last pressed key
\r
213 ModifiedKey m_oneShotKey; /// one shot key
\r
214 unsigned int m_oneShotRepeatableRepeatCount; /// repeat count of one shot key
\r
215 bool m_isPrefix; /// is prefix ?
\r
216 bool m_doesIgnoreModifierForPrefix; /** does ignore modifier key
\r
218 bool m_doesEditNextModifier; /** does edit next user input
\r
219 key's modifier ? */
\r
220 Modifier m_modifierForNextKey; /** modifier for next key if
\r
223 /** current keymaps.
\r
225 <dt>when &OtherWindowClass
\r
226 <dd>currentKeymap becoms currentKeymaps[++ Current::i]
\r
227 <dt>when &KeymapParent
\r
228 <dd>currentKeymap becoms currentKeyamp->parentKeymap
\r
230 <dd>currentKeyamp becoms *Current::i
\r
233 const Keymap * volatile m_currentKeymap; /// current keymap
\r
234 FocusOfThreads /*volatile*/ m_focusOfThreads; ///
\r
235 FocusOfThread * volatile m_currentFocusOfThread; ///
\r
236 FocusOfThread m_globalFocus; ///
\r
237 HWND m_hwndFocus; /// current focus window
\r
238 DetachedThreadIds m_detachedThreadIds; ///
\r
241 KeymapPtrList m_keymapPrefixHistory; /// for &KeymapPrevPrefix
\r
242 EmacsEditKillLine m_emacsEditKillLine; /// for &EmacsEditKillLine
\r
243 const ActionFunction *m_afShellExecute; /// for &ShellExecute
\r
245 WindowPositions m_windowPositions; ///
\r
246 WindowsWithAlpha m_windowsWithAlpha; ///
\r
248 tstring m_helpMessage; /// for &HelpMessage
\r
249 tstring m_helpTitle; /// for &HelpMessage
\r
250 int m_variable; /// for &Variable,
\r
254 tomsgstream &m_log; /** log stream (output to log
\r
258 /// keyboard handler thread
\r
259 static unsigned int WINAPI keyboardDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam);
\r
260 /// mouse handler thread
\r
261 static unsigned int WINAPI mouseDetour(Engine *i_this, WPARAM i_wParam, LPARAM i_lParam);
\r
264 unsigned int keyboardDetour(KBDLLHOOKSTRUCT *i_kid);
\r
266 unsigned int mouseDetour(WPARAM i_message, MSLLHOOKSTRUCT *i_mid);
\r
268 unsigned int injectInput(const KEYBOARD_INPUT_DATA *i_kid, const KBDLLHOOKSTRUCT *i_kidRaw);
\r
271 /// keyboard handler thread
\r
272 static unsigned int WINAPI keyboardHandler(void *i_this);
\r
274 void keyboardHandler();
\r
276 /// check focus window
\r
277 void checkFocusWindow();
\r
278 /// is modifier pressed ?
\r
279 bool isPressed(Modifier::Type i_mt);
\r
280 /// fix modifier key
\r
281 bool fixModifierKey(ModifiedKey *io_mkey, Keymap::AssignMode *o_am);
\r
284 void outputToLog(const Key *i_key, const ModifiedKey &i_mkey,
\r
287 /// genete modifier events
\r
288 void generateModifierEvents(const Modifier &i_mod);
\r
291 void generateEvents(Current i_c, const Keymap *i_keymap, Key *i_event);
\r
293 /// generate keyboard event
\r
294 void generateKeyEvent(Key *i_key, bool i_doPress, bool i_isByAssign);
\r
296 void generateActionEvents(const Current &i_c, const Action *i_a,
\r
299 void generateKeySeqEvents(const Current &i_c, const KeySeq *i_keySeq,
\r
302 void generateKeyboardEvents(const Current &i_c);
\r
304 void beginGeneratingKeyboardEvents(const Current &i_c, bool i_isModifier);
\r
306 /// pop all pressed key on win32
\r
307 void keyboardResetOnWin32();
\r
309 /// get current modifiers
\r
310 Modifier getCurrentModifiers(Key *i_key, bool i_isPressed);
\r
312 /// describe bindings
\r
313 void describeBindings();
\r
315 /// update m_lastPressedKey
\r
316 void updateLastPressedKey(Key *i_key);
\r
318 /// set current keymap
\r
319 void setCurrentKeymap(const Keymap *i_keymap,
\r
320 bool i_doesAddToHistory = false);
\r
321 /** open mayu device
\r
322 @return true if mayu device successfully is opened
\r
326 /// close mayu device
\r
329 /// load/unload [sc]ts4mayu.dll
\r
330 void manageTs4mayu(TCHAR *i_ts4mayuDllName, TCHAR *i_dependDllName,
\r
331 bool i_load, HMODULE *i_pTs4mayu);
\r
334 // BEGINING OF FUNCTION DEFINITION
\r
335 /// send a default key to Windows
\r
336 void funcDefault(FunctionParam *i_param);
\r
337 /// use a corresponding key of a parent keymap
\r
338 void funcKeymapParent(FunctionParam *i_param);
\r
339 /// use a corresponding key of a current window
\r
340 void funcKeymapWindow(FunctionParam *i_param);
\r
341 /// use a corresponding key of the previous prefixed keymap
\r
342 void funcKeymapPrevPrefix(FunctionParam *i_param, int i_previous);
\r
343 /// use a corresponding key of an other window class, or use a default key
\r
344 void funcOtherWindowClass(FunctionParam *i_param);
\r
346 void funcPrefix(FunctionParam *i_param, const Keymap *i_keymap,
\r
347 BooleanType i_doesIgnoreModifiers = BooleanType_true);
\r
348 /// other keymap's key
\r
349 void funcKeymap(FunctionParam *i_param, const Keymap *i_keymap);
\r
351 void funcSync(FunctionParam *i_param);
\r
353 void funcToggle(FunctionParam *i_param, ModifierLockType i_lock,
\r
354 ToggleType i_toggle = ToggleType_toggle);
\r
355 /// edit next user input key's modifier
\r
356 void funcEditNextModifier(FunctionParam *i_param,
\r
357 const Modifier &i_modifier);
\r
359 void funcVariable(FunctionParam *i_param, int i_mag, int i_inc);
\r
361 void funcRepeat(FunctionParam *i_param, const KeySeq *i_keySeq,
\r
363 /// undefined (bell)
\r
364 void funcUndefined(FunctionParam *i_param);
\r
366 void funcIgnore(FunctionParam *i_param);
\r
368 void funcPostMessage(FunctionParam *i_param, ToWindowType i_window,
\r
369 UINT i_message, WPARAM i_wParam, LPARAM i_lParam);
\r
371 void funcShellExecute(FunctionParam *i_param, const StrExprArg &i_operation,
\r
372 const StrExprArg &i_file, const StrExprArg &i_parameters,
\r
373 const StrExprArg &i_directory,
\r
374 ShowCommandType i_showCommand);
\r
375 /// SetForegroundWindow
\r
376 void funcSetForegroundWindow(FunctionParam *i_param,
\r
377 const tregex &i_windowClassName,
\r
378 LogicalOperatorType i_logicalOp
\r
379 = LogicalOperatorType_and,
\r
380 const tregex &i_windowTitleName
\r
381 = tregex(_T(".*")));
\r
383 void funcLoadSetting(FunctionParam *i_param,
\r
384 const StrExprArg &i_name = StrExprArg());
\r
386 void funcVK(FunctionParam *i_param, VKey i_vkey);
\r
388 void funcWait(FunctionParam *i_param, int i_milliSecond);
\r
389 /// investigate WM_COMMAND, WM_SYSCOMMAND
\r
390 void funcInvestigateCommand(FunctionParam *i_param);
\r
391 /// show mayu dialog box
\r
392 void funcMayuDialog(FunctionParam *i_param, MayuDialogType i_dialog,
\r
393 ShowCommandType i_showCommand);
\r
394 /// describe bindings
\r
395 void funcDescribeBindings(FunctionParam *i_param);
\r
396 /// show help message
\r
397 void funcHelpMessage(FunctionParam *i_param,
\r
398 const StrExprArg &i_title = StrExprArg(),
\r
399 const StrExprArg &i_message = StrExprArg());
\r
401 void funcHelpVariable(FunctionParam *i_param, const StrExprArg &i_title);
\r
403 void funcWindowRaise(FunctionParam *i_param,
\r
404 TargetWindowType i_twt = TargetWindowType_overlapped);
\r
406 void funcWindowLower(FunctionParam *i_param,
\r
407 TargetWindowType i_twt = TargetWindowType_overlapped);
\r
408 /// minimize window
\r
409 void funcWindowMinimize(FunctionParam *i_param, TargetWindowType i_twt
\r
410 = TargetWindowType_overlapped);
\r
411 /// maximize window
\r
412 void funcWindowMaximize(FunctionParam *i_param, TargetWindowType i_twt
\r
413 = TargetWindowType_overlapped);
\r
414 /// maximize window horizontally
\r
415 void funcWindowHMaximize(FunctionParam *i_param, TargetWindowType i_twt
\r
416 = TargetWindowType_overlapped);
\r
417 /// maximize window virtically
\r
418 void funcWindowVMaximize(FunctionParam *i_param, TargetWindowType i_twt
\r
419 = TargetWindowType_overlapped);
\r
420 /// maximize window virtically or horizontally
\r
421 void funcWindowHVMaximize(FunctionParam *i_param, BooleanType i_isHorizontal,
\r
422 TargetWindowType i_twt
\r
423 = TargetWindowType_overlapped);
\r
425 void funcWindowMove(FunctionParam *i_param, int i_dx, int i_dy,
\r
426 TargetWindowType i_twt
\r
427 = TargetWindowType_overlapped);
\r
428 /// move window to ...
\r
429 void funcWindowMoveTo(FunctionParam *i_param, GravityType i_gravityType,
\r
430 int i_dx, int i_dy, TargetWindowType i_twt
\r
431 = TargetWindowType_overlapped);
\r
432 /// move window visibly
\r
433 void funcWindowMoveVisibly(FunctionParam *i_param,
\r
434 TargetWindowType i_twt
\r
435 = TargetWindowType_overlapped);
\r
436 /// move window to other monitor
\r
437 void funcWindowMonitorTo(FunctionParam *i_param,
\r
438 WindowMonitorFromType i_fromType, int i_monitor,
\r
439 BooleanType i_adjustPos = BooleanType_true,
\r
440 BooleanType i_adjustSize = BooleanType_false);
\r
441 /// move window to other monitor
\r
442 void funcWindowMonitor(FunctionParam *i_param, int i_monitor,
\r
443 BooleanType i_adjustPos = BooleanType_true,
\r
444 BooleanType i_adjustSize = BooleanType_false);
\r
446 void funcWindowClingToLeft(FunctionParam *i_param,
\r
447 TargetWindowType i_twt
\r
448 = TargetWindowType_overlapped);
\r
450 void funcWindowClingToRight(FunctionParam *i_param,
\r
451 TargetWindowType i_twt
\r
452 = TargetWindowType_overlapped);
\r
454 void funcWindowClingToTop(FunctionParam *i_param,
\r
455 TargetWindowType i_twt
\r
456 = TargetWindowType_overlapped);
\r
458 void funcWindowClingToBottom(FunctionParam *i_param,
\r
459 TargetWindowType i_twt
\r
460 = TargetWindowType_overlapped);
\r
462 void funcWindowClose(FunctionParam *i_param,
\r
463 TargetWindowType i_twt = TargetWindowType_overlapped);
\r
464 /// toggle top-most flag of the window
\r
465 void funcWindowToggleTopMost(FunctionParam *i_param);
\r
466 /// identify the window
\r
467 void funcWindowIdentify(FunctionParam *i_param);
\r
468 /// set alpha blending parameter to the window
\r
469 void funcWindowSetAlpha(FunctionParam *i_param, int i_alpha);
\r
470 /// redraw the window
\r
471 void funcWindowRedraw(FunctionParam *i_param);
\r
472 /// resize window to
\r
473 void funcWindowResizeTo(FunctionParam *i_param, int i_width, int i_height,
\r
474 TargetWindowType i_twt
\r
475 = TargetWindowType_overlapped);
\r
476 /// move the mouse cursor
\r
477 void funcMouseMove(FunctionParam *i_param, int i_dx, int i_dy);
\r
478 /// send a mouse-wheel-message to Windows
\r
479 void funcMouseWheel(FunctionParam *i_param, int i_delta);
\r
480 /// convert the contents of the Clipboard to upper case or lower case
\r
481 void funcClipboardChangeCase(FunctionParam *i_param,
\r
482 BooleanType i_doesConvertToUpperCase);
\r
483 /// convert the contents of the Clipboard to upper case
\r
484 void funcClipboardUpcaseWord(FunctionParam *i_param);
\r
485 /// convert the contents of the Clipboard to lower case
\r
486 void funcClipboardDowncaseWord(FunctionParam *i_param);
\r
487 /// set the contents of the Clipboard to the string
\r
488 void funcClipboardCopy(FunctionParam *i_param, const StrExprArg &i_text);
\r
490 void funcEmacsEditKillLinePred(FunctionParam *i_param,
\r
491 const KeySeq *i_keySeq1,
\r
492 const KeySeq *i_keySeq2);
\r
494 void funcEmacsEditKillLineFunc(FunctionParam *i_param);
\r
496 void funcLogClear(FunctionParam *i_param);
\r
498 void funcRecenter(FunctionParam *i_param);
\r
500 void funcDirectSSTP(FunctionParam *i_param,
\r
501 const tregex &i_name,
\r
502 const StrExprArg &i_protocol,
\r
503 const std::list<tstringq> &i_headers);
\r
505 void funcPlugIn(FunctionParam *i_param,
\r
506 const StrExprArg &i_dllName,
\r
507 const StrExprArg &i_funcName = StrExprArg(),
\r
508 const StrExprArg &i_funcParam = StrExprArg(),
\r
509 BooleanType i_doesCreateThread = BooleanType_false);
\r
510 /// set IME open status
\r
511 void funcSetImeStatus(FunctionParam *i_param, ToggleType i_toggle = ToggleType_toggle);
\r
512 /// set string to IME
\r
513 void funcSetImeString(FunctionParam *i_param, const StrExprArg &i_data);
\r
514 /// enter to mouse event hook mode
\r
515 void funcMouseHook(FunctionParam *i_param, MouseHookType i_hookType, int i_hookParam);
\r
517 void funcCancelPrefix(FunctionParam *i_param);
\r
519 // END OF FUNCTION DEFINITION
\r
520 # define FUNCTION_FRIEND
\r
521 # include "functions.h"
\r
522 # undef FUNCTION_FRIEND
\r
526 Engine(tomsgstream &i_log);
\r
530 /// start/stop keyboard handler thread
\r
535 /// pause keyboard handler thread and close device
\r
538 /// resume keyboard handler thread and re-open device
\r
541 /// do some procedure before quit which must be done synchronously
\r
542 /// (i.e. not on WM_QUIT)
\r
543 bool prepairQuit();
\r
546 void enableLogMode(bool i_isLogMode = true) {
\r
547 m_isLogMode = i_isLogMode;
\r
550 void disableLogMode() {
\r
551 m_isLogMode = false;
\r
554 /// enable/disable engine
\r
555 void enable(bool i_isEnabled = true) {
\r
556 m_isEnabled = i_isEnabled;
\r
560 m_isEnabled = false;
\r
563 bool getIsEnabled() const {
\r
564 return m_isEnabled;
\r
567 /// associated window
\r
568 void setAssociatedWndow(HWND i_hwnd) {
\r
569 m_hwndAssocWindow = i_hwnd;
\r
572 /// associated window
\r
573 HWND getAssociatedWndow() const {
\r
574 return m_hwndAssocWindow;
\r
578 bool setSetting(Setting *i_setting);
\r
581 bool setFocus(HWND i_hwndFocus, DWORD i_threadId,
\r
582 const tstringi &i_className,
\r
583 const tstringi &i_titleName, bool i_isConsole);
\r
586 bool setLockState(bool i_isNumLockToggled, bool i_isCapsLockToggled,
\r
587 bool i_isScrollLockToggled, bool i_isKanaLockToggled,
\r
588 bool i_isImeLockToggled, bool i_isImeCompToggled);
\r
591 void checkShow(HWND i_hwnd);
\r
592 bool setShow(bool i_isMaximized, bool i_isMinimized, bool i_isMDI);
\r
597 /// thread detach notify
\r
598 bool threadDetachNotify(DWORD i_threadId);
\r
601 void shellExecute();
\r
603 /// get help message
\r
604 void getHelpMessages(tstring *o_helpMessage, tstring *o_helpTitle);
\r
607 template <typename WPARAM_T, typename LPARAM_T>
\r
608 void commandNotify(HWND i_hwnd, UINT i_message, WPARAM_T i_wParam,
\r
611 Acquire b(&m_log, 0);
\r
612 HWND hf = m_hwndFocus;
\r
616 if (GetWindowThreadProcessId(hf, NULL) ==
\r
617 GetWindowThreadProcessId(m_hwndAssocWindow, NULL))
\r
618 return; // inhibit the investigation of MADO TSUKAI NO YUUTSU
\r
620 const _TCHAR *target = NULL;
\r
621 int number_target = 0;
\r
624 target = _T("ToItself");
\r
625 else if (i_hwnd == GetParent(hf))
\r
626 target = _T("ToParentWindow");
\r
628 // Function::toMainWindow
\r
631 HWND p = GetParent(h);
\r
637 target = _T("ToMainWindow");
\r
639 // Function::toOverlappedWindow
\r
643 LONG_PTR style = GetWindowLongPtr(h, GWL_STYLE);
\r
645 LONG style = GetWindowLong(h, GWL_STYLE);
\r
647 if ((style & WS_CHILD) == 0)
\r
652 target = _T("ToOverlappedWindow");
\r
656 for (number_target = 0; h; number_target ++, h = GetParent(h))
\r
664 m_log << _T("&PostMessage(");
\r
668 m_log << number_target;
\r
669 m_log << _T(", ") << i_message
\r
670 << _T(", 0x") << std::hex << i_wParam
\r
671 << _T(", 0x") << i_lParam << _T(") # hwnd = ")
\r
672 << reinterpret_cast<int>(i_hwnd) << _T(", ")
\r
673 << _T("message = ") << std::dec;
\r
674 if (i_message == WM_COMMAND)
\r
675 m_log << _T("WM_COMMAND, ");
\r
676 else if (i_message == WM_SYSCOMMAND)
\r
677 m_log << _T("WM_SYSCOMMAND, ");
\r
679 m_log << i_message << _T(", ");
\r
680 m_log << _T("wNotifyCode = ") << HIWORD(i_wParam) << _T(", ")
\r
681 << _T("wID = ") << LOWORD(i_wParam) << _T(", ")
\r
682 << _T("hwndCtrl = 0x") << std::hex << i_lParam << std::dec << std::endl;
\r
685 /// get current window class name
\r
686 const tstringi &getCurrentWindowClassName() const {
\r
687 return m_currentFocusOfThread->m_className;
\r
690 /// get current window title name
\r
691 const tstringi &getCurrentWindowTitleName() const {
\r
692 return m_currentFocusOfThread->m_titleName;
\r
698 class FunctionParam
\r
701 bool m_isPressed; /// is key pressed ?
\r
703 Engine::Current m_c; /// new context
\r
704 bool m_doesNeedEndl; /// need endl ?
\r
705 const ActionFunction *m_af; ///
\r
709 #endif // !_ENGINE_H
\r