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, |