Implement keyboard grabbing for Wayland
This commit is contained in:
@@ -453,6 +453,7 @@ if (UNIX AND NOT APPLE AND NOT HAIKU)
|
|||||||
set(WL_SOURCE_VAR)
|
set(WL_SOURCE_VAR)
|
||||||
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/relative-pointer-unstable-v1.xml BASENAME relative-pointer-unstable-v1)
|
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/relative-pointer-unstable-v1.xml BASENAME relative-pointer-unstable-v1)
|
||||||
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1)
|
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1)
|
||||||
|
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml BASENAME keyboard-shortcuts-inhibit-unstable-v1)
|
||||||
target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
|
target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
|
||||||
target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp)
|
target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp)
|
||||||
if (XKBCOMMON_FOUND)
|
if (XKBCOMMON_FOUND)
|
||||||
|
|||||||
@@ -672,6 +672,16 @@ main(int argc, char *argv[])
|
|||||||
} else {
|
} else {
|
||||||
main_window->show();
|
main_window->show();
|
||||||
}
|
}
|
||||||
|
#ifdef __unix__
|
||||||
|
if (QApplication::platformName().contains("wayland")) {
|
||||||
|
/* Force a sync. */
|
||||||
|
(void)main_window->winId();
|
||||||
|
QApplication::sync();
|
||||||
|
extern void wl_keyboard_grab(QWindow *window);
|
||||||
|
wl_keyboard_grab(main_window->windowHandle());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
app.installEventFilter(main_window);
|
app.installEventFilter(main_window);
|
||||||
|
|
||||||
|
|||||||
@@ -322,7 +322,8 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
if (ui->stackedWidget->mouse_capture_func)
|
if (ui->stackedWidget->mouse_capture_func)
|
||||||
ui->stackedWidget->mouse_capture_func(this->windowHandle());
|
ui->stackedWidget->mouse_capture_func(this->windowHandle());
|
||||||
} else {
|
} else {
|
||||||
this->releaseKeyboard();
|
if (!(windowState() & Qt::WindowActive))
|
||||||
|
this->releaseKeyboard();
|
||||||
if (ui->stackedWidget->mouse_uncapture_func) {
|
if (ui->stackedWidget->mouse_uncapture_func) {
|
||||||
ui->stackedWidget->mouse_uncapture_func();
|
ui->stackedWidget->mouse_uncapture_func();
|
||||||
}
|
}
|
||||||
@@ -1492,8 +1493,26 @@ MainWindow::eventFilter(QObject *receiver, QEvent *event)
|
|||||||
curdopause = dopause;
|
curdopause = dopause;
|
||||||
plat_pause(isShowMessage ? 2 : 1);
|
plat_pause(isShowMessage ? 2 : 1);
|
||||||
emit setMouseCapture(false);
|
emit setMouseCapture(false);
|
||||||
|
releaseKeyboard();
|
||||||
} else if (event->type() == QEvent::WindowUnblocked) {
|
} else if (event->type() == QEvent::WindowUnblocked) {
|
||||||
plat_pause(curdopause);
|
plat_pause(curdopause);
|
||||||
|
#ifdef __unix__
|
||||||
|
if (!QApplication::platformName().contains("wayland") && (this->windowState() & Qt::WindowActive)) {
|
||||||
|
this->grabKeyboard();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (event->type() == QEvent::WindowActivate) {
|
||||||
|
#ifdef __unix__
|
||||||
|
if (!QApplication::platformName().contains("wayland")) {
|
||||||
|
this->grabKeyboard();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (event->type() == QEvent::WindowDeactivate) {
|
||||||
|
#ifdef __unix__
|
||||||
|
if (!QApplication::platformName().contains("wayland")) {
|
||||||
|
this->releaseKeyboard();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1611,13 +1630,13 @@ MainWindow::getRenderWidgetSize()
|
|||||||
void
|
void
|
||||||
MainWindow::focusInEvent(QFocusEvent *event)
|
MainWindow::focusInEvent(QFocusEvent *event)
|
||||||
{
|
{
|
||||||
this->grabKeyboard();
|
//this->grabKeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::focusOutEvent(QFocusEvent *event)
|
MainWindow::focusOutEvent(QFocusEvent *event)
|
||||||
{
|
{
|
||||||
this->releaseKeyboard();
|
//this->releaseKeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <wayland-client-protocol.h>
|
#include <wayland-client-protocol.h>
|
||||||
#include <wayland-relative-pointer-unstable-v1-client-protocol.h>
|
#include <wayland-relative-pointer-unstable-v1-client-protocol.h>
|
||||||
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
||||||
|
#include <wayland-keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h>
|
||||||
|
|
||||||
#include <qpa/qplatformnativeinterface.h>
|
#include <qpa/qplatformnativeinterface.h>
|
||||||
#include <QWindow>
|
#include <QWindow>
|
||||||
@@ -30,10 +31,12 @@ extern "C" {
|
|||||||
#include <86box/plat.h>
|
#include <86box/plat.h>
|
||||||
}
|
}
|
||||||
|
|
||||||
static zwp_relative_pointer_manager_v1 *rel_manager = nullptr;
|
static zwp_relative_pointer_manager_v1 *rel_manager = nullptr;
|
||||||
static zwp_relative_pointer_v1 *rel_pointer = nullptr;
|
static zwp_relative_pointer_v1 *rel_pointer = nullptr;
|
||||||
static zwp_pointer_constraints_v1 *conf_pointer_interface = nullptr;
|
static zwp_pointer_constraints_v1 *conf_pointer_interface = nullptr;
|
||||||
static zwp_locked_pointer_v1 *conf_pointer = nullptr;
|
static zwp_locked_pointer_v1 *conf_pointer = nullptr;
|
||||||
|
static zwp_keyboard_shortcuts_inhibit_manager_v1 *kbd_manager = nullptr;
|
||||||
|
static zwp_keyboard_shortcuts_inhibitor_v1 *kbd_inhibitor = nullptr;
|
||||||
|
|
||||||
static bool wl_init_ok = false;
|
static bool wl_init_ok = false;
|
||||||
|
|
||||||
@@ -47,6 +50,12 @@ static struct zwp_relative_pointer_v1_listener rel_listener = {
|
|||||||
rel_mouse_event
|
rel_mouse_event
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct zwp_keyboard_shortcuts_inhibitor_v1_listener kbd_listener
|
||||||
|
{
|
||||||
|
[](void *data, struct zwp_keyboard_shortcuts_inhibitor_v1 *zwp_keyboard_shortcuts_inhibitor_v1) -> void {},
|
||||||
|
[](void *data, struct zwp_keyboard_shortcuts_inhibitor_v1 *zwp_keyboard_shortcuts_inhibitor_v1) -> void {}
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
|
display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
|
||||||
const char *interface, uint32_t version)
|
const char *interface, uint32_t version)
|
||||||
@@ -57,16 +66,25 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
|
|||||||
if (!strcmp(interface, "zwp_pointer_constraints_v1")) {
|
if (!strcmp(interface, "zwp_pointer_constraints_v1")) {
|
||||||
conf_pointer_interface = (zwp_pointer_constraints_v1 *) wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, version);
|
conf_pointer_interface = (zwp_pointer_constraints_v1 *) wl_registry_bind(registry, id, &zwp_pointer_constraints_v1_interface, version);
|
||||||
}
|
}
|
||||||
|
if (!strcmp(interface, "zwp_keyboard_shortcuts_inhibit_manager_v1")) {
|
||||||
|
kbd_manager = (zwp_keyboard_shortcuts_inhibit_manager_v1 *) wl_registry_bind(registry, id, &zwp_keyboard_shortcuts_inhibit_manager_v1_interface, version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
|
display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
|
||||||
{
|
{
|
||||||
plat_mouse_capture(0);
|
plat_mouse_capture(0);
|
||||||
|
if (kbd_inhibitor) {
|
||||||
|
zwp_keyboard_shortcuts_inhibitor_v1_destroy(kbd_inhibitor);
|
||||||
|
kbd_inhibitor = nullptr;
|
||||||
|
}
|
||||||
|
zwp_keyboard_shortcuts_inhibit_manager_v1_destroy(kbd_manager);
|
||||||
zwp_relative_pointer_manager_v1_destroy(rel_manager);
|
zwp_relative_pointer_manager_v1_destroy(rel_manager);
|
||||||
zwp_pointer_constraints_v1_destroy(conf_pointer_interface);
|
zwp_pointer_constraints_v1_destroy(conf_pointer_interface);
|
||||||
rel_manager = nullptr;
|
rel_manager = nullptr;
|
||||||
conf_pointer_interface = nullptr;
|
conf_pointer_interface = nullptr;
|
||||||
|
kbd_manager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct wl_registry_listener registry_listener = {
|
static const struct wl_registry_listener registry_listener = {
|
||||||
@@ -90,9 +108,20 @@ wl_init()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wl_keyboard_grab(QWindow *window)
|
||||||
|
{
|
||||||
|
if (!kbd_inhibitor && kbd_manager) {
|
||||||
|
kbd_inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(kbd_manager, (wl_surface *) QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window), (wl_seat *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_seat"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
wl_mouse_capture(QWindow *window)
|
wl_mouse_capture(QWindow *window)
|
||||||
{
|
{
|
||||||
|
if (!kbd_inhibitor) {
|
||||||
|
kbd_inhibitor = zwp_keyboard_shortcuts_inhibit_manager_v1_inhibit_shortcuts(kbd_manager, (wl_surface *) QGuiApplication::platformNativeInterface()->nativeResourceForWindow("surface", window), (wl_seat *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_seat"));
|
||||||
|
}
|
||||||
if (rel_manager) {
|
if (rel_manager) {
|
||||||
rel_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(rel_manager, (wl_pointer *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer"));
|
rel_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer(rel_manager, (wl_pointer *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_pointer"));
|
||||||
zwp_relative_pointer_v1_add_listener(rel_pointer, &rel_listener, nullptr);
|
zwp_relative_pointer_v1_add_listener(rel_pointer, &rel_listener, nullptr);
|
||||||
|
|||||||
143
wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml
Normal file
143
wl_protocols/keyboard-shortcuts-inhibit-unstable-v1.xml
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="keyboard_shortcuts_inhibit_unstable_v1">
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2017 Red Hat Inc.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="Protocol for inhibiting the compositor keyboard shortcuts">
|
||||||
|
This protocol specifies a way for a client to request the compositor
|
||||||
|
to ignore its own keyboard shortcuts for a given seat, so that all
|
||||||
|
key events from that seat get forwarded to a surface.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible
|
||||||
|
changes may be added together with the corresponding interface
|
||||||
|
version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version
|
||||||
|
number in the protocol and interface names and resetting the
|
||||||
|
interface version. Once the protocol is to be declared stable,
|
||||||
|
the 'z' prefix and the version number in the protocol and
|
||||||
|
interface names are removed and the interface version number is
|
||||||
|
reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwp_keyboard_shortcuts_inhibit_manager_v1" version="1">
|
||||||
|
<description summary="context object for keyboard grab_manager">
|
||||||
|
A global interface used for inhibiting the compositor keyboard shortcuts.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the keyboard shortcuts inhibitor object">
|
||||||
|
Destroy the keyboard shortcuts inhibitor manager.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="inhibit_shortcuts">
|
||||||
|
<description summary="create a new keyboard shortcuts inhibitor object">
|
||||||
|
Create a new keyboard shortcuts inhibitor object associated with
|
||||||
|
the given surface for the given seat.
|
||||||
|
|
||||||
|
If shortcuts are already inhibited for the specified seat and surface,
|
||||||
|
a protocol error "already_inhibited" is raised by the compositor.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_keyboard_shortcuts_inhibitor_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"
|
||||||
|
summary="the surface that inhibits the keyboard shortcuts behavior"/>
|
||||||
|
<arg name="seat" type="object" interface="wl_seat"
|
||||||
|
summary="the wl_seat for which keyboard shortcuts should be disabled"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="already_inhibited"
|
||||||
|
value="0"
|
||||||
|
summary="the shortcuts are already inhibited for this surface"/>
|
||||||
|
</enum>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_keyboard_shortcuts_inhibitor_v1" version="1">
|
||||||
|
<description summary="context object for keyboard shortcuts inhibitor">
|
||||||
|
A keyboard shortcuts inhibitor instructs the compositor to ignore
|
||||||
|
its own keyboard shortcuts when the associated surface has keyboard
|
||||||
|
focus. As a result, when the surface has keyboard focus on the given
|
||||||
|
seat, it will receive all key events originating from the specified
|
||||||
|
seat, even those which would normally be caught by the compositor for
|
||||||
|
its own shortcuts.
|
||||||
|
|
||||||
|
The Wayland compositor is however under no obligation to disable
|
||||||
|
all of its shortcuts, and may keep some special key combo for its own
|
||||||
|
use, including but not limited to one allowing the user to forcibly
|
||||||
|
restore normal keyboard events routing in the case of an unwilling
|
||||||
|
client. The compositor may also use the same key combo to reactivate
|
||||||
|
an existing shortcut inhibitor that was previously deactivated on
|
||||||
|
user request.
|
||||||
|
|
||||||
|
When the compositor restores its own keyboard shortcuts, an
|
||||||
|
"inactive" event is emitted to notify the client that the keyboard
|
||||||
|
shortcuts inhibitor is not effectively active for the surface and
|
||||||
|
seat any more, and the client should not expect to receive all
|
||||||
|
keyboard events.
|
||||||
|
|
||||||
|
When the keyboard shortcuts inhibitor is inactive, the client has
|
||||||
|
no way to forcibly reactivate the keyboard shortcuts inhibitor.
|
||||||
|
|
||||||
|
The user can chose to re-enable a previously deactivated keyboard
|
||||||
|
shortcuts inhibitor using any mechanism the compositor may offer,
|
||||||
|
in which case the compositor will send an "active" event to notify
|
||||||
|
the client.
|
||||||
|
|
||||||
|
If the surface is destroyed, unmapped, or loses the seat's keyboard
|
||||||
|
focus, the keyboard shortcuts inhibitor becomes irrelevant and the
|
||||||
|
compositor will restore its own keyboard shortcuts but no "inactive"
|
||||||
|
event is emitted in this case.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the keyboard shortcuts inhibitor object">
|
||||||
|
Remove the keyboard shortcuts inhibitor from the associated wl_surface.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="active">
|
||||||
|
<description summary="shortcuts are inhibited">
|
||||||
|
This event indicates that the shortcut inhibitor is active.
|
||||||
|
|
||||||
|
The compositor sends this event every time compositor shortcuts
|
||||||
|
are inhibited on behalf of the surface. When active, the client
|
||||||
|
may receive input events normally reserved by the compositor
|
||||||
|
(see zwp_keyboard_shortcuts_inhibitor_v1).
|
||||||
|
|
||||||
|
This occurs typically when the initial request "inhibit_shortcuts"
|
||||||
|
first becomes active or when the user instructs the compositor to
|
||||||
|
re-enable and existing shortcuts inhibitor using any mechanism
|
||||||
|
offered by the compositor.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="inactive">
|
||||||
|
<description summary="shortcuts are restored">
|
||||||
|
This event indicates that the shortcuts inhibitor is inactive,
|
||||||
|
normal shortcuts processing is restored by the compositor.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
Reference in New Issue
Block a user