zocker-160 / keyboard-center

Application for mapping macro keys on Logitech keyboards
GNU General Public License v3.0
65 stars 2 forks source link

G935 support #52

Closed coxaka closed 1 year ago

coxaka commented 1 year ago

I am trying to get output from a G935. G935 is a headset that has buttons on the side which can be remapped in the Logitech software just like any other G-Key.

Unfortunately the newDeviceDebugger just throws an error:

usbVendor = 0x046d
usbProduct = 0x0a87
DEBUG: Searching for keyboard...
DEBUG: Keyboard found! :)
DEBUG: requesting USB endpoint...
Traceback (most recent call last):
  File "/tmp//keyboard-center/src/newDeviceDebugger.py", line 222, in <module>
    main()
  File "/tmp//keyboard-center/src/newDeviceDebugger.py", line 183, in main
    keyboardEndpoint: core.Endpoint = keyboard\
                                      ^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/usb/core.py", line 534, in __getitem__
    return Endpoint(
           ^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/usb/core.py", line 347, in __init__
    desc = backend.get_endpoint_descriptor(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.11/site-packages/usb/backend/libusb1.py", line 798, in get_endpoint_descriptor
    ep_desc = i.endpoint[ep]
              ~~~~~~~~~~^^^^
ValueError: NULL pointer access

same output for --info I also tested with my G815 which works without issues.

To me it seems like the G935 connects just like a keyboard since volume up and volume down "keypresses" are correctly being recognized in other software

Event: time 1690496964.584296, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00ea
Event: time 1690496964.584296, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 1
Event: time 1690496964.584296, -------------- SYN_REPORT ------------
Event: time 1690496964.783341, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00ea
Event: time 1690496964.783341, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 0
Event: time 1690496964.783341, -------------- SYN_REPORT ------------
Event: time 1690496965.985354, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9
Event: time 1690496965.985354, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 1
Event: time 1690496965.985354, -------------- SYN_REPORT ------------
Event: time 1690496966.134346, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9
Event: time 1690496966.134346, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 0
Event: time 1690496966.134346, -------------- SYN_REPORT ------------
zocker-160 commented 1 year ago

Is your G935 connected wirelessly?

Getting this to work is going to be tricky. The error you see is because the script tries to find the USB endpoint of the device, which if connected via Bluetooth is not going to exist.

This issue is similar to the G915 (wireless version of G815), because the USB endpoint registered in the system is not actually the one of the keyboard, but it is the one of the USB dongle doing the connection.

Is it possible to connect the headphones via USB cable?

If yes it would be interesting if the USB endpoint can be found correctly or not. If not, then could you give me the dmesg output when connecting your headphones?

You can do it like this:

It should show some output of the headphones registering in the kernel.

In general it is sadly quite tricky to add support for devices "remotely" since so far I have always needed to also reverse engineer the Windows driver in order to get command sequences needed to switch the device into host mode.

coxaka commented 1 year ago

It is connected wireless with a dongle. As far as I know you can only connect USB for charging

dmesg output:

[ 1344.560923] usb 1-5: new full-speed USB device number 9 using xhci_hcd
[ 1344.728220] usb 1-5: New USB device found, idVendor=046d, idProduct=0a87, bcdDevice= 1.12
[ 1344.728233] usb 1-5: New USB device strings: Mfr=3, Product=4, SerialNumber=0
[ 1344.728237] usb 1-5: Product: G935 Gaming Headset
[ 1344.728241] usb 1-5: Manufacturer: Logitech
[ 1345.069799] input: Logitech G935 Gaming Headset Consumer Control as /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:046D:0A87.0009/input/input32
[ 1345.124631] input: Logitech G935 Gaming Headset as /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:046D:0A87.0009/input/input33
[ 1345.124746] input: Logitech G935 Gaming Headset as /devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5:1.3/0003:046D:0A87.0009/input/input35
[ 1345.125116] hid-generic 0003:046D:0A87.0009: input,hiddev96,hidraw0: USB HID v1.11 Device [Logitech G935 Gaming Headset] on usb-0000:00:14.0-5/input3
zocker-160 commented 1 year ago

Thank you for the dmesg, it is sadly the exact same problem / situation as with the G915 (#25).

Connecting to the USB dongle probably fails, because one or more of these parameters at the start of the script are not correct:

usbConfiguration = 0
usbInterface = (1, 0)
usbEndpoint = 0
disableGKeysInterface = 1
usbUseWrite = True

Sadly I cannot tell you which ones are needed for your device, every device is different, it is essentially a guessing game.

Once that works, it should be possible to find the correct HID endpoint and connect to it.

If you are lucky, the headphones will directly send raw data to that endpoint. If not (like it is the case with the G915) then I usually have to send one or more commands to the device to make it send the raw commands. Sadly as I already mentioned above, I had to find those out by reversing the Windows driver as Logitech does not document them publicly.

coxaka commented 1 year ago

I managed to get the USB info by running

import usb.core
print(usb.core.find(idVendor=0x046d, idProduct=0x0a87))
Output ``` DEVICE ID 046d:0a87 on Bus 001 Address 010 ================= bLength : 0x12 (18 bytes) bDescriptorType : 0x1 Device bcdUSB : 0x110 USB 1.1 bDeviceClass : 0x0 Specified at interface bDeviceSubClass : 0x0 bDeviceProtocol : 0x0 bMaxPacketSize0 : 0x40 (64 bytes) idVendor : 0x046d idProduct : 0x0a87 bcdDevice : 0x112 Device 1.12 iManufacturer : 0x3 Logitech iProduct : 0x4 G935 Gaming Headset iSerialNumber : 0x0 bNumConfigurations : 0x1 CONFIGURATION 1: 100 mA ================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x2 Configuration wTotalLength : 0x10d (269 bytes) bNumInterfaces : 0x4 bConfigurationValue : 0x1 iConfiguration : 0x0 bmAttributes : 0x80 Bus Powered bMaxPower : 0x32 (100 mA) INTERFACE 0: Audio ===================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x0 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0x1 Audio bInterfaceSubClass : 0x1 bInterfaceProtocol : 0x0 iInterface : 0x1 G935 Gaming Headset INTERFACE 1: Audio ===================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0x1 Audio bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 INTERFACE 1, 1: Audio ================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x1 bAlternateSetting : 0x1 bNumEndpoints : 0x1 bInterfaceClass : 0x1 Audio bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 ENDPOINT 0x81: Isochronous IN ======================== bLength : 0x9 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x81 IN bmAttributes : 0xd Isochronous wMaxPacketSize : 0x90 (144 bytes) bInterval : 0x1 INTERFACE 2: Audio ===================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x2 bAlternateSetting : 0x0 bNumEndpoints : 0x0 bInterfaceClass : 0x1 Audio bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 INTERFACE 2, 1: Audio ================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x2 bAlternateSetting : 0x1 bNumEndpoints : 0x0 bInterfaceClass : 0x1 Audio bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 INTERFACE 2, 2: Audio ================================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x2 bAlternateSetting : 0x2 bNumEndpoints : 0x1 bInterfaceClass : 0x1 Audio bInterfaceSubClass : 0x2 bInterfaceProtocol : 0x0 iInterface : 0x0 ENDPOINT 0x2: Isochronous OUT ======================== bLength : 0x9 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x2 OUT bmAttributes : 0xd Isochronous wMaxPacketSize : 0x120 (288 bytes) bInterval : 0x1 INTERFACE 3: Human Interface Device ==================== bLength : 0x9 (9 bytes) bDescriptorType : 0x4 Interface bInterfaceNumber : 0x3 bAlternateSetting : 0x0 bNumEndpoints : 0x1 bInterfaceClass : 0x3 Human Interface Device bInterfaceSubClass : 0x0 bInterfaceProtocol : 0x0 iInterface : 0x2 G935 Gaming Headset ENDPOINT 0x83: Interrupt IN ========================== bLength : 0x7 (7 bytes) bDescriptorType : 0x5 Endpoint bEndpointAddress : 0x83 IN bmAttributes : 0x3 Interrupt wMaxPacketSize : 0x20 (32 bytes) bInterval : 0x1 ```

Using interface 3 seems to work

usbConfiguration = 0
usbInterface = (3, 0)
usbEndpoint = 0
disableGKeysInterface = 3
usbUseWrite = True

DEBUG: Searching for keyboard...
DEBUG: Keyboard found! :)
DEBUG: requesting USB endpoint...
DEBUG: HIDraw read endpoint found: /dev/hidraw0
DEBUG: HIDraw disable endpoint found: /dev/hidraw0
DEBUG: HIDraw read endpoint found: /dev/hidraw0
DEBUG: HIDraw disable endpoint found: /dev/hidraw0
[...]
DEBUG: Checking for HID availability...
DEBUG: Connected to /dev/hidraw0
INFO: starting listener...
DEBUG: Using selector: EpollSelector
DEBUG: Connection using HIDAPI...
DEBUG: Sending sequence to disable G keys
0: b'\x11\xff\x10>\x00\x04\x00\x00\x00\x00\x00\x00\xd0\x01d\x07\x00\x00\x00\x00'
1: b'\x11\xff\x08.\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
DEBUG: listening to USB Interface (3, 0) | b'/dev/hidraw0'

Unfortunately only the mute and volume controls seem to be picked up. I tried all known disableGKey commands but they dont seem to change anything


vol up
got data from keyboard: b'\x01\x01\x00\x00\x00'
got data from keyboard: b'\x01\x00\x00\x00\x00'
vol down
got data from keyboard: b'\x01\x02\x00\x00\x00'
got data from keyboard: b'\x01\x00\x00\x00\x00'
mute/unmute
got data from keyboard: b'\x01\x00\x00\x00\x00'

Oddly when toggling the LEDs or changing sidetone settings with other software like HeadsetControl the headset sends something back:

leds off
got data from keyboard: b'\x11\xff\x04<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
leds on
got data from keyboard: b'\x11\xff\x04<\x00\x02\x00\xb6\xff\x0f\xa0\x00d\x00\x00\x00\x00\x00\x00\x00'
sidetone off
got data from keyboard: b'\x11\xff\x07\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
sidetone max
got data from keyboard: b'\x11\xff\x07\x1ad\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

is there a method to finding the correct commands? or just poking around in a debugger?

zocker-160 commented 1 year ago

Oh this is interesting, so Interfaces 0 - 2 are Audio, which makes sense and 3 is a HID device.

Does anything happen when you press the GKeys? In the case of the G915 the GKeys are mapped to F1-Fn by default is that also the case for you?

is there a method to finding the correct commands? or just poking around in a debugger?

Depends on the device. If your headset is supported by Logitech Ghub (not LGS), then my setup was a Windows VM with Logitech Ghub installed in it and Wireshark with the USB plugin (you have to check the USB thingy in the installer).

Then you have to listen on the USB port of the device and launch Ghub.

It will then send a bunch of data back and forth. Most important is the launch sequence and when you press any of the GKeys.

You can copy the bytes sent directly into the debugger script and check if it is working.

EDIT: how does the headset get listed in sudo evtest ? When listening to it, which buttons does it trigger when you press any of the GKeys?

coxaka commented 1 year ago

evtest only triggers when using the volume wheel while newDeviceDebugger additionally shows mic mute events.

/dev/input/event3:      Logitech G935 Gaming Headset Consumer Control
/dev/input/event4:      Logitech G935 Gaming Headset
/dev/input/event5:      Logitech G935 Gaming Headset
3
Event: time 1690760103.022618, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9
Event: time 1690760103.022618, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 1
Event: time 1690760103.022618, -------------- SYN_REPORT ------------
Event: time 1690760103.072615, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00e9
Event: time 1690760103.072615, type 1 (EV_KEY), code 115 (KEY_VOLUMEUP), value 0
Event: time 1690760103.072615, -------------- SYN_REPORT ------------
Event: time 1690760105.924779, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00ea
Event: time 1690760105.924779, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 1
Event: time 1690760105.924779, -------------- SYN_REPORT ------------
Event: time 1690760105.974727, type 4 (EV_MSC), code 4 (MSC_SCAN), value c00ea
Event: time 1690760105.974727, type 1 (EV_KEY), code 114 (KEY_VOLUMEDOWN), value 0

I'll check later if I can see something with wireshark

coxaka commented 1 year ago

Progress :)

Using wireshark I found commands being sent from the host

Traffic ``` b'\x11\xff\x02\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x08\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x08\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x08\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x1a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x2a\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\xca\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\xca\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x08\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x05\x2a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x7a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x8a\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x07\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\xca\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\xca\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x4a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x07\x1a\x46\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x08\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x3a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x3a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x06\x2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x04\x4a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x08\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', b'\x11\xff\x06\x2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', ```

putting these into the newDeviceDebugger actually seems to work and I can see the G buttons being pressed

from my testing only this packet seems to be required:

disableGKeys = [
    b'\x11\xff\x05\x2a\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
]

which leads to these results:

G3 pressed
got data from keyboard: b'\x11\xff\x05\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
unpressed
got data from keyboard: b'\x11\xff\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

G2 pressed/unpressed
got data from keyboard: b'\x11\xff\x05\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
got data from keyboard: b'\x11\xff\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

G1 pressed/unpressed
got data from keyboard: b'\x11\xff\x05\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
got data from keyboard: b'\x11\xff\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

Mute button pressed
got data from keyboard: b'\x08\x01'

flick up microphone (mute)
got data from keyboard: b'\x08\x10'

flick down microphone (unmute)
got data from keyboard: b'\x08 '

lost connection to headset (turned off)
got data from keyboard: b'\x11\xff\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

headset connected
got data from keyboard: b'\x11\xff\x08\x00\x0ec\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
got data from keyboard: b'\x01\x00\x00\x00\x00'
got data from keyboard: b'\x01\x00\x00\x00\x00'
zocker-160 commented 1 year ago

oh nice good job, this is exactly what I need!

Does mute / unmute actually work, as in does it trigger the mute / unmute system wide? If not, this could be added quite easily.

EDIT: does the mute button not send two packages? Usually there is a "pressed" and a "release" package

zocker-160 commented 1 year ago

I have pushed the initial implementation to the G935 branch, could you give it a try and see how far you can get?

coxaka commented 1 year ago

I tested the G935 branch and it works like a charm.

Mute/unmute doesnt work, flicking up the microphone mutes it but there is no way to unmute it after that. The mute button only sends one packet no matter if the microphone is muted or unmuted or if the button is pressed released or held. I think it would be best to make the mute button also configurable since you mainly mute yourself by moving the microphone up.

Also if its not too hard to implement it would be great if the disableGKeys command can be sent everytime the headset connects (in case you turn the headset off or change batteries)

coxaka commented 1 year ago

Another small nitpick: The order of the G buttons does not represent the physical layout, it should be G3, G2, G1, Mute

zocker-160 commented 1 year ago

Mute/unmute doesnt work I think it would be best to make the mute button also configurable since you mainly mute yourself by moving the microphone up.

Sorry this might be a dumb question, but are you talking about the headphone mute or the microphone mute? You make it sound like they are the same thing and both mute the microphone?

flicking up the microphone mutes it but there is no way to unmute it after that.

This seems to be a known issue since forever and it looks like only hacky solutions exist. (see here for reference). My hope is that uinput.KEY_MICMUTE does also unmute it, but it could get really messy as it would just toggle each time and not actually set on or off.

The mute button only sends one packet no matter if the microphone is muted or unmuted or if the button is pressed released or held.

Ok understood not a big issue, but weird given that all their keyboards do it.

Also if its not too hard to implement it would be great if the disableGKeys command can be sent everytime the headset connects (in case you turn the headset off or change batteries)

Sadly tricky to implement in the current codebase as this behavior does not exist with wired keyboard. A quick hack could be doable, but I fear that it might cause issues with existing users, so the proper way would be to implement an alternative mode for headphones (where I then could also treat the mute / unmute separately as currently mute is done by the kernel driver for all supported keyboard.

Another small nitpick: The order of the G buttons does not represent the physical layout, it should be G3, G2, G1, Mute

Do you mean just the order of the buttons in the UI or does G1 in the UI not map to the physical G1 button?

coxaka commented 1 year ago

Sorry this might be a dumb question, but are you talking about the headphone mute or the microphone mute? You make it sound like they are the same thing and both mute the microphone?

They both mute the microphone which is why I suggested making the button configurable.

This seems to be a known issue since forever and it looks like only hacky solutions exist. (see here for reference). My hope is that uinput.KEY_MICMUTE does also unmute it, but it could get really messy as it would just toggle each time and not actually set on or off.

Actually it all works as expected until you disable G keys. And when G keys are disabled and the microphone is stuck you can fix it by muting and unmuting e.g. by sending XF86AudioMicMute twice

Do you mean just the order of the buttons in the UI or does G1 in the UI not map to the physical G1 button?

It is mapped correctly, just the order in the UI is wrong

zocker-160 commented 1 year ago

They both mute the microphone which is why I suggested making the button configurable.

Alright ok now I understand.

And when G keys are disabled and the microphone is stuck you can fix it by muting and unmuting e.g. by sending XF86AudioMicMute twice

Does mute / unmute after G keys disabled work at all? If yes, then that is the kernel driver doing it, which means remapping those buttons is not trivial. if no, then it should be fixable.

It is mapped correctly, just the order in the UI is wrong

Understood, well that is currently hard coded. :V

coxaka commented 1 year ago

Does mute / unmute after G keys disabled work at all? If yes, then that is the kernel driver doing it, which means remapping those buttons is not trivial. if no, then it should be fixable.

with G keys disabled unmute doesnt work at all, mute only works when moving the microphone up, which is probably a firmware thing

zocker-160 commented 1 year ago

ok one last question, does the mute button (the one you would like to remap) do anything after sending disableGKeys?

coxaka commented 1 year ago

no it just sends data but doesnt mute or unmute the microphone got data from keyboard: b'\x08\x01'

zocker-160 commented 1 year ago

Alright understood, I will add the mute button as G4 then so you can remap it. (the names are hard coded for now, renaming them will require implementing a separate mode for that, which I currently don't have the time to do)

EDIT: ah damn I just realized that I cannot do that with the current logic, because there is no releaseEvent, so the moment you press the button it will get registered as you holding down the button all the time.

zocker-160 commented 1 year ago

I pushed version 1.0.5 with initial support. For full support you will have to be a bit patient as I currently don't have the time to do it.

coxaka commented 1 year ago

Awesome. Take your time, the features you added already help a lot, the rest are just nice to haves. Thanks for helping and thanks for writing this software!