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 22namespace aura { 23namespace test { 24namespace { 25 26using ui_controls::DOWN; 27using ui_controls::LEFT; 28using ui_controls::MIDDLE; 29using ui_controls::MouseButton; 30using ui_controls::RIGHT; 31using ui_controls::UIControlsAura; 32using ui_controls::UP; 33 34// Mask of the buttons currently down. 35unsigned button_down_mask = 0; 36 37// Returns atom that indidates that the XEvent is marker event. 38Atom MarkerEventAtom() { 39 return XInternAtom(gfx::GetXDisplay(), "marker_event", False); 40} 41 42// Returns true when the event is a marker event. 43bool Matcher(const base::NativeEvent& event) { 44 return event->xany.type == ClientMessage && 45 event->xclient.message_type == MarkerEventAtom(); 46} 47 48class 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 return SendKeyPressNotifyWhenDone( 60 window, key, control, shift, alt, command, base::Closure()); 61 } 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_Meta_L, Mod4Mask); 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 if (command) 95 UnmaskAndSetKeycodeThenSend(&xevent, Mod4Mask, XK_Meta_L); 96 DCHECK(!xevent.xkey.state); 97 RunClosureAfterAllPendingUIEvents(closure); 98 return true; 99 } 100 101 virtual bool SendMouseMove(long screen_x, long screen_y) OVERRIDE { 102 return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure()); 103 } 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); 114 } 115 gfx::Point root_current_location = 116 QueryLatestMousePositionRequestInHost(host_); 117 host_->ConvertPointFromHost(&root_current_location); 118 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); 133 } 134 RunClosureAfterAllPendingUIEvents(closure); 135 return true; 136 } 137 virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE { 138 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); 139 } 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); 152 } 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; 169 } 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; 175 } 176 if (state & UP) { 177 xevent.xbutton.type = ButtonRelease; 178 host_->PostNativeEvent(&xevent); 179 button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state; 180 } 181 RunClosureAfterAllPendingUIEvents(closure); 182 return true; 183 } 184 virtual bool SendMouseClick(MouseButton type) OVERRIDE { 185 return SendMouseEvents(type, UP | DOWN); 186 } 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; 198 } 199 marker_event->xclient.message_type = MarkerEventAtom(); 200 host_->PostNativeEvent(marker_event); 201 ui::PlatformEventWaiter::Create(closure, base::Bind(&Matcher)); 202 } 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; 211 } 212 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); 220 } 221 222 WindowTreeHost* host_; 223 224 DISALLOW_COPY_AND_ASSIGN(UIControlsX11); 225}; 226 227} // namespace 228 229UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) { 230 return new UIControlsX11(host); 231} 232 233} // namespace test 234} // namespace aura 235