| Index: chrome/browser/automation/ui_controls_win.cc
|
| diff --git a/chrome/browser/automation/ui_controls_win.cc b/chrome/browser/automation/ui_controls_win.cc
|
| index 9385df5eb3591a3befbada2c7e26845d61550c74..6db0e4a398ce851e049456d3dbb18d0419006237 100644
|
| --- a/chrome/browser/automation/ui_controls_win.cc
|
| +++ b/chrome/browser/automation/ui_controls_win.cc
|
| @@ -4,331 +4,12 @@
|
|
|
| #include "chrome/browser/automation/ui_controls.h"
|
|
|
| -#include "base/bind.h"
|
| -#include "base/callback.h"
|
| -#include "base/logging.h"
|
| -#include "base/memory/ref_counted.h"
|
| -#include "base/message_loop.h"
|
| -#include "base/task.h"
|
| -#include "ui/base/keycodes/keyboard_codes.h"
|
| -#include "ui/base/keycodes/keyboard_code_conversion_win.h"
|
| +#include "chrome/browser/automation/ui_controls_internal.h"
|
| +#include "ui/gfx/point.h"
|
| #include "views/view.h"
|
|
|
| namespace ui_controls {
|
|
|
| -namespace {
|
| -
|
| -// InputDispatcher ------------------------------------------------------------
|
| -
|
| -// InputDispatcher is used to listen for a mouse/keyboard event. When the
|
| -// appropriate event is received the task is notified.
|
| -class InputDispatcher : public base::RefCounted<InputDispatcher> {
|
| - public:
|
| - InputDispatcher(const base::Closure& task, WPARAM message_waiting_for);
|
| -
|
| - // Invoked from the hook. If mouse_message matches message_waiting_for_
|
| - // MatchingMessageFound is invoked.
|
| - void DispatchedMessage(WPARAM mouse_message);
|
| -
|
| - // Invoked when a matching event is found. Uninstalls the hook and schedules
|
| - // an event that notifies the task.
|
| - void MatchingMessageFound();
|
| -
|
| - private:
|
| - friend class base::RefCounted<InputDispatcher>;
|
| -
|
| - ~InputDispatcher();
|
| -
|
| - // Notifies the task and release this (which should delete it).
|
| - void NotifyTask();
|
| -
|
| - // The task we notify.
|
| - base::Closure task_;
|
| -
|
| - // Message we're waiting for. Not used for keyboard events.
|
| - const WPARAM message_waiting_for_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(InputDispatcher);
|
| -};
|
| -
|
| -// Have we installed the hook?
|
| -bool installed_hook_ = false;
|
| -
|
| -// Return value from SetWindowsHookEx.
|
| -HHOOK next_hook_ = NULL;
|
| -
|
| -// If a hook is installed, this is the dispatcher.
|
| -InputDispatcher* current_dispatcher_ = NULL;
|
| -
|
| -// Callback from hook when a mouse message is received.
|
| -LRESULT CALLBACK MouseHook(int n_code, WPARAM w_param, LPARAM l_param) {
|
| - HHOOK next_hook = next_hook_;
|
| - if (n_code == HC_ACTION) {
|
| - DCHECK(current_dispatcher_);
|
| - current_dispatcher_->DispatchedMessage(w_param);
|
| - }
|
| - return CallNextHookEx(next_hook, n_code, w_param, l_param);
|
| -}
|
| -
|
| -// Callback from hook when a key message is received.
|
| -LRESULT CALLBACK KeyHook(int n_code, WPARAM w_param, LPARAM l_param) {
|
| - HHOOK next_hook = next_hook_;
|
| - if (n_code == HC_ACTION) {
|
| - DCHECK(current_dispatcher_);
|
| - if (l_param & (1 << 30)) {
|
| - // Only send on key up.
|
| - current_dispatcher_->MatchingMessageFound();
|
| - }
|
| - }
|
| - return CallNextHookEx(next_hook, n_code, w_param, l_param);
|
| -}
|
| -
|
| -// Installs dispatcher as the current hook.
|
| -void InstallHook(InputDispatcher* dispatcher, bool key_hook) {
|
| - DCHECK(!installed_hook_);
|
| - current_dispatcher_ = dispatcher;
|
| - installed_hook_ = true;
|
| - if (key_hook) {
|
| - next_hook_ = SetWindowsHookEx(WH_KEYBOARD, &KeyHook, NULL,
|
| - GetCurrentThreadId());
|
| - } else {
|
| - // NOTE: I originally tried WH_CALLWNDPROCRET, but for some reason I
|
| - // didn't get a mouse message like I do with MouseHook.
|
| - next_hook_ = SetWindowsHookEx(WH_MOUSE, &MouseHook, NULL,
|
| - GetCurrentThreadId());
|
| - }
|
| - DCHECK(next_hook_);
|
| -}
|
| -
|
| -// Uninstalls the hook set in InstallHook.
|
| -void UninstallHook(InputDispatcher* dispatcher) {
|
| - if (current_dispatcher_ == dispatcher) {
|
| - installed_hook_ = false;
|
| - current_dispatcher_ = NULL;
|
| - UnhookWindowsHookEx(next_hook_);
|
| - }
|
| -}
|
| -
|
| -InputDispatcher::InputDispatcher(const base::Closure& task,
|
| - UINT message_waiting_for)
|
| - : task_(task), message_waiting_for_(message_waiting_for) {
|
| - InstallHook(this, message_waiting_for == WM_KEYUP);
|
| -}
|
| -
|
| -InputDispatcher::~InputDispatcher() {
|
| - // Make sure the hook isn't installed.
|
| - UninstallHook(this);
|
| -}
|
| -
|
| -void InputDispatcher::DispatchedMessage(WPARAM message) {
|
| - if (message == message_waiting_for_)
|
| - MatchingMessageFound();
|
| -}
|
| -
|
| -void InputDispatcher::MatchingMessageFound() {
|
| - UninstallHook(this);
|
| - // At the time we're invoked the event has not actually been processed.
|
| - // Use PostTask to make sure the event has been processed before notifying.
|
| - MessageLoop::current()->PostTask(
|
| - FROM_HERE, base::Bind(&InputDispatcher::NotifyTask, this));
|
| -}
|
| -
|
| -void InputDispatcher::NotifyTask() {
|
| - task_.Run();
|
| - Release();
|
| -}
|
| -
|
| -// Private functions ----------------------------------------------------------
|
| -
|
| -// Populate the INPUT structure with the appropriate keyboard event
|
| -// parameters required by SendInput
|
| -bool FillKeyboardInput(ui::KeyboardCode key, INPUT* input, bool key_up) {
|
| - memset(input, 0, sizeof(INPUT));
|
| - input->type = INPUT_KEYBOARD;
|
| - input->ki.wVk = ui::WindowsKeyCodeForKeyboardCode(key);
|
| - input->ki.dwFlags = key_up ? KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP :
|
| - KEYEVENTF_EXTENDEDKEY;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -// Send a key event (up/down)
|
| -bool SendKeyEvent(ui::KeyboardCode key, bool up) {
|
| - INPUT input = { 0 };
|
| -
|
| - if (!FillKeyboardInput(key, &input, up))
|
| - return false;
|
| -
|
| - if (!::SendInput(1, &input, sizeof(INPUT)))
|
| - return false;
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SendKeyPressImpl(ui::KeyboardCode key,
|
| - bool control, bool shift, bool alt,
|
| - const base::Closure& task) {
|
| - scoped_refptr<InputDispatcher> dispatcher(
|
| - !task.is_null() ? new InputDispatcher(task, WM_KEYUP) : NULL);
|
| -
|
| - // If a pop-up menu is open, it won't receive events sent using SendInput.
|
| - // Check for a pop-up menu using its window class (#32768) and if one
|
| - // exists, send the key event directly there.
|
| - HWND popup_menu = ::FindWindow(L"#32768", 0);
|
| - if (popup_menu != NULL && popup_menu == ::GetTopWindow(NULL)) {
|
| - WPARAM w_param = ui::WindowsKeyCodeForKeyboardCode(key);
|
| - LPARAM l_param = 0;
|
| - ::SendMessage(popup_menu, WM_KEYDOWN, w_param, l_param);
|
| - ::SendMessage(popup_menu, WM_KEYUP, w_param, l_param);
|
| -
|
| - if (dispatcher.get())
|
| - dispatcher->AddRef();
|
| - return true;
|
| - }
|
| -
|
| - INPUT input[8] = { 0 }; // 8, assuming all the modifiers are activated.
|
| -
|
| - UINT i = 0;
|
| - if (control) {
|
| - if (!FillKeyboardInput(ui::VKEY_CONTROL, &input[i], false))
|
| - return false;
|
| - i++;
|
| - }
|
| -
|
| - if (shift) {
|
| - if (!FillKeyboardInput(ui::VKEY_SHIFT, &input[i], false))
|
| - return false;
|
| - i++;
|
| - }
|
| -
|
| - if (alt) {
|
| - if (!FillKeyboardInput(ui::VKEY_MENU, &input[i], false))
|
| - return false;
|
| - i++;
|
| - }
|
| -
|
| - if (!FillKeyboardInput(key, &input[i], false))
|
| - return false;
|
| - i++;
|
| -
|
| - if (!FillKeyboardInput(key, &input[i], true))
|
| - return false;
|
| - i++;
|
| -
|
| - if (alt) {
|
| - if (!FillKeyboardInput(ui::VKEY_MENU, &input[i], true))
|
| - return false;
|
| - i++;
|
| - }
|
| -
|
| - if (shift) {
|
| - if (!FillKeyboardInput(ui::VKEY_SHIFT, &input[i], true))
|
| - return false;
|
| - i++;
|
| - }
|
| -
|
| - if (control) {
|
| - if (!FillKeyboardInput(ui::VKEY_CONTROL, &input[i], true))
|
| - return false;
|
| - i++;
|
| - }
|
| -
|
| - if (::SendInput(i, input, sizeof(INPUT)) != i)
|
| - return false;
|
| -
|
| - if (dispatcher.get())
|
| - dispatcher->AddRef();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SendMouseMoveImpl(long x, long y, const base::Closure& task) {
|
| - // First check if the mouse is already there.
|
| - POINT current_pos;
|
| - ::GetCursorPos(¤t_pos);
|
| - if (x == current_pos.x && y == current_pos.y) {
|
| - if (!task.is_null())
|
| - MessageLoop::current()->PostTask(FROM_HERE, task);
|
| - return true;
|
| - }
|
| -
|
| - INPUT input = { 0 };
|
| -
|
| - int screen_width = ::GetSystemMetrics(SM_CXSCREEN) - 1;
|
| - int screen_height = ::GetSystemMetrics(SM_CYSCREEN) - 1;
|
| - LONG pixel_x = static_cast<LONG>(x * (65535.0f / screen_width));
|
| - LONG pixel_y = static_cast<LONG>(y * (65535.0f / screen_height));
|
| -
|
| - input.type = INPUT_MOUSE;
|
| - input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
|
| - input.mi.dx = pixel_x;
|
| - input.mi.dy = pixel_y;
|
| -
|
| - scoped_refptr<InputDispatcher> dispatcher(
|
| - !task.is_null() ? new InputDispatcher(task, WM_MOUSEMOVE) : NULL);
|
| -
|
| - if (!::SendInput(1, &input, sizeof(INPUT)))
|
| - return false;
|
| -
|
| - if (dispatcher.get())
|
| - dispatcher->AddRef();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -bool SendMouseEventsImpl(MouseButton type, int state,
|
| - const base::Closure& task) {
|
| - DWORD down_flags = MOUSEEVENTF_ABSOLUTE;
|
| - DWORD up_flags = MOUSEEVENTF_ABSOLUTE;
|
| - UINT last_event;
|
| -
|
| - switch (type) {
|
| - case LEFT:
|
| - down_flags |= MOUSEEVENTF_LEFTDOWN;
|
| - up_flags |= MOUSEEVENTF_LEFTUP;
|
| - last_event = (state & UP) ? WM_LBUTTONUP : WM_LBUTTONDOWN;
|
| - break;
|
| -
|
| - case MIDDLE:
|
| - down_flags |= MOUSEEVENTF_MIDDLEDOWN;
|
| - up_flags |= MOUSEEVENTF_MIDDLEUP;
|
| - last_event = (state & UP) ? WM_MBUTTONUP : WM_MBUTTONDOWN;
|
| - break;
|
| -
|
| - case RIGHT:
|
| - down_flags |= MOUSEEVENTF_RIGHTDOWN;
|
| - up_flags |= MOUSEEVENTF_RIGHTUP;
|
| - last_event = (state & UP) ? WM_RBUTTONUP : WM_RBUTTONDOWN;
|
| - break;
|
| -
|
| - default:
|
| - NOTREACHED();
|
| - return false;
|
| - }
|
| -
|
| - scoped_refptr<InputDispatcher> dispatcher(
|
| - !task.is_null() ? new InputDispatcher(task, last_event) : NULL);
|
| -
|
| - INPUT input = { 0 };
|
| - input.type = INPUT_MOUSE;
|
| - input.mi.dwFlags = down_flags;
|
| - if ((state & DOWN) && !::SendInput(1, &input, sizeof(INPUT)))
|
| - return false;
|
| -
|
| - input.mi.dwFlags = up_flags;
|
| - if ((state & UP) && !::SendInput(1, &input, sizeof(INPUT)))
|
| - return false;
|
| -
|
| - if (dispatcher.get())
|
| - dispatcher->AddRef();
|
| -
|
| - return true;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -// public functions -----------------------------------------------------------
|
| -
|
| bool SendKeyPress(gfx::NativeWindow window,
|
| ui::KeyboardCode key,
|
| bool control,
|
| @@ -336,7 +17,7 @@ bool SendKeyPress(gfx::NativeWindow window,
|
| bool alt,
|
| bool command) {
|
| DCHECK(!command); // No command key on Windows
|
| - return SendKeyPressImpl(key, control, shift, alt, base::Closure());
|
| + return internal::SendKeyPressImpl(key, control, shift, alt, base::Closure());
|
| }
|
|
|
| bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
|
| @@ -347,28 +28,28 @@ bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
|
| bool command,
|
| const base::Closure& task) {
|
| DCHECK(!command); // No command key on Windows
|
| - return SendKeyPressImpl(key, control, shift, alt, task);
|
| + return internal::SendKeyPressImpl(key, control, shift, alt, task);
|
| }
|
|
|
| bool SendMouseMove(long x, long y) {
|
| - return SendMouseMoveImpl(x, y, base::Closure());
|
| + return internal::SendMouseMoveImpl(x, y, base::Closure());
|
| }
|
|
|
| bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
|
| - return SendMouseMoveImpl(x, y, task);
|
| + return internal::SendMouseMoveImpl(x, y, task);
|
| }
|
|
|
| bool SendMouseEvents(MouseButton type, int state) {
|
| - return SendMouseEventsImpl(type, state, base::Closure());
|
| + return internal::SendMouseEventsImpl(type, state, base::Closure());
|
| }
|
|
|
| bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
|
| const base::Closure& task) {
|
| - return SendMouseEventsImpl(type, state, task);
|
| + return internal::SendMouseEventsImpl(type, state, task);
|
| }
|
|
|
| bool SendMouseClick(MouseButton type) {
|
| - return SendMouseEventsImpl(type, UP | DOWN, base::Closure());
|
| + return internal::SendMouseEventsImpl(type, UP | DOWN, base::Closure());
|
| }
|
|
|
| void MoveMouseToCenterAndPress(views::View* view,
|
|
|