derkyjadex / M8WebDisplay

Display for headless M8 tracker
https://derkyjadex.github.io/M8WebDisplay/
MIT License
196 stars 39 forks source link

can't map arrow keys to controller #6

Closed koraysels closed 2 years ago

koraysels commented 2 years ago

hi, i can't map the arrow keys of my snes-like gamepasd controller on my mac. The controller arrow keys works if I test it using gamepad tester

JeffAlyanak commented 2 years ago

Hmm, I've got the same thing here.

I think potentially that this heuristic isn't properly detecting the d-pad. I'll have to fiddle with it at some point and look at submitting a PR.

https://github.com/derkyjadex/M8WebDisplay/blob/6f10677d557dc33a033a445e9bb90997b981e0ee/js/input.js#L178-L190

derkyjadex commented 2 years ago

Hi, sorry for not looking at this sooner. It'll be hard for me to debug this without the hardware to test with, so if you can get it working and submit a patch that would be great. I'll try to give some background on what's going on with that code, in case it's helpful.

What I found with a couple of the controllers I have is that the d-pad isn't reported as a set of buttons but instead as a single byte value with different codes for each direction (this is from looking at the USB packets with Wireshark). So up is 0, up+right is 1, right is 2, etc up to 7. Nothing pressed is 8 or 15, depending on the controller. Somewhere between the OS and Chrome, this input is being interpreted as a single analogue axis and the raw value is mapped to a float, which is supposed to be between -1.0 and 1.0. Line 180 should map the value back to an integer, but it's slightly off because of accumulated floating point errors, hence the error checking part. Obviously there are other real axes that aren't d-pads, so if we ever see an "invalid" value from an axis then it can't possibly be a d-pad and we know we can ignore it from now on.

What might be going on is that the error tolerance might not be quite large enough in your case for some reason, or the gamepad is reporting some other value outside of 0-8 or 15.

amo-ableton commented 2 years ago

I just stumbled upon this issue with a newly bought . 8BitDo M30 Bluetooth Wireless Gamepad. Let me know if there's anything I can contribute in terms of data (I'm not a programmer). On https://gamepad-tester.com/ teh D-pad registers on axis 0 and 1.

amo-ableton commented 2 years ago

I just stumbled upon this issue with a newly bought . 8BitDo M30 Bluetooth Wireless Gamepad. Let me know if there's anything I can contribute in terms of data (I'm not a programmer). On https://gamepad-tester.com/ teh D-pad registers on axis 0 and 1.

Actually my report isn't true: there was a key combination on the controller to perform, and now the D-pad works. I had to press UP and Select and hold for a few seconds. It is described here: https://support.8bitdo.com/faq/m30-bluetooth-controller.html

milestorm commented 2 years ago

I have the chinese copy of SNES controller, which D-pad is like axis. But the mapping does not work. I tried to fiddle with it, but no luck. There is axis array of two floats: left-right and up-down (both when pressed goes to -1 and 1). If I mapped the controller with a 3rd party app as keystrokes, it works, but there were double pressing... Anyways... My workaround for this I've disabled the two listeners for connecting and disconnecting gamepad, and the mapping works now perfectly. So maybe if there will be some switch in settings to turn off controllers... :)

TimPietrusky commented 2 years ago

@milestorm

Anyways... My workaround for this I've disabled the two listeners for connecting and disconnecting gamepad, and the mapping works now perfectly. So maybe if there will be some switch in settings to turn off controllers... :)

What does this actually mean? You changed the code to remove the listeners? And why does this fix the mapping of the SNES controller clone?

I have the same controller clone and wonder what is actually needed to use it.

milestorm commented 2 years ago

@TimPietrusky

I have commented the listeners on line 218 to 231 in file input.js to disable the gamepad functionality in the m8webdisplay app, because, when I used external program for mapping the keyboard keys to the gamepad (Enjoyable app for Mac), it does not work properly and the I got double triggers, even when everything was mapped correctly.

derkyjadex commented 2 years ago

Hi @milestorm, have you tried using "Clear All" in Control Mapping and then just re-adding the mappings for the keyboard keys you've set up in Enjoyable? Does that still result in double pressing?

I can't work out where the double presses could be coming from. Even if you have multiple keys/buttons mapped to the same action and pressed them all at once, the web display and M8 won't register a second press until at least one of the keys or buttons is released and then the same key (or one of the others) is pressed a second time.

Are you able to debug the code to see what might be causing the extra events? I would start by watching for when connection.sendKeys(keyState) is called (line 102) and checking what keyState values are being sent. For a double press I would expect one of the bits to be going to 1, then 0 and then back to 1. Assuming that is the case, I'd want to find out what event is triggering that middle switch to 0.

milestorm commented 2 years ago

Hi @derkyjadex, for some unknown reason the clearing of all keys never came to my mind, when I tried the controller. It clearly clears some default gamepad mappings, and when I set the mappings to keyboard, turned on Enjoyable, than it works (even with the gamepad listeners on) Now it is OK: I can control webdisplay with gamepad thru Enjoyable, but direct mapping of the controller still does not work. - all buttons work except the arrow cross... GamepadTester shows two axis. Axis 0 for the left (-1) and right (1) button, and Axis 1 for the up (-1) and down (1) button. And when nothing is pressed, both axis are on value -0.00392...

Edit: Maybe it will be good, if actual mappings were shown in the buttons? :)

yentzee commented 2 years ago

same problem here. I am using a playstation 4 controller with usb receiver and everything but the d pad down is working :( might try another browser.

ebfe commented 2 years ago

I hit the same problem with an 8BitDo N30 which uses the same mapping as reported above . I think there are multiple issues with that controller:

diff --git a/js/input.js b/js/input.js
index 824a136..f7718b6 100644
--- a/js/input.js
+++ b/js/input.js
@@ -171,23 +171,20 @@ function pollGamepads() {
         }

         if (gamepad.mapping !== 'standard') {
-            for (let i = 0; i < gamepad.axes.length; i++) {
-                if (state.axes[i] === false)
-                    continue;
-
-                // Heuristics to locate a d-pad or
-                // "hat switch" masquerading as an axis
-                const value = (gamepad.axes[i] + 1) * 3.5;
-                const error = Math.abs(Math.round(value) - value);
-                const hatPosition = hatMap[Math.round(value)];
-                if (error > 4.8e-7 || hatPosition === undefined) {
-                    state.axes[i] = false;
-                    continue;
-                } else if (value === 0 && state.axes[i] !== true) {
-                    continue;
-                } else {
-                    state.axes[i] = true;
-                }
+            for (let i = 0; i < 2; i++) {
+               let hatPosition = [false, false, false, false];
+               if (gamepad.axes[0] < -0.9) {
+                   hatPosition[0] = true;
+               }
+               if (gamepad.axes[0] > 0.9) {
+                   hatPosition[1] = true;
+               }
+               if (gamepad.axes[1] < -0.9) {
+                   hatPosition[2] = true;
+               }
+               if (gamepad.axes[1] > 0.9) {
+                   hatPosition[3] = true;
+               }

                 for (let b = 0; b < 4; b++) {
                     const pressed = hatPosition[b];

which seems to work fine with this specific controller.

derkyjadex commented 2 years ago

Just taking another look through this. I'll first mention that the display does not currently support actual analogue axis inputs. So any kind of analogue stick, or anything that reports as an analogue stick will be ignored (apart from the "hat switch" hack mentioned above).

So the 8BitDo M30 (@amo-ableton) and the SNES controller (@milestorm) d-pad inputs are not currently mappable. I didn't implement this originally because it seemed like too much work at the time, but thinking about it now I don't think it'll be too hard.

@ebfe Thanks for the info and code. The neutral position value shouldn't be a problem; it's only relevant for the "hat switch" hack. If I implement proper analogue axis support it shouldn't be an issue. I would probably set the value threshold to ±0.5 so actual analogue sticks work as expected (a full diagonal position gives values ~±0.8). Axis 9 reporting a constant 3.28571* also shouldn't be an issue since presses are only registered when the input value changes. So it would only register when the controller first shows up (when it will be mapped to nothing) and shouldn't interfere with setting mappings or general usage after that.

@yentzee I've set up a PS4 controller on macOS and it is all working fine for me. You mention a USB receiver so I assume you're on some other platform. It's worth testing your controller/browser combo with https://gamepad-tester.com/. If your down button isn't working there, the problem is outside the M8WebDisplay. If everything is working there, maybe the button is being reported with an unusual number, so try manually adding a mapping for it.

~*Is that correct? It should be clamped to ±1~

derkyjadex commented 2 years ago

I've just pushed updates with support for analogue axes. It should now be possible to set up mappings for the 8BitDo N30 and the SNES controller described above.

I haven't published the changes yet, I want to do a little more testing before I do that. You'll have to build and run the code locally to try it out. If anyone who's had problems in this thread could do that and let me know how it works out, that'd be great.

@ebfe One of my gamepads is reporting exactly the same weird value on axis 9. In my case though it is coming from the d-pad and 3.28571 is the "nothing pressed" value, which maps to 15 in the heuristic code.

derkyjadex commented 2 years ago

Also, for anyone testing their gamepad in the browser, it looks like https://greggman.github.io/html5-gamepad-test/ does a better job of showing what's going on. The other Gamepad Tester site was ignoring some buttons that were working fine elsewhere.

milestorm commented 2 years ago

@derkyjadex Works like a charm for SNES controller :) Thank you for the update :) 👍

Edit: after my mac turns off its display, as it thinks I'm doing nothing with my computer... :D (MacOS & Chrome)

derkyjadex commented 2 years ago

I've just pushed another change which should help with that. There's a "Prevent Sleep" option in the menu, which is disabled by default.

TimPietrusky commented 2 years ago

I just tried to use the SNES gamepad-clone to map the arrows, but they are still not recognized.

When using https://greggman.github.io/html5-gamepad-test/ everything is recognized correctly, so I'm not sure what else might be going wrong. Do I still need to change some code to actually get the gamepad working?

EDIT

I used the deployed version on gh-pages, but that doesn't seem up to date. I try to use the version from main!

EDIT 2

Everything works out perfectly with the version in main, thank you super much!

ebfe commented 2 years ago

Thanks @derkyjadex! Can confirm current master branch now works as expected with the 8BitDo N30.

derkyjadex commented 2 years ago

I've published these changes now. Looks like everyone's issues should be fixed.