mutter/src/backends/x11/meta-virtual-input-device-x11.c

277 lines
11 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 "backends/x11/meta-virtual-input-device-x11.h"
#include <glib-object.h>
#include <X11/extensions/XTest.h>
#include "backends/x11/meta-backend-x11.h"
#include "backends/x11/meta-clutter-backend-x11.h"
#include "backends/x11/meta-keymap-x11.h"
#include "backends/x11/meta-seat-x11.h"
#include "clutter/clutter.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 Display *
xdisplay_from_virtual_input_device (ClutterVirtualInputDevice *virtual_device)
{
ClutterSeat *seat = clutter_virtual_input_device_get_seat (virtual_device);
MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
MetaBackend *backend = meta_seat_x11_get_backend (seat_x11);
return meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
}
static void
meta_virtual_input_device_x11_notify_relative_motion (ClutterVirtualInputDevice *virtual_device,
uint64_t time_us,
double dx,
double dy)
{
Display *xdisplay = xdisplay_from_virtual_input_device (virtual_device);
XTestFakeRelativeMotionEvent (xdisplay, (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)
{
ClutterSeat *seat = clutter_virtual_input_device_get_seat (virtual_device);
MetaSeatX11 *seat_x11 = META_SEAT_X11 (seat);
MetaBackend *backend = meta_seat_x11_get_backend (seat_x11);
Display *xdisplay;
Screen *xscreen;
xdisplay = meta_backend_x11_get_xdisplay (META_BACKEND_X11 (backend));
xscreen = meta_backend_x11_get_xscreen (META_BACKEND_X11 (backend));
XTestFakeMotionEvent (xdisplay, XScreenNumberOfScreen (xscreen),
(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)
{
Display *xdisplay = xdisplay_from_virtual_input_device (virtual_device);
XTestFakeButtonEvent (xdisplay,
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 = xdisplay_from_virtual_input_device (virtual_device);
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)
{
Display *xdisplay = xdisplay_from_virtual_input_device (virtual_device);
XTestFakeKeyEvent (xdisplay,
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));
Display *xdisplay = xdisplay_from_virtual_input_device (virtual_device);
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 (xdisplay,
(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;
}