Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for BlackWidow V4 Pro #2054

Merged
merged 4 commits into from
Oct 16, 2023
Merged

Conversation

Jacajack
Copy link
Contributor

@Jacajack Jacajack commented Apr 26, 2023

Current status:

  • Reading serial number
  • Brightness control
  • Basic matrix effects (had to use WAVE_DIRS to reverse wave effect direction)
  • Custom matrix effects
  • Gamemode LED control
  • Wheel matrix effect
  • Macro LED control (turns out it works fine when the daemon is active)
  • Command dial bindings (can be handled with an external script, see this comment)
  • M1-M5 macro key support
  • M6-M8 macro key support (side buttons)
  • Basic wheel effect support
  • Volume acts as scroll
  • Entering/exiting gamemode is broken sometimes
  • Onboard macros seem to be broken (mapped macro keys to F13-F20, F24)
  • Update tests etc.

Currently all M1-M5 bindings set in Synapse work on Linux as well, however all non-standard bindings for the command dial are lost. It would be great if we could get the driver to enable them back on Linux. Not sure if this should become a part of this PR, though.

I'm currently investigating why the macro LED doesn't work. I've tweaked razer_attr_write_macro_led_state() so it sends the same commands as Synapse, but with no luck so far. Synapse does it like that (NOSTORE and transaction ID 0x1f seem to be a bit unusual):

This should close #2044.

@z3ntu
Copy link
Member

z3ntu commented Apr 27, 2023

In the packet capture from the linked issue I see class 0x03, cmd 0x00 with GAME_LED and a different request with a previously unused led ID 0x18, worth a shot using that?

There's also plenty of commands we haven't decoded yet so who knows what's hiding there.

driver/razerkbd_driver.h Outdated Show resolved Hide resolved
@Jacajack
Copy link
Contributor Author

In the packet capture from the linked issue I see class 0x03, cmd 0x00 with GAME_LED and a different request with a previously unused led ID 0x18, worth a shot using that?

I will give it a try. I should have some time for experiments next week.

@Jacajack
Copy link
Contributor Author

I've brute forced all LED IDs from 0 to 255. Still no luck with the macro LED. Interestingly though, LED 0x18 seems to be the mute indicator. Enabling it switches off backlight under the mute media key.

@Jacajack
Copy link
Contributor Author

I've added "wheel" effect support on the driver end. Sadly, no progress with the macro LEDs.

@Jacajack
Copy link
Contributor Author

Ah, the macro LED is driving me crazy. Below is a Wireshark dump of Windows taking control over the keyboard and me pressing Fn + Macro two times:

Screenshot_20230530_203413

I've tried sending the command marked with ???, but it didn't seem to have any effect. Now I'm wondering whether the macro LED state could somehow be related to this shorter variant of razer_chroma_extended_matrix_effect_custom_frame() (in violet) - they always seem come together. I've also noticed that sometimes 0x01 is sent as one of the arguments.

I'll keep on searching. Any suggestions and hints are welcome.


This is slightly off-topic I suppose, but I think I managed to learn how Synapse configures key bindings. I'm leaving some info below in case it comes useful anytime in the future.

Key bindings for my macro keys are sent by Synapse in the pink section in the above dump. Each pink command binds one physical key to a USB HID scancode. Setting key action to "default" in Synapse actually causes it to be bound to the "normal" scancode.

// Command: bind key function
number_of_params = 0x0a;
transaction_id = 0x1f;
command_class = 0x02;
command_id = 0x0d;
args[0] = 0x01; // Always 0x01
args[1] = razer_scancode; // See table below
args[2] = 0; // Usually zero?
args[3] = binding_type; // See table below

// For binding_type == 0x02
// Keyboard function (key -> scancode)
args[4] = 0x02; // Always?
args[5] = modifier_bits; // See table below
args[6] = scancode; // USB HID keyboard scancode (see https://gist.github.com/MightyPork/6da26e382a7ad91b5496ee55fdc73db2)
Modifier bitsRazer scancodesBinding types
Modifier bit Modifier
0x01 Left Ctrl
0x02 Left Shift
0x04 Left Alt
0x10 Right Ctrl
0x20 Right Shift
0x40 Right Alt

Modifier bits used when binding keys to scancodes.

Razer scancode Key
0x01 `
0x06 5
0x10 Tab
0x1f A
0x3d Space
0x6e Esc
0x75 F6

I've only checked these. They seem to somewhat correspond to key layout on the keyboard.

ID Binding type
0x00 Disable?
0x01 Mouse function
0x02 Keyboard function
0x03 Macro
0x0a Multimedia
0x0d Keyboard + Turbo

These categories correspond to different "function" tabs in Synapse.

As per the command dial, the main 8 functions are configured with command class/id 0x03/0x12. RGB triplets for each function are sent as a part of the payload. This command doesn't seem to take any custom bindings into account - these are probably just handled by Synapse.

@z3ntu
Copy link
Member

z3ntu commented May 31, 2023

For rebinding see also #2031

@LeoFuso
Copy link

LeoFuso commented Jun 12, 2023

Guys, I don't know if this topic will be addressed, but can we use the Macros available on the Keyboard once this issue is concluded?

I bought this keyboard hoping I could customize Macros to perform scripts or key combinations, etc. I've noticed, at least on Windows, the macro's capabilities are limited.

@z3ntu
Copy link
Member

z3ntu commented Jun 13, 2023

@LeoFuso You should be able to use this for macros (and key remapping) even without openrazer support: https://github.com/sezanzeb/input-remapper

@Jacajack
Copy link
Contributor Author

I've added initial support for "wheel" effect on Python end and it seems to be working nicely, but I'm not sure if I haven't missed something in the code. I haven't updated tests yet, that's for sure. I've reused wave direction state for the wheel effect - is that okay or should I add separate state for wheel effect only?

There are also some annoyances which will require fixing. When the daemon is running, the volume control works as mouse scroll, exiting game mode doesn't seem to be working and effects cannot be changed with Fn+Ctrl+0-9.

@LeoFuso
Copy link

LeoFuso commented Jun 14, 2023

@LeoFuso You should be able to use this for macros (and key remapping) even without openrazer support: https://github.com/sezanzeb/input-remapper

Thanks! I'll give it a try. I'm not sure it will work since the macro keys aren't being tracked by the OS. An issue regarding the problem: https://superuser.com/a/474595

@z3ntu
Copy link
Member

z3ntu commented Jun 15, 2023

Can you please make a video demonstrating what the wheel effect looks like?

@Jacajack
Copy link
Contributor Author

Sure, here's the video: https://youtu.be/T6AblbeCO9A. Razer has one on their YouTube channel too: https://youtu.be/KGURYdPXJe4

@Jacajack
Copy link
Contributor Author

Jacajack commented Jun 18, 2023

I've fixed volume control knob and macro keys in driver mode. Currently, the three additional side buttons are mapped to F18-F20. Pressing the command dial emits a F24 keystroke. When turned, it acts as horizontal scroll. Perhaps this should be remapped to something else?

EDIT: I've just noticed that F18-F24 are already used for brightness control etc.

@Jacajack
Copy link
Contributor Author

@z3ntu I have some questions/thoughts regarding the M6-M8 macro keys. I see that the F20-F24 scancodes are currently used for brightness control, game mode and so on. Do you think we could instead use some more obscure HID scancodes for Razer-specific keyboard functions and reserve F13-F24 keys for macro buttons?

I'm afraid that approach might be slightly flawed, though. It seems that Razer-specific keypresses are not filtered out by the daemon. If some media-key scancodes are allowed to pass thtough, we could end up spawning internet browsers and ejecting CDs while changing the keyboard brightness.

I've been wondering if perhaps python-evdev is the solution here. The daemon could grab all Razer keyboard and mouse devices and replicate the input on virtual devices while filtering unwanted events at the same time. You can find a related code example here. This would also allow replaying macros without dependency on xte. As a bonus, the client library could provide a callback interface for handling (suppressing/emitting) evdev events - that would be really useful for things like the command dial or DIY macros/remapping scripts.

This is of course just an idea. If you think that's a reasonable approach, I'd be willing to work on something like that.

Aside from reasonable bindings for M6-M8 and the command dial, I think I finally managed to get everything working :)

@z3ntu
Copy link
Member

z3ntu commented Jun 21, 2023

The macro buttons (and other special actions) are a long-standing open issue that I'm unsure how to resolve correctly.

See e.g. #579 where our "Brightness down" event (key F20) triggers microphone mute.

Generally I want to avoid any Razer-specific mapping code since there's other great projects and nothing should be Razer specific https://github.com/sezanzeb/input-remapper But of course giving user space some reasonable key codes is a must for that to work properly. And if anyhow possible it should work correctly without anything extra running in user space and filtering some events.

When turned, it acts as horizontal scroll.

I believe we already have some code in the driver that maps this back to the volume wheel, you should be able to find it.

@Jacajack
Copy link
Contributor Author

I've pushed some experimental changes in aa02f04. Chroma control keys are now being reported as KEY_MACRO27-KEY_MACRO30. This allowed me to fit 4 additional BlackWidow V4's macro keys in the F13-F24 range. Theoretically, this should also resolve issues like #579, at least for chroma control keys. What do you think about that?

I believe we already have some code in the driver that maps this back to the volume wheel, you should be able to find it.

I've already fixed the volume knob - the command dial is a different matter. This behavior isn't inherently bad, I was just wondering if maybe there's a better alternative. The scroll events are reported via a separate input device which isn't currently monitored by the daemon. Perhaps it's better to handle that in another PR?

@Jacajack Jacajack marked this pull request as ready for review June 22, 2023 16:47
@Jacajack
Copy link
Contributor Author

If anybody is interested, I made a simple Python script for command dial support (mode switching, dial colors, binding Python code). Luckily, the daemon is not using the mouse evdev interface, so it can be safely grabbed and the horizontal scroll events can be nicely filtered out.

https://gist.github.com/Jacajack/dc40a4a7883149937a1da51c07a9c6c4

@Jacajack
Copy link
Contributor Author

Jacajack commented Jun 30, 2023

Okay, so it appears that the BlackWidow V4 might have a firmware bug. When running the custom effect from the script above, my keyboard occasionally glitches and certain matrix sections flicker with random colors. There are a couple of differences between how Synapse updates the matrix vs how it's done by the Linux driver:

  1. Synapse writes columns 0x00-0x17 (so 24 total for some reason)
  2. Synapse uses 0x4d as packet length, so row_length + 5
  3. Synapse doesn't send the effect_custom_frame every time the matrix is written
  4. Synapse doesn't read responses from the keyboard when sending custom matrix data

I've tried making following changes in the code:

  1. Changing matrix width to 24 (didn't help)
  2. Using row_length + 5 as packet length instead of fixed 0x47 (didn't help)
  3. Cranking up usleep_range() delay up to 5000µs in razer_send_control_msg() (didn't help either)
  4. Eliminating effect_custom_frame packets interleaved with subsequent matrix writes
  5. Not reading responses when writing custom frame data

I've found combination of points 4 and 5 to work. It appears that the keyboard firmware is occasionally confused when it has to send responses while also receiving custom matrix data (?). The nasty hack in razer_get_usb_response() presented below seems to get rid of the problem:

diff --git a/driver/razercommon.c b/driver/razercommon.c
index 587d034..9caa5ab 100644
--- a/driver/razercommon.c
+++ b/driver/razercommon.c
@@ -92,6 +92,11 @@ int razer_get_usb_response(struct usb_device *usb_dev, uint report_index, struct
     retval = razer_send_control_msg(usb_dev, request_report, report_index, wait_min, wait_max);
 
     // Now ask for response
+    len = 90; 
+    
+    if (!(request_report->command_class == 0x0F && request_report->command_id.id == 0x03)
+        && !(request_report->command_class == 0x0F && request_report->command_id.id == 0x02))
+    {
     len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
                           request,         // Request
                           request_type,    // RequestType
@@ -102,6 +107,8 @@ int razer_get_usb_response(struct usb_device *usb_dev, uint report_index, struct
                           USB_CTRL_SET_TIMEOUT);
 
     memcpy(response_report, buf, sizeof(struct razer_report));
+    }
+    
     kfree(buf);
 
     // Error if report is wrong length

I will try to commit a cleaner solution with separate functions for handling BlackWidow's quirks soon.

Jacajack added a commit to Jacajack/openrazer that referenced this pull request Jul 1, 2023
Do not expect responses for `matrix_custom_frame` and `matrix_effect_custom` commands. This is more similar to what Synapse does on Windows and apparently eliminates matrix glitches when continuously updating a custom effect.

See: openrazer#2054 (comment)
@Jacajack
Copy link
Contributor Author

I've updated the tests, please let me know if there's anything else I need to do. I'm aware that the coding style CI is failing, but the formatting script makes a lot of changes in files I didn't touch. I'm guessing it's better to run it after the final review then?

Jacajack added a commit to Jacajack/openrazer that referenced this pull request Aug 13, 2023
Do not expect responses for `matrix_custom_frame` and `matrix_effect_custom` commands. This is more similar to what Synapse does on Windows and apparently eliminates matrix glitches when continuously updating a custom effect.

See: openrazer#2054 (comment)
Jacajack added a commit to Jacajack/openrazer that referenced this pull request Aug 13, 2023
Do not expect responses for `matrix_custom_frame` and `matrix_effect_custom` commands. This is more similar to what Synapse does on Windows and apparently eliminates matrix glitches when continuously updating a custom effect.

See: openrazer#2054 (comment)
@Jacajack
Copy link
Contributor Author

Very weird. My astyle 3.4-1 on Arch Linux doesn't change any files when running ./scripts/format_source.sh . Do you run it the same way?

Okay, the issue was caused by a forgotten .astylerc in my home directory. Maybe there should be a project-wise astyle config file to prevent that kind of thing in the future?

I've managed to unsqash the commit with the workaround and added WHEEL_LEFT and WHEEL_RIGHT constants, swapped brightness up/down event codes and fixed that one include.

@z3ntu
Copy link
Member

z3ntu commented Aug 13, 2023

Maybe there should be a project-wise astyle config file to prevent that kind of thing in the future?

I'd rather adopt clang-format long term really. Just will require reformatting half of the code to have consistent codestyle which is annoying. Astyle is unfortunately not an amazing tool in total, just does very basic format things on the code while ignoring lots others.

Great, I'll take a look at it again!

Jacajack added a commit to Jacajack/openrazer that referenced this pull request Aug 16, 2023
Do not expect responses for `matrix_custom_frame` and `matrix_effect_custom` commands. This is more similar to what Synapse does on Windows and apparently eliminates matrix glitches when continuously updating a custom effect.

See: openrazer#2054 (comment)
Jacajack added a commit to Jacajack/openrazer that referenced this pull request Aug 16, 2023
Do not expect responses for `matrix_custom_frame` and `matrix_effect_custom` commands. This is more similar to what Synapse does on Windows and apparently eliminates matrix glitches when continuously updating a custom effect.

See: openrazer#2054 (comment)
@Jacajack
Copy link
Contributor Author

I pushed and squashed a minor change: poll_rate attribute is now exposed for BlackWidow V4 Pro and uses razer_chroma_misc_get_polling_rate2() to set polling rates up to 8kHz available in Synapse.

Jacajack added a commit to Jacajack/openrazer that referenced this pull request Aug 16, 2023
Do not expect responses for `matrix_custom_frame` and `matrix_effect_custom` commands. This is more similar to what Synapse does on Windows and apparently eliminates matrix glitches when continuously updating a custom effect.

See: openrazer#2054 (comment)
z3ntu pushed a commit to Jacajack/openrazer that referenced this pull request Oct 14, 2023
Do not expect responses for `matrix_custom_frame` and
`matrix_effect_custom` commands. This is more similar to what Synapse
does on Windows and apparently eliminates matrix glitches when
continuously updating a custom effect.

See: openrazer#2054 (comment)
Jacajack and others added 3 commits October 16, 2023 18:57
Driver support will be added in an upcoming commit.
Co-authored-by: Luca Weiss <luca@z3ntu.xyz>
Prepare to have a slighly different implementation for razer_get_report.
z3ntu pushed a commit to Jacajack/openrazer that referenced this pull request Oct 16, 2023
Do not expect responses for `matrix_custom_frame` and
`matrix_effect_custom` commands. This is more similar to what Synapse
does on Windows and apparently eliminates matrix glitches when
continuously updating a custom effect.

See: openrazer#2054 (comment)
@z3ntu z3ntu removed the In Progress label Oct 16, 2023
Do not expect responses for `matrix_custom_frame` and
`matrix_effect_custom` commands. This is more similar to what Synapse
does on Windows and apparently eliminates matrix glitches when
continuously updating a custom effect.

See: openrazer#2054 (comment)
Copy link
Member

@z3ntu z3ntu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked a few things but LGTM now. Thanks a lot for the PR!

@z3ntu z3ntu merged commit 27a29d5 into openrazer:master Oct 16, 2023
2 checks passed
@Agorass
Copy link

Agorass commented Oct 19, 2023

Thank you all so much for your work on this.. this is so awesome. How can i update the driver for the Blackwidow v4 Pro? or when is the new update planed? Tank you all
Greetings

@Jacajack
Copy link
Contributor Author

Thanks, I'm also happy to contribute since I learned a lot while working on that PR. I don't know the official release schedule, but if by any chance you're using an Arch-based distro, the changes are already available as part of the openrazer-meta-git AUR package.

@z3ntu
Copy link
Member

z3ntu commented Oct 20, 2023

I'm planning a new release soon, maybe this weekend or next one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Support for BlackWidow V4 Pro (Wired)
4 participants