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 |