Loosen up heuristics for detecting account creation forms.
[chromium-blink-merge.git] / chrome_frame / test / simulate_input.cc
blob2ee8cd7bb4135a6694f69b032e6c09f9ff548d02
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome_frame/test/simulate_input.h"
7 #include <atlbase.h>
8 #include <atlwin.h>
10 #include "chrome_frame/utils.h"
12 namespace simulate_input {
14 class ForegroundHelperWindow : public CWindowImpl<ForegroundHelperWindow> {
15 public:
16 BEGIN_MSG_MAP(ForegroundHelperWindow)
17 MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
18 END_MSG_MAP()
20 ForegroundHelperWindow() : window_(NULL) {}
22 HRESULT SetForeground(HWND window) {
23 DCHECK(::IsWindow(window));
24 window_ = window;
25 if (NULL == Create(NULL, NULL, NULL, WS_POPUP))
26 return AtlHresultFromLastError();
28 static const int kHotKeyId = 0x0000baba;
29 static const int kHotKeyWaitTimeout = 2000;
31 RegisterHotKey(m_hWnd, kHotKeyId, 0, VK_F22);
33 MSG msg = {0};
34 PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
36 SendMnemonic(VK_F22, NONE, false, false);
37 // There are scenarios where the WM_HOTKEY is not dispatched by the
38 // the corresponding foreground thread. To prevent us from indefinitely
39 // waiting for the hotkey, we set a timer and exit the loop.
40 SetTimer(kHotKeyId, kHotKeyWaitTimeout, NULL);
42 while (GetMessage(&msg, NULL, 0, 0)) {
43 TranslateMessage(&msg);
44 DispatchMessage(&msg);
45 if (msg.message == WM_HOTKEY) {
46 break;
48 if (msg.message == WM_TIMER) {
49 SetForegroundWindow(window);
50 break;
54 UnregisterHotKey(m_hWnd, kHotKeyId);
55 KillTimer(kHotKeyId);
56 DestroyWindow();
57 return S_OK;
60 LRESULT OnHotKey(UINT msg, WPARAM wp, LPARAM lp, BOOL& handled) { // NOLINT
61 SetForegroundWindow(window_);
62 return 1;
64 private:
65 HWND window_;
68 bool ForceSetForegroundWindow(HWND window) {
69 if (GetForegroundWindow() == window)
70 return true;
71 ForegroundHelperWindow foreground_helper_window;
72 HRESULT hr = foreground_helper_window.SetForeground(window);
73 return SUCCEEDED(hr);
76 struct PidAndWindow {
77 base::ProcessId pid;
78 HWND hwnd;
81 BOOL CALLBACK FindWindowInProcessCallback(HWND hwnd, LPARAM param) {
82 PidAndWindow* paw = reinterpret_cast<PidAndWindow*>(param);
83 base::ProcessId pid;
84 GetWindowThreadProcessId(hwnd, &pid);
85 if (pid == paw->pid && IsWindowVisible(hwnd)) {
86 paw->hwnd = hwnd;
87 return FALSE;
90 return TRUE;
93 bool EnsureProcessInForeground(base::ProcessId process_id) {
94 HWND hwnd = GetForegroundWindow();
95 base::ProcessId current_foreground_pid = 0;
96 DWORD active_thread_id = GetWindowThreadProcessId(hwnd,
97 &current_foreground_pid);
98 if (current_foreground_pid == process_id)
99 return true;
101 PidAndWindow paw = { process_id };
102 EnumWindows(FindWindowInProcessCallback, reinterpret_cast<LPARAM>(&paw));
103 if (!IsWindow(paw.hwnd)) {
104 LOG(ERROR) << "failed to find process window";
105 return false;
108 bool ret = ForceSetForegroundWindow(paw.hwnd);
109 LOG_IF(ERROR, !ret) << "ForceSetForegroundWindow: " << ret;
111 return ret;
114 void SendScanCode(short scan_code, Modifier modifiers) {
115 DCHECK(-1 != scan_code);
117 // High order byte in |scan_code| is SHIFT/CTRL/ALT key state.
118 modifiers = static_cast<Modifier>(modifiers | HIBYTE(scan_code));
119 DCHECK(modifiers <= ALT);
121 // Low order byte in |scan_code| is the actual scan code.
122 SendMnemonic(LOBYTE(scan_code), modifiers, false, true);
125 void SendCharA(char c, Modifier modifiers) {
126 SendScanCode(VkKeyScanA(c), modifiers);
129 void SendCharW(wchar_t c, Modifier modifiers) {
130 SendScanCode(VkKeyScanW(c), modifiers);
133 // Sends a keystroke to the currently active application with optional
134 // modifiers set.
135 void SendMnemonic(WORD mnemonic_char, Modifier modifiers, bool extended,
136 bool unicode) {
137 INPUT keys[4] = {0}; // Keyboard events
138 int key_count = 0; // Number of generated events
140 if (modifiers & SHIFT) {
141 keys[key_count].type = INPUT_KEYBOARD;
142 keys[key_count].ki.wVk = VK_SHIFT;
143 keys[key_count].ki.wScan = MapVirtualKey(VK_SHIFT, 0);
144 key_count++;
147 if (modifiers & CONTROL) {
148 keys[key_count].type = INPUT_KEYBOARD;
149 keys[key_count].ki.wVk = VK_CONTROL;
150 keys[key_count].ki.wScan = MapVirtualKey(VK_CONTROL, 0);
151 key_count++;
154 if (modifiers & ALT) {
155 keys[key_count].type = INPUT_KEYBOARD;
156 keys[key_count].ki.wVk = VK_MENU;
157 keys[key_count].ki.wScan = MapVirtualKey(VK_MENU, 0);
158 key_count++;
161 keys[key_count].type = INPUT_KEYBOARD;
162 keys[key_count].ki.wVk = mnemonic_char;
163 keys[key_count].ki.wScan = MapVirtualKey(mnemonic_char, 0);
165 if (extended)
166 keys[key_count].ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
167 if (unicode)
168 keys[key_count].ki.dwFlags |= KEYEVENTF_UNICODE;
169 key_count++;
171 bool should_sleep = key_count > 1;
173 // Send key downs
174 for (int i = 0; i < key_count; i++) {
175 SendInput(1, &keys[ i ], sizeof(keys[0]));
176 keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
177 if (should_sleep) {
178 Sleep(10);
182 // Now send key ups in reverse order
183 for (int i = key_count; i; i--) {
184 SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
185 if (should_sleep) {
186 Sleep(10);
191 void SetKeyboardFocusToWindow(HWND window) {
192 SendMouseClick(window, 1, 1, LEFT);
195 void SendMouseClick(int x, int y, MouseButton button) {
196 // TODO(joshia): Fix this. GetSystemMetrics(SM_CXSCREEN) will
197 // retrieve screen size of the primarary monitor only. And monitors
198 // arrangement could be pretty arbitrary.
199 double screen_width = ::GetSystemMetrics(SM_CXSCREEN) - 1;
200 double screen_height = ::GetSystemMetrics(SM_CYSCREEN) - 1;
201 double location_x = x * (65535.0f / screen_width);
202 double location_y = y * (65535.0f / screen_height);
204 // Take advantage of button flag bitmask layout
205 unsigned int button_flag = MOUSEEVENTF_LEFTDOWN << (button + button);
207 INPUT input_info = {0};
208 input_info.type = INPUT_MOUSE;
209 input_info.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
210 input_info.mi.dx = static_cast<LONG>(location_x);
211 input_info.mi.dy = static_cast<LONG>(location_y);
212 ::SendInput(1, &input_info, sizeof(INPUT));
214 Sleep(10);
216 input_info.mi.dwFlags = button_flag | MOUSEEVENTF_ABSOLUTE;
217 ::SendInput(1, &input_info, sizeof(INPUT));
219 Sleep(10);
221 input_info.mi.dwFlags = (button_flag << 1) | MOUSEEVENTF_ABSOLUTE;
222 ::SendInput(1, &input_info, sizeof(INPUT));
225 void SendMouseClick(HWND window, int x, int y, MouseButton button) {
226 if (!IsWindow(window)) {
227 NOTREACHED() << "Invalid window handle.";
228 return;
231 HWND top_level_window = window;
232 if (!IsTopLevelWindow(top_level_window)) {
233 top_level_window = GetAncestor(window, GA_ROOT);
236 ForceSetForegroundWindow(top_level_window);
238 POINT cursor_position = {x, y};
239 ClientToScreen(window, &cursor_position);
240 SendMouseClick(cursor_position.x, cursor_position.y, button);
243 void SendExtendedKey(WORD key, Modifier modifiers) {
244 SendMnemonic(key, modifiers, true, false);
247 void SendStringW(const std::wstring& s) {
248 for (size_t i = 0; i < s.length(); i++) {
249 SendCharW(s[i], NONE);
250 Sleep(10);
254 void SendStringA(const std::string& s) {
255 for (size_t i = 0; i < s.length(); i++) {
256 SendCharA(s[i], NONE);
257 Sleep(10);
261 } // namespace simulate_input