Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 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. | |
| 4 | |
| 5 #include "chrome/browser/automation/ui_controls.h" | |
| 6 | |
| 7 #include <X11/keysym.h> | |
| 8 #include <X11/Xlib.h> | |
| 9 | |
| 10 #include "base/callback.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/message_pump_x.h" | |
| 13 #include "chrome/browser/automation/ui_controls_internal.h" | |
| 14 #include "ui/aura/desktop.h" | |
| 15 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | |
| 16 #include "views/view.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Event waiter executes the given |closure| when an event that | |
| 21 // matches condition implemented by |matcher|. | |
|
sky
2011/11/22 00:28:33
Event waiter executes the specified closure when a
oshima
2011/11/22 01:36:10
Done.
| |
| 22 // TODO(oshima): Move this to base. | |
| 23 class EventWaiter : public MessageLoopForUI::Observer { | |
| 24 public: | |
| 25 typedef bool (*EventWaiterMatcher)(const base::NativeEvent& event); | |
| 26 | |
| 27 EventWaiter(const base::Closure& closure, EventWaiterMatcher matcher) | |
| 28 : closure_(closure), | |
| 29 matcher_(matcher) { | |
| 30 MessageLoopForUI::current()->AddObserver(this); | |
| 31 } | |
| 32 | |
| 33 virtual ~EventWaiter() { | |
| 34 MessageLoopForUI::current()->RemoveObserver(this); | |
| 35 } | |
| 36 | |
| 37 // MessageLoop::Observer implementation: | |
| 38 virtual base::EventStatus WillProcessEvent(const base::NativeEvent& event) { | |
|
sky
2011/11/22 00:28:33
OVERRIDE here and on DidProcessEvent.
oshima
2011/11/22 01:36:10
Done.
| |
| 39 if ((*matcher_)(event)) { | |
| 40 MessageLoop::current()->PostTask(FROM_HERE, closure_); | |
| 41 delete this; | |
| 42 } | |
| 43 return base::EVENT_CONTINUE; | |
| 44 } | |
| 45 | |
| 46 virtual void DidProcessEvent(const base::NativeEvent& event) { | |
| 47 | |
|
sky
2011/11/22 00:28:33
nit: remove empty line.
oshima
2011/11/22 01:36:10
Done.
| |
| 48 } | |
| 49 private: | |
|
sky
2011/11/22 00:28:33
nit: newline between 48 and 49.
oshima
2011/11/22 01:36:10
Done.
| |
| 50 base::Closure closure_; | |
| 51 EventWaiterMatcher matcher_; | |
| 52 DISALLOW_COPY_AND_ASSIGN(EventWaiter); | |
| 53 }; | |
| 54 | |
| 55 // Latest mouse pointer location set by SendMouseMoveNotifyWhenDone. | |
| 56 int g_current_x = -1000; | |
| 57 int g_current_y = -1000; | |
| 58 | |
| 59 // Returns atom that indidates that the XEvent is marker event. | |
| 60 Atom MarkerEventAtom() { | |
| 61 return XInternAtom(base::MessagePumpX::GetDefaultXDisplay(), | |
| 62 "marker_event", | |
| 63 False); | |
| 64 } | |
| 65 | |
| 66 // Returns true when the event is a marker event. | |
| 67 bool Matcher(const base::NativeEvent& event) { | |
| 68 return event->xany.type == ClientMessage && | |
| 69 event->xclient.message_type == MarkerEventAtom(); | |
| 70 } | |
| 71 | |
| 72 void RunClosureAfterEvents(const base::Closure closure) { | |
| 73 if (closure.is_null()) | |
| 74 return; | |
| 75 static XEvent* marker_event = NULL; | |
| 76 if (!marker_event) { | |
| 77 marker_event = new XEvent(); | |
| 78 marker_event->xclient.type = ClientMessage; | |
| 79 marker_event->xclient.display = NULL; | |
| 80 marker_event->xclient.window = None; | |
| 81 marker_event->xclient.format = 8; | |
| 82 } | |
| 83 marker_event->xclient.message_type = MarkerEventAtom(); | |
| 84 aura::Desktop::GetInstance()->PostNativeEvent(marker_event); | |
| 85 new EventWaiter(closure, &Matcher); | |
| 86 } | |
| 87 | |
| 88 } // namespace | |
| 89 | |
| 90 namespace ui_controls { | |
| 91 | |
| 92 bool SendKeyPress(gfx::NativeWindow window, | |
| 93 ui::KeyboardCode key, | |
| 94 bool control, | |
| 95 bool shift, | |
| 96 bool alt, | |
| 97 bool command) { | |
| 98 DCHECK(!command); // No command key on Aura | |
| 99 return SendKeyPressNotifyWhenDone( | |
| 100 window, key, control, shift, alt, command, base::Closure()); | |
| 101 } | |
| 102 | |
| 103 void SetMaskAndKeycodeThenSend(XEvent* xevent, | |
| 104 unsigned int mask, | |
| 105 unsigned int keycode) { | |
| 106 xevent->xkey.state |= mask; | |
| 107 xevent->xkey.keycode = keycode; | |
| 108 aura::Desktop::GetInstance()->PostNativeEvent(xevent); | |
| 109 } | |
| 110 | |
| 111 void SetKeycodeAndSendThenUnmask(XEvent* xevent, | |
| 112 unsigned int mask, | |
| 113 unsigned int keycode) { | |
| 114 xevent->xkey.keycode = keycode; | |
| 115 aura::Desktop::GetInstance()->PostNativeEvent(xevent); | |
| 116 xevent->xkey.state ^= mask; | |
| 117 } | |
| 118 | |
| 119 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, | |
| 120 ui::KeyboardCode key, | |
| 121 bool control, | |
| 122 bool shift, | |
| 123 bool alt, | |
| 124 bool command, | |
| 125 const base::Closure& closure) { | |
| 126 DCHECK(!command); // No command key on Aura | |
| 127 XEvent xevent = {0}; | |
| 128 xevent.xkey.type = KeyPress; | |
| 129 if (control) | |
| 130 SetMaskAndKeycodeThenSend(&xevent, ControlMask, XK_Control_L); | |
| 131 if (shift) | |
| 132 SetMaskAndKeycodeThenSend(&xevent, ShiftMask, XK_Shift_L); | |
| 133 if (alt) | |
| 134 SetMaskAndKeycodeThenSend(&xevent, Mod1Mask, XK_Alt_L); | |
| 135 xevent.xkey.keycode = ui::XKeysymForWindowsKeyCode(key, shift); | |
| 136 aura::Desktop::GetInstance()->PostNativeEvent(&xevent); | |
| 137 | |
| 138 // Send key release events. | |
| 139 xevent.xkey.type = KeyRelease; | |
| 140 aura::Desktop::GetInstance()->PostNativeEvent(&xevent); | |
| 141 if (alt) | |
| 142 SetKeycodeAndSendThenUnmask(&xevent, Mod1Mask, XK_Alt_L); | |
| 143 if (shift) | |
| 144 SetKeycodeAndSendThenUnmask(&xevent, ShiftMask, XK_Shift_L); | |
| 145 if (control) | |
| 146 SetKeycodeAndSendThenUnmask(&xevent, ControlMask, XK_Control_L); | |
| 147 DCHECK(!xevent.xkey.state); | |
| 148 RunClosureAfterEvents(closure); | |
| 149 return true; | |
| 150 } | |
| 151 | |
| 152 bool SendMouseMove(long x, long y) { | |
| 153 return SendMouseMoveNotifyWhenDone(x, y, base::Closure()); | |
| 154 } | |
| 155 | |
| 156 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& closure) { | |
| 157 XEvent xevent = {0}; | |
| 158 XMotionEvent* xmotion = &xevent.xmotion; | |
| 159 xmotion->type = MotionNotify; | |
| 160 g_current_x = xmotion->x = x; | |
| 161 g_current_y = xmotion->y = y; | |
| 162 xmotion->same_screen = True; | |
| 163 // Desktop will take care of other necessary fields. | |
| 164 aura::Desktop::GetInstance()->PostNativeEvent(&xevent); | |
| 165 RunClosureAfterEvents(closure); | |
| 166 return false; | |
| 167 } | |
| 168 | |
| 169 bool SendMouseEvents(MouseButton type, int state) { | |
| 170 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); | |
| 171 } | |
| 172 | |
| 173 bool SendMouseEventsNotifyWhenDone(MouseButton type, | |
| 174 int state, | |
| 175 const base::Closure& closure) { | |
| 176 XEvent xevent = {0}; | |
| 177 XButtonEvent* xbutton = &xevent.xbutton; | |
| 178 DCHECK_NE(g_current_x, -1000); | |
| 179 DCHECK_NE(g_current_y, -1000); | |
| 180 xbutton->x = g_current_x; | |
| 181 xbutton->y = g_current_y; | |
| 182 xbutton->same_screen = True; | |
| 183 switch (type) { | |
| 184 case LEFT: | |
| 185 xbutton->button = Button1; | |
| 186 xbutton->state = Button1Mask; | |
| 187 break; | |
| 188 case MIDDLE: | |
| 189 xbutton->button = Button2; | |
| 190 xbutton->state = Button2Mask; | |
| 191 break; | |
| 192 case RIGHT: | |
| 193 xbutton->button = Button3; | |
| 194 xbutton->state = Button3Mask; | |
| 195 break; | |
| 196 } | |
| 197 // Desktop will take care of other necessary fields. | |
| 198 | |
| 199 aura::Desktop* desktop = aura::Desktop::GetInstance(); | |
| 200 if (state & DOWN) { | |
| 201 xevent.xbutton.type = ButtonPress; | |
| 202 desktop->PostNativeEvent(&xevent); | |
| 203 } | |
| 204 if (state & UP) { | |
| 205 xevent.xbutton.type = ButtonRelease; | |
| 206 desktop->PostNativeEvent(&xevent); | |
| 207 } | |
| 208 RunClosureAfterEvents(closure); | |
| 209 return false; | |
| 210 } | |
| 211 | |
| 212 bool SendMouseClick(MouseButton type) { | |
| 213 return SendMouseEvents(type, UP | DOWN); | |
| 214 } | |
| 215 | |
| 216 void MoveMouseToCenterAndPress(views::View* view, MouseButton button, | |
| 217 int state, const base::Closure& closure) { | |
| 218 DCHECK(view); | |
| 219 DCHECK(view->GetWidget()); | |
| 220 gfx::Point view_center(view->width() / 2, view->height() / 2); | |
| 221 views::View::ConvertPointToScreen(view, &view_center); | |
| 222 SendMouseMove(view_center.x(), view_center.y()); | |
| 223 SendMouseEventsNotifyWhenDone(button, state, closure); | |
| 224 } | |
| 225 | |
| 226 } // namespace ui_controls | |
| OLD | NEW |