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     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