1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qwaylandinputdevice.h"
44 #include "qwaylandintegration.h"
45 #include "qwaylandwindow.h"
46 #include "qwaylandbuffer.h"
47 #include "qwaylanddatadevicemanager.h"
48 #include "qwaylandtouch.h"
50 #include <QtGui/private/qpixmap_raster_p.h>
51 #include <qpa/qplatformwindow.h>
57 #include <QtGui/QGuiApplication>
59 #ifndef QT_NO_WAYLAND_XKB
60 #include <xkbcommon/xkbcommon.h>
61 #include <X11/keysym.h>
64 QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, uint32_t id)
66 , mDisplay(display->wl_display())
74 #ifndef QT_NO_WAYLAND_XKB
80 mSeat = static_cast<struct wl_seat *>(wl_display_bind(mDisplay, id, &wl_seat_interface));
81 wl_seat_add_listener(mSeat, &seatListener, this);
82 wl_seat_set_user_data(mSeat, this);
84 #ifndef QT_NO_WAYLAND_XKB
86 names.rules = strdup("evdev");
87 names.model = strdup("pc105");
88 names.layout = strdup("us");
89 names.variant = strdup("");
90 names.options = strdup("");
92 xkb_context *mXkbContext = xkb_context_new(xkb_context_flags(0));
94 mXkbMap = xkb_map_new_from_names(mXkbContext, &names, xkb_map_compile_flags(0));
96 mXkbState = xkb_state_new(mXkbMap);
100 if (!mXkbContext || !mXkbMap || !mXkbState)
101 qWarning() << "xkb_map_new_from_names failed, no key input";
104 if (mQDisplay->dndSelectionHandler()) {
105 mTransferDevice = mQDisplay->dndSelectionHandler()->getDataDevice(this);
109 QWaylandInputDevice::~QWaylandInputDevice()
111 #ifndef QT_NO_WAYLAND_XKB
113 xkb_state_unref(mXkbState);
115 xkb_map_unref(mXkbMap);
117 xkb_context_unref(mXkbContext);
121 const struct wl_seat_listener QWaylandInputDevice::seatListener = {
122 QWaylandInputDevice::seat_capabilities
125 const struct wl_pointer_listener QWaylandInputDevice::pointerListener = {
126 QWaylandInputDevice::pointer_enter,
127 QWaylandInputDevice::pointer_leave,
128 QWaylandInputDevice::pointer_motion,
129 QWaylandInputDevice::pointer_button,
130 QWaylandInputDevice::pointer_axis
133 const struct wl_keyboard_listener QWaylandInputDevice::keyboardListener = {
134 QWaylandInputDevice::keyboard_enter,
135 QWaylandInputDevice::keyboard_leave,
136 QWaylandInputDevice::keyboard_key
139 const struct wl_touch_listener QWaylandInputDevice::touchListener = {
140 QWaylandInputDevice::touch_down,
141 QWaylandInputDevice::touch_up,
142 QWaylandInputDevice::touch_motion,
143 QWaylandInputDevice::touch_frame,
144 QWaylandInputDevice::touch_cancel
147 void QWaylandInputDevice::seat_capabilities(void *data, struct wl_seat *seat, uint32_t caps)
149 QWaylandInputDevice *self = static_cast<QWaylandInputDevice *>(data);
152 if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
153 self->mDeviceInterfaces.keyboard = wl_seat_get_keyboard(seat);
154 wl_keyboard_add_listener(self->mDeviceInterfaces.keyboard, &keyboardListener, self);
157 if (caps & WL_SEAT_CAPABILITY_POINTER) {
158 self->mDeviceInterfaces.pointer = wl_seat_get_pointer(seat);
159 wl_pointer_add_listener(self->mDeviceInterfaces.pointer, &pointerListener, self);
162 if (caps & WL_SEAT_CAPABILITY_TOUCH) {
163 self->mDeviceInterfaces.touch = wl_seat_get_touch(seat);
164 wl_touch_add_listener(self->mDeviceInterfaces.touch, &touchListener, self);
166 if (!self->mTouchDevice) {
167 self->mTouchDevice = new QTouchDevice;
168 self->mTouchDevice->setType(QTouchDevice::TouchScreen);
169 self->mTouchDevice->setCapabilities(QTouchDevice::Position);
170 QWindowSystemInterface::registerTouchDevice(self->mTouchDevice);
175 void QWaylandInputDevice::handleWindowDestroyed(QWaylandWindow *window)
177 if (window == mPointerFocus)
179 if (window == mKeyboardFocus)
183 void QWaylandInputDevice::setTransferDevice(struct wl_data_device *device)
185 mTransferDevice = device;
188 struct wl_data_device *QWaylandInputDevice::transferDevice() const
190 Q_ASSERT(mTransferDevice);
191 return mTransferDevice;
194 void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button)
196 mButtons = mButtons & !button;
199 void QWaylandInputDevice::attach(QWaylandBuffer *buffer, int x, int y)
201 if (mCaps & WL_SEAT_CAPABILITY_POINTER)
202 wl_pointer_attach(mDeviceInterfaces.pointer, mTime, buffer->buffer(), x, y);
205 void QWaylandInputDevice::pointer_enter(void *data,
206 struct wl_pointer *pointer,
207 uint32_t time, struct wl_surface *surface,
208 wl_fixed_t sx, wl_fixed_t sy)
213 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
218 QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
219 window->handleMouseEnter();
220 inputDevice->mPointerFocus = window;
222 inputDevice->mTime = time;
225 void QWaylandInputDevice::pointer_leave(void *data,
226 struct wl_pointer *pointer,
227 uint32_t time, struct wl_surface *surface)
230 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
232 // The event may arrive after destroying the window, indicated by
237 QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
238 window->handleMouseLeave();
239 inputDevice->mPointerFocus = 0;
240 inputDevice->mButtons = Qt::NoButton;
242 inputDevice->mTime = time;
245 void QWaylandInputDevice::pointer_motion(void *data,
246 struct wl_pointer *pointer,
248 wl_fixed_t surface_x, wl_fixed_t surface_y)
253 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
254 QWaylandWindow *window = inputDevice->mPointerFocus;
256 if (window == NULL) {
257 // We destroyed the pointer focus surface, but the server
258 // didn't get the message yet.
262 QPointF pos(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
263 QPointF delta = pos - pos.toPoint();
264 QPointF global = window->window()->mapToGlobal(pos.toPoint());
267 inputDevice->mSurfacePos = pos;
268 inputDevice->mGlobalPos = global;
269 inputDevice->mTime = time;
271 window->handleMouse(inputDevice,
273 inputDevice->mSurfacePos,
274 inputDevice->mGlobalPos,
275 inputDevice->mButtons,
279 void QWaylandInputDevice::pointer_button(void *data,
280 struct wl_pointer *pointer,
281 uint32_t serial, uint32_t time,
282 uint32_t button, uint32_t state)
286 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
287 QWaylandWindow *window = inputDevice->mPointerFocus;
288 Qt::MouseButton qt_button;
291 // translate from kernel (input.h) 'button' to corresponding Qt:MouseButton.
292 // The range of mouse values is 0x110 <= mouse_button < 0x120, the first Joystick button.
294 case 0x110: qt_button = Qt::LeftButton; break; // kernel BTN_LEFT
295 case 0x111: qt_button = Qt::RightButton; break;
296 case 0x112: qt_button = Qt::MiddleButton; break;
297 case 0x113: qt_button = Qt::ExtraButton1; break; // AKA Qt::BackButton
298 case 0x114: qt_button = Qt::ExtraButton2; break; // AKA Qt::ForwardButton
299 case 0x115: qt_button = Qt::ExtraButton3; break; // AKA Qt::TaskButton
300 case 0x116: qt_button = Qt::ExtraButton4; break;
301 case 0x117: qt_button = Qt::ExtraButton5; break;
302 case 0x118: qt_button = Qt::ExtraButton6; break;
303 case 0x119: qt_button = Qt::ExtraButton7; break;
304 case 0x11a: qt_button = Qt::ExtraButton8; break;
305 case 0x11b: qt_button = Qt::ExtraButton9; break;
306 case 0x11c: qt_button = Qt::ExtraButton10; break;
307 case 0x11d: qt_button = Qt::ExtraButton11; break;
308 case 0x11e: qt_button = Qt::ExtraButton12; break;
309 case 0x11f: qt_button = Qt::ExtraButton13; break;
310 default: return; // invalid button number (as far as Qt is concerned)
314 inputDevice->mButtons |= qt_button;
316 inputDevice->mButtons &= ~qt_button;
318 inputDevice->mTime = time;
321 window->handleMouse(inputDevice,
323 inputDevice->mSurfacePos,
324 inputDevice->mGlobalPos,
325 inputDevice->mButtons,
330 void QWaylandInputDevice::pointer_axis(void *data,
331 struct wl_pointer *pointer,
337 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
338 QWaylandWindow *window = inputDevice->mPointerFocus;
339 Qt::Orientation orientation = axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ? Qt::Horizontal
341 QWindowSystemInterface::handleWheelEvent(window->window(),
343 inputDevice->mSurfacePos,
344 inputDevice->mGlobalPos,
349 #ifndef QT_NO_WAYLAND_XKB
351 static Qt::KeyboardModifiers translateModifiers(xkb_state *state)
353 Qt::KeyboardModifiers ret = Qt::NoModifier;
354 xkb_state_component cstate = xkb_state_component(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED);
356 if (xkb_state_mod_name_is_active(state, "Shift", cstate))
357 ret |= Qt::ShiftModifier;
358 if (xkb_state_mod_name_is_active(state, "Control", cstate))
359 ret |= Qt::ControlModifier;
360 if (xkb_state_mod_name_is_active(state, "Alt", cstate))
361 ret |= Qt::AltModifier;
362 if (xkb_state_mod_name_is_active(state, "Mod1", cstate))
363 ret |= Qt::AltModifier;
364 if (xkb_state_mod_name_is_active(state, "Mod4", cstate))
365 ret |= Qt::MetaModifier;
370 static const uint32_t KeyTbl[] = {
371 XK_Escape, Qt::Key_Escape,
373 XK_ISO_Left_Tab, Qt::Key_Backtab,
374 XK_BackSpace, Qt::Key_Backspace,
375 XK_Return, Qt::Key_Return,
376 XK_Insert, Qt::Key_Insert,
377 XK_Delete, Qt::Key_Delete,
378 XK_Clear, Qt::Key_Delete,
379 XK_Pause, Qt::Key_Pause,
380 XK_Print, Qt::Key_Print,
382 XK_Home, Qt::Key_Home,
384 XK_Left, Qt::Key_Left,
386 XK_Right, Qt::Key_Right,
387 XK_Down, Qt::Key_Down,
388 XK_Prior, Qt::Key_PageUp,
389 XK_Next, Qt::Key_PageDown,
391 XK_Shift_L, Qt::Key_Shift,
392 XK_Shift_R, Qt::Key_Shift,
393 XK_Shift_Lock, Qt::Key_Shift,
394 XK_Control_L, Qt::Key_Control,
395 XK_Control_R, Qt::Key_Control,
396 XK_Meta_L, Qt::Key_Meta,
397 XK_Meta_R, Qt::Key_Meta,
398 XK_Alt_L, Qt::Key_Alt,
399 XK_Alt_R, Qt::Key_Alt,
400 XK_Caps_Lock, Qt::Key_CapsLock,
401 XK_Num_Lock, Qt::Key_NumLock,
402 XK_Scroll_Lock, Qt::Key_ScrollLock,
403 XK_Super_L, Qt::Key_Super_L,
404 XK_Super_R, Qt::Key_Super_R,
405 XK_Menu, Qt::Key_Menu,
406 XK_Hyper_L, Qt::Key_Hyper_L,
407 XK_Hyper_R, Qt::Key_Hyper_R,
408 XK_Help, Qt::Key_Help,
410 XK_KP_Space, Qt::Key_Space,
411 XK_KP_Tab, Qt::Key_Tab,
412 XK_KP_Enter, Qt::Key_Enter,
413 XK_KP_Home, Qt::Key_Home,
414 XK_KP_Left, Qt::Key_Left,
415 XK_KP_Up, Qt::Key_Up,
416 XK_KP_Right, Qt::Key_Right,
417 XK_KP_Down, Qt::Key_Down,
418 XK_KP_Prior, Qt::Key_PageUp,
419 XK_KP_Next, Qt::Key_PageDown,
420 XK_KP_End, Qt::Key_End,
421 XK_KP_Begin, Qt::Key_Clear,
422 XK_KP_Insert, Qt::Key_Insert,
423 XK_KP_Delete, Qt::Key_Delete,
424 XK_KP_Equal, Qt::Key_Equal,
425 XK_KP_Multiply, Qt::Key_Asterisk,
426 XK_KP_Add, Qt::Key_Plus,
427 XK_KP_Separator, Qt::Key_Comma,
428 XK_KP_Subtract, Qt::Key_Minus,
429 XK_KP_Decimal, Qt::Key_Period,
430 XK_KP_Divide, Qt::Key_Slash,
432 XK_ISO_Level3_Shift, Qt::Key_AltGr,
433 XK_Multi_key, Qt::Key_Multi_key,
434 XK_Codeinput, Qt::Key_Codeinput,
435 XK_SingleCandidate, Qt::Key_SingleCandidate,
436 XK_MultipleCandidate, Qt::Key_MultipleCandidate,
437 XK_PreviousCandidate, Qt::Key_PreviousCandidate,
439 XK_Mode_switch, Qt::Key_Mode_switch,
440 XK_script_switch, Qt::Key_Mode_switch,
445 static uint32_t translateKey(uint32_t sym, char *string, size_t size)
451 for (int i = 0; KeyTbl[i]; i += 2) {
452 if (sym == KeyTbl[i]) {
453 code = KeyTbl[i + 1];
465 #endif // QT_NO_WAYLAND_XKB
467 void QWaylandInputDevice::keyboard_enter(void *data,
468 struct wl_keyboard *keyboard,
470 struct wl_surface *surface,
471 struct wl_array *keys)
480 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
481 QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
482 inputDevice->mKeyboardFocus = window;
483 inputDevice->mQDisplay->setLastKeyboardFocusInputDevice(inputDevice);
484 QWindowSystemInterface::handleWindowActivated(window->window());
487 void QWaylandInputDevice::keyboard_leave(void *data,
488 struct wl_keyboard *keyboard,
490 struct wl_surface *surface)
496 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
497 inputDevice->mKeyboardFocus = NULL;
498 inputDevice->mQDisplay->setLastKeyboardFocusInputDevice(0);
499 QWindowSystemInterface::handleWindowActivated(0);
502 void QWaylandInputDevice::keyboard_key(void *data,
503 struct wl_keyboard *keyboard,
504 uint32_t serial, uint32_t time,
505 uint32_t key, uint32_t state)
509 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
510 QWaylandWindow *window = inputDevice->mKeyboardFocus;
511 #ifndef QT_NO_WAYLAND_XKB
512 uint32_t numSyms, code;
513 const xkb_keysym_t *syms;
514 Qt::KeyboardModifiers modifiers;
518 if (!inputDevice->mXkbMap)
522 bool isDown = state != 0;
523 numSyms = xkb_key_get_syms(inputDevice->mXkbState, code, &syms);
524 xkb_state_update_key(inputDevice->mXkbState, code,
525 isDown ? XKB_KEY_DOWN : XKB_KEY_UP);
528 // We destroyed the keyboard focus surface, but the server
529 // didn't get the message yet.
534 xkb_keysym_t sym = syms[0];
535 Qt::KeyboardModifiers modifiers = translateModifiers(inputDevice->mXkbState);
536 type = isDown ? QEvent::KeyPress : QEvent::KeyRelease;
538 sym = translateKey(sym, s, sizeof s);
541 QWindowSystemInterface::handleExtendedKeyEvent(window->window(),
545 QString::fromLatin1(s));
548 // Generic fallback for single hard keys: Assume 'key' is a Qt key code.
550 QWindowSystemInterface::handleExtendedKeyEvent(window->window(),
551 time, state ? QEvent::KeyPress : QEvent::KeyRelease,
552 key + 8, // qt-compositor substracts 8 for some reason
559 void QWaylandInputDevice::touch_down(void *data,
560 struct wl_touch *touch,
563 struct wl_surface *surface,
571 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
572 inputDevice->mTouchFocus = static_cast<QWaylandWindow *>(wl_surface_get_user_data(surface));
573 inputDevice->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed);
576 void QWaylandInputDevice::touch_up(void *data,
577 struct wl_touch *touch,
585 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
586 inputDevice->mTouchFocus = 0;
587 inputDevice->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased);
590 void QWaylandInputDevice::touch_motion(void *data,
591 struct wl_touch *touch,
599 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
600 inputDevice->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointMoved);
603 void QWaylandInputDevice::touch_frame(void *data, struct wl_touch *touch)
606 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
607 inputDevice->handleTouchFrame();
610 void QWaylandInputDevice::touch_cancel(void *data, struct wl_touch *touch)
613 QWaylandInputDevice *self = static_cast<QWaylandInputDevice *>(data);
615 self->mPrevTouchPoints.clear();
616 self->mTouchPoints.clear();
618 QWaylandTouchExtension *touchExt = self->mQDisplay->touchExtension();
620 touchExt->touchCanceled();
622 QWindowSystemInterface::handleTouchCancelEvent(0, self->mTouchDevice);
625 void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state)
627 QWindowSystemInterface::TouchPoint tp;
629 // Find out the coordinates for Released events.
630 bool coordsOk = false;
631 if (state == Qt::TouchPointReleased)
632 for (int i = 0; i < mPrevTouchPoints.count(); ++i)
633 if (mPrevTouchPoints.at(i).id == id) {
634 tp.area = mPrevTouchPoints.at(i).area;
640 // x and y are surface relative.
641 // We need a global (screen) position.
642 QWaylandWindow *win = mTouchFocus;
644 //is it possible that mTouchFocus is null;
648 win = mKeyboardFocus;
649 if (!win || !win->window())
652 tp.area = QRectF(0, 0, 8, 8);
653 QMargins margins = win->frameMargins();
654 tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x+margins.left(), y+margins.top())));
659 tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
660 mTouchPoints.append(tp);
663 void QWaylandInputDevice::handleTouchFrame()
665 // Copy all points, that are in the previous but not in the current list, as stationary.
666 for (int i = 0; i < mPrevTouchPoints.count(); ++i) {
667 const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i));
668 if (prevPoint.state == Qt::TouchPointReleased)
671 for (int j = 0; j < mTouchPoints.count(); ++j)
672 if (mTouchPoints.at(j).id == prevPoint.id) {
677 QWindowSystemInterface::TouchPoint p = prevPoint;
678 p.state = Qt::TouchPointStationary;
679 mTouchPoints.append(p);
683 if (mTouchPoints.isEmpty()) {
684 mPrevTouchPoints.clear();
688 QWindowSystemInterface::handleTouchEvent(0, mTouchDevice, mTouchPoints);
690 bool allReleased = true;
691 for (int i = 0; i < mTouchPoints.count(); ++i)
692 if (mTouchPoints.at(i).state != Qt::TouchPointReleased) {
697 mPrevTouchPoints = mTouchPoints;
698 mTouchPoints.clear();
701 QWindowSystemInterface::handleTouchEvent(0, mTouchDevice, mTouchPoints);
702 mPrevTouchPoints.clear();