Files
DroidDeck/tools/linuxfs/preload/inputudev.c
T
MaxsTechReview c5577478ca chore: remove source comments and unused code, translate every missing string (#1965)
* chore(i18n): translate every missing string in all locales

Adds the 87 strings the bottom-screen Dashboard and in-game stats pages
introduced to all 32 locales, plus the 51 older settings strings Japanese
and the 50 Chinese locales were still missing. Every locale now has all
3456 translatable strings with the same placeholders as English.

Also translates 36 entries that were still English where the language
does not use the English word, and makes es-419 touch_app_id use the same
%1$s placeholder as English.

* chore(patches): drop comments from the lines downstream patches add

Removes comment lines and trailing comments from lines our patches add,
with hunk headers recounted. Lines that a later patch uses as context
and the upstream backport 0123 are left as they are.

The gamescope, FEX, proot and xodus series still apply to their pinned
sources, and the patched trees differ only in those comments.
test_hud_frames now finds the HUD writer by its first declaration.

* docs: credit Greenlight, Better xCloud, viture-v2, GameNative and DiRTTelemetryErrorFix

These were credited only in source headers and NOTICE files.

* chore: remove source comments and unused functions

Removes explanatory comments from first-party Kotlin, Java, C, C++,
Rust, TypeScript, Python, shell, Gradle, CMake and workflow files.
License and attribution headers stay, and vendored third-party trees,
generated files and license files are untouched. A shellcheck directive
is kept, and udevmon's fallthrough comments became fallthrough attributes.

Syntax trees and token streams match the previous sources apart from the
comments and Python docstrings. Module docstrings that argparse prints
are kept, and device-smoke.sh prints the same --help text from a heredoc.

Also removes 37 functions and 4 fields that nothing referenced.

* chore: remove comments from the Syncthing integration and the latest main sources

* docs: credit Syncthing and the syncthing-android fork

* chore(i18n): translate the Syncthing strings in all locales

The 107 strings the Syncthing integration added are now in all 32 locales.
sync_web_path_locked names the Syncthing tab by its label.

* docs: credit @xXJSONDeruloXx for the HUD metric readers

The CPU, GPU load, thermal and battery readers come from their
PerformanceHudView pull requests #777, #877, #991, #1406 and #1573.
The FusionHUD credit line is unchanged.

* docs: credit the HUD metric readers to @xXJSONDeruloXx's work
2026-11-01 16:27:27 -05:00

342 lines
11 KiB
C

/*
* Ported from WinNative (maxjivi05, feature/wayland-gamescope, 2026-09-18/19), GPL-3.0.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <limits.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
#define RING_MAX 4
#define UINPUT_BASE 16
#define PAD_MAX 64
#define EVENT_MINOR_BASE 64
#define PAD_UEVENT_FORMAT \
"PRODUCT=6/28de/11ff/110\n" \
"NAME=\"Generic HID Gamepad %d\"\n" \
"PHYS=\"usb-fakeinput/input%d\"\n"
#define PAD_PHYSICAL_UEVENT_FORMAT \
"PRODUCT=3/45e/28e/110\n" \
"NAME=\"Xbox 360 Controller (%d)\"\n" \
"PHYS=\"usb-fakeinput/input%d\"\n"
struct pad {
char syspath[64];
char devnode[32];
char sysname[16];
char uevent[256];
dev_t devnum;
};
static struct pad pads[PAD_MAX];
static int pad_count;
static pthread_mutex_t virtual_lock = PTHREAD_MUTEX_INITIALIZER;
static void discover_pads(void) {
const char *spec = getenv("FAKE_EVDEV_MEMFD_PATHS");
const char *entry;
if (spec == NULL) return;
for (entry = spec; *entry != '\0';) {
char *end;
long slot = strtol(entry, &end, 10);
if (end != entry && *end == '=' && slot >= 0 && slot < RING_MAX) {
struct pad *pad = &pads[slot];
if (pad->devnode[0] == '\0') {
snprintf(pad->sysname, sizeof(pad->sysname), "event%ld", slot);
snprintf(pad->syspath, sizeof(pad->syspath), "/sys/devices/virtual/input/droiddeck%ld",
slot);
snprintf(pad->devnode, sizeof(pad->devnode), "/dev/input/event%ld", slot);
snprintf(pad->uevent, sizeof(pad->uevent), PAD_UEVENT_FORMAT, (int)slot, (int)slot);
pad->devnum = makedev(13, EVENT_MINOR_BASE + (unsigned int)slot);
if (slot >= pad_count) pad_count = (int)slot + 1;
}
}
entry = strchr(entry, ';');
if (entry == NULL) break;
entry++;
}
}
static void ensure_pads(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, discover_pads);
}
static int uinput_enabled(void) {
const char *enabled = getenv("FAKE_EVDEV_UINPUT");
return enabled != NULL && atoi(enabled) != 0;
}
static int read_virtual_uevent(int node, char *buf, size_t size) {
const char *dir = getenv("FAKE_EVDEV_DIR");
char path[PATH_MAX];
FILE *file;
size_t length;
if (dir == NULL) return 0;
snprintf(path, sizeof(path), "%s/.uinput-event%d.uevent", dir, node);
if ((file = fopen(path, "re")) == NULL) return 0;
length = fread(buf, 1, size - 1, file);
fclose(file);
buf[length] = '\0';
return length > 0;
}
static int any_virtual_pad(void) {
char uevent[256];
int node;
for (node = UINPUT_BASE; node < PAD_MAX; node++)
if (read_virtual_uevent(node, uevent, sizeof(uevent))) return 1;
return 0;
}
static void refresh_pad(int node) {
struct pad *pad;
if (node < 0 || node >= PAD_MAX) return;
pad = &pads[node];
pthread_mutex_lock(&virtual_lock);
if (node >= UINPUT_BASE) {
char uevent[sizeof(pad->uevent)];
if (read_virtual_uevent(node, uevent, sizeof(uevent))) {
snprintf(pad->sysname, sizeof(pad->sysname), "event%d", node);
snprintf(pad->syspath, sizeof(pad->syspath), "/sys/devices/virtual/input/droiddeck%d", node);
memcpy(pad->uevent, uevent, sizeof(uevent));
pad->devnum = makedev(13, EVENT_MINOR_BASE + (unsigned int)node);
snprintf(pad->devnode, sizeof(pad->devnode), "/dev/input/event%d", node);
if (node >= pad_count) pad_count = node + 1;
} else {
pad->devnode[0] = '\0';
}
} else if (pad->devnode[0] != '\0' && uinput_enabled()) {
snprintf(pad->uevent, sizeof(pad->uevent),
any_virtual_pad() ? PAD_PHYSICAL_UEVENT_FORMAT : PAD_UEVENT_FORMAT, node, node);
}
pthread_mutex_unlock(&virtual_lock);
}
static struct pad *pad_for_syspath(const char *syspath) {
int i;
if (syspath == NULL) return NULL;
ensure_pads();
for (i = 0; i < pad_count; i++) {
if (pads[i].devnode[0] != '\0' && strcmp(pads[i].syspath, syspath) == 0) return &pads[i];
}
return NULL;
}
static struct pad *pad_for_device(void *device) {
int i;
if (device == NULL) return NULL;
ensure_pads();
for (i = 0; i < pad_count; i++) {
if (&pads[i] == device) return pads[i].devnode[0] != '\0' ? &pads[i] : NULL;
}
return NULL;
}
static struct pad *pad_for_syslink(const char *path) {
static const char prefix[] = "/sys/class/input/";
const char *name;
int i;
if (path == NULL || strncmp(path, prefix, sizeof(prefix) - 1) != 0) return NULL;
name = path + sizeof(prefix) - 1;
ensure_pads();
if (strncmp(name, "event", 5) == 0 && name[5] >= '0' && name[5] <= '9') refresh_pad(atoi(name + 5));
for (i = 0; i < pad_count; i++) {
if (pads[i].devnode[0] != '\0' && strcmp(pads[i].sysname, name) == 0) return &pads[i];
}
return NULL;
}
static void *next_symbol(const char *name) { return dlsym(RTLD_NEXT, name); }
char *bl_cached_realpath(const char *path, char *resolved, char *(*real)(const char *, char *))
__attribute__((visibility("hidden")));
static int caller_is_winebus(void *caller) {
Dl_info info;
if (dladdr(caller, &info) == 0 || info.dli_fname == NULL) return 0;
return strstr(info.dli_fname, "winebus.so") != NULL;
}
__attribute__((visibility("hidden"))) int bl_winebus_rumble_ioctl(int (*real)(int, unsigned long, void *), int fd,
unsigned long request, void *arg, void *caller,
int *rc) {
struct ff_effect *effect = arg;
__u16 length;
if (request != EVIOCSFF || effect == NULL || effect->type != FF_RUMBLE || !caller_is_winebus(caller)) return 0;
length = effect->replay.length;
effect->replay.length = 0;
*rc = real(fd, request, arg);
effect->replay.length = length;
return 1;
}
char *realpath(const char *path, char *resolved) {
static char *(*real_realpath)(const char *, char *);
void *caller = __builtin_return_address(0);
struct pad *pad = caller_is_winebus(caller) ? pad_for_syslink(path) : NULL;
if (pad != NULL) {
if (resolved == NULL) return strdup(pad->syspath);
memcpy(resolved, pad->syspath, strlen(pad->syspath) + 1);
return resolved;
}
if (real_realpath == NULL) real_realpath = next_symbol("realpath");
if (real_realpath == NULL) return NULL;
return bl_cached_realpath(path, resolved, real_realpath);
}
void *udev_device_new_from_syspath(void *udev, const char *syspath) {
static void *(*real_new)(void *, const char *);
void *caller = __builtin_return_address(0);
struct pad *pad = caller_is_winebus(caller) ? pad_for_syspath(syspath) : NULL;
if (pad != NULL) return pad;
if (real_new == NULL) real_new = next_symbol("udev_device_new_from_syspath");
if (real_new == NULL) return NULL;
return real_new(udev, syspath);
}
void *udev_device_ref(void *device) {
static void *(*real_ref)(void *);
if (pad_for_device(device) != NULL) return device;
if (real_ref == NULL) real_ref = next_symbol("udev_device_ref");
if (real_ref == NULL) return NULL;
return real_ref(device);
}
void *udev_device_unref(void *device) {
static void *(*real_unref)(void *);
if (pad_for_device(device) != NULL) return NULL;
if (real_unref == NULL) real_unref = next_symbol("udev_device_unref");
if (real_unref == NULL) return NULL;
return real_unref(device);
}
const char *udev_device_get_devnode(void *device) {
static const char *(*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return pad->devnode;
if (real_get == NULL) real_get = next_symbol("udev_device_get_devnode");
if (real_get == NULL) return NULL;
return real_get(device);
}
const char *udev_device_get_syspath(void *device) {
static const char *(*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return pad->syspath;
if (real_get == NULL) real_get = next_symbol("udev_device_get_syspath");
if (real_get == NULL) return NULL;
return real_get(device);
}
const char *udev_device_get_sysname(void *device) {
static const char *(*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return pad->sysname;
if (real_get == NULL) real_get = next_symbol("udev_device_get_sysname");
if (real_get == NULL) return NULL;
return real_get(device);
}
const char *udev_device_get_subsystem(void *device) {
static const char *(*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return "input";
if (real_get == NULL) real_get = next_symbol("udev_device_get_subsystem");
if (real_get == NULL) return NULL;
return real_get(device);
}
const char *udev_device_get_devtype(void *device) {
static const char *(*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return NULL;
if (real_get == NULL) real_get = next_symbol("udev_device_get_devtype");
if (real_get == NULL) return NULL;
return real_get(device);
}
const char *udev_device_get_action(void *device) {
static const char *(*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return NULL;
if (real_get == NULL) real_get = next_symbol("udev_device_get_action");
if (real_get == NULL) return NULL;
return real_get(device);
}
dev_t udev_device_get_devnum(void *device) {
static dev_t (*real_get)(void *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return pad->devnum;
if (real_get == NULL) real_get = next_symbol("udev_device_get_devnum");
if (real_get == NULL) return makedev(0, 0);
return real_get(device);
}
void *udev_device_get_parent_with_subsystem_devtype(void *device, const char *subsystem,
const char *devtype) {
static void *(*real_get)(void *, const char *, const char *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) {
if (subsystem != NULL && strcmp(subsystem, "input") == 0 && devtype == NULL) return pad;
return NULL;
}
if (real_get == NULL) real_get = next_symbol("udev_device_get_parent_with_subsystem_devtype");
if (real_get == NULL) return NULL;
return real_get(device, subsystem, devtype);
}
const char *udev_device_get_sysattr_value(void *device, const char *attr) {
static const char *(*real_get)(void *, const char *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return attr != NULL && strcmp(attr, "uevent") == 0 ? pad->uevent : NULL;
if (real_get == NULL) real_get = next_symbol("udev_device_get_sysattr_value");
if (real_get == NULL) return NULL;
return real_get(device, attr);
}
const char *udev_device_get_property_value(void *device, const char *key) {
static const char *(*real_get)(void *, const char *);
struct pad *pad = pad_for_device(device);
if (pad != NULL) return key != NULL && strcmp(key, "ID_INPUT_JOYSTICK") == 0 ? "1" : NULL;
if (real_get == NULL) real_get = next_symbol("udev_device_get_property_value");
if (real_get == NULL) return NULL;
return real_get(device, key);
}