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 #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" 21 22 namespace aura { 23 namespace test { 24 namespace { 25 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; 33 34 // Mask of the buttons currently down. 35 unsigned button_down_mask = 0; 36 37 // Returns atom that indidates that the XEvent is marker event. 38 Atom MarkerEventAtom() { 39 return XInternAtom(gfx::GetXDisplay(), "marker_event", False); 40 } 41 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(); 46 } 47 48 class UIControlsX11 : public UIControlsAura { 49 public: 50 UIControlsX11(WindowTreeHost* host) : host_(host) { 51 } 52 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 DCHECK(!command); // No command key on Aura 60 return SendKeyPressNotifyWhenDone( 61 window, key, control, shift, alt, command, base::Closure()); 62 } 63 virtual bool SendKeyPressNotifyWhenDone( 64 gfx::NativeWindow window, 65 ui::KeyboardCode key, 66 bool control, 67 bool shift, 68 bool alt, 69 bool command, 70 const base::Closure& closure) OVERRIDE { 71 DCHECK(!command); // No command key on Aura 72 XEvent xevent = {0}; 73 xevent.xkey.type = KeyPress; 74 if (control) 75 SetKeycodeAndSendThenMask(&xevent, XK_Control_L, ControlMask); 76 if (shift) 77 SetKeycodeAndSendThenMask(&xevent, XK_Shift_L, ShiftMask); 78 if (alt) 79 SetKeycodeAndSendThenMask(&xevent, XK_Alt_L, Mod1Mask); 80 xevent.xkey.keycode = 81 XKeysymToKeycode(gfx::GetXDisplay(), 82 ui::XKeysymForWindowsKeyCode(key, shift)); 83 host_->PostNativeEvent(&xevent); 84 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 DCHECK(!xevent.xkey.state); 95 RunClosureAfterAllPendingUIEvents(closure); 96 return true; 97 } 98 99 virtual bool SendMouseMove(long screen_x, long screen_y) OVERRIDE { 100 return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure()); 101 } 102 virtual bool SendMouseMoveNotifyWhenDone( 103 long screen_x, 104 long screen_y, 105 const base::Closure& closure) OVERRIDE { 106 gfx::Point root_location(screen_x, screen_y); 107 aura::client::ScreenPositionClient* screen_position_client = 108 aura::client::GetScreenPositionClient(host_->window()); 109 if (screen_position_client) { 110 screen_position_client->ConvertPointFromScreen(host_->window(), 111 &root_location); 112 } 113 gfx::Point root_current_location = 114 QueryLatestMousePositionRequestInHost(host_); 115 host_->ConvertPointFromHost(&root_current_location); 116 117 if (root_location != root_current_location && button_down_mask == 0) { 118 // Move the cursor because EnterNotify/LeaveNotify are generated with the 119 // current mouse position as a result of XGrabPointer() 120 host_->window()->MoveCursorTo(root_location); 121 } else { 122 XEvent xevent = {0}; 123 XMotionEvent* xmotion = &xevent.xmotion; 124 xmotion->type = MotionNotify; 125 xmotion->x = root_location.x(); 126 xmotion->y = root_location.y(); 127 xmotion->state = button_down_mask; 128 xmotion->same_screen = True; 129 // WindowTreeHost will take care of other necessary fields. 130 host_->PostNativeEvent(&xevent); 131 } 132 RunClosureAfterAllPendingUIEvents(closure); 133 return true; 134 } 135 virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE { 136 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); 137 } 138 virtual bool SendMouseEventsNotifyWhenDone( 139 MouseButton type, 140 int state, 141 const base::Closure& closure) OVERRIDE { 142 XEvent xevent = {0}; 143 XButtonEvent* xbutton = &xevent.xbutton; 144 gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location(); 145 aura::client::ScreenPositionClient* screen_position_client = 146 aura::client::GetScreenPositionClient(host_->window()); 147 if (screen_position_client) { 148 screen_position_client->ConvertPointFromScreen(host_->window(), 149 &mouse_loc); 150 } 151 xbutton->x = mouse_loc.x(); 152 xbutton->y = mouse_loc.y(); 153 xbutton->same_screen = True; 154 switch (type) { 155 case LEFT: 156 xbutton->button = Button1; 157 xbutton->state = Button1Mask; 158 break; 159 case MIDDLE: 160 xbutton->button = Button2; 161 xbutton->state = Button2Mask; 162 break; 163 case RIGHT: 164 xbutton->button = Button3; 165 xbutton->state = Button3Mask; 166 break; 167 } 168 // WindowEventDispatcher will take care of other necessary fields. 169 if (state & DOWN) { 170 xevent.xbutton.type = ButtonPress; 171 host_->PostNativeEvent(&xevent); 172 button_down_mask |= xbutton->state; 173 } 174 if (state & UP) { 175 xevent.xbutton.type = ButtonRelease; 176 host_->PostNativeEvent(&xevent); 177 button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state; 178 } 179 RunClosureAfterAllPendingUIEvents(closure); 180 return true; 181 } 182 virtual bool SendMouseClick(MouseButton type) OVERRIDE { 183 return SendMouseEvents(type, UP | DOWN); 184 } 185 virtual void RunClosureAfterAllPendingUIEvents( 186 const base::Closure& closure) OVERRIDE { 187 if (closure.is_null()) 188 return; 189 static XEvent* marker_event = NULL; 190 if (!marker_event) { 191 marker_event = new XEvent(); 192 marker_event->xclient.type = ClientMessage; 193 marker_event->xclient.display = NULL; 194 marker_event->xclient.window = None; 195 marker_event->xclient.format = 8; 196 } 197 marker_event->xclient.message_type = MarkerEventAtom(); 198 host_->PostNativeEvent(marker_event); 199 ui::PlatformEventWaiter::Create(closure, base::Bind(&Matcher)); 200 } 201 private: 202 void SetKeycodeAndSendThenMask(XEvent* xevent, 203 KeySym keysym, 204 unsigned int mask) { 205 xevent->xkey.keycode = 206 XKeysymToKeycode(gfx::GetXDisplay(), keysym); 207 host_->PostNativeEvent(xevent); 208 xevent->xkey.state |= mask; 209 } 210 211 void UnmaskAndSetKeycodeThenSend(XEvent* xevent, 212 unsigned int mask, 213 KeySym keysym) { 214 xevent->xkey.state ^= mask; 215 xevent->xkey.keycode = 216 XKeysymToKeycode(gfx::GetXDisplay(), keysym); 217 host_->PostNativeEvent(xevent); 218 } 219 220 WindowTreeHost* host_; 221 222 DISALLOW_COPY_AND_ASSIGN(UIControlsX11); 223 }; 224 225 } // namespace 226 227 UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) { 228 return new UIControlsX11(host); 229 } 230 231 } // namespace test 232 } // namespace aura 233