| Index: chrome_frame/test/simulate_input.cc
|
| ===================================================================
|
| --- chrome_frame/test/simulate_input.cc (revision 0)
|
| +++ chrome_frame/test/simulate_input.cc (revision 0)
|
| @@ -0,0 +1,223 @@
|
| +// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome_frame/test/simulate_input.h"
|
| +
|
| +#include <atlbase.h>
|
| +#include <atlwin.h>
|
| +
|
| +#include "chrome_frame/utils.h"
|
| +
|
| +namespace simulate_input {
|
| +
|
| +class ForegroundHelperWindow : public CWindowImpl<ForegroundHelperWindow> {
|
| + public:
|
| +BEGIN_MSG_MAP(ForegroundHelperWindow)
|
| + MESSAGE_HANDLER(WM_HOTKEY, OnHotKey)
|
| +END_MSG_MAP()
|
| +
|
| + ForegroundHelperWindow() : window_(NULL) {}
|
| +
|
| + HRESULT SetForeground(HWND window) {
|
| + DCHECK(::IsWindow(window));
|
| + window_ = window;
|
| + if (NULL == Create(NULL, NULL, NULL, WS_POPUP))
|
| + return AtlHresultFromLastError();
|
| +
|
| + static const int kHotKeyId = 0x0000baba;
|
| + static const int kHotKeyWaitTimeout = 2000;
|
| +
|
| + RegisterHotKey(m_hWnd, kHotKeyId, 0, VK_F22);
|
| +
|
| + MSG msg = {0};
|
| + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
|
| +
|
| + SendMnemonic(VK_F22, false, false, false, false, false);
|
| + // There are scenarios where the WM_HOTKEY is not dispatched by the
|
| + // the corresponding foreground thread. To prevent us from indefinitely
|
| + // waiting for the hotkey, we set a timer and exit the loop.
|
| + SetTimer(kHotKeyId, kHotKeyWaitTimeout, NULL);
|
| +
|
| + while (GetMessage(&msg, NULL, 0, 0)) {
|
| + TranslateMessage(&msg);
|
| + DispatchMessage(&msg);
|
| + if (msg.message == WM_HOTKEY) {
|
| + break;
|
| + }
|
| + if (msg.message == WM_TIMER) {
|
| + SetForegroundWindow(window);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + UnregisterHotKey(m_hWnd, kHotKeyId);
|
| + KillTimer(kHotKeyId);
|
| + DestroyWindow();
|
| + return S_OK;
|
| + }
|
| +
|
| + LRESULT OnHotKey(UINT msg, WPARAM wp, LPARAM lp, BOOL& handled) { // NOLINT
|
| + SetForegroundWindow(window_);
|
| + return 1;
|
| + }
|
| + private:
|
| + HWND window_;
|
| +};
|
| +
|
| +bool ForceSetForegroundWindow(HWND window) {
|
| + if (GetForegroundWindow() == window)
|
| + return true;
|
| + ForegroundHelperWindow foreground_helper_window;
|
| + HRESULT hr = foreground_helper_window.SetForeground(window);
|
| + return SUCCEEDED(hr);
|
| +}
|
| +
|
| +struct PidAndWindow {
|
| + base::ProcessId pid;
|
| + HWND hwnd;
|
| +};
|
| +
|
| +BOOL CALLBACK FindWindowInProcessCallback(HWND hwnd, LPARAM param) {
|
| + PidAndWindow* paw = reinterpret_cast<PidAndWindow*>(param);
|
| + base::ProcessId pid;
|
| + GetWindowThreadProcessId(hwnd, &pid);
|
| + if (pid == paw->pid && IsWindowVisible(hwnd)) {
|
| + paw->hwnd = hwnd;
|
| + return FALSE;
|
| + }
|
| +
|
| + return TRUE;
|
| +}
|
| +
|
| +bool EnsureProcessInForeground(base::ProcessId process_id) {
|
| + HWND hwnd = GetForegroundWindow();
|
| + base::ProcessId current_foreground_pid = 0;
|
| + DWORD active_thread_id = GetWindowThreadProcessId(hwnd,
|
| + ¤t_foreground_pid);
|
| + if (current_foreground_pid == process_id)
|
| + return true;
|
| +
|
| + PidAndWindow paw = { process_id };
|
| + EnumWindows(FindWindowInProcessCallback, reinterpret_cast<LPARAM>(&paw));
|
| + if (!IsWindow(paw.hwnd)) {
|
| + DLOG(ERROR) << "failed to find process window";
|
| + return false;
|
| + }
|
| +
|
| + bool ret = ForceSetForegroundWindow(paw.hwnd);
|
| + LOG_IF(ERROR, !ret) << "ForceSetForegroundWindow: " << ret;
|
| +
|
| + return ret;
|
| +}
|
| +
|
| +void SendChar(char c, bool control, bool alt) {
|
| + SendMnemonic(toupper(c), !!isupper(c), control, alt, false, false);
|
| +}
|
| +
|
| +void SendChar(wchar_t c, bool control, bool alt) {
|
| + SendMnemonic(towupper(c), !!iswupper(c), control, alt, false, true);
|
| +}
|
| +
|
| +// Sends a keystroke to the currently active application with optional
|
| +// modifiers set.
|
| +bool SendMnemonic(WORD mnemonic_char, bool shift_pressed, bool control_pressed,
|
| + bool alt_pressed, bool extended, bool unicode) {
|
| + INPUT keys[4] = {0}; // Keyboard events
|
| + int key_count = 0; // Number of generated events
|
| +
|
| + if (shift_pressed) {
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = VK_SHIFT;
|
| + key_count++;
|
| + }
|
| +
|
| + if (control_pressed) {
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = VK_CONTROL;
|
| + key_count++;
|
| + }
|
| +
|
| + if (alt_pressed) {
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = VK_MENU;
|
| + key_count++;
|
| + }
|
| +
|
| + keys[key_count].type = INPUT_KEYBOARD;
|
| + keys[key_count].ki.wVk = mnemonic_char;
|
| + if (extended)
|
| + keys[key_count].ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
|
| + if (unicode)
|
| + keys[key_count].ki.dwFlags |= KEYEVENTF_UNICODE;
|
| + key_count++;
|
| +
|
| + // Send key downs
|
| + for (int i = 0; i < key_count; i++) {
|
| + SendInput(1, &keys[ i ], sizeof(keys[0]));
|
| + keys[i].ki.dwFlags |= KEYEVENTF_KEYUP;
|
| + }
|
| +
|
| + // Now send key ups in reverse order
|
| + for (int i = key_count; i; i--) {
|
| + SendInput(1, &keys[ i - 1 ], sizeof(keys[0]));
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void SetKeyboardFocusToWindow(HWND window) {
|
| + SendMouseClick(window, 1, 1, LEFT);
|
| +}
|
| +
|
| +void SendMouseClick(HWND window, int x, int y, MouseButton button) {
|
| + if (!IsWindow(window)) {
|
| + NOTREACHED() << "Invalid window handle.";
|
| + return;
|
| + }
|
| +
|
| + HWND top_level_window = window;
|
| + if (!IsTopLevelWindow(top_level_window)) {
|
| + top_level_window = GetAncestor(window, GA_ROOT);
|
| + }
|
| +
|
| + ForceSetForegroundWindow(top_level_window);
|
| +
|
| + POINT cursor_position = {x, y};
|
| + ClientToScreen(window, &cursor_position);
|
| +
|
| + // TODO(joshia): Fix this. GetSystemMetrics(SM_CXSCREEN) will
|
| + // retrieve screen size of the primarary monitor only. And monitors
|
| + // arrangement could be pretty arbitrary.
|
| + double screen_width = ::GetSystemMetrics(SM_CXSCREEN) - 1;
|
| + double screen_height = ::GetSystemMetrics(SM_CYSCREEN) - 1;
|
| + double location_x = cursor_position.x * (65535.0f / screen_width);
|
| + double location_y = cursor_position.y * (65535.0f / screen_height);
|
| +
|
| + // Take advantage of button flag bitmask layout
|
| + unsigned int button_flag = MOUSEEVENTF_LEFTDOWN << (button + button);
|
| +
|
| + INPUT input_info = {0};
|
| + input_info.type = INPUT_MOUSE;
|
| + input_info.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
|
| + input_info.mi.dx = static_cast<long>(location_x);
|
| + input_info.mi.dy = static_cast<long>(location_y);
|
| + ::SendInput(1, &input_info, sizeof(INPUT));
|
| +
|
| + Sleep(10);
|
| +
|
| + input_info.mi.dwFlags = button_flag | MOUSEEVENTF_ABSOLUTE;
|
| + ::SendInput(1, &input_info, sizeof(INPUT));
|
| +
|
| + Sleep(10);
|
| +
|
| + input_info.mi.dwFlags = (button_flag << 1) | MOUSEEVENTF_ABSOLUTE;
|
| + ::SendInput(1, &input_info, sizeof(INPUT));
|
| +}
|
| +
|
| +bool SendExtendedKey(WORD key, bool shift, bool control, bool alt) {
|
| + return SendMnemonic(key, shift, control, alt, true, false);
|
| +}
|
| +
|
| +} // namespace simulate_input
|
| +
|
|
|
| Property changes on: chrome_frame\test\simulate_input.cc
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|