early-access version 1611

This commit is contained in:
pineappleEA
2021-04-18 05:35:25 +02:00
parent 16f54e367d
commit 18db69f039
1409 changed files with 545335 additions and 10 deletions

359
externals/SDL/src/core/linux/SDL_dbus.c vendored Executable file
View File

@@ -0,0 +1,359 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "SDL_dbus.h"
#if SDL_USE_LIBDBUS
/* we never link directly to libdbus. */
#include "SDL_loadso.h"
static const char *dbus_library = "libdbus-1.so.3";
static void *dbus_handle = NULL;
static unsigned int screensaver_cookie = 0;
static SDL_DBusContext dbus;
static int
LoadDBUSSyms(void)
{
#define SDL_DBUS_SYM2(x, y) \
if (!(dbus.x = SDL_LoadFunction(dbus_handle, #y))) return -1
#define SDL_DBUS_SYM(x) \
SDL_DBUS_SYM2(x, dbus_##x)
SDL_DBUS_SYM(bus_get_private);
SDL_DBUS_SYM(bus_register);
SDL_DBUS_SYM(bus_add_match);
SDL_DBUS_SYM(connection_open_private);
SDL_DBUS_SYM(connection_set_exit_on_disconnect);
SDL_DBUS_SYM(connection_get_is_connected);
SDL_DBUS_SYM(connection_add_filter);
SDL_DBUS_SYM(connection_try_register_object_path);
SDL_DBUS_SYM(connection_send);
SDL_DBUS_SYM(connection_send_with_reply_and_block);
SDL_DBUS_SYM(connection_close);
SDL_DBUS_SYM(connection_unref);
SDL_DBUS_SYM(connection_flush);
SDL_DBUS_SYM(connection_read_write);
SDL_DBUS_SYM(connection_dispatch);
SDL_DBUS_SYM(message_is_signal);
SDL_DBUS_SYM(message_new_method_call);
SDL_DBUS_SYM(message_append_args);
SDL_DBUS_SYM(message_append_args_valist);
SDL_DBUS_SYM(message_get_args);
SDL_DBUS_SYM(message_get_args_valist);
SDL_DBUS_SYM(message_iter_init);
SDL_DBUS_SYM(message_iter_next);
SDL_DBUS_SYM(message_iter_get_basic);
SDL_DBUS_SYM(message_iter_get_arg_type);
SDL_DBUS_SYM(message_iter_recurse);
SDL_DBUS_SYM(message_unref);
SDL_DBUS_SYM(error_init);
SDL_DBUS_SYM(error_is_set);
SDL_DBUS_SYM(error_free);
SDL_DBUS_SYM(get_local_machine_id);
SDL_DBUS_SYM(free);
SDL_DBUS_SYM(free_string_array);
SDL_DBUS_SYM(shutdown);
#undef SDL_DBUS_SYM
#undef SDL_DBUS_SYM2
return 0;
}
static void
UnloadDBUSLibrary(void)
{
if (dbus_handle != NULL) {
SDL_UnloadObject(dbus_handle);
dbus_handle = NULL;
}
}
static int
LoadDBUSLibrary(void)
{
int retval = 0;
if (dbus_handle == NULL) {
dbus_handle = SDL_LoadObject(dbus_library);
if (dbus_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
} else {
retval = LoadDBUSSyms();
if (retval < 0) {
UnloadDBUSLibrary();
}
}
}
return retval;
}
void
SDL_DBus_Init(void)
{
static SDL_bool is_dbus_available = SDL_TRUE;
if (!is_dbus_available) {
return; /* don't keep trying if this fails. */
}
if (!dbus.session_conn) {
DBusError err;
if (LoadDBUSLibrary() == -1) {
is_dbus_available = SDL_FALSE; /* can't load at all? Don't keep trying. */
return; /* oh well */
}
dbus.error_init(&err);
dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
if (!dbus.error_is_set(&err)) {
dbus.system_conn = dbus.bus_get_private(DBUS_BUS_SYSTEM, &err);
}
if (dbus.error_is_set(&err)) {
dbus.error_free(&err);
SDL_DBus_Quit();
is_dbus_available = SDL_FALSE;
return; /* oh well */
}
dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
dbus.connection_set_exit_on_disconnect(dbus.session_conn, 0);
}
}
void
SDL_DBus_Quit(void)
{
if (dbus.system_conn) {
dbus.connection_close(dbus.system_conn);
dbus.connection_unref(dbus.system_conn);
}
if (dbus.session_conn) {
dbus.connection_close(dbus.session_conn);
dbus.connection_unref(dbus.session_conn);
}
/* Don't do this - bug 3950
dbus_shutdown() is a debug feature which closes all global resources in the dbus library. Calling this should be done by the app, not a library, because if there are multiple users of dbus in the process then SDL could shut it down even though another part is using it.
*/
#if 0
if (dbus.shutdown) {
dbus.shutdown();
}
#endif
SDL_zero(dbus);
UnloadDBUSLibrary();
}
SDL_DBusContext *
SDL_DBus_GetContext(void)
{
if (!dbus_handle || !dbus.session_conn) {
SDL_DBus_Init();
}
return (dbus_handle && dbus.session_conn) ? &dbus : NULL;
}
static SDL_bool
SDL_DBus_CallMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
{
SDL_bool retval = SDL_FALSE;
if (conn) {
DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
if (msg) {
int firstarg;
va_list ap_reply;
va_copy(ap_reply, ap); /* copy the arg list so we don't compete with D-Bus for it */
firstarg = va_arg(ap, int);
if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
if (reply) {
/* skip any input args, get to output args. */
while ((firstarg = va_arg(ap_reply, int)) != DBUS_TYPE_INVALID) {
/* we assume D-Bus already validated all this. */
{ void *dumpptr = va_arg(ap_reply, void*); (void) dumpptr; }
if (firstarg == DBUS_TYPE_ARRAY) {
{ const int dumpint = va_arg(ap_reply, int); (void) dumpint; }
}
}
firstarg = va_arg(ap_reply, int);
if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_get_args_valist(reply, NULL, firstarg, ap_reply)) {
retval = SDL_TRUE;
}
dbus.message_unref(reply);
}
}
va_end(ap_reply);
dbus.message_unref(msg);
}
}
return retval;
}
SDL_bool
SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
{
SDL_bool retval;
va_list ap;
va_start(ap, method);
retval = SDL_DBus_CallMethodInternal(conn, node, path, interface, method, ap);
va_end(ap);
return retval;
}
SDL_bool
SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...)
{
SDL_bool retval;
va_list ap;
va_start(ap, method);
retval = SDL_DBus_CallMethodInternal(dbus.session_conn, node, path, interface, method, ap);
va_end(ap);
return retval;
}
static SDL_bool
SDL_DBus_CallVoidMethodInternal(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, va_list ap)
{
SDL_bool retval = SDL_FALSE;
if (conn) {
DBusMessage *msg = dbus.message_new_method_call(node, path, interface, method);
if (msg) {
int firstarg = va_arg(ap, int);
if ((firstarg == DBUS_TYPE_INVALID) || dbus.message_append_args_valist(msg, firstarg, ap)) {
if (dbus.connection_send(conn, msg, NULL)) {
dbus.connection_flush(conn);
retval = SDL_TRUE;
}
}
dbus.message_unref(msg);
}
}
return retval;
}
SDL_bool
SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...)
{
SDL_bool retval;
va_list ap;
va_start(ap, method);
retval = SDL_DBus_CallVoidMethodInternal(conn, node, path, interface, method, ap);
va_end(ap);
return retval;
}
SDL_bool
SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...)
{
SDL_bool retval;
va_list ap;
va_start(ap, method);
retval = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
va_end(ap);
return retval;
}
SDL_bool
SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
{
SDL_bool retval = SDL_FALSE;
if (conn) {
DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
if (msg) {
if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
if (reply) {
DBusMessageIter iter, sub;
dbus.message_iter_init(reply, &iter);
if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
dbus.message_iter_recurse(&iter, &sub);
if (dbus.message_iter_get_arg_type(&sub) == expectedtype) {
dbus.message_iter_get_basic(&sub, result);
retval = SDL_TRUE;
}
}
dbus.message_unref(reply);
}
}
dbus.message_unref(msg);
}
}
return retval;
}
SDL_bool
SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result)
{
return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, node, path, interface, property, expectedtype, result);
}
void
SDL_DBus_ScreensaverTickle(void)
{
if (screensaver_cookie == 0) { /* no need to tickle if we're inhibiting. */
/* org.gnome.ScreenSaver is the legacy interface, but it'll either do nothing or just be a second harmless tickle on newer systems, so we leave it for now. */
SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
SDL_DBus_CallVoidMethod("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
}
}
SDL_bool
SDL_DBus_ScreensaverInhibit(SDL_bool inhibit)
{
if ( (inhibit && (screensaver_cookie != 0)) || (!inhibit && (screensaver_cookie == 0)) ) {
return SDL_TRUE;
} else {
const char *node = "org.freedesktop.ScreenSaver";
const char *path = "/org/freedesktop/ScreenSaver";
const char *interface = "org.freedesktop.ScreenSaver";
if (inhibit) {
const char *app = "My SDL application";
const char *reason = "Playing a game";
if (!SDL_DBus_CallMethod(node, path, interface, "Inhibit",
DBUS_TYPE_STRING, &app, DBUS_TYPE_STRING, &reason, DBUS_TYPE_INVALID,
DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
return SDL_FALSE;
}
return (screensaver_cookie != 0) ? SDL_TRUE : SDL_FALSE;
} else {
if (!SDL_DBus_CallVoidMethod(node, path, interface, "UnInhibit", DBUS_TYPE_UINT32, &screensaver_cookie, DBUS_TYPE_INVALID)) {
return SDL_FALSE;
}
screensaver_cookie = 0;
}
}
return SDL_TRUE;
}
#endif
/* vi: set ts=4 sw=4 expandtab: */

96
externals/SDL/src/core/linux/SDL_dbus.h vendored Executable file
View File

@@ -0,0 +1,96 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifndef SDL_dbus_h_
#define SDL_dbus_h_
#ifdef HAVE_DBUS_DBUS_H
#define SDL_USE_LIBDBUS 1
#include "SDL_stdinc.h"
#include <dbus/dbus.h>
typedef struct SDL_DBusContext {
DBusConnection *session_conn;
DBusConnection *system_conn;
DBusConnection *(*bus_get_private)(DBusBusType, DBusError *);
dbus_bool_t (*bus_register)(DBusConnection *, DBusError *);
void (*bus_add_match)(DBusConnection *, const char *, DBusError *);
DBusConnection * (*connection_open_private)(const char *, DBusError *);
void (*connection_set_exit_on_disconnect)(DBusConnection *, dbus_bool_t);
dbus_bool_t (*connection_get_is_connected)(DBusConnection *);
dbus_bool_t (*connection_add_filter)(DBusConnection *, DBusHandleMessageFunction, void *, DBusFreeFunction);
dbus_bool_t (*connection_try_register_object_path)(DBusConnection *, const char *,
const DBusObjectPathVTable *, void *, DBusError *);
dbus_bool_t (*connection_send)(DBusConnection *, DBusMessage *, dbus_uint32_t *);
DBusMessage *(*connection_send_with_reply_and_block)(DBusConnection *, DBusMessage *, int, DBusError *);
void (*connection_close)(DBusConnection *);
void (*connection_unref)(DBusConnection *);
void (*connection_flush)(DBusConnection *);
dbus_bool_t (*connection_read_write)(DBusConnection *, int);
DBusDispatchStatus (*connection_dispatch)(DBusConnection *);
dbus_bool_t (*message_is_signal)(DBusMessage *, const char *, const char *);
DBusMessage *(*message_new_method_call)(const char *, const char *, const char *, const char *);
dbus_bool_t (*message_append_args)(DBusMessage *, int, ...);
dbus_bool_t (*message_append_args_valist)(DBusMessage *, int, va_list);
dbus_bool_t (*message_get_args)(DBusMessage *, DBusError *, int, ...);
dbus_bool_t (*message_get_args_valist)(DBusMessage *, DBusError *, int, va_list);
dbus_bool_t (*message_iter_init)(DBusMessage *, DBusMessageIter *);
dbus_bool_t (*message_iter_next)(DBusMessageIter *);
void (*message_iter_get_basic)(DBusMessageIter *, void *);
int (*message_iter_get_arg_type)(DBusMessageIter *);
void (*message_iter_recurse)(DBusMessageIter *, DBusMessageIter *);
void (*message_unref)(DBusMessage *);
void (*error_init)(DBusError *);
dbus_bool_t (*error_is_set)(const DBusError *);
void (*error_free)(DBusError *);
char *(*get_local_machine_id)(void);
void (*free)(void *);
void (*free_string_array)(char **);
void (*shutdown)(void);
} SDL_DBusContext;
extern void SDL_DBus_Init(void);
extern void SDL_DBus_Quit(void);
extern SDL_DBusContext * SDL_DBus_GetContext(void);
/* These use the built-in Session connection. */
extern SDL_bool SDL_DBus_CallMethod(const char *node, const char *path, const char *interface, const char *method, ...);
extern SDL_bool SDL_DBus_CallVoidMethod(const char *node, const char *path, const char *interface, const char *method, ...);
extern SDL_bool SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result);
/* These use whatever connection you like. */
extern SDL_bool SDL_DBus_CallMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
extern SDL_bool SDL_DBus_CallVoidMethodOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *method, ...);
extern SDL_bool SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, const char *node, const char *path, const char *interface, const char *property, const int expectedtype, void *result);
extern void SDL_DBus_ScreensaverTickle(void);
extern SDL_bool SDL_DBus_ScreensaverInhibit(SDL_bool inhibit);
#endif /* HAVE_DBUS_DBUS_H */
#endif /* SDL_dbus_h_ */
/* vi: set ts=4 sw=4 expandtab: */

797
externals/SDL/src/core/linux/SDL_evdev.c vendored Executable file
View File

@@ -0,0 +1,797 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef SDL_INPUT_LINUXEV
/* This is based on the linux joystick driver */
/* References: https://www.kernel.org/doc/Documentation/input/input.txt
* https://www.kernel.org/doc/Documentation/input/event-codes.txt
* /usr/include/linux/input.h
* The evtest application is also useful to debug the protocol
*/
#include "SDL_evdev.h"
#include "SDL_evdev_kbd.h"
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include "SDL.h"
#include "SDL_assert.h"
#include "SDL_endian.h"
#include "SDL_scancode.h"
#include "../../events/SDL_events_c.h"
#include "../../events/scancodes_linux.h" /* adds linux_scancode_table */
#include "../../core/linux/SDL_udev.h"
/* These are not defined in older Linux kernel headers */
#ifndef SYN_DROPPED
#define SYN_DROPPED 3
#endif
#ifndef ABS_MT_SLOT
#define ABS_MT_SLOT 0x2f
#define ABS_MT_POSITION_X 0x35
#define ABS_MT_POSITION_Y 0x36
#define ABS_MT_TRACKING_ID 0x39
#define ABS_MT_PRESSURE 0x3a
#endif
typedef struct SDL_evdevlist_item
{
char *path;
int fd;
/* TODO: use this for every device, not just touchscreen */
int out_of_sync;
/* TODO: expand on this to have data for every possible class (mouse,
keyboard, touchpad, etc.). Also there's probably some things in here we
can pull out to the SDL_evdevlist_item i.e. name */
int is_touchscreen;
struct {
char* name;
int min_x, max_x, range_x;
int min_y, max_y, range_y;
int min_pressure, max_pressure, range_pressure;
int max_slots;
int current_slot;
struct {
enum {
EVDEV_TOUCH_SLOTDELTA_NONE = 0,
EVDEV_TOUCH_SLOTDELTA_DOWN,
EVDEV_TOUCH_SLOTDELTA_UP,
EVDEV_TOUCH_SLOTDELTA_MOVE
} delta;
int tracking_id;
int x, y, pressure;
} * slots;
} * touchscreen_data;
struct SDL_evdevlist_item *next;
} SDL_evdevlist_item;
typedef struct SDL_EVDEV_PrivateData
{
int ref_count;
int num_devices;
SDL_evdevlist_item *first;
SDL_evdevlist_item *last;
SDL_EVDEV_keyboard_state *kbd;
} SDL_EVDEV_PrivateData;
#undef _THIS
#define _THIS SDL_EVDEV_PrivateData *_this
static _THIS = NULL;
static SDL_Scancode SDL_EVDEV_translate_keycode(int keycode);
static void SDL_EVDEV_sync_device(SDL_evdevlist_item *item);
static int SDL_EVDEV_device_removed(const char *dev_path);
#if SDL_USE_LIBUDEV
static int SDL_EVDEV_device_added(const char *dev_path, int udev_class);
static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class,
const char *dev_path);
#endif /* SDL_USE_LIBUDEV */
static Uint8 EVDEV_MouseButtons[] = {
SDL_BUTTON_LEFT, /* BTN_LEFT 0x110 */
SDL_BUTTON_RIGHT, /* BTN_RIGHT 0x111 */
SDL_BUTTON_MIDDLE, /* BTN_MIDDLE 0x112 */
SDL_BUTTON_X1, /* BTN_SIDE 0x113 */
SDL_BUTTON_X2, /* BTN_EXTRA 0x114 */
SDL_BUTTON_X2 + 1, /* BTN_FORWARD 0x115 */
SDL_BUTTON_X2 + 2, /* BTN_BACK 0x116 */
SDL_BUTTON_X2 + 3 /* BTN_TASK 0x117 */
};
static int
SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
{
/* Mice already send relative events through this interface */
return 0;
}
int
SDL_EVDEV_Init(void)
{
if (_this == NULL) {
_this = (SDL_EVDEV_PrivateData*)SDL_calloc(1, sizeof(*_this));
if (_this == NULL) {
return SDL_OutOfMemory();
}
#if SDL_USE_LIBUDEV
if (SDL_UDEV_Init() < 0) {
SDL_free(_this);
_this = NULL;
return -1;
}
/* Set up the udev callback */
if (SDL_UDEV_AddCallback(SDL_EVDEV_udev_callback) < 0) {
SDL_UDEV_Quit();
SDL_free(_this);
_this = NULL;
return -1;
}
/* Force a scan to build the initial device list */
SDL_UDEV_Scan();
#else
/* TODO: Scan the devices manually, like a caveman */
#endif /* SDL_USE_LIBUDEV */
_this->kbd = SDL_EVDEV_kbd_init();
}
SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
_this->ref_count += 1;
return 0;
}
void
SDL_EVDEV_Quit(void)
{
if (_this == NULL) {
return;
}
_this->ref_count -= 1;
if (_this->ref_count < 1) {
#if SDL_USE_LIBUDEV
SDL_UDEV_DelCallback(SDL_EVDEV_udev_callback);
SDL_UDEV_Quit();
#endif /* SDL_USE_LIBUDEV */
SDL_EVDEV_kbd_quit(_this->kbd);
/* Remove existing devices */
while(_this->first != NULL) {
SDL_EVDEV_device_removed(_this->first->path);
}
SDL_assert(_this->first == NULL);
SDL_assert(_this->last == NULL);
SDL_assert(_this->num_devices == 0);
SDL_free(_this);
_this = NULL;
}
}
#if SDL_USE_LIBUDEV
static void SDL_EVDEV_udev_callback(SDL_UDEV_deviceevent udev_event, int udev_class,
const char* dev_path)
{
if (dev_path == NULL) {
return;
}
switch(udev_event) {
case SDL_UDEV_DEVICEADDED:
if (!(udev_class & (SDL_UDEV_DEVICE_MOUSE | SDL_UDEV_DEVICE_KEYBOARD |
SDL_UDEV_DEVICE_TOUCHSCREEN)))
return;
SDL_EVDEV_device_added(dev_path, udev_class);
break;
case SDL_UDEV_DEVICEREMOVED:
SDL_EVDEV_device_removed(dev_path);
break;
default:
break;
}
}
#endif /* SDL_USE_LIBUDEV */
void
SDL_EVDEV_Poll(void)
{
struct input_event events[32];
int i, j, len;
SDL_evdevlist_item *item;
SDL_Scancode scan_code;
int mouse_button;
SDL_Mouse *mouse;
float norm_x, norm_y, norm_pressure;
if (!_this) {
return;
}
#if SDL_USE_LIBUDEV
SDL_UDEV_Poll();
#endif
mouse = SDL_GetMouse();
for (item = _this->first; item != NULL; item = item->next) {
while ((len = read(item->fd, events, (sizeof events))) > 0) {
len /= sizeof(events[0]);
for (i = 0; i < len; ++i) {
/* special handling for touchscreen, that should eventually be
used for all devices */
if (item->out_of_sync && item->is_touchscreen &&
events[i].type == EV_SYN && events[i].code != SYN_REPORT) {
break;
}
switch (events[i].type) {
case EV_KEY:
if (events[i].code >= BTN_MOUSE && events[i].code < BTN_MOUSE + SDL_arraysize(EVDEV_MouseButtons)) {
mouse_button = events[i].code - BTN_MOUSE;
if (events[i].value == 0) {
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_RELEASED, EVDEV_MouseButtons[mouse_button]);
} else if (events[i].value == 1) {
SDL_SendMouseButton(mouse->focus, mouse->mouseID, SDL_PRESSED, EVDEV_MouseButtons[mouse_button]);
}
break;
}
/* BTH_TOUCH event value 1 indicates there is contact with
a touchscreen or trackpad (earlist finger's current
position is sent in EV_ABS ABS_X/ABS_Y, switching to
next finger after earlist is released) */
if (item->is_touchscreen && events[i].code == BTN_TOUCH) {
if (item->touchscreen_data->max_slots == 1) {
if (events[i].value)
item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
else
item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_UP;
}
break;
}
/* Probably keyboard */
scan_code = SDL_EVDEV_translate_keycode(events[i].code);
if (scan_code != SDL_SCANCODE_UNKNOWN) {
if (events[i].value == 0) {
SDL_SendKeyboardKey(SDL_RELEASED, scan_code);
} else if (events[i].value == 1 || events[i].value == 2 /* key repeated */) {
SDL_SendKeyboardKey(SDL_PRESSED, scan_code);
}
}
SDL_EVDEV_kbd_keycode(_this->kbd, events[i].code, events[i].value);
break;
case EV_ABS:
switch(events[i].code) {
case ABS_MT_SLOT:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
item->touchscreen_data->current_slot = events[i].value;
break;
case ABS_MT_TRACKING_ID:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
if (events[i].value >= 0) {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].tracking_id = events[i].value;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
} else {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_UP;
}
break;
case ABS_MT_POSITION_X:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].x = events[i].value;
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
case ABS_MT_POSITION_Y:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].y = events[i].value;
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
case ABS_MT_PRESSURE:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
item->touchscreen_data->slots[item->touchscreen_data->current_slot].pressure = events[i].value;
if (item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta == EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[item->touchscreen_data->current_slot].delta = EVDEV_TOUCH_SLOTDELTA_MOVE;
}
break;
case ABS_X:
if (item->is_touchscreen) {
if (item->touchscreen_data->max_slots != 1)
break;
item->touchscreen_data->slots[0].x = events[i].value;
} else
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
break;
case ABS_Y:
if (item->is_touchscreen) {
if (item->touchscreen_data->max_slots != 1)
break;
item->touchscreen_data->slots[0].y = events[i].value;
} else
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
break;
default:
break;
}
break;
case EV_REL:
switch(events[i].code) {
case REL_X:
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, events[i].value, 0);
break;
case REL_Y:
SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_TRUE, 0, events[i].value);
break;
case REL_WHEEL:
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, 0, events[i].value, SDL_MOUSEWHEEL_NORMAL);
break;
case REL_HWHEEL:
SDL_SendMouseWheel(mouse->focus, mouse->mouseID, events[i].value, 0, SDL_MOUSEWHEEL_NORMAL);
break;
default:
break;
}
break;
case EV_SYN:
switch (events[i].code) {
case SYN_REPORT:
if (!item->is_touchscreen) /* FIXME: temp hack */
break;
for(j = 0; j < item->touchscreen_data->max_slots; j++) {
norm_x = (float)(item->touchscreen_data->slots[j].x - item->touchscreen_data->min_x) /
(float)item->touchscreen_data->range_x;
norm_y = (float)(item->touchscreen_data->slots[j].y - item->touchscreen_data->min_y) /
(float)item->touchscreen_data->range_y;
if (item->touchscreen_data->range_pressure > 0) {
norm_pressure = (float)(item->touchscreen_data->slots[j].pressure - item->touchscreen_data->min_pressure) /
(float)item->touchscreen_data->range_pressure;
} else {
/* This touchscreen does not support pressure */
norm_pressure = 1.0f;
}
/* FIXME: the touch's window shouldn't be null, but
* the coordinate space of touch positions needs to
* be window-relative in that case. */
switch(item->touchscreen_data->slots[j].delta) {
case EVDEV_TOUCH_SLOTDELTA_DOWN:
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_TRUE, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_UP:
SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].tracking_id = -1;
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
case EVDEV_TOUCH_SLOTDELTA_MOVE:
SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, norm_x, norm_y, norm_pressure);
item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
break;
default:
break;
}
}
if (item->out_of_sync)
item->out_of_sync = 0;
break;
case SYN_DROPPED:
if (item->is_touchscreen)
item->out_of_sync = 1;
SDL_EVDEV_sync_device(item);
break;
default:
break;
}
break;
}
}
}
}
}
static SDL_Scancode
SDL_EVDEV_translate_keycode(int keycode)
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
if (keycode < SDL_arraysize(linux_scancode_table)) {
scancode = linux_scancode_table[keycode];
if (scancode == SDL_SCANCODE_UNKNOWN) {
/* BTN_TOUCH is handled elsewhere, but we might still end up here if
you get an unexpected BTN_TOUCH from something SDL believes is not
a touch device. In this case, we'd rather not get a misleading
SDL_Log message about an unknown key. */
if (keycode != BTN_TOUCH) {
SDL_Log("The key you just pressed is not recognized by SDL. To help "
"get this fixed, please report this to the SDL forums/mailing list "
"<https://discourse.libsdl.org/> EVDEV KeyCode %d", keycode);
}
}
}
return scancode;
}
#ifdef SDL_USE_LIBUDEV
static int
SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
{
int ret, i;
unsigned long xreq, yreq;
char name[64];
struct input_absinfo abs_info;
if (!item->is_touchscreen)
return 0;
item->touchscreen_data = SDL_calloc(1, sizeof(*item->touchscreen_data));
if (item->touchscreen_data == NULL)
return SDL_OutOfMemory();
ret = ioctl(item->fd, EVIOCGNAME(sizeof(name)), name);
if (ret < 0) {
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen name");
}
item->touchscreen_data->name = SDL_strdup(name);
if (item->touchscreen_data->name == NULL) {
SDL_free(item->touchscreen_data);
return SDL_OutOfMemory();
}
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen limits");
}
if (abs_info.maximum == 0) {
item->touchscreen_data->max_slots = 1;
xreq = EVIOCGABS(ABS_X);
yreq = EVIOCGABS(ABS_Y);
} else {
item->touchscreen_data->max_slots = abs_info.maximum + 1;
xreq = EVIOCGABS(ABS_MT_POSITION_X);
yreq = EVIOCGABS(ABS_MT_POSITION_Y);
}
ret = ioctl(item->fd, xreq, &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen limits");
}
item->touchscreen_data->min_x = abs_info.minimum;
item->touchscreen_data->max_x = abs_info.maximum;
item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
ret = ioctl(item->fd, yreq, &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen limits");
}
item->touchscreen_data->min_y = abs_info.minimum;
item->touchscreen_data->max_y = abs_info.maximum;
item->touchscreen_data->range_y = abs_info.maximum - abs_info.minimum;
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_PRESSURE), &abs_info);
if (ret < 0) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_SetError("Failed to get evdev touchscreen limits");
}
item->touchscreen_data->min_pressure = abs_info.minimum;
item->touchscreen_data->max_pressure = abs_info.maximum;
item->touchscreen_data->range_pressure = abs_info.maximum - abs_info.minimum;
item->touchscreen_data->slots = SDL_calloc(
item->touchscreen_data->max_slots,
sizeof(*item->touchscreen_data->slots));
if (item->touchscreen_data->slots == NULL) {
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return SDL_OutOfMemory();
}
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
item->touchscreen_data->slots[i].tracking_id = -1;
}
ret = SDL_AddTouch(item->fd, /* I guess our fd is unique enough */
SDL_TOUCH_DEVICE_DIRECT,
item->touchscreen_data->name);
if (ret < 0) {
SDL_free(item->touchscreen_data->slots);
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
return ret;
}
return 0;
}
#endif /* SDL_USE_LIBUDEV */
static void
SDL_EVDEV_destroy_touchscreen(SDL_evdevlist_item* item) {
if (!item->is_touchscreen)
return;
SDL_DelTouch(item->fd);
SDL_free(item->touchscreen_data->slots);
SDL_free(item->touchscreen_data->name);
SDL_free(item->touchscreen_data);
}
static void
SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
{
#ifdef EVIOCGMTSLOTS
int i, ret;
struct input_absinfo abs_info;
/*
* struct input_mt_request_layout {
* __u32 code;
* __s32 values[num_slots];
* };
*
* this is the structure we're trying to emulate
*/
Uint32* mt_req_code;
Sint32* mt_req_values;
size_t mt_req_size;
/* TODO: sync devices other than touchscreen */
if (!item->is_touchscreen)
return;
mt_req_size = sizeof(*mt_req_code) +
sizeof(*mt_req_values) * item->touchscreen_data->max_slots;
mt_req_code = SDL_calloc(1, mt_req_size);
if (mt_req_code == NULL) {
return;
}
mt_req_values = (Sint32*)mt_req_code + 1;
*mt_req_code = ABS_MT_TRACKING_ID;
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
return;
}
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
/*
* This doesn't account for the very edge case of the user removing their
* finger and replacing it on the screen during the time we're out of sync,
* which'll mean that we're not going from down -> up or up -> down, we're
* going from down -> down but with a different tracking id, meaning we'd
* have to tell SDL of the two events, but since we wait till SYN_REPORT in
* SDL_EVDEV_Poll to tell SDL, the current structure of this code doesn't
* allow it. Lets just pray to God it doesn't happen.
*/
if (item->touchscreen_data->slots[i].tracking_id < 0 &&
mt_req_values[i] >= 0) {
item->touchscreen_data->slots[i].tracking_id = mt_req_values[i];
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
} else if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
mt_req_values[i] < 0) {
item->touchscreen_data->slots[i].tracking_id = -1;
item->touchscreen_data->slots[i].delta = EVDEV_TOUCH_SLOTDELTA_UP;
}
}
*mt_req_code = ABS_MT_POSITION_X;
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
return;
}
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
item->touchscreen_data->slots[i].x != mt_req_values[i]) {
item->touchscreen_data->slots[i].x = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[i].delta =
EVDEV_TOUCH_SLOTDELTA_MOVE;
}
}
}
*mt_req_code = ABS_MT_POSITION_Y;
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
return;
}
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
item->touchscreen_data->slots[i].y != mt_req_values[i]) {
item->touchscreen_data->slots[i].y = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[i].delta =
EVDEV_TOUCH_SLOTDELTA_MOVE;
}
}
}
*mt_req_code = ABS_MT_PRESSURE;
ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);
if (ret < 0) {
SDL_free(mt_req_code);
return;
}
for(i = 0; i < item->touchscreen_data->max_slots; i++) {
if (item->touchscreen_data->slots[i].tracking_id >= 0 &&
item->touchscreen_data->slots[i].pressure != mt_req_values[i]) {
item->touchscreen_data->slots[i].pressure = mt_req_values[i];
if (item->touchscreen_data->slots[i].delta ==
EVDEV_TOUCH_SLOTDELTA_NONE) {
item->touchscreen_data->slots[i].delta =
EVDEV_TOUCH_SLOTDELTA_MOVE;
}
}
}
ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
if (ret < 0) {
SDL_free(mt_req_code);
return;
}
item->touchscreen_data->current_slot = abs_info.value;
SDL_free(mt_req_code);
#endif /* EVIOCGMTSLOTS */
}
#if SDL_USE_LIBUDEV
static int
SDL_EVDEV_device_added(const char *dev_path, int udev_class)
{
int ret;
SDL_evdevlist_item *item;
/* Check to make sure it's not already in list. */
for (item = _this->first; item != NULL; item = item->next) {
if (SDL_strcmp(dev_path, item->path) == 0) {
return -1; /* already have this one */
}
}
item = (SDL_evdevlist_item *) SDL_calloc(1, sizeof (SDL_evdevlist_item));
if (item == NULL) {
return SDL_OutOfMemory();
}
item->fd = open(dev_path, O_RDONLY | O_NONBLOCK);
if (item->fd < 0) {
SDL_free(item);
return SDL_SetError("Unable to open %s", dev_path);
}
item->path = SDL_strdup(dev_path);
if (item->path == NULL) {
close(item->fd);
SDL_free(item);
return SDL_OutOfMemory();
}
if (udev_class & SDL_UDEV_DEVICE_TOUCHSCREEN) {
item->is_touchscreen = 1;
if ((ret = SDL_EVDEV_init_touchscreen(item)) < 0) {
close(item->fd);
SDL_free(item);
return ret;
}
}
if (_this->last == NULL) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
_this->last = item;
}
SDL_EVDEV_sync_device(item);
return _this->num_devices++;
}
#endif /* SDL_USE_LIBUDEV */
static int
SDL_EVDEV_device_removed(const char *dev_path)
{
SDL_evdevlist_item *item;
SDL_evdevlist_item *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
/* found it, remove it. */
if (SDL_strcmp(dev_path, item->path) == 0) {
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
_this->first = item->next;
}
if (item == _this->last) {
_this->last = prev;
}
if (item->is_touchscreen) {
SDL_EVDEV_destroy_touchscreen(item);
}
close(item->fd);
SDL_free(item->path);
SDL_free(item);
_this->num_devices--;
return 0;
}
prev = item;
}
return -1;
}
#endif /* SDL_INPUT_LINUXEV */
/* vi: set ts=4 sw=4 expandtab: */

39
externals/SDL/src/core/linux/SDL_evdev.h vendored Executable file
View File

@@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifndef SDL_evdev_h_
#define SDL_evdev_h_
#ifdef SDL_INPUT_LINUXEV
#include "SDL_events.h"
extern int SDL_EVDEV_Init(void);
extern void SDL_EVDEV_Quit(void);
extern void SDL_EVDEV_Poll(void);
#endif /* SDL_INPUT_LINUXEV */
#endif /* SDL_evdev_h_ */
/* vi: set ts=4 sw=4 expandtab: */

842
externals/SDL/src/core/linux/SDL_evdev_kbd.c vendored Executable file
View File

@@ -0,0 +1,842 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#include "SDL_evdev_kbd.h"
#include "SDL_hints.h"
#ifdef SDL_INPUT_LINUXKD
/* This logic is adapted from drivers/tty/vt/keyboard.c in the Linux kernel source */
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include <linux/vt.h>
#include <linux/tiocl.h> /* for TIOCL_GETSHIFTSTATE */
#include <signal.h>
#include "../../events/SDL_events_c.h"
#include "SDL_evdev_kbd_default_accents.h"
#include "SDL_evdev_kbd_default_keymap.h"
/* These are not defined in older Linux kernel headers */
#ifndef K_UNICODE
#define K_UNICODE 0x03
#endif
#ifndef K_OFF
#define K_OFF 0x04
#endif
/*
* Handler Tables.
*/
#define K_HANDLERS\
k_self, k_fn, k_spec, k_pad,\
k_dead, k_cons, k_cur, k_shift,\
k_meta, k_ascii, k_lock, k_lowercase,\
k_slock, k_dead2, k_brl, k_ignore
typedef void (k_handler_fn)(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag);
static k_handler_fn K_HANDLERS;
static k_handler_fn *k_handler[16] = { K_HANDLERS };
typedef void (fn_handler_fn)(SDL_EVDEV_keyboard_state *kbd);
static void fn_enter(SDL_EVDEV_keyboard_state *kbd);
static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd);
static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd);
static void fn_num(SDL_EVDEV_keyboard_state *kbd);
static void fn_compose(SDL_EVDEV_keyboard_state *kbd);
static fn_handler_fn *fn_handler[] =
{
NULL, fn_enter, NULL, NULL,
NULL, NULL, NULL, fn_caps_toggle,
fn_num, NULL, NULL, NULL,
NULL, fn_caps_on, fn_compose, NULL,
NULL, NULL, NULL, fn_num
};
/*
* Keyboard State
*/
struct SDL_EVDEV_keyboard_state
{
int console_fd;
int old_kbd_mode;
unsigned short **key_maps;
unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */
SDL_bool dead_key_next;
int npadch; /* -1 or number assembled on pad */
struct kbdiacrs *accents;
unsigned int diacr;
SDL_bool rep; /* flag telling character repeat */
unsigned char lockstate;
unsigned char slockstate;
unsigned char ledflagstate;
char shift_state;
char text[128];
unsigned int text_len;
};
#ifdef DUMP_ACCENTS
static void SDL_EVDEV_dump_accents(SDL_EVDEV_keyboard_state *kbd)
{
unsigned int i;
printf("static struct kbdiacrs default_accents = {\n");
printf(" %d,\n", kbd->accents->kb_cnt);
printf(" {\n");
for (i = 0; i < kbd->accents->kb_cnt; ++i) {
struct kbdiacr *diacr = &kbd->accents->kbdiacr[i];
printf(" { 0x%.2x, 0x%.2x, 0x%.2x },\n",
diacr->diacr, diacr->base, diacr->result);
}
while (i < 256) {
printf(" { 0x00, 0x00, 0x00 },\n");
++i;
}
printf(" }\n");
printf("};\n");
}
#endif /* DUMP_ACCENTS */
#ifdef DUMP_KEYMAP
static void SDL_EVDEV_dump_keymap(SDL_EVDEV_keyboard_state *kbd)
{
int i, j;
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
if (kbd->key_maps[i]) {
printf("static unsigned short default_key_map_%d[NR_KEYS] = {", i);
for (j = 0; j < NR_KEYS; ++j) {
if ((j%8) == 0) {
printf("\n ");
}
printf("0x%.4x, ", kbd->key_maps[i][j]);
}
printf("\n};\n");
}
}
printf("\n");
printf("static unsigned short *default_key_maps[MAX_NR_KEYMAPS] = {\n");
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
if (kbd->key_maps[i]) {
printf(" default_key_map_%d,\n", i);
} else {
printf(" NULL,\n");
}
}
printf("};\n");
}
#endif /* DUMP_KEYMAP */
static int SDL_EVDEV_kbd_load_keymaps(SDL_EVDEV_keyboard_state *kbd)
{
int i, j;
kbd->key_maps = (unsigned short **)SDL_calloc(MAX_NR_KEYMAPS, sizeof(unsigned short *));
if (!kbd->key_maps) {
return -1;
}
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
struct kbentry kbe;
kbe.kb_table = i;
kbe.kb_index = 0;
if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
return -1;
}
if (kbe.kb_value == K_NOSUCHMAP) {
continue;
}
kbd->key_maps[i] = (unsigned short *)SDL_malloc(NR_KEYS * sizeof(unsigned short));
if (!kbd->key_maps[i]) {
return -1;
}
for (j = 0; j < NR_KEYS; ++j) {
kbe.kb_table = i;
kbe.kb_index = j;
if (ioctl(kbd->console_fd, KDGKBENT, &kbe) < 0) {
return -1;
}
kbd->key_maps[i][j] = (kbe.kb_value ^ 0xf000);
}
}
return 0;
}
static SDL_EVDEV_keyboard_state * kbd_cleanup_state = NULL;
static int kbd_cleanup_sigactions_installed = 0;
static int kbd_cleanup_atexit_installed = 0;
static struct sigaction old_sigaction[NSIG];
static int fatal_signals[] =
{
/* Handlers for SIGTERM and SIGINT are installed in SDL_QuitInit. */
SIGHUP, SIGQUIT, SIGILL, SIGABRT,
SIGFPE, SIGSEGV, SIGPIPE, SIGBUS,
SIGSYS
};
static void kbd_cleanup(void)
{
SDL_EVDEV_keyboard_state* kbd = kbd_cleanup_state;
if (kbd == NULL) {
return;
}
kbd_cleanup_state = NULL;
ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
}
void
SDL_EVDEV_kbd_reraise_signal(int sig)
{
raise(sig);
}
siginfo_t* SDL_EVDEV_kdb_cleanup_siginfo = NULL;
void* SDL_EVDEV_kdb_cleanup_ucontext = NULL;
static void kbd_cleanup_signal_action(int signum, siginfo_t* info, void* ucontext)
{
struct sigaction* old_action_p = &(old_sigaction[signum]);
sigset_t sigset;
/* Restore original signal handler before going any further. */
sigaction(signum, old_action_p, NULL);
/* Unmask current signal. */
sigemptyset(&sigset);
sigaddset(&sigset, signum);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
/* Save original signal info and context for archeologists. */
SDL_EVDEV_kdb_cleanup_siginfo = info;
SDL_EVDEV_kdb_cleanup_ucontext = ucontext;
/* Restore keyboard. */
kbd_cleanup();
/* Reraise signal. */
SDL_EVDEV_kbd_reraise_signal(signum);
}
static void kbd_unregister_emerg_cleanup()
{
int tabidx, signum;
kbd_cleanup_state = NULL;
if (!kbd_cleanup_sigactions_installed) {
return;
}
kbd_cleanup_sigactions_installed = 0;
for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
struct sigaction* old_action_p;
struct sigaction cur_action;
signum = fatal_signals[tabidx];
old_action_p = &(old_sigaction[signum]);
/* Examine current signal action */
if (sigaction(signum, NULL, &cur_action))
continue;
/* Check if action installed and not modifed */
if (!(cur_action.sa_flags & SA_SIGINFO)
|| cur_action.sa_sigaction != &kbd_cleanup_signal_action)
continue;
/* Restore original action */
sigaction(signum, old_action_p, NULL);
}
}
static void kbd_cleanup_atexit(void)
{
/* Restore keyboard. */
kbd_cleanup();
/* Try to restore signal handlers in case shared library is being unloaded */
kbd_unregister_emerg_cleanup();
}
static void kbd_register_emerg_cleanup(SDL_EVDEV_keyboard_state * kbd)
{
int tabidx, signum;
if (kbd_cleanup_state != NULL) {
return;
}
kbd_cleanup_state = kbd;
if (!kbd_cleanup_atexit_installed) {
/* Since glibc 2.2.3, atexit() (and on_exit(3)) can be used within a shared library to establish
* functions that are called when the shared library is unloaded.
* -- man atexit(3)
*/
atexit(kbd_cleanup_atexit);
kbd_cleanup_atexit_installed = 1;
}
if (kbd_cleanup_sigactions_installed) {
return;
}
kbd_cleanup_sigactions_installed = 1;
for (tabidx = 0; tabidx < sizeof(fatal_signals) / sizeof(fatal_signals[0]); ++tabidx) {
struct sigaction* old_action_p;
struct sigaction new_action;
signum = fatal_signals[tabidx];
old_action_p = &(old_sigaction[signum]);
if (sigaction(signum, NULL, old_action_p))
continue;
/* Skip SIGHUP and SIGPIPE if handler is already installed
* - assume the handler will do the cleanup
*/
if ((signum == SIGHUP || signum == SIGPIPE)
&& (old_action_p->sa_handler != SIG_DFL
|| (void (*)(int))old_action_p->sa_sigaction != SIG_DFL))
continue;
new_action = *old_action_p;
new_action.sa_flags |= SA_SIGINFO;
new_action.sa_sigaction = &kbd_cleanup_signal_action;
sigaction(signum, &new_action, NULL);
}
}
SDL_EVDEV_keyboard_state *
SDL_EVDEV_kbd_init(void)
{
SDL_EVDEV_keyboard_state *kbd;
int i;
char flag_state;
char shift_state[ sizeof (long) ] = {TIOCL_GETSHIFTSTATE, 0};
kbd = (SDL_EVDEV_keyboard_state *)SDL_calloc(1, sizeof(*kbd));
if (!kbd) {
return NULL;
}
kbd->npadch = -1;
/* This might fail if we're not connected to a tty (e.g. on the Steam Link) */
kbd->console_fd = open("/dev/tty", O_RDONLY);
if (ioctl(kbd->console_fd, TIOCLINUX, shift_state) == 0) {
kbd->shift_state = *shift_state;
}
if (ioctl(kbd->console_fd, KDGKBLED, &flag_state) == 0) {
kbd->ledflagstate = flag_state;
}
kbd->accents = &default_accents;
if (ioctl(kbd->console_fd, KDGKBDIACR, kbd->accents) < 0) {
/* No worries, we'll use the default accent table */
}
kbd->key_maps = default_key_maps;
if (ioctl(kbd->console_fd, KDGKBMODE, &kbd->old_kbd_mode) == 0) {
/* Set the keyboard in UNICODE mode and load the keymaps */
ioctl(kbd->console_fd, KDSKBMODE, K_UNICODE);
if (SDL_EVDEV_kbd_load_keymaps(kbd) < 0) {
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
if (kbd->key_maps[i]) {
SDL_free(kbd->key_maps[i]);
}
}
SDL_free(kbd->key_maps);
kbd->key_maps = default_key_maps;
}
/* Allow inhibiting keyboard mute with env. variable for debugging etc. */
if (getenv("SDL_INPUT_LINUX_KEEP_KBD") == NULL) {
/* Mute the keyboard so keystrokes only generate evdev events
* and do not leak through to the console
*/
ioctl(kbd->console_fd, KDSKBMODE, K_OFF);
/* Make sure to restore keyboard if application fails to call
* SDL_Quit before exit or fatal signal is raised.
*/
if (!SDL_GetHintBoolean(SDL_HINT_NO_SIGNAL_HANDLERS, SDL_FALSE)) {
kbd_register_emerg_cleanup(kbd);
}
}
}
#ifdef DUMP_ACCENTS
SDL_EVDEV_dump_accents(kbd);
#endif
#ifdef DUMP_KEYMAP
SDL_EVDEV_dump_keymap(kbd);
#endif
return kbd;
}
void
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *kbd)
{
if (!kbd) {
return;
}
kbd_unregister_emerg_cleanup();
if (kbd->console_fd >= 0) {
/* Restore the original keyboard mode */
ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
close(kbd->console_fd);
kbd->console_fd = -1;
}
if (kbd->key_maps && kbd->key_maps != default_key_maps) {
int i;
for (i = 0; i < MAX_NR_KEYMAPS; ++i) {
if (kbd->key_maps[i]) {
SDL_free(kbd->key_maps[i]);
}
}
SDL_free(kbd->key_maps);
}
SDL_free(kbd);
}
/*
* Helper Functions.
*/
static void put_queue(SDL_EVDEV_keyboard_state *kbd, uint c)
{
/* c is already part of a UTF-8 sequence and safe to add as a character */
if (kbd->text_len < (sizeof(kbd->text)-1)) {
kbd->text[kbd->text_len++] = (char)c;
}
}
static void put_utf8(SDL_EVDEV_keyboard_state *kbd, uint c)
{
if (c < 0x80)
/* 0******* */
put_queue(kbd, c);
else if (c < 0x800) {
/* 110***** 10****** */
put_queue(kbd, 0xc0 | (c >> 6));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x10000) {
if (c >= 0xD800 && c < 0xE000)
return;
if (c == 0xFFFF)
return;
/* 1110**** 10****** 10****** */
put_queue(kbd, 0xe0 | (c >> 12));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
} else if (c < 0x110000) {
/* 11110*** 10****** 10****** 10****** */
put_queue(kbd, 0xf0 | (c >> 18));
put_queue(kbd, 0x80 | ((c >> 12) & 0x3f));
put_queue(kbd, 0x80 | ((c >> 6) & 0x3f));
put_queue(kbd, 0x80 | (c & 0x3f));
}
}
/*
* We have a combining character DIACR here, followed by the character CH.
* If the combination occurs in the table, return the corresponding value.
* Otherwise, if CH is a space or equals DIACR, return DIACR.
* Otherwise, conclude that DIACR was not combining after all,
* queue it and return CH.
*/
static unsigned int handle_diacr(SDL_EVDEV_keyboard_state *kbd, unsigned int ch)
{
unsigned int d = kbd->diacr;
unsigned int i;
kbd->diacr = 0;
for (i = 0; i < kbd->accents->kb_cnt; i++) {
if (kbd->accents->kbdiacr[i].diacr == d &&
kbd->accents->kbdiacr[i].base == ch) {
return kbd->accents->kbdiacr[i].result;
}
}
if (ch == ' ' || ch == d)
return d;
put_utf8(kbd, d);
return ch;
}
static int vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
return (kbd->ledflagstate & flag) != 0;
}
static void set_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate |= flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void clr_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate &= ~flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
static void chg_vc_kbd_lock(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->lockstate ^= 1 << flag;
}
static void chg_vc_kbd_slock(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->slockstate ^= 1 << flag;
}
static void chg_vc_kbd_led(SDL_EVDEV_keyboard_state *kbd, int flag)
{
kbd->ledflagstate ^= flag;
ioctl(kbd->console_fd, KDSETLED, (unsigned long)(kbd->ledflagstate));
}
/*
* Special function handlers
*/
static void fn_enter(SDL_EVDEV_keyboard_state *kbd)
{
if (kbd->diacr) {
put_utf8(kbd, kbd->diacr);
kbd->diacr = 0;
}
}
static void fn_caps_toggle(SDL_EVDEV_keyboard_state *kbd)
{
if (kbd->rep)
return;
chg_vc_kbd_led(kbd, K_CAPSLOCK);
}
static void fn_caps_on(SDL_EVDEV_keyboard_state *kbd)
{
if (kbd->rep)
return;
set_vc_kbd_led(kbd, K_CAPSLOCK);
}
static void fn_num(SDL_EVDEV_keyboard_state *kbd)
{
if (!kbd->rep)
chg_vc_kbd_led(kbd, K_NUMLOCK);
}
static void fn_compose(SDL_EVDEV_keyboard_state *kbd)
{
kbd->dead_key_next = SDL_TRUE;
}
/*
* Special key handlers
*/
static void k_ignore(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_spec(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
if (up_flag)
return;
if (value >= SDL_arraysize(fn_handler))
return;
if (fn_handler[value])
fn_handler[value](kbd);
}
static void k_lowercase(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_self(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
if (up_flag)
return; /* no action, if this is a key release */
if (kbd->diacr)
value = handle_diacr(kbd, value);
if (kbd->dead_key_next) {
kbd->dead_key_next = SDL_FALSE;
kbd->diacr = value;
return;
}
put_utf8(kbd, value);
}
static void k_deadunicode(SDL_EVDEV_keyboard_state *kbd, unsigned int value, char up_flag)
{
if (up_flag)
return;
kbd->diacr = (kbd->diacr ? handle_diacr(kbd, value) : value);
}
static void k_dead(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
k_deadunicode(kbd, ret_diacr[value], up_flag);
}
static void k_dead2(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
k_deadunicode(kbd, value, up_flag);
}
static void k_cons(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_fn(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_cur(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_pad(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
static const char pad_chars[] = "0123456789+-*/\015,.?()#";
if (up_flag)
return; /* no action, if this is a key release */
if (!vc_kbd_led(kbd, K_NUMLOCK)) {
/* unprintable action */
return;
}
put_queue(kbd, pad_chars[value]);
}
static void k_shift(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
int old_state = kbd->shift_state;
if (kbd->rep)
return;
/*
* Mimic typewriter:
* a CapsShift key acts like Shift but undoes CapsLock
*/
if (value == KVAL(K_CAPSSHIFT)) {
value = KVAL(K_SHIFT);
if (!up_flag)
clr_vc_kbd_led(kbd, K_CAPSLOCK);
}
if (up_flag) {
/*
* handle the case that two shift or control
* keys are depressed simultaneously
*/
if (kbd->shift_down[value])
kbd->shift_down[value]--;
} else
kbd->shift_down[value]++;
if (kbd->shift_down[value])
kbd->shift_state |= (1 << value);
else
kbd->shift_state &= ~(1 << value);
/* kludge */
if (up_flag && kbd->shift_state != old_state && kbd->npadch != -1) {
put_utf8(kbd, kbd->npadch);
kbd->npadch = -1;
}
}
static void k_meta(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
static void k_ascii(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
int base;
if (up_flag)
return;
if (value < 10) {
/* decimal input of code, while Alt depressed */
base = 10;
} else {
/* hexadecimal input of code, while AltGr depressed */
value -= 10;
base = 16;
}
if (kbd->npadch == -1)
kbd->npadch = value;
else
kbd->npadch = kbd->npadch * base + value;
}
static void k_lock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
if (up_flag || kbd->rep)
return;
chg_vc_kbd_lock(kbd, value);
}
static void k_slock(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
k_shift(kbd, value, up_flag);
if (up_flag || kbd->rep)
return;
chg_vc_kbd_slock(kbd, value);
/* try to make Alt, oops, AltGr and such work */
if (!kbd->key_maps[kbd->lockstate ^ kbd->slockstate]) {
kbd->slockstate = 0;
chg_vc_kbd_slock(kbd, value);
}
}
static void k_brl(SDL_EVDEV_keyboard_state *kbd, unsigned char value, char up_flag)
{
}
void
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *kbd, unsigned int keycode, int down)
{
unsigned char shift_final;
unsigned char type;
unsigned short *key_map;
unsigned short keysym;
if (!kbd) {
return;
}
kbd->rep = (down == 2);
shift_final = (kbd->shift_state | kbd->slockstate) ^ kbd->lockstate;
key_map = kbd->key_maps[shift_final];
if (!key_map) {
/* Unsupported shift state (e.g. ctrl = 4, alt = 8), just reset to the default state */
kbd->shift_state = 0;
kbd->slockstate = 0;
kbd->lockstate = 0;
return;
}
if (keycode < NR_KEYS) {
keysym = key_map[keycode];
} else {
return;
}
type = KTYP(keysym);
if (type < 0xf0) {
if (down) {
put_utf8(kbd, keysym);
}
} else {
type -= 0xf0;
/* if type is KT_LETTER then it can be affected by Caps Lock */
if (type == KT_LETTER) {
type = KT_LATIN;
if (vc_kbd_led(kbd, K_CAPSLOCK)) {
key_map = kbd->key_maps[shift_final ^ (1 << KG_SHIFT)];
if (key_map) {
keysym = key_map[keycode];
}
}
}
(*k_handler[type])(kbd, keysym & 0xff, !down);
if (type != KT_SLOCK) {
kbd->slockstate = 0;
}
}
if (kbd->text_len > 0) {
kbd->text[kbd->text_len] = '\0';
SDL_SendKeyboardText(kbd->text);
kbd->text_len = 0;
}
}
#else /* !SDL_INPUT_LINUXKD */
SDL_EVDEV_keyboard_state *
SDL_EVDEV_kbd_init(void)
{
return NULL;
}
void
SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down)
{
}
void
SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state)
{
}
#endif /* SDL_INPUT_LINUXKD */
/* vi: set ts=4 sw=4 expandtab: */

34
externals/SDL/src/core/linux/SDL_evdev_kbd.h vendored Executable file
View File

@@ -0,0 +1,34 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_evdev_kbd_h_
#define SDL_evdev_kbd_h_
struct SDL_EVDEV_keyboard_state;
typedef struct SDL_EVDEV_keyboard_state SDL_EVDEV_keyboard_state;
extern SDL_EVDEV_keyboard_state *SDL_EVDEV_kbd_init(void);
extern void SDL_EVDEV_kbd_keycode(SDL_EVDEV_keyboard_state *state, unsigned int keycode, int down);
extern void SDL_EVDEV_kbd_quit(SDL_EVDEV_keyboard_state *state);
#endif /* SDL_evdev_kbd_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View File

@@ -0,0 +1,284 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
static struct kbdiacrs default_accents = {
68,
{
{ 0x60, 0x41, 0xc0 },
{ 0x60, 0x61, 0xe0 },
{ 0x27, 0x41, 0xc1 },
{ 0x27, 0x61, 0xe1 },
{ 0x5e, 0x41, 0xc2 },
{ 0x5e, 0x61, 0xe2 },
{ 0x7e, 0x41, 0xc3 },
{ 0x7e, 0x61, 0xe3 },
{ 0x22, 0x41, 0xc4 },
{ 0x22, 0x61, 0xe4 },
{ 0x4f, 0x41, 0xc5 },
{ 0x6f, 0x61, 0xe5 },
{ 0x30, 0x41, 0xc5 },
{ 0x30, 0x61, 0xe5 },
{ 0x41, 0x41, 0xc5 },
{ 0x61, 0x61, 0xe5 },
{ 0x41, 0x45, 0xc6 },
{ 0x61, 0x65, 0xe6 },
{ 0x2c, 0x43, 0xc7 },
{ 0x2c, 0x63, 0xe7 },
{ 0x60, 0x45, 0xc8 },
{ 0x60, 0x65, 0xe8 },
{ 0x27, 0x45, 0xc9 },
{ 0x27, 0x65, 0xe9 },
{ 0x5e, 0x45, 0xca },
{ 0x5e, 0x65, 0xea },
{ 0x22, 0x45, 0xcb },
{ 0x22, 0x65, 0xeb },
{ 0x60, 0x49, 0xcc },
{ 0x60, 0x69, 0xec },
{ 0x27, 0x49, 0xcd },
{ 0x27, 0x69, 0xed },
{ 0x5e, 0x49, 0xce },
{ 0x5e, 0x69, 0xee },
{ 0x22, 0x49, 0xcf },
{ 0x22, 0x69, 0xef },
{ 0x2d, 0x44, 0xd0 },
{ 0x2d, 0x64, 0xf0 },
{ 0x7e, 0x4e, 0xd1 },
{ 0x7e, 0x6e, 0xf1 },
{ 0x60, 0x4f, 0xd2 },
{ 0x60, 0x6f, 0xf2 },
{ 0x27, 0x4f, 0xd3 },
{ 0x27, 0x6f, 0xf3 },
{ 0x5e, 0x4f, 0xd4 },
{ 0x5e, 0x6f, 0xf4 },
{ 0x7e, 0x4f, 0xd5 },
{ 0x7e, 0x6f, 0xf5 },
{ 0x22, 0x4f, 0xd6 },
{ 0x22, 0x6f, 0xf6 },
{ 0x2f, 0x4f, 0xd8 },
{ 0x2f, 0x6f, 0xf8 },
{ 0x60, 0x55, 0xd9 },
{ 0x60, 0x75, 0xf9 },
{ 0x27, 0x55, 0xda },
{ 0x27, 0x75, 0xfa },
{ 0x5e, 0x55, 0xdb },
{ 0x5e, 0x75, 0xfb },
{ 0x22, 0x55, 0xdc },
{ 0x22, 0x75, 0xfc },
{ 0x27, 0x59, 0xdd },
{ 0x27, 0x79, 0xfd },
{ 0x54, 0x48, 0xde },
{ 0x74, 0x68, 0xfe },
{ 0x73, 0x73, 0xdf },
{ 0x22, 0x79, 0xff },
{ 0x73, 0x7a, 0xdf },
{ 0x69, 0x6a, 0xff },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
{ 0x00, 0x00, 0x00 },
}
};
/* vi: set ts=4 sw=4 expandtab: */

File diff suppressed because it is too large Load Diff

373
externals/SDL/src/core/linux/SDL_fcitx.c vendored Executable file
View File

@@ -0,0 +1,373 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef HAVE_FCITX_FRONTEND_H
#include <fcitx/frontend.h>
#include <unistd.h>
#include "SDL_fcitx.h"
#include "SDL_keycode.h"
#include "SDL_keyboard.h"
#include "../../events/SDL_keyboard_c.h"
#include "SDL_dbus.h"
#include "SDL_syswm.h"
#if SDL_VIDEO_DRIVER_X11
# include "../../video/x11/SDL_x11video.h"
#endif
#include "SDL_hints.h"
#define FCITX_DBUS_SERVICE "org.fcitx.Fcitx"
#define FCITX_IM_DBUS_PATH "/inputmethod"
#define FCITX_IC_DBUS_PATH "/inputcontext_%d"
#define FCITX_IM_DBUS_INTERFACE "org.fcitx.Fcitx.InputMethod"
#define FCITX_IC_DBUS_INTERFACE "org.fcitx.Fcitx.InputContext"
#define IC_NAME_MAX 64
#define DBUS_TIMEOUT 500
typedef struct _FcitxClient
{
SDL_DBusContext *dbus;
char servicename[IC_NAME_MAX];
char icname[IC_NAME_MAX];
int id;
SDL_Rect cursor_rect;
} FcitxClient;
static FcitxClient fcitx_client;
static int
GetDisplayNumber()
{
const char *display = SDL_getenv("DISPLAY");
const char *p = NULL;
int number = 0;
if (display == NULL)
return 0;
display = SDL_strchr(display, ':');
if (display == NULL)
return 0;
display++;
p = SDL_strchr(display, '.');
if (p == NULL && display != NULL) {
number = SDL_strtod(display, NULL);
} else {
char *buffer = SDL_strdup(display);
buffer[p - display] = '\0';
number = SDL_strtod(buffer, NULL);
SDL_free(buffer);
}
return number;
}
static char*
GetAppName()
{
#if defined(__LINUX__) || defined(__FREEBSD__)
char *spot;
char procfile[1024];
char linkfile[1024];
int linksize;
#if defined(__LINUX__)
SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/exe", getpid());
#elif defined(__FREEBSD__)
SDL_snprintf(procfile, sizeof(procfile), "/proc/%d/file", getpid());
#endif
linksize = readlink(procfile, linkfile, sizeof(linkfile) - 1);
if (linksize > 0) {
linkfile[linksize] = '\0';
spot = SDL_strrchr(linkfile, '/');
if (spot) {
return SDL_strdup(spot + 1);
} else {
return SDL_strdup(linkfile);
}
}
#endif /* __LINUX__ || __FREEBSD__ */
return SDL_strdup("SDL_App");
}
static DBusHandlerResult
DBus_MessageFilter(DBusConnection *conn, DBusMessage *msg, void *data)
{
SDL_DBusContext *dbus = (SDL_DBusContext *)data;
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "CommitString")) {
DBusMessageIter iter;
const char *text = NULL;
dbus->message_iter_init(msg, &iter);
dbus->message_iter_get_basic(&iter, &text);
if (text)
SDL_SendKeyboardText(text);
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus->message_is_signal(msg, FCITX_IC_DBUS_INTERFACE, "UpdatePreedit")) {
DBusMessageIter iter;
const char *text;
dbus->message_iter_init(msg, &iter);
dbus->message_iter_get_basic(&iter, &text);
if (text && *text) {
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;
while (i < text_bytes) {
const size_t sz = SDL_utf8strlcpy(buf, text + i, sizeof(buf));
const size_t chars = SDL_utf8strlen(buf);
SDL_SendEditingText(buf, cursor, chars);
i += sz;
cursor += chars;
}
}
SDL_Fcitx_UpdateTextRect(NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static void
FcitxClientICCallMethod(FcitxClient *client, const char *method)
{
SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, method, DBUS_TYPE_INVALID);
}
static void SDLCALL
Fcitx_SetCapabilities(void *data,
const char *name,
const char *old_val,
const char *internal_editing)
{
FcitxClient *client = (FcitxClient *)data;
Uint32 caps = CAPACITY_NONE;
if (!(internal_editing && *internal_editing == '1')) {
caps |= CAPACITY_PREEDIT;
}
SDL_DBus_CallVoidMethod(client->servicename, client->icname, FCITX_IC_DBUS_INTERFACE, "SetCapacity", DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
}
static SDL_bool
FcitxClientCreateIC(FcitxClient *client)
{
char *appname = GetAppName();
pid_t pid = getpid();
int id = -1;
Uint32 enable, arg1, arg2, arg3, arg4;
if (!SDL_DBus_CallMethod(client->servicename, FCITX_IM_DBUS_PATH, FCITX_IM_DBUS_INTERFACE, "CreateICv3",
DBUS_TYPE_STRING, &appname, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID,
DBUS_TYPE_INT32, &id, DBUS_TYPE_BOOLEAN, &enable, DBUS_TYPE_UINT32, &arg1, DBUS_TYPE_UINT32, &arg2, DBUS_TYPE_UINT32, &arg3, DBUS_TYPE_UINT32, &arg4, DBUS_TYPE_INVALID)) {
id = -1; /* just in case. */
}
SDL_free(appname);
if (id >= 0) {
SDL_DBusContext *dbus = client->dbus;
client->id = id;
SDL_snprintf(client->icname, IC_NAME_MAX, FCITX_IC_DBUS_PATH, client->id);
dbus->bus_add_match(dbus->session_conn,
"type='signal', interface='org.fcitx.Fcitx.InputContext'",
NULL);
dbus->connection_add_filter(dbus->session_conn,
&DBus_MessageFilter, dbus,
NULL);
dbus->connection_flush(dbus->session_conn);
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, Fcitx_SetCapabilities, client);
return SDL_TRUE;
}
return SDL_FALSE;
}
static Uint32
Fcitx_ModState(void)
{
Uint32 fcitx_mods = 0;
SDL_Keymod sdl_mods = SDL_GetModState();
if (sdl_mods & KMOD_SHIFT) fcitx_mods |= FcitxKeyState_Shift;
if (sdl_mods & KMOD_CAPS) fcitx_mods |= FcitxKeyState_CapsLock;
if (sdl_mods & KMOD_CTRL) fcitx_mods |= FcitxKeyState_Ctrl;
if (sdl_mods & KMOD_ALT) fcitx_mods |= FcitxKeyState_Alt;
if (sdl_mods & KMOD_NUM) fcitx_mods |= FcitxKeyState_NumLock;
if (sdl_mods & KMOD_LGUI) fcitx_mods |= FcitxKeyState_Super;
if (sdl_mods & KMOD_RGUI) fcitx_mods |= FcitxKeyState_Meta;
return fcitx_mods;
}
SDL_bool
SDL_Fcitx_Init()
{
fcitx_client.dbus = SDL_DBus_GetContext();
fcitx_client.cursor_rect.x = -1;
fcitx_client.cursor_rect.y = -1;
fcitx_client.cursor_rect.w = 0;
fcitx_client.cursor_rect.h = 0;
SDL_snprintf(fcitx_client.servicename, IC_NAME_MAX,
"%s-%d",
FCITX_DBUS_SERVICE, GetDisplayNumber());
return FcitxClientCreateIC(&fcitx_client);
}
void
SDL_Fcitx_Quit()
{
FcitxClientICCallMethod(&fcitx_client, "DestroyIC");
}
void
SDL_Fcitx_SetFocus(SDL_bool focused)
{
if (focused) {
FcitxClientICCallMethod(&fcitx_client, "FocusIn");
} else {
FcitxClientICCallMethod(&fcitx_client, "FocusOut");
}
}
void
SDL_Fcitx_Reset(void)
{
FcitxClientICCallMethod(&fcitx_client, "Reset");
FcitxClientICCallMethod(&fcitx_client, "CloseIC");
}
SDL_bool
SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
Uint32 state = Fcitx_ModState();
Uint32 handled = SDL_FALSE;
int type = FCITX_PRESS_KEY;
Uint32 event_time = 0;
if (SDL_DBus_CallMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent",
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INT32, &type, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID,
DBUS_TYPE_INT32, &handled, DBUS_TYPE_INVALID)) {
if (handled) {
SDL_Fcitx_UpdateTextRect(NULL);
return SDL_TRUE;
}
}
return SDL_FALSE;
}
void
SDL_Fcitx_UpdateTextRect(SDL_Rect *rect)
{
SDL_Window *focused_win = NULL;
SDL_SysWMinfo info;
int x = 0, y = 0;
SDL_Rect *cursor = &fcitx_client.cursor_rect;
if (rect) {
SDL_memcpy(cursor, rect, sizeof(SDL_Rect));
}
focused_win = SDL_GetKeyboardFocus();
if (!focused_win) {
return ;
}
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(focused_win, &info)) {
return;
}
SDL_GetWindowPosition(focused_win, &x, &y);
#if SDL_VIDEO_DRIVER_X11
if (info.subsystem == SDL_SYSWM_X11) {
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
Display *x_disp = info.info.x11.display;
Window x_win = info.info.x11.window;
int x_screen = displaydata->screen;
Window unused;
X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
}
#endif
if (cursor->x == -1 && cursor->y == -1 && cursor->w == 0 && cursor->h == 0) {
/* move to bottom left */
int w = 0, h = 0;
SDL_GetWindowSize(focused_win, &w, &h);
cursor->x = 0;
cursor->y = h;
}
x += cursor->x;
y += cursor->y;
SDL_DBus_CallVoidMethod(fcitx_client.servicename, fcitx_client.icname, FCITX_IC_DBUS_INTERFACE, "SetCursorRect",
DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &cursor->w, DBUS_TYPE_INT32, &cursor->h, DBUS_TYPE_INVALID);
}
void
SDL_Fcitx_PumpEvents(void)
{
SDL_DBusContext *dbus = fcitx_client.dbus;
DBusConnection *conn = dbus->session_conn;
dbus->connection_read_write(conn, 0);
while (dbus->connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS) {
/* Do nothing, actual work happens in DBus_MessageFilter */
usleep(10);
}
}
#endif /* HAVE_FCITX_FRONTEND_H */
/* vi: set ts=4 sw=4 expandtab: */

40
externals/SDL/src/core/linux/SDL_fcitx.h vendored Executable file
View File

@@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_fcitx_h_
#define SDL_fcitx_h_
#include "../../SDL_internal.h"
#include "SDL_stdinc.h"
#include "SDL_rect.h"
extern SDL_bool SDL_Fcitx_Init(void);
extern void SDL_Fcitx_Quit(void);
extern void SDL_Fcitx_SetFocus(SDL_bool focused);
extern void SDL_Fcitx_Reset(void);
extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect);
extern void SDL_Fcitx_PumpEvents(void);
#endif /* SDL_fcitx_h_ */
/* vi: set ts=4 sw=4 expandtab: */

584
externals/SDL/src/core/linux/SDL_ibus.c vendored Executable file
View File

@@ -0,0 +1,584 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef HAVE_IBUS_IBUS_H
#include "SDL.h"
#include "SDL_syswm.h"
#include "SDL_ibus.h"
#include "SDL_dbus.h"
#include "../../video/SDL_sysvideo.h"
#include "../../events/SDL_keyboard_c.h"
#if SDL_VIDEO_DRIVER_X11
#include "../../video/x11/SDL_x11video.h"
#endif
#include <sys/inotify.h>
#include <unistd.h>
#include <fcntl.h>
static const char IBUS_SERVICE[] = "org.freedesktop.IBus";
static const char IBUS_PATH[] = "/org/freedesktop/IBus";
static const char IBUS_INTERFACE[] = "org.freedesktop.IBus";
static const char IBUS_INPUT_INTERFACE[] = "org.freedesktop.IBus.InputContext";
static char *input_ctx_path = NULL;
static SDL_Rect ibus_cursor_rect = { 0, 0, 0, 0 };
static DBusConnection *ibus_conn = NULL;
static char *ibus_addr_file = NULL;
static int inotify_fd = -1, inotify_wd = -1;
static Uint32
IBus_ModState(void)
{
Uint32 ibus_mods = 0;
SDL_Keymod sdl_mods = SDL_GetModState();
/* Not sure about MOD3, MOD4 and HYPER mappings */
if (sdl_mods & KMOD_LSHIFT) ibus_mods |= IBUS_SHIFT_MASK;
if (sdl_mods & KMOD_CAPS) ibus_mods |= IBUS_LOCK_MASK;
if (sdl_mods & KMOD_LCTRL) ibus_mods |= IBUS_CONTROL_MASK;
if (sdl_mods & KMOD_LALT) ibus_mods |= IBUS_MOD1_MASK;
if (sdl_mods & KMOD_NUM) ibus_mods |= IBUS_MOD2_MASK;
if (sdl_mods & KMOD_MODE) ibus_mods |= IBUS_MOD5_MASK;
if (sdl_mods & KMOD_LGUI) ibus_mods |= IBUS_SUPER_MASK;
if (sdl_mods & KMOD_RGUI) ibus_mods |= IBUS_META_MASK;
return ibus_mods;
}
static const char *
IBus_GetVariantText(DBusConnection *conn, DBusMessageIter *iter, SDL_DBusContext *dbus)
{
/* The text we need is nested weirdly, use dbus-monitor to see the structure better */
const char *text = NULL;
const char *struct_id = NULL;
DBusMessageIter sub1, sub2;
if (dbus->message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT) {
return NULL;
}
dbus->message_iter_recurse(iter, &sub1);
if (dbus->message_iter_get_arg_type(&sub1) != DBUS_TYPE_STRUCT) {
return NULL;
}
dbus->message_iter_recurse(&sub1, &sub2);
if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
return NULL;
}
dbus->message_iter_get_basic(&sub2, &struct_id);
if (!struct_id || SDL_strncmp(struct_id, "IBusText", sizeof("IBusText")) != 0) {
return NULL;
}
dbus->message_iter_next(&sub2);
dbus->message_iter_next(&sub2);
if (dbus->message_iter_get_arg_type(&sub2) != DBUS_TYPE_STRING) {
return NULL;
}
dbus->message_iter_get_basic(&sub2, &text);
return text;
}
static DBusHandlerResult
IBus_MessageHandler(DBusConnection *conn, DBusMessage *msg, void *user_data)
{
SDL_DBusContext *dbus = (SDL_DBusContext *)user_data;
if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "CommitText")) {
DBusMessageIter iter;
const char *text;
dbus->message_iter_init(msg, &iter);
text = IBus_GetVariantText(conn, &iter, dbus);
if (text && *text) {
char buf[SDL_TEXTINPUTEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
while (i < text_bytes) {
size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
SDL_SendKeyboardText(buf);
i += sz;
}
}
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "UpdatePreeditText")) {
DBusMessageIter iter;
const char *text;
dbus->message_iter_init(msg, &iter);
text = IBus_GetVariantText(conn, &iter, dbus);
if (text) {
char buf[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
size_t text_bytes = SDL_strlen(text), i = 0;
size_t cursor = 0;
do {
const size_t sz = SDL_utf8strlcpy(buf, text+i, sizeof(buf));
const size_t chars = SDL_utf8strlen(buf);
SDL_SendEditingText(buf, cursor, chars);
i += sz;
cursor += chars;
} while (i < text_bytes);
}
SDL_IBus_UpdateTextRect(NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
if (dbus->message_is_signal(msg, IBUS_INPUT_INTERFACE, "HidePreeditText")) {
SDL_SendEditingText("", 0, 0);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static char *
IBus_ReadAddressFromFile(const char *file_path)
{
char addr_buf[1024];
SDL_bool success = SDL_FALSE;
FILE *addr_file;
addr_file = fopen(file_path, "r");
if (!addr_file) {
return NULL;
}
while (fgets(addr_buf, sizeof(addr_buf), addr_file)) {
if (SDL_strncmp(addr_buf, "IBUS_ADDRESS=", sizeof("IBUS_ADDRESS=")-1) == 0) {
size_t sz = SDL_strlen(addr_buf);
if (addr_buf[sz-1] == '\n') addr_buf[sz-1] = 0;
if (addr_buf[sz-2] == '\r') addr_buf[sz-2] = 0;
success = SDL_TRUE;
break;
}
}
fclose(addr_file);
if (success) {
return SDL_strdup(addr_buf + (sizeof("IBUS_ADDRESS=") - 1));
} else {
return NULL;
}
}
static char *
IBus_GetDBusAddressFilename(void)
{
SDL_DBusContext *dbus;
const char *disp_env;
char config_dir[PATH_MAX];
char *display = NULL;
const char *addr;
const char *conf_env;
char *key;
char file_path[PATH_MAX];
const char *host;
char *disp_num, *screen_num;
if (ibus_addr_file) {
return SDL_strdup(ibus_addr_file);
}
dbus = SDL_DBus_GetContext();
if (!dbus) {
return NULL;
}
/* Use this environment variable if it exists. */
addr = SDL_getenv("IBUS_ADDRESS");
if (addr && *addr) {
return SDL_strdup(addr);
}
/* Otherwise, we have to get the hostname, display, machine id, config dir
and look up the address from a filepath using all those bits, eek. */
disp_env = SDL_getenv("DISPLAY");
if (!disp_env || !*disp_env) {
display = SDL_strdup(":0.0");
} else {
display = SDL_strdup(disp_env);
}
host = display;
disp_num = SDL_strrchr(display, ':');
screen_num = SDL_strrchr(display, '.');
if (!disp_num) {
SDL_free(display);
return NULL;
}
*disp_num = 0;
disp_num++;
if (screen_num) {
*screen_num = 0;
}
if (!*host) {
host = "unix";
}
SDL_memset(config_dir, 0, sizeof(config_dir));
conf_env = SDL_getenv("XDG_CONFIG_HOME");
if (conf_env && *conf_env) {
SDL_strlcpy(config_dir, conf_env, sizeof(config_dir));
} else {
const char *home_env = SDL_getenv("HOME");
if (!home_env || !*home_env) {
SDL_free(display);
return NULL;
}
SDL_snprintf(config_dir, sizeof(config_dir), "%s/.config", home_env);
}
key = dbus->get_local_machine_id();
SDL_memset(file_path, 0, sizeof(file_path));
SDL_snprintf(file_path, sizeof(file_path), "%s/ibus/bus/%s-%s-%s",
config_dir, key, host, disp_num);
dbus->free(key);
SDL_free(display);
return SDL_strdup(file_path);
}
static SDL_bool IBus_CheckConnection(SDL_DBusContext *dbus);
static void SDLCALL
IBus_SetCapabilities(void *data, const char *name, const char *old_val,
const char *internal_editing)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
Uint32 caps = IBUS_CAP_FOCUS;
if (!(internal_editing && *internal_editing == '1')) {
caps |= IBUS_CAP_PREEDIT_TEXT;
}
SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCapabilities",
DBUS_TYPE_UINT32, &caps, DBUS_TYPE_INVALID);
}
}
static SDL_bool
IBus_SetupConnection(SDL_DBusContext *dbus, const char* addr)
{
const char *client_name = "SDL2_Application";
const char *path = NULL;
SDL_bool result = SDL_FALSE;
DBusObjectPathVTable ibus_vtable;
SDL_zero(ibus_vtable);
ibus_vtable.message_function = &IBus_MessageHandler;
ibus_conn = dbus->connection_open_private(addr, NULL);
if (!ibus_conn) {
return SDL_FALSE;
}
dbus->connection_flush(ibus_conn);
if (!dbus->bus_register(ibus_conn, NULL)) {
ibus_conn = NULL;
return SDL_FALSE;
}
dbus->connection_flush(ibus_conn);
if (SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, IBUS_PATH, IBUS_INTERFACE, "CreateInputContext",
DBUS_TYPE_STRING, &client_name, DBUS_TYPE_INVALID,
DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) {
SDL_free(input_ctx_path);
input_ctx_path = SDL_strdup(path);
SDL_AddHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL);
dbus->bus_add_match(ibus_conn, "type='signal',interface='org.freedesktop.IBus.InputContext'", NULL);
dbus->connection_try_register_object_path(ibus_conn, input_ctx_path, &ibus_vtable, dbus, NULL);
dbus->connection_flush(ibus_conn);
result = SDL_TRUE;
}
SDL_IBus_SetFocus(SDL_GetKeyboardFocus() != NULL);
SDL_IBus_UpdateTextRect(NULL);
return result;
}
static SDL_bool
IBus_CheckConnection(SDL_DBusContext *dbus)
{
if (!dbus) return SDL_FALSE;
if (ibus_conn && dbus->connection_get_is_connected(ibus_conn)) {
return SDL_TRUE;
}
if (inotify_fd > 0 && inotify_wd > 0) {
char buf[1024];
ssize_t readsize = read(inotify_fd, buf, sizeof(buf));
if (readsize > 0) {
char *p;
SDL_bool file_updated = SDL_FALSE;
for (p = buf; p < buf + readsize; /**/) {
struct inotify_event *event = (struct inotify_event*) p;
if (event->len > 0) {
char *addr_file_no_path = SDL_strrchr(ibus_addr_file, '/');
if (!addr_file_no_path) return SDL_FALSE;
if (SDL_strcmp(addr_file_no_path + 1, event->name) == 0) {
file_updated = SDL_TRUE;
break;
}
}
p += sizeof(struct inotify_event) + event->len;
}
if (file_updated) {
char *addr = IBus_ReadAddressFromFile(ibus_addr_file);
if (addr) {
SDL_bool result = IBus_SetupConnection(dbus, addr);
SDL_free(addr);
return result;
}
}
}
}
return SDL_FALSE;
}
SDL_bool
SDL_IBus_Init(void)
{
SDL_bool result = SDL_FALSE;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (dbus) {
char *addr_file = IBus_GetDBusAddressFilename();
char *addr;
char *addr_file_dir;
if (!addr_file) {
return SDL_FALSE;
}
/* !!! FIXME: if ibus_addr_file != NULL, this will overwrite it and leak (twice!) */
ibus_addr_file = SDL_strdup(addr_file);
addr = IBus_ReadAddressFromFile(addr_file);
if (!addr) {
SDL_free(addr_file);
return SDL_FALSE;
}
if (inotify_fd < 0) {
inotify_fd = inotify_init();
fcntl(inotify_fd, F_SETFL, O_NONBLOCK);
}
addr_file_dir = SDL_strrchr(addr_file, '/');
if (addr_file_dir) {
*addr_file_dir = 0;
}
inotify_wd = inotify_add_watch(inotify_fd, addr_file, IN_CREATE | IN_MODIFY);
SDL_free(addr_file);
if (addr) {
result = IBus_SetupConnection(dbus, addr);
SDL_free(addr);
}
}
return result;
}
void
SDL_IBus_Quit(void)
{
SDL_DBusContext *dbus;
if (input_ctx_path) {
SDL_free(input_ctx_path);
input_ctx_path = NULL;
}
if (ibus_addr_file) {
SDL_free(ibus_addr_file);
ibus_addr_file = NULL;
}
dbus = SDL_DBus_GetContext();
if (dbus && ibus_conn) {
dbus->connection_close(ibus_conn);
dbus->connection_unref(ibus_conn);
}
if (inotify_fd > 0 && inotify_wd > 0) {
inotify_rm_watch(inotify_fd, inotify_wd);
inotify_wd = -1;
}
SDL_DelHintCallback(SDL_HINT_IME_INTERNAL_EDITING, IBus_SetCapabilities, NULL);
SDL_memset(&ibus_cursor_rect, 0, sizeof(ibus_cursor_rect));
}
static void
IBus_SimpleMessage(const char *method)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID);
}
}
void
SDL_IBus_SetFocus(SDL_bool focused)
{
const char *method = focused ? "FocusIn" : "FocusOut";
IBus_SimpleMessage(method);
}
void
SDL_IBus_Reset(void)
{
IBus_SimpleMessage("Reset");
}
SDL_bool
SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
Uint32 result = 0;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
Uint32 mods = IBus_ModState();
if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID,
DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) {
result = 0;
}
}
SDL_IBus_UpdateTextRect(NULL);
return result ? SDL_TRUE : SDL_FALSE;
}
void
SDL_IBus_UpdateTextRect(SDL_Rect *rect)
{
SDL_Window *focused_win;
SDL_SysWMinfo info;
int x = 0, y = 0;
SDL_DBusContext *dbus;
if (rect) {
SDL_memcpy(&ibus_cursor_rect, rect, sizeof(ibus_cursor_rect));
}
focused_win = SDL_GetKeyboardFocus();
if (!focused_win) {
return;
}
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(focused_win, &info)) {
return;
}
SDL_GetWindowPosition(focused_win, &x, &y);
#if SDL_VIDEO_DRIVER_X11
if (info.subsystem == SDL_SYSWM_X11) {
SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(focused_win)->driverdata;
Display *x_disp = info.info.x11.display;
Window x_win = info.info.x11.window;
int x_screen = displaydata->screen;
Window unused;
X11_XTranslateCoordinates(x_disp, x_win, RootWindow(x_disp, x_screen), 0, 0, &x, &y, &unused);
}
#endif
x += ibus_cursor_rect.x;
y += ibus_cursor_rect.y;
dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "SetCursorLocation",
DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &ibus_cursor_rect.w, DBUS_TYPE_INT32, &ibus_cursor_rect.h, DBUS_TYPE_INVALID);
}
}
void
SDL_IBus_PumpEvents(void)
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
dbus->connection_read_write(ibus_conn, 0);
while (dbus->connection_dispatch(ibus_conn) == DBUS_DISPATCH_DATA_REMAINS) {
/* Do nothing, actual work happens in IBus_MessageHandler */
}
}
}
#endif
/* vi: set ts=4 sw=4 expandtab: */

58
externals/SDL/src/core/linux/SDL_ibus.h vendored Executable file
View File

@@ -0,0 +1,58 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifndef SDL_ibus_h_
#define SDL_ibus_h_
#ifdef HAVE_IBUS_IBUS_H
#define SDL_USE_IBUS 1
#include "SDL_stdinc.h"
#include <ibus-1.0/ibus.h>
extern SDL_bool SDL_IBus_Init(void);
extern void SDL_IBus_Quit(void);
/* Lets the IBus server know about changes in window focus */
extern void SDL_IBus_SetFocus(SDL_bool focused);
/* Closes the candidate list and resets any text currently being edited */
extern void SDL_IBus_Reset(void);
/* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to
update its candidate list or change input methods. PumpEvents should be
called some time after this, to recieve the TextInput / TextEditing event back. */
extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
/* Update the position of IBus' candidate list. If rect is NULL then this will
just reposition it relative to the focused window's new position. */
extern void SDL_IBus_UpdateTextRect(SDL_Rect *window_relative_rect);
/* Checks DBus for new IBus events, and calls SDL_SendKeyboardText /
SDL_SendEditingText for each event it finds */
extern void SDL_IBus_PumpEvents(void);
#endif /* HAVE_IBUS_IBUS_H */
#endif /* SDL_ibus_h_ */
/* vi: set ts=4 sw=4 expandtab: */

152
externals/SDL/src/core/linux/SDL_ime.c vendored Executable file
View File

@@ -0,0 +1,152 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_ime.h"
#include "SDL_ibus.h"
#include "SDL_fcitx.h"
typedef SDL_bool (*_SDL_IME_Init)();
typedef void (*_SDL_IME_Quit)();
typedef void (*_SDL_IME_SetFocus)(SDL_bool);
typedef void (*_SDL_IME_Reset)();
typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32);
typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *);
typedef void (*_SDL_IME_PumpEvents)();
static _SDL_IME_Init SDL_IME_Init_Real = NULL;
static _SDL_IME_Quit SDL_IME_Quit_Real = NULL;
static _SDL_IME_SetFocus SDL_IME_SetFocus_Real = NULL;
static _SDL_IME_Reset SDL_IME_Reset_Real = NULL;
static _SDL_IME_ProcessKeyEvent SDL_IME_ProcessKeyEvent_Real = NULL;
static _SDL_IME_UpdateTextRect SDL_IME_UpdateTextRect_Real = NULL;
static _SDL_IME_PumpEvents SDL_IME_PumpEvents_Real = NULL;
static void
InitIME()
{
static SDL_bool inited = SDL_FALSE;
#ifdef HAVE_FCITX_FRONTEND_H
const char *im_module = SDL_getenv("SDL_IM_MODULE");
const char *xmodifiers = SDL_getenv("XMODIFIERS");
#endif
if (inited == SDL_TRUE)
return;
inited = SDL_TRUE;
/* See if fcitx IME support is being requested */
#ifdef HAVE_FCITX_FRONTEND_H
if (!SDL_IME_Init_Real &&
((im_module && SDL_strcmp(im_module, "fcitx") == 0) ||
(!im_module && xmodifiers && SDL_strstr(xmodifiers, "@im=fcitx") != NULL))) {
SDL_IME_Init_Real = SDL_Fcitx_Init;
SDL_IME_Quit_Real = SDL_Fcitx_Quit;
SDL_IME_SetFocus_Real = SDL_Fcitx_SetFocus;
SDL_IME_Reset_Real = SDL_Fcitx_Reset;
SDL_IME_ProcessKeyEvent_Real = SDL_Fcitx_ProcessKeyEvent;
SDL_IME_UpdateTextRect_Real = SDL_Fcitx_UpdateTextRect;
SDL_IME_PumpEvents_Real = SDL_Fcitx_PumpEvents;
}
#endif /* HAVE_FCITX_FRONTEND_H */
/* default to IBus */
#ifdef HAVE_IBUS_IBUS_H
if (!SDL_IME_Init_Real) {
SDL_IME_Init_Real = SDL_IBus_Init;
SDL_IME_Quit_Real = SDL_IBus_Quit;
SDL_IME_SetFocus_Real = SDL_IBus_SetFocus;
SDL_IME_Reset_Real = SDL_IBus_Reset;
SDL_IME_ProcessKeyEvent_Real = SDL_IBus_ProcessKeyEvent;
SDL_IME_UpdateTextRect_Real = SDL_IBus_UpdateTextRect;
SDL_IME_PumpEvents_Real = SDL_IBus_PumpEvents;
}
#endif /* HAVE_IBUS_IBUS_H */
}
SDL_bool
SDL_IME_Init(void)
{
InitIME();
if (SDL_IME_Init_Real) {
if (SDL_IME_Init_Real()) {
return SDL_TRUE;
}
/* uhoh, the IME implementation's init failed! Disable IME support. */
SDL_IME_Init_Real = NULL;
SDL_IME_Quit_Real = NULL;
SDL_IME_SetFocus_Real = NULL;
SDL_IME_Reset_Real = NULL;
SDL_IME_ProcessKeyEvent_Real = NULL;
SDL_IME_UpdateTextRect_Real = NULL;
SDL_IME_PumpEvents_Real = NULL;
}
return SDL_FALSE;
}
void
SDL_IME_Quit(void)
{
if (SDL_IME_Quit_Real)
SDL_IME_Quit_Real();
}
void
SDL_IME_SetFocus(SDL_bool focused)
{
if (SDL_IME_SetFocus_Real)
SDL_IME_SetFocus_Real(focused);
}
void
SDL_IME_Reset(void)
{
if (SDL_IME_Reset_Real)
SDL_IME_Reset_Real();
}
SDL_bool
SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode)
{
if (SDL_IME_ProcessKeyEvent_Real)
return SDL_IME_ProcessKeyEvent_Real(keysym, keycode);
return SDL_FALSE;
}
void
SDL_IME_UpdateTextRect(SDL_Rect *rect)
{
if (SDL_IME_UpdateTextRect_Real)
SDL_IME_UpdateTextRect_Real(rect);
}
void
SDL_IME_PumpEvents()
{
if (SDL_IME_PumpEvents_Real)
SDL_IME_PumpEvents_Real();
}
/* vi: set ts=4 sw=4 expandtab: */

40
externals/SDL/src/core/linux/SDL_ime.h vendored Executable file
View File

@@ -0,0 +1,40 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_ime_h_
#define SDL_ime_h_
#include "../../SDL_internal.h"
#include "SDL_stdinc.h"
#include "SDL_rect.h"
extern SDL_bool SDL_IME_Init(void);
extern void SDL_IME_Quit(void);
extern void SDL_IME_SetFocus(SDL_bool focused);
extern void SDL_IME_Reset(void);
extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode);
extern void SDL_IME_UpdateTextRect(SDL_Rect *rect);
extern void SDL_IME_PumpEvents(void);
#endif /* SDL_ime_h_ */
/* vi: set ts=4 sw=4 expandtab: */

116
externals/SDL/src/core/linux/SDL_threadprio.c vendored Executable file
View File

@@ -0,0 +1,116 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifdef __LINUX__
#include "SDL_error.h"
#include "SDL_stdinc.h"
#if !SDL_THREADS_DISABLED
#include <sys/time.h>
#include <sys/resource.h>
#include <pthread.h>
#include "SDL_system.h"
#include "SDL_dbus.h"
#if SDL_USE_LIBDBUS
/* d-bus queries to org.freedesktop.RealtimeKit1. */
#define RTKIT_DBUS_NODE "org.freedesktop.RealtimeKit1"
#define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1"
#define RTKIT_DBUS_INTERFACE "org.freedesktop.RealtimeKit1"
static pthread_once_t rtkit_initialize_once = PTHREAD_ONCE_INIT;
static Sint32 rtkit_min_nice_level = -20;
static void
rtkit_initialize()
{
SDL_DBusContext *dbus = SDL_DBus_GetContext();
/* Try getting minimum nice level: this is often greater than PRIO_MIN (-20). */
if (!dbus || !SDL_DBus_QueryPropertyOnConnection(dbus->system_conn, RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MinNiceLevel",
DBUS_TYPE_INT32, &rtkit_min_nice_level)) {
rtkit_min_nice_level = -20;
}
}
static SDL_bool
rtkit_setpriority(pid_t thread, int nice_level)
{
Uint64 ui64 = (Uint64)thread;
Sint32 si32 = (Sint32)nice_level;
SDL_DBusContext *dbus = SDL_DBus_GetContext();
pthread_once(&rtkit_initialize_once, rtkit_initialize);
if (si32 < rtkit_min_nice_level)
si32 = rtkit_min_nice_level;
if (!dbus || !SDL_DBus_CallMethodOnConnection(dbus->system_conn,
RTKIT_DBUS_NODE, RTKIT_DBUS_PATH, RTKIT_DBUS_INTERFACE, "MakeThreadHighPriority",
DBUS_TYPE_UINT64, &ui64, DBUS_TYPE_INT32, &si32, DBUS_TYPE_INVALID,
DBUS_TYPE_INVALID)) {
return SDL_FALSE;
}
return SDL_TRUE;
}
#endif /* dbus */
#endif /* threads */
/* this is a public symbol, so it has to exist even if threads are disabled. */
int
SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
{
#if SDL_THREADS_DISABLED
return SDL_Unsupported();
#else
if (setpriority(PRIO_PROCESS, (id_t)threadID, priority) == 0) {
return 0;
}
#if SDL_USE_LIBDBUS
/* Note that this fails you most likely:
* Have your process's scheduler incorrectly configured.
See the requirements at:
http://git.0pointer.net/rtkit.git/tree/README#n16
* Encountered dbus/polkit security restrictions. Note
that the RealtimeKit1 dbus endpoint is inaccessible
over ssh connections for most common distro configs.
You might want to check your local config for details:
/usr/share/polkit-1/actions/org.freedesktop.RealtimeKit1.policy
README and sample code at: http://git.0pointer.net/rtkit.git
*/
if (rtkit_setpriority((pid_t)threadID, priority)) {
return 0;
}
#endif
return SDL_SetError("setpriority() failed");
#endif
}
#endif /* __LINUX__ */
/* vi: set ts=4 sw=4 expandtab: */

576
externals/SDL/src/core/linux/SDL_udev.c vendored Executable file
View File

@@ -0,0 +1,576 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* To list the properties of a device, try something like:
* udevadm info -a -n snd/hwC0D0 (for a sound card)
* udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc)
* udevadm info --query=property -n input/event2
*/
#include "SDL_udev.h"
#ifdef SDL_USE_LIBUDEV
#include <linux/input.h>
#include "SDL_assert.h"
#include "SDL_loadso.h"
#include "SDL_timer.h"
#include "SDL_hints.h"
#include "../unix/SDL_poll.h"
static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
#define _THIS SDL_UDEV_PrivateData *_this
static _THIS = NULL;
static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr);
static int SDL_UDEV_load_syms(void);
static SDL_bool SDL_UDEV_hotplug_update_available(void);
static void device_event(SDL_UDEV_deviceevent type, struct udev_device *dev);
static SDL_bool
SDL_UDEV_load_sym(const char *fn, void **addr)
{
*addr = SDL_LoadFunction(_this->udev_handle, fn);
if (*addr == NULL) {
/* Don't call SDL_SetError(): SDL_LoadFunction already did. */
return SDL_FALSE;
}
return SDL_TRUE;
}
static int
SDL_UDEV_load_syms(void)
{
/* cast funcs to char* first, to please GCC's strict aliasing rules. */
#define SDL_UDEV_SYM(x) \
if (!SDL_UDEV_load_sym(#x, (void **) (char *) & _this->syms.x)) return -1
SDL_UDEV_SYM(udev_device_get_action);
SDL_UDEV_SYM(udev_device_get_devnode);
SDL_UDEV_SYM(udev_device_get_subsystem);
SDL_UDEV_SYM(udev_device_get_parent_with_subsystem_devtype);
SDL_UDEV_SYM(udev_device_get_property_value);
SDL_UDEV_SYM(udev_device_get_sysattr_value);
SDL_UDEV_SYM(udev_device_new_from_syspath);
SDL_UDEV_SYM(udev_device_unref);
SDL_UDEV_SYM(udev_enumerate_add_match_property);
SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
SDL_UDEV_SYM(udev_enumerate_get_list_entry);
SDL_UDEV_SYM(udev_enumerate_new);
SDL_UDEV_SYM(udev_enumerate_scan_devices);
SDL_UDEV_SYM(udev_enumerate_unref);
SDL_UDEV_SYM(udev_list_entry_get_name);
SDL_UDEV_SYM(udev_list_entry_get_next);
SDL_UDEV_SYM(udev_monitor_enable_receiving);
SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
SDL_UDEV_SYM(udev_monitor_get_fd);
SDL_UDEV_SYM(udev_monitor_new_from_netlink);
SDL_UDEV_SYM(udev_monitor_receive_device);
SDL_UDEV_SYM(udev_monitor_unref);
SDL_UDEV_SYM(udev_new);
SDL_UDEV_SYM(udev_unref);
SDL_UDEV_SYM(udev_device_new_from_devnum);
SDL_UDEV_SYM(udev_device_get_devnum);
#undef SDL_UDEV_SYM
return 0;
}
static SDL_bool
SDL_UDEV_hotplug_update_available(void)
{
if (_this->udev_mon != NULL) {
const int fd = _this->syms.udev_monitor_get_fd(_this->udev_mon);
if (SDL_IOReady(fd, SDL_FALSE, 0)) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
int
SDL_UDEV_Init(void)
{
int retval = 0;
if (_this == NULL) {
_this = (SDL_UDEV_PrivateData *) SDL_calloc(1, sizeof(*_this));
if(_this == NULL) {
return SDL_OutOfMemory();
}
retval = SDL_UDEV_LoadLibrary();
if (retval < 0) {
SDL_UDEV_Quit();
return retval;
}
/* Set up udev monitoring
* Listen for input devices (mouse, keyboard, joystick, etc) and sound devices
*/
_this->udev = _this->syms.udev_new();
if (_this->udev == NULL) {
SDL_UDEV_Quit();
return SDL_SetError("udev_new() failed");
}
_this->udev_mon = _this->syms.udev_monitor_new_from_netlink(_this->udev, "udev");
if (_this->udev_mon == NULL) {
SDL_UDEV_Quit();
return SDL_SetError("udev_monitor_new_from_netlink() failed");
}
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "input", NULL);
_this->syms.udev_monitor_filter_add_match_subsystem_devtype(_this->udev_mon, "sound", NULL);
_this->syms.udev_monitor_enable_receiving(_this->udev_mon);
/* Do an initial scan of existing devices */
SDL_UDEV_Scan();
}
_this->ref_count += 1;
return retval;
}
void
SDL_UDEV_Quit(void)
{
SDL_UDEV_CallbackList *item;
if (_this == NULL) {
return;
}
_this->ref_count -= 1;
if (_this->ref_count < 1) {
if (_this->udev_mon != NULL) {
_this->syms.udev_monitor_unref(_this->udev_mon);
_this->udev_mon = NULL;
}
if (_this->udev != NULL) {
_this->syms.udev_unref(_this->udev);
_this->udev = NULL;
}
/* Remove existing devices */
while (_this->first != NULL) {
item = _this->first;
_this->first = _this->first->next;
SDL_free(item);
}
SDL_UDEV_UnloadLibrary();
SDL_free(_this);
_this = NULL;
}
}
void
SDL_UDEV_Scan(void)
{
struct udev_enumerate *enumerate = NULL;
struct udev_list_entry *devs = NULL;
struct udev_list_entry *item = NULL;
if (_this == NULL) {
return;
}
enumerate = _this->syms.udev_enumerate_new(_this->udev);
if (enumerate == NULL) {
SDL_UDEV_Quit();
SDL_SetError("udev_enumerate_new() failed");
return;
}
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "input");
_this->syms.udev_enumerate_add_match_subsystem(enumerate, "sound");
_this->syms.udev_enumerate_scan_devices(enumerate);
devs = _this->syms.udev_enumerate_get_list_entry(enumerate);
for (item = devs; item; item = _this->syms.udev_list_entry_get_next(item)) {
const char *path = _this->syms.udev_list_entry_get_name(item);
struct udev_device *dev = _this->syms.udev_device_new_from_syspath(_this->udev, path);
if (dev != NULL) {
device_event(SDL_UDEV_DEVICEADDED, dev);
_this->syms.udev_device_unref(dev);
}
}
_this->syms.udev_enumerate_unref(enumerate);
}
void
SDL_UDEV_UnloadLibrary(void)
{
if (_this == NULL) {
return;
}
if (_this->udev_handle != NULL) {
SDL_UnloadObject(_this->udev_handle);
_this->udev_handle = NULL;
}
}
int
SDL_UDEV_LoadLibrary(void)
{
int retval = 0, i;
if (_this == NULL) {
return SDL_SetError("UDEV not initialized");
}
/* See if there is a udev library already loaded */
if (SDL_UDEV_load_syms() == 0) {
return 0;
}
#ifdef SDL_UDEV_DYNAMIC
/* Check for the build environment's libudev first */
if (_this->udev_handle == NULL) {
_this->udev_handle = SDL_LoadObject(SDL_UDEV_DYNAMIC);
if (_this->udev_handle != NULL) {
retval = SDL_UDEV_load_syms();
if (retval < 0) {
SDL_UDEV_UnloadLibrary();
}
}
}
#endif
if (_this->udev_handle == NULL) {
for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
_this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
if (_this->udev_handle != NULL) {
retval = SDL_UDEV_load_syms();
if (retval < 0) {
SDL_UDEV_UnloadLibrary();
}
else {
break;
}
}
}
if (_this->udev_handle == NULL) {
retval = -1;
/* Don't call SDL_SetError(): SDL_LoadObject already did. */
}
}
return retval;
}
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define LONG(x) ((x)/BITS_PER_LONG)
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len)
{
const char *value;
char text[4096];
char *word;
int i;
unsigned long v;
SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask));
value = _this->syms.udev_device_get_sysattr_value(pdev, attr);
if (!value) {
return;
}
SDL_strlcpy(text, value, sizeof(text));
i = 0;
while ((word = SDL_strrchr(text, ' ')) != NULL) {
v = SDL_strtoul(word+1, NULL, 16);
if (i < bitmask_len) {
bitmask[i] = v;
}
++i;
*word = '\0';
}
v = SDL_strtoul(text, NULL, 16);
if (i < bitmask_len) {
bitmask[i] = v;
}
}
static int
guess_device_class(struct udev_device *dev)
{
int devclass = 0;
struct udev_device *pdev;
unsigned long bitmask_ev[NBITS(EV_MAX)];
unsigned long bitmask_abs[NBITS(ABS_MAX)];
unsigned long bitmask_key[NBITS(KEY_MAX)];
unsigned long bitmask_rel[NBITS(REL_MAX)];
unsigned long keyboard_mask;
/* walk up the parental chain until we find the real input device; the
* argument is very likely a subdevice of this, like eventN */
pdev = dev;
while (pdev && !_this->syms.udev_device_get_sysattr_value(pdev, "capabilities/ev")) {
pdev = _this->syms.udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
}
if (!pdev) {
return 0;
}
get_caps(dev, pdev, "capabilities/ev", bitmask_ev, SDL_arraysize(bitmask_ev));
get_caps(dev, pdev, "capabilities/abs", bitmask_abs, SDL_arraysize(bitmask_abs));
get_caps(dev, pdev, "capabilities/rel", bitmask_rel, SDL_arraysize(bitmask_rel));
get_caps(dev, pdev, "capabilities/key", bitmask_key, SDL_arraysize(bitmask_key));
if (test_bit(EV_ABS, bitmask_ev) &&
test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) {
if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) {
; /* ID_INPUT_TABLET */
} else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) {
; /* ID_INPUT_TOUCHPAD */
} else if (test_bit(BTN_MOUSE, bitmask_key)) {
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
} else if (test_bit(BTN_TOUCH, bitmask_key)) {
/* TODO: better determining between touchscreen and multitouch touchpad,
see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */
}
if (test_bit(BTN_TRIGGER, bitmask_key) ||
test_bit(BTN_A, bitmask_key) ||
test_bit(BTN_1, bitmask_key) ||
test_bit(ABS_RX, bitmask_abs) ||
test_bit(ABS_RY, bitmask_abs) ||
test_bit(ABS_RZ, bitmask_abs) ||
test_bit(ABS_THROTTLE, bitmask_abs) ||
test_bit(ABS_RUDDER, bitmask_abs) ||
test_bit(ABS_WHEEL, bitmask_abs) ||
test_bit(ABS_GAS, bitmask_abs) ||
test_bit(ABS_BRAKE, bitmask_abs)) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */
}
}
if (test_bit(EV_REL, bitmask_ev) &&
test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) &&
test_bit(BTN_MOUSE, bitmask_key)) {
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
}
/* the first 32 bits are ESC, numbers, and Q to D; if we have any of
* those, consider it a keyboard device; do not test KEY_RESERVED, though */
keyboard_mask = 0xFFFFFFFE;
if ((bitmask_key[0] & keyboard_mask) != 0)
devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */
return devclass;
}
static void
device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
{
const char *subsystem;
const char *val = NULL;
int devclass = 0;
const char *path;
SDL_UDEV_CallbackList *item;
path = _this->syms.udev_device_get_devnode(dev);
if (path == NULL) {
return;
}
subsystem = _this->syms.udev_device_get_subsystem(dev);
if (SDL_strcmp(subsystem, "sound") == 0) {
devclass = SDL_UDEV_DEVICE_SOUND;
} else if (SDL_strcmp(subsystem, "input") == 0) {
/* udev rules reference: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c */
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
}
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE) &&
val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_JOYSTICK;
}
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_MOUSE;
}
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_TOUCHSCREEN");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN;
}
/* The undocumented rule is:
- All devices with keys get ID_INPUT_KEY
- From this subset, if they have ESC, numbers, and Q to D, it also gets ID_INPUT_KEYBOARD
Ref: http://cgit.freedesktop.org/systemd/systemd/tree/src/udev/udev-builtin-input_id.c#n183
*/
val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_KEY");
if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
devclass |= SDL_UDEV_DEVICE_KEYBOARD;
}
if (devclass == 0) {
/* Fall back to old style input classes */
val = _this->syms.udev_device_get_property_value(dev, "ID_CLASS");
if (val != NULL) {
if (SDL_strcmp(val, "joystick") == 0) {
devclass = SDL_UDEV_DEVICE_JOYSTICK;
} else if (SDL_strcmp(val, "mouse") == 0) {
devclass = SDL_UDEV_DEVICE_MOUSE;
} else if (SDL_strcmp(val, "kbd") == 0) {
devclass = SDL_UDEV_DEVICE_KEYBOARD;
} else {
return;
}
} else {
/* We could be linked with libudev on a system that doesn't have udev running */
devclass = guess_device_class(dev);
}
}
} else {
return;
}
/* Process callbacks */
for (item = _this->first; item != NULL; item = item->next) {
item->callback(type, devclass, path);
}
}
void
SDL_UDEV_Poll(void)
{
struct udev_device *dev = NULL;
const char *action = NULL;
if (_this == NULL) {
return;
}
while (SDL_UDEV_hotplug_update_available()) {
dev = _this->syms.udev_monitor_receive_device(_this->udev_mon);
if (dev == NULL) {
break;
}
action = _this->syms.udev_device_get_action(dev);
if (SDL_strcmp(action, "add") == 0) {
/* Wait for the device to finish initialization */
SDL_Delay(100);
device_event(SDL_UDEV_DEVICEADDED, dev);
} else if (SDL_strcmp(action, "remove") == 0) {
device_event(SDL_UDEV_DEVICEREMOVED, dev);
}
_this->syms.udev_device_unref(dev);
}
}
int
SDL_UDEV_AddCallback(SDL_UDEV_Callback cb)
{
SDL_UDEV_CallbackList *item;
item = (SDL_UDEV_CallbackList *) SDL_calloc(1, sizeof (SDL_UDEV_CallbackList));
if (item == NULL) {
return SDL_OutOfMemory();
}
item->callback = cb;
if (_this->last == NULL) {
_this->first = _this->last = item;
} else {
_this->last->next = item;
_this->last = item;
}
return 1;
}
void
SDL_UDEV_DelCallback(SDL_UDEV_Callback cb)
{
SDL_UDEV_CallbackList *item;
SDL_UDEV_CallbackList *prev = NULL;
for (item = _this->first; item != NULL; item = item->next) {
/* found it, remove it. */
if (item->callback == cb) {
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(_this->first == item);
_this->first = item->next;
}
if (item == _this->last) {
_this->last = prev;
}
SDL_free(item);
return;
}
prev = item;
}
}
const SDL_UDEV_Symbols *
SDL_UDEV_GetUdevSyms(void)
{
if (SDL_UDEV_Init() < 0) {
SDL_SetError("Could not initialize UDEV");
return NULL;
}
return &_this->syms;
}
void
SDL_UDEV_ReleaseUdevSyms(void)
{
SDL_UDEV_Quit();
}
#endif /* SDL_USE_LIBUDEV */
/* vi: set ts=4 sw=4 expandtab: */

125
externals/SDL/src/core/linux/SDL_udev.h vendored Executable file
View File

@@ -0,0 +1,125 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#ifndef SDL_udev_h_
#define SDL_udev_h_
#if HAVE_LIBUDEV_H
#ifndef SDL_USE_LIBUDEV
#define SDL_USE_LIBUDEV 1
#endif
#include "SDL_loadso.h"
#include "SDL_events.h"
#include <libudev.h>
#include <sys/time.h>
#include <sys/types.h>
/**
* \brief Device type
*/
typedef enum
{
SDL_UDEV_DEVICEADDED = 1,
SDL_UDEV_DEVICEREMOVED
} SDL_UDEV_deviceevent;
/* A device can be any combination of these classes */
typedef enum
{
SDL_UDEV_DEVICE_UNKNOWN = 0x0000,
SDL_UDEV_DEVICE_MOUSE = 0x0001,
SDL_UDEV_DEVICE_KEYBOARD = 0x0002,
SDL_UDEV_DEVICE_JOYSTICK = 0x0004,
SDL_UDEV_DEVICE_SOUND = 0x0008,
SDL_UDEV_DEVICE_TOUCHSCREEN = 0x0010
} SDL_UDEV_deviceclass;
typedef void (*SDL_UDEV_Callback)(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
typedef struct SDL_UDEV_CallbackList {
SDL_UDEV_Callback callback;
struct SDL_UDEV_CallbackList *next;
} SDL_UDEV_CallbackList;
typedef struct SDL_UDEV_Symbols {
const char *(*udev_device_get_action)(struct udev_device *);
const char *(*udev_device_get_devnode)(struct udev_device *);
const char *(*udev_device_get_subsystem)(struct udev_device *);
struct udev_device *(*udev_device_get_parent_with_subsystem_devtype)(struct udev_device *udev_device, const char *subsystem, const char *devtype);
const char *(*udev_device_get_property_value)(struct udev_device *, const char *);
const char *(*udev_device_get_sysattr_value)(struct udev_device *udev_device, const char *sysattr);
struct udev_device *(*udev_device_new_from_syspath)(struct udev *, const char *);
void (*udev_device_unref)(struct udev_device *);
int (*udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *);
int (*udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *);
struct udev_list_entry *(*udev_enumerate_get_list_entry)(struct udev_enumerate *);
struct udev_enumerate *(*udev_enumerate_new)(struct udev *);
int (*udev_enumerate_scan_devices)(struct udev_enumerate *);
void (*udev_enumerate_unref)(struct udev_enumerate *);
const char *(*udev_list_entry_get_name)(struct udev_list_entry *);
struct udev_list_entry *(*udev_list_entry_get_next)(struct udev_list_entry *);
int (*udev_monitor_enable_receiving)(struct udev_monitor *);
int (*udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *);
int (*udev_monitor_get_fd)(struct udev_monitor *);
struct udev_monitor *(*udev_monitor_new_from_netlink)(struct udev *, const char *);
struct udev_device *(*udev_monitor_receive_device)(struct udev_monitor *);
void (*udev_monitor_unref)(struct udev_monitor *);
struct udev *(*udev_new)(void);
void (*udev_unref)(struct udev *);
struct udev_device * (*udev_device_new_from_devnum)(struct udev *udev, char type, dev_t devnum);
dev_t (*udev_device_get_devnum) (struct udev_device *udev_device);
} SDL_UDEV_Symbols;
typedef struct SDL_UDEV_PrivateData
{
const char *udev_library;
void *udev_handle;
struct udev *udev;
struct udev_monitor *udev_mon;
int ref_count;
SDL_UDEV_CallbackList *first, *last;
/* Function pointers */
SDL_UDEV_Symbols syms;
} SDL_UDEV_PrivateData;
extern int SDL_UDEV_Init(void);
extern void SDL_UDEV_Quit(void);
extern void SDL_UDEV_UnloadLibrary(void);
extern int SDL_UDEV_LoadLibrary(void);
extern void SDL_UDEV_Poll(void);
extern void SDL_UDEV_Scan(void);
extern int SDL_UDEV_AddCallback(SDL_UDEV_Callback cb);
extern void SDL_UDEV_DelCallback(SDL_UDEV_Callback cb);
extern const SDL_UDEV_Symbols *SDL_UDEV_GetUdevSyms(void);
extern void SDL_UDEV_ReleaseUdevSyms(void);
#endif /* HAVE_LIBUDEV_H */
#endif /* SDL_udev_h_ */
/* vi: set ts=4 sw=4 expandtab: */