ExternalWindowTracker.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. AttachThreadInput(GetWindowThreadProcessId(newActive, NULL), GetCurrentThreadId(), TRUE);
  24. newFocus = GetFocus();
  25. AttachThreadInput(GetWindowThreadProcessId(newActive, NULL), GetCurrentThreadId(), FALSE);
  26. fromHook = false;
  27. }
  28. if(newFocus == 0 && newActive != 0)
  29. {
  30. newFocus = newActive;
  31. }
  32. else if(newActive == 0 && newFocus != 0)
  33. {
  34. newActive = newFocus;
  35. }
  36. if(newFocus == 0 || !IsWindow(newFocus) || newActive == 0 || !IsWindow(newActive))
  37. {
  38. Log(_T("TargetActiveWindow values invalid"));
  39. return false;
  40. }
  41. if(newFocus == m_focusWnd)
  42. {
  43. // Log(_T("TargetActiveWindow window the same"));
  44. return false;
  45. }
  46. TCHAR className[50];
  47. GetClassName(newFocus, className, (sizeof(className) / sizeof(TCHAR)));
  48. if(STRCMP(className, _T("Shell_TrayWnd")) == 0)
  49. {
  50. Log(_T("TargetActiveWindow shell tray icon has focus"));
  51. return false;
  52. }
  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. m_dittoHasFocus = true;
  62. 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));
  63. return false;
  64. }
  65. m_focusWnd = newFocus;
  66. m_activeWnd = newActive;
  67. m_dittoHasFocus = false;
  68. if(theApp.QPasteWnd())
  69. theApp.QPasteWnd()->UpdateStatus(true);
  70. Log(StrF(_T("TargetActiveWindow Active: %s (%d), Focus: %s (%d), FromHook %d"), WndName(m_activeWnd), m_activeWnd, WndName(m_focusWnd), m_focusWnd, fromHook));
  71. return true;
  72. }
  73. bool ExternalWindowTracker::WaitForActiveWnd(HWND activeWnd, int timeout)
  74. {
  75. DWORD start = GetTickCount();
  76. while(((int)(GetTickCount() - start)) < timeout)
  77. {
  78. if(::GetForegroundWindow() == activeWnd)
  79. {
  80. Log(StrF(_T("found focus wait %d"), GetTickCount()-start));
  81. return true;
  82. }
  83. Sleep(0);
  84. ActivateTarget();
  85. }
  86. Log(_T("Didn't find focus"));
  87. return false;
  88. }
  89. bool ExternalWindowTracker::ActivateTarget()
  90. {
  91. Log(StrF(_T("Activate Target - Active: %d Focus: %d"), m_activeWnd, m_focusWnd));
  92. SetForegroundWindow(m_activeWnd);
  93. AttachThreadInput(GetWindowThreadProcessId(m_activeWnd, NULL), GetCurrentThreadId(), TRUE);
  94. SetFocus(m_focusWnd);
  95. AttachThreadInput(GetWindowThreadProcessId(m_activeWnd, NULL), GetCurrentThreadId(), FALSE);
  96. return true;
  97. }
  98. void ExternalWindowTracker::SendPaste(bool activateTarget)
  99. {
  100. CSendKeys send;
  101. send.AllKeysUp();
  102. CString csPasteToApp = GetProcessName(m_activeWnd);
  103. CString csPasteString = g_Opt.GetPasteString(csPasteToApp);
  104. DWORD delay = g_Opt.SendKeysDelay();
  105. if(activateTarget)
  106. {
  107. ActivateTarget();
  108. theApp.PumpMessageEx();
  109. WaitForActiveWnd(m_activeWnd, max(25, g_Opt.WaitForActiveWndTimeout()));
  110. }
  111. else
  112. {
  113. theApp.PumpMessageEx();
  114. }
  115. m_dittoHasFocus = false;
  116. Log(StrF(_T("Sending paste to app %s key stroke: %s, SeDelay: %d"), csPasteToApp, csPasteString, delay));
  117. send.SetKeyDownDelay(max(50, delay));
  118. send.SendKeys(csPasteString, true);
  119. Log(_T("Post sending paste"));
  120. }
  121. void ExternalWindowTracker::SendCopy()
  122. {
  123. CSendKeys send;
  124. send.AllKeysUp();
  125. CString csToApp = GetProcessName(m_activeWnd);
  126. CString csString = g_Opt.GetCopyString(csToApp);
  127. DWORD delay = g_Opt.SendKeysDelay();
  128. Sleep(delay);
  129. theApp.PumpMessageEx();
  130. Log(StrF(_T("Sending copy to app %s key stroke: %s, Delay: %d"), csToApp, csString, delay));
  131. //give the app some time to take focus before sending paste
  132. Sleep(delay);
  133. send.SetKeyDownDelay(max(50, delay));
  134. send.SendKeys(csString, true);
  135. Log(_T("Post sending copy"));
  136. }
  137. // sends Ctrl-X to the TargetWnd
  138. void ExternalWindowTracker::SendCut()
  139. {
  140. CSendKeys send;
  141. send.AllKeysUp();
  142. CString csToApp = GetProcessName(m_activeWnd);
  143. CString csString = g_Opt.GetCopyString(csToApp);
  144. DWORD delay = g_Opt.SendKeysDelay();
  145. Sleep(delay);
  146. theApp.PumpMessageEx();
  147. Log(StrF(_T("Sending cut to app %s key stroke: %s, Delay: %d"), csToApp, csString, delay));
  148. //give the app some time to take focus before sending paste
  149. Sleep(delay);
  150. send.SetKeyDownDelay(max(50, delay));
  151. send.SendKeys(csString, true);
  152. Log(_T("Post sending cut"));
  153. }
  154. CString ExternalWindowTracker::ActiveWndName()
  155. {
  156. return WndName(m_activeWnd);
  157. }
  158. CString ExternalWindowTracker::WndName(HWND hWnd)
  159. {
  160. TCHAR cWindowText[200];
  161. HWND hParent = hWnd;
  162. ::GetWindowText(hParent, cWindowText, 100);
  163. int nCount = 0;
  164. while(STRLEN(cWindowText) <= 0)
  165. {
  166. hParent = ::GetParent(hParent);
  167. if(hParent == NULL)
  168. break;
  169. ::GetWindowText(hParent, cWindowText, 100);
  170. nCount++;
  171. if(nCount > 100)
  172. {
  173. Log(_T("GetTargetName reached maximum search depth of 100"));
  174. break;
  175. }
  176. }
  177. return cWindowText;
  178. }
  179. bool ExternalWindowTracker::ReleaseFocus()
  180. {
  181. if( IsAppWnd(::GetForegroundWindow()) )
  182. {
  183. return ActivateTarget();
  184. }
  185. return false;
  186. }
  187. CPoint ExternalWindowTracker::FocusCaret()
  188. {
  189. CPoint pt(-1, -1);
  190. if(m_activeWnd)
  191. {
  192. GUITHREADINFO guiThreadInfo;
  193. guiThreadInfo.cbSize = sizeof(GUITHREADINFO);
  194. DWORD OtherThreadID = GetWindowThreadProcessId(m_activeWnd, NULL);
  195. if(GetGUIThreadInfo(OtherThreadID, &guiThreadInfo))
  196. {
  197. CRect rc(guiThreadInfo.rcCaret);
  198. if(rc.IsRectEmpty() == FALSE)
  199. {
  200. pt = rc.BottomRight();
  201. ::ClientToScreen(m_focusWnd, &pt);
  202. }
  203. }
  204. }
  205. return pt;
  206. }