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/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"
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
;
34 // Mask of the buttons currently down.
35 unsigned button_down_mask
= 0;
37 // Returns atom that indidates that the XEvent is marker event.
38 Atom
MarkerEventAtom() {
39 return XInternAtom(gfx::GetXDisplay(), "marker_event", False
);
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();
48 class UIControlsX11
: public UIControlsAura
{
50 UIControlsX11(WindowTreeHost
* host
) : host_(host
) {
53 virtual bool SendKeyPress(gfx::NativeWindow window
,
58 bool command
) OVERRIDE
{
59 return SendKeyPressNotifyWhenDone(
60 window
, key
, control
, shift
, alt
, command
, base::Closure());
62 virtual bool SendKeyPressNotifyWhenDone(
63 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_Super_L
, Mod4Mask
);
81 XKeysymToKeycode(gfx::GetXDisplay(),
82 ui::XKeysymForWindowsKeyCode(key
, shift
));
83 host_
->PostNativeEvent(&xevent
);
85 // Send key release events.
86 xevent
.xkey
.type
= KeyRelease
;
87 host_
->PostNativeEvent(&xevent
);
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_Super_L
);
96 DCHECK(!xevent
.xkey
.state
);
97 RunClosureAfterAllPendingUIEvents(closure
);
101 virtual bool SendMouseMove(long screen_x
, long screen_y
) OVERRIDE
{
102 return SendMouseMoveNotifyWhenDone(screen_x
, screen_y
, base::Closure());
104 virtual bool SendMouseMoveNotifyWhenDone(
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(),
115 gfx::Point root_current_location
=
116 QueryLatestMousePositionRequestInHost(host_
);
117 host_
->ConvertPointFromHost(&root_current_location
);
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
);
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
);
134 RunClosureAfterAllPendingUIEvents(closure
);
137 virtual bool SendMouseEvents(MouseButton type
, int state
) OVERRIDE
{
138 return SendMouseEventsNotifyWhenDone(type
, state
, base::Closure());
140 virtual bool SendMouseEventsNotifyWhenDone(
143 const base::Closure
& closure
) OVERRIDE
{
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(),
153 xbutton
->x
= mouse_loc
.x();
154 xbutton
->y
= mouse_loc
.y();
155 xbutton
->same_screen
= True
;
158 xbutton
->button
= Button1
;
159 xbutton
->state
= Button1Mask
;
162 xbutton
->button
= Button2
;
163 xbutton
->state
= Button2Mask
;
166 xbutton
->button
= Button3
;
167 xbutton
->state
= Button3Mask
;
170 // WindowEventDispatcher will take care of other necessary fields.
172 xevent
.xbutton
.type
= ButtonPress
;
173 host_
->PostNativeEvent(&xevent
);
174 button_down_mask
|= xbutton
->state
;
177 xevent
.xbutton
.type
= ButtonRelease
;
178 host_
->PostNativeEvent(&xevent
);
179 button_down_mask
= (button_down_mask
| xbutton
->state
) ^ xbutton
->state
;
181 RunClosureAfterAllPendingUIEvents(closure
);
184 virtual bool SendMouseClick(MouseButton type
) OVERRIDE
{
185 return SendMouseEvents(type
, UP
| DOWN
);
187 virtual void RunClosureAfterAllPendingUIEvents(
188 const base::Closure
& closure
) OVERRIDE
{
189 if (closure
.is_null())
191 static XEvent
* marker_event
= NULL
;
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;
199 marker_event
->xclient
.message_type
= MarkerEventAtom();
200 host_
->PostNativeEvent(marker_event
);
201 ui::PlatformEventWaiter::Create(closure
, base::Bind(&Matcher
));
204 void SetKeycodeAndSendThenMask(XEvent
* xevent
,
207 xevent
->xkey
.keycode
=
208 XKeysymToKeycode(gfx::GetXDisplay(), keysym
);
209 host_
->PostNativeEvent(xevent
);
210 xevent
->xkey
.state
|= mask
;
213 void UnmaskAndSetKeycodeThenSend(XEvent
* xevent
,
216 xevent
->xkey
.state
^= mask
;
217 xevent
->xkey
.keycode
=
218 XKeysymToKeycode(gfx::GetXDisplay(), keysym
);
219 host_
->PostNativeEvent(xevent
);
222 WindowTreeHost
* host_
;
224 DISALLOW_COPY_AND_ASSIGN(UIControlsX11
);
229 UIControlsAura
* CreateUIControlsAura(WindowTreeHost
* host
) {
230 return new UIControlsX11(host
);