Skip to content
This repository has been archived by the owner on Mar 19, 2024. It is now read-only.

Some Fixes For Gamepad.go #41

Closed
wants to merge 4 commits into from
Closed

Conversation

ThomasT75
Copy link

This PR fixes #40 (what i meant to say in that Issue was the hat value was too weak)
It also adds 2 ___TriggerForce() new functions for trigger-axis control that fixes #39

@bendahl
Copy link
Owner

bendahl commented Feb 26, 2024

Hi @ThomasT75,

thanks for the feedback and your efforts!

I reviewed the changes and also performed some testing to verify the suggested hat values of 32767 and -32767. Using hardwaretester, as you suggested, while running the below code (based on the TestHatMovement test located in gamepad_test.go) yields the expected values of 1 and -1 for the generated events. The device created does have a number of axis, though (8 to be precise). Axis 6 and 7 are the ones that are being used for the hat (see attached screenshots).

Also, when attaching an actual USB controller that comes with a single 4-way hat, there are only two axis (0 and 1) that events are generated for. The values also being 1 and -1, not 32767 and -32767. Therefore, I don't believe that using MaximumAxisValue in sendHatEvent is a good idea.

Based on these findings it appears that we would rather need a new hat movement function that allows to choose between different hats instead of using number 6 and 7. I will have to investigate this further, however.

Code to reproduce the findings:

func TestHatMovement(t *testing.T) {
	vg, err := CreateGamepad("/dev/uinput", []byte("Hot gophers in your area"), 0xDEAD, 0xBEEF)
	if err != nil {
		t.Fatalf("Failed to create the virtual gamepad. Last error was: %s\n", err)
	}

	err = vg.HatPress(HatUp)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to move hat up")
	}
	err = vg.HatRelease(HatUp)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatRight)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to move hat right")
	}
	err = vg.HatRelease(HatRight)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatDown)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to move hat down")
	}
	err = vg.HatRelease(HatDown)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
	err = vg.HatPress(HatLeft)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to move hat left")
	}
	err = vg.HatRelease(HatLeft)
	time.Sleep(2 * time.Second)
	if err != nil {
		t.Fatalf("Failed to release hat")
	}
}

Screenshots:
hat_down
hat_left
hat_right
hat_up

@ThomasT75
Copy link
Author

Hi @bendahl

Im not too familiar with how to emulate a real device in my use case i just want to emulate a random controller like a ds4 or xbox controller so using a VID PID that no real device uses like 0xdead 0xbeef just works else i think the kernel tries to use a driver for it and i don't know how to write a controller for a specific driver

I also would like to know how you got the event value for that USB controller did you use evdev?

IMO the current gamepad.go implementation is very abstracted around a normal controller and by normal i mean 2 sticks, 1 dpad, 4 face buttons, 2 bumpers, 2 triggers and 3 main buttons, I think you are right we should just send a value for the force, but i don't think we need to support multiple hats.

Btw i think hardwaretester doesn't differentiate between what an axis represents is it just list them in order it got from the browser gamepad api so axis 6 and 7 might become axis 0 and 1 if you only have a hat in the capability list and the axis are normalized between -1 and 1

If you want to support multiple hats i say why only multiple hats we should do another struct with everything verbose but easy to use like instead of saying LeftStickMoveX(value) we could say MoveAxis(ABS_X, value) that way we are not like saying this is the left stick or doing any abstractions on the value, So the value you put in is the value that will come out

Another point is that lets say i want to make a gyro and an accelerometer this module doesn't have a gyro.go and a accelerometer.go so it would be hard for me to add this functionally without altering the source code

Also after using more this gamepad.go i found out that if you use lets say a "fake" VID PID uinput.ButtonNorth and uinput.ButtonWest are swapped because the default behavior it seems to emulate a xbox controller in most apps i tried and after some digging i found in input-event-codes.h to have them swapped too for BTN_X BTN_Y defines

I might add the missing value for the hats + missing event codes for BTN_X as uinput.ButtonX etc tomorrow

I reverted hat force to -1:1 but set the Absmin/max to -1:1
@ThomasT75 ThomasT75 marked this pull request as draft February 29, 2024 05:49
@ThomasT75
Copy link
Author

Well i did a commit that broke absHat0 completely so moving this to a draft

@ThomasT75
Copy link
Author

Ok I didn't not broke it per say but hardwaretester showing absHat0 as a dpad button press/release

I think that is due to with the Absmin/max being -1:1

The lack of a Hat0Axis resembles more a broken ds4 controller I have here:
image

DEAD BEEF with the commit that made Hat0Axis "disappear" (it is still there but it is being reported as buttons by the site):
image

Another thing is that while Steam or Duckstation can't see the triggers using the ButtonDown function (making an axis trigger necessary) they can see the ButtonDown form of dpad but can't see Hat0Axis (even when hardwaretester show it as a button) So these apps decided (apparently) to ignore Hat0Axis completely

In the doc below it is says that it is up to the app to choose which one is better for they use
Linux Gamepad Specification

So assuming that gamepad.go is trying to mimic the gamepad in the link above and that most apps don't read AbsHat0 I say we remove the HatRelease/Press functions altogether and save complexity and I don't think many devs rely on the current implementation of HatRelease/Press considering gamepad.go was missing triggers

I will still leave this as a draft because I want to hear what you think @bendahl and work from there

@bendahl
Copy link
Owner

bendahl commented Mar 19, 2024

Hey @ThomasT75,

once again thanks for all the input and effort. I really appreciate this. However, I've come to realize that I simply can't find the time to review the requested changes with the required diligence and really dig into this. I've been pondering this decision for a while now and have finally come to the conclusion that it just doesn't make sense for me to maintain this project any longer. I will be keeping this repo online for reference, so that others may fork and use it.

Feel free to incorporate your changes in your fork. Personally, I would always advice against API changes (however small) if they're not strictly required, as this can have side effects on downstream projects. These are just my two cents.

Again, thanks for the efforts and sorry for the unfortunate timing.

Cheers
Ben

@bendahl bendahl closed this Mar 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Gamepad Hat*(direction) doesn't allow value input Gamepad no way to send a trigger command using an axis
2 participants