Add test for ChromeVox keyboard commands.
[chromium-blink-merge.git] / ui / aura / test / ui_controls_factory_aurax11.cc
blob383d0734049e3773f959490fe08c6dd073ea7f37
1 // Copyright 2013 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.
5 #include <X11/keysym.h>
6 #include <X11/Xlib.h>
8 #include "base/bind.h"
9 #include "base/logging.h"
10 #include "ui/aura/client/screen_position_client.h"
11 #include "ui/aura/env.h"
12 #include "ui/aura/test/aura_test_utils.h"
13 #include "ui/aura/test/ui_controls_factory_aura.h"
14 #include "ui/aura/window.h"
15 #include "ui/aura/window_tree_host.h"
16 #include "ui/base/test/ui_controls_aura.h"
17 #include "ui/base/x/x11_util.h"
18 #include "ui/compositor/dip_util.h"
19 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
20 #include "ui/events/test/platform_event_waiter.h"
22 namespace aura {
23 namespace test {
24 namespace {
26 using ui_controls::DOWN;
27 using ui_controls::LEFT;
28 using ui_controls::MIDDLE;
29 using ui_controls::MouseButton;
30 using ui_controls::RIGHT;
31 using ui_controls::UIControlsAura;
32 using ui_controls::UP;
34 // Mask of the buttons currently down.
35 unsigned button_down_mask = 0;
37 // Returns atom that indidates that the XEvent is marker event.
38 Atom MarkerEventAtom() {
39 return XInternAtom(gfx::GetXDisplay(), "marker_event", False);
42 // Returns true when the event is a marker event.
43 bool Matcher(const base::NativeEvent& event) {
44 return event->xany.type == ClientMessage &&
45 event->xclient.message_type == MarkerEventAtom();
48 class UIControlsX11 : public UIControlsAura {
49 public:
50 UIControlsX11(WindowTreeHost* host) : host_(host) {
53 virtual bool SendKeyPress(gfx::NativeWindow window,
54 ui::KeyboardCode key,
55 bool control,
56 bool shift,
57 bool alt,
58 bool command) OVERRIDE {
59 return SendKeyPressNotifyWhenDone(
60 window, key, control, shift, alt, command, base::Closure());
62 virtual bool SendKeyPressNotifyWhenDone(
63 gfx::NativeWindow window,
64 ui::KeyboardCode key,
65 bool control,
66 bool shift,
67 bool alt,
68 bool command,
69 const base::Closure& closure) OVERRIDE {
70 XEvent xevent = {0};
71 xevent.xkey.type = KeyPress;
72 if (control)
73 SetKeycodeAndSendThenMask(&xevent, XK_Control_L, ControlMask);
74 if (shift)
75 SetKeycodeAndSendThenMask(&xevent, XK_Shift_L, ShiftMask);
76 if (alt)
77 SetKeycodeAndSendThenMask(&xevent, XK_Alt_L, Mod1Mask);
78 if (command)
79 SetKeycodeAndSendThenMask(&xevent, XK_Super_L, Mod4Mask);
80 xevent.xkey.keycode =
81 XKeysymToKeycode(gfx::GetXDisplay(),
82 ui::XKeysymForWindowsKeyCode(key, shift));
83 host_->PostNativeEvent(&xevent);
85 // Send key release events.
86 xevent.xkey.type = KeyRelease;
87 host_->PostNativeEvent(&xevent);
88 if (alt)
89 UnmaskAndSetKeycodeThenSend(&xevent, Mod1Mask, XK_Alt_L);
90 if (shift)
91 UnmaskAndSetKeycodeThenSend(&xevent, ShiftMask, XK_Shift_L);
92 if (control)
93 UnmaskAndSetKeycodeThenSend(&xevent, ControlMask, XK_Control_L);
94 if (command)
95 UnmaskAndSetKeycodeThenSend(&xevent, Mod4Mask, XK_Super_L);
96 DCHECK(!xevent.xkey.state);
97 RunClosureAfterAllPendingUIEvents(closure);
98 return true;
101 virtual bool SendMouseMove(long screen_x, long screen_y) OVERRIDE {
102 return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure());
104 virtual bool SendMouseMoveNotifyWhenDone(
105 long screen_x,
106 long screen_y,
107 const base::Closure& closure) OVERRIDE {
108 gfx::Point root_location(screen_x, screen_y);
109 aura::client::ScreenPositionClient* screen_position_client =
110 aura::client::GetScreenPositionClient(host_->window());
111 if (screen_position_client) {
112 screen_position_client->ConvertPointFromScreen(host_->window(),
113 &root_location);
115 gfx::Point root_current_location =
116 QueryLatestMousePositionRequestInHost(host_);
117 host_->ConvertPointFromHost(&root_current_location);
119 if (root_location != root_current_location && button_down_mask == 0) {
120 // Move the cursor because EnterNotify/LeaveNotify are generated with the
121 // current mouse position as a result of XGrabPointer()
122 host_->window()->MoveCursorTo(root_location);
123 } else {
124 XEvent xevent = {0};
125 XMotionEvent* xmotion = &xevent.xmotion;
126 xmotion->type = MotionNotify;
127 xmotion->x = root_location.x();
128 xmotion->y = root_location.y();
129 xmotion->state = button_down_mask;
130 xmotion->same_screen = True;
131 // WindowTreeHost will take care of other necessary fields.
132 host_->PostNativeEvent(&xevent);
134 RunClosureAfterAllPendingUIEvents(closure);
135 return true;
137 virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE {
138 return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
140 virtual bool SendMouseEventsNotifyWhenDone(
141 MouseButton type,
142 int state,
143 const base::Closure& closure) OVERRIDE {
144 XEvent xevent = {0};
145 XButtonEvent* xbutton = &xevent.xbutton;
146 gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location();
147 aura::client::ScreenPositionClient* screen_position_client =
148 aura::client::GetScreenPositionClient(host_->window());
149 if (screen_position_client) {
150 screen_position_client->ConvertPointFromScreen(host_->window(),
151 &mouse_loc);
153 xbutton->x = mouse_loc.x();
154 xbutton->y = mouse_loc.y();
155 xbutton->same_screen = True;
156 switch (type) {
157 case LEFT:
158 xbutton->button = Button1;
159 xbutton->state = Button1Mask;
160 break;
161 case MIDDLE:
162 xbutton->button = Button2;
163 xbutton->state = Button2Mask;
164 break;
165 case RIGHT:
166 xbutton->button = Button3;
167 xbutton->state = Button3Mask;
168 break;
170 // WindowEventDispatcher will take care of other necessary fields.
171 if (state & DOWN) {
172 xevent.xbutton.type = ButtonPress;
173 host_->PostNativeEvent(&xevent);
174 button_down_mask |= xbutton->state;
176 if (state & UP) {
177 xevent.xbutton.type = ButtonRelease;
178 host_->PostNativeEvent(&xevent);
179 button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state;
181 RunClosureAfterAllPendingUIEvents(closure);
182 return true;
184 virtual bool SendMouseClick(MouseButton type) OVERRIDE {
185 return SendMouseEvents(type, UP | DOWN);
187 virtual void RunClosureAfterAllPendingUIEvents(
188 const base::Closure& closure) OVERRIDE {
189 if (closure.is_null())
190 return;
191 static XEvent* marker_event = NULL;
192 if (!marker_event) {
193 marker_event = new XEvent();
194 marker_event->xclient.type = ClientMessage;
195 marker_event->xclient.display = NULL;
196 marker_event->xclient.window = None;
197 marker_event->xclient.format = 8;
199 marker_event->xclient.message_type = MarkerEventAtom();
200 host_->PostNativeEvent(marker_event);
201 ui::PlatformEventWaiter::Create(closure, base::Bind(&Matcher));
203 private:
204 void SetKeycodeAndSendThenMask(XEvent* xevent,
205 KeySym keysym,
206 unsigned int mask) {
207 xevent->xkey.keycode =
208 XKeysymToKeycode(gfx::GetXDisplay(), keysym);
209 host_->PostNativeEvent(xevent);
210 xevent->xkey.state |= mask;
213 void UnmaskAndSetKeycodeThenSend(XEvent* xevent,
214 unsigned int mask,
215 KeySym keysym) {
216 xevent->xkey.state ^= mask;
217 xevent->xkey.keycode =
218 XKeysymToKeycode(gfx::GetXDisplay(), keysym);
219 host_->PostNativeEvent(xevent);
222 WindowTreeHost* host_;
224 DISALLOW_COPY_AND_ASSIGN(UIControlsX11);
227 } // namespace
229 UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) {
230 return new UIControlsX11(host);
233 } // namespace test
234 } // namespace aura