notaz / picodrive

Fast MegaDrive/MegaCD/32X emulator
Other
291 stars 165 forks source link

SDL Hat support code suggestion #89

Closed noabody closed 6 years ago

noabody commented 6 years ago

I was looking at platform/libpicofe/in_sdl.c and see that the input layouts follow this standard closely: SDL Quick Reference Simply changing line 276 from 1 to 8 allows stick "2" to control the GUI.

        if (event->jaxis.axis > 8)

Unfortunately attempts to map stick "1" lead to \x00 for movement along any directional. Without either HAT support or a Joystick, one must use something like AntiMicro to map the gamepad to keyboard events to play a game.

This issue isn't specifically for the developer, I simply don't have the programming skils (any actually) to alter the code in a meaningful way.

Perhaps someone else would be able to update the code for said functionality. Thank you for your attention and the beautiful emulator work.

noabody commented 6 years ago

After fifty or so variations on the code in_sdl.c, in reference to dozens of internet search examples of code usage, I finally constructed this:

diff --git a/platform/libpicofe/in_sdl.c  b/platform/libpicofe/in_sdl.c
--- a/platform/libpicofe/in_sdl.c   2018-07-29 08:38:02.016564259 -0600
+++ b/platform/libpicofe/in_sdl.c   2018-07-29 08:37:06.309806921 -0600
@@ -300,6 +300,34 @@
        }
        break;

+   case SDL_JOYHATMOTION:
+       if (event->jhat.which != state->joy_id)
+           return -2;
+       if (event->jhat.value == SDL_HAT_CENTERED) {
+           kc = state->axis_keydown[event->jhat.hat];
+           state->axis_keydown[event->jhat.hat] = 0;
+           ret = 1;
+       }
+       else if (event->jhat.value & SDL_HAT_UP || event->jhat.value & SDL_HAT_LEFT) {
+           kc = state->axis_keydown[event->jhat.hat];
+           if (kc)
+               update_keystate(state->keystate, kc, 0);
+           kc = (event->jhat.value & SDL_HAT_UP) ? SDLK_UP : SDLK_LEFT;
+           state->axis_keydown[event->jhat.hat] = kc;
+           down = 1;
+           ret = 1;
+       }
+       else if (event->jhat.value & SDL_HAT_DOWN || event->jhat.value & SDL_HAT_RIGHT) {
+           kc = state->axis_keydown[event->jhat.hat];
+           if (kc)
+               update_keystate(state->keystate, kc, 0);
+           kc = (event->jhat.value & SDL_HAT_DOWN) ? SDLK_DOWN : SDLK_RIGHT;
+           state->axis_keydown[event->jhat.hat] = kc;
+           down = 1;
+           ret = 1;
+       }
+       break;
+
    case SDL_JOYBUTTONDOWN:
    case SDL_JOYBUTTONUP:
        if (event->jbutton.which != state->joy_id)

It appears to work fine. I guess sheer determination sometimes outweighs ability. Sorry to the developer if this is crap.

The only thing I was able to learn after four days, and a dozen hours, is that the Joystick code blocks axes greater than 1, then measures center, then checks for movement in the negative axes (up/left) using the axis number as a truth table to map SDLK_UP or SDLK_LEFT. The same is then done on the positive axes for SDLK_DOWN or SDLK_RIGHT. With that in mind, I constructed similar statements to mimic the joystick code with hat terminology.

It's important to note this code-base always maps joystick, or hat motion, into the equivalent keyboard key for Up/Left, Down/Right, so there is no need to map either the hat or the joystick in the controller configuration. Just leave the directionals at default and map game-pad buttons.

noabody commented 6 years ago

Close to pull requests against master and submodule libpicofe https://github.com/notaz/picodrive/pull/90 https://github.com/notaz/libpicofe/pull/3