mutter/src/backends/x11/meta-virtual-input-device-x11.c
Pascal Nowack 72cfe9b3fd backends/x11: Interpret keycode correctly
Currently, when a remote desktop user submits a keycode, it will be
interpreted differently, when using the x11 session, instead of a
wayland session.
In a wayland session, submitting a keycode will have the expected
result (as if the key was pressed locally).
In a x11 session, this is not the case. Instead of getting the expected
key, some other key will be pressed (or sometimes even none).
The reason for this is that the native backend interprets the keycode
as evdev keycode and the x11 backend interprets the keycode as xkb
keycode.

To ensure that both backends produce the same behaviour when submitting
a keycode, fix the x11 backend to always interpret the keycode as evdev
keycode, instead of a xkb keycode.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1732>
2021-02-23 08:18:05 +00:00

254 lines
10 KiB
C

/*
* Copyright (C) 2016 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author: Jonas Ådahl <jadahl@gmail.com>
*/
#include "config.h"
#include <glib-object.h>
#include <X11/extensions/XTest.h>
#include "clutter/clutter.h"
#include "clutter/x11/clutter-x11.h"
#include "meta-keymap-x11.h"
#include "meta-virtual-input-device-x11.h"
#define DISCRETE_SCROLL_STEP 10.0
struct _MetaVirtualInputDeviceX11
{
ClutterVirtualInputDevice parent;
double accum_scroll_dx;
double accum_scroll_dy;
};
G_DEFINE_TYPE (MetaVirtualInputDeviceX11,
meta_virtual_input_device_x11,
CLUTTER_TYPE_VIRTUAL_INPUT_DEVICE)
static void
meta_virtual_input_device_x11_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy)
{
XTestFakeRelativeMotionEvent (clutter_x11_get_default_display (),
(int) dx,
(int) dy,
0);
}
static void
meta_virtual_input_device_x11_notify_absolute_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double x,
double y)
{
XTestFakeMotionEvent (clutter_x11_get_default_display (),
clutter_x11_get_default_screen (),
(int) x,
(int) y,
0);
}
static void
meta_virtual_input_device_x11_notify_button (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t button,
ClutterButtonState button_state)
{
XTestFakeButtonEvent (clutter_x11_get_default_display (),
button, button_state == CLUTTER_BUTTON_STATE_PRESSED, 0);
}
static void
meta_virtual_input_device_x11_notify_discrete_scroll (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
ClutterScrollDirection direction,
ClutterScrollSource scroll_source)
{
Display *xdisplay = clutter_x11_get_default_display ();
int button;
switch (direction)
{
case CLUTTER_SCROLL_UP:
button = 4;
break;
case CLUTTER_SCROLL_DOWN:
button = 5;
break;
case CLUTTER_SCROLL_LEFT:
button = 6;
break;
case CLUTTER_SCROLL_RIGHT:
button = 7;
break;
default:
g_warn_if_reached ();
return;
}
XTestFakeButtonEvent (xdisplay, button, True, 0);
XTestFakeButtonEvent (xdisplay, button, False, 0);
}
static void
meta_virtual_input_device_x11_notify_scroll_continuous (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy,
ClutterScrollSource scroll_source,
ClutterScrollFinishFlags finish_flags)
{
MetaVirtualInputDeviceX11 *virtual_device_x11;
ClutterScrollDirection direction;
int i, n_xscrolls, n_yscrolls;
virtual_device_x11 = META_VIRTUAL_INPUT_DEVICE_X11 (virtual_device);
virtual_device_x11->accum_scroll_dx += dx;
virtual_device_x11->accum_scroll_dy += dy;
n_xscrolls = floor ((fabs (virtual_device_x11->accum_scroll_dx) + DBL_EPSILON) /
DISCRETE_SCROLL_STEP);
n_yscrolls = floor ((fabs (virtual_device_x11->accum_scroll_dy) + DBL_EPSILON) /
DISCRETE_SCROLL_STEP);
direction = virtual_device_x11->accum_scroll_dx > 0 ? CLUTTER_SCROLL_RIGHT
: CLUTTER_SCROLL_LEFT;
for (i = 0; i < n_xscrolls; ++i)
{
meta_virtual_input_device_x11_notify_discrete_scroll (
virtual_device, time_us, direction, CLUTTER_SCROLL_SOURCE_WHEEL);
}
direction = virtual_device_x11->accum_scroll_dy > 0 ? CLUTTER_SCROLL_DOWN
: CLUTTER_SCROLL_UP;
for (i = 0; i < n_yscrolls; ++i)
{
meta_virtual_input_device_x11_notify_discrete_scroll (
virtual_device, time_us, direction, CLUTTER_SCROLL_SOURCE_WHEEL);
}
virtual_device_x11->accum_scroll_dx =
fmod (virtual_device_x11->accum_scroll_dx, DISCRETE_SCROLL_STEP);
virtual_device_x11->accum_scroll_dy =
fmod (virtual_device_x11->accum_scroll_dy, DISCRETE_SCROLL_STEP);
}
static void
meta_virtual_input_device_x11_notify_key (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t key,
ClutterKeyState key_state)
{
XTestFakeKeyEvent (clutter_x11_get_default_display (),
key + 8, key_state == CLUTTER_KEY_STATE_PRESSED, 0);
}
static void
meta_virtual_input_device_x11_notify_keyval (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
uint32_t keyval,
ClutterKeyState key_state)
{
ClutterBackend *backend = clutter_get_default_backend ();
ClutterSeat *seat = clutter_backend_get_default_seat (backend);
MetaKeymapX11 *keymap = META_KEYMAP_X11 (clutter_seat_get_keymap (seat));
uint32_t keycode, level;
if (!meta_keymap_x11_keycode_for_keyval (keymap, keyval, &keycode, &level))
{
level = 0;
if (!meta_keymap_x11_reserve_keycode (keymap, keyval, &keycode))
{
g_warning ("No keycode found for keyval %x in current group", keyval);
return;
}
}
if (!meta_keymap_x11_get_is_modifier (keymap, keycode) &&
key_state == CLUTTER_KEY_STATE_PRESSED)
meta_keymap_x11_latch_modifiers (keymap, level, TRUE);
XTestFakeKeyEvent (clutter_x11_get_default_display (),
(KeyCode) keycode,
key_state == CLUTTER_KEY_STATE_PRESSED, 0);
if (key_state == CLUTTER_KEY_STATE_RELEASED)
{
if (!meta_keymap_x11_get_is_modifier (keymap, keycode))
meta_keymap_x11_latch_modifiers (keymap, level, FALSE);
meta_keymap_x11_release_keycode_if_needed (keymap, keycode);
}
}
static void
meta_virtual_input_device_x11_notify_touch_down (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
int device_slot,
double x,
double y)
{
g_warning ("Virtual touch motion not implemented under X11");
}
static void
meta_virtual_input_device_x11_notify_touch_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
int device_slot,
double x,
double y)
{
g_warning ("Virtual touch motion not implemented under X11");
}
static void
meta_virtual_input_device_x11_notify_touch_up (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
int device_slot)
{
g_warning ("Virtual touch motion not implemented under X11");
}
static void
meta_virtual_input_device_x11_init (MetaVirtualInputDeviceX11 *virtual_device_x11)
{
}
static void
meta_virtual_input_device_x11_class_init (MetaVirtualInputDeviceX11Class *klass)
{
ClutterVirtualInputDeviceClass *virtual_input_device_class =
CLUTTER_VIRTUAL_INPUT_DEVICE_CLASS (klass);
virtual_input_device_class->notify_relative_motion = meta_virtual_input_device_x11_notify_relative_motion;
virtual_input_device_class->notify_absolute_motion = meta_virtual_input_device_x11_notify_absolute_motion;
virtual_input_device_class->notify_button = meta_virtual_input_device_x11_notify_button;
virtual_input_device_class->notify_discrete_scroll = meta_virtual_input_device_x11_notify_discrete_scroll;
virtual_input_device_class->notify_scroll_continuous = meta_virtual_input_device_x11_notify_scroll_continuous;
virtual_input_device_class->notify_key = meta_virtual_input_device_x11_notify_key;
virtual_input_device_class->notify_keyval = meta_virtual_input_device_x11_notify_keyval;
virtual_input_device_class->notify_touch_down = meta_virtual_input_device_x11_notify_touch_down;
virtual_input_device_class->notify_touch_motion = meta_virtual_input_device_x11_notify_touch_motion;
virtual_input_device_class->notify_touch_up = meta_virtual_input_device_x11_notify_touch_up;
}