mirror of
https://github.com/brl/mutter.git
synced 2024-12-12 14:20:17 +00:00
6060b6a240
Certains keys (such as ~ and |) are in the keyboard map behind the second shift level. This means in order for them to be input, the shift key needs to be held down by the user. The GNOME Shell on-screen keyboard presents these keys separately on a page of keys that has no shift key. Instead, it relies on mutter to set a shift latch before the key event is emitted. A shift latch is a virtual press of the shift key that automatically gets released after the next key press (in our case the ~ or | key). The problem is using a shift latch doesn't work very well in the face of key repeat. The latch is automatically released after the first press, and subsequent repeats of that press no longer have shift latched to them. This commit fixes the problem by using a shift lock instead of a shift latch. A shift lock is never implicitly released, so it remains in place for the duration of key repeat. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2045>
254 lines
10 KiB
C
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 "backends/x11/meta-clutter-backend-x11.h"
|
|
#include "clutter/clutter.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 (meta_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 (meta_clutter_x11_get_default_display (),
|
|
meta_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 (meta_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 = meta_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 (meta_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_lock_modifiers (keymap, level, TRUE);
|
|
|
|
XTestFakeKeyEvent (meta_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_lock_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;
|
|
}
|