ui_controls_factory_aurax11.cc revision 58537e28ecd584eab876aee8be7156509866d23a
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. 4 5#include <X11/keysym.h> 6#include <X11/Xlib.h> 7 8// X macro fail. 9#if defined(RootWindow) 10#undef RootWindow 11#endif 12 13#include "base/logging.h" 14#include "base/message_loop/message_pump_x11.h" 15#include "ui/aura/client/screen_position_client.h" 16#include "ui/aura/env.h" 17#include "ui/aura/root_window.h" 18#include "ui/aura/test/ui_controls_factory_aura.h" 19#include "ui/base/keycodes/keyboard_code_conversion_x.h" 20#include "ui/base/test/ui_controls_aura.h" 21#include "ui/compositor/dip_util.h" 22 23namespace aura { 24namespace test { 25namespace { 26 27using ui_controls::DOWN; 28using ui_controls::LEFT; 29using ui_controls::MIDDLE; 30using ui_controls::MouseButton; 31using ui_controls::RIGHT; 32using ui_controls::UIControlsAura; 33using ui_controls::UP; 34 35// Mask of the buttons currently down. 36unsigned button_down_mask = 0; 37 38// Event waiter executes the specified closure|when a matching event 39// is found. 40// TODO(oshima): Move this to base. 41class EventWaiter : public base::MessageLoopForUI::Observer { 42 public: 43 typedef bool (*EventWaiterMatcher)(const base::NativeEvent& event); 44 45 EventWaiter(const base::Closure& closure, EventWaiterMatcher matcher) 46 : closure_(closure), 47 matcher_(matcher) { 48 base::MessageLoopForUI::current()->AddObserver(this); 49 } 50 51 virtual ~EventWaiter() { 52 base::MessageLoopForUI::current()->RemoveObserver(this); 53 } 54 55 // MessageLoop::Observer implementation: 56 virtual base::EventStatus WillProcessEvent( 57 const base::NativeEvent& event) OVERRIDE { 58 if ((*matcher_)(event)) { 59 base::MessageLoop::current()->PostTask(FROM_HERE, closure_); 60 delete this; 61 } 62 return base::EVENT_CONTINUE; 63 } 64 65 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE { 66 } 67 68 private: 69 base::Closure closure_; 70 EventWaiterMatcher matcher_; 71 DISALLOW_COPY_AND_ASSIGN(EventWaiter); 72}; 73 74// Returns atom that indidates that the XEvent is marker event. 75Atom MarkerEventAtom() { 76 return XInternAtom(base::MessagePumpX11::GetDefaultXDisplay(), 77 "marker_event", 78 False); 79} 80 81// Returns true when the event is a marker event. 82bool Matcher(const base::NativeEvent& event) { 83 return event->xany.type == ClientMessage && 84 event->xclient.message_type == MarkerEventAtom(); 85} 86 87class UIControlsX11 : public UIControlsAura { 88 public: 89 UIControlsX11(aura::RootWindow* root_window) : root_window_(root_window) { 90 } 91 92 virtual bool SendKeyPress(gfx::NativeWindow window, 93 ui::KeyboardCode key, 94 bool control, 95 bool shift, 96 bool alt, 97 bool command) OVERRIDE { 98 DCHECK(!command); // No command key on Aura 99 return SendKeyPressNotifyWhenDone( 100 window, key, control, shift, alt, command, base::Closure()); 101 } 102 virtual bool SendKeyPressNotifyWhenDone( 103 gfx::NativeWindow window, 104 ui::KeyboardCode key, 105 bool control, 106 bool shift, 107 bool alt, 108 bool command, 109 const base::Closure& closure) OVERRIDE { 110 DCHECK(!command); // No command key on Aura 111 XEvent xevent = {0}; 112 xevent.xkey.type = KeyPress; 113 if (control) 114 SetKeycodeAndSendThenMask(&xevent, XK_Control_L, ControlMask); 115 if (shift) 116 SetKeycodeAndSendThenMask(&xevent, XK_Shift_L, ShiftMask); 117 if (alt) 118 SetKeycodeAndSendThenMask(&xevent, XK_Alt_L, Mod1Mask); 119 xevent.xkey.keycode = 120 XKeysymToKeycode(base::MessagePumpX11::GetDefaultXDisplay(), 121 ui::XKeysymForWindowsKeyCode(key, shift)); 122 root_window_->PostNativeEvent(&xevent); 123 124 // Send key release events. 125 xevent.xkey.type = KeyRelease; 126 root_window_->PostNativeEvent(&xevent); 127 if (alt) 128 UnmaskAndSetKeycodeThenSend(&xevent, Mod1Mask, XK_Alt_L); 129 if (shift) 130 UnmaskAndSetKeycodeThenSend(&xevent, ShiftMask, XK_Shift_L); 131 if (control) 132 UnmaskAndSetKeycodeThenSend(&xevent, ControlMask, XK_Control_L); 133 DCHECK(!xevent.xkey.state); 134 RunClosureAfterAllPendingUIEvents(closure); 135 return true; 136 } 137 138 // Simulate a mouse move. (x,y) are absolute screen coordinates. 139 virtual bool SendMouseMove(long x, long y) OVERRIDE { 140 return SendMouseMoveNotifyWhenDone(x, y, base::Closure()); 141 } 142 virtual bool SendMouseMoveNotifyWhenDone( 143 long x, 144 long y, 145 const base::Closure& closure) OVERRIDE { 146 XEvent xevent = {0}; 147 XMotionEvent* xmotion = &xevent.xmotion; 148 xmotion->type = MotionNotify; 149 gfx::Point point = ui::ConvertPointToPixel( 150 root_window_->layer(), 151 gfx::Point(static_cast<int>(x), static_cast<int>(y))); 152 xmotion->x = point.x(); 153 xmotion->y = point.y(); 154 xmotion->state = button_down_mask; 155 xmotion->same_screen = True; 156 // RootWindow will take care of other necessary fields. 157 root_window_->PostNativeEvent(&xevent); 158 RunClosureAfterAllPendingUIEvents(closure); 159 return true; 160 } 161 virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE { 162 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); 163 } 164 virtual bool SendMouseEventsNotifyWhenDone( 165 MouseButton type, 166 int state, 167 const base::Closure& closure) OVERRIDE { 168 XEvent xevent = {0}; 169 XButtonEvent* xbutton = &xevent.xbutton; 170 gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location(); 171 aura::client::ScreenPositionClient* screen_position_client = 172 aura::client::GetScreenPositionClient(root_window_); 173 if (screen_position_client) 174 screen_position_client->ConvertPointFromScreen(root_window_, &mouse_loc); 175 xbutton->x = mouse_loc.x(); 176 xbutton->y = mouse_loc.y(); 177 xbutton->same_screen = True; 178 switch (type) { 179 case LEFT: 180 xbutton->button = Button1; 181 xbutton->state = Button1Mask; 182 break; 183 case MIDDLE: 184 xbutton->button = Button2; 185 xbutton->state = Button2Mask; 186 break; 187 case RIGHT: 188 xbutton->button = Button3; 189 xbutton->state = Button3Mask; 190 break; 191 } 192 // RootWindow will take care of other necessary fields. 193 if (state & DOWN) { 194 xevent.xbutton.type = ButtonPress; 195 root_window_->PostNativeEvent(&xevent); 196 button_down_mask |= xbutton->state; 197 } 198 if (state & UP) { 199 xevent.xbutton.type = ButtonRelease; 200 root_window_->PostNativeEvent(&xevent); 201 button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state; 202 } 203 RunClosureAfterAllPendingUIEvents(closure); 204 return true; 205 } 206 virtual bool SendMouseClick(MouseButton type) OVERRIDE { 207 return SendMouseEvents(type, UP | DOWN); 208 } 209 virtual void RunClosureAfterAllPendingUIEvents( 210 const base::Closure& closure) OVERRIDE { 211 if (closure.is_null()) 212 return; 213 static XEvent* marker_event = NULL; 214 if (!marker_event) { 215 marker_event = new XEvent(); 216 marker_event->xclient.type = ClientMessage; 217 marker_event->xclient.display = NULL; 218 marker_event->xclient.window = None; 219 marker_event->xclient.format = 8; 220 } 221 marker_event->xclient.message_type = MarkerEventAtom(); 222 root_window_->PostNativeEvent(marker_event); 223 new EventWaiter(closure, &Matcher); 224 } 225 private: 226 void SetKeycodeAndSendThenMask(XEvent* xevent, 227 KeySym keysym, 228 unsigned int mask) { 229 xevent->xkey.keycode = 230 XKeysymToKeycode(base::MessagePumpX11::GetDefaultXDisplay(), 231 keysym); 232 root_window_->PostNativeEvent(xevent); 233 xevent->xkey.state |= mask; 234 } 235 236 void UnmaskAndSetKeycodeThenSend(XEvent* xevent, 237 unsigned int mask, 238 KeySym keysym) { 239 xevent->xkey.state ^= mask; 240 xevent->xkey.keycode = 241 XKeysymToKeycode(base::MessagePumpX11::GetDefaultXDisplay(), 242 keysym); 243 root_window_->PostNativeEvent(xevent); 244 } 245 246 aura::RootWindow* root_window_; 247 248 DISALLOW_COPY_AND_ASSIGN(UIControlsX11); 249}; 250 251} // namespace 252 253UIControlsAura* CreateUIControlsAura(aura::RootWindow* root_window) { 254 return new UIControlsX11(root_window); 255} 256 257} // namespace test 258} // namespace aura 259