2001-04-15 04:18:22 +00:00
|
|
|
/*
|
|
|
|
in_x11.c
|
|
|
|
|
|
|
|
general x11 input driver
|
|
|
|
|
|
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
Copyright (C) 2000 Marcus Sundberg [mackan@stacken.kth.se]
|
|
|
|
Copyright (C) 1999,2000 contributors of the QuakeForge project
|
|
|
|
Please see the file "AUTHORS" for a list of contributors
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License
|
|
|
|
as published by the Free Software Foundation; either version 2
|
|
|
|
of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This program 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 General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to:
|
|
|
|
|
|
|
|
Free Software Foundation, Inc.
|
|
|
|
59 Temple Place - Suite 330
|
|
|
|
Boston, MA 02111-1307, USA
|
|
|
|
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
2003-01-15 15:31:36 +00:00
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
# include <string.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_STRINGS_H
|
|
|
|
# include <strings.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define _BSD
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <errno.h>
|
2001-08-27 01:00:03 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2001-04-15 04:18:22 +00:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/keysym.h>
|
2011-12-19 07:37:48 +00:00
|
|
|
#include <X11/XF86keysym.h>
|
2021-11-18 04:01:33 +00:00
|
|
|
#include <X11/XKBlib.h>
|
2011-12-19 07:37:48 +00:00
|
|
|
#include <X11/Sunkeysym.h>
|
2001-09-18 04:53:01 +00:00
|
|
|
#include <X11/Xutil.h>
|
2002-01-08 19:33:42 +00:00
|
|
|
#include <X11/Xatom.h>
|
2001-04-15 04:18:22 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_DGA
|
2010-08-05 02:35:16 +00:00
|
|
|
# ifdef DGA_OLD_HEADERS
|
|
|
|
# include <X11/extensions/xf86dga.h>
|
|
|
|
# else
|
|
|
|
# include <X11/extensions/Xxf86dga.h>
|
2021-11-21 14:01:12 +00:00
|
|
|
# endif
|
2010-08-05 02:35:16 +00:00
|
|
|
#endif
|
2021-11-21 14:01:12 +00:00
|
|
|
#ifdef HAVE_XI2
|
|
|
|
# include <X11/extensions/XInput2.h>
|
2001-04-15 04:18:22 +00:00
|
|
|
#endif
|
2021-11-22 04:16:05 +00:00
|
|
|
#ifdef HAVE_XFIXES
|
|
|
|
# include <X11/extensions/Xfixes.h>
|
|
|
|
#endif
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2001-07-05 20:35:42 +00:00
|
|
|
#include "QF/cdaudio.h"
|
2001-04-15 04:18:22 +00:00
|
|
|
#include "QF/cmd.h"
|
|
|
|
#include "QF/cvar.h"
|
|
|
|
#include "QF/input.h"
|
|
|
|
#include "QF/joystick.h"
|
|
|
|
#include "QF/keys.h"
|
2001-04-15 07:18:04 +00:00
|
|
|
#include "QF/mathlib.h"
|
2001-04-15 04:18:22 +00:00
|
|
|
#include "QF/qargs.h"
|
2001-07-05 20:18:23 +00:00
|
|
|
#include "QF/sound.h"
|
2001-04-15 04:18:22 +00:00
|
|
|
#include "QF/sys.h"
|
|
|
|
|
2021-11-03 13:20:17 +00:00
|
|
|
#include "QF/input/event.h"
|
|
|
|
|
2001-07-05 20:18:23 +00:00
|
|
|
#include "compat.h"
|
2001-04-15 07:18:04 +00:00
|
|
|
#include "context_x11.h"
|
|
|
|
#include "dga_check.h"
|
2021-11-21 12:22:11 +00:00
|
|
|
#include "in_x11.h"
|
2021-09-28 01:53:51 +00:00
|
|
|
#include "qfselect.h"
|
2012-02-17 07:13:56 +00:00
|
|
|
#include "vid_internal.h"
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2021-11-03 13:20:17 +00:00
|
|
|
typedef struct x11_device_s {
|
|
|
|
const char *name;
|
|
|
|
int num_axes;
|
|
|
|
int num_buttons;
|
|
|
|
in_axisinfo_t *axes;
|
|
|
|
in_buttoninfo_t *buttons;
|
2021-11-09 13:31:09 +00:00
|
|
|
void *event_data;
|
2021-11-03 13:20:17 +00:00
|
|
|
int devid;
|
|
|
|
} x11_device_t;
|
|
|
|
|
2021-11-21 13:16:08 +00:00
|
|
|
#define X11_MOUSE_BUTTONS 32
|
2021-11-23 14:15:08 +00:00
|
|
|
#define X11_MOUSE_AXES 2
|
2021-11-03 13:20:17 +00:00
|
|
|
// The X11 protocol supports only 256 keys
|
|
|
|
static in_buttoninfo_t x11_key_buttons[256];
|
2021-11-23 14:15:08 +00:00
|
|
|
// X11 mice have only two axes (FIXME NOT always true (XInput says otherwise!)
|
|
|
|
static in_axisinfo_t x11_mouse_axes[X11_MOUSE_AXES];
|
2021-11-21 13:16:08 +00:00
|
|
|
// FIXME assume up to 32 mouse buttons (see X11_MOUSE_BUTTONS)
|
|
|
|
static in_buttoninfo_t x11_mouse_buttons[X11_MOUSE_BUTTONS];
|
2021-11-18 04:01:33 +00:00
|
|
|
static const char *x11_mouse_axis_names[] = {"M_X", "M_Y"};
|
|
|
|
static const char *x11_mouse_button_names[] = {
|
|
|
|
"M_BUTTON1", "M_BUTTON2", "M_BUTTON3", "M_WHEEL_UP",
|
|
|
|
"M_WHEEL_DOWN", "M_BUTTON6", "M_BUTTON7", "M_BUTTON8",
|
|
|
|
"M_BUTTON9", "M_BUTTON10", "M_BUTTON11", "M_BUTTON12",
|
|
|
|
"M_BUTTON13", "M_BUTTON14", "M_BUTTON15", "M_BUTTON16",
|
|
|
|
"M_BUTTON17", "M_BUTTON18", "M_BUTTON19", "M_BUTTON20",
|
|
|
|
"M_BUTTON21", "M_BUTTON22", "M_BUTTON23", "M_BUTTON24",
|
|
|
|
"M_BUTTON25", "M_BUTTON26", "M_BUTTON27", "M_BUTTON28",
|
|
|
|
"M_BUTTON29", "M_BUTTON30", "M_BUTTON31", "M_BUTTON32",
|
|
|
|
};
|
2021-11-03 13:20:17 +00:00
|
|
|
|
2021-11-18 04:01:33 +00:00
|
|
|
#define SIZE(x) (sizeof (x) / sizeof (x[0]))
|
2021-11-03 13:20:17 +00:00
|
|
|
|
|
|
|
static x11_device_t x11_keyboard_device = {
|
2021-11-05 01:02:21 +00:00
|
|
|
"core:keyboard",
|
2021-11-18 04:01:33 +00:00
|
|
|
0, SIZE (x11_key_buttons),
|
2021-11-03 13:20:17 +00:00
|
|
|
0, x11_key_buttons,
|
|
|
|
};
|
|
|
|
|
|
|
|
static x11_device_t x11_mouse_device = {
|
2021-11-05 01:02:21 +00:00
|
|
|
"core:mouse",
|
2021-11-18 04:01:33 +00:00
|
|
|
SIZE (x11_mouse_axes), SIZE (x11_mouse_buttons),
|
2021-11-03 13:20:17 +00:00
|
|
|
x11_mouse_axes, x11_mouse_buttons,
|
|
|
|
};
|
|
|
|
|
2021-11-21 14:37:42 +00:00
|
|
|
cvar_t *in_auto_focus;
|
2021-11-21 14:23:16 +00:00
|
|
|
cvar_t *in_snd_block;
|
|
|
|
cvar_t *in_dga;
|
|
|
|
cvar_t *in_mouse_accel;
|
2001-04-15 04:18:22 +00:00
|
|
|
|
|
|
|
static qboolean dga_avail;
|
|
|
|
static qboolean dga_active;
|
2021-11-05 04:26:44 +00:00
|
|
|
static IE_mouse_event_t x11_mouse;
|
|
|
|
static IE_key_event_t x11_key;
|
2010-11-27 00:25:29 +00:00
|
|
|
static int input_grabbed = 0;
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2021-11-21 14:01:12 +00:00
|
|
|
static int xi_opcode;
|
2021-11-22 04:16:05 +00:00
|
|
|
static int xf_opcode;
|
|
|
|
static PointerBarrier x11_left_barrier;
|
|
|
|
static PointerBarrier x11_right_barrier;
|
|
|
|
static PointerBarrier x11_top_barrier;
|
|
|
|
static PointerBarrier x11_bottom_barrier;
|
2021-11-21 14:01:12 +00:00
|
|
|
static int x11_have_xi;
|
2021-09-27 02:24:35 +00:00
|
|
|
static int x11_fd;
|
2021-11-03 13:20:17 +00:00
|
|
|
static int x11_driver_handle = -1;
|
2021-11-22 04:16:05 +00:00
|
|
|
static int x11_event_handler_id;
|
|
|
|
static qboolean x11_have_pointer;
|
2021-09-27 02:24:35 +00:00
|
|
|
|
2001-08-30 20:04:13 +00:00
|
|
|
static void
|
|
|
|
dga_on (void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_DGA
|
|
|
|
if (dga_avail && !dga_active) {
|
2010-11-27 00:25:29 +00:00
|
|
|
int ret;
|
|
|
|
ret = XF86DGADirectVideo (x_disp, DefaultScreen (x_disp),
|
2021-11-21 14:23:16 +00:00
|
|
|
XF86DGADirectMouse);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid, "XF86DGADirectVideo returned %d\n", ret);
|
2010-11-27 00:25:29 +00:00
|
|
|
if (ret)
|
|
|
|
dga_active = true;
|
2001-08-30 20:04:13 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dga_off (void)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_DGA
|
|
|
|
if (dga_avail && dga_active) {
|
2010-11-27 00:25:29 +00:00
|
|
|
int ret;
|
|
|
|
ret = XF86DGADirectVideo (x_disp, DefaultScreen (x_disp), 0);
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid, "XF86DGADirectVideo returned %d\n", ret);
|
2010-11-27 00:25:29 +00:00
|
|
|
if (ret)
|
|
|
|
dga_active = false;
|
2001-08-30 20:04:13 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_dga_f (cvar_t *var)
|
|
|
|
{
|
2010-11-27 00:25:29 +00:00
|
|
|
if (var->int_val && input_grabbed) {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid, "VID: in_dga_f on\n");
|
2010-11-27 00:25:29 +00:00
|
|
|
dga_on ();
|
|
|
|
} else {
|
2021-03-29 10:58:00 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid, "VID: in_dga_f off\n");
|
2010-11-27 00:25:29 +00:00
|
|
|
dga_off ();
|
2001-08-30 20:04:13 +00:00
|
|
|
}
|
|
|
|
}
|
2001-08-27 01:00:03 +00:00
|
|
|
|
2003-09-04 22:29:40 +00:00
|
|
|
static void
|
|
|
|
in_mouse_accel_f (cvar_t *var)
|
|
|
|
{
|
|
|
|
if (var->int_val) {
|
|
|
|
X11_RestoreMouseAcceleration ();
|
|
|
|
} else {
|
|
|
|
X11_SaveMouseAcceleration ();
|
|
|
|
X11_RemoveMouseAcceleration ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-30 18:20:56 +00:00
|
|
|
static void
|
|
|
|
in_paste_buffer_f (void)
|
|
|
|
{
|
2002-01-08 19:33:42 +00:00
|
|
|
Atom property;
|
|
|
|
|
|
|
|
if (XGetSelectionOwner (x_disp, XA_PRIMARY) == None)
|
2001-10-30 18:20:56 +00:00
|
|
|
return;
|
2002-01-08 19:33:42 +00:00
|
|
|
property = XInternAtom (x_disp, "GETCLIPBOARDDATA_PROP", False);
|
2002-01-08 20:07:19 +00:00
|
|
|
XConvertSelection (x_disp, XA_PRIMARY, XA_STRING, property, x_win, x_time);
|
2002-01-08 19:33:42 +00:00
|
|
|
XFlush (x_disp);
|
|
|
|
}
|
|
|
|
|
2003-02-25 17:19:47 +00:00
|
|
|
static void
|
|
|
|
enter_notify (XEvent *event)
|
|
|
|
{
|
2021-11-22 04:16:05 +00:00
|
|
|
x11_have_pointer = true;
|
2003-02-25 17:19:47 +00:00
|
|
|
x_time = event->xcrossing.time;
|
|
|
|
|
2021-11-05 04:26:44 +00:00
|
|
|
x11_mouse.x = event->xmotion.x;
|
|
|
|
x11_mouse.y = event->xmotion.y;
|
2021-11-21 14:37:42 +00:00
|
|
|
if (!x_have_focus && (!in_auto_focus || in_auto_focus->int_val)) {
|
|
|
|
XSetInputFocus (x_disp, x_win, RevertToPointerRoot, CurrentTime);
|
|
|
|
}
|
2003-02-25 17:19:47 +00:00
|
|
|
}
|
2021-11-05 04:26:44 +00:00
|
|
|
|
2021-11-22 04:16:05 +00:00
|
|
|
static void
|
|
|
|
leave_notify (XEvent *event)
|
|
|
|
{
|
|
|
|
x11_have_pointer = false;
|
|
|
|
}
|
|
|
|
|
2001-08-16 16:41:40 +00:00
|
|
|
static void
|
2021-09-27 10:54:08 +00:00
|
|
|
XLateKey (XKeyEvent *ev, int *k, int *u)
|
2001-04-15 04:18:22 +00:00
|
|
|
{
|
2005-06-08 06:35:48 +00:00
|
|
|
char buffer[4];
|
2011-06-19 01:48:02 +00:00
|
|
|
int unicode;
|
2001-04-15 04:18:22 +00:00
|
|
|
int key = 0;
|
2001-08-17 19:47:51 +00:00
|
|
|
KeySym keysym, shifted_keysym;
|
2001-08-16 16:41:40 +00:00
|
|
|
XComposeStatus compose;
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2001-08-17 19:47:51 +00:00
|
|
|
keysym = XLookupKeysym (ev, 0);
|
2021-09-27 10:54:08 +00:00
|
|
|
XLookupString (ev, buffer, sizeof(buffer), &shifted_keysym, &compose);
|
2005-06-08 06:35:48 +00:00
|
|
|
unicode = (byte) buffer[0];
|
2001-04-15 04:18:22 +00:00
|
|
|
|
|
|
|
switch (keysym) {
|
|
|
|
case XK_KP_Page_Up:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP9;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Page_Up:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_PAGEUP;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Page_Down:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP3;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Page_Down:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_PAGEDOWN;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Home:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP7;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Home:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_HOME;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_End:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP1;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_End:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_END;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Left:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP4;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Left:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_LEFT;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Right:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP6;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Right:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_RIGHT;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Down:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP2;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Down:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_DOWN;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Up:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP8;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Up:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_UP;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Escape:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_ESCAPE;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Enter:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP_ENTER;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Return:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_RETURN;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Tab:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_TAB;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_F1:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F1;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F2:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F2;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F3:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F3;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F4:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F4;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F5:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F5;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F6:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F6;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F7:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F7;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F8:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F8;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F9:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F9;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F10:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F10;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F11:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F11;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F12:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_F12;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_BackSpace:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_BACKSPACE;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Delete:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP_PERIOD;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_Delete:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_DELETE;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Pause:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_PAUSE;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Shift_L:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_LSHIFT;
|
2001-08-16 16:41:40 +00:00
|
|
|
break;
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Shift_R:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_RSHIFT;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Execute:
|
|
|
|
case XK_Control_L:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_LCTRL;
|
2001-08-16 16:41:40 +00:00
|
|
|
break;
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Control_R:
|
2002-08-08 05:53:58 +00:00
|
|
|
key = QFK_RCTRL;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Mode_switch:
|
|
|
|
case XK_Alt_L:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_LALT;
|
2001-08-16 16:41:40 +00:00
|
|
|
break;
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Meta_L:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_LMETA;
|
2001-08-16 16:41:40 +00:00
|
|
|
break;
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Alt_R:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_RALT;
|
2001-08-16 16:41:40 +00:00
|
|
|
break;
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Meta_R:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_RMETA;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
2009-03-18 00:26:34 +00:00
|
|
|
case XK_Super_L:
|
|
|
|
key = QFK_LSUPER;
|
|
|
|
break;
|
|
|
|
case XK_Super_R:
|
|
|
|
key = QFK_RSUPER;
|
|
|
|
break;
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2002-04-27 00:25:40 +00:00
|
|
|
case XK_Multi_key:
|
|
|
|
key = QFK_COMPOSE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Menu:
|
|
|
|
key = QFK_MENU;
|
|
|
|
break;
|
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Caps_Lock:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_CAPSLOCK;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
2002-08-08 05:53:58 +00:00
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_KP_Begin:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP5;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
2002-04-27 00:07:47 +00:00
|
|
|
case XK_Print:
|
|
|
|
key = QFK_PRINT;
|
|
|
|
break;
|
|
|
|
|
2001-08-20 02:06:55 +00:00
|
|
|
case XK_Scroll_Lock:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_SCROLLOCK;
|
2001-08-20 02:06:55 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_Num_Lock:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_NUMLOCK;
|
2001-08-20 02:06:55 +00:00
|
|
|
break;
|
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_Insert:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_INSERT;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_KP_Insert:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP0;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case XK_KP_Multiply:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP_MULTIPLY;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_KP_Add:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP_PLUS;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_KP_Subtract:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP_MINUS;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_KP_Divide:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_KP_DIVIDE;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
2002-08-21 00:04:35 +00:00
|
|
|
// For Sun keyboards
|
2001-04-15 04:18:22 +00:00
|
|
|
case XK_F27:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_HOME;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F29:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_PAGEUP;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F33:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_END;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
case XK_F35:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_PAGEDOWN;
|
2001-04-15 04:18:22 +00:00
|
|
|
break;
|
|
|
|
|
2002-08-21 00:04:35 +00:00
|
|
|
// Some high ASCII symbols, for azerty keymaps
|
2001-07-19 21:46:34 +00:00
|
|
|
case XK_twosuperior:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_WORLD_18;
|
2001-07-19 21:46:34 +00:00
|
|
|
break;
|
|
|
|
case XK_eacute:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_WORLD_63;
|
2001-07-19 21:46:34 +00:00
|
|
|
break;
|
|
|
|
case XK_section:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_WORLD_7;
|
2001-07-19 21:46:34 +00:00
|
|
|
break;
|
|
|
|
case XK_egrave:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_WORLD_72;
|
2001-07-19 21:46:34 +00:00
|
|
|
break;
|
|
|
|
case XK_ccedilla:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_WORLD_71;
|
2001-07-19 21:46:34 +00:00
|
|
|
break;
|
|
|
|
case XK_agrave:
|
2001-10-28 04:23:37 +00:00
|
|
|
key = QFK_WORLD_64;
|
2001-07-19 21:46:34 +00:00
|
|
|
break;
|
|
|
|
|
2009-03-18 00:26:34 +00:00
|
|
|
case XK_Kanji:
|
|
|
|
key = QFK_KANJI;
|
|
|
|
break;
|
|
|
|
case XK_Muhenkan:
|
|
|
|
key = QFK_MUHENKAN;
|
|
|
|
break;
|
|
|
|
case XK_Henkan:
|
|
|
|
key = QFK_HENKAN;
|
|
|
|
break;
|
|
|
|
case XK_Romaji:
|
|
|
|
key = QFK_ROMAJI;
|
|
|
|
break;
|
|
|
|
case XK_Hiragana:
|
|
|
|
key = QFK_HIRAGANA;
|
|
|
|
break;
|
|
|
|
case XK_Katakana:
|
|
|
|
key = QFK_KATAKANA;
|
|
|
|
break;
|
|
|
|
case XK_Hiragana_Katakana:
|
2013-01-13 09:54:23 +00:00
|
|
|
key = QFK_HIRAGANA_KATAKANA;
|
2009-03-18 00:26:34 +00:00
|
|
|
break;
|
|
|
|
case XK_Zenkaku:
|
|
|
|
key = QFK_ZENKAKU;
|
|
|
|
break;
|
|
|
|
case XK_Hankaku:
|
|
|
|
key = QFK_HANKAKU;
|
|
|
|
break;
|
|
|
|
case XK_Zenkaku_Hankaku:
|
|
|
|
key = QFK_ZENKAKU_HANKAKU;
|
|
|
|
break;
|
|
|
|
case XK_Touroku:
|
|
|
|
key = QFK_TOUROKU;
|
|
|
|
break;
|
|
|
|
case XK_Massyo:
|
|
|
|
key = QFK_MASSYO;
|
|
|
|
break;
|
|
|
|
case XK_Kana_Lock:
|
|
|
|
key = QFK_KANA_LOCK;
|
|
|
|
break;
|
|
|
|
case XK_Kana_Shift:
|
|
|
|
key = QFK_KANA_SHIFT;
|
|
|
|
break;
|
|
|
|
case XK_Eisu_Shift:
|
|
|
|
key = QFK_EISU_SHIFT;
|
|
|
|
break;
|
|
|
|
case XK_Eisu_toggle:
|
|
|
|
key = QFK_EISU_TOGGLE;
|
|
|
|
break;
|
|
|
|
case XK_Kanji_Bangou:
|
|
|
|
key = QFK_KANJI_BANGOU;
|
|
|
|
break;
|
|
|
|
case XK_Zen_Koho:
|
|
|
|
key = QFK_ZEN_KOHO;
|
|
|
|
break;
|
|
|
|
case XK_Mae_Koho:
|
|
|
|
key = QFK_MAE_KOHO;
|
|
|
|
break;
|
2011-12-19 07:37:48 +00:00
|
|
|
case XF86XK_HomePage:
|
|
|
|
key = QFK_HOMEPAGE;
|
|
|
|
break;
|
|
|
|
case XF86XK_Search:
|
|
|
|
key = QFK_SEARCH;
|
|
|
|
break;
|
|
|
|
case XF86XK_Mail:
|
|
|
|
key = QFK_MAIL;
|
|
|
|
break;
|
|
|
|
case XF86XK_Favorites:
|
|
|
|
key = QFK_FAVORITES;
|
|
|
|
break;
|
|
|
|
case XF86XK_AudioMute:
|
|
|
|
key = QFK_AUDIOMUTE;
|
|
|
|
break;
|
|
|
|
case XF86XK_AudioLowerVolume:
|
|
|
|
key = QFK_AUDIOLOWERVOLUME;
|
|
|
|
break;
|
|
|
|
case XF86XK_AudioRaiseVolume:
|
|
|
|
key = QFK_AUDIORAISEVOLUME;
|
|
|
|
break;
|
|
|
|
case XF86XK_AudioPlay:
|
|
|
|
key = QFK_AUDIOPLAY;
|
|
|
|
break;
|
|
|
|
case XF86XK_Calculator:
|
|
|
|
key = QFK_CALCULATOR;
|
|
|
|
break;
|
|
|
|
case XK_Help:
|
|
|
|
key = QFK_HELP;
|
|
|
|
break;
|
|
|
|
case XK_Undo:
|
|
|
|
key = QFK_UNDO;
|
|
|
|
break;
|
|
|
|
case XK_Redo:
|
|
|
|
key = QFK_REDO;
|
|
|
|
break;
|
|
|
|
case XF86XK_New:
|
|
|
|
key = QFK_NEW;
|
|
|
|
break;
|
|
|
|
case XF86XK_Reload: // eh? it's open (hiraku) on my kb
|
|
|
|
key = QFK_RELOAD;
|
|
|
|
break;
|
|
|
|
case SunXK_Open:
|
|
|
|
//FALL THROUGH
|
|
|
|
case XF86XK_Open:
|
|
|
|
key = QFK_OPEN;
|
|
|
|
break;
|
|
|
|
case XF86XK_Close:
|
|
|
|
key = QFK_CLOSE;
|
|
|
|
break;
|
|
|
|
case XF86XK_Reply:
|
|
|
|
key = QFK_REPLY;
|
|
|
|
break;
|
|
|
|
case XF86XK_MailForward:
|
|
|
|
key = QFK_MAILFORWARD;
|
|
|
|
break;
|
|
|
|
case XF86XK_Send:
|
|
|
|
key = QFK_SEND;
|
|
|
|
break;
|
|
|
|
case XF86XK_Save:
|
|
|
|
key = QFK_SAVE;
|
|
|
|
break;
|
|
|
|
case XK_KP_Equal:
|
|
|
|
key = QFK_KP_EQUALS;
|
|
|
|
break;
|
|
|
|
case XK_parenleft:
|
|
|
|
key = QFK_LEFTPAREN;
|
|
|
|
break;
|
|
|
|
case XK_parenright:
|
|
|
|
key = QFK_RIGHTPAREN;
|
|
|
|
break;
|
|
|
|
case XF86XK_Back:
|
|
|
|
key = QFK_BACK;
|
|
|
|
break;
|
|
|
|
case XF86XK_Forward:
|
|
|
|
key = QFK_FORWARD;
|
|
|
|
break;
|
2009-03-18 00:26:34 +00:00
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
default:
|
2002-08-21 00:04:35 +00:00
|
|
|
if (keysym < 128) { // ASCII keys
|
2001-04-15 04:18:22 +00:00
|
|
|
key = keysym;
|
2001-08-16 16:41:40 +00:00
|
|
|
if ((key >= 'A') && (key <= 'Z')) {
|
2001-04-15 04:18:22 +00:00
|
|
|
key = key + ('a' - 'A');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2001-08-16 16:41:40 +00:00
|
|
|
*k = key;
|
|
|
|
*u = unicode;
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
|
|
|
|
2021-11-22 05:07:55 +00:00
|
|
|
static void
|
|
|
|
in_x11_send_focus_event (int gain)
|
|
|
|
{
|
|
|
|
IE_event_t event = {
|
|
|
|
.type = gain ? ie_app_gain_focus : ie_app_lose_focus,
|
|
|
|
.when = Sys_LongTime (),
|
|
|
|
};
|
|
|
|
IE_Send_Event (&event);
|
|
|
|
}
|
|
|
|
|
2001-07-05 20:18:23 +00:00
|
|
|
static void
|
2002-01-08 20:07:19 +00:00
|
|
|
event_focusout (XEvent *event)
|
2001-07-05 20:18:23 +00:00
|
|
|
{
|
2005-03-06 08:22:15 +00:00
|
|
|
if (x_have_focus) {
|
|
|
|
x_have_focus = false;
|
2021-11-22 05:07:55 +00:00
|
|
|
in_x11_send_focus_event (0);
|
2005-03-06 08:22:15 +00:00
|
|
|
if (in_snd_block->int_val) {
|
|
|
|
S_BlockSound ();
|
|
|
|
CDAudio_Pause ();
|
|
|
|
}
|
|
|
|
X11_RestoreGamma ();
|
2001-07-05 20:35:42 +00:00
|
|
|
}
|
2001-07-05 20:18:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2002-01-08 20:07:19 +00:00
|
|
|
event_focusin (XEvent *event)
|
2001-07-05 20:18:23 +00:00
|
|
|
{
|
2021-11-22 05:07:55 +00:00
|
|
|
in_x11_send_focus_event (1);
|
2003-02-13 18:24:30 +00:00
|
|
|
x_have_focus = true;
|
2002-08-21 01:40:21 +00:00
|
|
|
if (in_snd_block->int_val) {
|
|
|
|
S_UnblockSound ();
|
|
|
|
CDAudio_Resume ();
|
|
|
|
}
|
2003-02-13 18:24:30 +00:00
|
|
|
VID_UpdateGamma (vid_gamma);
|
2001-07-05 20:18:23 +00:00
|
|
|
}
|
2001-04-15 04:18:22 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
center_pointer (void)
|
|
|
|
{
|
2020-03-08 12:30:08 +00:00
|
|
|
XEvent event = {};
|
2001-04-15 04:18:22 +00:00
|
|
|
|
|
|
|
event.type = MotionNotify;
|
|
|
|
event.xmotion.display = x_disp;
|
|
|
|
event.xmotion.window = x_win;
|
2012-02-14 10:47:02 +00:00
|
|
|
event.xmotion.x = viddef.width / 2;
|
|
|
|
event.xmotion.y = viddef.height / 2;
|
2001-04-15 04:18:22 +00:00
|
|
|
XSendEvent (x_disp, x_win, False, PointerMotionMask, &event);
|
|
|
|
XWarpPointer (x_disp, None, x_win, 0, 0, 0, 0,
|
2012-02-14 10:47:02 +00:00
|
|
|
viddef.width / 2, viddef.height / 2);
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 13:20:17 +00:00
|
|
|
static void
|
|
|
|
in_x11_send_axis_event (int devid, in_axisinfo_t *axis)
|
|
|
|
{
|
|
|
|
IE_event_t event = {
|
|
|
|
.type = ie_axis,
|
|
|
|
.when = Sys_LongTime (),
|
|
|
|
.axis = {
|
2021-11-09 13:31:09 +00:00
|
|
|
.data = x11_mouse_device.event_data,
|
2021-11-03 13:20:17 +00:00
|
|
|
.devid = devid,
|
|
|
|
.axis = axis->axis,
|
|
|
|
.value = axis->value,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
IE_Send_Event (&event);
|
|
|
|
}
|
|
|
|
|
2021-11-16 03:55:55 +00:00
|
|
|
static int
|
2021-11-05 04:26:44 +00:00
|
|
|
in_x11_send_mouse_event (IE_mouse_type type)
|
|
|
|
{
|
|
|
|
IE_event_t event = {
|
|
|
|
.type = ie_mouse,
|
|
|
|
.when = Sys_LongTime (),
|
|
|
|
.mouse = x11_mouse,
|
|
|
|
};
|
|
|
|
event.mouse.type = type;
|
2021-11-16 03:55:55 +00:00
|
|
|
return IE_Send_Event (&event);
|
2021-11-05 04:26:44 +00:00
|
|
|
}
|
|
|
|
|
2021-11-16 03:55:55 +00:00
|
|
|
static int
|
2021-11-05 05:54:33 +00:00
|
|
|
in_x11_send_key_event (void)
|
2021-11-05 04:26:44 +00:00
|
|
|
{
|
|
|
|
IE_event_t event = {
|
|
|
|
.type = ie_key,
|
|
|
|
.when = Sys_LongTime (),
|
|
|
|
.key = x11_key,
|
|
|
|
};
|
2021-11-16 03:55:55 +00:00
|
|
|
return IE_Send_Event (&event);
|
2021-11-05 04:26:44 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 13:20:17 +00:00
|
|
|
static void
|
2021-11-09 13:31:09 +00:00
|
|
|
in_x11_send_button_event (int devid, in_buttoninfo_t *button, void *event_data)
|
2021-11-03 13:20:17 +00:00
|
|
|
{
|
|
|
|
IE_event_t event = {
|
|
|
|
.type = ie_button,
|
|
|
|
.when = Sys_LongTime (),
|
|
|
|
.button = {
|
2021-11-09 13:31:09 +00:00
|
|
|
.data = event_data,
|
2021-11-03 13:20:17 +00:00
|
|
|
.devid = devid,
|
|
|
|
.button = button->button,
|
|
|
|
.state = button->state,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
IE_Send_Event (&event);
|
|
|
|
}
|
|
|
|
|
2021-11-05 05:54:33 +00:00
|
|
|
static void
|
|
|
|
selection_notify (XEvent *event)
|
|
|
|
{
|
|
|
|
unsigned char *data, *p;
|
|
|
|
unsigned long num_bytes;
|
|
|
|
unsigned long tmp, len;
|
|
|
|
int format;
|
|
|
|
Atom type, property;
|
|
|
|
|
|
|
|
x_time = event->xselection.time;
|
|
|
|
|
|
|
|
if ((property = event->xselection.property) == None)
|
|
|
|
return;
|
|
|
|
|
|
|
|
XGetWindowProperty (x_disp, x_win, property, 0, 0, False, AnyPropertyType,
|
|
|
|
&type, &format, &len, &num_bytes, &data);
|
|
|
|
if (num_bytes <= 0)
|
|
|
|
return;
|
|
|
|
if (XGetWindowProperty (x_disp, x_win, property, 0, num_bytes, True,
|
|
|
|
AnyPropertyType, &type, &format, &len, &tmp, &data)
|
|
|
|
!= Success) {
|
|
|
|
XFree (data); // FIXME is this correct for this instance?
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//FIXME send paste event instead of key presses?
|
|
|
|
x11_key.code = 0;
|
|
|
|
for (p = data; num_bytes && *p; p++, num_bytes--) {
|
|
|
|
x11_key.unicode = *p;
|
|
|
|
in_x11_send_key_event ();
|
|
|
|
}
|
|
|
|
XFree (data);
|
|
|
|
}
|
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
static void
|
2002-01-08 20:07:19 +00:00
|
|
|
event_motion (XEvent *event)
|
2001-04-15 04:18:22 +00:00
|
|
|
{
|
2002-01-08 20:07:19 +00:00
|
|
|
x_time = event->xmotion.time;
|
2004-03-21 05:21:27 +00:00
|
|
|
if (x_time <= x_mouse_time) {
|
2021-11-05 04:26:44 +00:00
|
|
|
x11_mouse.x = event->xmotion.x;
|
|
|
|
x11_mouse.y = event->xmotion.y;
|
2004-03-21 05:21:27 +00:00
|
|
|
return;
|
|
|
|
}
|
2002-01-08 20:07:19 +00:00
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
if (dga_active) {
|
2021-11-03 13:20:17 +00:00
|
|
|
x11_mouse_axes[0].value = event->xmotion.x_root;
|
|
|
|
x11_mouse_axes[1].value = event->xmotion.y_root;
|
2001-04-15 04:18:22 +00:00
|
|
|
} else {
|
2010-11-27 00:25:29 +00:00
|
|
|
if (vid_fullscreen->int_val || input_grabbed) {
|
2001-04-15 04:18:22 +00:00
|
|
|
if (!event->xmotion.send_event) {
|
2013-01-24 02:25:30 +00:00
|
|
|
unsigned dist_x = abs (viddef.width / 2 - event->xmotion.x);
|
|
|
|
unsigned dist_y = abs (viddef.height / 2 - event->xmotion.y);
|
2021-11-03 13:20:17 +00:00
|
|
|
|
2021-11-05 04:26:44 +00:00
|
|
|
x11_mouse_axes[0].value = event->xmotion.x - x11_mouse.x;
|
|
|
|
x11_mouse_axes[1].value = event->xmotion.y - x11_mouse.y;
|
2012-02-14 10:47:02 +00:00
|
|
|
if (dist_x > viddef.width / 4 || dist_y > viddef.height / 4) {
|
2001-04-15 04:18:22 +00:00
|
|
|
center_pointer ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2021-11-05 04:26:44 +00:00
|
|
|
x11_mouse_axes[0].value = event->xmotion.x - x11_mouse.x;
|
|
|
|
x11_mouse_axes[1].value = event->xmotion.y - x11_mouse.y;
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
|
|
|
}
|
2021-11-05 04:26:44 +00:00
|
|
|
|
|
|
|
x11_mouse.shift = event->xmotion.state & 0xff;
|
|
|
|
x11_mouse.x = event->xmotion.x;
|
|
|
|
x11_mouse.y = event->xmotion.y;
|
2021-11-16 03:55:55 +00:00
|
|
|
if (!in_x11_send_mouse_event (ie_mousemove)) {
|
|
|
|
in_x11_send_axis_event (x11_mouse_device.devid, &x11_mouse_axes[0]);
|
|
|
|
in_x11_send_axis_event (x11_mouse_device.devid, &x11_mouse_axes[1]);
|
|
|
|
}
|
2021-11-03 13:20:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
event_button (XEvent *event)
|
|
|
|
{
|
|
|
|
unsigned but;
|
|
|
|
|
|
|
|
x_time = event->xbutton.time;
|
|
|
|
|
2021-11-21 13:16:08 +00:00
|
|
|
// x11 buttons are 1-based
|
2021-11-05 04:26:44 +00:00
|
|
|
but = event->xbutton.button - 1;
|
2021-11-21 13:16:08 +00:00
|
|
|
if (but > X11_MOUSE_BUTTONS) {
|
2021-11-03 13:20:17 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-11-05 04:26:44 +00:00
|
|
|
int press = event->type == ButtonPress;
|
2021-11-03 13:20:17 +00:00
|
|
|
|
2021-11-05 04:26:44 +00:00
|
|
|
x11_mouse_buttons[but].state = press;
|
|
|
|
|
|
|
|
x11_mouse.shift = event->xmotion.state & 0xff;
|
|
|
|
x11_mouse.x = event->xmotion.x;
|
|
|
|
x11_mouse.y = event->xmotion.y;
|
|
|
|
if (press) {
|
|
|
|
x11_mouse.buttons |= 1 << but;
|
|
|
|
} else {
|
|
|
|
x11_mouse.buttons &= ~(1 << but);
|
|
|
|
}
|
2021-11-16 03:55:55 +00:00
|
|
|
if (!in_x11_send_mouse_event (press ? ie_mousedown : ie_mouseup)) {
|
|
|
|
in_x11_send_button_event (x11_mouse_device.devid,
|
|
|
|
&x11_mouse_buttons[but],
|
|
|
|
x11_mouse_device.event_data);
|
|
|
|
}
|
2021-11-03 13:20:17 +00:00
|
|
|
}
|
|
|
|
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
static unsigned
|
|
|
|
in_x11_process_key_button (unsigned keycode, int press)
|
|
|
|
{
|
|
|
|
// X11 protocol supports only 256 keys. The key codes are the AT scan codes
|
|
|
|
// offset by 8 (so Esc is 9 instead of 1).
|
|
|
|
unsigned key = (keycode - 8) & 0xff;
|
|
|
|
x11_key_buttons[key].state = press;
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2021-11-03 13:20:17 +00:00
|
|
|
static void
|
|
|
|
event_key (XEvent *event)
|
|
|
|
{
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
unsigned key = 0;
|
2021-11-03 13:20:17 +00:00
|
|
|
|
|
|
|
x_time = event->xkey.time;
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
if (!x11_have_xi) {
|
|
|
|
key = in_x11_process_key_button (event->xkey.keycode,
|
|
|
|
event->type == KeyPress);
|
|
|
|
}
|
2021-11-05 04:26:44 +00:00
|
|
|
x11_key.shift = event->xmotion.state & 0xff;
|
|
|
|
XLateKey (&event->xkey, &x11_key.code, &x11_key.unicode);
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
if (!(event->type == KeyPress && in_x11_send_key_event ())
|
|
|
|
&& !x11_have_xi) {
|
2021-11-16 03:55:55 +00:00
|
|
|
in_x11_send_button_event (x11_keyboard_device.devid,
|
|
|
|
&x11_key_buttons[key],
|
|
|
|
x11_keyboard_device.event_data);
|
2021-11-08 02:20:04 +00:00
|
|
|
}
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
|
|
|
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
static void
|
|
|
|
xi_raw_key (void *event, int press)
|
|
|
|
{
|
|
|
|
if (!x_have_focus) {
|
|
|
|
//avoid being a keylogger
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
XIRawEvent *re = event;
|
|
|
|
unsigned key = in_x11_process_key_button (re->detail, press);
|
|
|
|
|
|
|
|
// Send only the button press: event_key takes care of the UI key event,
|
|
|
|
// which includes character translation and repeat (XInput2 raw key events
|
|
|
|
// do not repeat)
|
|
|
|
in_x11_send_button_event (x11_keyboard_device.devid,
|
|
|
|
&x11_key_buttons[key],
|
|
|
|
x11_keyboard_device.event_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xi_raw_key_press (void *event)
|
|
|
|
{
|
|
|
|
xi_raw_key (event, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xi_raw_key_resease (void *event)
|
|
|
|
{
|
|
|
|
xi_raw_key (event, 0);
|
|
|
|
}
|
|
|
|
|
2021-11-21 14:01:12 +00:00
|
|
|
static void
|
|
|
|
xi_raw_motion (void *event)
|
|
|
|
{
|
|
|
|
int root_x, root_y;
|
|
|
|
Window root_w, child_w;
|
|
|
|
XIRawEvent *re = event;
|
|
|
|
|
2021-11-23 14:15:08 +00:00
|
|
|
//FIXME it turns out mice can have multiple axes (my trackball has 4:
|
|
|
|
//usual x and y, +scroll up/down and left/right (clicky and icky, but
|
|
|
|
//still...)
|
|
|
|
unsigned mask = re->valuators.mask[0] & 3;
|
|
|
|
if (!mask) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
x11_mouse_axes[0].value = 0;
|
|
|
|
x11_mouse_axes[1].value = 0;
|
|
|
|
for (int axis = 0, ind = 0; mask; axis++, mask >>= 1) {
|
|
|
|
if (mask & 1) {
|
|
|
|
x11_mouse_axes[axis].value = re->raw_values[ind++];
|
|
|
|
}
|
|
|
|
}
|
2021-11-21 14:01:12 +00:00
|
|
|
XQueryPointer (x_disp, x_win, &root_w, &child_w, &root_x, &root_y,
|
|
|
|
&x11_mouse.x, &x11_mouse.y, &x11_mouse.shift);
|
|
|
|
// want only the modifier state
|
|
|
|
x11_mouse.shift &= 0xff;
|
|
|
|
if (!in_x11_send_mouse_event (ie_mousemove)) {
|
|
|
|
in_x11_send_axis_event (x11_mouse_device.devid,
|
|
|
|
&x11_mouse_axes[0]);
|
|
|
|
in_x11_send_axis_event (x11_mouse_device.devid,
|
|
|
|
&x11_mouse_axes[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xi_raw_button (void *event, int press)
|
|
|
|
{
|
|
|
|
int root_x, root_y;
|
|
|
|
Window root_w, child_w;
|
|
|
|
unsigned button;
|
|
|
|
XIRawEvent *re = event;
|
|
|
|
|
|
|
|
// x11 buttons are 1-based
|
|
|
|
button = re->detail - 1;
|
|
|
|
if (button > X11_MOUSE_BUTTONS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
XQueryPointer (x_disp, x_win, &root_w, &child_w, &root_x, &root_y,
|
|
|
|
&x11_mouse.x, &x11_mouse.y, &x11_mouse.shift);
|
|
|
|
// want only the modifier state
|
|
|
|
x11_mouse.shift &= 0xff;
|
|
|
|
if (press) {
|
|
|
|
x11_mouse.buttons |= 1 << button;
|
|
|
|
} else {
|
|
|
|
x11_mouse.buttons &= ~(1 << button);
|
|
|
|
}
|
|
|
|
if (!in_x11_send_mouse_event (press ? ie_mousedown : ie_mouseup)) {
|
|
|
|
in_x11_send_button_event (x11_mouse_device.devid,
|
|
|
|
&x11_mouse_buttons[button],
|
|
|
|
x11_mouse_device.event_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xi_raw_button_press (void *event)
|
|
|
|
{
|
|
|
|
xi_raw_button (event, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xi_raw_button_resease (void *event)
|
|
|
|
{
|
|
|
|
xi_raw_button (event, 0);
|
|
|
|
}
|
|
|
|
|
2021-11-22 04:16:05 +00:00
|
|
|
static void
|
|
|
|
xi_barrier_hit (void *event)
|
|
|
|
{
|
|
|
|
__auto_type be = *(XIBarrierEvent *) event;
|
|
|
|
|
2021-11-22 04:49:50 +00:00
|
|
|
if (be.barrier != x11_left_barrier
|
|
|
|
&& be.barrier != x11_right_barrier
|
|
|
|
&& be.barrier != x11_top_barrier
|
|
|
|
&& be.barrier != x11_bottom_barrier) {
|
|
|
|
Sys_MaskPrintf (SYS_vid, "xi_barrier_hit: bad barrier %ld\n",
|
|
|
|
be.barrier);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-11-22 04:16:05 +00:00
|
|
|
if (!x11_have_pointer || !input_grabbed) {
|
|
|
|
XIBarrierReleasePointer (x_disp, be.deviceid, be.barrier, be.eventid);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
xi_barrier_leave (void *event)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-11-21 14:01:12 +00:00
|
|
|
static void
|
|
|
|
event_generic (XEvent *event)
|
|
|
|
{
|
|
|
|
// XI_LASTEVENT is the actual last event, not +1
|
|
|
|
static void (*xi_event_handlers[XI_LASTEVENT + 1]) (void *) = {
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
[XI_RawKeyPress] = xi_raw_key_press,
|
|
|
|
[XI_RawKeyRelease] = xi_raw_key_resease,
|
2021-11-21 14:01:12 +00:00
|
|
|
[XI_RawMotion] = xi_raw_motion,
|
|
|
|
[XI_RawButtonPress] = xi_raw_button_press,
|
|
|
|
[XI_RawButtonRelease] = xi_raw_button_resease,
|
2021-11-22 04:16:05 +00:00
|
|
|
[XI_BarrierHit] = xi_barrier_hit,
|
|
|
|
[XI_BarrierLeave] = xi_barrier_leave,
|
2021-11-21 14:01:12 +00:00
|
|
|
};
|
|
|
|
XGenericEventCookie *cookie = &event->xcookie;
|
|
|
|
|
|
|
|
if (cookie->type != GenericEvent || cookie->extension != xi_opcode
|
|
|
|
|| !XGetEventData (x_disp, cookie)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((unsigned) cookie->evtype <= XI_LASTEVENT
|
|
|
|
&& xi_event_handlers[cookie->evtype]) {
|
|
|
|
xi_event_handlers[cookie->evtype] (cookie->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
XFreeEventData (x_disp, cookie);
|
|
|
|
}
|
|
|
|
|
2003-03-07 22:30:15 +00:00
|
|
|
static void
|
|
|
|
grab_error (int code, const char *device)
|
|
|
|
{
|
|
|
|
const char *reason;
|
|
|
|
|
|
|
|
switch (code) {
|
|
|
|
case AlreadyGrabbed:
|
|
|
|
reason = "already grabbed";
|
|
|
|
break;
|
|
|
|
case GrabNotViewable:
|
|
|
|
reason = "grab not viewable";
|
|
|
|
break;
|
|
|
|
case GrabFrozen:
|
|
|
|
reason = "grab frozen";
|
|
|
|
break;
|
|
|
|
case GrabInvalidTime:
|
|
|
|
reason = "grab invalid time";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
reason = "unknown reason";
|
|
|
|
break;
|
|
|
|
}
|
2007-11-06 10:17:14 +00:00
|
|
|
Sys_Printf ("failed to grab %s: %s\n", device, reason);
|
2003-03-07 22:30:15 +00:00
|
|
|
}
|
|
|
|
|
2021-08-27 00:10:21 +00:00
|
|
|
static void
|
2021-08-30 00:54:36 +00:00
|
|
|
in_x11_grab_input (void *data, int grab)
|
2001-08-30 20:04:13 +00:00
|
|
|
{
|
2001-09-05 03:14:41 +00:00
|
|
|
if (!x_disp || !x_win)
|
2003-03-07 03:55:51 +00:00
|
|
|
return;
|
|
|
|
|
2021-11-22 04:16:05 +00:00
|
|
|
if (xf_opcode) {
|
|
|
|
input_grabbed = grab;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-03-07 03:55:51 +00:00
|
|
|
if (vid_fullscreen)
|
|
|
|
grab = grab || vid_fullscreen->int_val;
|
|
|
|
|
|
|
|
if ((input_grabbed && grab) || (!input_grabbed && !grab))
|
|
|
|
return;
|
|
|
|
|
2003-03-07 22:30:15 +00:00
|
|
|
if (grab) {
|
|
|
|
int ret;
|
|
|
|
|
2004-03-21 00:34:24 +00:00
|
|
|
ret = XGrabPointer (x_disp, x_win, True, X11_MOUSE_MASK, GrabModeAsync,
|
2003-03-07 22:30:15 +00:00
|
|
|
GrabModeAsync, x_win, None, CurrentTime);
|
|
|
|
if (ret != GrabSuccess) {
|
|
|
|
grab_error (ret, "mouse");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ret = XGrabKeyboard (x_disp, x_win, 1, GrabModeAsync, GrabModeAsync,
|
|
|
|
CurrentTime);
|
|
|
|
if (ret != GrabSuccess) {
|
|
|
|
XUngrabPointer (x_disp, CurrentTime);
|
|
|
|
grab_error (ret, "keyboard");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
input_grabbed = 1;
|
2010-11-27 00:25:29 +00:00
|
|
|
in_dga_f (in_dga);
|
2003-03-07 22:30:15 +00:00
|
|
|
} else {
|
|
|
|
XUngrabPointer (x_disp, CurrentTime);
|
|
|
|
XUngrabKeyboard (x_disp, CurrentTime);
|
|
|
|
input_grabbed = 0;
|
2010-11-27 00:25:29 +00:00
|
|
|
in_dga_f (in_dga);
|
2003-03-07 03:55:51 +00:00
|
|
|
}
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
2021-11-05 04:30:01 +00:00
|
|
|
#ifdef X11_USE_SELECT
|
2021-08-27 00:10:21 +00:00
|
|
|
static void
|
2021-09-28 01:53:51 +00:00
|
|
|
in_x11_add_select (qf_fd_set *fdset, int *maxfd, void *data)
|
2021-09-27 02:24:35 +00:00
|
|
|
{
|
2021-09-28 01:53:51 +00:00
|
|
|
QF_FD_SET (x11_fd, fdset);
|
2021-09-27 02:24:35 +00:00
|
|
|
if (*maxfd < x11_fd) {
|
|
|
|
*maxfd = x11_fd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-09-28 01:53:51 +00:00
|
|
|
in_x11_check_select (qf_fd_set *fdset, void *data)
|
2001-04-15 04:18:22 +00:00
|
|
|
{
|
2021-09-28 01:53:51 +00:00
|
|
|
if (QF_FD_ISSET (x11_fd, fdset)) {
|
2021-11-05 04:30:01 +00:00
|
|
|
Sys_Printf ("in_x11_check_select\n");
|
2021-09-27 02:24:35 +00:00
|
|
|
X11_ProcessEvents (); // Get events from X server.
|
|
|
|
}
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
2021-11-05 04:30:01 +00:00
|
|
|
#else
|
|
|
|
static void
|
|
|
|
in_x11_process_events (void *data)
|
|
|
|
{
|
|
|
|
X11_ProcessEvents (); // Get events from X server.
|
|
|
|
}
|
|
|
|
#endif
|
2021-11-03 13:20:17 +00:00
|
|
|
static void
|
|
|
|
in_x11_axis_info (void *data, void *device, in_axisinfo_t *axes, int *numaxes)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
if (!axes) {
|
|
|
|
*numaxes = dev->num_axes;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (*numaxes > dev->num_axes) {
|
|
|
|
*numaxes = dev->num_axes;
|
|
|
|
}
|
|
|
|
memcpy (axes, dev->axes, *numaxes * sizeof (in_axisinfo_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_x11_button_info (void *data, void *device, in_buttoninfo_t *buttons,
|
|
|
|
int *numbuttons)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
if (!buttons) {
|
|
|
|
*numbuttons = dev->num_buttons;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (*numbuttons > dev->num_buttons) {
|
|
|
|
*numbuttons = dev->num_buttons;
|
|
|
|
}
|
|
|
|
memcpy (buttons, dev->buttons, *numbuttons * sizeof (in_buttoninfo_t));
|
|
|
|
}
|
|
|
|
|
2021-11-18 04:01:33 +00:00
|
|
|
static const char *
|
|
|
|
in_x11_get_axis_name (void *data, void *device, int axis_num)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
const char *name = 0;
|
|
|
|
|
|
|
|
if (dev == &x11_keyboard_device) {
|
|
|
|
// keyboards don't have axes...
|
|
|
|
} else if (dev == &x11_mouse_device) {
|
|
|
|
if ((unsigned) axis_num < SIZE (x11_mouse_axis_names)) {
|
|
|
|
name = x11_mouse_axis_names[axis_num];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
in_x11_get_button_name (void *data, void *device, int button_num)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
const char *name = 0;
|
|
|
|
|
|
|
|
if (dev == &x11_keyboard_device) {
|
|
|
|
// X11 protocol supports only 256 keys. The key codes are the AT scan
|
|
|
|
// codes offset by 8 (so Esc is 9 instead of 1).
|
|
|
|
KeyCode keycode = (button_num + 8) & 0xff;
|
|
|
|
KeySym keysym = XkbKeycodeToKeysym (x_disp, keycode, 0, 0);
|
|
|
|
if (keysym != NoSymbol) {
|
|
|
|
name = XKeysymToString (keysym);
|
|
|
|
}
|
|
|
|
} else if (dev == &x11_mouse_device) {
|
|
|
|
if ((unsigned) button_num < SIZE (x11_mouse_button_names)) {
|
|
|
|
name = x11_mouse_button_names[button_num];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
in_x11_get_axis_num (void *data, void *device, const char *axis_name)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
int num = -1;
|
|
|
|
|
|
|
|
if (dev == &x11_keyboard_device) {
|
|
|
|
// keyboards don't have axes...
|
|
|
|
} else if (dev == &x11_mouse_device) {
|
|
|
|
for (size_t i = 0; i < SIZE (x11_mouse_axis_names); i++) {
|
|
|
|
if (strcasecmp (axis_name, x11_mouse_axis_names[i]) == 0) {
|
|
|
|
num = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
in_x11_get_button_num (void *data, void *device, const char *button_name)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
int num = -1;
|
|
|
|
|
|
|
|
if (dev == &x11_keyboard_device) {
|
|
|
|
KeySym keysym = XStringToKeysym (button_name);
|
|
|
|
if (keysym != NoSymbol) {
|
|
|
|
KeyCode keycode = XKeysymToKeycode (x_disp, keysym);
|
|
|
|
if (keycode != 0) {
|
|
|
|
// X11 protocol supports only 256 keys. The key codes are the
|
|
|
|
// AT scan codes offset by 8 (so Esc is 9 instead of 1).
|
|
|
|
num = (keycode - 8) & 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (dev == &x11_mouse_device) {
|
|
|
|
for (size_t i = 0; i < SIZE (x11_mouse_button_names); i++) {
|
|
|
|
if (strcasecmp (button_name, x11_mouse_button_names[i]) == 0) {
|
|
|
|
num = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2021-08-27 00:10:21 +00:00
|
|
|
static void
|
2021-08-30 00:54:36 +00:00
|
|
|
in_x11_shutdown (void *data)
|
2001-04-15 04:18:22 +00:00
|
|
|
{
|
2021-08-27 00:10:21 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid, "in_x11_shutdown\n");
|
2001-04-15 04:18:22 +00:00
|
|
|
if (x_disp) {
|
2021-01-30 05:49:42 +00:00
|
|
|
// XAutoRepeatOn (x_disp);
|
2001-08-30 20:32:27 +00:00
|
|
|
dga_off ();
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
2004-02-14 07:53:49 +00:00
|
|
|
if (in_mouse_accel && !in_mouse_accel->int_val)
|
2004-03-19 20:24:26 +00:00
|
|
|
X11_RestoreMouseAcceleration ();
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 13:31:09 +00:00
|
|
|
static void
|
|
|
|
in_x11_set_device_event_data (void *device, void *event_data, void *data)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
dev->event_data = event_data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *
|
|
|
|
in_x11_get_device_event_data (void *device, void *data)
|
|
|
|
{
|
|
|
|
x11_device_t *dev = device;
|
|
|
|
return dev->event_data;
|
|
|
|
}
|
|
|
|
|
2021-08-27 00:10:21 +00:00
|
|
|
static void
|
2021-11-21 02:33:58 +00:00
|
|
|
in_x11_init_cvars (void *data)
|
2021-08-27 00:10:21 +00:00
|
|
|
{
|
2021-11-21 14:37:42 +00:00
|
|
|
in_auto_focus = Cvar_Get ("in_auto_focus", "1", CVAR_ARCHIVE, 0,
|
|
|
|
"grab input focus when the mouse enters the"
|
|
|
|
" window when using xinput2 with certain"
|
|
|
|
" window managers using focus-follows-mouse"
|
|
|
|
" (eg, openbox)");
|
2021-08-27 00:10:21 +00:00
|
|
|
in_snd_block = Cvar_Get ("in_snd_block", "0", CVAR_ARCHIVE, NULL,
|
|
|
|
"block sound output on window focus loss");
|
2021-11-21 14:01:12 +00:00
|
|
|
in_dga = Cvar_Get ("in_dga", "0", CVAR_ARCHIVE, in_dga_f,
|
2021-08-27 00:10:21 +00:00
|
|
|
"DGA Input support");
|
|
|
|
in_mouse_accel = Cvar_Get ("in_mouse_accel", "1", CVAR_ARCHIVE,
|
|
|
|
in_mouse_accel_f,
|
|
|
|
"set to 0 to remove mouse acceleration");
|
|
|
|
}
|
|
|
|
|
2021-11-03 13:20:17 +00:00
|
|
|
static void
|
|
|
|
x11_add_device (x11_device_t *dev)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < dev->num_axes; i++) {
|
|
|
|
dev->axes[i].axis = i;
|
|
|
|
}
|
|
|
|
for (int i = 0; i < dev->num_buttons; i++) {
|
|
|
|
dev->buttons[i].button = i;
|
|
|
|
}
|
|
|
|
dev->devid = IN_AddDevice (x11_driver_handle, dev, dev->name, dev->name);
|
|
|
|
}
|
|
|
|
|
2021-11-21 14:01:12 +00:00
|
|
|
static int
|
|
|
|
in_x11_check_xi2 (void)
|
|
|
|
{
|
|
|
|
// Support XI 2.2
|
|
|
|
int major = 2, minor = 2;
|
|
|
|
int event, error;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!XQueryExtension (x_disp, "XInputExtension",
|
|
|
|
&xi_opcode, &event, &error)) {
|
|
|
|
Sys_MaskPrintf (SYS_vid, "X Input extenions not available.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if ((ret = XIQueryVersion (x_disp, &major, &minor)) == BadRequest) {
|
|
|
|
Sys_MaskPrintf (SYS_vid,
|
|
|
|
"No XI2 support. Server supports only %d.%d\n",
|
|
|
|
major, minor);
|
|
|
|
return 0;
|
|
|
|
} else if (ret != Success) {
|
|
|
|
Sys_MaskPrintf (SYS_vid, "in_x11_check_xi2: Xlib return bad: %d\n",
|
|
|
|
ret);
|
|
|
|
}
|
2021-11-22 04:49:50 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid, "XI2 supported: version %d.%d, op: %d err: %d\n",
|
|
|
|
major, minor, xi_opcode, error);
|
2021-11-22 04:16:05 +00:00
|
|
|
|
|
|
|
if (!XQueryExtension (x_disp, "XFIXES", &xf_opcode, &event, &error)) {
|
|
|
|
Sys_MaskPrintf (SYS_vid, "X fixes extenions not available.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
major = 5, minor = 0;
|
|
|
|
if (!XFixesQueryVersion (x_disp, &major, &minor)
|
|
|
|
|| (major * 10 + minor) < 50) {
|
|
|
|
Sys_MaskPrintf (SYS_vid, "Need X fixes 5.0.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2021-11-22 04:49:50 +00:00
|
|
|
Sys_MaskPrintf (SYS_vid,
|
|
|
|
"XFixes supported: version %d.%d, op: %d err: %d\n",
|
|
|
|
major, minor, xf_opcode, error);
|
2021-11-21 14:01:12 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_x11_xi_select_events (void)
|
|
|
|
{
|
2021-11-22 04:16:05 +00:00
|
|
|
byte mask[(XI_LASTEVENT + 7) / 8] = {};
|
|
|
|
XIEventMask evmask = {
|
|
|
|
.deviceid = XIAllMasterDevices,
|
|
|
|
.mask_len = sizeof (mask),
|
|
|
|
.mask = mask,
|
|
|
|
};
|
|
|
|
XISetMask (mask, XI_BarrierHit);
|
|
|
|
XISetMask (mask, XI_BarrierLeave);
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
XISetMask (mask, XI_RawKeyPress);
|
|
|
|
XISetMask (mask, XI_RawKeyRelease);
|
2021-11-22 06:42:22 +00:00
|
|
|
XISelectEvents (x_disp, x_root, &evmask, 1);
|
2021-11-21 14:01:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
in_x11_xi_setup_grabs (void)
|
|
|
|
{
|
|
|
|
// FIXME normal apps aren't supposed to care about the client pointer,
|
|
|
|
// but grabbing all master devices grabs the keyboard, too, which blocks
|
|
|
|
// alt-tab and the like
|
|
|
|
int dev;
|
|
|
|
XIGetClientPointer (x_disp, x_win, &dev);
|
|
|
|
|
|
|
|
byte mask[(XI_LASTEVENT + 7) / 8] = {};
|
|
|
|
XIEventMask evmask = {
|
|
|
|
.deviceid = dev,
|
|
|
|
.mask_len = sizeof (mask),
|
|
|
|
.mask = mask,
|
|
|
|
};
|
|
|
|
XISetMask (mask, XI_RawMotion);
|
|
|
|
XISetMask (mask, XI_RawButtonPress);
|
|
|
|
XISetMask (mask, XI_RawButtonRelease);
|
|
|
|
|
|
|
|
XIGrabModifiers modif = {
|
|
|
|
.modifiers = XIAnyModifier,
|
|
|
|
};
|
|
|
|
|
|
|
|
XIGrabEnter (x_disp, dev, x_win, None, XIGrabModeAsync, XIGrabModeAsync,
|
|
|
|
0, &evmask, 1, &modif);
|
|
|
|
}
|
|
|
|
|
2021-11-22 04:16:05 +00:00
|
|
|
static void
|
|
|
|
in_x11_setup_barriers (int xpos, int ypos, int xlen, int ylen)
|
|
|
|
{
|
|
|
|
if (x11_left_barrier > 0) {
|
|
|
|
XFixesDestroyPointerBarrier (x_disp, x11_left_barrier);
|
|
|
|
}
|
|
|
|
if (x11_right_barrier > 0) {
|
|
|
|
XFixesDestroyPointerBarrier (x_disp, x11_right_barrier);
|
|
|
|
}
|
|
|
|
if (x11_top_barrier > 0) {
|
|
|
|
XFixesDestroyPointerBarrier (x_disp, x11_top_barrier);
|
|
|
|
}
|
|
|
|
if (x11_bottom_barrier > 0) {
|
|
|
|
XFixesDestroyPointerBarrier (x_disp, x11_bottom_barrier);
|
|
|
|
}
|
|
|
|
|
|
|
|
int lx = xpos;
|
|
|
|
int ty = ypos;
|
|
|
|
int rx = xpos + xlen - 1;
|
|
|
|
int by = ypos + ylen - 1;
|
2021-11-22 06:42:22 +00:00
|
|
|
x11_left_barrier = XFixesCreatePointerBarrier (x_disp, x_root,
|
2021-11-22 04:16:05 +00:00
|
|
|
lx, ty-1, lx, by+1,
|
|
|
|
BarrierPositiveX, 0, 0);
|
2021-11-22 06:42:22 +00:00
|
|
|
x11_right_barrier = XFixesCreatePointerBarrier (x_disp, x_root,
|
2021-11-22 04:16:05 +00:00
|
|
|
rx, ty-1, rx, by+1,
|
|
|
|
BarrierNegativeX, 0, 0);
|
2021-11-22 06:42:22 +00:00
|
|
|
x11_top_barrier = XFixesCreatePointerBarrier (x_disp, x_root,
|
2021-11-22 04:16:05 +00:00
|
|
|
lx-1, ty, rx+1, ty,
|
|
|
|
BarrierPositiveY, 0, 0);
|
2021-11-22 06:42:22 +00:00
|
|
|
x11_bottom_barrier = XFixesCreatePointerBarrier (x_disp, x_root,
|
2021-11-22 04:16:05 +00:00
|
|
|
lx-1, by, rx+1, by,
|
|
|
|
BarrierNegativeY, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
x11_app_window (const IE_event_t *ie_event)
|
|
|
|
{
|
|
|
|
__auto_type aw = ie_event->app_window;
|
|
|
|
in_x11_setup_barriers (aw.xpos, aw.ypos, aw.xlen, aw.ylen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
x11_event_handler (const IE_event_t *ie_event, void *unused)
|
|
|
|
{
|
|
|
|
static void (*handlers[ie_event_count]) (const IE_event_t *ie_event) = {
|
|
|
|
[ie_app_window] = x11_app_window,
|
|
|
|
};
|
|
|
|
if (ie_event->type < 0 || ie_event->type >= ie_event_count
|
|
|
|
|| !handlers[ie_event->type]) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
handlers[ie_event->type] (ie_event);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-11-21 12:22:11 +00:00
|
|
|
long
|
|
|
|
IN_X11_Preinit (void)
|
2001-04-15 04:18:22 +00:00
|
|
|
{
|
|
|
|
if (!x_disp)
|
2002-05-14 06:12:29 +00:00
|
|
|
Sys_Error ("IN: No display!!");
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2021-11-21 12:22:11 +00:00
|
|
|
long event_mask = X11_INPUT_MASK;
|
2001-04-15 04:18:22 +00:00
|
|
|
|
2021-11-22 04:16:05 +00:00
|
|
|
x11_event_handler_id = IE_Add_Handler (x11_event_handler, 0);
|
|
|
|
|
[x11] Implement raw keyboard input via XInput2
UI key presses are still handled by regular X events, but in-game
"button" presses arrive via raw keyboard events. This gives transparent
handling of keyboard repeat (UI keys see repeat, game keys do not),
without messing with the server's settings (yay, that was most annoying
when it came to debugging), and the keyboard is never grabbed, so this
is a fairly user-friendly setup.
At first, I wasn't too keen on capturing them from the root window
(thinking about the user's security), but after a lot of investigation,
I found a post by Peter Hutterer
(http://who-t.blogspot.com/2011/09/whats-new-in-xi-21-raw-events.html)
commenting that root window events were added to XInput2 specifically
for games. Since application focus is tracked and unfocused key events
are dropped very early on, there's no way for code further down the
food-chain to know there even was an event, abusing the access would
require modifying the x11 input code, in which case all bets are off
anyway and any attempt at security anywhere in the code will fail,
meaning that nefarious progs code and the like shouldn't be a problem.
2021-11-23 02:18:32 +00:00
|
|
|
x11_have_xi = in_x11_check_xi2 ();
|
|
|
|
|
2001-04-15 04:18:22 +00:00
|
|
|
X11_AddEvent (KeyPress, &event_key);
|
|
|
|
X11_AddEvent (KeyRelease, &event_key);
|
2001-07-05 20:18:23 +00:00
|
|
|
X11_AddEvent (FocusIn, &event_focusin);
|
|
|
|
X11_AddEvent (FocusOut, &event_focusout);
|
2002-01-08 19:33:42 +00:00
|
|
|
X11_AddEvent (SelectionNotify, &selection_notify);
|
2003-02-25 17:19:47 +00:00
|
|
|
X11_AddEvent (EnterNotify, &enter_notify);
|
2021-11-22 04:16:05 +00:00
|
|
|
X11_AddEvent (LeaveNotify, &leave_notify);
|
2001-07-05 20:18:23 +00:00
|
|
|
|
2021-11-22 14:54:31 +00:00
|
|
|
if (x11_have_xi) {
|
|
|
|
X11_AddEvent (GenericEvent, &event_generic);
|
|
|
|
} else {
|
|
|
|
X11_AddEvent (MotionNotify, &event_motion);
|
|
|
|
X11_AddEvent (ButtonPress, &event_button);
|
|
|
|
X11_AddEvent (ButtonRelease, &event_button);
|
2021-11-21 12:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Cmd_AddCommand ("in_paste_buffer", in_paste_buffer_f,
|
|
|
|
"Paste the contents of X's C&P buffer to the console");
|
|
|
|
return event_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
IN_X11_Postinit (void)
|
|
|
|
{
|
|
|
|
if (!x_disp)
|
|
|
|
Sys_Error ("IN: No display!!");
|
|
|
|
if (!x_win)
|
|
|
|
Sys_Error ("IN: No window!!");
|
2021-11-03 13:20:17 +00:00
|
|
|
|
2021-11-22 14:54:31 +00:00
|
|
|
if (x11_have_xi) {
|
|
|
|
in_x11_xi_select_events ();
|
|
|
|
in_x11_xi_setup_grabs ();
|
|
|
|
} else {
|
|
|
|
dga_avail = VID_CheckDGA (x_disp, NULL, NULL, NULL);
|
|
|
|
Sys_MaskPrintf (SYS_vid, "VID_CheckDGA returned %d\n",
|
|
|
|
dga_avail);
|
2021-11-21 12:22:11 +00:00
|
|
|
}
|
|
|
|
}
|
2001-07-06 00:17:09 +00:00
|
|
|
|
2021-11-21 12:22:11 +00:00
|
|
|
static void
|
|
|
|
in_x11_init (void *data)
|
|
|
|
{
|
|
|
|
x11_fd = ConnectionNumber (x_disp);
|
|
|
|
|
|
|
|
x11_add_device (&x11_keyboard_device);
|
2021-11-22 14:54:31 +00:00
|
|
|
x11_add_device (&x11_mouse_device);
|
2001-04-15 04:18:22 +00:00
|
|
|
}
|
|
|
|
|
2021-08-27 00:10:21 +00:00
|
|
|
static void
|
2021-08-30 00:54:36 +00:00
|
|
|
in_x11_clear_states (void *data)
|
2001-04-15 04:18:22 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2021-08-27 00:10:21 +00:00
|
|
|
static in_driver_t in_x11_driver = {
|
2021-11-21 02:33:58 +00:00
|
|
|
.init_cvars = in_x11_init_cvars,
|
2021-08-27 00:10:21 +00:00
|
|
|
.init = in_x11_init,
|
|
|
|
.shutdown = in_x11_shutdown,
|
2021-11-09 13:31:09 +00:00
|
|
|
.set_device_event_data = in_x11_set_device_event_data,
|
|
|
|
.get_device_event_data = in_x11_get_device_event_data,
|
2021-11-05 04:30:01 +00:00
|
|
|
#ifdef X11_USE_SELECT
|
2021-09-27 02:24:35 +00:00
|
|
|
.add_select = in_x11_add_select,
|
|
|
|
.check_select = in_x11_check_select,
|
2021-11-05 04:30:01 +00:00
|
|
|
#else
|
|
|
|
.process_events = in_x11_process_events,
|
|
|
|
#endif
|
2021-08-27 00:10:21 +00:00
|
|
|
.clear_states = in_x11_clear_states,
|
|
|
|
.grab_input = in_x11_grab_input,
|
2021-11-03 13:20:17 +00:00
|
|
|
|
|
|
|
.axis_info = in_x11_axis_info,
|
|
|
|
.button_info = in_x11_button_info,
|
2021-11-18 04:01:33 +00:00
|
|
|
|
|
|
|
.get_axis_name = in_x11_get_axis_name,
|
|
|
|
.get_button_name = in_x11_get_button_name,
|
|
|
|
.get_axis_num = in_x11_get_axis_num,
|
|
|
|
.get_button_num = in_x11_get_button_num,
|
2021-08-27 00:10:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static void __attribute__((constructor))
|
|
|
|
in_x11_register_driver (void)
|
2001-04-17 15:55:33 +00:00
|
|
|
{
|
2021-11-03 13:20:17 +00:00
|
|
|
x11_driver_handle = IN_RegisterDriver (&in_x11_driver, 0);
|
2001-04-17 15:55:33 +00:00
|
|
|
}
|
2021-08-27 00:10:21 +00:00
|
|
|
|
|
|
|
int x11_force_link;
|