qmk / qmk_firmware

Open-source keyboard firmware for Atmel AVR and Arm USB families
https://qmk.fm
GNU General Public License v2.0
18.02k stars 38.74k forks source link

HID Gamepad support #3903

Closed a-chol closed 1 year ago

a-chol commented 6 years ago

Hello, I am in the process of adding an analog stick to my keyboard (bminiex by winkeyless). I have researched current issues and the code repository and haven't found any previous work on the subject (apart from isolated work which doesn't seem to have been pushed into the main qmk repo) I would like to expose it to the OS through an HID gamepad interface. The code works so far for this part, but it relies on modifications outside of my user keyboard configuration to add the gamepad HID interface to v-usb. Moreover, the key matrix could support sending HID gamepad button signals instead of keyboard events, which also requires changes inside qmk/tmk. In this context, my issue is : does the qmk maintainers approve the integration of this feature?

To advocate for the latter, there is already support for mouse and MIDI interfaces, so gamepad doesn't seem out of place. Moreover, I have seen people asking for advice to create their own gamepad controller (for homemade arcades) and qmk could be a good approach on multiple counts. What do you guys think about this?

yiancar commented 5 years ago

I think anything that can be turn on/off using a DEFINE is welcome on qmk:) would have to be tested on all platforms, ARM and AVR, but we can help with that!:)

jackhumbert commented 5 years ago

@a-chol just to echo what @yiancar said - absolutely :) with the addition of the Qwiic Joystiic, this would be a great feature to build-out! Do you have your modifications on a branch somewhere?

a-chol commented 5 years ago

So here is where I'm at right now : https://github.com/a-chol/qmk_firmware/commit/50a059ce9c6aa8ea74c4f81e69ce27b2d404d6c0 I have chosen to rename the feature as Joystick instead of gamepad, which seems to fit the definition of the HID specification better. Everything is protected by #ifdef ENABLE_JOYSTICK. I support up to 6 axes and 32 buttons ; it is tested and working (I haven't pushed my personal keymap yet though) I implemented hid report sending for joystick interface only for the v-usb driver for now. I don't have a keyboard that uses LUFA, but I can give a shot at an initial implementation. I haven't built the electronics side of the project yet, but I'm planning on doing this in the coming weeks. I salvaged a dualaxis analogic joystick and the schematic of my kb (ps2avrgb) seems to indicate that I have a "hole in the matrix" available to connect two analogic inputs. With the current implementation, one is able to control a virtual joystick from the keyboard, which is already a useful feature. I'll create a pull request when the analog read is tested to be working, or sooner if you find the current state usefull.

yiancar commented 5 years ago

this would be good to get working on arm as well! I imagine u need to get the adc working for that?

a-chol commented 5 years ago

Yeah, I haven't checked what is available in the drivers/arm folder. The only function I use from the avr folder is analogRead.

yiancar commented 5 years ago

yea we will need to set it up but its quite easy. have a google regarding chibios adc. there should be a hal library for it. I mean that after you get it working on avr. I can have a look and help you as well when the time comes

twschum commented 5 years ago

Just like to voice my support for this! I am looking at building out a macropad + analog inputs device and would love to be able to use QMK for it.

a-chol commented 5 years ago

So this feature is materializing into PR #4226 . I am in the process of doing the electrical wiring for the analog joystick I got. I thought everything everything was going the work out until the following problem : when one potentiometer is connected, all keys from the row get triggered. I'm a bit of a noob in electronics, so my understanding might be off. Here is what I have done :

My expectation was that the col was driven high when selected for reading, and when a switch is depressed, would drive the corresponding row input to high.

After reading the code, I'm not sure I understand how the matrix scanning works anymore : columns are set to low when selected (?), the others are never set to high : what does it matter to have column if they are never high? does setting columns as "input high" output current on the pin? rows (inputs) are configured with pull-up resistor : I get from that that the default reading would be 1, except when connected to the ground? Does a switch depression short the pin towards ground?

I must be missing some basic knowledge of how MCU IO pins work, so a short explanation of what I am missing would be great.

drashna commented 5 years ago

You may want to check this out: https://docs.qmk.fm/#/hand_wire

a-chol commented 5 years ago

Thank you for the link. As I had understood,

send a logical 1 to the columns, one at a time, and read from the rows,

Then I don't get why each of the columns in qmk's scan_matrix are set to low successively, which should correspond to writing a logical 0.

drashna commented 5 years ago

IIRC, AVR doesn't support pulling high. But I'm not an expert with the hardware interface stuff, at all. @jackhumbert, @skullydazed, or @fredizzimo would be more qualified to answer this. (and to which I'd likely open a PR to update docs)

a-chol commented 5 years ago

So I figured some things out regarding the circuitry that is a bit "wrong" in the handwiring guide. Basically, input pins for the matrix are set with pull-up resistor. It means that the "default" tension to the input pin is 5v (Vcc) as the input reads high. As soon as "some" current (more than the current that flows through the pullup resistor, if I got that well) is drawn towards the ground, the input pin reads low. This is required to properly detect circuit closure when contacts of a switch might be a bit oxydized and conduct current with a bit of resistance. The consequence of this is that when a switch is pressed, current actually flows from the input pin (at Vcc) towards output pin. During matrix scan, all outputs are set high (at Vcc) except the current column, which is set low and consequently acts as a ground. That's why, when configuring the qmk matrix, you have to define the DIODE_DIRECTION to go from inputs to outputs. The good news is that, since this is opposite to the current flow we need to set up to read an analog device on the ADC, we can seggregate the keyboard matrix circuit from the analog device circuit using diodes, meaning that probably anyone can add an analog device to his keyboard. For my joystick, the working circuit is set up with diodes at the ADC pin, and at the ground pin, which is a pin turned to output low during analogRead.

pahlers commented 4 years ago

@a-chol Can you update the status of this project. I would like to use something like the Qwiic Joystick in a project. Thanks for you good work :+1:

edit: Strike through the question. The pull request https://github.com/qmk/qmk_firmware/pull/4226 is almost merged! Well done!

amrsoll commented 2 years ago

@a-chol I presume this issue could be closed?

drashna commented 1 year ago

the HID joystick feature should support this.