Home | History | Annotate | Download | only in test
      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     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 
    229 UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) {
    230   return new UIControlsX11(host);
    231 }
    232 
    233 }  // namespace test
    234 }  // namespace aura
    235