diff --git a/src/game/gameport.c b/src/game/gameport.c index 8ae1c7d25..67447d447 100644 --- a/src/game/gameport.c +++ b/src/game/gameport.c @@ -15,7 +15,7 @@ * * Copyright 2016-2022 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * Copyright 2021 RichardG. + * Copyright 2021 RichardG. * Copyright 2021-2025 Jasmine Iwanek. */ #include @@ -90,11 +90,18 @@ static const struct { } joysticks[] = { { &joystick_none }, { &joystick_2axis_2button }, + { &joystick_2button_gamepad }, + { &joystick_2button_flight_yoke }, { &joystick_2axis_4button }, + { &joystick_4button_gamepad }, + { &joystick_4button_flight_yoke }, { &joystick_2axis_6button }, { &joystick_2axis_8button }, { &joystick_3axis_2button }, + { &joystick_2button_yoke_throttle }, { &joystick_3axis_4button }, + { &joystick_win95_steering_wheel }, // Temp + { &joystick_4button_yoke_throttle }, { &joystick_4axis_4button }, { &joystick_ch_flightstick_pro }, { &joystick_ch_flightstick_pro_ch_pedals }, diff --git a/src/game/joystick_standard.c b/src/game/joystick_standard.c index 5f200cb98..593bc6596 100644 --- a/src/game/joystick_standard.c +++ b/src/game/joystick_standard.c @@ -8,13 +8,14 @@ * * Implementation of a standard joystick. * - * - * * Authors: Miran Grca, * Sarah Walker, + * Miran Grca, + * Jasmine Iwanek, * * Copyright 2016-2018 Miran Grca. * Copyright 2008-2018 Sarah Walker. + * Copyright 2021-2025 Jasmine Iwanek. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -147,6 +148,37 @@ joystick_standard_read_axis_4button(UNUSED(void *priv), int axis) } } +static int +joystick_standard_read_axis_with_pov(UNUSED(void *priv), int axis) +{ + if (!JOYSTICK_PRESENT(0, 0)) + return AXIS_NOT_PRESENT; + + switch (axis) { + case 0: // X-axis + return joystick_state[0][0].axis[0]; + case 1: // Y-axis + return joystick_state[0][0].axis[1]; + case 2: // POV Hat (mapped to the 3rd logical axis, index 2) + if (joystick_state[0][0].pov[0] == -1) + return 32767; // Centered/No input (as per tm_fcs_rcs_read_axis example) + if (joystick_state[0][0].pov[0] > 315 || joystick_state[0][0].pov[0] < 45) + return -32768; // Up + if (joystick_state[0][0].pov[0] >= 45 && joystick_state[0][0].pov[0] < 135) + return -16384; // Up-Right (example value, matches tm_fcs_rcs_read_axis) + if (joystick_state[0][0].pov[0] >= 135 && joystick_state[0][0].pov[0] < 225) + return 0; // Right/Left (example, matches tm_fcs_rcs_read_axis) + if (joystick_state[0][0].pov[0] >= 225 && joystick_state[0][0].pov[0] < 315) + return 16384; // Down-Left (example value, matches tm_fcs_rcs_read_axis) + return 0; // Fallback + case 3: // This case might be used for a Z-axis if present, or can return 0 if not. + // For gamepads with only X/Y and POV, this will likely be unused or return 0. + return 0; + default: + return 0; + } +} + static int joystick_standard_read_axis_3axis(UNUSED(void *priv), int axis) { @@ -257,6 +289,42 @@ const joystick_if_t joystick_2axis_2button = { .pov_names = { NULL } }; +const joystick_if_t joystick_2button_gamepad = { + .name = "2-button gamepad(s)", + .internal_name = "2button_gamepad", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 2, + .pov_count = 0, + .max_joysticks = 2, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2" }, + .pov_names = { NULL } +}; + +const joystick_if_t joystick_2button_flight_yoke = { + .name = "2-button flight yoke", + .internal_name = "2button_flight_yoke", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 2, + .pov_count = 0, + .max_joysticks = 2, + .axis_names = { "Roll axis", "Pitch axis" }, + .button_names = { "Trigger", "Button 2" }, + .pov_names = { NULL } +}; + const joystick_if_t joystick_2axis_4button = { .name = "2-axis, 4-button joystick", .internal_name = "2axis_4button", @@ -275,6 +343,42 @@ const joystick_if_t joystick_2axis_4button = { .pov_names = { NULL } }; +const joystick_if_t joystick_4button_gamepad = { + .name = "4-button gamepad", + .internal_name = "4button_gamepad", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_4button, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "X axis", "Y axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } +}; + +const joystick_if_t joystick_4button_flight_yoke = { + .name = "4-button flight yoke", + .internal_name = "4button_flight_yoke", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_4button, + .a0_over = joystick_standard_a0_over, + .axis_count = 2, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "Roll axis", "Pitch axis" }, + .button_names = { "Trigger", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } +}; + const joystick_if_t joystick_3axis_2button = { .name = "3-axis, 2-button joystick", .internal_name = "3axis_2button", @@ -293,6 +397,24 @@ const joystick_if_t joystick_3axis_2button = { .pov_names = { NULL } }; +const joystick_if_t joystick_2button_yoke_throttle = { + .name = "2-button flight yoke with throttle", + .internal_name = "2button_yoke_throttle", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_3axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 3, + .button_count = 2, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "Roll axis", "Pitch axis", "Throttle axis" }, + .button_names = { "Trigger", "Button 2" }, + .pov_names = { NULL } +}; + const joystick_if_t joystick_3axis_4button = { .name = "3-axis, 4-button joystick", .internal_name = "3axis_4button", @@ -311,6 +433,42 @@ const joystick_if_t joystick_3axis_4button = { .pov_names = { NULL } }; +const joystick_if_t joystick_4button_yoke_throttle = { + .name = "4-button flight yoke with throttle", + .internal_name = "4button_yoke_throttle", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_3axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 3, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "Roll axis", "Pitch axis", "Throttle axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } +}; + +const joystick_if_t joystick_win95_steering_wheel = { + .name = "Win95 Steering Wheel (3-axis, 4-button)", + .internal_name = "win95_steering_wheel", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_3axis, + .a0_over = joystick_standard_a0_over, + .axis_count = 3, + .button_count = 4, + .pov_count = 0, + .max_joysticks = 1, + .axis_names = { "Steering axis", "Accelerator axis", "Brake axis" }, + .button_names = { "Button 1", "Button 2", "Button 3", "Button 4" }, + .pov_names = { NULL } +}; + const joystick_if_t joystick_4axis_4button = { .name = "4-axis, 4-button joystick", .internal_name = "4axis_4button", diff --git a/src/include/86box/gameport.h b/src/include/86box/gameport.h index 7928cdd30..655eea942 100644 --- a/src/include/86box/gameport.h +++ b/src/include/86box/gameport.h @@ -15,7 +15,7 @@ * * Copyright 2016-2022 Miran Grca. * Copyright 2008-2018 Sarah Walker. - * Copyright 2021 RichardG. + * Copyright 2021 RichardG. * Copyright 2021-2025 Jasmine Iwanek. */ #ifndef EMU_GAMEPORT_H @@ -52,6 +52,26 @@ #define GAMEPORT_8ADDR 0x080000 #define GAMEPORT_SIO 0x1000000 +typedef struct joystick_if_t { + const char *name; + const char *internal_name; + + void *(*init)(void); + void (*close)(void *priv); + uint8_t (*read)(void *priv); + void (*write)(void *priv); + int (*read_axis)(void *priv, int axis); + void (*a0_over)(void *priv); + + int axis_count; + int button_count; + int pov_count; + int max_joysticks; + const char *axis_names[MAX_JOY_AXES]; + const char *button_names[MAX_JOY_BUTTONS]; + const char *pov_names[MAX_JOY_POVS]; +} joystick_if_t; + typedef struct plat_joystick_t { char name[260]; @@ -90,26 +110,6 @@ typedef struct joystick_t { int pov_mapping[MAX_JOY_POVS][2]; } joystick_t; -typedef struct joystick_if_t { - const char *name; - const char *internal_name; - - void *(*init)(void); - void (*close)(void *priv); - uint8_t (*read)(void *priv); - void (*write)(void *priv); - int (*read_axis)(void *priv, int axis); - void (*a0_over)(void *priv); - - int axis_count; - int button_count; - int pov_count; - int max_joysticks; - const char *axis_names[MAX_JOY_AXES]; - const char *button_names[MAX_JOY_BUTTONS]; - const char *pov_names[MAX_JOY_POVS]; -} joystick_if_t; - extern device_t game_ports[GAMEPORT_MAX]; #ifdef __cplusplus @@ -171,9 +171,16 @@ extern void gameport_remap(void *priv, uint16_t address); extern void *gameport_add(const device_t *gameport_type); extern const joystick_if_t joystick_2axis_2button; +extern const joystick_if_t joystick_2button_gamepad; +extern const joystick_if_t joystick_2button_flight_yoke; extern const joystick_if_t joystick_2axis_4button; +extern const joystick_if_t joystick_4button_gamepad; +extern const joystick_if_t joystick_4button_flight_yoke; extern const joystick_if_t joystick_3axis_2button; +extern const joystick_if_t joystick_2button_yoke_throttle; extern const joystick_if_t joystick_3axis_4button; +extern const joystick_if_t joystick_4button_yoke_throttle; +extern const joystick_if_t joystick_win95_steering_wheel; extern const joystick_if_t joystick_4axis_4button; extern const joystick_if_t joystick_2axis_6button; extern const joystick_if_t joystick_2axis_8button; @@ -186,14 +193,6 @@ extern const joystick_if_t joystick_sw_pad; extern const joystick_if_t joystick_tm_fcs; extern const joystick_if_t joystick_tm_fcs_rcs; -extern int gameport_available(int); -extern int gameport_has_config(int); -extern const char *gameport_get_internal_name(int); -extern int gampeport_get_from_internal_name(char *); -#ifdef EMU_DEVICE_H -extern const device_t *gameport_getdevice(int); -#endif - #ifdef __cplusplus } #endif diff --git a/src/qt/win_joystick_rawinput.c b/src/qt/win_joystick_rawinput.c index 5173d4f05..ecd885d3a 100644 --- a/src/qt/win_joystick_rawinput.c +++ b/src/qt/win_joystick_rawinput.c @@ -222,6 +222,7 @@ joystick_get_capabilities(raw_joystick_t *rawjoy, plat_joystick_t *joy) UINT size = 0; PHIDP_BUTTON_CAPS btn_caps = NULL; PHIDP_VALUE_CAPS val_caps = NULL; + HIDP_CAPS caps; /* Get preparsed data (HID data format) */ GetRawInputDeviceInfoW(rawjoy->hdevice, RIDI_PREPARSEDDATA, NULL, &size); @@ -229,7 +230,6 @@ joystick_get_capabilities(raw_joystick_t *rawjoy, plat_joystick_t *joy) if (GetRawInputDeviceInfoW(rawjoy->hdevice, RIDI_PREPARSEDDATA, rawjoy->data, &size) <= 0) fatal("joystick_get_capabilities: Failed to get preparsed data.\n"); - HIDP_CAPS caps; HidP_GetCaps(rawjoy->data, &caps); /* Buttons */ @@ -356,6 +356,7 @@ end_loop: free(info); } + free(deviceList); joystick_log("joystick_init: joysticks_present=%i\n", joysticks_present); /* Initialize the RawInput (joystick and gamepad) module. */