? BUILD.log Index: Makefile =================================================================== RCS file: /cvs/ports/games/godot/pack1/Makefile,v diff -u -p -r1.4 Makefile --- Makefile 16 May 2026 00:44:44 -0000 1.4 +++ Makefile 29 May 2026 20:27:40 -0000 @@ -6,12 +6,12 @@ COMMENT-sharp= .NET libs for mono/C# mod VERSION = 3.6.2 PKGNAME = godot3-${VERSION} SHARPFILES_V = 3.5.2 -REVISION = 1 +REVISION = 2 MULTI_PACKAGES = -main -sharp WANTLIB += ${COMPILER_LIBCXX} BulletCollision BulletDynamics BulletSoftBody -WANTLIB += GL LinearMath X11 Xcursor Xext +WANTLIB += GL LinearMath SDL3 X11 Xcursor Xext WANTLIB += Xi Xinerama Xrandr Xrender c enet execinfo WANTLIB += intl m mbedcrypto mbedtls mbedx509 mpcdec ogg opus WANTLIB += opusfile pcre2-32 sndio steam_api theora theoradec @@ -61,6 +61,7 @@ LIB_DEPENDS = archivers/zstd \ devel/bullet \ devel/gettext,-runtime \ devel/pcre2 \ + devel/sdl3 \ games/goldberg_emulator \ graphics/libwebp \ multimedia/libtheora \ @@ -111,8 +112,6 @@ CXXFLAGS += -I${LOCALBASE}/include/goldb post-extract: cp -R ${FILESDIR}/sndio ${WRKDIST}/drivers - cp ${FILESDIR}/ujoy/joypad_openbsd.{cpp,h} \ - ${WRKDIST}/platform/x11/ .if ${PROPERTIES:Mmono} mkdir -p ${PORTHOME}/.nuget mv ${WRKDIR}/godot-${SHARPFILES_V}-nuget-packages ${PORTHOME}/.nuget/packages Index: files/ujoy/joypad_openbsd.cpp =================================================================== RCS file: files/ujoy/joypad_openbsd.cpp diff -N files/ujoy/joypad_openbsd.cpp --- files/ujoy/joypad_openbsd.cpp 4 Mar 2026 05:35:04 -0000 1.1.1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,470 +0,0 @@ -/*************************************************************************/ -/* joypad_openbsd.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -//author: Thomas Frohwein -#ifdef JOYDEV_ENABLED - -#include "joypad_openbsd.h" - -#include - -#include -#include -#include - -extern "C" { - #include - #include - #include -} - -#define HUG_DPAD_UP 0x90 -#define HUG_DPAD_DOWN 0x91 -#define HUG_DPAD_RIGHT 0x92 -#define HUG_DPAD_LEFT 0x93 - -#define HAT_CENTERED 0x00 -#define HAT_UP 0x01 -#define HAT_RIGHT 0x02 -#define HAT_DOWN 0x04 -#define HAT_LEFT 0x08 -#define HAT_RIGHTUP (HAT_RIGHT|HAT_UP) -#define HAT_RIGHTDOWN (HAT_RIGHT|HAT_DOWN) -#define HAT_LEFTUP (HAT_LEFT|HAT_UP) -#define HAT_LEFTDOWN (HAT_LEFT|HAT_DOWN) - -#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data) - -static struct -{ - int uhid_report; - hid_kind_t kind; - const char *name; -} const repinfo[] = { - {UHID_INPUT_REPORT, hid_input, "input"}, - {UHID_OUTPUT_REPORT, hid_output, "output"}, - {UHID_FEATURE_REPORT, hid_feature, "feature"} -}; - -enum -{ - REPORT_INPUT, - REPORT_OUTPUT, - REPORT_FEATURE -}; - -enum -{ - JOYAXE_X, - JOYAXE_Y, - JOYAXE_Z, - JOYAXE_SLIDER, - JOYAXE_WHEEL, - JOYAXE_RX, - JOYAXE_RY, - JOYAXE_RZ, - JOYAXE_count -}; - -static int -report_alloc(struct report *r, struct report_desc *rd, int repind) -{ - int len; - len = hid_report_size(rd, repinfo[repind].kind, r->rid); - if (len < 0) { - ERR_PRINT("Negative HID report siz"); - return ERR_PARAMETER_RANGE_ERROR; - } - r->size = len; - - if (r->size > 0) { - r->buf = (usb_ctl_report *)malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) + r->size); - if (r->buf == NULL) - return ERR_OUT_OF_MEMORY; - } else { - r->buf = NULL; - } - - r->status = report::SREPORT_CLEAN; - return OK; -} - -static int -usage_to_joyaxe(unsigned usage) -{ - switch (usage) { - case HUG_X: - return JOYAXE_X; - case HUG_Y: - return JOYAXE_Y; - case HUG_Z: - return JOYAXE_Z; - case HUG_SLIDER: - return JOYAXE_SLIDER; - case HUG_WHEEL: - return JOYAXE_WHEEL; - case HUG_RX: - return JOYAXE_RX; - case HUG_RY: - return JOYAXE_RY; - case HUG_RZ: - return JOYAXE_RZ; - default: - return -1; - } -} - -static unsigned -hatval_conversion(int hatval) -{ - static const unsigned hat_dir_map[8] = { - HAT_UP, HAT_RIGHTUP, HAT_RIGHT, HAT_RIGHTDOWN, - HAT_DOWN, HAT_LEFTDOWN, HAT_LEFT, HAT_LEFTUP - }; - if ((hatval & 7) == hatval) - return hat_dir_map[hatval]; - else - return HAT_CENTERED; -} - -/* calculate the value from the state of the dpad */ -int -dpad_conversion(int *dpad) -{ - if (dpad[2]) { - if (dpad[0]) - return HAT_RIGHTUP; - else if (dpad[1]) - return HAT_RIGHTDOWN; - else - return HAT_RIGHT; - } else if (dpad[3]) { - if (dpad[0]) - return HAT_LEFTUP; - else if (dpad[1]) - return HAT_LEFTDOWN; - else - return HAT_LEFT; - } else if (dpad[0]) { - return HAT_UP; - } else if (dpad[1]) { - return HAT_DOWN; - } - return HAT_CENTERED; -} - -JoypadOpenBSD::Joypad::Joypad() { - fd = -1; - dpad = 0; - devpath = ""; -} - -JoypadOpenBSD::Joypad::~Joypad() { -} - -void JoypadOpenBSD::Joypad::reset() { - dpad = 0; - fd = -1; - - for (int i = 0; i < MAX_ABS; ++i) { - abs_map[i] = -1; - curr_axis[i] = 0; - } -} - -JoypadOpenBSD::JoypadOpenBSD(InputDefault *in) { - input = in; - joy_thread.start(joy_thread_func, this); - hid_init(NULL); -} - -JoypadOpenBSD::~JoypadOpenBSD() { - exit_monitor.set(); - joy_thread.wait_to_finish(); - close_joypad(); -} - -void JoypadOpenBSD::joy_thread_func(void *p_user) { - if (p_user) { - JoypadOpenBSD *joy = (JoypadOpenBSD *)p_user; - joy->run_joypad_thread(); - } -} - -void JoypadOpenBSD::run_joypad_thread() { - monitor_joypads(); -} - -void JoypadOpenBSD::monitor_joypads() { - while (!exit_monitor.is_set()) { - joy_mutex.lock(); - for (int i = 0; i < 32; i++) { - char fname[64]; - sprintf(fname, "/dev/ujoy/%d", i); - if (attached_devices.find(fname) == -1) { - open_joypad(fname); - } - } - joy_mutex.unlock(); - usleep(1000000); // 1s - } -} - -int JoypadOpenBSD::get_joy_from_path(String p_path) const { - for (int i = 0; i < JOYPADS_MAX; i++) { - if (joypads[i].devpath == p_path) { - return i; - } - } - return -2; -} - -void JoypadOpenBSD::close_joypad(int p_id) { - if (p_id == -1) { - for (int i = 0; i < JOYPADS_MAX; i++) { - close_joypad(i); - }; - return; - } else if (p_id < 0) - return; - - Joypad &joy = joypads[p_id]; - - if (joy.fd != -1) { - close(joy.fd); - joy.fd = -1; - attached_devices.remove(attached_devices.find(joy.devpath)); - input->joy_connection_changed(p_id, false, ""); - }; -} - -void JoypadOpenBSD::setup_joypad_properties(int p_id) { - Error err; - Joypad *joy = &joypads[p_id]; - struct hid_item hitem; - struct hid_data *hdata; - struct report *rep = NULL; - int i; - int ax; - - for (ax = 0; ax < JOYAXE_count; ax++) - joy->axis_map[ax] = -1; - - joy->type = Joypad::BSDJOY_UHID; // TODO: hardcoded; later check if /dev/joyX or /dev/ujoy/X - joy->repdesc = hid_get_report_desc(joy->fd); - if (joy->repdesc == NULL) { - ERR_PRINT("getting USB report descriptor"); - } - rep = &joy->inreport; - if (ioctl(joy->fd, USB_GET_REPORT_ID, &rep->rid) < 0) { - rep->rid = -1; /* XXX */ - } - err = (Error)report_alloc(rep, joy->repdesc, REPORT_INPUT); - if (err != OK) { - ERR_PRINT("allocating report descriptor"); - } - if (rep->size <= 0) { - ERR_PRINT("input report descriptor has invalid length"); - } - hdata = hid_start_parse(joy->repdesc, 1 << hid_input, rep->rid); - if (hdata == NULL) { - ERR_PRINT("cannot start HID parser"); - } - - int num_buttons = 0; - int num_axes = 0; - int num_hats = 0; - - while (hid_get_item(hdata, &hitem)) { - switch (hitem.kind) { - case hid_input: - switch (HID_PAGE(hitem.usage)) { - case HUP_GENERIC_DESKTOP: { - unsigned usage = HID_USAGE(hitem.usage); - int joyaxe = usage_to_joyaxe(usage); - if (joyaxe >= 0) { - joy->axis_map[joyaxe] = 1; - } else if (usage == HUG_HAT_SWITCH || usage == HUG_DPAD_UP) { - num_hats++; - } - break; - } - case HUP_BUTTON: - num_buttons++; - break; - default: - break; - } - default: - break; - } - } - hid_end_parse(hdata); - for (i = 0; i < JOYAXE_count; i++) - if (joy->axis_map[i] > 0) - joy->axis_map[i] = num_axes++; - - if (num_axes == 0 && num_buttons == 0 && num_hats == 0) { - ERR_PRINT("Not a joystick!"); - } else { - printf("joypad %d: %d axes %d buttons %d hats\n", p_id, num_axes, num_buttons, num_hats); - } - joy->force_feedback = false; - joy->ff_effect_timestamp = 0; -} - -void JoypadOpenBSD::open_joypad(const char *p_path) { - int joy_num = input->get_unused_joy_id(); - if (joy_num < 0) { - ERR_PRINT("no ID available to assign to joypad device"); - return; - } - int fd = open(p_path, O_RDONLY | O_NONBLOCK); - if (fd != -1 && joy_num != -1) { - // add to attached devices so we don't try to open it again - attached_devices.push_back(String(p_path)); - - String name = ""; - joypads[joy_num].reset(); - - Joypad &joy = joypads[joy_num]; - joy.fd = fd; - joy.devpath = String(p_path); - setup_joypad_properties(joy_num); - String uidname = "00"; - input->joy_connection_changed(joy_num, true, name, uidname); - } -} - -void JoypadOpenBSD::joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { - /* not supported */ -} - -void JoypadOpenBSD::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { - /* not supported */ -} - -float JoypadOpenBSD::axis_correct(int min, int max, int p_value) const { - // Convert to a value between -1.0 and 1.0f. - return 2.0f * (p_value - min) / (max - min) - 1.0f; -} - -void JoypadOpenBSD::process_joypads() { - struct hid_item hitem; - struct hid_data *hdata; - struct report *rep; - int nbutton, naxe = -1; - int v; - int dpad[4] = { 0, 0, 0, 0 }; - int actualbutton; - - if (joy_mutex.try_lock() != OK) { - return; - } - for (int i = 0; i < JOYPADS_MAX; i++) { - if (joypads[i].fd == -1) continue; - - Joypad *joy = &joypads[i]; - rep = &joy->inreport; - - while (true) { - ssize_t r = read(joy->fd, REP_BUF_DATA(rep), rep->size); - if (r < 0 || (size_t)r != rep->size) { - break; - } - - hdata = hid_start_parse(joy->repdesc, 1 << hid_input, rep->rid); - if (hdata == NULL) { - continue; - } - - for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) { - (void)nbutton; - switch (hitem.kind) { - case hid_input: - unsigned usage; - int joyaxe; - switch (HID_PAGE(hitem.usage)) { - case HUP_GENERIC_DESKTOP: - usage = HID_USAGE(hitem.usage); - joyaxe = usage_to_joyaxe(usage); - if (joyaxe >= 0) { - naxe = joy->axis_map[joyaxe]; - (void)naxe; - v = hid_get_data(REP_BUF_DATA(rep), &hitem); - /* XInput controllermapping relies on inverted Y axes. - * These devices have a 16bit signed space, as opposed - * to older DInput devices (8bit unsigned), so - * hitem.logical_maximum can be used to differentiate them. - */ - if ((joyaxe == JOYAXE_Y || joyaxe == JOYAXE_RY) - && hitem.logical_maximum > 255) { - if (v != 0) - v = ~v; - } - input->joy_axis(i, joyaxe, axis_correct(hitem.logical_minimum, hitem.logical_maximum, v)); - break; - } else if (usage == HUG_HAT_SWITCH) { - v = hid_get_data(REP_BUF_DATA(rep), &hitem); - joy->dpad = hatval_conversion(v); - } else if (usage == HUG_DPAD_UP) { - dpad[0] = hid_get_data(REP_BUF_DATA(rep), &hitem); - joy->dpad = dpad_conversion(dpad); - } else if (usage == HUG_DPAD_DOWN) { - dpad[1] = hid_get_data(REP_BUF_DATA(rep), &hitem); - joy->dpad = dpad_conversion(dpad); - } else if (usage == HUG_DPAD_RIGHT) { - dpad[2] = hid_get_data(REP_BUF_DATA(rep), &hitem); - joy->dpad = dpad_conversion(dpad); - } else if (usage == HUG_DPAD_LEFT) { - dpad[3] = hid_get_data(REP_BUF_DATA(rep), &hitem); - joy->dpad = dpad_conversion(dpad); - } - input->joy_hat(i, joy->dpad); - break; - case HUP_BUTTON: - v = hid_get_data(REP_BUF_DATA(rep), &hitem); - actualbutton = HID_USAGE(hitem.usage) - 1; // buttons are zero-based - input->joy_button(i, actualbutton, v); - default: - continue; - } - break; - default: - break; - } - } - hid_end_parse(hdata); - } - } - joy_mutex.unlock(); -} - -#endif Index: files/ujoy/joypad_openbsd.h =================================================================== RCS file: files/ujoy/joypad_openbsd.h diff -N files/ujoy/joypad_openbsd.h --- files/ujoy/joypad_openbsd.h 4 Mar 2026 05:35:04 -0000 1.1.1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,121 +0,0 @@ -/*************************************************************************/ -/* joypad_openbsd.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -//author: Thomas Frohwein -#ifndef JOYPAD_OPENBSD_H -#define JOYPAD_OPENBSD_H - -#ifdef JOYDEV_ENABLED -#include "core/os/mutex.h" -#include "core/os/thread.h" -#include "main/input_default.h" - -struct input_absinfo; - -struct report -{ - struct usb_ctl_report *buf; /* Buffer */ - size_t size; /* Buffer size */ - int rid; /* Report ID */ - enum - { - SREPORT_UNINIT, - SREPORT_CLEAN, - SREPORT_DIRTY - } status; -}; - -class JoypadOpenBSD { -public: - JoypadOpenBSD(InputDefault *in); - ~JoypadOpenBSD(); - void process_joypads(); - -private: - enum { - JOYPADS_MAX = 16, - MAX_ABS = 63, - MAX_KEY = 767, // Hack because can't be included here - }; - - struct Joypad { - float curr_axis[MAX_ABS]; - int key_map[MAX_KEY]; - int abs_map[MAX_ABS]; - int dpad; - int fd; - - char *path; - enum - { - BSDJOY_UHID, /* uhid(4) */ - BSDJOY_JOY /* joy(4) */ - } type; - struct report_desc *repdesc; - struct report inreport; - int axis_map[8]; /* TODO: replace with JOYAXE_count */ - - String devpath; - input_absinfo *abs_info[MAX_ABS]; - - bool force_feedback; - int ff_effect_id; - uint64_t ff_effect_timestamp; - - Joypad(); - ~Joypad(); - void reset(); - }; - - SafeFlag exit_monitor; - Mutex joy_mutex; - Thread joy_thread; - InputDefault *input; - Joypad joypads[JOYPADS_MAX]; - Vector attached_devices; - - static void joy_thread_func(void *p_user); - - int get_joy_from_path(String p_path) const; - - void setup_joypad_properties(int p_id); - void close_joypad(int p_id = -1); - void monitor_joypads(); - void run_joypad_thread(); - void open_joypad(const char *p_path); - - void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); - void joypad_vibration_stop(int p_id, uint64_t p_timestamp); - - float axis_correct(int min, int max, int p_value) const; -}; - -#endif -#endif // JOYPAD_OPENBSD_H Index: patches/patch-SConstruct =================================================================== RCS file: patches/patch-SConstruct diff -N patches/patch-SConstruct --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-SConstruct 29 May 2026 20:27:40 -0000 @@ -0,0 +1,22 @@ +backport commit 0b3496f: + Add support for SDL3 joystick input driver + +Index: SConstruct +--- SConstruct.orig ++++ SConstruct +@@ -134,6 +134,7 @@ opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 a + opts.Add(BoolVariable("disable_exceptions", "Force disabling exception handling code", True)) + opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "") + opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True)) ++opts.Add(BoolVariable("sdl", "Enable the SDL3 input driver", True)) + + # Advanced options + opts.Add(BoolVariable("dev", "If yes, alias for verbose=yes warnings=extra werror=yes", False)) +@@ -188,6 +189,7 @@ opts.Add(BoolVariable("builtin_pcre2", "Use the built- + opts.Add(BoolVariable("builtin_pcre2_with_jit", "Use JIT compiler for the built-in PCRE2 library", True)) + opts.Add(BoolVariable("builtin_recast", "Use the built-in Recast library", True)) + opts.Add(BoolVariable("builtin_rvo2", "Use the built-in RVO2 library", True)) ++opts.Add(BoolVariable("builtin_sdl", "Use the built-in SDL library", False)) + opts.Add(BoolVariable("builtin_squish", "Use the built-in squish library", True)) + opts.Add(BoolVariable("builtin_xatlas", "Use the built-in xatlas library", True)) + opts.Add(BoolVariable("builtin_zlib", "Use the built-in zlib library", True)) Index: patches/patch-core_os_input_h =================================================================== RCS file: patches/patch-core_os_input_h diff -N patches/patch-core_os_input_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-core_os_input_h 29 May 2026 20:27:40 -0000 @@ -0,0 +1,15 @@ +backport commit 0b3496f: + Add support for SDL3 joystick input driver + +Index: core/os/input.h +--- core/os/input.h.orig ++++ core/os/input.h +@@ -95,7 +95,7 @@ class Input : public Object { (public) + virtual float get_joy_axis(int p_device, int p_axis) const = 0; + virtual String get_joy_name(int p_idx) = 0; + virtual Array get_connected_joypads() = 0; +- virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) = 0; ++ virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "", const Dictionary &p_joypad_info = Dictionary()) = 0; + virtual void add_joy_mapping(String p_mapping, bool p_update_existing = false) = 0; + virtual void remove_joy_mapping(String p_guid) = 0; + virtual bool is_joy_known(int p_device) = 0; Index: patches/patch-drivers_SCsub =================================================================== RCS file: /cvs/ports/games/godot/pack1/patches/patch-drivers_SCsub,v diff -u -p -r1.1.1.1 patch-drivers_SCsub --- patches/patch-drivers_SCsub 4 Mar 2026 05:35:04 -0000 1.1.1.1 +++ patches/patch-drivers_SCsub 29 May 2026 20:27:40 -0000 @@ -1,5 +1,8 @@ add sndio +backport commit 0b3496f: +Add support for SDL3 joystick input driver + Index: drivers/SCsub --- drivers/SCsub.orig +++ drivers/SCsub @@ -11,3 +14,15 @@ Index: drivers/SCsub if env["platform"] == "windows": SConscript("wasapi/SCsub") if env["xaudio2"]: +@@ -30,6 +31,11 @@ if env["platform"] != "server": + SConscript("gl_context/SCsub") + else: + SConscript("dummy/SCsub") ++ ++# Input drivers ++if env["sdl"] and env["platform"] in ["x11", "macos", "windows"]: ++ # TODO: Evaluate support for Android, iOS, and Web. ++ SConscript("sdl/SCsub") + + # Core dependencies + SConscript("png/SCsub") Index: patches/patch-drivers_sdl_SCsub =================================================================== RCS file: patches/patch-drivers_sdl_SCsub diff -N patches/patch-drivers_sdl_SCsub --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-drivers_sdl_SCsub 29 May 2026 20:27:40 -0000 @@ -0,0 +1,215 @@ +backport commit 0b3496f: +Add support for SDL3 joystick input driver + +Index: drivers/sdl/SCsub +--- drivers/sdl/SCsub.orig ++++ drivers/sdl/SCsub +@@ -0,0 +1,208 @@ ++#!/usr/bin/env python ++ ++Import("env") ++ ++env_sdl = env.Clone() ++ ++# Thirdparty source files ++ ++thirdparty_obj = [] ++ ++if env["builtin_sdl"]: ++ thirdparty_dir = "#thirdparty/sdl/" ++ ++ # Use our own SDL_build_config_private.h. ++ env_sdl.Prepend(CPPDEFINES=["SDL_PLATFORM_PRIVATE"]) ++ ++ # Common sources. ++ ++ env_sdl.Prepend( ++ CPPPATH=[ ++ thirdparty_dir, ++ thirdparty_dir + "include", ++ thirdparty_dir + "include/build_config", ++ ".", # SDL_build_config_private.h ++ ] ++ ) ++ ++ thirdparty_sources = [ ++ "SDL.c", ++ "SDL_assert.c", ++ "SDL_error.c", ++ "SDL_guid.c", ++ "SDL_hashtable.c", ++ "SDL_hints.c", ++ "SDL_list.c", ++ "SDL_log.c", ++ "SDL_properties.c", ++ "SDL_utils.c", ++ "atomic/SDL_atomic.c", ++ "atomic/SDL_spinlock.c", ++ "events/SDL_events.c", ++ "events/SDL_eventwatch.c", ++ "haptic/SDL_haptic.c", ++ "io/SDL_iostream.c", ++ "joystick/SDL_gamepad.c", ++ "joystick/SDL_joystick.c", ++ "joystick/SDL_steam_virtual_gamepad.c", ++ "joystick/controller_type.c", ++ "libm/e_atan2.c", ++ "libm/e_exp.c", ++ "libm/e_fmod.c", ++ "libm/e_log.c", ++ "libm/e_log10.c", ++ "libm/e_pow.c", ++ "libm/e_rem_pio2.c", ++ "libm/e_sqrt.c", ++ "libm/k_cos.c", ++ "libm/k_rem_pio2.c", ++ "libm/k_sin.c", ++ "libm/k_tan.c", ++ "libm/s_atan.c", ++ "libm/s_copysign.c", ++ "libm/s_cos.c", ++ "libm/s_fabs.c", ++ "libm/s_floor.c", ++ "libm/s_isinf.c", ++ "libm/s_isinff.c", ++ "libm/s_isnan.c", ++ "libm/s_isnanf.c", ++ "libm/s_modf.c", ++ "libm/s_scalbn.c", ++ "libm/s_sin.c", ++ "libm/s_tan.c", ++ "sensor/SDL_sensor.c", ++ "sensor/dummy/SDL_dummysensor.c", ++ "stdlib/SDL_crc16.c", ++ "stdlib/SDL_crc32.c", ++ "stdlib/SDL_getenv.c", ++ "stdlib/SDL_iconv.c", ++ "stdlib/SDL_malloc.c", ++ "stdlib/SDL_memcpy.c", ++ "stdlib/SDL_memmove.c", ++ "stdlib/SDL_memset.c", ++ "stdlib/SDL_mslibc.c", ++ "stdlib/SDL_murmur3.c", ++ "stdlib/SDL_qsort.c", ++ "stdlib/SDL_random.c", ++ "stdlib/SDL_stdlib.c", ++ "stdlib/SDL_string.c", ++ "stdlib/SDL_strtokr.c", ++ "thread/SDL_thread.c", ++ "thread/generic/SDL_syscond.c", ++ "thread/generic/SDL_sysrwlock.c", ++ "thread/generic/SDL_systhread.c", ++ "timer/SDL_timer.c", ++ ] ++ ++ # HIDAPI ++ thirdparty_sources += [ ++ "hidapi/SDL_hidapi.c", ++ "joystick/hidapi/SDL_hidapi_combined.c", ++ "joystick/hidapi/SDL_hidapi_gamecube.c", ++ "joystick/hidapi/SDL_hidapijoystick.c", ++ "joystick/hidapi/SDL_hidapi_luna.c", ++ "joystick/hidapi/SDL_hidapi_ps3.c", ++ "joystick/hidapi/SDL_hidapi_ps4.c", ++ "joystick/hidapi/SDL_hidapi_ps5.c", ++ "joystick/hidapi/SDL_hidapi_rumble.c", ++ "joystick/hidapi/SDL_hidapi_shield.c", ++ "joystick/hidapi/SDL_hidapi_stadia.c", ++ "joystick/hidapi/SDL_hidapi_steam.c", ++ "joystick/hidapi/SDL_hidapi_steamdeck.c", ++ "joystick/hidapi/SDL_hidapi_steam_hori.c", ++ "joystick/hidapi/SDL_hidapi_switch.c", ++ "joystick/hidapi/SDL_hidapi_wii.c", ++ "joystick/hidapi/SDL_hidapi_xbox360.c", ++ "joystick/hidapi/SDL_hidapi_xbox360w.c", ++ "joystick/hidapi/SDL_hidapi_xboxone.c", ++ ] ++ ++ # Platform specific sources. ++ ++ if env["platform"] == "linuxbsd": ++ # TODO: Check support for BSD systems. ++ env_sdl.Append(CPPDEFINES=["SDL_PLATFORM_LINUX"]) ++ thirdparty_sources += [ ++ "core/linux/SDL_dbus.c", ++ "core/linux/SDL_evdev.c", ++ "core/linux/SDL_evdev_capabilities.c", ++ "core/linux/SDL_evdev_kbd.c", ++ "core/linux/SDL_fcitx.c", ++ "core/linux/SDL_ibus.c", ++ "core/linux/SDL_ime.c", ++ "core/linux/SDL_system_theme.c", ++ "core/linux/SDL_threadprio.c", ++ "core/linux/SDL_udev.c", ++ "core/unix/SDL_appid.c", ++ "core/unix/SDL_poll.c", ++ "haptic/linux/SDL_syshaptic.c", ++ "joystick/linux/SDL_sysjoystick.c", ++ "loadso/dlopen/SDL_sysloadso.c", ++ "thread/pthread/SDL_syscond.c", ++ "thread/pthread/SDL_sysmutex.c", ++ "thread/pthread/SDL_sysrwlock.c", ++ "thread/pthread/SDL_syssem.c", ++ "thread/pthread/SDL_systhread.c", ++ "thread/pthread/SDL_systls.c", ++ "timer/unix/SDL_systimer.c", ++ ] ++ ++ elif env["platform"] == "macos": ++ env_sdl.Append(CPPDEFINES=["SDL_PLATFORM_MACOS"]) ++ thirdparty_sources += [ ++ "core/unix/SDL_appid.c", ++ "core/unix/SDL_poll.c", ++ "haptic/darwin/SDL_syshaptic.c", ++ "joystick/darwin/SDL_iokitjoystick.c", ++ "joystick/apple/SDL_mfijoystick.m", ++ "thread/pthread/SDL_syscond.c", ++ "thread/pthread/SDL_sysmutex.c", ++ "thread/pthread/SDL_sysrwlock.c", ++ "thread/pthread/SDL_syssem.c", ++ "thread/pthread/SDL_systhread.c", ++ "thread/pthread/SDL_systls.c", ++ "timer/unix/SDL_systimer.c", ++ ] ++ ++ elif env["platform"] == "windows": ++ env_sdl.Append(CPPDEFINES=["SDL_PLATFORM_WINDOWS"]) ++ thirdparty_sources += [ ++ "core/windows/SDL_gameinput.c", ++ "core/windows/SDL_hid.c", ++ "core/windows/SDL_immdevice.c", ++ "core/windows/SDL_windows.c", ++ "core/windows/SDL_xinput.c", ++ "core/windows/pch.c", ++ "haptic/windows/SDL_dinputhaptic.c", ++ "haptic/windows/SDL_windowshaptic.c", ++ "joystick/windows/SDL_dinputjoystick.c", ++ "joystick/windows/SDL_rawinputjoystick.c", ++ "joystick/windows/SDL_windows_gaming_input.c", ++ "joystick/windows/SDL_windowsjoystick.c", ++ "joystick/windows/SDL_xinputjoystick.c", ++ "thread/windows/SDL_syscond_cv.c", ++ "thread/windows/SDL_sysmutex.c", ++ "thread/windows/SDL_sysrwlock_srw.c", ++ "thread/windows/SDL_syssem.c", ++ "thread/windows/SDL_systhread.c", ++ "thread/windows/SDL_systls.c", ++ "timer/windows/SDL_systimer.c", ++ ] ++ ++ thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] ++ ++ env_thirdparty = env_sdl.Clone() ++ env_thirdparty.disable_warnings() ++ env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources) ++ env.drivers_sources += thirdparty_obj ++ ++# Godot source files ++ ++driver_obj = [] ++ ++env_sdl.add_source_files(driver_obj, "*.cpp") ++env.drivers_sources += driver_obj ++ ++# Needed to force rebuilding the driver files when the thirdparty library is updated. ++env.Depends(driver_obj, thirdparty_obj) Index: patches/patch-drivers_sdl_SDL_build_config_private_h =================================================================== RCS file: patches/patch-drivers_sdl_SDL_build_config_private_h diff -N patches/patch-drivers_sdl_SDL_build_config_private_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-drivers_sdl_SDL_build_config_private_h 29 May 2026 20:27:40 -0000 @@ -0,0 +1,137 @@ +backport commit 0b3496f: +Add support for SDL3 joystick input driver + +Index: drivers/sdl/SDL_build_config_private.h +--- drivers/sdl/SDL_build_config_private.h.orig ++++ drivers/sdl/SDL_build_config_private.h +@@ -0,0 +1,130 @@ ++/**************************************************************************/ ++/* SDL_build_config_private.h */ ++/**************************************************************************/ ++/* This file is part of: */ ++/* GODOT ENGINE */ ++/* https://godotengine.org */ ++/**************************************************************************/ ++/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ ++/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ ++/* */ ++/* Permission is hereby granted, free of charge, to any person obtaining */ ++/* a copy of this software and associated documentation files (the */ ++/* "Software"), to deal in the Software without restriction, including */ ++/* without limitation the rights to use, copy, modify, merge, publish, */ ++/* distribute, sublicense, and/or sell copies of the Software, and to */ ++/* permit persons to whom the Software is furnished to do so, subject to */ ++/* the following conditions: */ ++/* */ ++/* The above copyright notice and this permission notice shall be */ ++/* included in all copies or substantial portions of the Software. */ ++/* */ ++/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ ++/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ ++/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ ++/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ ++/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ ++/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ ++/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++/**************************************************************************/ ++ ++#pragma once ++ ++#define SDL_build_config_h_ ++ ++#include ++ ++#define HAVE_STDARG_H 1 ++#define HAVE_STDDEF_H 1 ++ ++// Here we disable SDL subsystems that are not going to be used ++#define SDL_CPUINFO_DISABLED 1 ++#define SDL_AUDIO_DISABLED 1 ++#define SDL_PROCESS_DUMMY 1 ++#define SDL_LOADSO_DUMMY 1 ++#define SDL_VIDEO_DISABLED 1 ++#define SDL_CAMERA_DISABLED 1 ++#define SDL_DIALOG_DISABLED 1 ++#define SDL_FILESYSTEM_DUMMY 1 ++#define SDL_FSOPS_DUMMY 1 ++#define SDL_SENSOR_DISABLED 1 ++#define SDL_GPU_DISABLED 1 ++#define SDL_RENDER_DISABLED 1 ++#define SDL_POWER_DISABLED 1 ++#define SDL_LEAN_AND_MEAN 1 ++ ++// Windows defines ++#if defined(SDL_PLATFORM_WINDOWS) ++ ++#define SDL_PLATFORM_PRIVATE_NAME "Windows" ++#define HAVE_LIBC 1 ++#define HAVE_DINPUT_H 1 ++#define HAVE_XINPUT_H 1 ++#if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0A00 /* Windows 10 SDK */ ++#define HAVE_WINDOWS_GAMING_INPUT_H 1 ++#define SDL_JOYSTICK_WGI 1 ++#endif ++#define SDL_JOYSTICK_DINPUT 1 ++#define SDL_JOYSTICK_HIDAPI 1 ++#define SDL_JOYSTICK_RAWINPUT 1 ++#define SDL_JOYSTICK_XINPUT 1 ++#define SDL_HAPTIC_DINPUT 1 ++#define SDL_THREAD_GENERIC_COND_SUFFIX 1 ++#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1 ++#define SDL_THREAD_WINDOWS 1 ++#define SDL_TIMER_WINDOWS 1 ++ ++// Linux defines ++#elif defined(SDL_PLATFORM_LINUX) ++ ++#define SDL_PLATFORM_PRIVATE_NAME "Linux" ++#define SDL_PLATFORM_UNIX 1 ++ ++#define HAVE_STDIO_H 1 ++#define HAVE_LINUX_INPUT_H 1 ++#define HAVE_POLL 1 ++ ++// TODO: handle dynamic loading with SOWRAP_ENABLED ++ ++// (even though DBus can also be loaded with SOWRAP_ENABLED, we load it ++// statically regardless of SOWRAP_ENABLED, because otherwise SDL won't compile) ++#ifdef DBUS_ENABLED ++#define HAVE_DBUS_DBUS_H 1 ++#endif ++ ++#if defined(UDEV_ENABLED) && !defined(SOWRAP_ENABLED) ++#define HAVE_LIBUDEV_H 1 ++#endif ++ ++#define SDL_LOADSO_DLOPEN 1 ++#define SDL_HAPTIC_LINUX 1 ++#define SDL_TIMER_UNIX 1 ++#define SDL_JOYSTICK_LINUX 1 ++#define SDL_INPUT_LINUXEV 1 ++#define SDL_THREAD_PTHREAD 1 ++ ++// MacOS defines ++#elif defined(SDL_PLATFORM_MACOS) ++ ++#define SDL_PLATFORM_PRIVATE_NAME "macOS" ++#define SDL_PLATFORM_UNIX 1 ++#define HAVE_STDIO_H 1 ++#define HAVE_LIBC 1 ++#define SDL_HAPTIC_IOKIT 1 ++#define SDL_JOYSTICK_IOKIT 1 ++#define SDL_JOYSTICK_MFI 1 ++#define SDL_TIMER_UNIX 1 ++#define SDL_THREAD_PTHREAD 1 ++ ++// Other platforms are not supported (for now) ++#else ++#error "No SDL build config was found for this platform. Setup one before compiling the engine." ++#endif ++ ++#if !defined(HAVE_STDINT_H) && !defined(_STDINT_H_) ++#define HAVE_STDINT_H 1 ++#endif /* !_STDINT_H_ && !HAVE_STDINT_H */ ++ ++#ifdef __GNUC__ ++#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1 ++#endif Index: patches/patch-drivers_sdl_joypad_sdl_cpp =================================================================== RCS file: patches/patch-drivers_sdl_joypad_sdl_cpp diff -N patches/patch-drivers_sdl_joypad_sdl_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-drivers_sdl_joypad_sdl_cpp 29 May 2026 20:27:40 -0000 @@ -0,0 +1,281 @@ +backport commit 0b3496f: + Add support for SDL3 joystick input driver + +Index: drivers/sdl/joypad_sdl.cpp +--- drivers/sdl/joypad_sdl.cpp.orig ++++ drivers/sdl/joypad_sdl.cpp +@@ -0,0 +1,274 @@ ++/**************************************************************************/ ++/* joypad_sdl.cpp */ ++/**************************************************************************/ ++/* This file is part of: */ ++/* GODOT ENGINE */ ++/* https://godotengine.org */ ++/**************************************************************************/ ++/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ ++/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ ++/* */ ++/* Permission is hereby granted, free of charge, to any person obtaining */ ++/* a copy of this software and associated documentation files (the */ ++/* "Software"), to deal in the Software without restriction, including */ ++/* without limitation the rights to use, copy, modify, merge, publish, */ ++/* distribute, sublicense, and/or sell copies of the Software, and to */ ++/* permit persons to whom the Software is furnished to do so, subject to */ ++/* the following conditions: */ ++/* */ ++/* The above copyright notice and this permission notice shall be */ ++/* included in all copies or substantial portions of the Software. */ ++/* */ ++/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ ++/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ ++/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ ++/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ ++/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ ++/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ ++/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++/**************************************************************************/ ++ ++#include "joypad_sdl.h" ++ ++#ifdef SDL_ENABLED ++ ++#include "core/os/time.h" ++#include "core/dictionary.h" ++#include "main/default_controller_mappings.h" ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++JoypadSDL *JoypadSDL::singleton = nullptr; ++ ++// Macro to skip the SDL joystick event handling if the device is an SDL gamepad, because ++// there are separate events for SDL gamepads ++#define SKIP_EVENT_FOR_GAMEPAD \ ++ if (SDL_IsGamepad(sdl_event.jdevice.which)) { \ ++ continue; \ ++ } ++ ++JoypadSDL::JoypadSDL(InputDefault *in) { ++ singleton = this; ++ input = in; ++} ++ ++JoypadSDL::~JoypadSDL() { ++ // Process any remaining input events ++ process_events(); ++ for (int i = 0; i < InputDefault::JOYPADS_MAX; i++) { ++ if (joypads[i].attached) { ++ close_joypad(i); ++ } ++ } ++ SDL_Quit(); ++ singleton = nullptr; ++} ++ ++JoypadSDL *JoypadSDL::get_singleton() { ++ return singleton; ++} ++ ++Error JoypadSDL::initialize() { ++ SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1"); ++ SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1"); ++ ERR_FAIL_COND_V_MSG(!SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD), FAILED, SDL_GetError()); ++ ++ // Add Godot's mapping database from memory ++ int i = 0; ++ while (DefaultControllerMappings::mappings[i]) { ++ String mapping_string = DefaultControllerMappings::mappings[i++]; ++ CharString data = mapping_string.utf8(); ++ SDL_IOStream *rw = SDL_IOFromMem((void *)data.ptr(), data.size()); ++ SDL_AddGamepadMappingsFromIO(rw, 1); ++ } ++ ++ print_verbose("SDL: Init OK!"); ++ return OK; ++} ++ ++void JoypadSDL::process_events() { ++ // Update rumble first for it to be applied when we handle SDL events ++ for (int i = 0; i < InputDefault::JOYPADS_MAX; i++) { ++ Joypad &joy = joypads[i]; ++ if (joy.attached && joy.supports_force_feedback) { ++ uint64_t timestamp = Input::get_singleton()->get_joy_vibration_timestamp(i); ++ ++ // Update the joypad rumble only if there was a new vibration request ++ if (timestamp > joy.ff_effect_timestamp) { ++ joy.ff_effect_timestamp = timestamp; ++ ++ SDL_Joystick *sdl_joy = SDL_GetJoystickFromID(joypads[i].sdl_instance_idx); ++ Vector2 strength = Input::get_singleton()->get_joy_vibration_strength(i); ++ ++ // If the vibration was requested to start, SDL_RumbleJoystick will start it. ++ // If the vibration was requested to stop, strength and duration will be 0, so SDL will stop the rumble. ++ SDL_RumbleJoystick( ++ sdl_joy, ++ // Rumble strength goes from 0 to 0xFFFF ++ strength.x * UINT16_MAX, ++ strength.y * UINT16_MAX, ++ Input::get_singleton()->get_joy_vibration_duration(i) * 1000); ++ } ++ } ++ } ++ ++ SDL_Event sdl_event; ++ while (SDL_PollEvent(&sdl_event)) { ++ // A new joypad was attached ++ if (sdl_event.type == SDL_EVENT_JOYSTICK_ADDED) { ++ int joy_id = input->get_unused_joy_id(); ++ if (joy_id == -1) { ++ // There is no space for more joypads... ++ print_error("A new joypad was attached but couldn't allocate a new id for it because joypad limit was reached."); ++ } else { ++ SDL_Joystick *joy = nullptr; ++ String device_name; ++ ++ // Gamepads must be opened with SDL_OpenGamepad to get their special remapped events ++ if (SDL_IsGamepad(sdl_event.jdevice.which)) { ++ SDL_Gamepad *gamepad = SDL_OpenGamepad(sdl_event.jdevice.which); ++ ++ ERR_CONTINUE_MSG(!gamepad, ++ vformat("Error opening gamepad at index %d: %s", sdl_event.jdevice.which, SDL_GetError())); ++ ++ device_name = SDL_GetGamepadName(gamepad); ++ joy = SDL_GetGamepadJoystick(gamepad); ++ ++ print_verbose(vformat("SDL: Gamepad %s connected", SDL_GetGamepadName(gamepad))); ++ } else { ++ joy = SDL_OpenJoystick(sdl_event.jdevice.which); ++ ERR_CONTINUE_MSG(!joy, ++ vformat("Error opening joystick at index %d: %s", sdl_event.jdevice.which, SDL_GetError())); ++ ++ device_name = SDL_GetJoystickName(joy); ++ ++ print_verbose(vformat("SDL: Joystick %s connected", SDL_GetJoystickName(joy))); ++ } ++ ++ const int MAX_GUID_SIZE = 64; ++ char guid[MAX_GUID_SIZE] = {}; ++ ++ SDL_GUIDToString(SDL_GetJoystickGUID(joy), guid, MAX_GUID_SIZE); ++ SDL_PropertiesID propertiesID = SDL_GetJoystickProperties(joy); ++ ++ joypads[joy_id].attached = true; ++ joypads[joy_id].sdl_instance_idx = sdl_event.jdevice.which; ++ joypads[joy_id].supports_force_feedback = SDL_GetBooleanProperty(propertiesID, SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, false); ++ joypads[joy_id].guid = StringName(String(guid)); ++ ++ sdl_instance_id_to_joypad_id[sdl_event.jdevice.which] = joy_id; ++ ++ // Skip Godot's mapping system because SDL already handles the joypad's mapping ++ Dictionary joypad_info; ++ joypad_info["mapping_handled"] = true; ++ ++ Input::get_singleton()->joy_connection_changed( ++ joy_id, ++ true, ++ device_name, ++ joypads[joy_id].guid, ++ joypad_info); ++ } ++ // An event for an attached joypad ++ } else if (sdl_event.type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && sdl_event.type < SDL_EVENT_FINGER_DOWN && sdl_instance_id_to_joypad_id.has(sdl_event.jdevice.which)) { ++ int joy_id = sdl_instance_id_to_joypad_id.get(sdl_event.jdevice.which); ++ ++ switch (sdl_event.type) { ++ case SDL_EVENT_JOYSTICK_REMOVED: ++ Input::get_singleton()->joy_connection_changed(joy_id, false, ""); ++ close_joypad(joy_id); ++ break; ++ ++ case SDL_EVENT_JOYSTICK_AXIS_MOTION: ++ SKIP_EVENT_FOR_GAMEPAD; ++ ++ input->joy_axis( ++ joy_id, ++ sdl_event.jaxis.axis, // Godot joy axis constants are already intentionally the same as SDL's ++ ((sdl_event.jaxis.value - SDL_JOYSTICK_AXIS_MIN) / (float)(SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) - 0.5f) * 2.0f); ++ break; ++ ++ case SDL_EVENT_JOYSTICK_BUTTON_UP: ++ case SDL_EVENT_JOYSTICK_BUTTON_DOWN: ++ SKIP_EVENT_FOR_GAMEPAD; ++ ++ input->joy_button( ++ joy_id, ++ sdl_event.jbutton.button, // Godot button constants are intentionally the same as SDL's, so we can just straight up use them ++ sdl_event.jbutton.down); ++ break; ++ ++ case SDL_EVENT_JOYSTICK_HAT_MOTION: ++ SKIP_EVENT_FOR_GAMEPAD; ++ ++ input->joy_hat( ++ joy_id, ++ (InputDefault::HatMask)sdl_event.jhat.value // Godot hat masks are identical to SDL hat masks, so we can just use them as-is. ++ ); ++ break; ++ ++ case SDL_EVENT_GAMEPAD_AXIS_MOTION: { ++ float axis_value; ++ ++ if (sdl_event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || sdl_event.gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { ++ // Gamepad triggers go from 0 to SDL_JOYSTICK_AXIS_MAX ++ axis_value = sdl_event.gaxis.value / (float)SDL_JOYSTICK_AXIS_MAX; ++ } else { ++ // Other axis go from SDL_JOYSTICK_AXIS_MIN to SDL_JOYSTICK_AXIS_MAX ++ axis_value = ++ ((sdl_event.gaxis.value - SDL_JOYSTICK_AXIS_MIN) / (float)(SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) - 0.5f) * 2.0f; ++ } ++ ++ input->joy_axis( ++ joy_id, ++ sdl_event.gaxis.axis, // Godot joy axis constants are already intentionally the same as SDL's ++ axis_value); ++ } break; ++ ++ // Do note SDL gamepads do not have separate events for the dpad ++ case SDL_EVENT_GAMEPAD_BUTTON_UP: ++ case SDL_EVENT_GAMEPAD_BUTTON_DOWN: ++ input->joy_button( ++ joy_id, ++ sdl_event.gbutton.button, // Godot button constants are intentionally the same as SDL's, so we can just straight up use them ++ sdl_event.gbutton.down); ++ break; ++ } ++ } ++ } ++} ++ ++#ifdef WINDOWS_ENABLED ++extern "C" { ++HWND SDL_HelperWindow; ++} ++ ++// Required for DInput joypads to work ++void JoypadSDL::setup_sdl_helper_window(HWND p_hwnd) { ++ SDL_HelperWindow = p_hwnd; ++} ++#endif ++ ++void JoypadSDL::close_joypad(int p_pad_idx) { ++ int sdl_instance_idx = joypads[p_pad_idx].sdl_instance_idx; ++ ++ joypads[p_pad_idx].attached = false; ++ sdl_instance_id_to_joypad_id.erase(sdl_instance_idx); ++ ++ if (SDL_IsGamepad(sdl_instance_idx)) { ++ SDL_Gamepad *gamepad = SDL_GetGamepadFromID(sdl_instance_idx); ++ SDL_CloseGamepad(gamepad); ++ } else { ++ SDL_Joystick *joy = SDL_GetJoystickFromID(sdl_instance_idx); ++ SDL_CloseJoystick(joy); ++ } ++} ++ ++#endif // SDL_ENABLED Index: patches/patch-drivers_sdl_joypad_sdl_h =================================================================== RCS file: patches/patch-drivers_sdl_joypad_sdl_h diff -N patches/patch-drivers_sdl_joypad_sdl_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-drivers_sdl_joypad_sdl_h 29 May 2026 20:27:40 -0000 @@ -0,0 +1,78 @@ +backport commit 0b3496f: + Add support for SDL3 joystick input driver + +Index: drivers/sdl/joypad_sdl.h +--- drivers/sdl/joypad_sdl.h.orig ++++ drivers/sdl/joypad_sdl.h +@@ -0,0 +1,71 @@ ++/**************************************************************************/ ++/* joypad_sdl.h */ ++/**************************************************************************/ ++/* This file is part of: */ ++/* GODOT ENGINE */ ++/* https://godotengine.org */ ++/**************************************************************************/ ++/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ ++/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ ++/* */ ++/* Permission is hereby granted, free of charge, to any person obtaining */ ++/* a copy of this software and associated documentation files (the */ ++/* "Software"), to deal in the Software without restriction, including */ ++/* without limitation the rights to use, copy, modify, merge, publish, */ ++/* distribute, sublicense, and/or sell copies of the Software, and to */ ++/* permit persons to whom the Software is furnished to do so, subject to */ ++/* the following conditions: */ ++/* */ ++/* The above copyright notice and this permission notice shall be */ ++/* included in all copies or substantial portions of the Software. */ ++/* */ ++/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ ++/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ ++/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ ++/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ ++/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ ++/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ ++/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ ++/**************************************************************************/ ++ ++#pragma once ++ ++#include "core/input_map.h" ++#include "core/os/thread.h" ++#include "main/input_default.h" ++ ++typedef uint32_t SDL_JoystickID; ++typedef struct HWND__ *HWND; ++ ++class JoypadSDL { ++public: ++ JoypadSDL(InputDefault *in); ++ ~JoypadSDL(); ++ ++ static JoypadSDL *get_singleton(); ++ ++ Error initialize(); ++ void process_events(); ++#ifdef WINDOWS_ENABLED ++ void setup_sdl_helper_window(HWND p_hwnd); ++#endif ++ ++private: ++ struct Joypad { ++ bool attached = false; ++ StringName guid; ++ ++ SDL_JoystickID sdl_instance_idx; ++ ++ bool supports_force_feedback = false; ++ uint64_t ff_effect_timestamp = 0; ++ }; ++ ++ static JoypadSDL *singleton; ++ InputDefault *input; ++ ++ Joypad joypads[InputDefault::JOYPADS_MAX]; ++ HashMap sdl_instance_id_to_joypad_id; ++ ++ void close_joypad(int p_pad_idx); ++}; Index: patches/patch-main_input_default_cpp =================================================================== RCS file: patches/patch-main_input_default_cpp diff -N patches/patch-main_input_default_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-main_input_default_cpp 29 May 2026 20:27:40 -0000 @@ -0,0 +1,39 @@ +backport commit 0b3496f: + Add support for SDL3 joystick input driver + +Index: main/input_default.cpp +--- main/input_default.cpp.orig ++++ main/input_default.cpp +@@ -261,11 +261,12 @@ static String _hex_str(uint8_t p_byte) { + return ret; + }; + +-void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) { ++void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid, const Dictionary &p_joypad_info) { + _THREAD_SAFE_METHOD_ + Joypad js; + js.name = p_connected ? p_name : ""; + js.uid = p_connected ? p_guid : ""; ++ js.info = p_connected ? p_joypad_info : Dictionary(); + + if (p_connected) { + String uidname = p_guid; +@@ -278,10 +279,14 @@ void InputDefault::joy_connection_changed(int p_idx, b + js.uid = uidname; + js.connected = true; + int mapping = fallback_mapping; +- for (int i = 0; i < map_db.size(); i++) { +- if (js.uid == map_db[i].uid) { +- mapping = i; +- js.name = map_db[i].name; ++ // Bypass the mapping system if the joypad's mapping is already handled by its driver ++ // (for example, the SDL joypad driver). ++ if (!p_joypad_info.get("mapping_handled", false)) { ++ for (int i = 0; i < map_db.size(); i++) { ++ if (js.uid == map_db[i].uid) { ++ mapping = i; ++ js.name = map_db[i].name; ++ } + }; + }; + js.mapping = mapping; Index: patches/patch-main_input_default_h =================================================================== RCS file: patches/patch-main_input_default_h diff -N patches/patch-main_input_default_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-main_input_default_h 29 May 2026 20:27:40 -0000 @@ -0,0 +1,23 @@ +backport commit 0b3496f: + Add support for SDL3 joystick input driver + +Index: main/input_default.h +--- main/input_default.h.orig ++++ main/input_default.h +@@ -92,6 +92,7 @@ class InputDefault : public Input { + int last_hat; + int mapping; + int hat_current; ++ Dictionary info; + + Joypad() { + for (int i = 0; i < JOY_AXIS_MAX; i++) { +@@ -241,7 +242,7 @@ class InputDefault : public Input { + virtual Vector2 get_joy_vibration_strength(int p_device); + virtual float get_joy_vibration_duration(int p_device); + virtual uint64_t get_joy_vibration_timestamp(int p_device); +- void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = ""); ++ void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "", const Dictionary &p_joypad_info = Dictionary()); + + virtual Vector3 get_gravity() const; + virtual Vector3 get_accelerometer() const; Index: patches/patch-platform_x11_SCsub =================================================================== RCS file: /cvs/ports/games/godot/pack1/patches/patch-platform_x11_SCsub,v diff -u -p -r1.1.1.1 patch-platform_x11_SCsub --- patches/patch-platform_x11_SCsub 4 Mar 2026 05:35:04 -0000 1.1.1.1 +++ patches/patch-platform_x11_SCsub 29 May 2026 20:27:40 -0000 @@ -1,12 +1,14 @@ +backport commit 0b3496f: +Add support for SDL3 joystick input driver + Index: platform/x11/SCsub --- platform/x11/SCsub.orig +++ platform/x11/SCsub -@@ -10,7 +10,7 @@ common_x11 = [ +@@ -10,7 +10,6 @@ common_x11 = [ "crash_handler_x11.cpp", "os_x11.cpp", "key_mapping_x11.cpp", - "joypad_linux.cpp", -+ "joypad_openbsd.cpp", "power_x11.cpp", "detect_prime.cpp", ] Index: patches/patch-platform_x11_detect_py =================================================================== RCS file: /cvs/ports/games/godot/pack1/patches/patch-platform_x11_detect_py,v diff -u -p -r1.1.1.1 patch-platform_x11_detect_py --- patches/patch-platform_x11_detect_py 4 Mar 2026 05:35:04 -0000 1.1.1.1 +++ patches/patch-platform_x11_detect_py 29 May 2026 20:27:40 -0000 @@ -1,3 +1,6 @@ +backport commit 0b3496f: +Add support for SDL3 joystick input driver + Index: platform/x11/detect.py --- platform/x11/detect.py.orig +++ platform/x11/detect.py @@ -42,13 +45,22 @@ Index: platform/x11/detect.py if env["pulseaudio"]: if os.system("pkg-config --exists libpulse") == 0: # 0 means found env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"]) -@@ -398,6 +379,9 @@ def configure(env): +@@ -398,6 +379,18 @@ def configure(env): print("Warning: libudev development libraries not found. Disabling controller hotplugging support.") else: env["udev"] = False # Linux specific + -+ if platform.system() == "OpenBSD": -+ env.Append(CPPDEFINES=["JOYDEV_ENABLED"]) ++ if env["sdl"]: ++ if env["builtin_sdl"]: ++ env.Append(CPPDEFINES=["SDL_ENABLED"]) ++ elif os.system("pkg-config --exists fontconfig") == 0: # 0 means found ++ env.ParseConfig("pkg-config sdl3 --cflags --libs") ++ env.Append(CPPDEFINES=["SDL_ENABLED"]) ++ else: ++ print_warning( ++ "SDL3 development libraries not found, and `builtin_sdl` was explicitly disabled. Disabling SDL input driver support." ++ ) ++ env["sdl"] = False # Linkflags below this line should typically stay the last ones if not env["builtin_zlib"]: Index: patches/patch-platform_x11_joypad_linux_cpp =================================================================== RCS file: patches/patch-platform_x11_joypad_linux_cpp diff -N patches/patch-platform_x11_joypad_linux_cpp --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-platform_x11_joypad_linux_cpp 29 May 2026 20:27:40 -0000 @@ -0,0 +1,602 @@ +backport commit 0b3496f: +Add support for SDL3 joystick input driver + +Index: platform/x11/joypad_linux.cpp +--- platform/x11/joypad_linux.cpp.orig ++++ platform/x11/joypad_linux.cpp +@@ -1,595 +1 @@ +-/**************************************************************************/ +-/* joypad_linux.cpp */ +-/**************************************************************************/ +-/* This file is part of: */ +-/* GODOT ENGINE */ +-/* https://godotengine.org */ +-/**************************************************************************/ +-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +-/* */ +-/* Permission is hereby granted, free of charge, to any person obtaining */ +-/* a copy of this software and associated documentation files (the */ +-/* "Software"), to deal in the Software without restriction, including */ +-/* without limitation the rights to use, copy, modify, merge, publish, */ +-/* distribute, sublicense, and/or sell copies of the Software, and to */ +-/* permit persons to whom the Software is furnished to do so, subject to */ +-/* the following conditions: */ +-/* */ +-/* The above copyright notice and this permission notice shall be */ +-/* included in all copies or substantial portions of the Software. */ +-/* */ +-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +-/**************************************************************************/ + +-#ifdef JOYDEV_ENABLED +- +-#include "joypad_linux.h" +- +-#include "core/os/os.h" +- +-#include +-#include +-#include +-#include +-#include +- +-#ifdef UDEV_ENABLED +-#include "libudev-so_wrap.h" +-#endif +- +-#define LONG_BITS (sizeof(long) * 8) +-#define test_bit(nr, addr) (((1UL << ((nr) % LONG_BITS)) & ((addr)[(nr) / LONG_BITS])) != 0) +-#define NBITS(x) ((((x)-1) / LONG_BITS) + 1) +- +-#ifdef UDEV_ENABLED +-static const char *ignore_str = "/dev/input/js"; +-#endif +- +-JoypadLinux::Joypad::Joypad() { +- fd = -1; +- dpad = 0; +- devpath = ""; +- for (int i = 0; i < MAX_ABS; i++) { +- abs_info[i] = nullptr; +- } +-} +- +-JoypadLinux::Joypad::~Joypad() { +- for (int i = 0; i < MAX_ABS; i++) { +- if (abs_info[i]) { +- memdelete(abs_info[i]); +- } +- } +-} +- +-void JoypadLinux::Joypad::reset() { +- dpad = 0; +- fd = -1; +- for (int i = 0; i < MAX_ABS; i++) { +- abs_map[i] = -1; +- curr_axis[i] = 0; +- } +- events.clear(); +-} +- +-#ifdef UDEV_ENABLED +-// This function is derived from SDL: +-// https://github.com/libsdl-org/SDL/blob/main/src/core/linux/SDL_sandbox.c#L28-L45 +-static bool detect_sandbox() { +- if (access("/.flatpak-info", F_OK) == 0) { +- return true; +- } +- +- // For Snap, we check multiple variables because they might be set for +- // unrelated reasons. This is the same thing WebKitGTK does. +- if (OS::get_singleton()->has_environment("SNAP") && OS::get_singleton()->has_environment("SNAP_NAME") && OS::get_singleton()->has_environment("SNAP_REVISION")) { +- return true; +- } +- +- if (access("/run/host/container-manager", F_OK) == 0) { +- return true; +- } +- +- return false; +-} +-#endif // UDEV_ENABLED +- +-JoypadLinux::JoypadLinux(InputDefault *in) { +-#ifdef UDEV_ENABLED +- if (detect_sandbox()) { +- // Linux binaries in sandboxes / containers need special handling because +- // libudev doesn't work there. So we need to fallback to manual parsing +- // of /dev/input in such case. +- use_udev = false; +- print_verbose("JoypadLinux: udev enabled, but detected incompatible sandboxed mode. Falling back to /dev/input to detect joypads."); +- } else { +- use_udev = initialize_libudev() == 0; +- if (use_udev) { +- print_verbose("JoypadLinux: udev enabled and loaded successfully."); +- } else { +- print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads."); +- } +- } +-#else +- print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads."); +-#endif +- input = in; +- monitor_joypads_thread.start(monitor_joypads_thread_func, this); +- joypad_events_thread.start(joypad_events_thread_func, this); +-} +- +-JoypadLinux::~JoypadLinux() { +- monitor_joypads_exit.set(); +- joypad_events_exit.set(); +- monitor_joypads_thread.wait_to_finish(); +- joypad_events_thread.wait_to_finish(); +- close_joypads(); +-} +- +-void JoypadLinux::monitor_joypads_thread_func(void *p_user) { +- if (p_user) { +- JoypadLinux *joy = (JoypadLinux *)p_user; +- joy->monitor_joypads_thread_run(); +- } +-} +- +-void JoypadLinux::monitor_joypads_thread_run() { +-#ifdef UDEV_ENABLED +- if (use_udev) { +- udev *_udev = udev_new(); +- if (!_udev) { +- use_udev = false; +- ERR_PRINT("Failed getting an udev context, falling back to parsing /dev/input."); +- monitor_joypads(); +- } else { +- enumerate_joypads(_udev); +- monitor_joypads(_udev); +- udev_unref(_udev); +- } +- } else { +- monitor_joypads(); +- } +-#else +- monitor_joypads(); +-#endif +-} +- +-#ifdef UDEV_ENABLED +-void JoypadLinux::enumerate_joypads(udev *p_udev) { +- udev_enumerate *enumerate; +- udev_list_entry *devices, *dev_list_entry; +- udev_device *dev; +- +- enumerate = udev_enumerate_new(p_udev); +- udev_enumerate_add_match_subsystem(enumerate, "input"); +- +- udev_enumerate_scan_devices(enumerate); +- devices = udev_enumerate_get_list_entry(enumerate); +- udev_list_entry_foreach(dev_list_entry, devices) { +- const char *path = udev_list_entry_get_name(dev_list_entry); +- dev = udev_device_new_from_syspath(p_udev, path); +- const char *devnode = udev_device_get_devnode(dev); +- +- if (devnode) { +- String devnode_str = devnode; +- if (devnode_str.find(ignore_str) == -1) { +- open_joypad(devnode); +- } +- } +- udev_device_unref(dev); +- } +- udev_enumerate_unref(enumerate); +-} +- +-void JoypadLinux::monitor_joypads(udev *p_udev) { +- udev_device *dev = nullptr; +- udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev"); +- udev_monitor_filter_add_match_subsystem_devtype(mon, "input", nullptr); +- udev_monitor_enable_receiving(mon); +- int fd = udev_monitor_get_fd(mon); +- +- while (!monitor_joypads_exit.is_set()) { +- fd_set fds; +- struct timeval tv; +- int ret; +- +- FD_ZERO(&fds); +- FD_SET(fd, &fds); +- tv.tv_sec = 0; +- tv.tv_usec = 0; +- +- ret = select(fd + 1, &fds, nullptr, nullptr, &tv); +- +- /* Check if our file descriptor has received data. */ +- if (ret > 0 && FD_ISSET(fd, &fds)) { +- /* Make the call to receive the device. +- select() ensured that this will not block. */ +- dev = udev_monitor_receive_device(mon); +- +- if (dev && udev_device_get_devnode(dev) != nullptr) { +- String action = udev_device_get_action(dev); +- const char *devnode = udev_device_get_devnode(dev); +- if (devnode) { +- String devnode_str = devnode; +- if (devnode_str.find(ignore_str) == -1) { +- if (action == "add") { +- open_joypad(devnode); +- } else if (String(action) == "remove") { +- close_joypad(devnode); +- } +- } +- } +- udev_device_unref(dev); +- } +- } +- usleep(50000); +- } +- udev_monitor_unref(mon); +-} +-#endif +- +-void JoypadLinux::monitor_joypads() { +- while (!monitor_joypads_exit.is_set()) { +- DIR *input_directory; +- input_directory = opendir("/dev/input"); +- if (input_directory) { +- struct dirent *current; +- char fname[64]; +- +- while ((current = readdir(input_directory)) != nullptr) { +- if (strncmp(current->d_name, "event", 5) != 0) { +- continue; +- } +- sprintf(fname, "/dev/input/%.*s", 16, current->d_name); +- if (attached_devices.find(fname) == -1) { +- open_joypad(fname); +- } +- } +- } +- closedir(input_directory); +- usleep(1000000); // 1s +- } +-} +- +-void JoypadLinux::close_joypads() { +- for (int i = 0; i < JOYPADS_MAX; i++) { +- MutexLock lock(joypads_mutex[i]); +- Joypad &joypad = joypads[i]; +- close_joypad(joypad, i); +- } +-} +- +-void JoypadLinux::close_joypad(const char *p_devpath) { +- for (int i = 0; i < JOYPADS_MAX; i++) { +- MutexLock lock(joypads_mutex[i]); +- Joypad &joypad = joypads[i]; +- if (joypads[i].devpath == p_devpath) { +- close_joypad(joypad, i); +- } +- } +-} +- +-void JoypadLinux::close_joypad(Joypad &p_joypad, int p_id) { +- if (p_joypad.fd != -1) { +- close(p_joypad.fd); +- p_joypad.fd = -1; +- attached_devices.erase(p_joypad.devpath); +- input->joy_connection_changed(p_id, false, ""); +- }; +- p_joypad.events.clear(); +-} +- +-static String _hex_str(uint8_t p_byte) { +- static const char *dict = "0123456789abcdef"; +- char ret[3]; +- ret[2] = 0; +- +- ret[0] = dict[p_byte >> 4]; +- ret[1] = dict[p_byte & 0xF]; +- +- return ret; +-} +- +-void JoypadLinux::setup_joypad_properties(Joypad &p_joypad) { +- unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; +- unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; +- +- int num_buttons = 0; +- int num_axes = 0; +- +- if ((ioctl(p_joypad.fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || +- (ioctl(p_joypad.fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { +- return; +- } +- for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) { +- if (test_bit(i, keybit)) { +- p_joypad.key_map[i] = num_buttons++; +- } +- } +- for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) { +- if (test_bit(i, keybit)) { +- p_joypad.key_map[i] = num_buttons++; +- } +- } +- for (int i = 0; i < ABS_MISC; ++i) { +- /* Skip hats */ +- if (i == ABS_HAT0X) { +- i = ABS_HAT3Y; +- continue; +- } +- if (test_bit(i, absbit)) { +- p_joypad.abs_map[i] = num_axes++; +- p_joypad.abs_info[i] = memnew(input_absinfo); +- if (ioctl(p_joypad.fd, EVIOCGABS(i), p_joypad.abs_info[i]) < 0) { +- memdelete(p_joypad.abs_info[i]); +- p_joypad.abs_info[i] = nullptr; +- } +- } +- } +- +- p_joypad.force_feedback = false; +- p_joypad.ff_effect_timestamp = 0; +- unsigned long ffbit[NBITS(FF_CNT)]; +- if (ioctl(p_joypad.fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) != -1) { +- if (test_bit(FF_RUMBLE, ffbit)) { +- p_joypad.force_feedback = true; +- } +- } +-} +- +-void JoypadLinux::open_joypad(const char *p_path) { +- int joy_num = input->get_unused_joy_id(); +- int fd = open(p_path, O_RDWR | O_NONBLOCK); +- if (fd != -1 && joy_num != -1) { +- unsigned long evbit[NBITS(EV_MAX)] = { 0 }; +- unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; +- unsigned long absbit[NBITS(ABS_MAX)] = { 0 }; +- +- // add to attached devices so we don't try to open it again +- attached_devices.push_back(String(p_path)); +- +- if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) || +- (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) || +- (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) { +- close(fd); +- return; +- } +- +- //check if the device supports basic gamepad events, prevents certain keyboards from +- //being detected as joypads +- if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && +- (test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) || +- test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) && +- (test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) || +- test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit))) && +- !(test_bit(EV_ABS, evbit) && +- test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && +- test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit))) { +- close(fd); +- return; +- } +- +- char uid[128]; +- char namebuf[128]; +- String name = ""; +- input_id inpid; +- if (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) >= 0) { +- name = namebuf; +- } +- +- if (ioctl(fd, EVIOCGID, &inpid) < 0) { +- close(fd); +- return; +- } +- +- uint16_t vendor = BSWAP16(inpid.vendor); +- uint16_t product = BSWAP16(inpid.product); +- uint16_t version = BSWAP16(inpid.version); +- +- if (input->should_ignore_device(vendor, product)) { +- // This can be true in cases where Steam is passing information into the game to ignore +- // original gamepads when using virtual rebindings (See SteamInput). +- return; +- } +- +- MutexLock lock(joypads_mutex[joy_num]); +- Joypad &joypad = joypads[joy_num]; +- joypad.reset(); +- joypad.fd = fd; +- joypad.devpath = String(p_path); +- setup_joypad_properties(joypad); +- sprintf(uid, "%04x%04x", BSWAP16(inpid.bustype), 0); +- if (inpid.vendor && inpid.product && inpid.version) { +- sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor, 0, product, 0, version, 0); +- input->joy_connection_changed(joy_num, true, name, uid); +- } else { +- String uidname = uid; +- int uidlen = MIN(name.length(), 11); +- for (int i = 0; i < uidlen; i++) { +- uidname = uidname + _hex_str(name[i]); +- } +- uidname += "00"; +- input->joy_connection_changed(joy_num, true, name, uidname); +- } +- } +-} +- +-void JoypadLinux::joypad_vibration_start(Joypad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp) { +- if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_weak_magnitude < 0.f || p_weak_magnitude > 1.f || p_strong_magnitude < 0.f || p_strong_magnitude > 1.f) { +- return; +- } +- if (p_joypad.ff_effect_id != -1) { +- joypad_vibration_stop(p_joypad, p_timestamp); +- } +- +- struct ff_effect effect; +- effect.type = FF_RUMBLE; +- effect.id = -1; +- effect.u.rumble.weak_magnitude = floor(p_weak_magnitude * (float)0xffff); +- effect.u.rumble.strong_magnitude = floor(p_strong_magnitude * (float)0xffff); +- effect.replay.length = floor(p_duration * 1000); +- effect.replay.delay = 0; +- +- if (ioctl(p_joypad.fd, EVIOCSFF, &effect) < 0) { +- return; +- } +- +- struct input_event play; +- play.type = EV_FF; +- play.code = effect.id; +- play.value = 1; +- if (write(p_joypad.fd, (const void *)&play, sizeof(play)) == -1) { +- print_verbose("Couldn't write to Joypad device."); +- } +- +- p_joypad.ff_effect_id = effect.id; +- p_joypad.ff_effect_timestamp = p_timestamp; +-} +- +-void JoypadLinux::joypad_vibration_stop(Joypad &p_joypad, uint64_t p_timestamp) { +- if (!p_joypad.force_feedback || p_joypad.fd == -1 || p_joypad.ff_effect_id == -1) { +- return; +- } +- +- if (ioctl(p_joypad.fd, EVIOCRMFF, p_joypad.ff_effect_id) < 0) { +- return; +- } +- +- p_joypad.ff_effect_id = -1; +- p_joypad.ff_effect_timestamp = p_timestamp; +-} +- +-float JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const { +- int min = p_abs->minimum; +- int max = p_abs->maximum; +- // Convert to a value between -1.0f and 1.0f. +- return 2.0f * (p_value - min) / (max - min) - 1.0f; +-} +- +-void JoypadLinux::joypad_events_thread_func(void *p_user) { +- if (p_user) { +- JoypadLinux *joy = (JoypadLinux *)p_user; +- joy->joypad_events_thread_run(); +- } +-} +- +-void JoypadLinux::joypad_events_thread_run() { +- while (!joypad_events_exit.is_set()) { +- bool no_events = true; +- for (int i = 0; i < JOYPADS_MAX; i++) { +- MutexLock lock(joypads_mutex[i]); +- Joypad &joypad = joypads[i]; +- if (joypad.fd == -1) { +- continue; +- } +- input_event event; +- while (read(joypad.fd, &event, sizeof(event)) > 0) { +- JoypadEvent joypad_event; +- joypad_event.type = event.type; +- joypad_event.code = event.code; +- joypad_event.value = event.value; +- joypad.events.push_back(joypad_event); +- } +- if (errno != EAGAIN) { +- close_joypad(joypad, i); +- } +- } +- if (no_events) { +- usleep(10000); // 10ms +- } +- } +-} +- +-void JoypadLinux::process_joypads() { +- for (int i = 0; i < JOYPADS_MAX; i++) { +- MutexLock lock(joypads_mutex[i]); +- Joypad &joypad = joypads[i]; +- if (joypad.fd == -1) { +- continue; +- } +- for (uint32_t j = 0; j < joypad.events.size(); j++) { +- const JoypadEvent &joypad_event = joypad.events[j]; +- // joypad_event may be tainted and out of MAX_KEY range, which will cause +- // joypad.key_map[joypad_event.code] to crash +- if (joypad_event.code >= MAX_KEY) { +- return; +- } +- +- switch (joypad_event.type) { +- case EV_KEY: +- input->joy_button(i, joypad.key_map[joypad_event.code], joypad_event.value); +- break; +- +- case EV_ABS: +- switch (joypad_event.code) { +- case ABS_HAT0X: +- if (joypad_event.value != 0) { +- if (joypad_event.value < 0) { +- joypad.dpad = (joypad.dpad | InputDefault::HAT_MASK_LEFT) & ~InputDefault::HAT_MASK_RIGHT; +- } else { +- joypad.dpad = (joypad.dpad | InputDefault::HAT_MASK_RIGHT) & ~InputDefault::HAT_MASK_LEFT; +- } +- } else { +- joypad.dpad &= ~(InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_RIGHT); +- } +- input->joy_hat(i, joypad.dpad); +- break; +- +- case ABS_HAT0Y: +- if (joypad_event.value != 0) { +- if (joypad_event.value < 0) { +- joypad.dpad = (joypad.dpad | InputDefault::HAT_MASK_UP) & ~InputDefault::HAT_MASK_DOWN; +- } else { +- joypad.dpad = (joypad.dpad | InputDefault::HAT_MASK_DOWN) & ~InputDefault::HAT_MASK_UP; +- } +- } else { +- joypad.dpad &= ~(InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_DOWN); +- } +- input->joy_hat(i, joypad.dpad); +- break; +- +- default: +- if (joypad_event.code >= MAX_ABS) { +- return; +- } +- if (joypad.abs_map[joypad_event.code] != -1 && joypad.abs_info[joypad_event.code]) { +- float value = axis_correct(joypad.abs_info[joypad_event.code], joypad_event.value); +- joypad.curr_axis[joypad.abs_map[joypad_event.code]] = value; +- } +- break; +- } +- break; +- } +- } +- joypad.events.clear(); +- +- for (int j = 0; j < MAX_ABS; j++) { +- int index = joypad.abs_map[j]; +- if (index != -1) { +- input->joy_axis(i, index, joypad.curr_axis[index]); +- } +- } +- +- if (joypad.force_feedback) { +- uint64_t timestamp = input->get_joy_vibration_timestamp(i); +- if (timestamp > joypad.ff_effect_timestamp) { +- Vector2 strength = input->get_joy_vibration_strength(i); +- float duration = input->get_joy_vibration_duration(i); +- if (strength.x == 0 && strength.y == 0) { +- joypad_vibration_stop(joypad, timestamp); +- } else { +- joypad_vibration_start(joypad, strength.x, strength.y, duration, timestamp); +- } +- } +- } +- } +-} +- +-#endif // JOYDEV_ENABLED Index: patches/patch-platform_x11_joypad_linux_h =================================================================== RCS file: patches/patch-platform_x11_joypad_linux_h diff -N patches/patch-platform_x11_joypad_linux_h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ patches/patch-platform_x11_joypad_linux_h 29 May 2026 20:27:40 -0000 @@ -0,0 +1,132 @@ +backport commit 0b3496f: +Add support for SDL3 joystick input driver + +Index: platform/x11/joypad_linux.h +--- platform/x11/joypad_linux.h.orig ++++ platform/x11/joypad_linux.h +@@ -1,125 +1 @@ +-/**************************************************************************/ +-/* joypad_linux.h */ +-/**************************************************************************/ +-/* This file is part of: */ +-/* GODOT ENGINE */ +-/* https://godotengine.org */ +-/**************************************************************************/ +-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +-/* */ +-/* Permission is hereby granted, free of charge, to any person obtaining */ +-/* a copy of this software and associated documentation files (the */ +-/* "Software"), to deal in the Software without restriction, including */ +-/* without limitation the rights to use, copy, modify, merge, publish, */ +-/* distribute, sublicense, and/or sell copies of the Software, and to */ +-/* permit persons to whom the Software is furnished to do so, subject to */ +-/* the following conditions: */ +-/* */ +-/* The above copyright notice and this permission notice shall be */ +-/* included in all copies or substantial portions of the Software. */ +-/* */ +-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +-/**************************************************************************/ + +-//author: Andreas Haas +- +-#ifndef JOYPAD_LINUX_H +-#define JOYPAD_LINUX_H +- +-#ifdef JOYDEV_ENABLED +-#include "core/os/mutex.h" +-#include "core/os/thread.h" +-#include "main/input_default.h" +- +-struct input_absinfo; +- +-class JoypadLinux { +-public: +- JoypadLinux(InputDefault *in); +- ~JoypadLinux(); +- void process_joypads(); +- +-private: +- enum { +- JOYPADS_MAX = 16, +- MAX_ABS = 63, +- MAX_KEY = 767, // Hack because can't be included here +- }; +- +- struct JoypadEvent { +- uint16_t type; +- uint16_t code; +- int32_t value; +- }; +- +- struct Joypad { +- float curr_axis[MAX_ABS]; +- int key_map[MAX_KEY]; +- int abs_map[MAX_ABS]; +- int dpad; +- int fd; +- +- String devpath; +- input_absinfo *abs_info[MAX_ABS]; +- +- bool force_feedback; +- int ff_effect_id; +- uint64_t ff_effect_timestamp; +- +- LocalVector events; +- +- Joypad(); +- ~Joypad(); +- void reset(); +- }; +- +-#ifdef UDEV_ENABLED +- bool use_udev; +-#endif +- InputDefault *input; +- +- SafeFlag monitor_joypads_exit; +- SafeFlag joypad_events_exit; +- Thread monitor_joypads_thread; +- Thread joypad_events_thread; +- +- Joypad joypads[JOYPADS_MAX]; +- Mutex joypads_mutex[JOYPADS_MAX]; +- +- Vector attached_devices; +- +- static void monitor_joypads_thread_func(void *p_user); +- void monitor_joypads_thread_run(); +- +- void open_joypad(const char *p_path); +- void setup_joypad_properties(Joypad &p_joypad); +- +- void close_joypads(); +- void close_joypad(const char *p_devpath); +- void close_joypad(Joypad &p_joypad, int p_id); +- +-#ifdef UDEV_ENABLED +- void enumerate_joypads(struct udev *p_udev); +- void monitor_joypads(struct udev *p_udev); +-#endif +- void monitor_joypads(); +- +- void joypad_vibration_start(Joypad &p_joypad, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); +- void joypad_vibration_stop(Joypad &p_joypad, uint64_t p_timestamp); +- +- static void joypad_events_thread_func(void *p_user); +- void joypad_events_thread_run(); +- +- float axis_correct(const input_absinfo *p_abs, int p_value) const; +-}; +- +-#endif +- +-#endif // JOYPAD_LINUX_H Index: patches/patch-platform_x11_os_x11_cpp =================================================================== RCS file: /cvs/ports/games/godot/pack1/patches/patch-platform_x11_os_x11_cpp,v diff -u -p -r1.2 patch-platform_x11_os_x11_cpp --- patches/patch-platform_x11_os_x11_cpp 21 Mar 2026 20:27:26 -0000 1.2 +++ patches/patch-platform_x11_os_x11_cpp 29 May 2026 20:27:40 -0000 @@ -3,11 +3,23 @@ use OpenBSD joypad class suspend X11 screensaver for release builds we don't support DRI_PRIME as of March 2026 and setting it can lead to crashes in multi-GPU setups +backport commit 0b3496f: + Add support for SDL3 joystick input driver Index: platform/x11/os_x11.cpp --- platform/x11/os_x11.cpp.orig +++ platform/x11/os_x11.cpp -@@ -55,6 +55,10 @@ +@@ -35,6 +35,9 @@ + #include "detect_prime.h" + #include "drivers/gles2/rasterizer_gles2.h" + #include "drivers/gles3/rasterizer_gles3.h" ++#ifdef SDL_ENABLED ++#include "drivers/sdl/joypad_sdl.h" ++#endif + #include "key_mapping_x11.h" + #include "main/main.h" + #include "servers/visual/visual_server_raster.h" +@@ -55,6 +58,10 @@ #include #include @@ -18,7 +30,7 @@ Index: platform/x11/os_x11.cpp // ICCCM #define WM_NormalState 1L // window normal state #define WM_IconicState 3L // window minimized -@@ -219,7 +223,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i +@@ -219,7 +226,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i int xrandr_minor = 0; int event_base, error_base; xrandr_ext_ok = XRRQueryExtension(x11_display, &event_base, &error_base); @@ -27,7 +39,7 @@ Index: platform/x11/os_x11.cpp if (!xrandr_handle) { err = dlerror(); // For some arcane reason, NetBSD now ships libXrandr.so.3 while the rest of the world has libXrandr.so.2... -@@ -336,6 +340,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i +@@ -336,6 +343,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i } } @@ -35,7 +47,7 @@ Index: platform/x11/os_x11.cpp if (use_prime == -1) { print_verbose("Detecting GPUs, set DRI_PRIME in the environment to override GPU detection logic."); use_prime = detect_prime(); -@@ -346,6 +351,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i +@@ -346,6 +354,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i print_line("Note: Set DRI_PRIME=0 in the environment to disable Godot from using the discrete GPU."); setenv("DRI_PRIME", "1", 1); } @@ -43,12 +55,19 @@ Index: platform/x11/os_x11.cpp } ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_3_0_COMPATIBLE; -@@ -664,9 +670,13 @@ Error OS_X11::initialize(const VideoMode &p_desired, i +@@ -663,10 +672,19 @@ Error OS_X11::initialize(const VideoMode &p_desired, i + input = memnew(InputDefault); window_has_focus = true; // Set focus to true at init - #ifdef JOYDEV_ENABLED +-#ifdef JOYDEV_ENABLED - joypad = memnew(JoypadLinux(input)); -+ joypad = memnew(JoypadOpenBSD(input)); ++#ifdef SDL_ENABLED ++ joypad_sdl = memnew(JoypadSDL(input)); ++ if (joypad_sdl->initialize() != OK) { ++ ERR_PRINT("Couldn't initialize SDL joypad input driver."); ++ memdelete(joypad_sdl); ++ joypad_sdl = nullptr; ++ } #endif +#ifdef SUSPEND_SCREENSAVER @@ -58,7 +77,46 @@ Index: platform/x11/os_x11.cpp power_manager = memnew(PowerX11); if (p_desired.layered) { -@@ -4474,6 +4484,11 @@ void OS_X11::update_real_mouse_position() { +@@ -909,8 +927,10 @@ void OS_X11::finalize() { + } + #endif + +-#ifdef JOYDEV_ENABLED +- memdelete(joypad); ++#ifdef SDL_ENABLED ++ if (joypad_sdl) { ++ memdelete(joypad_sdl); ++ } + #endif + + xi.touch_devices.clear(); +@@ -4020,8 +4040,10 @@ void OS_X11::set_icon(const Ref &p_icon) { + + void OS_X11::force_process_input() { + process_xevents(); // get rid of pending events +-#ifdef JOYDEV_ENABLED +- joypad->process_joypads(); ++#ifdef SDL_ENABLED ++ if (joypad_sdl) { ++ joypad_sdl->process_events(); ++ } + #endif + } + +@@ -4041,8 +4063,10 @@ void OS_X11::run() { + + while (!force_quit) { + process_xevents(); // get rid of pending events +-#ifdef JOYDEV_ENABLED +- joypad->process_joypads(); ++#ifdef SDL_ENABLED ++ if (joypad_sdl) { ++ joypad_sdl->process_events(); ++ } + #endif + if (Main::iteration()) { + break; +@@ -4474,6 +4498,11 @@ void OS_X11::update_real_mouse_position() { } OS_X11::OS_X11() { Index: patches/patch-platform_x11_os_x11_h =================================================================== RCS file: /cvs/ports/games/godot/pack1/patches/patch-platform_x11_os_x11_h,v diff -u -p -r1.1.1.1 patch-platform_x11_os_x11_h --- patches/patch-platform_x11_os_x11_h 4 Mar 2026 05:35:04 -0000 1.1.1.1 +++ patches/patch-platform_x11_os_x11_h 29 May 2026 20:27:40 -0000 @@ -1,10 +1,12 @@ load sndio use OpenBSD joypad class +backport commit 0b3496f: + Add support for SDL3 joystick input driver Index: platform/x11/os_x11.h --- platform/x11/os_x11.h.orig +++ platform/x11/os_x11.h -@@ -37,9 +37,10 @@ +@@ -37,9 +37,9 @@ #include "crash_handler_x11.h" #include "drivers/alsa/audio_driver_alsa.h" #include "drivers/alsamidi/midi_driver_alsamidi.h" @@ -12,20 +14,30 @@ Index: platform/x11/os_x11.h #include "drivers/pulseaudio/audio_driver_pulseaudio.h" #include "drivers/unix/os_unix.h" -#include "joypad_linux.h" -+#include "joypad_openbsd.h" #include "main/input_default.h" #include "power_x11.h" #include "servers/audio_server.h" -@@ -203,7 +204,7 @@ class OS_X11 : public OS_Unix { +@@ -81,6 +81,8 @@ typedef struct _xrr_monitor_info { + + #undef CursorShape + ++class JoypadSDL; ++ + class OS_X11 : public OS_Unix { + Atom wm_delete; + Atom xdnd_enter; +@@ -202,8 +204,8 @@ class OS_X11 : public OS_Unix { + InputDefault *input; - #ifdef JOYDEV_ENABLED +-#ifdef JOYDEV_ENABLED - JoypadLinux *joypad; -+ JoypadOpenBSD *joypad; ++#ifdef SDL_ENABLED ++ JoypadSDL *joypad_sdl = nullptr; #endif #ifdef ALSA_ENABLED -@@ -212,6 +213,10 @@ class OS_X11 : public OS_Unix { +@@ -212,6 +214,10 @@ class OS_X11 : public OS_Unix { #ifdef ALSAMIDI_ENABLED MIDIDriverALSAMidi driver_alsamidi;