ExternalWindowTracker.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #include "stdafx.h"
  2. #include "externalwindowtracker.h"
  3. #include "Misc.h"
  4. #include "SendKeys.h"
  5. #include "Options.h"
  6. #include "CP_Main.h"
  7. ExternalWindowTracker::ExternalWindowTracker(void)
  8. {
  9. m_activeWnd = NULL;
  10. m_focusWnd = NULL;
  11. m_dittoHasFocus = false;
  12. }
  13. ExternalWindowTracker::~ExternalWindowTracker(void)
  14. {
  15. }
  16. bool ExternalWindowTracker::TrackActiveWnd(HWND focus)
  17. {
  18. BOOL fromHook = true;
  19. HWND newFocus = focus;
  20. HWND newActive = ::GetForegroundWindow();
  21. if(newFocus == NULL)
  22. {
  23. if(AttachThreadInput(GetWindowThreadProcessId(newActive, NULL), GetCurrentThreadId(), TRUE))
  24. {
  25. newFocus = GetFocus();
  26. AttachThreadInput(GetWindowThreadProcessId(newActive, NULL), GetCurrentThreadId(), FALSE);
  27. }
  28. else
  29. {
  30. //Log(_T("TrackActiveWnd - AttachThreadInput failed"));
  31. }
  32. fromHook = false;
  33. }
  34. if(newFocus == 0 && newActive != 0)
  35. {
  36. newFocus = newActive;
  37. }
  38. else if(newActive == 0 && newFocus != 0)
  39. {
  40. newActive = newFocus;
  41. }
  42. if(newFocus == 0 || !IsWindow(newFocus) || newActive == 0 || !IsWindow(newActive))
  43. {
  44. Log(_T("TargetActiveWindow values invalid"));
  45. return false;
  46. }
  47. if(newActive == m_activeWnd)
  48. {
  49. // Log(_T("TargetActiveWindow window the same"));
  50. return false;
  51. }
  52. TCHAR className[100];
  53. GetClassName(newActive, className, (sizeof(className) / sizeof(TCHAR)));
  54. if(STRCMP(className, _T("Shell_TrayWnd")) == 0)
  55. {
  56. Log(_T("TargetActiveWindow shell tray icon has active"));
  57. return false;
  58. }
  59. if(IsAppWnd(newFocus) || IsAppWnd(newActive))
  60. {
  61. if(m_dittoHasFocus == false)
  62. {
  63. Log(StrF(_T("Ditto has focus - Active: %s (%d), Focus: %s (%d), FromHook %d"), WndName(m_activeWnd), m_activeWnd, WndName(m_focusWnd), m_focusWnd, fromHook));
  64. }
  65. m_dittoHasFocus = true;
  66. return false;
  67. }
  68. m_focusWnd = newFocus;
  69. m_activeWnd = newActive;
  70. m_dittoHasFocus = false;
  71. if(theApp.QPasteWnd())
  72. theApp.QPasteWnd()->UpdateStatus(true);
  73. Log(StrF(_T("TargetActiveWindow Active: %s (%d), Focus: %s (%d), FromHook %d"), WndName(m_activeWnd), m_activeWnd, WndName(m_focusWnd), m_focusWnd, fromHook));
  74. return true;
  75. }
  76. bool ExternalWindowTracker::WaitForActiveWnd(HWND activeWnd, int timeout)
  77. {
  78. DWORD start = GetTickCount();
  79. while(((int)(GetTickCount() - start)) < timeout)
  80. {
  81. if(::GetForegroundWindow() == activeWnd)
  82. {
  83. Log(StrF(_T("found focus wait %d"), GetTickCount()-start));
  84. return true;
  85. }
  86. Sleep(0);
  87. ActivateTarget();
  88. }
  89. Log(_T("Didn't find focus"));
  90. return false;
  91. }
  92. void ExternalWindowTracker::ActivateFocus(const HWND activeHwnd, const HWND focushWnd)
  93. {
  94. CString csApp = GetProcessName(m_activeWnd);
  95. Log(StrF(_T("SetFocus - AppName: %s, Active: %d, Focus: %d"), csApp, m_activeWnd, m_focusWnd));
  96. if (focushWnd != NULL)
  97. {
  98. AttachThreadInput(GetWindowThreadProcessId(activeHwnd, NULL), GetCurrentThreadId(), TRUE);
  99. if (GetFocus() != focushWnd)
  100. {
  101. SetFocus(focushWnd);
  102. }
  103. AttachThreadInput(GetWindowThreadProcessId(activeHwnd, NULL), GetCurrentThreadId(), FALSE);
  104. }
  105. }
  106. bool ExternalWindowTracker::ActivateTarget()
  107. {
  108. Log(StrF(_T("Activate Target - Active: %d, Focus: %d"), m_activeWnd, m_focusWnd));
  109. if (IsIconic(m_activeWnd))
  110. {
  111. ShowWindow(m_activeWnd, SW_RESTORE);
  112. }
  113. // Save specified timeout period...
  114. DWORD timeoutMS = 0;
  115. SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &timeoutMS, 0);
  116. // ... then set it to zero to disable it
  117. SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)0, 0);
  118. //If we are doing this and we are not the current foreground window then attach to the current bef
  119. //setting the focus window
  120. //this shouldn't happen that much, most of the time we are the foreground window
  121. bool detach = false;
  122. DWORD foreGroundProcessId = GetWindowThreadProcessId(::GetForegroundWindow(), NULL);
  123. if(foreGroundProcessId != GetCurrentThreadId())
  124. {
  125. Log(_T("Attach to process, calling set foreground from non forground window"));
  126. if(AttachThreadInput(foreGroundProcessId, GetCurrentThreadId(), TRUE))
  127. {
  128. detach = true;
  129. }
  130. }
  131. BringWindowToTop(m_activeWnd);
  132. SetForegroundWindow(m_activeWnd);
  133. if(detach)
  134. {
  135. AttachThreadInput(foreGroundProcessId, GetCurrentThreadId(), FALSE);
  136. }
  137. //check to see if this app should set focus
  138. //this is off by default
  139. CString csApp = GetProcessName(m_activeWnd);
  140. if(g_Opt.GetSetFocusToApp(csApp))
  141. {
  142. ActivateFocus(m_activeWnd, m_focusWnd);
  143. }
  144. SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (PVOID)timeoutMS, 0);
  145. return true;
  146. }
  147. void ExternalWindowTracker::SendPaste(bool activateTarget)
  148. {
  149. HWND activeWnd = m_activeWnd;
  150. CSendKeys send;
  151. send.AllKeysUp();
  152. if(activateTarget == false)
  153. {
  154. activeWnd = ::GetForegroundWindow();
  155. }
  156. CString csPasteToApp = GetProcessName(activeWnd);
  157. CString csPasteString = g_Opt.GetPasteString(csPasteToApp);
  158. DWORD delay = g_Opt.SendKeysDelay();
  159. if(activateTarget)
  160. {
  161. ActivateTarget();
  162. theApp.PumpMessageEx();
  163. WaitForActiveWnd(activeWnd, max(25, g_Opt.WaitForActiveWndTimeout()));
  164. }
  165. else
  166. {
  167. theApp.PumpMessageEx();
  168. }
  169. m_dittoHasFocus = false;
  170. Log(StrF(_T("Sending paste to app %s key stroke: %s, SeDelay: %d"), csPasteToApp, csPasteString, delay));
  171. Sleep(delay);
  172. send.SetKeyDownDelay(max(50, delay));
  173. send.SendKeys(csPasteString, true);
  174. Log(_T("Post sending paste"));
  175. }
  176. void ExternalWindowTracker::SendCopy()
  177. {
  178. CSendKeys send;
  179. send.AllKeysUp();
  180. CString csToApp = GetProcessName(m_activeWnd);
  181. CString csString = g_Opt.GetCopyString(csToApp);
  182. DWORD delay = g_Opt.SendKeysDelay();
  183. Sleep(delay);
  184. theApp.PumpMessageEx();
  185. Log(StrF(_T("Sending copy to app %s key stroke: %s, Delay: %d"), csToApp, csString, delay));
  186. //give the app some time to take focus before sending paste
  187. Sleep(delay);
  188. send.SetKeyDownDelay(max(50, delay));
  189. send.SendKeys(csString, true);
  190. Log(_T("Post sending copy"));
  191. }
  192. // sends Ctrl-X to the TargetWnd
  193. void ExternalWindowTracker::SendCut()
  194. {
  195. CSendKeys send;
  196. send.AllKeysUp();
  197. CString csToApp = GetProcessName(m_activeWnd);
  198. CString csString = g_Opt.GetCopyString(csToApp);
  199. DWORD delay = g_Opt.SendKeysDelay();
  200. Sleep(delay);
  201. theApp.PumpMessageEx();
  202. Log(StrF(_T("Sending cut to app %s key stroke: %s, Delay: %d"), csToApp, csString, delay));
  203. //give the app some time to take focus before sending paste
  204. Sleep(delay);
  205. send.SetKeyDownDelay(max(50, delay));
  206. send.SendKeys(csString, true);
  207. Log(_T("Post sending cut"));
  208. }
  209. CString ExternalWindowTracker::ActiveWndName()
  210. {
  211. return WndName(m_activeWnd);
  212. }
  213. CString ExternalWindowTracker::WndName(HWND hWnd)
  214. {
  215. TCHAR cWindowText[200];
  216. HWND hParent = hWnd;
  217. ::GetWindowText(hParent, cWindowText, 100);
  218. int nCount = 0;
  219. while(STRLEN(cWindowText) <= 0)
  220. {
  221. hParent = ::GetParent(hParent);
  222. if(hParent == NULL)
  223. break;
  224. ::GetWindowText(hParent, cWindowText, 100);
  225. nCount++;
  226. if(nCount > 100)
  227. {
  228. Log(_T("GetTargetName reached maximum search depth of 100"));
  229. break;
  230. }
  231. }
  232. return cWindowText;
  233. }
  234. bool ExternalWindowTracker::ReleaseFocus()
  235. {
  236. if( IsAppWnd(::GetForegroundWindow()) )
  237. {
  238. return ActivateTarget();
  239. }
  240. return false;
  241. }
  242. CPoint ExternalWindowTracker::FocusCaret()
  243. {
  244. CPoint pt(-1, -1);
  245. if(m_activeWnd)
  246. {
  247. GUITHREADINFO guiThreadInfo;
  248. guiThreadInfo.cbSize = sizeof(GUITHREADINFO);
  249. DWORD OtherThreadID = GetWindowThreadProcessId(m_activeWnd, NULL);
  250. if(GetGUIThreadInfo(OtherThreadID, &guiThreadInfo))
  251. {
  252. CRect rc(guiThreadInfo.rcCaret);
  253. if(rc.IsRectEmpty() == FALSE)
  254. {
  255. pt = rc.BottomRight();
  256. ::ClientToScreen(m_focusWnd, &pt);
  257. }
  258. }
  259. }
  260. return pt;
  261. }