Hi,

This diff adds gamecontroller support to Godot. The code is largely
based on sdl2 and fit into Godot's framework.

This is generally functioning with an XInput/XBox 360 controller with
several games. The following is a list of limitations at this point
that will need more refinement, but that may best be done after
addition to the port:

- Currently should only support XInput controllers; the older DInput
  system can probably be added later based on sdl2's implementation.
- I've tested it with 2 of the more commonly used gamepads - the Xbox
  360 controller (wired) and the Logitech F310 in "X mode".
- Face buttons (ABXY), shoulder buttons (LR), Dpad, and Left analog
  stick work pretty consistently. Other elements (right analog stick,
  analog triggers, other buttons) most likely don't work correctly at
  the moment.
- I've tried to find a way to enable more button support in
  core/os/input_event.h with only very limited success.
- Most likely for better support of gamecontroller mapping, GUID
  detection and matching with gamecontrollerdb.txt will be needed;
  similar to SDL2. This is likely going to be added in the future.

I tested this working with the above buttons in several games: Haiki,
Primal Light, Bottomless, Satryn Deluxe, Oddventure (demo).

feedback and ok's welcome. I think in terms of functionality this is
at an okay point to add to the port and hopefully more widespread use
will help to figure out the remaining bits.

Ultimately I will be working probably with Omar on upstreaming both
sndio and gamecontroller support. It seems that upstream is deferring
such updates to the eventual 4.0 release which is still ways out.

Index: Makefile
===================================================================
RCS file: /cvs/ports/games/godot/Makefile,v
retrieving revision 1.28
diff -u -p -r1.28 Makefile
--- Makefile    29 Oct 2021 21:07:02 -0000      1.28
+++ Makefile    1 Nov 2021 06:49:42 -0000
@@ -11,7 +11,7 @@ V =           3.3.4
 GODOTSTEAM_V = g333-s151-g397
 DISTNAME =     godot-${V}-stable
 PKGNAME =      godot-${V}
-REVISION =     0
+REVISION =     1
 CATEGORIES =   games
 HOMEPAGE =     https://godotengine.org/
 MAINTAINER =   Omar Polo <o...@omarpolo.com>
@@ -23,7 +23,7 @@ WANTLIB += ${COMPILER_LIBCXX}
 WANTLIB += GL X11 Xau Xcursor Xdmcp Xext Xfixes Xi Xinerama Xrandr
 WANTLIB += Xrender c enet execinfo freetype intl m mbedtls mbedcrypto
 WANTLIB += mbedx509 mpcdec ogg opus opusfile png sndio steam_api theora
-WANTLIB += theoradec vorbis vorbisfile webp xcb z pcre2-32 vpx zstd
+WANTLIB += theoradec usbhid vorbis vorbisfile webp xcb z pcre2-32 vpx zstd
 
 # C++14
 COMPILER =     base-clang ports-gcc
@@ -43,7 +43,7 @@ MODSCONS_FLAGS =      CC="${CC}" \
                        CXX="${CXX}" \
                        CFLAGS="${CFLAGS} 
-I${LOCALBASE}/include/goldberg_emulator/sdk_includes" \
                        CXXFLAGS="${CXXFLAGS} -Wno-deprecated-register" \
-                       LINKFLAGS="${LDFLAGS} -lintl -lmpcdec" \
+                       LINKFLAGS="${LDFLAGS} -lintl -lmpcdec -lusbhid" \
                        builtin_enet=no \
                        builtin_freetype=no \
                        builtin_glew=no \
@@ -91,6 +91,8 @@ WANTLIB +=     atomic
 
 post-extract:
        cp -R ${FILESDIR}/sndio ${WRKDIST}/drivers
+       cp ${FILESDIR}/joypad_openbsd/joypad_openbsd.{cpp,h} \
+               ${WRKDIST}/platform/x11/
 
 pre-configure:
        ${SUBST_CMD} ${WRKSRC}/drivers/unix/os_unix.cpp
Index: files/joypad_openbsd/joypad_openbsd.cpp
===================================================================
RCS file: files/joypad_openbsd/joypad_openbsd.cpp
diff -N files/joypad_openbsd/joypad_openbsd.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ files/joypad_openbsd/joypad_openbsd.cpp     1 Nov 2021 06:49:42 -0000
@@ -0,0 +1,516 @@
+/*************************************************************************/
+/*  joypad_openbsd.cpp                                                     */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/* Copyright (c) 2021      Thomas Frohwein                               */
+/*                                                                       */
+/* 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_openbsd.h"
+
+#include <sys/param.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+extern "C" {
+       #include <dev/usb/usb.h>
+       #include <dev/usb/usbhid.h>
+       #include <usbhid.h>
+}
+
+#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)
+
+#define MAX_UHID_JOYS   64
+#define MAX_JOY_JOYS    2
+#define MAX_JOYS    (MAX_UHID_JOYS + MAX_JOY_JOYS)
+
+#define DEV_USB                3       /* needed to get GUID from 
USB_GET_DEVICEINFO */
+#define GUID_LEN       32      /* GUID string has length 32 */
+
+#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)
+
+extern "C" {
+
+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 = 0,
+       REPORT_OUTPUT = 1,
+       REPORT_FEATURE = 2
+};
+
+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 *, struct report_desc *, int);
+
+static int
+usage_to_joyaxe(unsigned usage)
+{
+       int joyaxe;
+       switch (usage) {
+       case HUG_X:
+               joyaxe = JOYAXE_X;
+               break;
+       case HUG_Y:
+               joyaxe = JOYAXE_Y;
+               break;
+       case HUG_Z:
+               joyaxe = JOYAXE_Z;
+               break;
+       case HUG_SLIDER:
+               joyaxe = JOYAXE_SLIDER;
+               break;
+       case HUG_WHEEL:
+               joyaxe = JOYAXE_WHEEL;
+               break;
+       case HUG_RX:
+               joyaxe = JOYAXE_RX;
+               break;
+       case HUG_RY:
+               joyaxe = JOYAXE_RY;
+               break;
+       case HUG_RZ:
+               joyaxe = JOYAXE_RZ;
+               break;
+       default:
+               joyaxe = -1;
+       }
+       return joyaxe;
+}
+
+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
+       };
+       unsigned result;
+       if ((hatval & 7) == hatval)
+               result = hat_dir_map[hatval];
+       else
+               result = HAT_CENTERED;
+       return result;
+}
+
+/* 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;
+}
+
+} // extern "C"
+
+JoypadOpenBSD::Joypad::Joypad() {
+       fd = -1;
+       dpad = 0;
+       devpath = "";
+}
+
+JoypadOpenBSD::Joypad::~Joypad() {
+}
+
+void JoypadOpenBSD::Joypad::reset() {
+       dpad = 0;
+       fd = -1;
+
+       InputDefault::JoyAxis jx;
+       jx.min = -1;
+       jx.value = 0.0f;
+}
+
+JoypadOpenBSD::JoypadOpenBSD(InputDefault *in) {
+       exit_ujoy = false;
+       input = in;
+
+       joy_thread.start(joy_thread_func, this);
+       hid_init(NULL);
+}
+
+JoypadOpenBSD::~JoypadOpenBSD() {
+       exit_ujoy = true;
+       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_ujoy) {
+               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) {
+       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 
should check if '/dev/joyX' or '/dev/ujoyX'
+
+       joy->repdesc = hid_get_report_desc(joy->fd);
+       if (joy->repdesc == NULL) {
+               printf("ERROR getting USB report descriptor\n");
+               // TODO: break/abort
+       }
+       rep = &joy->inreport;
+       if (ioctl(joy->fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
+               rep->rid = -1;  /* XXX */
+       }
+       if (report_alloc(rep, joy->repdesc, REPORT_INPUT) < 0) {
+               printf("ERROR allocating report descriptor\n");
+       }
+       if (rep->size <= 0) {
+               printf("ERROR: input report descriptor has invalid length\n");
+       }
+       hdata = hid_start_parse(joy->repdesc, 1 << hid_input, rep->rid);
+       if (hdata == NULL) {
+               printf("ERROR: Cannot start HID parser\n");
+       }
+
+       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;
+               }
+       }
+       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) {
+               printf("ERROR: Not a joystick!\n");
+       } else {
+               printf("joypad %d: %d axes %d buttons %d hats\n", p_id, 
num_axes, num_buttons, num_hats);
+       }
+       hid_end_parse(hdata);
+       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();
+       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));
+
+               char uid[128];
+               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 = uid;
+               int uidlen = MIN(name.length(), 11);
+               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 */
+}
+
+InputDefault::JoyAxis JoypadOpenBSD::axis_correct(int min, int max, int 
p_value) const {
+        InputDefault::JoyAxis jx;
+
+        if (min < 0) {
+                jx.min = -1;
+                if (p_value < 0) {
+                        jx.value = (float)-p_value / min;
+                } else {
+                        jx.value = (float)p_value / max;
+                }
+        } else if (min == 0) {
+                jx.min = 0;
+                jx.value = 0.0f + (float)p_value / max;
+        }
+
+        return jx;
+}
+
+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 (read(joy->fd, REP_BUF_DATA(rep), rep->size) == 
rep->size) {
+                       hdata = hid_start_parse(joy->repdesc, 1 << hid_input, 
rep->rid);
+                       if (hdata == NULL) {
+                               continue;
+                       }
+
+                       for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
+                               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) {
+                                                               naxe = 
joy->axis_map[joyaxe];
+                                                               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;
+                                                               }
+
+                                                               
//InputDefault::JoyAxis value = axis_correct(hitem.logical_minimum, 
hitem.logical_maximum, v);
+                                                               
//joy->curr_axis[joyaxe] = value;
+                                                               
//input->joy_axis(i, joyaxe, value);
+                                                               
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);
+                                               nbutton++;
+                                               break;
+                                       default:
+                                               continue;
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       hid_end_parse(hdata);
+               }
+       }
+       joy_mutex.unlock();
+}
+
+extern "C" {
+
+static int
+report_alloc(struct report *r, struct report_desc *rd, int repind)
+{
+       int len = hid_report_size(rd, repinfo[repind].kind, r->rid);
+       if (len < 0) {
+               printf("ERROR: Negative HID report size\n"); // 
SDL_SetError("Negative HID report size");
+       }
+       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 -1;
+               }
+       } else {
+               r->buf = NULL;
+       }
+
+       r->status = report::SREPORT_CLEAN;
+       return 0;
+}
+
+} // extern "C"
+#endif
Index: files/joypad_openbsd/joypad_openbsd.h
===================================================================
RCS file: files/joypad_openbsd/joypad_openbsd.h
diff -N files/joypad_openbsd/joypad_openbsd.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ files/joypad_openbsd/joypad_openbsd.h       1 Nov 2021 06:49:42 -0000
@@ -0,0 +1,118 @@
+/*************************************************************************/
+/*  joypad_openbsd.h                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md).   */
+/* Copyright (c) 2021      Thomas Frohwein                               */
+/*                                                                       */
+/* 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.                */
+/*************************************************************************/
+
+#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 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 <linux/input.h> can't be 
included here
+       };
+
+       struct Joypad {
+               InputDefault::JoyAxis 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;
+
+               bool force_feedback;
+               int ff_effect_id;
+               uint64_t ff_effect_timestamp;
+
+               Joypad();
+               ~Joypad();
+               void reset();
+       };
+
+       bool exit_ujoy;
+       Mutex joy_mutex;
+       Thread joy_thread;
+       InputDefault *input;
+       Joypad joypads[JOYPADS_MAX];
+       Vector<String> 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);
+
+       InputDefault::JoyAxis axis_correct(int min, int max, int p_value) const;
+};
+
+#endif
+#endif // JOYPAD_OPENBSD_H
Index: patches/patch-core_os_input_event_h
===================================================================
RCS file: patches/patch-core_os_input_event_h
diff -N patches/patch-core_os_input_event_h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-core_os_input_event_h 1 Nov 2021 06:49:42 -0000
@@ -0,0 +1,27 @@
+$OpenBSD$
+
+adjust JOY_ mappings until matching gamecontrollerdb.txt is supported.
+
+Index: core/os/input_event.h
+--- core/os/input_event.h.orig
++++ core/os/input_event.h
+@@ -94,13 +94,16 @@ enum JoystickList {
+       JOY_R2 = JOY_BUTTON_7,
+       JOY_L3 = JOY_BUTTON_8,
+       JOY_R3 = JOY_BUTTON_9,
+-      JOY_SELECT = JOY_BUTTON_10,
+-      JOY_START = JOY_BUTTON_11,
++      //JOY_SELECT = JOY_BUTTON_10,
++      JOY_SELECT = JOY_BUTTON_6,
++      //JOY_START = JOY_BUTTON_11,
++      JOY_START = JOY_BUTTON_7,
+       JOY_DPAD_UP = JOY_BUTTON_12,
+       JOY_DPAD_DOWN = JOY_BUTTON_13,
+       JOY_DPAD_LEFT = JOY_BUTTON_14,
+       JOY_DPAD_RIGHT = JOY_BUTTON_15,
+-      JOY_GUIDE = JOY_BUTTON_16,
++      //JOY_GUIDE = JOY_BUTTON_16,
++      JOY_GUIDE = JOY_BUTTON_10,
+       JOY_MISC1 = JOY_BUTTON_17,
+       JOY_PADDLE1 = JOY_BUTTON_18,
+       JOY_PADDLE2 = JOY_BUTTON_19,
Index: patches/patch-platform_x11_SCsub
===================================================================
RCS file: patches/patch-platform_x11_SCsub
diff -N patches/patch-platform_x11_SCsub
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ patches/patch-platform_x11_SCsub    1 Nov 2021 06:49:42 -0000
@@ -0,0 +1,14 @@
+$OpenBSD$
+
+Index: platform/x11/SCsub
+--- platform/x11/SCsub.orig
++++ platform/x11/SCsub
+@@ -10,7 +10,7 @@ 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/patches/patch-platform_x11_detect_py,v
retrieving revision 1.6
diff -u -p -r1.6 patch-platform_x11_detect_py
--- patches/patch-platform_x11_detect_py        22 Aug 2021 01:43:49 -0000      
1.6
+++ patches/patch-platform_x11_detect_py        1 Nov 2021 06:49:42 -0000
@@ -1,6 +1,7 @@
 $OpenBSD: patch-platform_x11_detect_py,v 1.6 2021/08/22 01:43:49 thfr Exp $
 
 remove hardcoded -O2, found by bcallah@. Add sndio
+set JOYDEV_ENABLED
 
 Index: platform/x11/detect.py
 --- platform/x11/detect.py.orig
@@ -33,14 +34,24 @@ Index: platform/x11/detect.py
      elif env["target"] == "debug":
          env.Prepend(CCFLAGS=["-ggdb"])
          env.Prepend(CCFLAGS=["-g3"])
-@@ -323,6 +306,10 @@ def configure(env):
-         env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"])
+@@ -324,6 +307,10 @@ def configure(env):
      else:
          print("ALSA libraries not found, disabling driver")
-+
+ 
 +    print("Enabling sndio")
 +    env.Append(CPPDEFINES=["SNDIO_ENABLED"])
 +    env.Append(LINKFLAGS=["-lsndio"])
- 
++
      if env["pulseaudio"]:
          if os.system("pkg-config --exists libpulse") == 0:  # 0 means found
+             print("Enabling PulseAudio")
+@@ -342,6 +329,9 @@ def configure(env):
+                 print("libudev development libraries not found, disabling 
udev support")
+     else:
+         env["udev"] = False  # Linux specific
++
++    if platform.system() == "OpenBSD":
++      env.Append(CPPDEFINES=["JOYDEV_ENABLED"])
+ 
+     # Linkflags below this line should typically stay the last ones
+     if not env["builtin_zlib"]:
Index: patches/patch-platform_x11_os_x11_cpp
===================================================================
RCS file: /cvs/ports/games/godot/patches/patch-platform_x11_os_x11_cpp,v
retrieving revision 1.6
diff -u -p -r1.6 patch-platform_x11_os_x11_cpp
--- patches/patch-platform_x11_os_x11_cpp       22 Aug 2021 01:43:49 -0000      
1.6
+++ patches/patch-platform_x11_os_x11_cpp       1 Nov 2021 06:49:42 -0000
@@ -1,6 +1,7 @@
 $OpenBSD: patch-platform_x11_os_x11_cpp,v 1.6 2021/08/22 01:43:49 thfr Exp $
 
 fix libXrandr library name and load sndio
+use OpenBSD joypad class
 
 Index: platform/x11/os_x11.cpp
 --- platform/x11/os_x11.cpp.orig
@@ -14,6 +15,15 @@ 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...
+@@ -612,7 +612,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, i
+ 
+       window_has_focus = true; // Set focus to true at init
+ #ifdef JOYDEV_ENABLED
+-      joypad = memnew(JoypadLinux(input));
++      joypad = memnew(JoypadOpenBSD(input));
+ #endif
+ 
+       power_manager = memnew(PowerX11);
 @@ -3973,6 +3973,10 @@ void OS_X11::update_real_mouse_position() {
  }
  
Index: patches/patch-platform_x11_os_x11_h
===================================================================
RCS file: /cvs/ports/games/godot/patches/patch-platform_x11_os_x11_h,v
retrieving revision 1.3
diff -u -p -r1.3 patch-platform_x11_os_x11_h
--- patches/patch-platform_x11_os_x11_h 3 May 2021 19:10:25 -0000       1.3
+++ patches/patch-platform_x11_os_x11_h 1 Nov 2021 06:49:42 -0000
@@ -1,18 +1,32 @@
 $OpenBSD: patch-platform_x11_os_x11_h,v 1.3 2021/05/03 19:10:25 thfr Exp $
 
 load sndio
+use OpenBSD joypad class
 
 Index: platform/x11/os_x11.h
 --- platform/x11/os_x11.h.orig
 +++ platform/x11/os_x11.h
-@@ -37,6 +37,7 @@
+@@ -37,9 +37,10 @@
  #include "crash_handler_x11.h"
  #include "drivers/alsa/audio_driver_alsa.h"
  #include "drivers/alsamidi/midi_driver_alsamidi.h"
 +#include "drivers/sndio/audio_driver_sndio.h"
  #include "drivers/pulseaudio/audio_driver_pulseaudio.h"
  #include "drivers/unix/os_unix.h"
- #include "joypad_linux.h"
+-#include "joypad_linux.h"
++#include "joypad_openbsd.h"
+ #include "main/input_default.h"
+ #include "power_x11.h"
+ #include "servers/audio_server.h"
+@@ -197,7 +198,7 @@ class OS_X11 : public OS_Unix {
+       InputDefault *input;
+ 
+ #ifdef JOYDEV_ENABLED
+-      JoypadLinux *joypad;
++      JoypadOpenBSD *joypad;
+ #endif
+ 
+ #ifdef ALSA_ENABLED
 @@ -206,6 +207,10 @@ class OS_X11 : public OS_Unix {
  
  #ifdef ALSAMIDI_ENABLED
Index: pkg/PLIST
===================================================================
RCS file: /cvs/ports/games/godot/pkg/PLIST,v
retrieving revision 1.1.1.1
diff -u -p -r1.1.1.1 PLIST
--- pkg/PLIST   27 Apr 2018 07:32:53 -0000      1.1.1.1
+++ pkg/PLIST   1 Nov 2021 06:49:42 -0000
@@ -1,2 +1,3 @@
 @comment $OpenBSD: PLIST,v 1.1.1.1 2018/04/27 07:32:53 bentley Exp $
 @bin bin/godot
+share/doc/pkg-readmes/${PKGSTEM}

Reply via email to