input_object.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #include "stdafx.h" // pre-compiled headers
  2. #include "defines.h"
  3. #include "globaldata.h"
  4. #include "script.h"
  5. #include "application.h"
  6. #include "script_object.h"
  7. #include "script_func_impl.h"
  8. #include "input_object.h"
  9. ObjectMemberMd InputObject::sMembers[] =
  10. {
  11. #define BOOL_OPTION(OPT) md_property(InputObject, OPT, Bool32)
  12. #define ONX_OPTION(X) \
  13. md_property_get(InputObject, On##X, Object), \
  14. md_property_set(InputObject, On##X, Variant)
  15. md_member(InputObject, __New, CALL, (In_Opt, String, Options), (In_Opt, String, EndKeys), (In_Opt, String, MatchList)),
  16. md_member(InputObject, KeyOpt, CALL, (In, String, Keys), (In, String, KeyOptions)),
  17. md_member(InputObject, Start, CALL, md_arg_none),
  18. md_member(InputObject, Stop, CALL, md_arg_none),
  19. md_member(InputObject, Wait, CALL, (In_Opt, Float64, MaxTime), (Ret, String, RetVal)),
  20. BOOL_OPTION(BackspaceIsUndo),
  21. BOOL_OPTION(CaseSensitive),
  22. BOOL_OPTION(FindAnywhere),
  23. BOOL_OPTION(NotifyNonText),
  24. BOOL_OPTION(VisibleNonText),
  25. BOOL_OPTION(VisibleText),
  26. md_property_get(InputObject, EndKey, String),
  27. md_property_get(InputObject, EndMods, String),
  28. md_property_get(InputObject, EndReason, String),
  29. md_property_get(InputObject, InProgress, Bool32),
  30. md_property_get(InputObject, Input, String),
  31. md_property_get(InputObject, Match, String),
  32. md_property(InputObject, MinSendLevel, Int32),
  33. ONX_OPTION(Char),
  34. ONX_OPTION(End),
  35. ONX_OPTION(KeyDown),
  36. ONX_OPTION(KeyUp),
  37. md_property(InputObject, Timeout, Float64)
  38. #undef BOOL_OPTION
  39. #undef ONX_OPTION
  40. };
  41. int InputObject::sMemberCount = _countof(sMembers);
  42. Object *InputObject::sPrototype;
  43. InputObject::InputObject()
  44. {
  45. input.ScriptObject = this;
  46. SetBase(sPrototype);
  47. }
  48. Object *InputObject::Create()
  49. {
  50. return new InputObject();
  51. }
  52. FResult InputObject::__New(optl<StrArg> aOptions, optl<StrArg> aEndKeys, optl<StrArg> aMatchList)
  53. {
  54. return input.Setup(aOptions.value_or_empty(), aEndKeys.value_or_empty(), aMatchList.value_or_empty()) ? OK : FR_FAIL;
  55. }
  56. FResult InputObject::Start()
  57. {
  58. if (!input.InProgress())
  59. {
  60. input.Buffer[input.BufferLength = 0] = '\0';
  61. InputStart(input);
  62. }
  63. return OK;
  64. }
  65. FResult InputObject::Wait(optl<double> aMaxTime, StrRet &aRetVal)
  66. {
  67. auto wait_ms = aMaxTime.has_value() ? (UINT)(aMaxTime.value() * 1000) : UINT_MAX;
  68. auto tick_start = GetTickCount();
  69. while (input.InProgress() && (GetTickCount() - tick_start) < wait_ms)
  70. MsgSleep();
  71. return get_EndReason(aRetVal);
  72. }
  73. FResult InputObject::Stop()
  74. {
  75. if (input.InProgress())
  76. input.Stop();
  77. return OK;
  78. }
  79. FResult InputObject::get_EndReason(StrRet &aRetVal)
  80. {
  81. aRetVal.SetStatic(input.GetEndReason(NULL, 0));
  82. return OK;
  83. }
  84. FResult InputObject::get_EndKey(StrRet &aRetVal)
  85. {
  86. if (input.Status == INPUT_TERMINATED_BY_ENDKEY)
  87. {
  88. auto buf = aRetVal.CallerBuf();
  89. input.GetEndReason(buf, aRetVal.CallerBufSize);
  90. aRetVal.SetTemp(buf);
  91. }
  92. else
  93. aRetVal.SetEmpty();
  94. return OK;
  95. }
  96. FResult InputObject::get_EndMods(StrRet &aRetVal)
  97. {
  98. auto buf = aRetVal.CallerBuf(), cp = buf;
  99. const auto mod_string = MODLR_STRING;
  100. for (int i = 0; i < 8; ++i)
  101. if (input.EndingMods & (1 << i))
  102. {
  103. *cp++ = mod_string[i * 2];
  104. *cp++ = mod_string[i * 2 + 1];
  105. }
  106. *cp = '\0';
  107. aRetVal.SetTemp(buf, cp - buf);
  108. return OK;
  109. }
  110. FResult InputObject::get_Input(StrRet &aRetVal)
  111. {
  112. aRetVal.SetTemp(input.Buffer, input.BufferLength);
  113. return OK;
  114. }
  115. FResult InputObject::get_Match(StrRet &aRetVal)
  116. {
  117. if (input.Status == INPUT_TERMINATED_BY_MATCH && input.EndingMatchIndex < input.MatchCount)
  118. aRetVal.SetTemp(input.match[input.EndingMatchIndex]);
  119. else
  120. aRetVal.SetEmpty();
  121. return OK;
  122. }
  123. FResult InputObject::get_On(IObject *&aRetVal, IObject *&aOn)
  124. {
  125. if (aRetVal = aOn)
  126. aRetVal->AddRef();
  127. return OK;
  128. }
  129. FResult InputObject::set_On(ExprTokenType &aValue, IObject *&aOn, int aValidParamCount)
  130. {
  131. auto obj = TokenToObject(aValue);
  132. if (obj)
  133. {
  134. auto fr = ValidateFunctor(obj, aValidParamCount);
  135. if (fr != OK)
  136. return fr;
  137. obj->AddRef();
  138. }
  139. else if (!TokenIsEmptyString(aValue))
  140. return FTypeError(_T("object"), aValue);
  141. auto prev = aOn;
  142. aOn = obj;
  143. if (prev)
  144. prev->Release();
  145. return OK;
  146. }
  147. FResult InputObject::set_MinSendLevel(int aValue)
  148. {
  149. if (aValue < 0 || aValue > 101)
  150. return FR_E_ARG(0);
  151. input.MinSendLevel = aValue;
  152. return OK;
  153. }
  154. FResult InputObject::set_Timeout(double aValue)
  155. {
  156. input.Timeout = (int)(aValue * 1000);
  157. if (input.InProgress() && input.Timeout > 0)
  158. input.SetTimeoutTimer();
  159. return OK;
  160. }
  161. FResult InputObject::KeyOpt(StrArg keys, StrArg options)
  162. {
  163. bool adding = true;
  164. UCHAR flag, add_flags = 0, remove_flags = 0;
  165. for (auto cp = options; *cp; ++cp)
  166. {
  167. switch (ctoupper(*cp))
  168. {
  169. case '+': adding = true; continue;
  170. case '-': adding = false; continue;
  171. case ' ': case '\t': continue;
  172. case 'E': flag = END_KEY_ENABLED; break;
  173. case 'I': flag = INPUT_KEY_IGNORE_TEXT; break;
  174. case 'N': flag = INPUT_KEY_NOTIFY; break;
  175. case 'S':
  176. flag = INPUT_KEY_SUPPRESS;
  177. if (adding)
  178. remove_flags |= INPUT_KEY_VISIBLE;
  179. break;
  180. case 'V':
  181. flag = INPUT_KEY_VISIBLE;
  182. if (adding)
  183. remove_flags |= INPUT_KEY_SUPPRESS;
  184. break;
  185. case 'Z': // Zero (reset)
  186. add_flags = 0;
  187. remove_flags = INPUT_KEY_OPTION_MASK;
  188. continue;
  189. default: return FValueError(ERR_INVALID_OPTION, cp);
  190. }
  191. if (adding)
  192. add_flags |= flag; // Add takes precedence over remove, so remove_flags isn't changed.
  193. else
  194. {
  195. remove_flags |= flag;
  196. add_flags &= ~flag; // Override any previous add.
  197. }
  198. }
  199. if (!_tcsicmp(keys, _T("{All}")))
  200. {
  201. // Could optimize by using memset() when remove_flags == 0xFF, but that doesn't seem
  202. // worthwhile since this mode is already faster than SetKeyFlags() with a single key.
  203. for (int i = 0; i < _countof(input.KeyVK); ++i)
  204. input.KeyVK[i] = (input.KeyVK[i] & ~remove_flags) | add_flags;
  205. for (int i = 0; i < _countof(input.KeySC); ++i)
  206. input.KeySC[i] = (input.KeySC[i] & ~remove_flags) | add_flags;
  207. return OK;
  208. }
  209. return input.SetKeyFlags(keys, false, remove_flags, add_flags) ? OK : FR_FAIL;
  210. }