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.
5 #include <X11/keysym.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/test/x11_event_sender.h"
15 #include "ui/aura/window.h"
16 #include "ui/aura/window_tree_host.h"
17 #include "ui/base/test/ui_controls_aura.h"
18 #include "ui/base/x/x11_util.h"
19 #include "ui/compositor/dip_util.h"
20 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
21 #include "ui/events/test/platform_event_waiter.h"
27 using ui_controls::DOWN
;
28 using ui_controls::LEFT
;
29 using ui_controls::MIDDLE
;
30 using ui_controls::MouseButton
;
31 using ui_controls::RIGHT
;
32 using ui_controls::UIControlsAura
;
33 using ui_controls::UP
;
35 // Mask of the buttons currently down.
36 unsigned button_down_mask
= 0;
38 // Returns atom that indidates that the XEvent is marker event.
39 Atom
MarkerEventAtom() {
40 return XInternAtom(gfx::GetXDisplay(), "marker_event", False
);
43 // Returns true when the event is a marker event.
44 bool Matcher(const base::NativeEvent
& event
) {
45 return event
->xany
.type
== ClientMessage
&&
46 event
->xclient
.message_type
== MarkerEventAtom();
49 class UIControlsX11
: public UIControlsAura
{
51 UIControlsX11(WindowTreeHost
* host
) : host_(host
) {
54 bool SendKeyPress(gfx::NativeWindow window
,
59 bool command
) override
{
60 return SendKeyPressNotifyWhenDone(
61 window
, key
, control
, shift
, alt
, command
, base::Closure());
63 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window
,
69 const base::Closure
& closure
) override
{
71 xevent
.xkey
.type
= KeyPress
;
73 SetKeycodeAndSendThenMask(&xevent
, XK_Control_L
, ControlMask
);
75 SetKeycodeAndSendThenMask(&xevent
, XK_Shift_L
, ShiftMask
);
77 SetKeycodeAndSendThenMask(&xevent
, XK_Alt_L
, Mod1Mask
);
79 SetKeycodeAndSendThenMask(&xevent
, XK_Meta_L
, Mod4Mask
);
81 XKeysymToKeycode(gfx::GetXDisplay(),
82 ui::XKeysymForWindowsKeyCode(key
, shift
));
83 PostEventToWindowTreeHost(xevent
, host_
);
85 // Send key release events.
86 xevent
.xkey
.type
= KeyRelease
;
87 PostEventToWindowTreeHost(xevent
, host_
);
89 UnmaskAndSetKeycodeThenSend(&xevent
, Mod1Mask
, XK_Alt_L
);
91 UnmaskAndSetKeycodeThenSend(&xevent
, ShiftMask
, XK_Shift_L
);
93 UnmaskAndSetKeycodeThenSend(&xevent
, ControlMask
, XK_Control_L
);
95 UnmaskAndSetKeycodeThenSend(&xevent
, Mod4Mask
, XK_Meta_L
);
96 DCHECK(!xevent
.xkey
.state
);
97 RunClosureAfterAllPendingUIEvents(closure
);
101 bool SendMouseMove(long screen_x
, long screen_y
) override
{
102 return SendMouseMoveNotifyWhenDone(screen_x
, screen_y
, base::Closure());
104 bool SendMouseMoveNotifyWhenDone(long screen_x
,
106 const base::Closure
& closure
) override
{
107 gfx::Point
root_location(screen_x
, screen_y
);
108 aura::client::ScreenPositionClient
* screen_position_client
=
109 aura::client::GetScreenPositionClient(host_
->window());
110 if (screen_position_client
) {
111 screen_position_client
->ConvertPointFromScreen(host_
->window(),
114 gfx::Point root_current_location
=
115 QueryLatestMousePositionRequestInHost(host_
);
116 host_
->ConvertPointFromHost(&root_current_location
);
118 if (root_location
!= root_current_location
&& button_down_mask
== 0) {
119 // Move the cursor because EnterNotify/LeaveNotify are generated with the
120 // current mouse position as a result of XGrabPointer()
121 host_
->window()->MoveCursorTo(root_location
);
124 XMotionEvent
* xmotion
= &xevent
.xmotion
;
125 xmotion
->type
= MotionNotify
;
126 xmotion
->x
= root_location
.x();
127 xmotion
->y
= root_location
.y();
128 xmotion
->state
= button_down_mask
;
129 xmotion
->same_screen
= True
;
130 // WindowTreeHost will take care of other necessary fields.
131 PostEventToWindowTreeHost(xevent
, host_
);
133 RunClosureAfterAllPendingUIEvents(closure
);
136 bool SendMouseEvents(MouseButton type
, int state
) override
{
137 return SendMouseEventsNotifyWhenDone(type
, state
, base::Closure());
139 bool SendMouseEventsNotifyWhenDone(MouseButton type
,
141 const base::Closure
& closure
) override
{
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(),
151 xbutton
->x
= mouse_loc
.x();
152 xbutton
->y
= mouse_loc
.y();
153 xbutton
->same_screen
= True
;
156 xbutton
->button
= Button1
;
157 xbutton
->state
= Button1Mask
;
160 xbutton
->button
= Button2
;
161 xbutton
->state
= Button2Mask
;
164 xbutton
->button
= Button3
;
165 xbutton
->state
= Button3Mask
;
168 // WindowEventDispatcher will take care of other necessary fields.
170 xevent
.xbutton
.type
= ButtonPress
;
171 PostEventToWindowTreeHost(xevent
, host_
);
172 button_down_mask
|= xbutton
->state
;
175 xevent
.xbutton
.type
= ButtonRelease
;
176 PostEventToWindowTreeHost(xevent
, host_
);
177 button_down_mask
= (button_down_mask
| xbutton
->state
) ^ xbutton
->state
;
179 RunClosureAfterAllPendingUIEvents(closure
);
182 bool SendMouseClick(MouseButton type
) override
{
183 return SendMouseEvents(type
, UP
| DOWN
);
185 void RunClosureAfterAllPendingUIEvents(
186 const base::Closure
& closure
) override
{
187 if (closure
.is_null())
189 static XEvent
* marker_event
= NULL
;
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;
197 marker_event
->xclient
.message_type
= MarkerEventAtom();
198 PostEventToWindowTreeHost(*marker_event
, host_
);
199 ui::PlatformEventWaiter::Create(closure
, base::Bind(&Matcher
));
202 void SetKeycodeAndSendThenMask(XEvent
* xevent
,
205 xevent
->xkey
.keycode
=
206 XKeysymToKeycode(gfx::GetXDisplay(), keysym
);
207 PostEventToWindowTreeHost(*xevent
, host_
);
208 xevent
->xkey
.state
|= mask
;
211 void UnmaskAndSetKeycodeThenSend(XEvent
* xevent
,
214 xevent
->xkey
.state
^= mask
;
215 xevent
->xkey
.keycode
=
216 XKeysymToKeycode(gfx::GetXDisplay(), keysym
);
217 PostEventToWindowTreeHost(*xevent
, host_
);
220 WindowTreeHost
* host_
;
222 DISALLOW_COPY_AND_ASSIGN(UIControlsX11
);
227 UIControlsAura
* CreateUIControlsAura(WindowTreeHost
* host
) {
228 return new UIControlsX11(host
);