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_keymap,
135 QWaylandInputDevice::keyboard_enter,
136 QWaylandInputDevice::keyboard_leave,
137 QWaylandInputDevice::keyboard_key,
138 QWaylandInputDevice::keyboard_modifiers
141 const struct wl_touch_listener QWaylandInputDevice::touchListener = {
142 QWaylandInputDevice::touch_down,
143 QWaylandInputDevice::touch_up,
144 QWaylandInputDevice::touch_motion,
145 QWaylandInputDevice::touch_frame,
146 QWaylandInputDevice::touch_cancel
149 void QWaylandInputDevice::seat_capabilities(void *data, struct wl_seat *seat, uint32_t caps)
151 QWaylandInputDevice *self = static_cast<QWaylandInputDevice *>(data);
154 if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
155 self->mDeviceInterfaces.keyboard = wl_seat_get_keyboard(seat);
156 wl_keyboard_add_listener(self->mDeviceInterfaces.keyboard, &keyboardListener, self);
159 if (caps & WL_SEAT_CAPABILITY_POINTER) {
160 self->mDeviceInterfaces.pointer = wl_seat_get_pointer(seat);
161 wl_pointer_add_listener(self->mDeviceInterfaces.pointer, &pointerListener, self);
164 if (caps & WL_SEAT_CAPABILITY_TOUCH) {
165 self->mDeviceInterfaces.touch = wl_seat_get_touch(seat);
166 wl_touch_add_listener(self->mDeviceInterfaces.touch, &touchListener, self);
168 if (!self->mTouchDevice) {
169 self->mTouchDevice = new QTouchDevice;
170 self->mTouchDevice->setType(QTouchDevice::TouchScreen);
171 self->mTouchDevice->setCapabilities(QTouchDevice::Position);
172 QWindowSystemInterface::registerTouchDevice(self->mTouchDevice);
177 void QWaylandInputDevice::handleWindowDestroyed(QWaylandWindow *window)
179 if (window == mPointerFocus)
181 if (window == mKeyboardFocus)
185 void QWaylandInputDevice::setTransferDevice(struct wl_data_device *device)
187 mTransferDevice = device;
190 struct wl_data_device *QWaylandInputDevice::transferDevice() const
192 Q_ASSERT(mTransferDevice);
193 return mTransferDevice;
196 void QWaylandInputDevice::removeMouseButtonFromState(Qt::MouseButton button)
198 mButtons = mButtons & !button;
201 void QWaylandInputDevice::attach(QWaylandBuffer *buffer, int x, int y)
203 if (mCaps & WL_SEAT_CAPABILITY_POINTER)
204 wl_pointer_attach(mDeviceInterfaces.pointer, mTime, buffer->buffer(), x, y);
207 void QWaylandInputDevice::pointer_enter(void *data,
208 struct wl_pointer *pointer,
209 uint32_t time, struct wl_surface *surface,
210 wl_fixed_t sx, wl_fixed_t sy)
215 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
220 QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
221 window->handleMouseEnter();
222 inputDevice->mPointerFocus = window;
224 inputDevice->mTime = time;
227 void QWaylandInputDevice::pointer_leave(void *data,
228 struct wl_pointer *pointer,
229 uint32_t time, struct wl_surface *surface)
232 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
234 // The event may arrive after destroying the window, indicated by
239 QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
240 window->handleMouseLeave();
241 inputDevice->mPointerFocus = 0;
242 inputDevice->mButtons = Qt::NoButton;
244 inputDevice->mTime = time;
247 void QWaylandInputDevice::pointer_motion(void *data,
248 struct wl_pointer *pointer,
250 wl_fixed_t surface_x, wl_fixed_t surface_y)
255 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
256 QWaylandWindow *window = inputDevice->mPointerFocus;
258 if (window == NULL) {
259 // We destroyed the pointer focus surface, but the server
260 // didn't get the message yet.
264 QPointF pos(wl_fixed_to_double(surface_x), wl_fixed_to_double(surface_y));
265 QPointF delta = pos - pos.toPoint();
266 QPointF global = window->window()->mapToGlobal(pos.toPoint());
269 inputDevice->mSurfacePos = pos;
270 inputDevice->mGlobalPos = global;
271 inputDevice->mTime = time;
273 window->handleMouse(inputDevice,
275 inputDevice->mSurfacePos,
276 inputDevice->mGlobalPos,
277 inputDevice->mButtons,
281 void QWaylandInputDevice::pointer_button(void *data,
282 struct wl_pointer *pointer,
283 uint32_t serial, uint32_t time,
284 uint32_t button, uint32_t state)
288 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
289 QWaylandWindow *window = inputDevice->mPointerFocus;
290 Qt::MouseButton qt_button;
293 // translate from kernel (input.h) 'button' to corresponding Qt:MouseButton.
294 // The range of mouse values is 0x110 <= mouse_button < 0x120, the first Joystick button.
296 case 0x110: qt_button = Qt::LeftButton; break; // kernel BTN_LEFT
297 case 0x111: qt_button = Qt::RightButton; break;
298 case 0x112: qt_button = Qt::MiddleButton; break;
299 case 0x113: qt_button = Qt::ExtraButton1; break; // AKA Qt::BackButton
300 case 0x114: qt_button = Qt::ExtraButton2; break; // AKA Qt::ForwardButton
301 case 0x115: qt_button = Qt::ExtraButton3; break; // AKA Qt::TaskButton
302 case 0x116: qt_button = Qt::ExtraButton4; break;
303 case 0x117: qt_button = Qt::ExtraButton5; break;
304 case 0x118: qt_button = Qt::ExtraButton6; break;
305 case 0x119: qt_button = Qt::ExtraButton7; break;
306 case 0x11a: qt_button = Qt::ExtraButton8; break;
307 case 0x11b: qt_button = Qt::ExtraButton9; break;
308 case 0x11c: qt_button = Qt::ExtraButton10; break;
309 case 0x11d: qt_button = Qt::ExtraButton11; break;
310 case 0x11e: qt_button = Qt::ExtraButton12; break;
311 case 0x11f: qt_button = Qt::ExtraButton13; break;
312 default: return; // invalid button number (as far as Qt is concerned)
316 inputDevice->mButtons |= qt_button;
318 inputDevice->mButtons &= ~qt_button;
320 inputDevice->mTime = time;
323 window->handleMouse(inputDevice,
325 inputDevice->mSurfacePos,
326 inputDevice->mGlobalPos,
327 inputDevice->mButtons,
332 void QWaylandInputDevice::pointer_axis(void *data,
333 struct wl_pointer *pointer,
339 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
340 QWaylandWindow *window = inputDevice->mPointerFocus;
341 Qt::Orientation orientation = axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL ? Qt::Horizontal
343 QWindowSystemInterface::handleWheelEvent(window->window(),
345 inputDevice->mSurfacePos,
346 inputDevice->mGlobalPos,
347 int(wl_fixed_to_double(value) * 120.0),
351 #ifndef QT_NO_WAYLAND_XKB
353 static Qt::KeyboardModifiers translateModifiers(xkb_state *state)
355 Qt::KeyboardModifiers ret = Qt::NoModifier;
356 xkb_state_component cstate = xkb_state_component(XKB_STATE_DEPRESSED | XKB_STATE_LATCHED);
358 if (xkb_state_mod_name_is_active(state, "Shift", cstate))
359 ret |= Qt::ShiftModifier;
360 if (xkb_state_mod_name_is_active(state, "Control", cstate))
361 ret |= Qt::ControlModifier;
362 if (xkb_state_mod_name_is_active(state, "Alt", cstate))
363 ret |= Qt::AltModifier;
364 if (xkb_state_mod_name_is_active(state, "Mod1", cstate))
365 ret |= Qt::AltModifier;
366 if (xkb_state_mod_name_is_active(state, "Mod4", cstate))
367 ret |= Qt::MetaModifier;
372 static const uint32_t KeyTbl[] = {
373 XK_Escape, Qt::Key_Escape,
375 XK_ISO_Left_Tab, Qt::Key_Backtab,
376 XK_BackSpace, Qt::Key_Backspace,
377 XK_Return, Qt::Key_Return,
378 XK_Insert, Qt::Key_Insert,
379 XK_Delete, Qt::Key_Delete,
380 XK_Clear, Qt::Key_Delete,
381 XK_Pause, Qt::Key_Pause,
382 XK_Print, Qt::Key_Print,
384 XK_Home, Qt::Key_Home,
386 XK_Left, Qt::Key_Left,
388 XK_Right, Qt::Key_Right,
389 XK_Down, Qt::Key_Down,
390 XK_Prior, Qt::Key_PageUp,
391 XK_Next, Qt::Key_PageDown,
393 XK_Shift_L, Qt::Key_Shift,
394 XK_Shift_R, Qt::Key_Shift,
395 XK_Shift_Lock, Qt::Key_Shift,
396 XK_Control_L, Qt::Key_Control,
397 XK_Control_R, Qt::Key_Control,
398 XK_Meta_L, Qt::Key_Meta,
399 XK_Meta_R, Qt::Key_Meta,
400 XK_Alt_L, Qt::Key_Alt,
401 XK_Alt_R, Qt::Key_Alt,
402 XK_Caps_Lock, Qt::Key_CapsLock,
403 XK_Num_Lock, Qt::Key_NumLock,
404 XK_Scroll_Lock, Qt::Key_ScrollLock,
405 XK_Super_L, Qt::Key_Super_L,
406 XK_Super_R, Qt::Key_Super_R,
407 XK_Menu, Qt::Key_Menu,
408 XK_Hyper_L, Qt::Key_Hyper_L,
409 XK_Hyper_R, Qt::Key_Hyper_R,
410 XK_Help, Qt::Key_Help,
412 XK_KP_Space, Qt::Key_Space,
413 XK_KP_Tab, Qt::Key_Tab,
414 XK_KP_Enter, Qt::Key_Enter,
415 XK_KP_Home, Qt::Key_Home,
416 XK_KP_Left, Qt::Key_Left,
417 XK_KP_Up, Qt::Key_Up,
418 XK_KP_Right, Qt::Key_Right,
419 XK_KP_Down, Qt::Key_Down,
420 XK_KP_Prior, Qt::Key_PageUp,
421 XK_KP_Next, Qt::Key_PageDown,
422 XK_KP_End, Qt::Key_End,
423 XK_KP_Begin, Qt::Key_Clear,
424 XK_KP_Insert, Qt::Key_Insert,
425 XK_KP_Delete, Qt::Key_Delete,
426 XK_KP_Equal, Qt::Key_Equal,
427 XK_KP_Multiply, Qt::Key_Asterisk,
428 XK_KP_Add, Qt::Key_Plus,
429 XK_KP_Separator, Qt::Key_Comma,
430 XK_KP_Subtract, Qt::Key_Minus,
431 XK_KP_Decimal, Qt::Key_Period,
432 XK_KP_Divide, Qt::Key_Slash,
434 XK_ISO_Level3_Shift, Qt::Key_AltGr,
435 XK_Multi_key, Qt::Key_Multi_key,
436 XK_Codeinput, Qt::Key_Codeinput,
437 XK_SingleCandidate, Qt::Key_SingleCandidate,
438 XK_MultipleCandidate, Qt::Key_MultipleCandidate,
439 XK_PreviousCandidate, Qt::Key_PreviousCandidate,
441 XK_Mode_switch, Qt::Key_Mode_switch,
442 XK_script_switch, Qt::Key_Mode_switch,
447 static uint32_t translateKey(uint32_t sym, char *string, size_t size)
453 for (int i = 0; KeyTbl[i]; i += 2) {
454 if (sym == KeyTbl[i]) {
455 code = KeyTbl[i + 1];
467 #endif // QT_NO_WAYLAND_XKB
469 void QWaylandInputDevice::keyboard_keymap(void *data,
470 struct wl_keyboard *keyboard,
482 void QWaylandInputDevice::keyboard_enter(void *data,
483 struct wl_keyboard *keyboard,
485 struct wl_surface *surface,
486 struct wl_array *keys)
495 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
496 QWaylandWindow *window = (QWaylandWindow *) wl_surface_get_user_data(surface);
497 inputDevice->mKeyboardFocus = window;
498 inputDevice->mQDisplay->setLastKeyboardFocusInputDevice(inputDevice);
499 QWindowSystemInterface::handleWindowActivated(window->window());
502 void QWaylandInputDevice::keyboard_leave(void *data,
503 struct wl_keyboard *keyboard,
505 struct wl_surface *surface)
511 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
512 inputDevice->mKeyboardFocus = NULL;
513 inputDevice->mQDisplay->setLastKeyboardFocusInputDevice(0);
514 QWindowSystemInterface::handleWindowActivated(0);
517 void QWaylandInputDevice::keyboard_key(void *data,
518 struct wl_keyboard *keyboard,
519 uint32_t serial, uint32_t time,
520 uint32_t key, uint32_t state)
524 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
525 QWaylandWindow *window = inputDevice->mKeyboardFocus;
526 #ifndef QT_NO_WAYLAND_XKB
527 if (!inputDevice->mXkbMap)
530 uint32_t code = key + 8;
531 bool isDown = state != 0;
532 const xkb_keysym_t *syms;
533 uint32_t numSyms = xkb_key_get_syms(inputDevice->mXkbState, code, &syms);
534 xkb_state_update_key(inputDevice->mXkbState, code,
535 isDown ? XKB_KEY_DOWN : XKB_KEY_UP);
538 // We destroyed the keyboard focus surface, but the server
539 // didn't get the message yet.
544 xkb_keysym_t sym = syms[0];
545 Qt::KeyboardModifiers modifiers = translateModifiers(inputDevice->mXkbState);
546 QEvent::Type type = isDown ? QEvent::KeyPress : QEvent::KeyRelease;
549 sym = translateKey(sym, s, sizeof s);
552 QWindowSystemInterface::handleExtendedKeyEvent(window->window(),
556 QString::fromLatin1(s));
559 // Generic fallback for single hard keys: Assume 'key' is a Qt key code.
561 QWindowSystemInterface::handleExtendedKeyEvent(window->window(),
562 time, state ? QEvent::KeyPress : QEvent::KeyRelease,
563 key + 8, // qt-compositor substracts 8 for some reason
570 void QWaylandInputDevice::keyboard_modifiers(void *data,
571 struct wl_keyboard *keyboard,
573 uint32_t mods_depressed,
574 uint32_t mods_latched,
575 uint32_t mods_locked,
580 #ifndef QT_NO_WAYLAND_XKB
581 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
582 if (inputDevice->mXkbState)
583 xkb_state_update_mask(inputDevice->mXkbState,
584 mods_depressed, mods_latched, mods_locked,
588 Q_UNUSED(mods_depressed);
589 Q_UNUSED(mods_latched);
590 Q_UNUSED(mods_locked);
595 void QWaylandInputDevice::touch_down(void *data,
596 struct wl_touch *touch,
599 struct wl_surface *surface,
607 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
608 inputDevice->mTouchFocus = static_cast<QWaylandWindow *>(wl_surface_get_user_data(surface));
609 inputDevice->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointPressed);
612 void QWaylandInputDevice::touch_up(void *data,
613 struct wl_touch *touch,
621 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
622 inputDevice->mTouchFocus = 0;
623 inputDevice->handleTouchPoint(id, 0, 0, Qt::TouchPointReleased);
626 void QWaylandInputDevice::touch_motion(void *data,
627 struct wl_touch *touch,
635 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
636 inputDevice->handleTouchPoint(id, wl_fixed_to_double(x), wl_fixed_to_double(y), Qt::TouchPointMoved);
639 void QWaylandInputDevice::touch_frame(void *data, struct wl_touch *touch)
642 QWaylandInputDevice *inputDevice = (QWaylandInputDevice *) data;
643 inputDevice->handleTouchFrame();
646 void QWaylandInputDevice::touch_cancel(void *data, struct wl_touch *touch)
649 QWaylandInputDevice *self = static_cast<QWaylandInputDevice *>(data);
651 self->mPrevTouchPoints.clear();
652 self->mTouchPoints.clear();
654 QWaylandTouchExtension *touchExt = self->mQDisplay->touchExtension();
656 touchExt->touchCanceled();
658 QWindowSystemInterface::handleTouchCancelEvent(0, self->mTouchDevice);
661 void QWaylandInputDevice::handleTouchPoint(int id, double x, double y, Qt::TouchPointState state)
663 QWindowSystemInterface::TouchPoint tp;
665 // Find out the coordinates for Released events.
666 bool coordsOk = false;
667 if (state == Qt::TouchPointReleased)
668 for (int i = 0; i < mPrevTouchPoints.count(); ++i)
669 if (mPrevTouchPoints.at(i).id == id) {
670 tp.area = mPrevTouchPoints.at(i).area;
676 // x and y are surface relative.
677 // We need a global (screen) position.
678 QWaylandWindow *win = mTouchFocus;
680 //is it possible that mTouchFocus is null;
684 win = mKeyboardFocus;
685 if (!win || !win->window())
688 tp.area = QRectF(0, 0, 8, 8);
689 QMargins margins = win->frameMargins();
690 tp.area.moveCenter(win->window()->mapToGlobal(QPoint(x+margins.left(), y+margins.top())));
695 tp.pressure = tp.state == Qt::TouchPointReleased ? 0 : 1;
696 mTouchPoints.append(tp);
699 void QWaylandInputDevice::handleTouchFrame()
701 // Copy all points, that are in the previous but not in the current list, as stationary.
702 for (int i = 0; i < mPrevTouchPoints.count(); ++i) {
703 const QWindowSystemInterface::TouchPoint &prevPoint(mPrevTouchPoints.at(i));
704 if (prevPoint.state == Qt::TouchPointReleased)
707 for (int j = 0; j < mTouchPoints.count(); ++j)
708 if (mTouchPoints.at(j).id == prevPoint.id) {
713 QWindowSystemInterface::TouchPoint p = prevPoint;
714 p.state = Qt::TouchPointStationary;
715 mTouchPoints.append(p);
719 if (mTouchPoints.isEmpty()) {
720 mPrevTouchPoints.clear();
724 QWindowSystemInterface::handleTouchEvent(0, mTouchDevice, mTouchPoints);
726 bool allReleased = true;
727 for (int i = 0; i < mTouchPoints.count(); ++i)
728 if (mTouchPoints.at(i).state != Qt::TouchPointReleased) {
733 mPrevTouchPoints = mTouchPoints;
734 mTouchPoints.clear();
737 QWindowSystemInterface::handleTouchEvent(0, mTouchDevice, mTouchPoints);
738 mPrevTouchPoints.clear();