SendKeys.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  1. #include "stdafx.h"
  2. #include "sendkeys.h"
  3. /*
  4. * -----------------------------------------------------------------------------
  5. * Copyright (c) 2004 lallous <[email protected]>
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  18. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  21. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27. * SUCH DAMAGE.
  28. * -----------------------------------------------------------------------------
  29. The Original SendKeys copyright info
  30. ---------------------------------------
  31. SendKeys (sndkeys32.pas) routine for 32-bit Delphi.
  32. Written by Ken Henderson
  33. Copyright (c) 1995 Ken Henderson <[email protected]>
  34. History
  35. ----------
  36. 04/19/2004
  37. * Initial version development
  38. 04/21/2004
  39. * Added number of times specifier to special keys
  40. * Added {BEEP X Y}
  41. * Added {APPACTIVATE WindowTitle}
  42. * Added CarryDelay() and now delay works properly with all keys
  43. * Added SetDelay() method
  44. * Fixed code in AppActivate that allowed to pass both NULL windowTitle/windowClass
  45. 05/21/2004
  46. * Fixed a bug in StringToVKey() that caused the search for RIGHTPAREN to be matched as RIGHT
  47. * Adjusted code so it compiles w/ VC6
  48. 05/24/2004
  49. * Added unicode support
  50. Todo
  51. -------
  52. * perhaps add mousecontrol: mousemove+mouse clicks
  53. * allow sending of normal keys multiple times as: {a 10}
  54. */
  55. const WORD CSendKeys::VKKEYSCANSHIFTON = 0x01;
  56. const WORD CSendKeys::VKKEYSCANCTRLON = 0x02;
  57. const WORD CSendKeys::VKKEYSCANALTON = 0x04;
  58. const WORD CSendKeys::INVALIDKEY = 0xFFFF;
  59. const BYTE CSendKeys::ExtendedVKeys[MaxExtendedVKeys] =
  60. {
  61. VK_UP,
  62. VK_DOWN,
  63. VK_LEFT,
  64. VK_RIGHT,
  65. VK_HOME,
  66. VK_END,
  67. VK_PRIOR, // PgUp
  68. VK_NEXT, // PgDn
  69. VK_INSERT,
  70. VK_DELETE,
  71. VK_CONTROL,
  72. VK_SHIFT,
  73. };
  74. CSendKeys::CSendKeys()
  75. {
  76. m_nDelayNow = m_nDelayAlways = m_keyDownDelay = 0;
  77. }
  78. // Delphi port regexps:
  79. // ---------------------
  80. // search: .+Name:'([^']+)'.+vkey:([^\)]+)\)
  81. // replace: {"\1", \2}
  82. //
  83. // **If you add to this list, you must be sure to keep it sorted alphabetically
  84. // by Name because a binary search routine is used to scan it.**
  85. //
  86. CSendKeys::key_desc_t CSendKeys::KeyNames[CSendKeys::MaxSendKeysRecs] =
  87. {
  88. {_T("ADD"), VK_ADD},
  89. {_T("APPS"), VK_APPS},
  90. {_T("AT"), '@', true},
  91. {_T("BACKSPACE"), VK_BACK},
  92. {_T("BKSP"), VK_BACK},
  93. {_T("BREAK"), VK_CANCEL},
  94. {_T("BS"), VK_BACK},
  95. {_T("CAPSLOCK"), VK_CAPITAL},
  96. {_T("CARET"), '^', true},
  97. {_T("CLEAR"), VK_CLEAR},
  98. {_T("DECIMAL"), VK_DECIMAL},
  99. {_T("DEL"), VK_DELETE},
  100. {_T("DELETE"), VK_DELETE},
  101. {_T("DIVIDE"), VK_DIVIDE},
  102. {_T("DOWN"), VK_DOWN},
  103. {_T("END"), VK_END},
  104. {_T("ENTER"), VK_RETURN},
  105. {_T("ESC"), VK_ESCAPE},
  106. {_T("ESCAPE"), VK_ESCAPE},
  107. {_T("F1"), VK_F1},
  108. {_T("F10"), VK_F10},
  109. {_T("F11"), VK_F11},
  110. {_T("F12"), VK_F12},
  111. {_T("F13"), VK_F13},
  112. {_T("F14"), VK_F14},
  113. {_T("F15"), VK_F15},
  114. {_T("F16"), VK_F16},
  115. {_T("F2"), VK_F2},
  116. {_T("F3"), VK_F3},
  117. {_T("F4"), VK_F4},
  118. {_T("F5"), VK_F5},
  119. {_T("F6"), VK_F6},
  120. {_T("F7"), VK_F7},
  121. {_T("F8"), VK_F8},
  122. {_T("F9"), VK_F9},
  123. {_T("HELP"), VK_HELP},
  124. {_T("HOME"), VK_HOME},
  125. {_T("INS"), VK_INSERT},
  126. {_T("LEFT"), VK_LEFT},
  127. {_T("LEFTBRACE"), '{', true},
  128. {_T("LEFTPAREN"), '(', true},
  129. {_T("LWIN"), VK_LWIN},
  130. {_T("MULTIPLY"), VK_MULTIPLY},
  131. {_T("NUMLOCK"), VK_NUMLOCK},
  132. {_T("NUMPAD0"), VK_NUMPAD0},
  133. {_T("NUMPAD1"), VK_NUMPAD1},
  134. {_T("NUMPAD2"), VK_NUMPAD2},
  135. {_T("NUMPAD3"), VK_NUMPAD3},
  136. {_T("NUMPAD4"), VK_NUMPAD4},
  137. {_T("NUMPAD5"), VK_NUMPAD5},
  138. {_T("NUMPAD6"), VK_NUMPAD6},
  139. {_T("NUMPAD7"), VK_NUMPAD7},
  140. {_T("NUMPAD8"), VK_NUMPAD8},
  141. {_T("NUMPAD9"), VK_NUMPAD9},
  142. {_T("PERCENT"), '%', true},
  143. {_T("PGDN"), VK_NEXT},
  144. {_T("PGUP"), VK_PRIOR},
  145. {_T("PLUS"), '+', true},
  146. {_T("PRTSC"), VK_PRINT},
  147. {_T("RIGHT"), VK_RIGHT},
  148. {_T("RIGHTBRACE"), '}', true},
  149. {_T("RIGHTPAREN"), ')', true},
  150. {_T("RWIN"), VK_RWIN},
  151. {_T("SCROLL"), VK_SCROLL},
  152. {_T("SEPARATOR"), VK_SEPARATOR},
  153. {_T("SNAPSHOT"), VK_SNAPSHOT},
  154. {_T("SUBTRACT"), VK_SUBTRACT},
  155. {_T("TAB"), VK_TAB},
  156. {_T("TILDE"), '~', true},
  157. {_T("UP"), VK_UP},
  158. {_T("WIN"), VK_LWIN}
  159. };
  160. // calls keybd_event() and waits, if needed, till the sent input is processed
  161. void CSendKeys::KeyboardEvent(BYTE VKey, BYTE ScanCode, LONG Flags)
  162. {
  163. keybd_event(VKey, ScanCode, Flags, 0);
  164. if (m_bWait)
  165. {
  166. MSG KeyboardMsg;
  167. while (::PeekMessage(&KeyboardMsg, 0, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
  168. {
  169. ::TranslateMessage(&KeyboardMsg);
  170. ::DispatchMessage(&KeyboardMsg);
  171. }
  172. }
  173. }
  174. // Checks whether the specified VKey is an extended key or not
  175. bool CSendKeys::IsVkExtended(BYTE VKey)
  176. {
  177. for (int i=0;i<MaxExtendedVKeys;i++)
  178. {
  179. if (ExtendedVKeys[i] == VKey)
  180. return true;
  181. }
  182. return false;
  183. }
  184. CString CSendKeys::VkString(BYTE VKey)
  185. {
  186. for (int i = 0; i < MaxSendKeysRecs; i++)
  187. {
  188. if (KeyNames[i].VKey == VKey)
  189. return KeyNames[i].keyName;
  190. }
  191. return _T("");
  192. }
  193. void CSendKeys::AllKeysUp()
  194. {
  195. for (int key = 0; key < 256; key++)
  196. {
  197. //If the key is pressed, send a key up, having other keys down interferes with sending ctrl-v, -c and -x
  198. short val = GetKeyState(key);
  199. if (val & 0x8000)
  200. {
  201. SendKeyUp(key);
  202. //CString cs;
  203. //cs.Format(_T("key was down, sending key up %d, value: %d\n"), key, val);
  204. //OutputDebugString(cs);
  205. }
  206. }
  207. //Force these to be up, i was having trouble with the right shift key, i think things were
  208. //getting confused between the basic shift and lshift, but not sure.
  209. SendKeyUp(VK_LSHIFT);
  210. SendKeyUp(VK_RSHIFT);
  211. SendKeyUp(VK_LCONTROL);
  212. SendKeyUp(VK_RCONTROL);
  213. SendKeyUp(VK_LMENU);
  214. SendKeyUp(VK_RMENU);
  215. }
  216. // Generates KEYUP
  217. void CSendKeys::SendKeyUp(BYTE VKey)
  218. {
  219. BYTE ScanCode = LOBYTE(::MapVirtualKey(VKey, 0));
  220. KeyboardEvent(VKey,
  221. ScanCode,
  222. KEYEVENTF_KEYUP | (IsVkExtended(VKey) ? KEYEVENTF_EXTENDEDKEY : 0));
  223. }
  224. void CSendKeys::SendKeyDown(BYTE VKey, WORD NumTimes, bool GenUpMsg, bool bDelay)
  225. {
  226. WORD Cnt = 0;
  227. BYTE ScanCode = 0;
  228. bool NumState = false;
  229. if (VKey == VK_NUMLOCK)
  230. {
  231. DWORD dwVersion = ::GetVersion();
  232. for (Cnt=1; Cnt<=NumTimes; Cnt++)
  233. {
  234. if (bDelay)
  235. CarryDelay();
  236. // snippet based on:
  237. // http://www.codeproject.com/cpp/togglekeys.asp
  238. if (dwVersion < 0x80000000)
  239. {
  240. ::keybd_event(VKey, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
  241. ::keybd_event(VKey, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
  242. }
  243. else
  244. {
  245. // Win98 and later
  246. if ( ((DWORD)(HIBYTE(LOWORD(dwVersion))) >= 10) )
  247. {
  248. // Define _WIN32_WINNT > 0x0400
  249. // to compile
  250. INPUT input[2] = {0};
  251. input[0].type = input[1].type = INPUT_KEYBOARD;
  252. input[0].ki.wVk = input[1].ki.wVk = VKey;
  253. input[1].ki.dwFlags = KEYEVENTF_KEYUP;
  254. ::SendInput(sizeof(input) / sizeof(INPUT), input, sizeof(INPUT));
  255. }
  256. // Win95
  257. else
  258. {
  259. KEYBOARDSTATE_t KeyboardState;
  260. NumState = GetKeyState(VK_NUMLOCK) & 1 ? true : false;
  261. GetKeyboardState(&KeyboardState[0]);
  262. if (NumState)
  263. KeyboardState[VK_NUMLOCK] &= ~1;
  264. else
  265. KeyboardState[VK_NUMLOCK] |= 1;
  266. SetKeyboardState(&KeyboardState[0]);
  267. }
  268. }
  269. }
  270. return;
  271. }
  272. // Get scancode
  273. ScanCode = LOBYTE(::MapVirtualKey(VKey, 0));
  274. // Send keys
  275. for (Cnt=1; Cnt<=NumTimes; Cnt++)
  276. {
  277. // Carry needed delay ?
  278. if (bDelay)
  279. CarryDelay();
  280. KeyboardEvent(VKey, ScanCode, IsVkExtended(VKey) ? KEYEVENTF_EXTENDEDKEY : 0);
  281. if(m_keyDownDelay > 0)
  282. {
  283. Sleep(m_keyDownDelay);
  284. }
  285. if (GenUpMsg)
  286. {
  287. SendKeyUp(VKey);
  288. }
  289. }
  290. }
  291. // Checks whether a bit is set
  292. bool CSendKeys::BitSet(BYTE BitTable, UINT BitMask)
  293. {
  294. return BitTable & BitMask ? true : false;
  295. }
  296. // Sends a single key
  297. void CSendKeys::SendKey(WORD MKey, WORD NumTimes, bool GenDownMsg)
  298. {
  299. // Send appropriate shift keys associated with the given VKey
  300. if (BitSet(HIBYTE(MKey), VKKEYSCANSHIFTON))
  301. SendKeyDown(VK_SHIFT, 1, false);
  302. if (BitSet(HIBYTE(MKey), VKKEYSCANCTRLON))
  303. SendKeyDown(VK_CONTROL, 1, false);
  304. if (BitSet(HIBYTE(MKey), VKKEYSCANALTON))
  305. SendKeyDown(VK_MENU, 1, false);
  306. // Send the actual VKey
  307. SendKeyDown(LOBYTE(MKey), NumTimes, GenDownMsg, true);
  308. // toggle up shift keys
  309. if (BitSet(HIBYTE(MKey), VKKEYSCANSHIFTON))
  310. SendKeyUp(VK_SHIFT);
  311. if (BitSet(HIBYTE(MKey), VKKEYSCANCTRLON))
  312. SendKeyUp(VK_CONTROL);
  313. if (BitSet(HIBYTE(MKey), VKKEYSCANALTON))
  314. SendKeyUp(VK_MENU);
  315. }
  316. // Implements a simple binary search to locate special key name strings
  317. WORD CSendKeys::StringToVKey(LPCTSTR KeyString, int &idx)
  318. {
  319. bool Found = false, Collided;
  320. int Bottom = 0,
  321. Top = MaxSendKeysRecs,
  322. Middle = (Bottom + Top) / 2;
  323. WORD retval = INVALIDKEY;
  324. idx = -1;
  325. do
  326. {
  327. Collided = (Bottom == Middle) || (Top == Middle);
  328. int cmp = _tcsnicmp(KeyNames[Middle].keyName, KeyString, _tcslen(KeyString));
  329. if (cmp == 0)
  330. {
  331. Found = true;
  332. retval = KeyNames[Middle].VKey;
  333. idx = Middle;
  334. break;
  335. }
  336. else
  337. {
  338. if (cmp < 0)
  339. Bottom = Middle;
  340. else
  341. Top = Middle;
  342. Middle = (Bottom + Top) / 2;
  343. }
  344. } while (!(Found || Collided));
  345. return retval;
  346. }
  347. // Releases all shift keys (keys that can be depressed while other keys are being pressed
  348. // If we are in a modifier group this function does nothing
  349. void CSendKeys::PopUpShiftKeys()
  350. {
  351. if (!m_bUsingParens)
  352. {
  353. if (m_bShiftDown)
  354. {
  355. SendKeyUp(VK_SHIFT);
  356. }
  357. if (m_bLShiftDown)
  358. {
  359. SendKeyUp(VK_LSHIFT);
  360. }
  361. if (m_bRShiftDown)
  362. {
  363. SendKeyUp(VK_RSHIFT);
  364. }
  365. if (m_bControlDown)
  366. {
  367. SendKeyUp(VK_CONTROL);
  368. }
  369. if (m_bLControlDown)
  370. {
  371. SendKeyUp(VK_LCONTROL);
  372. }
  373. if (m_bRControlDown)
  374. {
  375. SendKeyUp(VK_RCONTROL);
  376. }
  377. if (m_bAltDown)
  378. {
  379. SendKeyUp(VK_MENU);
  380. }
  381. if (m_bWinDown)
  382. {
  383. SendKeyUp(VK_LWIN);
  384. }
  385. m_bWinDown = m_bShiftDown = m_bLShiftDown = m_bRShiftDown = m_bControlDown = m_bLControlDown = m_bRControlDown = m_bAltDown = false;
  386. }
  387. }
  388. // Sends a key string
  389. bool CSendKeys::SendKeys(LPCTSTR KeysString, bool Wait)
  390. {
  391. WORD MKey;
  392. WORD NumTimes = 1;
  393. TCHAR KeyString[300] = {0};
  394. bool retval = false;
  395. int keyIdx;
  396. LPTSTR pKey = (LPTSTR) KeysString;
  397. TCHAR ch;
  398. m_bWait = Wait;
  399. m_bWinDown = m_bShiftDown = m_bLShiftDown = m_bRShiftDown = m_bControlDown = m_bLControlDown = m_bRControlDown = m_bAltDown = m_bUsingParens = false;
  400. while (ch = *pKey)
  401. {
  402. switch (ch)
  403. {
  404. // begin modifier group
  405. case _TXCHAR('('):
  406. m_bUsingParens = true;
  407. break;
  408. // end modifier group
  409. case _TXCHAR(')'):
  410. m_bUsingParens = false;
  411. PopUpShiftKeys(); // pop all shift keys when we finish a modifier group close
  412. break;
  413. // ALT key
  414. case _TXCHAR('%'):
  415. m_bAltDown = true;
  416. SendKeyDown(VK_MENU, 1, false);
  417. break;
  418. // SHIFT key
  419. case _TXCHAR('+'):
  420. m_bShiftDown = true;
  421. SendKeyDown(VK_SHIFT, 1, false);
  422. break;
  423. // CTRL key
  424. case _TXCHAR('^'):
  425. m_bControlDown = true;
  426. SendKeyDown(VK_CONTROL, 1, false);
  427. break;
  428. // WINKEY (Left-WinKey)
  429. case '@':
  430. m_bWinDown = true;
  431. SendKeyDown(VK_LWIN, 1, false);
  432. break;
  433. // enter
  434. case _TXCHAR('~'):
  435. SendKeyDown(VK_RETURN, 1, true);
  436. PopUpShiftKeys();
  437. break;
  438. // begin special keys
  439. case _TXCHAR('{'):
  440. {
  441. LPTSTR p = pKey+1; // skip past the beginning '{'
  442. size_t t;
  443. // find end of close
  444. while (*p && *p != _TXCHAR('}'))
  445. p++;
  446. t = p - pKey;
  447. // special key definition too big?
  448. if (t > sizeof(KeyString))
  449. return false;
  450. // Take this KeyString into local buffer
  451. _tcsncpy(KeyString, pKey+1, t);
  452. KeyString[t-1] = _TXCHAR('\0');
  453. keyIdx = -1;
  454. pKey += t; // skip to next keystring
  455. // Invalidate key
  456. MKey = INVALIDKEY;
  457. // sending arbitrary vkeys?
  458. if (_tcsnicmp(KeyString, _T("VKEY"), 4) == 0)
  459. {
  460. p = KeyString + 4;
  461. MKey = _ttoi(p);
  462. }
  463. else if (_tcsnicmp(KeyString, _T("BEEP"), 4) == 0)
  464. {
  465. p = KeyString + 4 + 1;
  466. LPTSTR p1 = p;
  467. DWORD frequency, delay;
  468. if ((p1 = _tcsstr(p, _T(" "))) != NULL)
  469. {
  470. *p1++ = _TXCHAR('\0');
  471. frequency = _ttoi(p);
  472. delay = _ttoi(p1);
  473. ::Beep(frequency, delay);
  474. }
  475. }
  476. // Should activate a window?
  477. else if (_tcsnicmp(KeyString, _T("APPACTIVATE"), 11) == 0)
  478. {
  479. p = KeyString + 11 + 1;
  480. AppActivate(p);
  481. }
  482. // want to send/set delay?
  483. else if (_tcsnicmp(KeyString, _T("DELAY"), 5) == 0)
  484. {
  485. // Advance to parameters
  486. p = KeyString + 5;
  487. // set "sleep factor"
  488. if (*p == _TXCHAR('='))
  489. m_nDelayAlways = _ttoi(p + 1); // Take number after the '=' character
  490. else
  491. // set "sleep now"
  492. m_nDelayNow = _ttoi(p);
  493. }
  494. // not command special keys, then process as keystring to VKey
  495. else
  496. {
  497. MKey = StringToVKey(KeyString, keyIdx);
  498. // Key found in table
  499. if (keyIdx != -1)
  500. {
  501. NumTimes = 1;
  502. // Does the key string have also count specifier?
  503. t = _tcslen(KeyNames[keyIdx].keyName);
  504. if (_tcslen(KeyString) > t)
  505. {
  506. p = KeyString + t;
  507. // Take the specified number of times
  508. NumTimes = _ttoi(p);
  509. }
  510. if (KeyNames[keyIdx].normalkey)
  511. MKey = ::VkKeyScan(KeyNames[keyIdx].VKey);
  512. }
  513. }
  514. // A valid key to send?
  515. if (MKey != INVALIDKEY)
  516. {
  517. if (MKey == VK_LCONTROL ||
  518. MKey == VK_RCONTROL)
  519. {
  520. m_bLControlDown = (MKey == VK_LCONTROL);
  521. m_bRControlDown = (MKey == VK_RCONTROL);
  522. SendKeyDown(MKey, 1, false);
  523. }
  524. else if (MKey == VK_LSHIFT ||
  525. MKey == VK_RSHIFT)
  526. {
  527. m_bLShiftDown = (MKey == VK_LSHIFT);
  528. m_bRShiftDown = (MKey == VK_RSHIFT);
  529. SendKeyDown(MKey, 1, false);
  530. }
  531. else
  532. {
  533. SendKey(MKey, NumTimes, true);
  534. PopUpShiftKeys();
  535. }
  536. }
  537. }
  538. break;
  539. // a normal key was pressed
  540. default:
  541. // Get the VKey from the key
  542. MKey = ::VkKeyScan(ch);
  543. SendKey(MKey, 1, true);
  544. PopUpShiftKeys();
  545. }
  546. pKey++;
  547. }
  548. m_bUsingParens = false;
  549. PopUpShiftKeys();
  550. return true;
  551. }
  552. bool CSendKeys::AppActivate(HWND wnd)
  553. {
  554. if (wnd == NULL)
  555. return false;
  556. ::SendMessage(wnd, WM_SYSCOMMAND, SC_HOTKEY, (LPARAM) wnd);
  557. ::SendMessage(wnd, WM_SYSCOMMAND, SC_RESTORE, (LPARAM) wnd);
  558. ::ShowWindow(wnd, SW_SHOW);
  559. ::SetForegroundWindow(wnd);
  560. ::SetFocus(wnd);
  561. return true;
  562. }
  563. BOOL CALLBACK CSendKeys::enumwindowsProc(HWND hwnd, LPARAM lParam)
  564. {
  565. enumwindow_t *t = (enumwindow_t *) lParam;
  566. LPTSTR wtitle = 0, wclass = 0, str = t->str;
  567. if (!*str)
  568. str++;
  569. else
  570. {
  571. wtitle = str;
  572. str += _tcslen(str) + 1;
  573. }
  574. if (*str)
  575. wclass = str;
  576. bool bMatch(false);
  577. if (wclass)
  578. {
  579. TCHAR szClass[300];
  580. if (::GetClassName(hwnd, szClass, sizeof(szClass)))
  581. bMatch |= (_tcsstr(szClass, wclass) != 0);
  582. }
  583. if (wtitle)
  584. {
  585. TCHAR szTitle[300];
  586. if (::GetWindowText(hwnd, szTitle, sizeof(szTitle)))
  587. bMatch |= (_tcsstr(szTitle, wtitle) != 0);
  588. }
  589. if (bMatch)
  590. {
  591. t->hwnd = hwnd;
  592. return false;
  593. }
  594. return true;
  595. }
  596. // Searchs and activates a window given its title or class name
  597. bool CSendKeys::AppActivate(LPCTSTR WindowTitle, LPCTSTR WindowClass)
  598. {
  599. HWND w;
  600. w = ::FindWindow(WindowClass, WindowTitle);
  601. if (w == NULL)
  602. {
  603. // Must specify at least a criteria
  604. if (WindowTitle == NULL && WindowClass == NULL)
  605. return false;
  606. // << Code to serialize the windowtitle/windowclass in order to send to EnumWindowProc()
  607. size_t l1(0), l2(0);
  608. if (WindowTitle)
  609. l1 = _tcslen(WindowTitle);
  610. if (WindowClass)
  611. l2 = _tcslen(WindowClass);
  612. LPTSTR titleclass = new TCHAR [l1 + l2 + 5];
  613. memset(titleclass, '\0', l1+l2+5);
  614. if (WindowTitle)
  615. _tcscpy(titleclass, WindowTitle);
  616. titleclass[l1] = 0;
  617. if (WindowClass)
  618. _tcscpy(titleclass+l1+1, WindowClass);
  619. // >>
  620. enumwindow_t t;
  621. t.hwnd = NULL;
  622. t.str = titleclass;
  623. ::EnumWindows(enumwindowsProc, (LPARAM) & t);
  624. w = t.hwnd;
  625. delete [] titleclass;
  626. }
  627. if (w == NULL)
  628. return false;
  629. return AppActivate(w);
  630. }
  631. // Carries the required delay and clears the m_nDelaynow value
  632. void CSendKeys::CarryDelay()
  633. {
  634. // Should we delay once?
  635. if (!m_nDelayNow)
  636. // should we delay always?
  637. m_nDelayNow = m_nDelayAlways;
  638. // No delay specified?
  639. if (m_nDelayNow)
  640. ::Sleep(m_nDelayNow); //::Beep(100, m_nDelayNow);
  641. // clear SleepNow
  642. m_nDelayNow = 0;
  643. }
  644. /*
  645. Test Binary search
  646. void CSendKeys::test()
  647. {
  648. WORD miss(0);
  649. for (int i=0;i<MaxSendKeysRecs;i++)
  650. {
  651. char *p = (char *)KeyNames[i].keyName;
  652. WORD v = StringToVKeyB(p);
  653. if (v == INVALIDKEY)
  654. {
  655. miss++;
  656. }
  657. }
  658. }
  659. */
  660. /*
  661. Search in a linear manner
  662. WORD CSendKeys::StringToVKey(const char *KeyString, int &idx)
  663. {
  664. for (int i=0;i<MaxSendKeysRecs;i++)
  665. {
  666. size_t len = strlen(KeyNames[i].keyName);
  667. if (strnicmp(KeyNames[i].keyName, KeyString, len) == 0)
  668. {
  669. idx = i;
  670. return KeyNames[i].VKey;
  671. }
  672. }
  673. idx = -1;
  674. return INVALIDKEY;
  675. }
  676. */