Compare commits

...
Author SHA1 Message Date
Adam Honse 1538936758 Initial driver for PawnIO-based Windows controller for Valve Steam Machine 2026-08-29 23:36:39 -05:00
Adam Honse 255cfcf422 Initialize active profile tracking variables and don't try loading active profile if no profile is active 2026-08-29 17:42:33 -05:00
Adam Honse c029bb2b1d Clean up detector entries that no longer exist when running detection 2026-08-29 15:10:23 -05:00
Devin Christensen e958e0132e Fix udev rule generation for Glorious Model O/O-/D Wireless mice 2026-08-29 01:08:50 -05:00
Adam Honse 51daeed585 Clean up REGISTER_DUMMY_DETECTOR lines that are no longer relevant after udev rework 2026-08-29 01:07:33 -05:00
Luca Cesarano 60e4309eec Improve Govee LAN mode support 2026-08-29 00:56:04 -05:00
Adam Honse 31247bacd4 Cleaner fix for plugin null check 2026-08-29 00:39:17 -05:00
Adam Honse 2c23fd6ace Revert "Fix skip_generic_detectors scope and a headless-server plugin-list crash"
This reverts commit d9a726d97f.
2026-08-29 00:34:40 -05:00
Hanjjog-ui Gamyeong 61fcdd1a1c Add legacy probe for Gigabyte GAMING OC RTX 5080 2026-08-28 19:30:31 -05:00
Adam Honse dc0e9b2fd3 SDK6 PROTOCOL CHANGE: Update missing timestamp field to Log Message packet on server side, type is actually 32-bit so update documentation, fix issue where log console was enabled based on local settings rather than remote settings 2026-08-28 19:00:10 -05:00
Adam Honse c90eafbe72 Save default server settings to configuration file if they don't exist already 2026-08-28 12:03:56 -05:00
Daniel Clark b087a65f3c Update Keychron Controller 2026-08-28 00:01:06 -05:00
Venatrix “Joe” Ritz c31c6088ac NZXTHue2Controller: Add friendly zone/LED naming for Kraken coolers and add read retry safeguard 2026-08-27 23:59:56 -05:00
Zoin Zoin b14342d9ee Add proper HiDPI rendering for color controls 2026-08-27 23:58:02 -05:00
Gökhan Jantz 849e725b11 Initial commit for Corsair Ironclaw Wireless SE 2026-08-27 18:19:24 -05:00
Rickey Bartlett b23da372ad AlienwareController: fix stack buffer overflow with >25 zones 2026-08-27 18:18:36 -05:00
Venatrix “Joe” Ritz a96b5e0f1a Add support for Turtle Beach Command Series KP7 keypad 2026-08-27 18:17:26 -05:00
Zoin Zoin 6315c79afa Improve Skydimo SK0L32 serial device support 2026-08-27 18:15:00 -05:00
Adam Honse ee8d24bac6 Rename migrated legacy profile files with .bak extension to prevent them from being re-migrated on every startup 2026-08-27 11:31:51 -05:00
Mathias Grün-Drebes d9a726d97f Fix skip_generic_detectors scope and a headless-server plugin-list crash 2026-08-27 07:41:58 -05:00
Adam Honse 1a55da8ac4 Clean up dead code in OpenRGBDevicePage 2026-08-27 00:06:47 -05:00
Adam Honse 5c8baf47f8 Add missing condition in per-zone mode sanity check to handle active mode -1 (follow device mode) 2026-08-26 20:16:33 -05:00
Adam Honse 249c22082d Fix multi-line comment warning in RGBController_AcerNitroHidLed.cpp 2026-08-26 19:25:28 -05:00
Adam Honse 02237aeb4d Fix warning in main_FreeBSD_Linux_MacOS.cpp 2026-08-26 19:18:09 -05:00
Adam Honse 5d7090b5fd Fix warnings in DetectionManager.cpp 2026-08-26 19:17:26 -05:00
Adam Honse f70c3bf8d4 Fix warning in SteelSeriesRival5Controller.cpp 2026-08-26 19:16:18 -05:00
Adam Honse dc0d2e2d2f Fix warnings in HIDLampArrayController.cpp 2026-08-26 19:15:11 -05:00
Adam Honse fa91a11964 Fix multi-line comment warning in RGBController_AcerNitroHidKeyboard.cpp 2026-08-26 19:12:55 -05:00
Adam Honse ecf0bfc847 Update MacOS and Linux AutoStart implementations to properly escape special characters in paths 2026-08-26 18:48:46 -05:00
Adam Honse 41b7087e20 Update Windows AutoStart implementation to allow non-ASCII paths 2026-08-26 18:48:46 -05:00
Alexander Skakov 046a1bae65 Add MSI RTX 4090 Suprim X Classic support 2026-08-26 18:46:36 -05:00
Adam Honse a9a1856b9c Prevent asynchronous mode update issues when setting mode 2026-08-26 16:42:27 -05:00
Adam Honse d7f452e542 Fix UI issue related to REQUIRES_ENTIRE_DEVICE flag when building per-zone modes list 2026-08-26 12:04:10 -05:00
MX1D 799113942c Add full support for Lenovo Legion K500 2026-08-26 00:00:06 -05:00
Aidan Stewart 206ef9aca5 Add support for MSI Raider 18 HX AI A2XWIG laptop 2026-08-25 23:55:29 -05:00
Jason Greathouse 603714f749 Enable Corsair header on MSI 7D70 (MPG X670E Carbon WIFI) 2026-08-25 22:21:09 -05:00
Adam Honse 49e1687141 Adjust button position in MSI 2026-08-25 18:55:30 -05:00
Adam Honse 6d07573fff Update UdevRules.md 2026-08-25 18:24:18 -05:00
JAO1988 2a0222bde1 Added AORUS 2080TI 11G 2026-08-25 18:10:22 -05:00
Jefte Puente 725d0ec1f5 Corsair M75 Wireless: add device support 2026-08-25 18:09:58 -05:00
Adam Honse f14b6cb49d Adjust spacing on installer 2026-08-25 18:08:47 -05:00
Adam Honse 2b60e9ac37 Make system service the default install on Windows 2026-08-25 17:03:53 -05:00
Jefte Puente 693332ff50 Fix SaveProfile carrying forward the wrong controller 2026-08-25 12:07:56 -05:00
Adam Honse a678f3bb25 Ignore files that are not shared libraries when scanning for plugins 2026-08-25 11:11:45 -05:00
Guilherme Santiago b80ac45d99 Kingston Fury DDR5: accept modules with unreadable signature (#4981) 2026-08-25 08:59:59 -05:00
Devar 20a8bc611b Add ASUS ROG ASTRAL RTX 5090 BTF GPU variant (SPID 0x8A5A) 2026-08-24 23:49:08 -05:00
Soldier Alexander 77a474b993 Fix MSI 761 direct mode bounds check comparing a byte offset against an LED count 2026-08-24 20:39:40 -05:00
Adam Honse 853074d80c Update metadata with 1.0rc3 Hotfix 1 2026-08-24 20:32:34 -05:00
Adam Honse 5df989c7a0 Update udev dialog message and update translations 2026-08-24 20:27:45 -05:00
Adam Honse f3b9f1c3fd Add --print-udev-rules for printing rules to stdout 2026-08-24 18:51:10 -05:00
Adam Honse 061bae9546 Remove udev rules and readme from AppImage CI 2026-08-24 18:09:28 -05:00
Adam Honse 679635afd9 Remove udev references in AppImage and artifacts scripts 2026-08-24 11:15:34 -05:00
Adam Honse 7854c491f7 Remove udev rules from the build process now that the rules are generated dynamically from the executable 2026-08-24 11:01:35 -05:00
Adam Honse 9695f9d00b Update upstream CI rules to run pipelines for tagged commits 2026-08-23 15:42:34 -05:00
Merih Bulut b26df0f67e Add support for Corsair K70 RGB PRO Optomechanical (1B1C:1BC6) 2026-08-23 12:57:48 -05:00
Adam Honse 88fa92fd8d Update Fedora packaging to use openrgb binary's generated udev rules in place of the build udev rules from build-udev-rules.sh 2026-08-23 01:24:28 -05:00
Adam Honse 430501408b Update Debian packaging to use openrgb binary's generated udev rules in place of the built udev rules from build-udev-rules.sh 2026-08-23 01:19:02 -05:00
Adam Honse 19d3f8884e Don't detect devices before and exit immediately after generating udev rules 2026-08-23 00:40:39 -05:00
Thomas Xu 3b4a66096a Added Gigabyte GeForce RTX 4060 Ti AERO OC 16G GPU 2026-08-22 12:17:49 -05:00
Raman b93fe2a058 Add Colorful iGame RTX 3060 Ultra W OC 12G 2503:1501 detector 2026-08-21 14:01:35 -05:00
Diego Ortiz 7332c6a7ea Add Gigabyte Z390 DESIGNARE-CF Ambient LED support 2026-08-21 12:50:00 -05:00
Adam Honse d91dae8f15 Update to Qt6 dependency as removing it broke build 2026-08-20 23:00:09 -05:00
Junguo Song 02979dc209 Initial commit for ZOTAC GAMING GeForce RTX 5090 D SOLID OC 2026-08-20 22:37:03 -05:00
Adam Honse c1cbbfc207 Remove outdated Qt dependency in Fedora build 2026-08-20 22:33:52 -05:00
Wiktor Max 2631b5c0b2 Add Gigabyte RX 9070 GAMING OC detection (at 0x75) 2026-08-20 22:31:59 -05:00
Adam Honse 5795280b49 Use Trixie for AppImage and Supported Devices CI targets, update Fedora target to 44 and update naming convention to match Debian targets 2026-08-20 11:43:39 -05:00
Adam Honse 2b834c9ee4 Put OpenRGB version and git commit in udev rules header 2026-08-20 11:32:43 -05:00
Adam Honse 444a748411 More updates to match the behavior of the build-udev-rules.sh script 2026-08-20 10:38:57 -05:00
Adam Honse 58238c048b Add custom udev rules everywhere a dummy detector was used 2026-08-20 10:38:57 -05:00
Adam Honse c5befc354b Add framework for registering custom udev rules 2026-08-20 10:38:57 -05:00
Adam Honse 33854f8886 Build udev from DetectionManager 2026-08-20 10:37:46 -05:00
Adam Honse 8121ee29f4 Clean up the CLI code 2026-08-19 23:53:28 -05:00
Richard Harris 15b784f6c6 Fix startup crash and other issues in VialRGB controller 2026-08-19 22:42:22 -05:00
Ken Sanislo 2df162408e Logitech HID++ 2.0: detect and drive devices over Bluetooth 2026-08-19 22:38:14 -05:00
Ken Sanislo 10d06298ce Logitech HID++ 2.0: read the whole Centurion feature set 2026-08-19 22:35:19 -05:00
QuickMythril eebe4dd0dd Initial commit for EVGA X12 Gaming Mouse 2026-08-19 13:43:54 -05:00
Adam Honse 0459df64c1 Add missing display name fields in SDK protocol documentation 2026-08-19 12:21:28 -05:00
Adam Honse b635f0c2fd Block signals when updating the mode colors spin box in UpdateLEDList 2026-08-18 22:36:00 -05:00
Ryan Black 770e40596e Corsair Strafe MK.2: add PID 0x1B48 to K70 MK2 group (fixes 4-year unresponsive-keyboard bug) 2026-08-18 22:23:24 -05:00
Adrian Tworzydlo 2e990ba3ce Add PowerColor Red Devil RX 7900 XTX support (V2 driver) 2026-08-18 22:22:27 -05:00
Ken Sanislo ea5d7c6c4c Logitech HID++ 2.0: read the power source on the device's broadcast 2026-08-18 22:09:52 -05:00
Ken Sanislo 779514a6fc Fix Logitech HID++ 2.0: key both collections of one Windows interface together 2026-08-18 22:08:17 -05:00
smbd f027b7a312 Add Palit RTX 3090 Ti GameRock support 2026-08-18 19:10:51 -05:00
Ken Sanislo da31501087 Fix LogitechHIDPP20Controller probe negative cache 2026-08-18 19:10:18 -05:00
Ken Sanislo 140aa96aff Fix/macos hid open nonexclusive 2026-08-18 19:01:53 -05:00
Adam Honse 671f0a66f5 Exit after listing profiles 2026-08-18 18:46:00 -05:00
Adam Honse 5b1e782b9b Update CLI description to match about in UI 2026-08-18 18:35:30 -05:00
Adam Honse b222dfeceb Clean up help text some more 2026-08-18 18:30:22 -05:00
Adam Honse 5db5678c1d Add -lp/--list-profiles command line options, clean up help text, and clear active profile on CLI device changes 2026-08-18 18:22:43 -05:00
Adam Honse 433cbc1837 Rework -l/--list-devices to just print a simple list, add -ld/--list-detailed for the full detailed list 2026-08-18 17:37:47 -05:00
Adam Honse bf99c32e72 Remove warning that triggered during normal operation 2026-08-18 17:25:52 -05:00
Adam Honse c2ec44c0b7 Ignore empty matrix maps when getting zone/segment descriptions 2026-08-18 11:01:56 -05:00
Adam Honse 550fa1046e Fix logic around denying setting or modifying local settings from the server 2026-08-17 19:37:55 -05:00
Adam Honse cf910d2616 Implement profile loading on service shutdown 2026-08-17 19:36:05 -05:00
Adam Honse 2d32510008 Create Startup directory if it doesn't exist on Windows 2026-08-17 16:47:33 -05:00
RomanG1337 4d8fd55206 Add support for GameSir Nova 2 Lite controller 2026-08-17 11:38:57 -05:00
Ken Sanislo c852af2a2c Logitech HID++ 2.0: VID-generic detection, protocol fixes and device support 2026-08-16 23:27:46 -05:00
Daniel Clark ae22e1e8ea Add Asus PG32UCDMR 2026-08-16 23:20:45 -05:00
Adam Honse 02620313f6 Adjust DetectionManager to allow specific VID, any PID detectors but still separate generic detectors into their own category 2026-08-16 19:34:42 -05:00
Adam Honse bbccdc2de0 Fix typo in Windows startup file 2026-08-16 18:43:21 -05:00
Adam Honse bc54e18e48 Clean up Creative Sound Blaster controllers 2026-08-16 18:41:23 -05:00
Adam Honse 8e4859688d Make zones in DDP, E1.31, and Serial LED strip manually configurable except for size, as this is defined in the manual configuration 2026-08-16 18:36:41 -05:00
Adam Honse 967bb51313 More settings schema filter fixes, allow registering a schema key that ignores filtering as Detectors needs this 2026-08-16 18:05:08 -05:00
Adam Honse 51d46849fb Pass from_server flags down from JsonString functions into Set/ModifySettings 2026-08-16 17:36:34 -05:00
Adam Honse 74bb119a05 Add an option to automatically load a profile on background service startup 2026-08-16 17:33:55 -05:00
Daniel Clark ae038bc8e9 Update DetectionManger to handle generic wildcards in safe mode. 2026-08-16 16:33:11 -05:00
Adam Honse 433788cc49 Add PNY RTX 5070Ti Epic-X ARGB non-OC 2026-08-16 14:42:37 -05:00
Buu342 5e6d627f51 Fix for LEDs without an assigned key not being properly represented in QMK Firmware 2026-08-15 19:51:28 -05:00
Adam Honse f9897ef99a Implement settings schema filtering
* Filter settings that have a registered schema so that only keys matching the schema get saved
  * Allow settings that do not have a registered schema (manually added devices, device-specific, plugins, client)
  * Update schema registration to allow marking a settings group as local only, which means it modifies the local instance's settings, not the remote
  * Deny setting local only settings when the update comes from the network server
2026-08-15 17:41:29 -05:00
Adam Honse 5c1a2c4d13 Attempt to build against mbedtls3 path by default and fall back to mbedtls path if it doesn't exist, fixes build on distros that have moved mbedtls 3.x to the /usr/include/mbedtls3 path 2026-08-14 11:33:40 -05:00
John Monteiro f987bc3199 Add support for Gigabyte B360 AORUS GAMING 3 WIFI-CF 2026-08-14 01:02:04 -05:00
Irturijus 0c1a73accc Add ASUS ROG Strix G18 G814JIR support 2026-08-12 18:23:40 -05:00
Adam Honse 1fb75b66dd Limit maximum SDK packet size to 8MB 2026-08-12 18:17:51 -05:00
Adam Honse 790e1485f6 Remove minimum width check when determining compact tab mode as it doesn't handle scaling above 100% properly and the manual configuration exists now 2026-08-11 20:00:22 -05:00
Adam Honse 400faabb21 Improve scroll wheel behavior in Plugins settings page 2026-08-11 19:58:57 -05:00
Rogue Turtle 684b74ca9e Added support for 75% Sinowealth10c-based keyboards with indices bigger than the keyboard size 2026-08-10 12:31:02 -05:00
Tony McDowell 6069a3c0cb RazerController: update HID detection for Razer Blackwidow V4 standard. 2026-08-10 12:16:03 -05:00
Adam Honse 606f5f6c86 Updates Flapak plugin support and building Flatpak in GitLab CI 2026-08-09 16:13:10 -05:00
Adam Honse bfccc1a95d Check /run/host paths when looking for udev rules, as this is the only way to mount these host-side paths on Flatpak 2026-08-08 15:45:39 -05:00
Chalenged e33a56001a Fix TUF Gaming K3 GEN II Miku Edition layout 2026-08-07 15:17:07 -05:00
Titan 0afc4c752f Skyloong GK68HE Pro Support 2026-08-07 11:27:18 -05:00
Adam Honse 834fc6a8f7 Use device type to set zone name in HID LampArray controller 2026-08-07 11:17:36 -05:00
Adam Honse da824ccfa8 Update hidapi-hotplug Windows dependencies to hidapi-hotplug-0.15.0 tag 2026-08-06 23:17:43 -05:00
Adam Honse 2c397c5110 Call DeviceUpdateLEDs from Zone/Single functions 2026-08-06 22:00:22 -05:00
Jannik Vogel 4a4f04825c Fix crash due to bad lamp count in DeviceUpdateLEDs 2026-08-06 21:59:36 -05:00
Adam Honse 2ac41813fa Add autonomous mode as a selectable mode 2026-08-06 21:57:25 -05:00
saad-script 422414737b rework report id parsing to be more consistent 2026-08-06 21:57:25 -05:00
Adam Honse d45d9a31be Units are in micrometers not millimeters 2026-08-06 21:57:25 -05:00
Adam Honse 5f297a62ba Get vendor and device names from HID descriptors 2026-08-06 21:57:25 -05:00
Adam Honse 7605c14d89 Switch to PU ONLY detector 2026-08-06 21:57:25 -05:00
Adam Honse bad23f7574 Use HID serial number 2026-08-06 21:57:25 -05:00
Adam Honse ee4886512b Determine device type from LampArray kind 2026-08-06 21:57:25 -05:00
Werner Sembach 8a87befeda Dynamically parse report IDs 2026-08-06 21:57:25 -05:00
Werner Sembach 44b37c57c1 Prepare LampArray report IDs being parsed dynamically 2026-08-06 21:57:25 -05:00
Werner Sembach 0b59ccfb42 Properly setup key names 2026-08-06 21:57:25 -05:00
Werner Sembach 3c8f05982e Automatically create matrix 2026-08-06 21:57:25 -05:00
Werner Sembach a7a6b241e0 Add meta information for udev rule to be generated automatically 2026-08-06 21:57:25 -05:00
Adam Honse d6de563178 Rework to use only a single hid_device and DetectionManager API 2026-08-06 21:57:25 -05:00
Adam Honse ee62b14384 Multi update packet working for proof of concept direct mode 2026-08-06 21:57:25 -05:00
Adam Honse 712df22b95 Implement getting lamp attributes for each lamp and disabling autonomous mode, work on multi update 2026-08-06 21:57:25 -05:00
Adam Honse a0d063e78f Begin implementing the HID LampArray protocol for Arduino test device 2026-08-06 21:57:25 -05:00
Adam Honse 5a2712750b Initial commit for HID LampArray Controller 2026-08-06 21:57:25 -05:00
Adam Honse 320f755e5e Update super_io_pawnio.cpp to add logging and update ioctls 2026-08-06 20:47:05 -05:00
Adam Honse f1d4a7c045 Add logging to MSI-RGB motherboard detection 2026-08-06 19:38:48 -05:00
Adam Honse 710f97bb62 Fix LpcIO.bin name in superio_pawnio so that Super IO access initializes in Windows 2026-08-06 18:51:14 -05:00
Adam Honse 454344185c MSI Motherboard Cleanup - Rename Mystic Light to Motherboard, move MSI Mystic Light 64 to keyboard as it is a keyboard, do some code cleanup 2026-08-06 17:20:17 -05:00
Kyle Finter b25250db7b New Keyboard layout for Corsair K70 LUX RGB 2026-08-06 08:35:47 -05:00
Yousif Ragab 009156994e Add support for Gigabyte AORUS RX 6900 XT MASTER rev 2.0 2026-08-06 08:31:13 -05:00
Aiden Corbin 6f21dd884c Add GALAX GeForce RTX 3070 1-Click OC 2026-08-06 07:18:49 -05:00
Adam Honse 5dfa33320e Split detector file for Asus Aura Core 2026-08-06 00:05:10 -05:00
Adam Honse 2147291c52 Split detector file for Alienware monitors and organize into folders 2026-08-06 00:01:52 -05:00
Rui Guilherme e971c619b1 Add support for Redragon M711-FPS-1 Cobra FPS 2026-08-05 20:32:02 -03:00
LittleQuartZ 6e832b337f Add PowerColor Red Devil RX 6700 XT support 2026-08-05 20:02:48 +07:00
Raulkong898 6ec5a955df Add Keychron J2 HE 8K support to QMKKeychronController 2026-08-05 01:59:28 -05:00
Adam Honse 71cd411ffc Fix active profile initialization during initial local client connection as well as local client reconnections 2026-08-05 01:20:06 -05:00
Adam Honse 1be9097852 Do not reinitialize client flags upon disconnect, this prevented local client from being re-requested upon local server restart 2026-08-05 00:25:38 -05:00
Adam Honse a8a848a259 More local client cleanup in the UI - don't show the save or rescan buttons for local client 2026-08-05 00:02:27 -05:00
Ken Sanislo 15d008a169 OpenRGBClientInfoPage: disable the disconnect button for the local client
Commit amended to adjust comment and tooltip by Adam Honse <[email protected]>
2026-08-04 23:40:41 -05:00
Adam Honse 2e09228568 SDK6 PROTOCOL CHANGE: Add client and server hostname set packets 2026-08-04 11:52:54 -05:00
274 changed files with 29963 additions and 23035 deletions
+55 -19
View File
@@ -14,9 +14,9 @@
# run only if manually started to save CI minutes if #
# GitLab hosted runners #
# * For commits to the CalcProgrammer1/OpenRGB repository, #
# automatically run all jobs on the default branch, #
# otherwise run them if the source is part of a merge #
# request #
# automatically run all jobs on the default branch or #
# tag builds, otherwise run them if the source is part #
# of a merge request #
#-----------------------------------------------------------#
.downstream_rules:
rules:
@@ -26,7 +26,7 @@
.upstream_rules:
rules:
- if: '$CI_PROJECT_PATH == "CalcProgrammer1/OpenRGB" && ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_PIPELINE_SOURCE == "merge_request_event")'
- if: '$CI_PROJECT_PATH == "CalcProgrammer1/OpenRGB" && ($CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH || $CI_COMMIT_TAG || $CI_PIPELINE_SOURCE == "merge_request_event")'
when: on_success
- !reference [.downstream_rules, rules]
@@ -51,7 +51,7 @@ before_script:
# Supported Devices Build Target #
#-----------------------------------------------------------#
"Supported Devices":
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:bookworm-amd64
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:trixie-amd64
tags:
- linux
- amd64
@@ -71,10 +71,10 @@ before_script:
- !reference [.upstream_rules, rules]
#-----------------------------------------------------------#
# OpenRGB Common Appimage Build Steps #
# OpenRGB Common AppImage Build Steps #
#-----------------------------------------------------------#
.hidden_appimage_script: &appimage_script_steps
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:bookworm-${TGT_ARCH}
image: registry.gitlab.com/openrgbdevelopers/openrgb-linux-ci-deb-builder:trixie-${TGT_ARCH}
tags:
- linux
- ${TGT_ARCH}
@@ -87,8 +87,6 @@ before_script:
name: "${CI_PROJECT_NAME}_Linux_${TGT_NAME}_${CI_COMMIT_SHORT_SHA}"
paths:
- OpenRGB-${TGT_PATH}.AppImage
- 60-openrgb.rules
- README.md
expire_in: 30 days
rules:
@@ -290,13 +288,13 @@ before_script:
<<: *debian_script_steps
#-----------------------------------------------------------#
# Linux (.rpm, F43) 64-bit Build Target #
# Linux (.rpm) Fedora 44 amd64 Build Target #
#-----------------------------------------------------------#
"Linux 64 F43 rpm":
image: fedora:43
"Linux amd64 .rpm (Fedora 44)":
image: fedora:44
stage: build
script:
- dnf install rpmdevtools dnf-plugins-core libcurl-devel qt5-qtbase-devel git wget -y
- dnf install rpmdevtools dnf-plugins-core libcurl-devel qt6-qtbase-devel git wget -y
- 'wget -O hidapi-hotplug.zip https://gitlab.com/OpenRGBDevelopers/hidapi-hotplug/-/jobs/artifacts/master/download?job=Linux+64+F43+rpm'
- unzip hidapi-hotplug.zip
- dnf install ./*.rpm -y
@@ -312,7 +310,7 @@ before_script:
- cd ${CI_PROJECT_DIR}
artifacts:
name: "${CI_PROJECT_NAME}_Linux_64_rpm_${CI_COMMIT_SHORT_SHA}"
name: "${CI_PROJECT_NAME}_Linux_amd64_rpm_${CI_COMMIT_SHORT_SHA}"
paths:
- openrgb*.rpm
expire_in: 30 days
@@ -320,6 +318,44 @@ before_script:
rules:
- !reference [.upstream_rules, rules]
#-----------------------------------------------------------#
# OpenRGB Common Flatpak Build Steps #
#-----------------------------------------------------------#
.hidden_flatpak_script: &flatpak_script_steps
image: ghcr.io/flathub-infra/flatpak-github-actions:kde-6.10
stage: build
tags:
- linux
- ${TGT_ARCH}
script:
- flatpak-builder --user --disable-rofiles-fuse --repo=build/repo build/flatpak-build flatpak/org.openrgb.OpenRGB.yaml
- flatpak build-bundle build/repo org.openrgb.OpenRGB.flatpak org.openrgb.OpenRGB
artifacts:
name: "${CI_PROJECT_NAME}_Linux_${TGT_ARCH}_Flatpak_${CI_COMMIT_SHORT_SHA}"
paths:
- org.openrgb.OpenRGB.flatpak
expire_in: 30 days
rules:
- !reference [.upstream_rules, rules]
#-----------------------------------------------------------#
# Linux Flatpak amd64 Build Target #
#-----------------------------------------------------------#
"Linux amd64 Flatpak":
variables:
TGT_ARCH: "amd64"
<<: *flatpak_script_steps
#-----------------------------------------------------------#
# Linux Flatpak arm64 Build Target #
#-----------------------------------------------------------#
"Linux arm64 Flatpak":
variables:
TGT_ARCH: "arm64"
<<: *flatpak_script_steps
#-----------------------------------------------------------#
# Debian i386 Bookworm test #
#-----------------------------------------------------------#
@@ -387,10 +423,10 @@ before_script:
- !reference [.upstream_rules, rules]
#-----------------------------------------------------------#
# Fedora 64 v43 test #
# Fedora amd64 44 test #
#-----------------------------------------------------------#
"Fedora 64 v43":
image: fedora:43
"Fedora 64 44":
image: fedora:44
stage: test
script:
- dnf install unzip wget -y
@@ -401,9 +437,9 @@ before_script:
- openrgb --version
- dnf5 -y remove openrgb
dependencies:
- "Linux 64 F43 rpm"
- "Linux amd64 .rpm (Fedora 44)"
needs:
- "Linux 64 F43 rpm"
- "Linux amd64 .rpm (Fedora 44)"
rules:
- !reference [.upstream_rules, rules]
+66 -2
View File
@@ -149,6 +149,64 @@ std::string AutoStart::GetExePath()
| Private Methods |
\*---------------------------------------------------------*/
/*---------------------------------------------------------*\
| Escape a single argument for use in a .desktop Exec= |
| field, per the Desktop Entry Specification. |
| |
| Reserved characters must be escaped by wrapping the whole |
| argument in double quotes and backslash-escaping the |
| quote/backquote/backslash/dollar characters, and any |
| literal '%' must be doubled to '%%'. |
\*---------------------------------------------------------*/
static std::string DesktopExecEscape(const std::string& arg)
{
static const std::string reserved = " \t\n\"'`\\><~|&;$*?#()%";
bool needs_quotes = false;
for(char c : arg)
{
if(reserved.find(c) != std::string::npos)
{
needs_quotes = true;
break;
}
}
std::string escaped;
if(needs_quotes)
{
escaped += '"';
}
for(char c : arg)
{
switch(c)
{
case '"':
case '`':
case '\\':
case '$':
escaped += '\\';
escaped += c;
break;
case '%':
escaped += "%%";
break;
default:
escaped += c;
break;
}
}
if(needs_quotes)
{
escaped += '"';
}
return(escaped);
}
std::string AutoStart::GenerateDesktopFile(AutoStartInfo autostart_info)
{
/*-----------------------------------------------------*\
@@ -169,11 +227,17 @@ std::string AutoStart::GenerateDesktopFile(AutoStartInfo autostart_info)
/*-----------------------------------------------------*\
| Add the executable path and arguments |
\*-----------------------------------------------------*/
fileContents << "Exec=" << autostart_info.path;
fileContents << "Exec=" << DesktopExecEscape(autostart_info.path);
if (autostart_info.args != "")
{
fileContents << " " << autostart_info.args;
std::istringstream arg_parser(autostart_info.args);
std::string arg;
while(arg_parser >> arg)
{
fileContents << " " << DesktopExecEscape(arg);
}
}
fileContents << std::endl;
+41 -2
View File
@@ -137,6 +137,43 @@ std::string AutoStart::GetExePath()
| Private Methods |
\*---------------------------------------------------------*/
/*---------------------------------------------------------*\
| Escape a string for embedding inside an XML element |
| (used by the .plist generator) to avoid producing |
| malformed property list files. |
\*---------------------------------------------------------*/
static std::string XmlEscape(const std::string& input)
{
std::string escaped;
for(char c : input)
{
switch(c)
{
case '&':
escaped += "&amp;";
break;
case '<':
escaped += "&lt;";
break;
case '>':
escaped += "&gt;";
break;
case '"':
escaped += "&quot;";
break;
case '\'':
escaped += "&apos;";
break;
default:
escaped += c;
break;
}
}
return(escaped);
}
std::string AutoStart::GenerateLaunchAgentFile(AutoStartInfo autostart_info)
{
/*-----------------------------------------------------*\
@@ -153,7 +190,8 @@ std::string AutoStart::GenerateLaunchAgentFile(AutoStartInfo autostart_info)
fileContents << " <string>org.openrgb</string>" << std::endl;
fileContents << " <key>ProgramArguments</key>" << std::endl;
fileContents << " <array>" << std::endl;
fileContents << " <string>" << autostart_info.path << "</string>" << std::endl;
fileContents << " <string>" << XmlEscape(autostart_info.path) << "</string>"
<< std::endl;
if(autostart_info.args != "")
{
@@ -162,7 +200,8 @@ std::string AutoStart::GenerateLaunchAgentFile(AutoStartInfo autostart_info)
while(arg_parser >> arg)
{
fileContents << " <string>" << arg << "</string>" << std::endl;
fileContents << " <string>" << XmlEscape(arg) << "</string>"
<< std::endl;
}
}
+34 -32
View File
@@ -12,6 +12,7 @@
#include <shlobj.h>
#include "AutoStart-Windows.h"
#include "LogManager.h"
#include "StringUtils.h"
#include "filesystem.h"
#include "windows.h"
@@ -71,11 +72,11 @@ bool AutoStart::EnableAutoStart(AutoStartInfo autostart_info)
HRESULT result;
IShellLinkW* shellLink = NULL;
std::wstring exepathw = utf8_decode(autostart_info.path);
std::wstring argumentsw = utf8_decode(autostart_info.args);
std::wstring startupfilepathw = utf8_decode(autostart_file);
std::wstring descriptionw = utf8_decode(autostart_info.desc);
std::wstring iconw = utf8_decode(autostart_info.path);
std::wstring exepathw = StringUtils::string_to_wstring(autostart_info.path);
std::wstring argumentsw = StringUtils::string_to_wstring(autostart_info.args);
std::wstring startupfilepathw = StringUtils::string_to_wstring(autostart_file);
std::wstring descriptionw = StringUtils::string_to_wstring(autostart_info.desc);
std::wstring iconw = StringUtils::string_to_wstring(autostart_info.path);
result = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_ALL, IID_IShellLinkW, (void**)&shellLink);
@@ -150,11 +151,16 @@ std::string AutoStart::GetExePath()
/*-----------------------------------------------------*\
| Create the OpenRGB executable path |
\*-----------------------------------------------------*/
char exepath[MAX_PATH] = "";
wchar_t exepath[MAX_PATH] = L"";
DWORD count = GetModuleFileNameA(NULL, exepath, MAX_PATH);
DWORD count = GetModuleFileNameW(NULL, exepath, MAX_PATH);
return(std::string(exepath, (count > 0) ? count : 0));
if(count == 0)
{
return(std::string());
}
return(StringUtils::wstring_to_string(std::wstring(exepath, count)));
}
/*---------------------------------------------------------*\
@@ -164,43 +170,39 @@ std::string AutoStart::GetExePath()
void AutoStart::InitAutoStart(std::string name)
{
char startMenuPath[MAX_PATH];
wchar_t startMenuPath[MAX_PATH];
autostart_name = name;
/*-----------------------------------------------------*\
| Get startup applications path |
\*-----------------------------------------------------*/
HRESULT result = SHGetFolderPathA(NULL, CSIDL_PROGRAMS, NULL, 0, startMenuPath);
HRESULT result = SHGetFolderPathW(NULL, CSIDL_PROGRAMS, NULL, 0, startMenuPath);
if(SUCCEEDED(result))
{
autostart_file = std::string(startMenuPath);
std::string autostart_dir = StringUtils::wstring_to_string(startMenuPath);
autostart_dir += "\\Startup\\";
autostart_file += "\\Startup\\" + autostart_name + ".lnk";
/*-------------------------------------------------*\
| Create the directory if it doesn't exist |
\*-------------------------------------------------*/
std::error_code ec;
bool success = true;
if(!filesystem::exists(autostart_dir))
{
success = filesystem::create_directories(autostart_dir, ec);
}
if(success)
{
autostart_file = autostart_dir + autostart_name + ".lnk";
}
}
else
{
autostart_file.clear();
}
}
/*---------------------------------------------------------*\
| Convert an UTF8 string to a wide Unicode String |
| (from wmi.cpp) |
\*---------------------------------------------------------*/
std::wstring AutoStart::utf8_decode(const std::string& str)
{
if(str.empty())
{
return std::wstring();
}
int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int) str.size(), nullptr, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, &str[0], (int) str.size(), &wstrTo[0], size_needed);
return(wstrTo);
}
-1
View File
@@ -24,5 +24,4 @@ public:
private:
void InitAutoStart(std::string name);
std::wstring utf8_decode(const std::string& str);
};
@@ -11,16 +11,16 @@
#include "RGBController_AcerNitroHidKeyboard.h"
// /**------------------------------------------------------------------*\
// @name Acer Nitro HID Keyboard
// @category Laptop
// @type HID
// @save :x:
// @direct :white_check_mark:
// @effects :white_check_mark:
// @detectors DetectAcerHIDControllers
// @comment
// \*-------------------------------------------------------------------*/
/**------------------------------------------------------------------*\
@name Acer Nitro HID Keyboard
@category Laptop
@type HID
@save :x:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectAcerHIDControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_AcerNitroHidKeyboard::RGBController_AcerNitroHidKeyboard(std::shared_ptr<AcerNitroHidKeyboardController> controller)
{
@@ -72,7 +72,7 @@ RGBController_AcerNitroHidKeyboard::RGBController_AcerNitroHidKeyboard(std::shar
Breathing.speed_min = 1;
Breathing.speed_max = 9;
Breathing.speed = 4;
Breathing.colors.resize(1);
Breathing.colors.resize(1);
modes.push_back(Breathing);
@@ -86,7 +86,7 @@ RGBController_AcerNitroHidKeyboard::RGBController_AcerNitroHidKeyboard(std::shar
Neon.brightness = 100;
Neon.speed_min = 1;
Neon.speed_max = 9;
Neon.speed = 4;
Neon.speed = 4;
modes.push_back(Neon);
@@ -104,7 +104,7 @@ RGBController_AcerNitroHidKeyboard::RGBController_AcerNitroHidKeyboard(std::shar
Wave.direction = 0;
modes.push_back(Wave);
mode Shifting;
Shifting.name = "Shifting";
Shifting.value = ACER_HID_MODE_SHIFTING;
@@ -199,15 +199,15 @@ void RGBController_AcerNitroHidKeyboard::SetupZones()
void RGBController_AcerNitroHidKeyboard::DeviceUpdateLEDs()
{
mode& current_mode = modes[active_mode];
if(current_mode.value == ACER_HID_MODE_DIRECT)
if(current_mode.value == ACER_HID_MODE_DIRECT)
{
controller->SetLEDs(colors, current_mode.brightness, device_id);
}
else
else
{
RGBColor color = current_mode.colors.size()==0? (RGBColor)0 : current_mode.colors[0];
unsigned char direction = 1;
if((modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) && modes[active_mode].direction)
if((modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) && modes[active_mode].direction)
{
direction = 2;
}
@@ -11,16 +11,16 @@
#include "RGBController_AcerNitroHidLed.h"
// /**------------------------------------------------------------------*\
// @name Acer Nitro HID Led
// @category Laptop
// @type HID
// @save :x:
// @direct :white_check_mark:
// @effects :white_check_mark:
// @detectors DetectAcerHIDControllers
// @comment
// \*-------------------------------------------------------------------*/
/**------------------------------------------------------------------*\
@name Acer Nitro HID Led
@category Laptop
@type HID
@save :x:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectAcerHIDControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_AcerNitroHidLed::RGBController_AcerNitroHidLed(std::shared_ptr<AcerNitroHidKeyboardController> controller)
{
@@ -108,27 +108,27 @@ void RGBController_AcerNitroHidLed::SetupZones()
new_zone->leds_max = 1;
new_zone->leds_count = 1;
zones.push_back(*new_zone);
led* new_led = new led();
new_led->name = "LED";
new_led->value = (unsigned int)leds.size();
leds.push_back(*new_led);
SetupColors();
}
void RGBController_AcerNitroHidLed::DeviceUpdateLEDs()
{
mode& current_mode = modes[active_mode];
if(current_mode.value == ACER_HID_MODE_DIRECT)
if(current_mode.value == ACER_HID_MODE_DIRECT)
{
controller->SetLEDs(colors, current_mode.brightness, device_id);
}
else
else
{
RGBColor color = current_mode.colors.size()==0? (RGBColor)0 : current_mode.colors[0];
unsigned char direction = 1;
if((modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) && modes[active_mode].direction)
if((modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) && modes[active_mode].direction)
{
direction = 2;
}
@@ -266,42 +266,53 @@ bool AlienwareController::Dim(std::vector<uint8_t> zones, double percent)
return(true);
}
unsigned char usb_buf[HIDAPI_ALIENWARE_REPORT_SIZE];
bool result = true;
/*-----------------------------------------------------*\
| Zero out buffer |
| Split the zone list into packet-sized chunks so it |
| never overflows usb_buf |
\*-----------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-----------------------------------------------------*\
| Set up message packet with leading 00, per hidapi |
\*-----------------------------------------------------*/
uint16_t num_zones = (uint16_t)zones.size();
usb_buf[0x00] = 0x00;
usb_buf[0x01] = 0x03;
usb_buf[0x02] = ALIENWARE_COMMAND_DIM;
usb_buf[0x03] = static_cast<uint8_t>(percent);
usb_buf[0x04] = num_zones >> 8;
usb_buf[0x05] = num_zones & 0xFF;
for(size_t i = 0; i < num_zones; i++)
for(size_t offset = 0; offset < zones.size(); offset += ALIENWARE_MAX_ZONES_PER_PACKET)
{
usb_buf[0x06+i] = zones[i];
unsigned char usb_buf[HIDAPI_ALIENWARE_REPORT_SIZE];
/*-------------------------------------------------*\
| Zero out buffer |
\*-------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-------------------------------------------------*\
| Set up message packet with leading 00, per hidapi |
\*-------------------------------------------------*/
uint16_t num_zones = (uint16_t)std::min<size_t>(ALIENWARE_MAX_ZONES_PER_PACKET, zones.size() - offset);
usb_buf[0x00] = 0x00;
usb_buf[0x01] = 0x03;
usb_buf[0x02] = ALIENWARE_COMMAND_DIM;
usb_buf[0x03] = static_cast<uint8_t>(percent);
usb_buf[0x04] = num_zones >> 8;
usb_buf[0x05] = num_zones & 0xFF;
for(size_t i = 0; i < num_zones; i++)
{
usb_buf[0x06+i] = zones[offset + i];
}
/*-------------------------------------------------*\
| Send packet |
\*-------------------------------------------------*/
SendHIDReport(dev, usb_buf, sizeof(usb_buf));
HidapiAlienwareReport response = GetResponse();
/*-------------------------------------------------*\
| For this command, error is if the output equals |
| the input |
\*-------------------------------------------------*/
result &= (response.data[1] == 0x03) && memcmp(usb_buf, response.data, HIDAPI_ALIENWARE_REPORT_SIZE);
}
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
SendHIDReport(dev, usb_buf, sizeof(usb_buf));
HidapiAlienwareReport response = GetResponse();
/*-----------------------------------------------------*\
| For this command, error is if the output equals the |
| input |
\*-----------------------------------------------------*/
return((response.data[1] == 0x03) && memcmp(usb_buf, response.data, HIDAPI_ALIENWARE_REPORT_SIZE));
return(result);
}
bool AlienwareController::UserAnimation(uint16_t subcommand, uint16_t animation, uint16_t duration)
@@ -370,42 +381,53 @@ bool AlienwareController::SelectZones(const std::vector<uint8_t>& zones)
return(false);
}
unsigned char usb_buf[HIDAPI_ALIENWARE_REPORT_SIZE];
bool result = true;
/*-----------------------------------------------------*\
| Zero out buffer |
| Split the zone list into packet-sized chunks so it |
| never overflows usb_buf |
\*-----------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-----------------------------------------------------*\
| Set up message packet with leading 00, per hidapi |
\*-----------------------------------------------------*/
uint16_t num_zones = (uint16_t)zones.size();
usb_buf[0x00] = 0x00;
usb_buf[0x01] = 0x03;
usb_buf[0x02] = ALIENWARE_COMMAND_SELECT_ZONES;
usb_buf[0x03] = 1; // loop?
usb_buf[0x04] = num_zones >> 8;
usb_buf[0x05] = num_zones & 0xFF;
for(size_t i = 0; i < num_zones; i++)
for(size_t offset = 0; offset < zones.size(); offset += ALIENWARE_MAX_ZONES_PER_PACKET)
{
usb_buf[0x06+i] = zones[i];
unsigned char usb_buf[HIDAPI_ALIENWARE_REPORT_SIZE];
/*-------------------------------------------------*\
| Zero out buffer |
\*-------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-------------------------------------------------*\
| Set up message packet with leading 00, per hidapi |
\*-------------------------------------------------*/
uint16_t num_zones = (uint16_t)std::min<size_t>(ALIENWARE_MAX_ZONES_PER_PACKET, zones.size() - offset);
usb_buf[0x00] = 0x00;
usb_buf[0x01] = 0x03;
usb_buf[0x02] = ALIENWARE_COMMAND_SELECT_ZONES;
usb_buf[0x03] = 1; // loop?
usb_buf[0x04] = num_zones >> 8;
usb_buf[0x05] = num_zones & 0xFF;
for(size_t i = 0; i < num_zones; i++)
{
usb_buf[0x06+i] = zones[offset + i];
}
/*-------------------------------------------------*\
| Send packet |
\*-------------------------------------------------*/
SendHIDReport(dev, usb_buf, sizeof(usb_buf));
HidapiAlienwareReport response = GetResponse();
/*-------------------------------------------------*\
| For this command, error is if the output equals |
| the input |
\*-------------------------------------------------*/
result &= (response.data[1] == 0x03) && memcmp(usb_buf, response.data, HIDAPI_ALIENWARE_REPORT_SIZE);
}
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
SendHIDReport(dev, usb_buf, sizeof(usb_buf));
HidapiAlienwareReport response = GetResponse();
/*-----------------------------------------------------*\
| For this command, error is if the output equals the |
| input |
\*-----------------------------------------------------*/
return((response.data[1] == 0x03) && memcmp(usb_buf, response.data, HIDAPI_ALIENWARE_REPORT_SIZE));
return(result);
}
bool AlienwareController::ModeAction(uint8_t mode, uint16_t duration, uint16_t tempo, RGBColor color)
@@ -509,44 +531,55 @@ bool AlienwareController::SetColorDirect(RGBColor color, std::vector<uint8_t> zo
return(true);
}
unsigned char usb_buf[HIDAPI_ALIENWARE_REPORT_SIZE];
bool result = true;
/*-----------------------------------------------------*\
| Zero out buffer |
| Split the zone list into packet-sized chunks so it |
| never overflows usb_buf |
\*-----------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-----------------------------------------------------*\
| Set up message packet with leading 00, per hidapi |
\*-----------------------------------------------------*/
uint16_t num_zones = (uint16_t)zones.size();
usb_buf[0x00] = 0x00;
usb_buf[0x01] = 0x03;
usb_buf[0x02] = ALIENWARE_COMMAND_SET_COLOR;
usb_buf[0x03] = RGBGetRValue(color);
usb_buf[0x04] = RGBGetGValue(color);
usb_buf[0x05] = RGBGetBValue(color);
usb_buf[0x06] = num_zones >> 8;
usb_buf[0x07] = num_zones & 0xFF;
for(size_t i = 0; i < num_zones; i++)
for(size_t offset = 0; offset < zones.size(); offset += ALIENWARE_MAX_ZONES_PER_PACKET)
{
usb_buf[0x08 + i] = zones[i];
unsigned char usb_buf[HIDAPI_ALIENWARE_REPORT_SIZE];
/*-------------------------------------------------*\
| Zero out buffer |
\*-------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-------------------------------------------------*\
| Set up message packet with leading 00, per hidapi |
\*-------------------------------------------------*/
uint16_t num_zones = (uint16_t)std::min<size_t>(ALIENWARE_MAX_ZONES_PER_PACKET, zones.size() - offset);
usb_buf[0x00] = 0x00;
usb_buf[0x01] = 0x03;
usb_buf[0x02] = ALIENWARE_COMMAND_SET_COLOR;
usb_buf[0x03] = RGBGetRValue(color);
usb_buf[0x04] = RGBGetGValue(color);
usb_buf[0x05] = RGBGetBValue(color);
usb_buf[0x06] = num_zones >> 8;
usb_buf[0x07] = num_zones & 0xFF;
for(size_t i = 0; i < num_zones; i++)
{
usb_buf[0x08 + i] = zones[offset + i];
}
/*-------------------------------------------------*\
| Send packet |
\*-------------------------------------------------*/
SendHIDReport(dev, usb_buf, sizeof(usb_buf));
HidapiAlienwareReport response = GetResponse();
/*-------------------------------------------------*\
| For this command, error is if the output equals |
| the input |
\*-------------------------------------------------*/
result &= (response.data[1] == 0x03) && memcmp(usb_buf, response.data, HIDAPI_ALIENWARE_REPORT_SIZE);
}
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
SendHIDReport(dev, usb_buf, sizeof(usb_buf));
HidapiAlienwareReport response = GetResponse();
/*-----------------------------------------------------*\
| For this command, error is if the output equals the |
| input |
\*-----------------------------------------------------*/
return((response.data[1] == 0x03) && memcmp(usb_buf, response.data, HIDAPI_ALIENWARE_REPORT_SIZE));
return(result);
}
bool AlienwareController::Reset()
@@ -22,6 +22,14 @@
#define ALIENWARE_REPORT_SIZE 33
#define HIDAPI_ALIENWARE_REPORT_SIZE (ALIENWARE_REPORT_SIZE + 1)
#define ALIENWARE_CONTROLLER_NAME "AlienWare Controller"
/*---------------------------------------------------------*\
| Max zone IDs that fit in one report after the command |
| header. Selections larger than this must be split across |
| multiple packets; writing them into a single report |
| overflows usb_buf (e.g. desktops with ~100 zones). |
\*---------------------------------------------------------*/
#define ALIENWARE_MAX_ZONES_PER_PACKET 25
enum
{
ALIENWARE_COMMAND_REPORT = 0x20, /* Set report type to get */
@@ -0,0 +1,47 @@
/*---------------------------------------------------------*\
| AlienwareAW3423DWFControllerDetect.cpp |
| |
| Detector for Alienware AW3423DWF monitor |
| |
| Ferréol DUBOIS COLI (Fefe_du_973) 23 Jan 2025 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <hidapi.h>
#include "AlienwareAW3423DWFController.h"
#include "DetectionManager.h"
#include "RGBController_AlienwareAW3423DWF.h"
/*---------------------------------------------------------*\
| Alienware Vendor ID |
\*---------------------------------------------------------*/
#define ALIENWARE_VID 0x187C
/*---------------------------------------------------------*\
| Alienware Vendor ID |
\*---------------------------------------------------------*/
#define ALIENWARE_AW3423DWF_PID 0x100E
#define ALIENWARE_USAGE_PAGE 0xFFDA
#define ALIENWARE_USAGE 0x00DA
DetectedControllers DetectAlienwareAW3423DWFControllers(hid_device_info* info, const std::string&)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
AlienwareAW3423DWFController* controller = new AlienwareAW3423DWFController(dev, info->path);
RGBController_AlienwareAW3423DWF* rgb_controller = new RGBController_AlienwareAW3423DWF(controller);
detected_controllers.push_back(rgb_controller);
}
return(detected_controllers);
}
REGISTER_HID_DETECTOR("Alienware AW3423DWF", DetectAlienwareAW3423DWFControllers, ALIENWARE_VID, ALIENWARE_AW3423DWF_PID);
@@ -10,10 +10,8 @@
\*---------------------------------------------------------*/
#include <hidapi.h>
#include "AlienwareAW3423DWFController.h"
#include "AlienwareMonitorController.h"
#include "DetectionManager.h"
#include "RGBController_AlienwareAW3423DWF.h"
#include "RGBController_AlienwareMonitor.h"
/*---------------------------------------------------------*\
@@ -24,29 +22,10 @@
/*---------------------------------------------------------*\
| Alienware Vendor ID |
\*---------------------------------------------------------*/
#define ALIENWARE_AW3423DWF_PID 0x100E
#define ALIENWARE_AW3225QF_PID 0x1013
#define ALIENWARE_USAGE_PAGE 0xFFDA
#define ALIENWARE_USAGE 0x00DA
DetectedControllers DetectAlienwareAW3423DWFControllers(hid_device_info* info, const std::string&)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
AlienwareAW3423DWFController* controller = new AlienwareAW3423DWFController(dev, info->path);
RGBController_AlienwareAW3423DWF* rgb_controller = new RGBController_AlienwareAW3423DWF(controller);
detected_controllers.push_back(rgb_controller);
}
return(detected_controllers);
}
DetectedControllers DetectAlienwareMonitorControllers(hid_device_info* info, const std::string& name)
{
DetectedControllers detected_controllers;
@@ -65,5 +44,4 @@ DetectedControllers DetectAlienwareMonitorControllers(hid_device_info* info, con
return(detected_controllers);
}
REGISTER_HID_DETECTOR("Alienware AW3423DWF", DetectAlienwareAW3423DWFControllers, ALIENWARE_VID, ALIENWARE_AW3423DWF_PID);
REGISTER_HID_DETECTOR("Alienware AW3225QF", DetectAlienwareMonitorControllers, ALIENWARE_VID, ALIENWARE_AW3225QF_PID);
@@ -44,8 +44,4 @@ DetectedControllers DetectArcticControllers()
}
REGISTER_DETECTOR("Arctic RGB controller", DetectArcticControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("Arctic RGB controller", DetectArcticControllers, 0x1A86, 0x7523 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(arctic, "Arctic RGB controller", "SUBSYSTEMS==\"serial|hidraw\", ATTRS{idVendor}==\"1a86\", ATTRS{idProduct}==\"7523\", TAG+=\"uaccess\", TAG+=\"Arctic_RGB_controller\"");
@@ -4,18 +4,15 @@
| Detector for ASUS ROG Aura Core |
| |
| Adam Honse (CalcProgrammer1) 13 Apr 2020 |
| Chris M (Dr_No) 28 Jul 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "DetectionManager.h"
#include "AsusAuraCoreController.h"
#include "RGBController.h"
#include "RGBController_AsusAuraCore.h"
#include "RGBController_AsusAuraCoreLaptop.h"
#include <hidapi.h>
#include "AsusAuraCoreController.h"
#include "DetectionManager.h"
#include "RGBController_AsusAuraCore.h"
#define AURA_CORE_VID 0x0B05
@@ -44,27 +41,6 @@ DetectedControllers DetectAsusAuraCoreControllers(hid_device_info* info, const s
return(detected_controllers);
}
DetectedControllers DetectAsusAuraCoreLaptopControllers(hid_device_info* info, const std::string& /*name*/)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
AsusAuraCoreLaptopController* controller = new AsusAuraCoreLaptopController(dev, info->path);
RGBController_AsusAuraCoreLaptop* rgb_controller = new RGBController_AsusAuraCoreLaptop(controller);
detected_controllers.push_back(rgb_controller);
}
return(detected_controllers);
}
REGISTER_HID_DETECTOR ("ASUS Aura Core", DetectAsusAuraCoreControllers, AURA_CORE_VID, 0x1854);
REGISTER_HID_DETECTOR ("ASUS Aura Core", DetectAsusAuraCoreControllers, AURA_CORE_VID, 0x1866);
REGISTER_HID_DETECTOR ("ASUS Aura Core", DetectAsusAuraCoreControllers, AURA_CORE_VID, 0x1869);
REGISTER_HID_DETECTOR_PU("ASUS ROG Strix SCAR 15", DetectAsusAuraCoreLaptopControllers, AURA_CORE_VID, AURA_STRIX_SCAR_15_PID, 0xFF31, 0x79);
REGISTER_HID_DETECTOR_PU("ASUS ROG Strix SCAR 17", DetectAsusAuraCoreLaptopControllers, AURA_CORE_VID, 0x1866, 0xFF31, 0x79);
@@ -0,0 +1,38 @@
/*---------------------------------------------------------*\
| AsusAuraCoreLaptopControllerDetect.cpp |
| |
| Detector for ASUS ROG Aura Core Laptop |
| |
| Chris M (Dr_No) 28 Jul 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <hidapi.h>
#include "AsusAuraCoreLaptopController.h"
#include "DetectionManager.h"
#include "RGBController_AsusAuraCoreLaptop.h"
#define AURA_CORE_VID 0x0B05
DetectedControllers DetectAsusAuraCoreLaptopControllers(hid_device_info* info, const std::string& /*name*/)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
AsusAuraCoreLaptopController* controller = new AsusAuraCoreLaptopController(dev, info->path);
RGBController_AsusAuraCoreLaptop* rgb_controller = new RGBController_AsusAuraCoreLaptop(controller);
detected_controllers.push_back(rgb_controller);
}
return(detected_controllers);
}
REGISTER_HID_DETECTOR_PU("ASUS ROG Strix SCAR 15", DetectAsusAuraCoreLaptopControllers, AURA_CORE_VID, AURA_STRIX_SCAR_15_PID, 0xFF31, 0x79);
REGISTER_HID_DETECTOR_PU("ASUS ROG Strix SCAR 17", DetectAsusAuraCoreLaptopControllers, AURA_CORE_VID, 0x1866, 0xFF31, 0x79);
@@ -940,6 +940,25 @@ static const aura_core_laptop_device g814jv_device =
}
};
/*-------------------------------------------------------------*\
| ASUS ROG Strix G18 (G814JIR) |
| |
| G814JIR uses the same Aura Core keyboard and lightbar |
| layout as the G814JV G18 profile. |
\*-------------------------------------------------------------*/
static const aura_core_laptop_device g814jir_device =
{
"G814JIR",
{
&g814rw_keyboard_zone,
&g814jv_lightbar_zone,
nullptr,
nullptr,
nullptr,
nullptr
}
};
/*-------------------------------------------------------------------------*\
| DEVICE MASTER LIST |
\*-------------------------------------------------------------------------*/
@@ -954,6 +973,7 @@ const aura_core_laptop_device* aura_core_laptop_device_list_data[] =
&g713rw_device,
&g733qr_device,
&g814jv_device,
&g814jir_device,
};
const unsigned int AURA_CORE_LAPTOP_DEVICE_COUNT = (sizeof(aura_core_laptop_device_list_data) / sizeof(aura_core_laptop_device_list_data[ 0 ]));
@@ -428,7 +428,6 @@ void RGBController_AuraTUFKeyboard::SetupZones()
break;
case AURA_TUF_K3_GAMING_PID:
case AURA_TUF_K7_GAMING_PID:
case AURA_TUF_K3_GENII_MIKU_EDITION_PID:
keyboard_ptr = &AsusTUFK7Layouts;
break;
case AURA_ROG_STRIX_SCOPE_PID:
@@ -485,6 +484,7 @@ void RGBController_AuraTUFKeyboard::SetupZones()
keyboard_ptr = &AsusTufK1Layouts;
break;
case AURA_TUF_K3_GAMING_GEN_II_PID:
case AURA_TUF_K3_GENII_MIKU_EDITION_PID:
keyboard_ptr = &AsusTUFK3GamingGen2Layouts;
break;
default:
@@ -22,8 +22,9 @@
| Product ID |
\*---------------------------------------------------------*/
#define ASUS_ROG_STRIX_XG27AQDMG_PID 0x1BA3
#define ASUS_ROG_SWIFT_XG27UCG_PID 0x1BB4
#define ASUS_ROG_STRIX_XG27UCG_PID 0x1BB4
#define ASUS_ROG_SWIFT_PG32UCDM_PID 0x1B2B
#define ASUS_ROG_SWIFT_PG32UCDMR_PID 0x1C9B
DetectedControllers DetectAsusMonitorControllers(hid_device_info* info, const std::string& name)
{
@@ -44,5 +45,7 @@ DetectedControllers DetectAsusMonitorControllers(hid_device_info* info, const st
}
REGISTER_HID_DETECTOR_IPU("Asus ROG STRIX XG27AQDMG", DetectAsusMonitorControllers, ASUS_VID, ASUS_ROG_STRIX_XG27AQDMG_PID, 1, 0xFF72, 0x00A1);
REGISTER_HID_DETECTOR_IPU("Asus ROG STRIX XG27UCG", DetectAsusMonitorControllers, ASUS_VID, ASUS_ROG_SWIFT_XG27UCG_PID, 1, 0xFF72, 0x00A1);
REGISTER_HID_DETECTOR_IPU("Asus ROG STRIX PG32UCDM", DetectAsusMonitorControllers, ASUS_VID, ASUS_ROG_SWIFT_PG32UCDM_PID, 1, 0xFF72, 0x00A1);
REGISTER_HID_DETECTOR_IPU("Asus ROG STRIX XG27UCG", DetectAsusMonitorControllers, ASUS_VID, ASUS_ROG_STRIX_XG27UCG_PID, 1, 0xFF72, 0x00A1);
REGISTER_HID_DETECTOR_IPU("Asus ROG SWIFT PG32UCDM", DetectAsusMonitorControllers, ASUS_VID, ASUS_ROG_SWIFT_PG32UCDM_PID, 1, 0xFF72, 0x00A1);
REGISTER_HID_DETECTOR_IPU("Asus ROG SWIFT PG32UCDMR", DetectAsusMonitorControllers, ASUS_VID, ASUS_ROG_SWIFT_PG32UCDMR_PID, 1, 0xFF72, 0x00A1);
@@ -36,3 +36,5 @@ DetectedControllers DetectAsusTUFLaptopLinuxControllers()
}
REGISTER_DETECTOR("ASUS TUF Laptop", DetectAsusTUFLaptopLinuxControllers);
REGISTER_CUSTOM_UDEV_RULE(asus_wmi, "ASUS TUF Laptops (asus-wmi)", "ACTION==\"add\", SUBSYSTEM==\"leds\", KERNEL==\"asus::kbd_backlight\", RUN+=\"/usr/bin/env chmod a+w /sys%p/kbd_rgb_mode\"\nACTION==\"add\", SUBSYSTEM==\"leds\", KERNEL==\"asus::kbd_backlight\", RUN+=\"/usr/bin/env chmod a+w /sys%p/brightness\"");
@@ -40,8 +40,4 @@ DetectedControllers DetectBlinkyTapeControllers()
}
REGISTER_DETECTOR("BlinkyTape", DetectBlinkyTapeControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("BlinkyTape", DetectBlinkyTapeControllers, 0x1D50, 0x605E ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(blinky_tape, "BlinkyTape", "SUBSYSTEMS==\"serial|hidraw\", ATTRS{idVendor}==\"1d50\", ATTRS{idProduct}==\"605e\", TAG+=\"uaccess\", TAG+=\"BlinkyTape\"");
@@ -1,4 +1,4 @@
/*---------------------------------------------------------*\
/*---------------------------------------------------------*\
| ColorfulGPUControllerDetect.cpp |
| |
| Detector for Colorful GPU |
@@ -51,6 +51,7 @@ DetectedControllers DetectColorfulGPUControllers(i2c_smbus_interface* bus, uint8
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Advanced OC 12G L-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060_LHR_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ADVANCED_OC_12G_LV, 0x61);
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Ultra W OC 12G L-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060_LHR_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ULTRAW_OC_12G, 0x61);
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Ultra W OC 12G L-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060_GA106_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ULTRAW_OC_12G, 0x61);
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Ultra W OC 12G L-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060_GA106_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ULTRAW_OC_12G_2, 0x61);
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Ultra W OC 12G L-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060_LHR_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ULTRAW_OC_12G_2, 0x61);
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Ti Ultra W OC LHR-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060TI_LHR_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ULTRAW_OC_12G, 0x61);
REGISTER_I2C_PCI_DETECTOR("iGame GeForce RTX 3060 Ti Ultra W OC LHR-V", DetectColorfulGPUControllers, NVIDIA_VEN, NVIDIA_RTX3060TI_LHR_DEV, COLORFUL_SUB_VEN, COLORFUL_IGAME_RTX_3060_ULTRAW_OC_12G_2, 0x61);
@@ -44,8 +44,4 @@ DetectedControllers DetectCorsairHydro2Controllers()
}
REGISTER_DETECTOR("Corsair H100i v2", DetectCorsairHydro2Controllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("Corsair H100i v2", DetectCorsairHydro2Controllers, 0x1B1C, 0x0C09 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(corsair_h100i_v2, "Corsair H100i v2", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"1b1c\", ATTRS{idProduct}==\"0c09\", TAG+=\"uaccess\", TAG+=\"Corsair_H100i_v2\"");
@@ -77,10 +77,6 @@ DetectedControllers DetectCorsairHydroControllers()
}
REGISTER_DETECTOR("Corsair Hydro Series", DetectCorsairHydroControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("Corsair Hydro Series", DetectCorsairHydroControllers, 0x1B1C, 0x0C12 ) |
| DUMMY_DEVICE_DETECTOR("Corsair Hydro Series", DetectCorsairHydroControllers, 0x1B1C, 0x0C13 ) |
| DUMMY_DEVICE_DETECTOR("Corsair Hydro Series", DetectCorsairHydroControllers, 0x1B1C, 0x0C15 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(corsair_hydro_1, "Corsair Hydro Series", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"1b1c\", ATTRS{idProduct}==\"0c12\", TAG+=\"uaccess\", TAG+=\"Corsair_Hydro_Series\"");
REGISTER_CUSTOM_UDEV_RULE(corsair_hydro_2, "Corsair Hydro Series", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"1b1c\", ATTRS{idProduct}==\"0c13\", TAG+=\"uaccess\", TAG+=\"Corsair_Hydro_Series\"");
REGISTER_CUSTOM_UDEV_RULE(corsair_hydro_3, "Corsair Hydro Series", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"1b1c\", ATTRS{idProduct}==\"0c15\", TAG+=\"uaccess\", TAG+=\"Corsair_Hydro_Series\"");
@@ -217,7 +217,7 @@ void CorsairPeripheralController::SetLEDsKeyboardFull(std::vector<RGBColor> colo
blu_val[keys_k95[color_idx]] = RGBGetBValue(color);
data_sz = 48; //untested
}
else if (logical_layout == CORSAIR_TYPE_K70_MK2)
else if (logical_layout == CORSAIR_TYPE_K70_MK2 || logical_layout == CORSAIR_TYPE_K70_LUX_RGB)
{
red_val[keys_k70_mk2[color_idx]] = RGBGetRValue(color);
grn_val[keys_k70_mk2[color_idx]] = RGBGetGValue(color);
@@ -447,7 +447,7 @@ void CorsairPeripheralController::SetupK55AndK95LightingControl()
if (physical_layout == CORSAIR_LAYOUT_ISO)
{
if(logical_layout == CORSAIR_TYPE_K70_MK2)
if(logical_layout == CORSAIR_TYPE_K70_MK2 || logical_layout == CORSAIR_TYPE_K70_LUX_RGB)
{
skipped_identifiers = key_mapping_k70_mk2_plat_iso;
skipped_identifiers_count = sizeof(key_mapping_k70_mk2_plat_iso) / sizeof(key_mapping_k70_mk2_plat_iso[0]);
@@ -632,10 +632,15 @@ void CorsairPeripheralController::ReadFirmwareInfo()
logical_layout = CORSAIR_TYPE_K55;
break;
case 0x1B33:
logical_layout = CORSAIR_TYPE_K70_LUX_RGB;
break;
case 0x1B38:
case 0x1B49:
case 0x1B6B:
case 0x1B55:
case 0x1B48:
logical_layout = CORSAIR_TYPE_K70_MK2;
break;
@@ -67,7 +67,8 @@ enum
CORSAIR_TYPE_K95 = 2,
CORSAIR_TYPE_K55 = 3,
CORSAIR_TYPE_K70_MK2 = 4,
CORSAIR_TYPE_K68 = 5
CORSAIR_TYPE_K68 = 5,
CORSAIR_TYPE_K70_LUX_RGB = 6
};
enum
@@ -48,7 +48,7 @@
#define CORSAIR_K70_RGB_MK2_PID 0x1B49
#define CORSAIR_K70_RGB_MK2_SE_PID 0x1B6B
#define CORSAIR_K70_RGB_MK2_LP_PID 0x1B55
#define CORSAIR_K70_RGB_PRO_OPTO_PID 0x1BC6
#define CORSAIR_K95_RGB_PID 0x1B11
#define CORSAIR_K95_PLATINUM_PID 0x1B2D
#define CORSAIR_K95_PLATINUM_SE_PID 0x1B82
@@ -192,6 +192,7 @@ REGISTER_HID_DETECTOR_IP("Corsair K70 RGB RAPIDFIRE", DetectCorsairPeriphe
REGISTER_HID_DETECTOR_IP("Corsair K70 RGB MK.2", DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K70_RGB_MK2_PID, 1, 0xFFC2);
REGISTER_HID_DETECTOR_IP("Corsair K70 RGB MK.2 SE", DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K70_RGB_MK2_SE_PID, 1, 0xFFC2);
REGISTER_HID_DETECTOR_IP("Corsair K70 RGB MK.2 Low Profile",DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K70_RGB_MK2_LP_PID, 1, 0xFFC2);
REGISTER_HID_DETECTOR_IP("Corsair K70 RGB PRO Optomechanical", DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K70_RGB_PRO_OPTO_PID, 1, 0xFFC2);
REGISTER_HID_DETECTOR_IP("Corsair K95 RGB", DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K95_RGB_PID, 1, 0xFFC2);
REGISTER_HID_DETECTOR_IP("Corsair K95 RGB PLATINUM", DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K95_PLATINUM_PID, 1, 0xFFC2);
REGISTER_HID_DETECTOR_IP("Corsair K95 RGB PLATINUM SE", DetectCorsairPeripheralControllers, CORSAIR_VID, CORSAIR_K95_PLATINUM_SE_PID, 1, 0xFFC2);
@@ -23,6 +23,15 @@ static unsigned int matrix_map[6][23] =
{ 4, 111, 22, 32, 40, 50, NA, 59, NA, 68, 78, 88, 97, 106, 61, NA, NA, 81, NA, 73, 83, 92, 109 },
{ 5, 14, 23, NA, NA, NA, NA, 41, NA, NA, NA, NA, 69, 79, 89, 71, 90, 99, 108, 101, NA, 110, NA } };
static unsigned int matrix_map_k70_lux_rgb[7][23] =
{ { NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 107, 8, NA, NA, 16, NA, NA,},
{ 0, NA, 10, 18, 28, 36, NA, 46, 55, 64, 74, NA, 84, 93, 102, 6, 15, 24, 33, 26, 35, 44, 53 },
{ 1, 11, 19, 29, 37, 47, NA, 56, 65, 75, 85, 94, 103, 7, 25, NA, 42, 51, 60, 62, 72, 82, 91 },
{ 2, NA, 12, 20, 30, 38, 48, 57, 66, 76, 86, NA, 95, 104, 70, 80, 34, 43, 52, 9, 17, 27, 100 },
{ 3, NA, 13, 21, 31, 39, 49, 58, 67, 77, 87, NA, 96, 105, 98, 112, NA, NA, NA, 45, 54, 63, NA },
{ 4, 111, NA, 22, 32, 40, 50, 59, 68, 78, 88, 97, NA, 106, 61, NA, NA, 81, NA, 73, 83, 92, 109 },
{ 5, NA, 14, 23, NA, NA, NA, 41, NA, NA, NA, 69, NA, 79, 89, 71, 90, 99, 108, 101, NA, 110, NA } };
static unsigned int matrix_map_k70_mk2[7][23] =
{ { NA, NA, NA, 115, 107, 8, NA, NA, NA, NA, NA, 113, 114, NA, NA, NA, NA, NA, NA, 16, NA, NA, NA,},
{ 0, NA, 10, 18, 28, 36, NA, 46, 55, 64, 74, NA, 84, 93, 102, 6, 15, 24, 33, 26, 35, 44, 53 },
@@ -68,6 +77,24 @@ static const zone_type zone_types[] =
ZONE_TYPE_MATRIX,
};
/*---------------------------------------------------------*\
| K70 LUX RGB Corsair Layout |
\*---------------------------------------------------------*/
static const char* zone_names_k70_lux_rgb[] =
{
ZONE_EN_KEYBOARD,
};
static const unsigned int zone_sizes_k70_lux_rgb[] =
{
116
};
static const zone_type zone_types_k70_lux_rgb[] =
{
ZONE_TYPE_MATRIX,
};
/*---------------------------------------------------------*\
| K70 MK2 Corsair Layout |
\*---------------------------------------------------------*/
@@ -159,7 +186,7 @@ static const char* led_names[] =
KEY_EN_LEFT_CONTROL, //5
KEY_EN_F12, //6
KEY_EN_EQUALS, //7
"Key: Lock", //8
KEY_EN_WINDOWS_LOCK, //8
KEY_EN_NUMPAD_7, //9
KEY_EN_F1, //12
KEY_EN_1, //13
@@ -258,7 +285,7 @@ static const char* led_names[] =
KEY_EN_LEFT_BRACKET, //134
KEY_EN_QUOTE, //135
KEY_EN_FORWARD_SLASH, //136
"Key: Brightness", //137
KEY_EN_BRIGHTNESS, //137
KEY_EN_RIGHT_ARROW, //139
KEY_EN_NUMPAD_ENTER, //140
KEY_EN_NUMPAD_PERIOD, //141
@@ -266,7 +293,7 @@ static const char* led_names[] =
KEY_EN_ISO_BACK_SLASH,
};
static const char* led_names_k70_mk2[] =
static const char* led_names_k70_lux_rgb[] =
{
KEY_EN_ESCAPE, //0
KEY_EN_BACK_TICK, //1
@@ -276,7 +303,7 @@ static const char* led_names_k70_mk2[] =
KEY_EN_LEFT_CONTROL, //5
KEY_EN_F12, //6
KEY_EN_EQUALS, //7
"Key: Lock", //8
KEY_EN_WINDOWS_LOCK, //8
KEY_EN_NUMPAD_7, //9
KEY_EN_F1, //12
KEY_EN_1, //13
@@ -380,7 +407,132 @@ static const char* led_names_k70_mk2[] =
KEY_EN_LEFT_BRACKET, //134
KEY_EN_QUOTE, //135
KEY_EN_FORWARD_SLASH, //136
"Key: Brightness", //137
KEY_EN_BRIGHTNESS, //137
KEY_EN_RIGHT_ARROW, //139
KEY_EN_NUMPAD_ENTER, //140
KEY_EN_NUMPAD_PERIOD, //141
"Key: / (ISO)", //16
KEY_EN_ISO_BACK_SLASH, //114
"Key: Logo Left", //047
"Key: Logo Right", //059
"Key: Profile", //125
};
static const char* led_names_k70_mk2[] =
{
KEY_EN_ESCAPE, //0
KEY_EN_BACK_TICK, //1
KEY_EN_TAB, //2
KEY_EN_CAPS_LOCK, //3
KEY_EN_LEFT_SHIFT, //4
KEY_EN_LEFT_CONTROL, //5
KEY_EN_F12, //6
KEY_EN_EQUALS, //7
KEY_EN_WINDOWS_LOCK, //8
KEY_EN_NUMPAD_7, //9
KEY_EN_F1, //12
KEY_EN_1, //13
KEY_EN_Q, //14
KEY_EN_A, //15
//"Key: / (ISO)", //16
KEY_EN_LEFT_WINDOWS, //17
KEY_EN_PRINT_SCREEN, //18
KEY_EN_MEDIA_MUTE, //20
KEY_EN_NUMPAD_8, //21
KEY_EN_F2, //24
KEY_EN_2, //25
KEY_EN_W, //26
KEY_EN_S, //27
KEY_EN_Z, //28
KEY_EN_LEFT_ALT, //29
KEY_EN_SCROLL_LOCK, //30
KEY_EN_BACKSPACE, //31
KEY_EN_MEDIA_STOP, //32
KEY_EN_NUMPAD_9, //33
KEY_EN_F3, //36
KEY_EN_3, //37
KEY_EN_E, //38
KEY_EN_D, //39
KEY_EN_X, //40
KEY_EN_PAUSE_BREAK, //42
KEY_EN_DELETE, //43
KEY_EN_MEDIA_PREVIOUS, //44
//"Key: Logo Left", //047
KEY_EN_F4, //48
KEY_EN_4, //49
KEY_EN_R, //50
KEY_EN_F, //51
KEY_EN_C, //52
KEY_EN_SPACE, //53
KEY_EN_INSERT, //54
KEY_EN_END, //55
KEY_EN_MEDIA_PLAY_PAUSE, //56
KEY_EN_NUMPAD_4, //57
//"Key: Logo Right", //059
KEY_EN_F5, //60
KEY_EN_5, //61
KEY_EN_T, //62
KEY_EN_G, //63
KEY_EN_V, //64
KEY_EN_HOME, //66
KEY_EN_PAGE_DOWN, //67
KEY_EN_MEDIA_NEXT, //68
KEY_EN_NUMPAD_5, //69
KEY_EN_F6, //72
KEY_EN_6, //73
KEY_EN_Y, //74
KEY_EN_H, //75
KEY_EN_B, //76
KEY_EN_PAGE_UP, //78
KEY_EN_RIGHT_SHIFT, //79
KEY_EN_NUMPAD_LOCK, //80
KEY_EN_NUMPAD_6, //81
KEY_EN_F7, //84
KEY_EN_7, //85
KEY_EN_U, //86
KEY_EN_J, //87
KEY_EN_N, //88
KEY_EN_RIGHT_ALT, //89
KEY_EN_RIGHT_BRACKET, //90
KEY_EN_RIGHT_CONTROL, //91
KEY_EN_NUMPAD_DIVIDE, //92
KEY_EN_NUMPAD_1, //93
KEY_EN_F8, //96
KEY_EN_8, //97
KEY_EN_I, //98
KEY_EN_K, //99
KEY_EN_M, //100
KEY_EN_RIGHT_WINDOWS, //101
KEY_EN_ANSI_BACK_SLASH, //102
KEY_EN_UP_ARROW, //103
KEY_EN_NUMPAD_TIMES, //104
KEY_EN_NUMPAD_2, //105
KEY_EN_F9, //108
KEY_EN_9, //109
KEY_EN_O, //110
KEY_EN_L, //111
KEY_EN_COMMA, //112
KEY_EN_MENU, //113
//KEY_EN_ISO_BACK_SLASH, //114
KEY_EN_LEFT_ARROW, //115
KEY_EN_NUMPAD_MINUS, //116
KEY_EN_NUMPAD_3, //117
KEY_EN_F10, //120
KEY_EN_0, //121
KEY_EN_P, //122
KEY_EN_SEMICOLON, //123
//"Key: Profile", //125
KEY_EN_PERIOD, //124
KEY_EN_ANSI_ENTER, //126
KEY_EN_DOWN_ARROW, //127
KEY_EN_NUMPAD_PLUS, //128
KEY_EN_NUMPAD_0, //129
KEY_EN_F11, //132
KEY_EN_MINUS, //133
KEY_EN_LEFT_BRACKET, //134
KEY_EN_QUOTE, //135
KEY_EN_FORWARD_SLASH, //136
KEY_EN_BRIGHTNESS, //137
KEY_EN_RIGHT_ARROW, //139
KEY_EN_NUMPAD_ENTER, //140
KEY_EN_NUMPAD_PERIOD, //141
@@ -401,7 +553,7 @@ static const char* led_names_k95_plat[] =
KEY_EN_LEFT_CONTROL, //5
KEY_EN_F12, //6
KEY_EN_EQUALS, //7
"Key: Lock", //8
KEY_EN_WINDOWS_LOCK, //8
KEY_EN_NUMPAD_7, //9
KEY_EN_F1, //12
KEY_EN_1, //13
@@ -500,7 +652,7 @@ static const char* led_names_k95_plat[] =
KEY_EN_LEFT_BRACKET, //134
KEY_EN_QUOTE, //135
KEY_EN_FORWARD_SLASH, //136
"Key: Brightness", //137
KEY_EN_BRIGHTNESS, //137
KEY_EN_RIGHT_ARROW, //139
KEY_EN_NUMPAD_ENTER, //140
KEY_EN_NUMPAD_PERIOD, //141
@@ -544,7 +696,7 @@ static const char* led_names_k95[] =
KEY_EN_LEFT_CONTROL, //5
KEY_EN_F12, //6
KEY_EN_EQUALS, //7
"Key: Lock", //8
KEY_EN_WINDOWS_LOCK, //8
KEY_EN_NUMPAD_7, //9
KEY_EN_F1, //12
KEY_EN_1, //13
@@ -643,7 +795,7 @@ static const char* led_names_k95[] =
KEY_EN_LEFT_BRACKET, //134
KEY_EN_QUOTE, //135
KEY_EN_FORWARD_SLASH, //136
"Key: Brightness", //137
KEY_EN_BRIGHTNESS, //137
KEY_EN_RIGHT_ARROW, //139
KEY_EN_NUMPAD_ENTER, //140
KEY_EN_NUMPAD_PERIOD, //141
@@ -1012,6 +1164,19 @@ void RGBController_CorsairPeripheral::SetupZones()
new_zone.leds_max = zone_sizes_k55[zone_idx];
new_zone.leds_count = zone_sizes_k55[zone_idx];
}
else if (logical_layout == CORSAIR_TYPE_K70_LUX_RGB)
{
new_zone.name = zone_names_k70_lux_rgb[zone_idx];
new_zone.type = zone_types_k70_lux_rgb[zone_idx];
new_zone.leds_min = zone_sizes_k70_lux_rgb[zone_idx];
new_zone.leds_max = zone_sizes_k70_lux_rgb[zone_idx];
new_zone.leds_count = zone_sizes_k70_lux_rgb[zone_idx];
if(zone_types[zone_idx] == ZONE_TYPE_MATRIX)
{
new_zone.matrix_map.Set(7, 23, (unsigned int *)&matrix_map_k70_lux_rgb);
}
}
else if (logical_layout == CORSAIR_TYPE_K70_MK2)
{
new_zone.name = zone_names_k70_mk2[zone_idx];
@@ -1101,6 +1266,10 @@ void RGBController_CorsairPeripheral::SetupZones()
{
new_led.name = led_names_k55[led_idx];
}
else if(logical_layout == CORSAIR_TYPE_K70_LUX_RGB)
{
new_led.name = led_names_k70_lux_rgb[led_idx];
}
else if(logical_layout == CORSAIR_TYPE_K70_MK2)
{
new_led.name = led_names_k70_mk2[led_idx];
@@ -9,6 +9,9 @@
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <chrono>
#include <thread>
#include "CorsairPeripheralV2Controller.h"
#include "StringUtils.h"
@@ -19,21 +22,24 @@ CorsairPeripheralV2Controller::CorsairPeripheralV2Controller(hid_device* dev_han
dev = dev_handle;
location = path;
device_name = name;
device_index = CORSAIR_V2_DEVICE_NOT_FOUND;
/*---------------------------------------------------------*\
| Get PID |
| If the PID is in the know wireless receivers list |
| switch the write_cmd to talk to the device and retry |
\*---------------------------------------------------------*/
unsigned int pid = GetAddress(0x12);
unsigned int pid = GetAddressRetry(0x12);
switch(pid)
{
case CORSAIR_SLIPSTREAM_WIRELESS_PID1:
case CORSAIR_SLIPSTREAM_WIRELESS_V2_PID1:
case CORSAIR_SLIPSTREAM_WIRELESS_PID2:
case CORSAIR_SLIPSTREAM_M75_PID:
case CORSAIR_SLIPSTREAM_IRONCLAW_SE_PID:
write_cmd = CORSAIR_V2_WRITE_WIRELESS_ID;
pid = GetAddress(0x12);
pid = GetAddressRetry(0x12);
break;
case CORSAIR_K57_RGB_WIRED_PID:
@@ -88,10 +94,18 @@ CorsairPeripheralV2Controller::CorsairPeripheralV2Controller(hid_device* dev_han
}
}
/*---------------------------------------------------------*\
| Unknown PID |
| Leave device_index at CORSAIR_V2_DEVICE_NOT_FOUND so |
| GetDeviceData() returns nullptr and the detector drops |
| the device, rather than building an RGBController on |
| top of an out of range index. |
\*---------------------------------------------------------*/
if(not_found)
{
LOG_ERROR("[%s] device capabilities not found. Please creata a new device request.",
device_name.c_str());
return;
}
/*---------------------------------------------------------*\
@@ -119,9 +133,19 @@ CorsairPeripheralV2Controller::~CorsairPeripheralV2Controller()
const corsair_v2_device* CorsairPeripheralV2Controller::GetDeviceData()
{
if(!IsDeviceSupported())
{
return nullptr;
}
return corsair_v2_device_list[device_index];
}
bool CorsairPeripheralV2Controller::IsDeviceSupported()
{
return device_index < CORSAIR_V2_DEVICE_COUNT;
}
std::string CorsairPeripheralV2Controller::GetDeviceLocation()
{
return("HID: " + location);
@@ -216,6 +240,34 @@ unsigned int CorsairPeripheralV2Controller::GetKeyboardLayout()
return GetAddress(0x41);
}
/*---------------------------------------------------------*\
| GetAddress returns NA when the device answers with a |
| protocol error, and a receiver whose device has not |
| woken answers zero. Straight after enumeration both |
| are normal, so poll before treating either as final. |
\*---------------------------------------------------------*/
unsigned int CorsairPeripheralV2Controller::GetAddressRetry(uint8_t address)
{
unsigned int value = NA;
for(unsigned int attempt = 0; attempt < CORSAIR_V2_PID_RETRIES; attempt++)
{
value = GetAddress(address);
if(value != NA && value != 0)
{
return value;
}
if(attempt + 1 < CORSAIR_V2_PID_RETRIES)
{
std::this_thread::sleep_for(std::chrono::milliseconds(CORSAIR_V2_PID_RETRY_DELAY));
}
}
return value;
}
unsigned int CorsairPeripheralV2Controller::GetAddress(uint8_t address)
{
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
@@ -37,6 +37,19 @@
#define CORSAIR_V2_BRIGHTNESS_MIN 0
#define CORSAIR_V2_BRIGHTNESS_MAX 0xFF
/*---------------------------------------------------------*\
| A device that has just enumerated does not answer the PID |
| query straight away, so retry before giving up on it. |
\*---------------------------------------------------------*/
#define CORSAIR_V2_PID_RETRIES 8
#define CORSAIR_V2_PID_RETRY_DELAY 120
/*---------------------------------------------------------*\
| device_index when the PID is not in the device list. |
| Never index the device list with it. |
\*---------------------------------------------------------*/
#define CORSAIR_V2_DEVICE_NOT_FOUND 0xFFFF
enum corsair_v2_cmd
{
CORSAIR_V2_CMD_SET = 0x01, /* Command for setting values */
@@ -84,6 +97,7 @@ public:
std::string GetName();
std::string GetSerialString();
const corsair_v2_device* GetDeviceData();
bool IsDeviceSupported();
unsigned int GetKeyboardLayout();
void SetRenderMode(corsair_v2_device_mode mode);
@@ -102,6 +116,7 @@ protected:
private:
void ClearPacketBuffer();
unsigned int GetAddress(uint8_t address);
unsigned int GetAddressRetry(uint8_t address);
unsigned char StartTransaction(uint8_t opt1);
void StopTransaction(uint8_t opt1);
@@ -12,6 +12,7 @@
\*---------------------------------------------------------*/
#include <hidapi.h>
#include "DetectionManager.h"
#include "LogManager.h"
/*---------------------------------------------------------*\
| Corsair Peripheral specific includes |
@@ -37,6 +38,20 @@ DetectedControllers DetectCorsairV2HardwareControllers(hid_device_info* info, co
if(dev)
{
CorsairPeripheralV2HWController* controller = new CorsairPeripheralV2HWController(dev, info->path, name);
/*---------------------------------------------------------*\
| A device whose PID is not in the device list has no |
| zone or LED data to build an RGBController from. |
| Drop it here: building one anyway indexes the device |
| list with an index that was never set. |
\*---------------------------------------------------------*/
if(!controller->IsDeviceSupported())
{
LOG_WARNING("[%s] not registering device, capabilities unknown.", name.c_str());
delete controller;
return(detected_controllers);
}
RGBController_CorsairV2HW* rgb_controller = new RGBController_CorsairV2HW(controller);
detected_controllers.push_back(rgb_controller);
@@ -55,6 +70,14 @@ DetectedControllers DetectCorsairV2SoftwareControllers(hid_device_info* info, co
if(dev)
{
CorsairPeripheralV2SWController* controller = new CorsairPeripheralV2SWController(dev, info->path, name);
if(!controller->IsDeviceSupported())
{
LOG_WARNING("[%s] not registering device, capabilities unknown.", name.c_str());
delete controller;
return(detected_controllers);
}
RGBController_CorsairV2SW* rgb_controller = new RGBController_CorsairV2SW(controller);
detected_controllers.push_back(rgb_controller);
@@ -91,6 +114,8 @@ REGISTER_HID_DETECTOR_IP("Corsair Dark Core RGB SE (Wired)", DetectCorsai
REGISTER_HID_DETECTOR_IP("Corsair Dark Core RGB Pro SE (Wired)", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_DARK_CORE_RGB_PRO_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Harpoon Wireless (Wired)", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_HARPOON_WIRELESS_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Ironclaw Wireless (Wired)", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_IRONCLAW_WIRELESS_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Ironclaw Wireless SE (Wired)", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_IRONCLAW_WIRELESS_SE_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Ironclaw Wireless SE", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_SLIPSTREAM_IRONCLAW_SE_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Katar Pro", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_KATAR_PRO_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Katar Pro V2", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_KATAR_PRO_V2_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Katar Pro XT", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_KATAR_PRO_XT_PID, 1, 0xFF42);
@@ -98,6 +123,8 @@ REGISTER_HID_DETECTOR_IP("Corsair M55 RGB PRO", DetectCorsai
REGISTER_HID_DETECTOR_IP("Corsair M65 RGB Ultra Wired", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_M65_RGB_ULTRA_WIRED_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair M65 RGB Ultra Wireless (Wired)", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_M65_RGB_ULTRA_WIRELESS_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair M75 Gaming Mouse", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_M75_GAMING_MOUSE_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair M75 Wireless", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_SLIPSTREAM_M75_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair M75 Wireless (Wired)", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_M75_WIRELESS_PID, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Slipstream Wireless Receiver HW", DetectCorsairV2HardwareControllers, CORSAIR_VID, CORSAIR_SLIPSTREAM_WIRELESS_PID1, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Slipstream Wireless Receiver SW", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_SLIPSTREAM_WIRELESS_PID2, 1, 0xFF42);
REGISTER_HID_DETECTOR_IP("Corsair Slipstream Wireless Receiver HW", DetectCorsairV2SoftwareControllers, CORSAIR_VID, CORSAIR_SLIPSTREAM_WIRELESS_V2_PID1, 1, 0xFF42);
@@ -638,6 +638,71 @@ static const corsair_v2_device ironclaw_wireless_device =
nullptr
};
/*-------------------------------------------------------------*\
| Corsair Ironclaw Wireless SE 1B1C:2B32 |
| |
| Zone "Logo" |
| Single |
| |
| Zone "Scroll Wheel" |
| Single |
| |
| Zone "Buttons" |
| Single |
| |
| Zone "Side" |
| Linear |
| 1 Row, 3 Columns |
\*-------------------------------------------------------------*/
static const corsair_v2_zone ironclaw_se_logo_zone =
{
"Logo",
ZONE_TYPE_SINGLE,
1,
1
};
static const corsair_v2_zone ironclaw_se_scroll_zone =
{
"Scroll Wheel",
ZONE_TYPE_SINGLE,
1,
1
};
static const corsair_v2_zone ironclaw_se_button_zone =
{
"Buttons",
ZONE_TYPE_SINGLE,
1,
1
};
static const corsair_v2_zone ironclaw_se_side_zone =
{
"Side Zone",
ZONE_TYPE_LINEAR,
1,
3
};
static const corsair_v2_device ironclaw_wireless_se_device =
{
CORSAIR_IRONCLAW_WIRELESS_SE_PID,
DEVICE_TYPE_MOUSE,
1,
6,
{
&ironclaw_se_logo_zone,
&ironclaw_se_scroll_zone,
&ironclaw_se_button_zone,
&ironclaw_se_side_zone,
nullptr,
nullptr
},
nullptr
};
/*-------------------------------------------------------------*\
| Corsair Katar Pro 1B1C:1B93 |
| |
@@ -1443,6 +1508,44 @@ static const corsair_v2_device m75_device =
nullptr
};
/*-------------------------------------------------------------*\
| Corsair M75 Wireless 1B1C:1BF1 |
| |
| Reached through the Slipstream receiver 1B1C:1BDC, which |
| reports the mouse PID 0x1BF1 once the write command is |
| switched to the wireless ID. |
| |
| Zone "Logo" |
| Single |
| |
| Zone "Bottom" |
| Single |
\*-------------------------------------------------------------*/
static const corsair_v2_zone m75_wireless_bottom_zone =
{
"Bottom",
ZONE_TYPE_SINGLE,
1,
1
};
static const corsair_v2_device m75_wireless_device =
{
CORSAIR_M75_WIRELESS_PID,
DEVICE_TYPE_MOUSE,
1,
2,
{
&m75_logo_zone,
&m75_wireless_bottom_zone,
nullptr,
nullptr,
nullptr,
nullptr
},
nullptr
};
/*-------------------------------------------------------------*\
| Corsair MM700 1B1C:1B9B |
| |
@@ -1543,6 +1646,7 @@ const corsair_v2_device* corsair_v2_device_list_data[] =
&dark_core_pro_se_device,
&harpoon_wireless_device,
&ironclaw_wireless_device,
&ironclaw_wireless_se_device,
&katar_pro_device,
&katar_pro_v2_device,
&katar_pro_xt_device,
@@ -1550,6 +1654,7 @@ const corsair_v2_device* corsair_v2_device_list_data[] =
&m65_rgb_ultra_wired_device,
&m65_ultra_rgb_device,
&m75_device,
&m75_wireless_device,
/*-----------------------------------------------------------------*\
| MOUSEMATS |
@@ -93,6 +93,8 @@ typedef struct
#define CORSAIR_DARK_CORE_RGB_PRO_PID 0x1B7E
#define CORSAIR_HARPOON_WIRELESS_PID 0x1B5E
#define CORSAIR_IRONCLAW_WIRELESS_PID 0x1B4C
#define CORSAIR_IRONCLAW_WIRELESS_SE_PID 0x2B32
#define CORSAIR_SLIPSTREAM_IRONCLAW_SE_PID 0x2B00
#define CORSAIR_KATAR_PRO_PID 0x1B93
#define CORSAIR_KATAR_PRO_V2_PID 0x1BBA
#define CORSAIR_KATAR_PRO_XT_PID 0x1BAC
@@ -100,6 +102,8 @@ typedef struct
#define CORSAIR_M65_RGB_ULTRA_WIRED_PID 0x1B9E
#define CORSAIR_M65_RGB_ULTRA_WIRELESS_PID 0x1BB5
#define CORSAIR_M75_GAMING_MOUSE_PID 0x1BF0
#define CORSAIR_M75_WIRELESS_PID 0x1BF1
#define CORSAIR_SLIPSTREAM_M75_PID 0x1BDC
#define CORSAIR_SLIPSTREAM_WIRELESS_PID1 0x1BA6
#define CORSAIR_SLIPSTREAM_WIRELESS_V2_PID1 0x1B66
#define CORSAIR_SLIPSTREAM_WIRELESS_PID2 0x1B65
@@ -16,13 +16,10 @@ DetectedControllers DetectCreativeAE5Device()
{
DetectedControllers detected_controllers;
LOG_INFO("[Creative SoundBlaster AE-5] Windows detection function called");
CreativeSoundBlasterAE5Controller_Windows* controller = new CreativeSoundBlasterAE5Controller_Windows();
if(controller->Initialize())
{
LOG_INFO("[Creative SoundBlaster AE-5] Device initialized successfully, registering controller");
RGBController_CreativeSoundBlasterAE5* rgb_controller = new RGBController_CreativeSoundBlasterAE5(controller);
detected_controllers.push_back(rgb_controller);
@@ -1,7 +1,7 @@
/*---------------------------------------------------------*\
| CreativeControllerDetect.cpp |
| CreativeSoundBlasterXG6ControllerDetect.cpp |
| |
| Detector for Creative devices |
| Detector for Creative Sound Blaster XG6 devices |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
@@ -15,14 +15,14 @@
/*---------------------------------------------------------*\
| Creative vendor ID |
\*---------------------------------------------------------*/
#define CREATIVE_VID 0x041E
#define CREATIVE_VID 0x041E
/*---------------------------------------------------------*\
| SoundCards |
| Creative Sound Blaster XG6 product ID |
\*---------------------------------------------------------*/
#define CREATIVE_SOUNDBLASTERX_G6_PID 0x3256
#define CREATIVE_SOUNDBLASTERX_G6_PID 0x3256
DetectedControllers DetectCreativeDevice(hid_device_info* info, const std::string& name)
DetectedControllers DetectCreativeSoundBlasterXG6Device(hid_device_info* info, const std::string& name)
{
DetectedControllers detected_controllers;
hid_device* dev;
@@ -40,7 +40,7 @@ DetectedControllers DetectCreativeDevice(hid_device_info* info, const std::strin
return(detected_controllers);
}
/*-------------------------------------------------------------------------------------------------------------------------------------------------*\
| Sound Cards |
\*-------------------------------------------------------------------------------------------------------------------------------------------------*/
REGISTER_HID_DETECTOR_I("Creative SoundBlasterX G6", DetectCreativeDevice, CREATIVE_VID, CREATIVE_SOUNDBLASTERX_G6_PID, 4);
/*---------------------------------------------------------*\
| Sound Cards |
\*---------------------------------------------------------*/
REGISTER_HID_DETECTOR_I("Creative SoundBlasterX G6", DetectCreativeSoundBlasterXG6Device, CREATIVE_VID, CREATIVE_SOUNDBLASTERX_G6_PID, 4);
+60 -10
View File
@@ -59,15 +59,57 @@ RGBController_DDP::~RGBController_DDP()
void RGBController_DDP::SetupZones()
{
for(unsigned int zone_idx = 0; zone_idx < devices.size(); zone_idx++)
/*-----------------------------------------------------*\
| Only set LED count on the first run |
\------------------------------------------------------*/
bool first_run = false;
if(zones.size() == 0)
{
zone led_zone;
led_zone.name = devices[zone_idx].name;
led_zone.type = ZONE_TYPE_LINEAR;
led_zone.leds_min = devices[zone_idx].num_leds;
led_zone.leds_max = devices[zone_idx].num_leds;
led_zone.leds_count = devices[zone_idx].num_leds;
zones.push_back(led_zone);
first_run = true;
}
/*-----------------------------------------------------*\
| Clear any existing color/LED configuration |
\------------------------------------------------------*/
leds.clear();
colors.clear();
zones.resize(devices.size());
/*-----------------------------------------------------*\
| Set zones and leds |
\------------------------------------------------------*/
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
zones[zone_idx].leds_min = devices[zone_idx].num_leds;
zones[zone_idx].leds_max = devices[zone_idx].num_leds;
if(first_run)
{
zones[zone_idx].flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_NAME
| ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE
| ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP
| ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS;
}
if(!(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_NAME))
{
zones[zone_idx].name = devices[zone_idx].name;
}
zones[zone_idx].leds_count = devices[zone_idx].num_leds;
if(!(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_TYPE))
{
zones[zone_idx].type = ZONE_TYPE_LINEAR;
}
if(!(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP))
{
zones[zone_idx].matrix_map.width = 0;
zones[zone_idx].matrix_map.height = 0;
zones[zone_idx].matrix_map.map.resize(0);
}
}
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
@@ -75,14 +117,22 @@ void RGBController_DDP::SetupZones()
for(unsigned int led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
{
led new_led;
new_led.name = zones[zone_idx].name + " LED " + std::to_string(led_idx + 1);
new_led.value = 0;
new_led.name = zones[zone_idx].name + " LED " + std::to_string(led_idx + 1);
leds.push_back(new_led);
}
}
SetupColors();
}
void RGBController_DDP::DeviceConfigureZone(int zone_idx)
{
if((size_t)zone_idx < zones.size())
{
SetupZones();
}
}
void RGBController_DDP::DeviceUpdateLEDs()
{
std::vector<unsigned int> brightness_adjusted_colors;
@@ -21,6 +21,8 @@ public:
void SetupZones();
void DeviceConfigureZone(int zone_idx);
void DeviceUpdateLEDs();
void DeviceUpdateZoneLEDs(int zone);
void DeviceUpdateSingleLED(int led);
@@ -40,8 +40,4 @@ DetectedControllers DetectDygmaRaiseControllers()
}
REGISTER_DETECTOR("Dygma Raise", DetectDygmaRaiseControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("Dygma Raise", DetectDygmaRaiseControllers, 0x1209, 0x2201 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(dygma_raise, "Dygma Raise", "SUBSYSTEMS==\"serial|hidraw\", ATTRS{idVendor}==\"1209\", ATTRS{idProduct}==\"2201\", TAG+=\"uaccess\", TAG+=\"Dygma_Raise\"");
@@ -223,33 +223,68 @@ RGBController_E131::~RGBController_E131()
void RGBController_E131::SetupZones()
{
/*-----------------------------------------------------*\
| Add Zones |
| Only set LED count on the first run |
\*-----------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < devices.size(); zone_idx++)
{
zone led_zone;
led_zone.name = devices[zone_idx].name;
led_zone.type = ZONE_TYPE_LINEAR;
led_zone.leds_min = devices[zone_idx].num_leds;
led_zone.leds_max = devices[zone_idx].num_leds;
led_zone.leds_count = devices[zone_idx].num_leds;
led_zone.flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE
| ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP
| ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS;
bool first_run = false;
zones.push_back(led_zone);
if(zones.size() == 0)
{
first_run = true;
}
/*-----------------------------------------------------*\
| Add LEDs |
| Clear any existing color/LED configuration |
\*-----------------------------------------------------*/
leds.clear();
colors.clear();
zones.resize(devices.size());
/*-----------------------------------------------------*\
| Set zones and leds |
\*-----------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
zones[zone_idx].leds_min = devices[zone_idx].num_leds;
zones[zone_idx].leds_max = devices[zone_idx].num_leds;
if(first_run)
{
zones[zone_idx].flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_NAME
| ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE
| ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP
| ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS;
}
if(!(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_NAME))
{
zones[zone_idx].name = devices[zone_idx].name;
}
zones[zone_idx].leds_count = devices[zone_idx].num_leds;
if(!(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_TYPE))
{
zones[zone_idx].type = ZONE_TYPE_LINEAR;
}
if(!(zones[zone_idx].flags & ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP))
{
zones[zone_idx].matrix_map.width = 0;
zones[zone_idx].matrix_map.height = 0;
zones[zone_idx].matrix_map.map.resize(0);
}
}
/*-----------------------------------------------------*\
| Add LEDs |
\*-----------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
for(std::size_t led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
{
led new_led;
new_led.name = zones[zone_idx].name + " LED ";
new_led.name = zones[zone_idx].name + " LED ";
new_led.name.append(std::to_string(led_idx));
leds.push_back(new_led);
@@ -259,6 +294,14 @@ void RGBController_E131::SetupZones()
SetupColors();
}
void RGBController_E131::DeviceConfigureZone(int zone_idx)
{
if((size_t)zone_idx < zones.size())
{
SetupZones();
}
}
void RGBController_E131::DeviceUpdateLEDs()
{
int color_idx = 0;
@@ -35,6 +35,8 @@ public:
void SetupZones();
void DeviceConfigureZone(int zone_idx);
void DeviceUpdateLEDs();
void DeviceUpdateZoneLEDs(int zone);
void DeviceUpdateSingleLED(int led);
@@ -427,6 +427,7 @@ REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL GeForce RTX 5080 WHITE",
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL GeForce RTX 5090 OC", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_RTX_5090_O32G_GAMING, 0x67);
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL GeForce RTX 5090", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_RTX_5090_O32G_GAMING_2, 0x67);
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL GeForce RTX 5090 OC BTF", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_RTX_5090_O32G_GAMING_BTF, 0x67);
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL GeForce RTX 5090 OC BTF", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_RTX_5090_O32G_GAMING_BTF_2, 0x67);
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL GeForce RTX 5090 OC WHITE", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_RTX_5090_O32G_GAMING_WHITE, 0x67);
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL LC GeForce RTX 5090 OC", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_LC_RTX_5090_O32G_GAMING, 0x67);
REGISTER_I2C_PCI_DETECTOR("ASUS ROG ASTRAL LC OC GeForce RTX 5090 OC", DetectENESMBusGPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, ASUS_SUB_VEN, ASUS_ROG_ASTRAL_LC_OC_RTX_5090_O32G_GAMING, 0x67);
@@ -0,0 +1,253 @@
/*---------------------------------------------------------*\
| EVGAX12Controller.cpp |
| |
| Driver for the EVGA X12 gaming mouse |
| |
| QuickMythril 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <chrono>
#include <cstring>
#include <thread>
#include "EVGAX12Controller.h"
#include "LogManager.h"
#include "StringUtils.h"
#define EVGA_X12_HEADER 0xEA
#define EVGA_X12_DIRECTION_GET 0x01
#define EVGA_X12_DIRECTION_SET 0x02
#define EVGA_X12_COMMAND_MODE 0x01
#define EVGA_X12_COMMAND_STATIC 0x02
#define EVGA_X12_START_WITH_PROFILE 0x01
#define EVGA_X12_READ_ATTEMPTS 5
#define EVGA_X12_READ_DELAY_MS 5
#define EVGA_X12_WRITE_ATTEMPTS 3
EVGAX12Controller::EVGAX12Controller(hid_device* dev_handle, const hid_device_info& info, const std::string& dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
}
EVGAX12Controller::~EVGAX12Controller()
{
hid_close(dev);
}
std::string EVGAX12Controller::GetDeviceLocation()
{
return("HID: " + location);
}
std::string EVGAX12Controller::GetNameString()
{
return(name);
}
std::string EVGAX12Controller::GetSerialString()
{
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
EVGAX12LightingState EVGAX12Controller::GetLightingState()
{
std::lock_guard<std::mutex> lock(device_mutex);
EVGAX12LightingState state = {};
unsigned char packet[EVGA_X12_REPORT_SIZE];
state.modes_valid = GetReport(EVGA_X12_COMMAND_MODE, packet);
if(state.modes_valid)
{
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
state.modes[led_idx] = packet[4 + led_idx];
}
}
state.static_valid = GetReport(EVGA_X12_COMMAND_STATIC, packet);
if(state.static_valid)
{
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
unsigned int offset = 4 + (led_idx * 4);
state.brightness[led_idx] = packet[offset];
state.colors[led_idx] = ToRGBColor(packet[offset + 1], packet[offset + 2], packet[offset + 3]);
}
}
return(state);
}
bool EVGAX12Controller::SetMode(unsigned char mode)
{
std::lock_guard<std::mutex> lock(device_mutex);
return(SetModeReport(mode));
}
bool EVGAX12Controller::SetModeReport(unsigned char mode)
{
unsigned char packet[EVGA_X12_REPORT_SIZE] = {};
packet[0] = EVGA_X12_REPORT_ID;
packet[1] = EVGA_X12_HEADER;
packet[2] = EVGA_X12_DIRECTION_SET;
packet[3] = EVGA_X12_COMMAND_MODE;
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
packet[4 + led_idx] = mode;
}
return(SendReport(packet));
}
bool EVGAX12Controller::SetStatic(const std::vector<RGBColor>& colors, unsigned char brightness)
{
if(colors.size() < EVGA_X12_LED_COUNT)
{
LOG_ERROR("[%s] Cannot set static lighting with only %u colors", name.c_str(), (unsigned int)colors.size());
return(false);
}
std::lock_guard<std::mutex> lock(device_mutex);
return(SetStaticReport(colors, brightness));
}
bool EVGAX12Controller::SetStaticAndActivate(const std::vector<RGBColor>& colors, unsigned char brightness)
{
if(colors.size() < EVGA_X12_LED_COUNT)
{
LOG_ERROR("[%s] Cannot set static lighting with only %u colors", name.c_str(), (unsigned int)colors.size());
return(false);
}
std::lock_guard<std::mutex> lock(device_mutex);
if(!SetStaticReport(colors, brightness))
{
return(false);
}
std::this_thread::sleep_for(std::chrono::milliseconds(EVGA_X12_READ_DELAY_MS));
return(SetModeReport(EVGA_X12_MODE_STATIC));
}
bool EVGAX12Controller::SetStaticReport(const std::vector<RGBColor>& colors, unsigned char brightness)
{
unsigned char packet[EVGA_X12_REPORT_SIZE] = {};
packet[0] = EVGA_X12_REPORT_ID;
packet[1] = EVGA_X12_HEADER;
packet[2] = EVGA_X12_DIRECTION_SET;
packet[3] = EVGA_X12_COMMAND_STATIC;
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
unsigned int offset = 4 + (led_idx * 4);
packet[offset] = brightness;
packet[offset + 1] = RGBGetRValue(colors[led_idx]);
packet[offset + 2] = RGBGetGValue(colors[led_idx]);
packet[offset + 3] = RGBGetBValue(colors[led_idx]);
packet[20 + led_idx] = EVGA_X12_START_WITH_PROFILE;
}
for(unsigned int attempt = 0; attempt < EVGA_X12_WRITE_ATTEMPTS; attempt++)
{
if(!SendReport(packet))
{
return(false);
}
std::this_thread::sleep_for(std::chrono::milliseconds(EVGA_X12_READ_DELAY_MS));
unsigned char reply[EVGA_X12_REPORT_SIZE];
if(GetReport(EVGA_X12_COMMAND_STATIC, reply))
{
bool matches = true;
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
unsigned int offset = 4 + (led_idx * 4);
if(std::memcmp(&packet[offset], &reply[offset], 4) != 0)
{
matches = false;
break;
}
}
if(matches)
{
return(true);
}
}
}
LOG_VERBOSE("[%s] Retries exhausted setting static lighting", name.c_str());
return(false);
}
bool EVGAX12Controller::GetReport(unsigned char command, unsigned char* packet)
{
std::memset(packet, 0, EVGA_X12_REPORT_SIZE);
packet[0] = EVGA_X12_REPORT_ID;
packet[1] = EVGA_X12_HEADER;
packet[2] = EVGA_X12_DIRECTION_GET;
packet[3] = command;
if(!SendReport(packet))
{
return(false);
}
for(unsigned int attempt = 0; attempt < EVGA_X12_READ_ATTEMPTS; attempt++)
{
std::this_thread::sleep_for(std::chrono::milliseconds(EVGA_X12_READ_DELAY_MS));
std::memset(packet, 0, EVGA_X12_REPORT_SIZE);
packet[0] = EVGA_X12_REPORT_ID;
int bytes_read = hid_get_feature_report(dev, packet, EVGA_X12_REPORT_SIZE);
if(bytes_read == EVGA_X12_REPORT_SIZE && packet[1] == EVGA_X12_HEADER && packet[3] == command)
{
return(true);
}
if(bytes_read < 0)
{
LOG_DEBUG("[%s] Error reading feature report: %ls", name.c_str(), hid_error(dev));
return(false);
}
}
LOG_VERBOSE("[%s] Retries exhausted reading command 0x%02X", name.c_str(), command);
return(false);
}
bool EVGAX12Controller::SendReport(const unsigned char* packet)
{
int bytes_written = hid_send_feature_report(dev, packet, EVGA_X12_REPORT_SIZE);
if(bytes_written != EVGA_X12_REPORT_SIZE)
{
LOG_DEBUG("[%s] Error writing feature report: %ls", name.c_str(), hid_error(dev));
return(false);
}
return(true);
}
@@ -0,0 +1,75 @@
/*---------------------------------------------------------*\
| EVGAX12Controller.h |
| |
| Driver for the EVGA X12 gaming mouse |
| |
| QuickMythril 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <mutex>
#include <string>
#include <vector>
#include <hidapi.h>
#include "RGBController.h"
#define EVGA_X12_REPORT_ID 0x07
#define EVGA_X12_REPORT_SIZE 40
#define EVGA_X12_LED_COUNT 4
#define EVGA_X12_BRIGHTNESS_MIN 0
#define EVGA_X12_BRIGHTNESS_MAX 255
enum
{
EVGA_X12_MODE_OFF = 0,
EVGA_X12_MODE_STATIC = 1,
};
enum
{
EVGA_X12_LED_HEAD_LEFT = 0,
EVGA_X12_LED_HEAD_RIGHT = 1,
EVGA_X12_LED_WHEEL = 2,
EVGA_X12_LED_LOGO = 3,
};
struct EVGAX12LightingState
{
std::array<unsigned char, EVGA_X12_LED_COUNT> modes;
std::array<unsigned char, EVGA_X12_LED_COUNT> brightness;
std::array<RGBColor, EVGA_X12_LED_COUNT> colors;
bool modes_valid;
bool static_valid;
};
class EVGAX12Controller
{
public:
EVGAX12Controller(hid_device* dev_handle, const hid_device_info& info, const std::string& dev_name);
~EVGAX12Controller();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
EVGAX12LightingState GetLightingState();
bool SetMode(unsigned char mode);
bool SetStatic(const std::vector<RGBColor>& colors, unsigned char brightness);
bool SetStaticAndActivate(const std::vector<RGBColor>& colors, unsigned char brightness);
private:
bool GetReport(unsigned char command, unsigned char* packet);
bool SetModeReport(unsigned char mode);
bool SetStaticReport(const std::vector<RGBColor>& colors, unsigned char brightness);
bool SendReport(const unsigned char* packet);
hid_device* dev;
std::string location;
std::string name;
std::mutex device_mutex;
};
@@ -0,0 +1,40 @@
/*---------------------------------------------------------*\
| EVGAX12ControllerDetect.cpp |
| |
| Detector for the EVGA X12 gaming mouse |
| |
| QuickMythril 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "DetectionManager.h"
#include "EVGAX12Controller.h"
#include "RGBController_EVGAX12.h"
#define EVGA_USB_VID 0x3842
#define EVGA_X12_PID 0x2422
#define EVGA_X12_INTERFACE 1
#define EVGA_X12_USAGE_PAGE 0x0008
#define EVGA_X12_USAGE 0x004B
DetectedControllers DetectEVGAX12(hid_device_info* info, const std::string& name)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
EVGAX12Controller* controller = new EVGAX12Controller(dev, *info, name);
RGBController_EVGAX12* rgb_controller = new RGBController_EVGAX12(controller);
detected_controllers.push_back(rgb_controller);
}
return(detected_controllers);
}
REGISTER_HID_DETECTOR_IPU("EVGA X12 Gaming Mouse", DetectEVGAX12, EVGA_USB_VID, EVGA_X12_PID, EVGA_X12_INTERFACE, EVGA_X12_USAGE_PAGE, EVGA_X12_USAGE);
@@ -0,0 +1,151 @@
/*---------------------------------------------------------*\
| RGBController_EVGAX12.cpp |
| |
| RGBController for the EVGA X12 gaming mouse |
| |
| QuickMythril 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_EVGAX12.h"
/**------------------------------------------------------------------*\
@name EVGA X12 Gaming Mouse
@category Mouse
@type USB
@save :x:
@direct :white_check_mark:
@effects :x:
@detectors DetectEVGAX12
@comment Lighting changes are volatile and revert to the onboard
profile when the mouse is reconnected.
\*-------------------------------------------------------------------*/
RGBController_EVGAX12::RGBController_EVGAX12(EVGAX12Controller* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "EVGA";
type = DEVICE_TYPE_MOUSE;
description = "EVGA X12 Gaming Mouse";
serial = controller->GetSerialString();
location = controller->GetDeviceLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = EVGA_X12_MODE_STATIC;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Direct.brightness_min = EVGA_X12_BRIGHTNESS_MIN;
Direct.brightness_max = EVGA_X12_BRIGHTNESS_MAX;
Direct.brightness = EVGA_X12_BRIGHTNESS_MAX;
Direct.color_mode = MODE_COLORS_PER_LED;
direct_mode_index = modes.size();
modes.push_back(Direct);
mode Off;
Off.name = "Off";
Off.value = EVGA_X12_MODE_OFF;
Off.color_mode = MODE_COLORS_NONE;
off_mode_index = modes.size();
modes.push_back(Off);
active_mode = direct_mode_index;
SetupZones();
EVGAX12LightingState current_state = controller->GetLightingState();
if(current_state.static_valid)
{
modes[direct_mode_index].brightness = current_state.brightness[0];
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
colors[led_idx] = current_state.colors[led_idx];
}
}
if(current_state.modes_valid)
{
bool all_off = true;
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
if(current_state.modes[led_idx] != EVGA_X12_MODE_OFF)
{
all_off = false;
break;
}
}
if(all_off)
{
active_mode = off_mode_index;
}
}
}
RGBController_EVGAX12::~RGBController_EVGAX12()
{
Shutdown();
delete controller;
}
void RGBController_EVGAX12::SetupZones()
{
const char* zone_names[EVGA_X12_LED_COUNT] =
{
"Left Head",
"Right Head",
"Scroll Wheel",
"Logo",
};
for(unsigned int led_idx = 0; led_idx < EVGA_X12_LED_COUNT; led_idx++)
{
zone new_zone;
new_zone.name = zone_names[led_idx];
new_zone.type = ZONE_TYPE_SINGLE;
new_zone.leds_min = 1;
new_zone.leds_max = 1;
new_zone.leds_count = 1;
zones.push_back(new_zone);
led new_led;
new_led.name = std::string(zone_names[led_idx]) + " LED";
new_led.value = led_idx;
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_EVGAX12::DeviceUpdateLEDs()
{
controller->SetStatic(colors, modes[direct_mode_index].brightness);
}
void RGBController_EVGAX12::DeviceUpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_EVGAX12::DeviceUpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_EVGAX12::DeviceUpdateMode()
{
if(modes[active_mode].value == EVGA_X12_MODE_OFF)
{
controller->SetMode(EVGA_X12_MODE_OFF);
}
else
{
controller->SetStaticAndActivate(colors, modes[direct_mode_index].brightness);
}
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_EVGAX12.h |
| |
| RGBController for the EVGA X12 gaming mouse |
| |
| QuickMythril 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "EVGAX12Controller.h"
#include "RGBController.h"
class RGBController_EVGAX12 : public RGBController
{
public:
RGBController_EVGAX12(EVGAX12Controller* controller_ptr);
~RGBController_EVGAX12();
void DeviceUpdateLEDs();
void DeviceUpdateZoneLEDs(int zone);
void DeviceUpdateSingleLED(int led);
void DeviceUpdateMode();
private:
void SetupZones();
EVGAX12Controller* controller;
unsigned int direct_mode_index;
unsigned int off_mode_index;
};
@@ -197,3 +197,5 @@ DetectedControllers DetectFaustusControllers()
}
REGISTER_DETECTOR("Faustus", DetectFaustusControllers);
REGISTER_CUSTOM_UDEV_RULE(faustus, "ASUS TUF Laptops (faustus)", "ACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_blue\"\nACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_flags\"\nACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_green\"\nACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_mode\"\nACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_red\"\nACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_set\"\nACTION==\"add\", SUBSYSTEM==\"platform\", KERNEL==\"faustus\", RUN+=\"/usr/bin/env chmod a+w /sys/bus/platform/devices/%k/kbbl/kbbl_speed\"");
@@ -109,5 +109,6 @@ REGISTER_I2C_PCI_DETECTOR("GALAX GeForce RTX 2070 SUPER EX Gamer Black", Dete
REGISTER_I2C_PCI_DETECTOR("KFA2 GeForce RTX 2080 EX OC", DetectGalaxGPUControllers, NVIDIA_VEN, NVIDIA_RTX2080_DEV, NVIDIA_SUB_VEN, KFA2_RTX_2080_EX_OC_SUB_DEV, 0x23);
REGISTER_I2C_PCI_DETECTOR("KFA2 GeForce RTX 2080 SUPER EX OC", DetectGalaxGPUControllers, NVIDIA_VEN, NVIDIA_RTX2080S_DEV, NVIDIA_SUB_VEN, KFA2_RTX_2080_SUPER_EX_OC_SUB_DEV, 0x23);
REGISTER_I2C_PCI_DETECTOR("KFA2 GeForce RTX 2080 Ti EX OC", DetectGalaxGPUControllers, NVIDIA_VEN, NVIDIA_RTX2080TI_DEV, NVIDIA_SUB_VEN, KFA2_RTX_2080TI_EX_OC_SUB_DEV, 0x23);
REGISTER_I2C_PCI_DETECTOR("GALAX GeForce RTX 3070 1-Click OC", DetectGalaxGPUControllers, NVIDIA_VEN, NVIDIA_RTX3070_DEV, NVIDIA_SUB_VEN, GALAX_RTX_3070_1_CLICK_OC_SUB_DEV, 0x23);
REGISTER_I2C_PCI_DETECTOR("GALAX GeForce RTX 3080 SG", DetectGalaxGPUControllers, NVIDIA_VEN, NVIDIA_RTX3080_DEV, NVIDIA_SUB_VEN, GALAX_RTX_3080_SG_SUB_DEV, 0x23);
REGISTER_I2C_PCI_DETECTOR("GALAX GeForce RTX 5070 Ti EX Gamer 1-Click OC", DetectGalaxGPUControllers, NVIDIA_VEN, NVIDIA_RTX5070TI_DEV, NVIDIA_SUB_VEN, GALAX_RTX_5070TI_EX_OC_SUB_DEV, 0x51);
@@ -0,0 +1,70 @@
/*---------------------------------------------------------*\
| GameSirController.cpp |
| |
| GameSir RGB Device |
| |
| Added by OpenRGB Community 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "GameSirController.h"
#include <cstring>
#include "StringUtils.h"
GameSirController::GameSirController(hid_device* dev_handle, const char* path)
{
dev = dev_handle;
location = path;
}
GameSirController::~GameSirController()
{
hid_close(dev);
}
std::string GameSirController::GetLocation()
{
return("HID: " + location);
}
std::string GameSirController::GetSerialString()
{
wchar_t serial_string[128];
memset(serial_string, 0x00, sizeof(serial_string));
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
void GameSirController::SetColor(unsigned char red, unsigned char green, unsigned char blue)
{
unsigned char buf[64];
memset(buf, 0x00, sizeof(buf));
buf[0] = 0x05;
buf[1] = 0x08;
buf[2] = 0x0A;
buf[3] = 0x01;
buf[4] = 0x03;
buf[5] = red;
buf[6] = green;
buf[7] = blue;
buf[8] = 0x00;
unsigned int checksum = 0;
for(int i = 0; i < 9; i++)
{
checksum += buf[i];
}
buf[9] = checksum & 0xFF;
hid_write(dev, buf, sizeof(buf));
}
@@ -0,0 +1,31 @@
/*---------------------------------------------------------*\
| GameSirController.h |
| |
| GameSir RGB Device |
| |
| Added by OpenRGB Community 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
class GameSirController
{
public:
GameSirController(hid_device* dev_handle, const char* path);
~GameSirController();
std::string GetLocation();
std::string GetSerialString();
void SetColor(unsigned char red, unsigned char green, unsigned char blue);
private:
hid_device* dev;
std::string location;
};
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| GameSirControllerDetect.cpp |
| |
| GameSir RGB Device |
| |
| Added by OpenRGB Community 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "DetectionManager.h"
#include "RGBController_GameSir.h"
#define GAMESIR_VID 0x3537
#define GAMESIR_NOVA_LITE_2_PID 0x100F
DetectedControllers DetectGameSirControllers(hid_device_info* info, const std::string& /*name*/)
{
DetectedControllers detected_controllers;
hid_device* dev = hid_open_path(info->path);
if(dev)
{
GameSirController* controller = new GameSirController(dev, info->path);
RGBController_GameSir* rgb_controller = new RGBController_GameSir(controller);
detected_controllers.push_back(rgb_controller);
}
return detected_controllers;
}
REGISTER_HID_DETECTOR_IPU("GameSir Nova 2 Lite", DetectGameSirControllers, GAMESIR_VID, GAMESIR_NOVA_LITE_2_PID, 2, 0xFF7A, 0x0001);
@@ -0,0 +1,75 @@
/*---------------------------------------------------------*\
| RGBController_GameSir.cpp |
| |
| GameSir RGB Device |
| |
| Added by OpenRGB Community 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_GameSir.h"
RGBController_GameSir::RGBController_GameSir(GameSirController* controller_ptr)
{
controller = controller_ptr;
name = "GameSir Nova 2 Lite";
vendor = "GameSir";
type = DEVICE_TYPE_GAMEPAD;
description = "GameSir RGB Device";
location = controller->GetLocation();
serial = controller->GetSerialString();
mode Static;
Static.name = "Static";
Static.value = 0xFFFF;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Static.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Static);
SetupZones();
}
RGBController_GameSir::~RGBController_GameSir()
{
delete controller;
}
void RGBController_GameSir::SetupZones()
{
zone new_zone;
new_zone.name = "Controller";
new_zone.type = ZONE_TYPE_SINGLE;
new_zone.leds_min = 1;
new_zone.leds_max = 1;
new_zone.leds_count = 1;
zones.push_back(new_zone);
led new_led;
new_led.name = "Main LED";
leds.push_back(new_led);
SetupColors();
}
void RGBController_GameSir::DeviceUpdateLEDs()
{
controller->SetColor(RGBGetRValue(colors[0]), RGBGetGValue(colors[0]), RGBGetBValue(colors[0]));
}
void RGBController_GameSir::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_GameSir::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_GameSir::DeviceUpdateMode()
{
DeviceUpdateLEDs();
}
@@ -0,0 +1,32 @@
/*---------------------------------------------------------*\
| RGBController_GameSir.h |
| |
| GameSir RGB Device |
| |
| Added by OpenRGB Community 08 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "GameSirController.h"
class RGBController_GameSir : public RGBController
{
public:
RGBController_GameSir(GameSirController* controller_ptr);
~RGBController_GameSir();
void SetupZones();
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
GameSirController* controller;
};
@@ -145,3 +145,4 @@ REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS Radeon RX 9070 XT Elite",
REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 9070 XT GAMING OC", DetectGigabyteRGBFusion2BlackwellGamingLayoutGPUControllers, AMD_GPU_VEN, AMD_NAVI48_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RX9070XT_GAMING_OC_16G_SUB_DEV, 0x75);
REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 9070 XT GAMING OC ICE", DetectGigabyteRGBFusion2BlackwellGamingLayoutGPUControllers, AMD_GPU_VEN, AMD_NAVI48_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RX9070XT_GAMING_OC_ICE_16G_SUB_DEV, 0x75);
REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 9070 XT GAMING", DetectGigabyteRGBFusion2BlackwellGamingLayoutGPUControllers, AMD_GPU_VEN, AMD_NAVI48_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RX9070XT_GAMING_16G_SUB_DEV, 0x75);
REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 9070 GAMING OC", DetectGigabyteRGBFusion2BlackwellGamingLayoutGPUControllers, AMD_GPU_VEN, AMD_NAVI48_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RX9070_GAMING_OC_16G_SUB_DEV, 0x75);
@@ -108,6 +108,7 @@ REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 SUPER Waterforce WB",
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 SUPER Waterforce WB", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX2080S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX2080S_WATERFORCE_WB_SUB_DEV_P,0x51);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 SUPER Waterforce", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX2080S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX2080S_WATERFORCE_SUB_DEV_H, 0x08);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 SUPER Waterforce", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX2080S_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX2080S_WATERFORCE_SUB_DEV_P, 0x08);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 Ti 11G", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX2080TI_A_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX2080TI_11G_SUB_DEV_H, 0x50);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 Ti XTREME", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX2080TI_A_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX2080TI_EXTREME_SUB_DEV_H, 0x50);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 2080 Ti XTREME", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX2080TI_A_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX2080TI_EXTREME_SUB_DEV_P, 0x50);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 3060 ELITE", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX3060_GA104_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX3060_ELITE_12GB_SUB_DEV, 0x70);
@@ -160,6 +161,7 @@ REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4090 AERO OC",
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4090 GAMING OC", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX4090_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX4090_GAMING_OC_24G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 4090 MASTER", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX4090_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX4090_MASTER_24G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 5090 D MASTER", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX5090D_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX5090D_MASTER_32G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 5080 GAMING OC", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX5080_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX5080_GAMING_OC_16G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 5090 GAMING OC", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX5090D_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX5090_GAMING_OC_32G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 5090 MASTER", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX5090_MASTER_32G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS GeForce RTX 5090 MASTER ICE", DetectGigabyteRGBFusion2GPUControllers, NVIDIA_VEN, NVIDIA_RTX5090_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RTX5090_MASTER_ICE_32G_SUB_DEV, 0x71);
@@ -181,6 +183,7 @@ REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 7900 XT GAMING OC",
REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 7900 XTX GAMING OC", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI31_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RX7900XTX_GAMING_OC_24G_SUB_DEV, 0x62);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS Radeon RX 7900 XTX ELITE 24G", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI31_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RX7900XTX_ELITE_24G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS RX 6750 XT ELITE 12G", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI22_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RX_6750_XT_ELITE_12G_SUB_DEV, 0x70);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS RX 6900 XT MASTER rev 2.0", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI21_DEV2, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RX6900XT_MASTER_SUB_DEV, 0x70);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS RX 6900 XT EXTREME WATERFORCE WB", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI21_DEV2, GIGABYTE_SUB_VEN, GIGABYTE_RX6900XT_XTREME_WATERFORCE_WB_SUB_DEV, 0x70);
REGISTER_I2C_PCI_DETECTOR("Gigabyte AORUS Radeon RX 9070 XT Elite", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI48_DEV, GIGABYTE_SUB_VEN, GIGABYTE_AORUS_RX9070XT_ELITE_16G_SUB_DEV, 0x73);
REGISTER_I2C_PCI_DETECTOR("Gigabyte Radeon RX 9070 XT GAMING OC", DetectGigabyteRGBFusion2GPUControllers, AMD_GPU_VEN, AMD_NAVI48_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RX9070XT_GAMING_OC_16G_SUB_DEV, 0x73);
@@ -56,6 +56,7 @@ json rgb_fusion_2_smbus_motherboards[] =
"X470 AORUS ULTRA GAMING",
"X470 AORUS ULTRA GAMING-CF",
"B360M AORUS Gaming 3-CF",
"B360 AORUS GAMING 3 WIFI-CF",
"Z370 AORUS Gaming 5-CF",
"Z370 AORUS Ultra Gaming-CF"
};
@@ -182,4 +182,5 @@ REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 3090 Gaming OC",
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4060 Gaming OC", DetectGigabyteRGBFusionGPUControllers, NVIDIA_VEN, NVIDIA_RTX4060_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX4060_GAMING_OC_8G_SUB_DEV, 0x55);
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4060 Ti Gaming OC", DetectGigabyteRGBFusionGPUControllers, NVIDIA_VEN, NVIDIA_RTX4060TI_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX4060TI_GAMING_OC_8G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4060 Ti Gaming OC", DetectGigabyteRGBFusionGPUControllers, NVIDIA_VEN, NVIDIA_RTX4060TI_16G_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX4060TI_GAMING_OC_16G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4060 Ti AERO OC", DetectGigabyteRGBFusionGPUControllers, NVIDIA_VEN, NVIDIA_RTX4060TI_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX4060TI_AERO_OC_16G_SUB_DEV, 0x71);
REGISTER_I2C_PCI_DETECTOR("Gigabyte GeForce RTX 4070 Ti SUPER EAGLE OC", DetectGigabyteRGBFusionGPUControllers, NVIDIA_VEN, NVIDIA_RTX4070TIS_DEV, GIGABYTE_SUB_VEN, GIGABYTE_RTX4070TIS_EAGLE_OC_16G_SUB_DEV, 0x71);
@@ -12,6 +12,18 @@
#include "GigabyteSuperIORGBController.h"
#include "super_io.h"
void GigabyteSuperIOEnter(int sioaddr)
{
/*-----------------------------------------------------*\
| ITE8620 Ambient LED Extended Function Mode sequence |
\*-----------------------------------------------------*/
superio_enter(sioaddr);
superio_inb(sioaddr, GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_1);
superio_inb(sioaddr, GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_2);
superio_inb(sioaddr, GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_3);
superio_inb(sioaddr, GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_4);
}
GigabyteSuperIORGBController::GigabyteSuperIORGBController(int sioaddr, std::string dev_name)
{
gig_sioaddr = sioaddr;
@@ -40,10 +52,7 @@ void GigabyteSuperIORGBController::ChipEntry()
/*--------------------------------*\
| Chip Entry Command |
\*_-------------------------------*/
superio_enter(gig_sioaddr);
superio_outb(gig_sioaddr, GIGABYTE_SUPERIO_CHIPENTRY_REGISTER_1, GIGABYTE_SUPERIO_CHIPENTRY_VALUE_1);
superio_outb(gig_sioaddr, GIGABYTE_SUPERIO_CHIPENTRY_REGISTER_2, GIGABYTE_SUPERIO_CHIPENTRY_VALUE_2);
superio_outb(gig_sioaddr, GIGABYTE_SUPERIO_CHIPENTRY_REGISTER_2, GIGABYTE_SUPERIO_CHIPENTRY_VALUE_2);
GigabyteSuperIOEnter(gig_sioaddr);
/*--------------------------------*\
| Chip Select Command |
@@ -15,6 +15,14 @@
enum
{
/*-----------------------------------*\
| Extended Function Mode Entry Values |
\*_----------------------------------*/
GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_1 = 0x87,
GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_2 = 0x01,
GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_3 = 0x55,
GIGABYTE_SUPERIO_EXTENDED_FUNCTION_ENTRY_4 = 0x55,
/*--------------------------------*\
| Chip Entry Registers and Values |
\*_-------------------------------*/
@@ -129,6 +137,8 @@ enum
};
void GigabyteSuperIOEnter(int sioaddr);
class GigabyteSuperIORGBController
{
public:
@@ -24,7 +24,8 @@ typedef struct
static gig_device compatible_devices[] =
{
{"X570 UD"}
{"X570 UD"},
{"Z390 DESIGNARE-CF"}
};
DetectedControllers DetectGigabyteSuperIORGBControllers()
@@ -41,12 +42,13 @@ DetectedControllers DetectGigabyteSuperIORGBControllers()
{
int sioaddr = sio_addrs[sioaddr_idx];
superio_enter(sioaddr);
GigabyteSuperIOEnter(sioaddr);
int val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | superio_inb(sioaddr, SIO_REG_DEVID + 1);
switch(val & SIO_ID_MASK)
{
case SIO_ITE8620_ID:
case SIO_ITE8688_ID:
for(unsigned int i = 0; i < NUM_COMPATIBLE_DEVICES; i++)
{
@@ -270,6 +270,33 @@ void GoveeController::SendRazerEnable()
port.udp_write((char *)command_str.c_str(), (int)command_str.length() + 1);
}
void GoveeController::SetBrightness(unsigned int brightness)
{
json command;
command["msg"]["cmd"] = "brightness";
command["msg"]["data"]["value"] = std::min(brightness, 100u);
/*-----------------------------------------------------*\
| Convert the JSON object to a string and write it |
\*-----------------------------------------------------*/
std::string command_str = command.dump();
port.udp_write((char *)command_str.c_str(), (int)command_str.length() + 1);
}
void GoveeController::SetPower(bool enabled)
{
json command;
command["msg"]["cmd"] = "turn";
command["msg"]["data"]["value"] = enabled ? 1 : 0;
std::string command_str = command.dump();
port.udp_write((char *)command_str.c_str(), (int)command_str.length() + 1);
}
void GoveeController::SendScan()
{
json command;
@@ -35,7 +35,9 @@ public:
void SendScan();
void SetBrightness(unsigned int brightness);
void SetColor(unsigned char red, unsigned char green, unsigned char blue);
void SetPower(bool enabled);
private:
std::string firmware_version;
@@ -20,22 +20,33 @@ struct GoveeHardwareInfo
{
unsigned int led_count;
unsigned int matrix_row_len; // 0 = linear
bool supports_razer;
};
const unsigned int GOVEE_FALLBACK_LED_COUNT = 20;
const unsigned int GOVEE_FALLBACK_LED_COUNT = 1;
static std::map<std::string, GoveeHardwareInfo> govee_hardware_info
{
{ "H6022", { 132, 12 } }, // Govee Smart Table Lamp 2
{ "H612F", { 12, 0 } }, // Govee Strip Light S (3m)
{ "H619A", { 20, 0 } }, // Govee RGBIC Led Strip Lights
{ "H70B1", { 20, 0 } }, // Govee LED Curtain Lights
{ "H607C", { 174, 0 } }, // Govee Floor Lamp 2
{ "H6022", { 132, 12, true } }, // Govee Smart Table Lamp 2
{ "H612F", { 12, 0, true } }, // Govee Strip Light S (3m)
{ "H619A", { 20, 0, true } }, // Govee RGBIC Led Strip Lights
{ "H70B1", { 20, 0, true } }, // Govee LED Curtain Lights
{ "H607C", { 174, 0, true } }, // Govee Floor Lamp 2
};
enum
{
GOVEE_MODE_STATIC = 0,
GOVEE_MODE_DIRECT = 1,
};
RGBController_Govee::RGBController_Govee(GoveeController* controller_ptr)
{
controller = controller_ptr;
controller = controller_ptr;
last_static_color = 0;
last_static_brightness = 0;
razer_supported = false;
static_initialized = false;
name = "Govee " + controller->GetSku();
vendor = "Govee";
@@ -45,25 +56,32 @@ RGBController_Govee::RGBController_Govee(GoveeController* controller_ptr)
version = controller->GetVersion();
mode Static;
Static.name = "Static";
Static.value = 1;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.colors_min = 1;
Static.colors_max = 1;
Static.name = "Static";
Static.value = GOVEE_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Static.brightness_min = 0;
Static.brightness_max = 100;
Static.brightness = 100;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(1);
modes.push_back(Static);
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
Direct.name = "Direct";
Direct.value = GOVEE_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Direct.brightness_min = 0;
Direct.brightness_max = 100;
Direct.brightness = 100;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
SetupZones();
keepalive_thread_run = 1;
last_update_time = std::chrono::steady_clock::now();
keepalive_thread = new std::thread(&RGBController_Govee::KeepaliveThread, this);
}
@@ -80,20 +98,19 @@ RGBController_Govee::~RGBController_Govee()
void RGBController_Govee::SetupZones()
{
GoveeHardwareInfo hw = { GOVEE_FALLBACK_LED_COUNT, 0 };
bool resizable = true;
GoveeHardwareInfo hw = { GOVEE_FALLBACK_LED_COUNT, 0, false };
std::map<std::string, GoveeHardwareInfo>::iterator it = govee_hardware_info.find(controller->GetSku());
if(it != govee_hardware_info.end())
{
hw = it->second;
resizable = false;
razer_supported = hw.supports_razer;
}
zone strip;
strip.leds_count = hw.led_count;
strip.leds_min = resizable ? 0 : hw.led_count;
strip.leds_max = resizable ? 255 : hw.led_count;
strip.leds_min = hw.led_count;
strip.leds_max = hw.led_count;
if(hw.matrix_row_len == 0)
{
@@ -171,14 +188,40 @@ void RGBController_Govee::DeviceConfigureZone(int zone_idx)
void RGBController_Govee::DeviceUpdateLEDs()
{
last_update_time = std::chrono::steady_clock::now();
if(modes[active_mode].color_mode == MODE_COLORS_PER_LED)
if(colors.empty())
{
if(!colors.empty())
return;
}
const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
last_update_time = now;
const unsigned int brightness = modes[active_mode].brightness;
if(razer_supported)
{
controller->SendRazerData(&colors[0], (unsigned int)colors.size());
controller->SetBrightness(brightness);
}
else
{
if(!static_initialized)
{
controller->SendRazerData(&colors[0], (unsigned int)colors.size());
controller->SetPower(true);
}
controller->SetColor
(
RGBGetRValue(colors[0]),
RGBGetGValue(colors[0]),
RGBGetBValue(colors[0])
);
controller->SetBrightness(brightness);
last_static_color = colors[0];
last_static_brightness = brightness;
static_initialized = true;
}
}
@@ -194,28 +237,59 @@ void RGBController_Govee::DeviceUpdateSingleLED(int /*led*/)
void RGBController_Govee::DeviceUpdateMode()
{
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
if(modes[active_mode].value == GOVEE_MODE_STATIC)
{
unsigned char red = RGBGetRValue(modes[active_mode].colors[0]);
unsigned char grn = RGBGetGValue(modes[active_mode].colors[0]);
unsigned char blu = RGBGetBValue(modes[active_mode].colors[0]);
controller->SetColor(red, grn, blu);
UpdateStatic(false);
}
else
else if(modes[active_mode].value == GOVEE_MODE_DIRECT)
{
controller->SendRazerEnable();
if(razer_supported)
{
controller->SendRazerEnable();
}
last_update_time = std::chrono::steady_clock::now();
DeviceUpdateLEDs();
}
}
void RGBController_Govee::UpdateStatic(bool force)
{
last_update_time = std::chrono::steady_clock::now();
const RGBColor color = modes[active_mode].colors[0];
const unsigned int brightness = modes[active_mode].brightness;
if(force || !static_initialized || (color != last_static_color))
{
controller->SetPower(true);
controller->SetColor(RGBGetRValue(color), RGBGetGValue(color), RGBGetBValue(color));
last_static_color = color;
}
if(force || !static_initialized || (brightness != last_static_brightness))
{
controller->SetBrightness(brightness);
last_static_brightness = brightness;
}
static_initialized = true;
}
void RGBController_Govee::KeepaliveThread()
{
while(keepalive_thread_run.load())
{
if((std::chrono::steady_clock::now() - last_update_time) > std::chrono::seconds(30))
const std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
if((now - last_update_time) > std::chrono::seconds(30))
{
DeviceUpdateLEDs();
if(modes[active_mode].value == GOVEE_MODE_STATIC)
{
UpdateStatic(true);
}
}
std::this_thread::sleep_for(10s);
}
}
@@ -32,8 +32,14 @@ public:
void KeepaliveThread();
private:
void UpdateStatic(bool force);
GoveeController* controller;
std::thread* keepalive_thread;
std::atomic<bool> keepalive_thread_run;
std::chrono::time_point<std::chrono::steady_clock> last_update_time;
RGBColor last_static_color;
unsigned int last_static_brightness;
bool razer_supported;
bool static_initialized;
};
@@ -0,0 +1,344 @@
/*---------------------------------------------------------*\
| HIDLampArrayController.cpp |
| |
| Driver for HID LampArray Devices |
| |
| Adam Honse ([email protected]) 26 Mar 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <cstdio>
#include <cstring>
#include "hid_util.h"
#include "HIDLampArrayController.h"
#include "StringUtils.h"
HIDLampArrayController::HIDLampArrayController(hid_device *dev_handle, const char *path)
{
dev = dev_handle;
location = path;
/*-----------------------------------------------------*\
| Parse report IDs from descriptor |
\*-----------------------------------------------------*/
unsigned int curr_collection_usage = 0;
unsigned char data_len = 0;
unsigned char key = 0;
unsigned char key_cmd = 0;
unsigned char key_size = 0;
unsigned int pos = 0;
unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
unsigned char report_id = 0;
unsigned int size = hid_get_report_descriptor(dev, report_descriptor, sizeof(report_descriptor));
unsigned int usage = 0;
unsigned char usage_page = 0;
/*-----------------------------------------------------*\
| Create a list of usages and their report IDs |
\*-----------------------------------------------------*/
std::unordered_map<unsigned int, unsigned int> usage_to_report_id;
while(pos < size)
{
get_hid_item_size(report_descriptor, size, pos, &data_len, &key_size);
key = report_descriptor[pos];
key_cmd = key & 0xFC;
switch(key)
{
case 0xA1:
curr_collection_usage = usage;
if(usage_page == 0x59 && report_id)
{
usage_to_report_id[curr_collection_usage] = report_id;
}
break;
case 0xC0:
curr_collection_usage = 0;
report_id = 0;
break;
}
switch(key_cmd)
{
case 0x4:
usage_page = get_hid_report_bytes(report_descriptor, size, data_len, pos);
break;
case 0x8:
usage = get_hid_report_bytes(report_descriptor, size, data_len, pos);
if(data_len == 4)
{
int local_usage_page = usage >> 16;
usage &= 0x0000FFFF;
if (local_usage_page == 0x59 && report_id)
{
usage_to_report_id[usage] = report_id;
}
}
break;
case 0x84:
report_id = get_hid_report_bytes(report_descriptor, size, data_len, pos);
if (usage_page == 0x59 && curr_collection_usage)
{
usage_to_report_id[curr_collection_usage] = report_id;
}
break;
}
pos += data_len + key_size;
}
/*-----------------------------------------------------*\
| Get the report IDs for each report |
\*-----------------------------------------------------*/
for(const std::pair<const unsigned int, unsigned int>& pair : usage_to_report_id)
{
switch(pair.first)
{
case 0x02:
ids.LampArrayAttributesReportID = pair.second;
break;
case 0x20:
ids.LampAttributesRequestReportID = pair.second;
break;
case 0x22:
ids.LampAttributesResponseReportID = pair.second;
break;
case 0x50:
ids.LampMultiUpdateReportID = pair.second;
break;
case 0x60:
ids.LampRangeUpdateReportID = pair.second;
break;
case 0x70:
ids.LampArrayControlReportID = pair.second;
break;
}
}
/*-----------------------------------------------------*\
| If reports are missing, return |
\*-----------------------------------------------------*/
bool report_missing = (ids.LampArrayAttributesReportID == 0)
|| (ids.LampAttributesRequestReportID == 0)
|| (ids.LampAttributesResponseReportID == 0)
|| (ids.LampMultiUpdateReportID == 0)
|| (ids.LampRangeUpdateReportID == 0)
|| (ids.LampArrayControlReportID == 0);
if(report_missing)
{
LampArray.LampCount = 0;
LampArray.LampArrayKind = HID_LAMPARRAY_KIND_UNDEFINED;
return;
}
/*-----------------------------------------------------*\
| Get LampArrayAttributesReport |
\*-----------------------------------------------------*/
GetLampArrayAttributesReport();
/*-----------------------------------------------------*\
| Set LampAttributesRequestReport for LampId 0 |
\*-----------------------------------------------------*/
SetLampAttributesRequestReport(0);
/*-----------------------------------------------------*\
| Get LampAttributesResponseReport for each LampId |
\*-----------------------------------------------------*/
for(unsigned int LampId = 0; LampId < LampArray.LampCount; LampId++)
{
GetLampAttributesResponseReport();
}
}
HIDLampArrayController::~HIDLampArrayController()
{
hid_close(dev);
}
std::string HIDLampArrayController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string HIDLampArrayController::GetDeviceName()
{
wchar_t name_string[128];
int ret = hid_get_product_string(dev, name_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(name_string));
}
std::string HIDLampArrayController::GetDeviceSerial()
{
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string HIDLampArrayController::GetDeviceVendor()
{
wchar_t vendor_string[128];
int ret = hid_get_manufacturer_string(dev, vendor_string, 128);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(vendor_string));
}
unsigned int HIDLampArrayController::GetLampArrayKind()
{
return(LampArray.LampArrayKind);
}
unsigned int HIDLampArrayController::GetLampCount()
{
return(LampArray.LampCount);
}
std::vector<LampAttributes> HIDLampArrayController::GetLamps()
{
return(Lamps);
}
void HIDLampArrayController::GetLampArrayAttributesReport()
{
unsigned char usb_buf[sizeof(LampArrayAttributes) + 1];
memset(usb_buf, 0, sizeof(usb_buf));
/*-----------------------------------------------------*\
| First byte is the report ID |
\*-----------------------------------------------------*/
usb_buf[0] = ids.LampArrayAttributesReportID;
/*-----------------------------------------------------*\
| Get the report |
\*-----------------------------------------------------*/
hid_get_feature_report(dev, usb_buf, sizeof(usb_buf));
memcpy(&LampArray, &usb_buf[1], sizeof(LampArray));
}
void HIDLampArrayController::GetLampAttributesResponseReport()
{
unsigned char usb_buf[65];
LampAttributes attributes;
memset(usb_buf, 0, sizeof(usb_buf));
/*-----------------------------------------------------*\
| First byte is the report ID |
\*-----------------------------------------------------*/
usb_buf[0] = ids.LampAttributesResponseReportID;
/*-----------------------------------------------------*\
| Get the report |
\*-----------------------------------------------------*/
hid_get_feature_report(dev, usb_buf, sizeof(usb_buf));
memcpy(&attributes, &usb_buf[1], sizeof(attributes));
/*-----------------------------------------------------*\
| Store the attributes |
\*-----------------------------------------------------*/
Lamps.push_back(attributes);
}
void HIDLampArrayController::SetLampArrayControlReport(unsigned char AutonomousMode)
{
unsigned char usb_buf[sizeof(LampArrayControl) + 1];
memset(usb_buf, 0, sizeof(usb_buf));
/*-----------------------------------------------------*\
| First byte is the report ID |
\*-----------------------------------------------------*/
usb_buf[0] = ids.LampArrayControlReportID;
/*-----------------------------------------------------*\
| Fill in control data |
\*-----------------------------------------------------*/
((LampArrayControl *)&usb_buf[1])->AutonomousMode = AutonomousMode;
/*-----------------------------------------------------*\
| Send the report |
\*-----------------------------------------------------*/
hid_send_feature_report(dev, usb_buf, sizeof(usb_buf));
}
void HIDLampArrayController::SetLampAttributesRequestReport(unsigned short LampId)
{
unsigned char usb_buf[sizeof(LampAttributesRequest) + 1];
memset(usb_buf, 0, sizeof(usb_buf));
/*-----------------------------------------------------*\
| First byte is the report ID |
\*-----------------------------------------------------*/
usb_buf[0] = ids.LampAttributesRequestReportID;
/*-----------------------------------------------------*\
| Fill in request data |
\*-----------------------------------------------------*/
((LampAttributesRequest *)&usb_buf[1])->LampId = LampId;
/*-----------------------------------------------------*\
| Send the report |
\*-----------------------------------------------------*/
hid_send_feature_report(dev, usb_buf, sizeof(usb_buf));
}
void HIDLampArrayController::SetLampMultiUpdateReport(unsigned char LampCount, unsigned char LampUpdateFlags, unsigned short * LampIds, LampArrayColor * UpdateColors)
{
unsigned char usb_buf[sizeof(LampMultiUpdate) + 1];
memset(usb_buf, 0, sizeof(usb_buf));
/*-----------------------------------------------------*\
| First byte is the report ID |
\*-----------------------------------------------------*/
usb_buf[0] = ids.LampMultiUpdateReportID;
/*-----------------------------------------------------*\
| Fill in multi update data |
\*-----------------------------------------------------*/
((LampMultiUpdate *)&usb_buf[1])->LampCount = LampCount;
((LampMultiUpdate *)&usb_buf[1])->LampUpdateFlags = LampUpdateFlags;
for(unsigned char LampId = 0; LampId < LampCount; LampId++)
{
((LampMultiUpdate *)&usb_buf[1])->LampIds[LampId] = LampIds[LampId];
((LampMultiUpdate *)&usb_buf[1])->UpdateColors[LampId] = UpdateColors[LampId];
}
/*-----------------------------------------------------*\
| Send the report |
\*-----------------------------------------------------*/
hid_send_feature_report(dev, usb_buf, sizeof(usb_buf));
}
@@ -0,0 +1,145 @@
/*---------------------------------------------------------*\
| HIDLampArrayController.h |
| |
| Driver for HID LampArray Devices |
| |
| Adam Honse ([email protected]) 26 Mar 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
#include "RGBController.h"
/*---------------------------------------------------------*\
| Struct packing macro for GCC and MSVC |
\*---------------------------------------------------------*/
#ifdef __GNUC__
#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__))
#endif
#ifdef _MSC_VER
#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop))
#endif
PACK(struct LampArrayAttributes
{
unsigned short LampCount;
unsigned int BoundingBoxWidthInMicrometers;
unsigned int BoundingBoxHeightInMicrometers;
unsigned int BoundingBoxDepthInMicrometers;
unsigned int LampArrayKind;
unsigned int MinUpdateIntervalInMilliseconds;
});
PACK(struct LampArrayColor
{
unsigned char RedChannel;
unsigned char GreenChannel;
unsigned char BlueChannel;
unsigned char IntensityChannel;
});
PACK(struct LampArrayControl
{
unsigned char AutonomousMode;
});
PACK(struct LampAttributes
{
unsigned short LampId;
unsigned int PositionXInMicrometers;
unsigned int PositionYInMicrometers;
unsigned int PositionZInMicrometers;
unsigned int UpdateLatencyInMilliseconds;
unsigned int LampPurposes;
unsigned char RedLevelCount;
unsigned char GreenLevelCount;
unsigned char BlueLevelCount;
unsigned char IntensityLevelCount;
unsigned char IsProgrammable;
unsigned char LampKey;
});
PACK(struct LampAttributesRequest
{
unsigned short LampId;
});
#define LAMP_MULTI_UPDATE_LAMP_COUNT 8
#define LAMP_UPDATE_FLAG_UPDATE_COMPLETE 1
PACK(struct LampMultiUpdate
{
unsigned char LampCount;
unsigned char LampUpdateFlags;
unsigned short LampIds[LAMP_MULTI_UPDATE_LAMP_COUNT];
LampArrayColor UpdateColors[LAMP_MULTI_UPDATE_LAMP_COUNT];
});
typedef struct
{
unsigned char LampArrayAttributesReportID;
unsigned char LampAttributesRequestReportID;
unsigned char LampAttributesResponseReportID;
unsigned char LampMultiUpdateReportID;
unsigned char LampRangeUpdateReportID;
unsigned char LampArrayControlReportID;
} HIDLampArrayReportIDs;
enum
{
HID_LAMPARRAY_KIND_UNDEFINED = 0x00, /* Undefined */
HID_LAMPARRAY_KIND_KEYBOARD = 0x01, /* LampArrayKindKeyboard */
HID_LAMPARRAY_KIND_MOUSE = 0x02, /* LampArrayKindMouse */
HID_LAMPARRAY_KIND_GAME_CONTROLLER = 0x03, /* LampArrayKindGameController */
HID_LAMPARRAY_KIND_PERIPHERAL = 0x04, /* LampArrayKindPeripheral */
HID_LAMPARRAY_KIND_SCENE = 0x05, /* LampArrayKindScene */
HID_LAMPARRAY_KIND_NOTIFICATION = 0x06, /* LampArrayKindNotification */
HID_LAMPARRAY_KIND_CHASSIS = 0x07, /* LampArrayKindChassis */
HID_LAMPARRAY_KIND_WEARABLE = 0x08, /* LampArrayKindWearable */
HID_LAMPARRAY_KIND_FURNITURE = 0x09, /* LampArrayKindFurniture */
HID_LAMPARRAY_KIND_ART = 0x0A, /* LampArrayKindArt */
};
class HIDLampArrayController
{
public:
HIDLampArrayController(hid_device *dev_handle, const char *path);
~HIDLampArrayController();
std::string GetDeviceLocation();
std::string GetDeviceName();
std::string GetDeviceSerial();
std::string GetDeviceVendor();
unsigned int GetLampArrayKind();
unsigned int GetLampCount();
std::vector<LampAttributes> GetLamps();
void SetLampArrayControlReport(unsigned char AutonomousMode);
void SetLampMultiUpdateReport(unsigned char LampCount, unsigned char LampUpdateFlags, unsigned short * LampIds, LampArrayColor * UpdateColors);
private:
hid_device * dev;
HIDLampArrayReportIDs ids;
std::string location;
/*-----------------------------------------------------*\
| Vector to store lamp attributes for each lamp |
\*-----------------------------------------------------*/
std::vector<LampAttributes> Lamps;
/*-----------------------------------------------------*\
| Parameters from LampArrayAttributesReport |
\*-----------------------------------------------------*/
LampArrayAttributes LampArray;
void GetLampArrayAttributesReport();
void GetLampAttributesResponseReport();
void SetLampAttributesRequestReport(unsigned short LampId);
};
@@ -0,0 +1,50 @@
/*---------------------------------------------------------*\
| HIDLampArrayControllerDetect.cpp |
| |
| Detector for HID LampArray Devices |
| |
| Adam Honse ([email protected]) 26 Mar 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include "DetectionManager.h"
#include "HIDLampArrayController.h"
#include "RGBController.h"
#include "RGBController_HIDLampArray.h"
#include <vector>
#include <hidapi.h>
DetectedControllers DetectHIDLampArrayControllers(hid_device_info* info, const std::string& /*name*/)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
HIDLampArrayController* controller = new HIDLampArrayController(dev, info->path);
/*-------------------------------------------------*\
| Only create the RGBController if there are lamps |
| detected in the controller. Otherwise, delete |
| the controller. |
\*-------------------------------------------------*/
if(controller->GetLampCount() > 0)
{
RGBController_HIDLampArray* rgb_controller = new RGBController_HIDLampArray(controller);
detected_controllers.push_back(rgb_controller);
}
else
{
delete controller;
}
}
return(detected_controllers);
}
REGISTER_HID_DETECTOR_PU_ONLY("HID LampArray Device", DetectHIDLampArrayControllers, 0x59, 0x01);
@@ -0,0 +1,429 @@
/*---------------------------------------------------------*\
| RGBController_HIDLampArray.cpp |
| |
| RGBController for HID LampArray Devices |
| |
| Adam Honse ([email protected]) 26 Mar 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <cstring>
#include <set>
#include "RGBController_HIDLampArray.h"
#include "RGBControllerKeyNames.h"
/**------------------------------------------------------------------*\
@name HID LampArray Controllers
@category Keyboard
@type USB
@detectors DetectHIDLampArrayControllers
\*-------------------------------------------------------------------*/
RGBController_HIDLampArray::RGBController_HIDLampArray(HIDLampArrayController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
description = "HID LampArray Device";
location = controller->GetDeviceLocation();
serial = controller->GetDeviceSerial();
vendor = controller->GetDeviceVendor();
/*-----------------------------------------------------*\
| Determine device type from LampArray kind |
\*-----------------------------------------------------*/
switch(controller->GetLampArrayKind())
{
case HID_LAMPARRAY_KIND_UNDEFINED:
default:
type = DEVICE_TYPE_UNKNOWN;
break;
case HID_LAMPARRAY_KIND_KEYBOARD:
type = DEVICE_TYPE_KEYBOARD;
break;
case HID_LAMPARRAY_KIND_MOUSE:
type = DEVICE_TYPE_MOUSE;
break;
case HID_LAMPARRAY_KIND_GAME_CONTROLLER:
type = DEVICE_TYPE_GAMEPAD;
break;
case HID_LAMPARRAY_KIND_PERIPHERAL:
case HID_LAMPARRAY_KIND_SCENE:
case HID_LAMPARRAY_KIND_NOTIFICATION:
case HID_LAMPARRAY_KIND_CHASSIS:
case HID_LAMPARRAY_KIND_WEARABLE:
case HID_LAMPARRAY_KIND_FURNITURE:
case HID_LAMPARRAY_KIND_ART:
type = DEVICE_TYPE_ACCESSORY;
break;
}
mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Autonomous;
Autonomous.name = "Autonomous";
Autonomous.value = 1;
Autonomous.flags = 0;
Autonomous.color_mode = MODE_COLORS_NONE;
modes.push_back(Autonomous);
SetupZones();
}
RGBController_HIDLampArray::~RGBController_HIDLampArray()
{
delete controller;
}
/*---------------------------------------------------------*\
| HID Usage Tables 1.6 -> 10 Keyboard/Keypad Page (0x07) |
\*---------------------------------------------------------*/
#define HID_KEYBOARD_USAGE_IDS_COUNT 0xE9
static const char *HIDUsageIDsToKeyNames[HID_KEYBOARD_USAGE_IDS_COUNT] =
{
KEY_EN_UNUSED, // Reserved
KEY_EN_UNUSED, // Keyboard ErrorRollOver
KEY_EN_UNUSED, // Keyboard POSTFail
KEY_EN_UNUSED, // Keyboard ErrorUndefined
KEY_EN_A, // Keyboard a and A
KEY_EN_B, // Keyboard b and B
KEY_EN_C, // Keyboard c and C
KEY_EN_D, // Keyboard d and D
KEY_EN_E, // Keyboard e and E
KEY_EN_F, // Keyboard f and F
KEY_EN_G, // Keyboard g and G
KEY_EN_H, // Keyboard h and H
KEY_EN_I, // Keyboard i and I
KEY_EN_J, // Keyboard j and J
KEY_EN_K, // Keyboard k and K
KEY_EN_L, // Keyboard l and L
KEY_EN_M, // Keyboard m and M
KEY_EN_N, // Keyboard n and N
KEY_EN_O, // Keyboard o and O
KEY_EN_P, // Keyboard p and P
KEY_EN_Q, // Keyboard q and Q
KEY_EN_R, // Keyboard r and R
KEY_EN_S, // Keyboard s and S
KEY_EN_T, // Keyboard t and T
KEY_EN_U, // Keyboard u and U
KEY_EN_V, // Keyboard v and V
KEY_EN_W, // Keyboard w and W
KEY_EN_X, // Keyboard x and X
KEY_EN_Y, // Keyboard y and Y
KEY_EN_Z, // Keyboard z and Z
KEY_EN_1, // Keyboard 1 and !
KEY_EN_2, // Keyboard 2 and @
KEY_EN_3, // Keyboard 3 and #
KEY_EN_4, // Keyboard 4 and $
KEY_EN_5, // Keyboard 5 and %
KEY_EN_6, // Keyboard 6 and ∧
KEY_EN_7, // Keyboard 7 and &
KEY_EN_8, // Keyboard 8 and *
KEY_EN_9, // Keyboard 9 and (
KEY_EN_0, // Keyboard 0 and )
KEY_EN_ANSI_ENTER, // Keyboard Return (ENTER)
KEY_EN_ESCAPE, // Keyboard ESCAPE
KEY_EN_BACKSPACE, // Keyboard DELETE (Backspace)
KEY_EN_TAB, // Keyboard Tab
KEY_EN_SPACE, // Keyboard Spacebar
KEY_EN_MINUS, // Keyboard - and (underscore)
KEY_EN_EQUALS, // Keyboard = and +
KEY_EN_LEFT_BRACKET, // Keyboard [ and {
KEY_EN_RIGHT_BRACKET, // Keyboard ] and }
KEY_EN_BACK_SLASH, // Keyboard \ and |
KEY_EN_POUND, // Keyboard Non-US # and ˜
KEY_EN_SEMICOLON, // Keyboard ; and :
KEY_EN_QUOTE, // Keyboard ‘ and “
KEY_EN_BACK_TICK, // Keyboard Grave Accent and Tilde
KEY_EN_COMMA, // Keyboard , and <
KEY_EN_PERIOD, // Keyboard . and >
KEY_EN_FORWARD_SLASH, // Keyboard / and ?
KEY_EN_CAPS_LOCK, // Keyboard Caps Lock
KEY_EN_F1, // Keyboard F1
KEY_EN_F2, // Keyboard F2
KEY_EN_F3, // Keyboard F3
KEY_EN_F4, // Keyboard F4
KEY_EN_F5, // Keyboard F5
KEY_EN_F6, // Keyboard F6
KEY_EN_F7, // Keyboard F7
KEY_EN_F8, // Keyboard F8
KEY_EN_F9, // Keyboard F9
KEY_EN_F10, // Keyboard F10
KEY_EN_F11, // Keyboard F11
KEY_EN_F12, // Keyboard F12
KEY_EN_PRINT_SCREEN, // Keyboard PrintScreen
KEY_EN_SCROLL_LOCK, // Keyboard Scroll Lock
KEY_EN_PAUSE_BREAK, // Keyboard Pause
KEY_EN_INSERT, // Keyboard Insert
KEY_EN_HOME, // Keyboard Home
KEY_EN_PAGE_UP, // Keyboard PageUp
KEY_EN_DELETE, // Keyboard Delete Forward
KEY_EN_END, // Keyboard End
KEY_EN_PAGE_DOWN, // Keyboard PageDown
KEY_EN_RIGHT_ARROW, // Keyboard RightArrow
KEY_EN_LEFT_ARROW, // Keyboard LeftArrow
KEY_EN_DOWN_ARROW, // Keyboard DownArrow
KEY_EN_UP_ARROW, // Keyboard UpArrow
KEY_EN_NUMPAD_LOCK, // Keypad Num Lock and Clear
KEY_EN_NUMPAD_DIVIDE, // Keypad /
KEY_EN_NUMPAD_TIMES, // Keypad *
KEY_EN_NUMPAD_MINUS, // Keypad -
KEY_EN_NUMPAD_PLUS, // Keypad +
KEY_EN_NUMPAD_ENTER, // Keypad ENTER
KEY_EN_NUMPAD_1, // Keypad 1 and End
KEY_EN_NUMPAD_2, // Keypad 2 and Down Arrow
KEY_EN_NUMPAD_3, // Keypad 3 and PageDn
KEY_EN_NUMPAD_4, // Keypad 4 and Left Arrow
KEY_EN_NUMPAD_5, // Keypad 5
KEY_EN_NUMPAD_6, // Keypad 6 and Right Arrow
KEY_EN_NUMPAD_7, // Keypad 7 and Home
KEY_EN_NUMPAD_8, // Keypad 8 and Up Arrow
KEY_EN_NUMPAD_9, // Keypad 9 and PageUp
KEY_EN_NUMPAD_0, // Keypad 0 and Insert
KEY_EN_NUMPAD_PERIOD, // Keypad . and Delete
KEY_EN_BACK_SLASH, // Keyboard Non-US \ and |
KEY_EN_UNUSED, // Keyboard Application
KEY_EN_POWER, // Keyboard Power
KEY_EN_NUMPAD_EQUAL, // Keypad =
KEY_EN_F13, // Keyboard F13
KEY_EN_F14, // Keyboard F14
KEY_EN_F15, // Keyboard F15
KEY_EN_F16, // Keyboard F16
KEY_EN_F17, // Keyboard F17
KEY_EN_F18, // Keyboard F18
KEY_EN_F19, // Keyboard F19
KEY_EN_F20, // Keyboard F20
KEY_EN_F21, // Keyboard F21
KEY_EN_F22, // Keyboard F22
KEY_EN_F23, // Keyboard F23
KEY_EN_F24, // Keyboard F24
KEY_EN_UNUSED, // Keyboard Execute
KEY_EN_UNUSED, // Keyboard Help
KEY_EN_MENU, // Keyboard Menu
KEY_EN_UNUSED, // Keyboard Select
KEY_EN_UNUSED, // Keyboard Stop
KEY_EN_UNUSED, // Keyboard Again
KEY_EN_UNUSED, // Keyboard Undo
KEY_EN_UNUSED, // Keyboard Cut
KEY_EN_UNUSED, // Keyboard Copy
KEY_EN_UNUSED, // Keyboard Paste
KEY_EN_UNUSED, // Keyboard Find
KEY_EN_MEDIA_MUTE, // Keyboard Mute
KEY_EN_MEDIA_VOLUME_UP, // Keyboard Volume Up
KEY_EN_MEDIA_VOLUME_DOWN, // Keyboard Volume Down
KEY_EN_UNUSED, // Keyboard Locking Caps Lock
KEY_EN_UNUSED, // Keyboard Locking Num Lock
KEY_EN_UNUSED, // Keyboard Locking Scroll Lock
KEY_EN_NUMPAD_PERIOD, // Keypad Comma
KEY_EN_NUMPAD_EQUAL, // Keypad Equal Sign
KEY_JP_RO, // Keyboard International1
KEY_JP_KANA, // Keyboard International2
KEY_JP_YEN, // Keyboard International3
KEY_JP_HENKAN, // Keyboard International4
KEY_JP_MUHENKAN, // Keyboard International5
KEY_EN_COMMA, // Keyboard International6
KEY_JP_ZENKAKU, // Keyboard International7
KEY_EN_UNUSED, // Keyboard International8
KEY_EN_UNUSED, // Keyboard International9
KEY_KR_HAN, // Keyboard LANG1
KEY_KR_HANJA, // Keyboard LANG2
KEY_JP_KATAKANA, // Keyboard LANG3
KEY_JP_HIRAGANA, // Keyboard LANG4
KEY_JP_ZENKAKU, // Keyboard LANG5
KEY_EN_UNUSED, // Keyboard LANG6
KEY_EN_UNUSED, // Keyboard LANG7
KEY_EN_UNUSED, // Keyboard LANG8
KEY_EN_UNUSED, // Keyboard LANG9
KEY_EN_UNUSED, // Keyboard Alternate Erase
KEY_EN_UNUSED, // Keyboard SysReq/Attention
KEY_EN_UNUSED, // Keyboard Cancel
KEY_EN_UNUSED, // Keyboard Clear
KEY_EN_UNUSED, // Keyboard Prior
KEY_EN_UNUSED, // Keyboard Return
KEY_EN_UNUSED, // Keyboard Separator
KEY_EN_UNUSED, // Keyboard Out
KEY_EN_UNUSED, // Keyboard Oper
KEY_EN_UNUSED, // Keyboard Clear/Again
KEY_EN_UNUSED, // Keyboard CrSel/Props
KEY_EN_UNUSED, // Keyboard ExSel
KEY_EN_UNUSED, // AF Reserved
KEY_EN_UNUSED, // Keypad 00
KEY_EN_UNUSED, // Keypad 000
KEY_EN_UNUSED, // Thousands Separator
KEY_EN_UNUSED, // Decimal Separator
KEY_EN_UNUSED, // Currency Unit
KEY_EN_UNUSED, // Currency Sub-unit
KEY_EN_UNUSED, // Keypad (
KEY_EN_UNUSED, // Keypad )
KEY_EN_UNUSED, // Keypad {
KEY_EN_UNUSED, // Keypad }
KEY_EN_UNUSED, // Keypad Tab
KEY_EN_UNUSED, // Keypad Backspace
KEY_EN_UNUSED, // Keypad A
KEY_EN_UNUSED, // Keypad B
KEY_EN_UNUSED, // Keypad C
KEY_EN_UNUSED, // Keypad D
KEY_EN_UNUSED, // Keypad E
KEY_EN_UNUSED, // Keypad F
KEY_EN_UNUSED, // Keypad XOR
KEY_EN_UNUSED, // Keypad ∧
KEY_EN_UNUSED, // Keypad %
KEY_EN_UNUSED, // Keypad <
KEY_EN_UNUSED, // Keypad >
KEY_EN_UNUSED, // Keypad &
KEY_EN_UNUSED, // Keypad &&
KEY_EN_UNUSED, // Keypad |
KEY_EN_UNUSED, // Keypad ||
KEY_EN_UNUSED, // Keypad :
KEY_EN_UNUSED, // Keypad #
KEY_EN_UNUSED, // Keypad Space
KEY_EN_UNUSED, // Keypad @
KEY_EN_UNUSED, // Keypad !
KEY_EN_UNUSED, // Keypad Memory Store
KEY_EN_UNUSED, // Keypad Memory Recall
KEY_EN_UNUSED, // Keypad Memory Clear
KEY_EN_UNUSED, // Keypad Memory Add
KEY_EN_UNUSED, // Keypad Memory Subtract
KEY_EN_UNUSED, // Keypad Memory Multiply
KEY_EN_UNUSED, // Keypad Memory Divide
KEY_EN_UNUSED, // Keypad +/-
KEY_EN_UNUSED, // Keypad Clear
KEY_EN_UNUSED, // Keypad Clear Entry
KEY_EN_UNUSED, // Keypad Binary
KEY_EN_UNUSED, // Keypad Octal
KEY_EN_UNUSED, // Keypad Decimal
KEY_EN_UNUSED, // Keypad Hexadecimal
KEY_EN_UNUSED, // DF Reserved
KEY_EN_LEFT_CONTROL, // Keyboard LeftControl
KEY_EN_LEFT_SHIFT, // Keyboard LeftShift
KEY_EN_LEFT_ALT, // Keyboard LeftAlt
KEY_EN_LEFT_WINDOWS, // Keyboard Left GUI
KEY_EN_RIGHT_CONTROL, // Keyboard RightControl
KEY_EN_RIGHT_SHIFT, // Keyboard RightShift
KEY_EN_RIGHT_ALT, // Keyboard RightAlt
KEY_EN_RIGHT_WINDOWS, // Keyboard Right GUI
};
void RGBController_HIDLampArray::SetupZones()
{
zone new_zone;
new_zone.name = RGBController::DeviceTypeToString(type);
new_zone.type = ZONE_TYPE_MATRIX;
new_zone.leds_count = controller->GetLampCount();
new_zone.leds_min = new_zone.leds_count;
new_zone.leds_max = new_zone.leds_count;
std::set<unsigned int> columns;
std::set<unsigned int> rows;
for(std::size_t lamp_idx = 0; lamp_idx < controller->GetLamps().size(); lamp_idx++)
{
rows.insert(controller->GetLamps()[lamp_idx].PositionYInMicrometers);
columns.insert(controller->GetLamps()[lamp_idx].PositionXInMicrometers);
}
new_zone.matrix_map.height = rows.size();
new_zone.matrix_map.width = columns.size();
new_zone.matrix_map.map.resize(rows.size() * columns.size());
memset(new_zone.matrix_map.map.data(), 0xFF, (new_zone.matrix_map.map.size() * sizeof(unsigned int)));
for(std::size_t lamp_idx = 0; lamp_idx < controller->GetLamps().size(); lamp_idx++)
{
//FIXME this assumes that matrix_size is big enough which is only guaranteed when no key possition is doubled
size_t idx = std::distance(columns.begin(), columns.find(controller->GetLamps()[lamp_idx].PositionXInMicrometers));
size_t idy = std::distance(rows.begin(), rows.find(controller->GetLamps()[lamp_idx].PositionYInMicrometers));
new_zone.matrix_map.map[idx + idy * new_zone.matrix_map.width] = lamp_idx;
}
zones.push_back(new_zone);
for(std::size_t lamp_idx = 0; lamp_idx < controller->GetLamps().size(); lamp_idx++)
{
led new_led;
if(controller->GetLamps()[lamp_idx].LampKey < HID_KEYBOARD_USAGE_IDS_COUNT)
{
new_led.name = HIDUsageIDsToKeyNames[controller->GetLamps()[lamp_idx].LampKey];
}
else
{
new_led.name = KEY_EN_UNUSED;
}
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_HIDLampArray::DeviceUpdateLEDs()
{
unsigned int leds_to_go = leds.size();
while(leds_to_go > 0)
{
unsigned int leds_this_frame = LAMP_MULTI_UPDATE_LAMP_COUNT;
unsigned short LampIds[LAMP_MULTI_UPDATE_LAMP_COUNT];
LampArrayColor UpdateColors[LAMP_MULTI_UPDATE_LAMP_COUNT];
unsigned char LampUpdateFlags = 0;
if(leds_to_go < leds_this_frame)
{
leds_this_frame = leds_to_go;
}
for(unsigned int led_frame_idx = 0; led_frame_idx < leds_this_frame; led_frame_idx++)
{
unsigned short led_idx = (leds.size() - leds_to_go) + led_frame_idx;
LampIds[led_frame_idx] = led_idx;
UpdateColors[led_frame_idx].RedChannel = RGBGetRValue(colors[led_idx]);
UpdateColors[led_frame_idx].GreenChannel = RGBGetGValue(colors[led_idx]);
UpdateColors[led_frame_idx].BlueChannel = RGBGetBValue(colors[led_idx]);
UpdateColors[led_frame_idx].IntensityChannel = 255;
}
leds_to_go -= leds_this_frame;
if(leds_to_go <= 0)
{
LampUpdateFlags = LAMP_UPDATE_FLAG_UPDATE_COMPLETE;
}
controller->SetLampMultiUpdateReport(leds_this_frame, LampUpdateFlags, LampIds, UpdateColors);
}
}
void RGBController_HIDLampArray::DeviceUpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_HIDLampArray::DeviceUpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_HIDLampArray::DeviceUpdateMode()
{
if(modes[active_mode].value == 0)
{
controller->SetLampArrayControlReport(false);
}
else
{
controller->SetLampArrayControlReport(true);
}
}
@@ -0,0 +1,33 @@
/*---------------------------------------------------------*\
| RGBController_HIDLampArray.h |
| |
| RGBController for HID LampArray Devices |
| |
| Adam Honse ([email protected]) 26 Mar 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "HIDLampArrayController.h"
class RGBController_HIDLampArray : public RGBController
{
public:
RGBController_HIDLampArray(HIDLampArrayController* controller_ptr);
~RGBController_HIDLampArray();
void SetupZones();
void DeviceUpdateLEDs();
void DeviceUpdateZoneLEDs(int zone);
void DeviceUpdateSingleLED(int led);
void DeviceUpdateMode();
private:
HIDLampArrayController* controller;
};
@@ -0,0 +1,107 @@
/*******************************************************
Utility functions taken from:
HIDAPI - Multi-Platform library for
communication with HID devices.
Alan Ott
Signal 11 Software
libusb/hidapi Team
Copyright 2022, All Rights Reserved.
At the discretion of the user of this library,
this software may be licensed under the terms of the
GNU General Public License v3, a BSD-Style license, or the
original HIDAPI license as outlined in the LICENSE.txt,
LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
files located at the root of the source distribution.
These files may also be found in the public source
code repository located at:
https://github.com/libusb/hidapi .
********************************************************/
/*
* Gets the size of the HID item at the given position
* Returns 1 if successful, 0 if an invalid key
* Sets data_len and key_size when successful
*/
static int get_hid_item_size(const unsigned char *report_descriptor, unsigned size, unsigned pos, unsigned char *data_len, unsigned char *key_size)
{
int key = report_descriptor[pos];
int size_code;
/*
* This is a Long Item. The next byte contains the
* length of the data section (value) for this key.
* See the HID specification, version 1.11, section
* 6.2.2.3, titled "Long Items."
*/
if ((key & 0xf0) == 0xf0) {
if (pos + 1 < size)
{
*data_len = report_descriptor[pos + 1];
*key_size = 3;
return 1;
}
*data_len = 0; /* malformed report */
*key_size = 0;
}
/*
* This is a Short Item. The bottom two bits of the
* key contain the size code for the data section
* (value) for this key. Refer to the HID
* specification, version 1.11, section 6.2.2.2,
* titled "Short Items."
*/
size_code = key & 0x3;
switch (size_code) {
case 0:
case 1:
case 2:
*data_len = size_code;
*key_size = 1;
return 1;
case 3:
*data_len = 4;
*key_size = 1;
return 1;
default:
/* Can't ever happen since size_code is & 0x3 */
*data_len = 0;
*key_size = 0;
break;
};
/* malformed report */
return 0;
}
/*
* Get bytes from a HID Report Descriptor.
* Only call with a num_bytes of 0, 1, 2, or 4.
*/
static unsigned get_hid_report_bytes(unsigned char *rpt, size_t len, size_t num_bytes, size_t cur)
{
/* Return if there aren't enough bytes. */
if (cur + num_bytes >= len)
return 0;
if (num_bytes == 0)
return 0;
else if (num_bytes == 1)
return rpt[cur + 1];
else if (num_bytes == 2)
return (rpt[cur + 2] * 256 + rpt[cur + 1]);
else if (num_bytes == 4)
return (
rpt[cur + 4] * 0x01000000 +
rpt[cur + 3] * 0x00010000 +
rpt[cur + 2] * 0x00000100 +
rpt[cur + 1] * 0x00000001
);
else
return 0;
}
@@ -75,9 +75,5 @@ DetectedControllers DetectHYTEMousematControllers()
}
REGISTER_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers, 0x3402, 0x0B00 ) |
| DUMMY_DEVICE_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers, 0x3402, 0x0B01 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(hyte_mousemat_1, "HYTE Mousemat", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"3402\", ATTRS{idProduct}==\"0b00\", TAG+=\"uaccess\", TAG+=\"HYTE_Mousemat\"");
REGISTER_CUSTOM_UDEV_RULE(hyte_mousemat_2, "HYTE Mousemat", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"3402\", ATTRS{idProduct}==\"0b01\", TAG+=\"uaccess\", TAG+=\"HYTE_Mousemat\"");
@@ -60,9 +60,3 @@ DetectedControllers DetectHYTEMousematControllers()
}
REGISTER_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers, 0x3402, 0x0B00 ) |
| DUMMY_DEVICE_DETECTOR("HYTE Mousemat", DetectHYTEMousematControllers, 0x3402, 0x0B01 ) |
\*---------------------------------------------------------------------------------------------------------*/
@@ -56,9 +56,5 @@ DetectedControllers DetectHYTENexusControllers()
}
REGISTER_DETECTOR("HYTE Nexus", DetectHYTENexusControllers);
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules |
| |
| DUMMY_DEVICE_DETECTOR("HYTE THICC Q60", DetectHYTENexusControllers, 0x3402, 0x0400 ) |
| DUMMY_DEVICE_DETECTOR("HYTE Nexus Portal NP50", DetectHYTENexusControllers, 0x3402, 0x0901 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_CUSTOM_UDEV_RULE(hyte_q60, "HYTE THICC Q60", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"3402\", ATTRS{idProduct}==\"0400\", TAG+=\"uaccess\", TAG+=\"HYTE_THICC_Q60\"");
REGISTER_CUSTOM_UDEV_RULE(hyte_nexus_portal, "HYTE Nexus Portal NP50", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"3402\", ATTRS{idProduct}==\"0901\", TAG+=\"uaccess\", TAG+=\"HYTE_Nexus_Portal_NP50\"");
@@ -45,6 +45,7 @@ bool TestDDR5Models(char code)
TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr, bool (*modelChecker)(char))
{
bool passed = true;
bool signature_ok = true;
char test_str[] = "FURY";
int res;
@@ -92,6 +93,24 @@ TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr
}
}
/*-----------------------------------------------------------------*\
| Some Kingston Fury DDR5 modules return garbage for the signature |
| and model registers (e.g. res=0708 at register 01) while every |
| other register and the apply command work normally. This happens |
| per slot on some boards (seen on ASUS B650 with DIMMs swapped: |
| the bad readings stay on the slot, not on the module). The SPD |
| already told us this slot holds a Kingston DDR5 module and the |
| RGB controller ACKed the transaction, so accept it with a warning.|
| See https://gitlab.com/CalcProgrammer1/OpenRGB/-/issues/4981 |
\*-----------------------------------------------------------------*/
if(!passed)
{
LOG_WARNING("[%s] 0x%02X: unreadable FURY signature, accepting anyway (SPD says Kingston DDR5, controller ACKs). See issue #4981",
FURY_CONTROLLER_NAME, slot_addr);
passed = true;
signature_ok = false;
}
if(passed)
{
// Get the model code
@@ -103,8 +122,16 @@ TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr
if(!modelChecker(model_code))
{
LOG_INFO("[%s] Unknown model code 0x%02X", FURY_CONTROLLER_NAME, model_code);
passed = false;
if(signature_ok)
{
LOG_INFO("[%s] Unknown model code 0x%02X", FURY_CONTROLLER_NAME, model_code);
passed = false;
}
else
{
LOG_WARNING("[%s] 0x%02X: model code 0x%02X unreadable too, assuming Fury Beast DDR5",
FURY_CONTROLLER_NAME, slot_addr, model_code);
}
}
}
@@ -50,18 +50,60 @@ RGBController_LEDStrip::~RGBController_LEDStrip()
void RGBController_LEDStrip::SetupZones()
{
zone led_zone;
led_zone.name = "LED Strip";
led_zone.type = ZONE_TYPE_LINEAR;
led_zone.leds_min = controller->num_leds;
led_zone.leds_max = controller->num_leds;
led_zone.leds_count = controller->num_leds;
zones.push_back(led_zone);
/*-----------------------------------------------------*\
| Only set LED count on the first run |
\------------------------------------------------------*/
bool first_run = false;
for(int led_idx = 0; led_idx < controller->num_leds; led_idx++)
if(zones.size() == 0)
{
first_run = true;
}
/*-----------------------------------------------------*\
| Clear any existing color/LED configuration |
\------------------------------------------------------*/
leds.clear();
colors.clear();
zones.resize(1);
/*-----------------------------------------------------*\
| Set zones and leds |
\------------------------------------------------------*/
zones[0].leds_min = controller->num_leds;
zones[0].leds_max = controller->num_leds;
if(first_run)
{
zones[0].flags = ZONE_FLAG_MANUALLY_CONFIGURABLE_NAME
| ZONE_FLAG_MANUALLY_CONFIGURABLE_TYPE
| ZONE_FLAG_MANUALLY_CONFIGURABLE_MATRIX_MAP
| ZONE_FLAG_MANUALLY_CONFIGURABLE_SEGMENTS;
}
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_NAME))
{
zones[0].name = "LED Strip";
}
zones[0].leds_count = controller->num_leds;
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_TYPE))
{
zones[0].type = ZONE_TYPE_LINEAR;
}
if(!(zones[0].flags & ZONE_FLAG_MANUALLY_CONFIGURED_MATRIX_MAP))
{
zones[0].matrix_map.width = 0;
zones[0].matrix_map.height = 0;
zones[0].matrix_map.map.resize(0);
}
for(unsigned int led_idx = 0; led_idx < zones[0].leds_count; led_idx++)
{
led new_led;
new_led.name = "LED ";
new_led.name = zones[0].name + ", LED ";
new_led.name.append(std::to_string(led_idx));
leds.push_back(new_led);
@@ -70,6 +112,14 @@ void RGBController_LEDStrip::SetupZones()
SetupColors();
}
void RGBController_LEDStrip::DeviceConfigureZone(int zone_idx)
{
if((size_t)zone_idx < zones.size())
{
SetupZones();
}
}
void RGBController_LEDStrip::DeviceUpdateLEDs()
{
controller->SetLEDs(colors);
@@ -23,6 +23,8 @@ public:
void SetupZones();
void DeviceConfigureZone(int zone_idx);
void DeviceUpdateLEDs();
void DeviceUpdateZoneLEDs(int zone);
void DeviceUpdateSingleLED(int led);
@@ -0,0 +1,239 @@
/*---------------------------------------------------------*\
| LenovoK500Controller.cpp |
| |
| Driver for Lenovo Legion K500 keyboard |
| |
| MX1D 10 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include <vector>
#include "LenovoK500Controller.h"
#include "LogManager.h"
using namespace std;
typedef struct
{
unsigned char byte_idx;
unsigned char bit_idx;
} k500_key;
static const k500_key k500_matrix[104] =
{
{0, 0}, // ESC
{0, 1}, // F1
{0, 2}, // F2
{0, 3}, // F3
{0, 4}, // F4
{0, 5}, // F5
{0, 6}, // F6
{0, 7}, // F7
{1, 0}, // F8
{1, 1}, // F9
{1, 2}, // F10
{1, 3}, // F11
{1, 4}, // F12
{1, 5}, // PrtSc
{1, 6}, // ScrollLock
{1, 7}, // Pause
{2, 0}, // Grave
{2, 1}, // 1
{2, 2}, // 2
{2, 3}, // 3
{2, 4}, // 4
{2, 5}, // 5
{2, 6}, // 6
{2, 7}, // 7
{3, 0}, // 8
{3, 1}, // 9
{3, 2}, // 0
{3, 3}, // Minus
{3, 4}, // Equal
{3, 5}, // Backspace
{3, 6}, // Insert
{3, 7}, // Home
{7, 6}, // PgUp
{12, 0}, // NumLock
{12, 5}, // NumSlash
{13, 1}, // NumAsterisk
{14, 0}, // NumMinus
{4, 0}, // Tab
{4, 1}, // Q
{4, 2}, // W
{4, 3}, // E
{4, 4}, // R
{4, 5}, // T
{4, 6}, // Y
{4, 7}, // U
{5, 0}, // I
{5, 1}, // O
{5, 2}, // P
{5, 3}, // LBracket
{5, 4}, // RBracket
{5, 5}, // Backslash
{5, 6}, // Delete
{5, 7}, // End
{7, 7}, // PgDn
{12, 1}, // Num7
{12, 6}, // Num8
{13, 2}, // Num9
{14, 1}, // NumPlus
{6, 0}, // CapsLock
{6, 1}, // A
{6, 2}, // S
{6, 3}, // D
{6, 4}, // F
{6, 5}, // G
{6, 6}, // H
{6, 7}, // J
{7, 0}, // K
{7, 1}, // L
{7, 2}, // Semicolon
{7, 3}, // Quote
{7, 4}, // Enter
{12, 2}, // Num4
{12, 7}, // Num5
{13, 3}, // Num6
{8, 0}, // LShift
{8, 1}, // Z
{8, 2}, // X
{8, 3}, // C
{8, 4}, // V
{8, 5}, // B
{8, 6}, // N
{8, 7}, // M
{9, 0}, // Comma
{9, 1}, // Period
{9, 2}, // Slash
{9, 3}, // RShift
{9, 6}, // Up
{12, 3}, // Num1
{13, 0}, // Num2
{13, 4}, // Num3
{14, 3}, // NumEnter
{10, 0}, // LCtrl
{10, 1}, // LWin
{10, 2}, // LAlt
{10, 5}, // Space
{11, 0}, // RAlt
{11, 1}, // RWin
{11, 2}, // Menu
{11, 3}, // RCtrl
{11, 6}, // Left
{11, 7}, // Down
{9, 7}, // Right
{12, 4}, // Num0
{13, 5}, // NumDecimal
};
static const unsigned char default_palette[] =
{
0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff,
0x00, 0x00, 0x00, 0xff, 0xff, 0x00
};
LenovoK500Controller::LenovoK500Controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
device = dev_handle;
location = info.path;
name = dev_name;
}
LenovoK500Controller::~LenovoK500Controller()
{
hid_close(device);
}
std::string LenovoK500Controller::GetDeviceLocation()
{
return("HID: " + location);
}
std::string LenovoK500Controller::GetDeviceName()
{
return(name);
}
void LenovoK500Controller::SetMode(unsigned char mode_value, std::vector<RGBColor> colors, unsigned int brightness, unsigned int speed)
{
LOG_DEBUG("[%s] Setting mode %02X, brightness %d, speed %d", name.c_str(), mode_value, brightness, speed);
unsigned char feature_buf[9];
memset(feature_buf, 0x00, sizeof(feature_buf));
feature_buf[0] = 0x00; // Report ID
feature_buf[1] = 0x14;
feature_buf[2] = 0x00;
feature_buf[3] = 0x5A;
hid_send_feature_report(device, feature_buf, sizeof(feature_buf));
unsigned char usb_buf[K500_DATA_SIZE + 1];
memset(usb_buf, 0x00, sizeof(usb_buf));
usb_buf[0x00] = 0x00; // HID Report ID (0 = no report ID)
usb_buf[0x01] = 0x01; // Magic byte
usb_buf[0x02] = mode_value;
usb_buf[0x03] = static_cast<unsigned char>(brightness);
usb_buf[0x04] = static_cast<unsigned char>(speed);
memcpy(&usb_buf[0x11], default_palette, sizeof(default_palette));
if(mode_value == K500_MODE_CUSTOMIZE)
{
memset(&usb_buf[0x31], 0x00, 16);
unsigned int custom_color = 0;
for(size_t i = 0; i < colors.size() && i < 104; i++)
{
if(colors[i] != 0)
{
custom_color = colors[i];
break;
}
}
for(size_t i = 0; i < colors.size() && i < 104; i++)
{
if(colors[i] != 0)
{
unsigned char byte_idx = k500_matrix[i].byte_idx;
unsigned char bit_idx = k500_matrix[i].bit_idx;
usb_buf[0x31 + byte_idx] |= (1 << bit_idx);
}
}
usb_buf[0x11] = static_cast<unsigned char>(RGBGetRValue(custom_color));
usb_buf[0x12] = static_cast<unsigned char>(RGBGetGValue(custom_color));
usb_buf[0x13] = static_cast<unsigned char>(RGBGetBValue(custom_color));
}
else
{
if(colors.size() > 0)
{
usb_buf[0x11] = static_cast<unsigned char>(RGBGetRValue(colors[0]));
usb_buf[0x12] = static_cast<unsigned char>(RGBGetGValue(colors[0]));
usb_buf[0x13] = static_cast<unsigned char>(RGBGetBValue(colors[0]));
}
if(colors.size() > 1)
{
usb_buf[0x15] = static_cast<unsigned char>(RGBGetRValue(colors[1]));
usb_buf[0x16] = static_cast<unsigned char>(RGBGetGValue(colors[1]));
usb_buf[0x17] = static_cast<unsigned char>(RGBGetBValue(colors[1]));
}
if(colors.size() > 2)
{
usb_buf[0x19] = static_cast<unsigned char>(RGBGetRValue(colors[2]));
usb_buf[0x1A] = static_cast<unsigned char>(RGBGetGValue(colors[2]));
usb_buf[0x1B] = static_cast<unsigned char>(RGBGetBValue(colors[2]));
}
}
hid_write(device, usb_buf, sizeof(usb_buf));
}
@@ -0,0 +1,58 @@
/*---------------------------------------------------------*\
| LenovoK500Controller.h |
| |
| Driver for Lenovo Legion K500 keyboard |
| |
| MX1D 10 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define K500_DATA_SIZE 64
#define K500_BRIGHTNESS_DEFAULT 2
#define K500_BRIGHTNESS_MIN 0
#define K500_BRIGHTNESS_MAX 2
#define K500_SPEED_DEFAULT 3
#define K500_SPEED_MIN 0
#define K500_SPEED_MAX 3
enum
{
K500_MODE_STATIC = 0x01,
K500_MODE_SPIRAL = 0x02,
K500_MODE_LASER = 0x03,
K500_MODE_DRIFTING = 0x04,
K500_MODE_FADING_TRACE = 0x05,
K500_MODE_CUSTOMIZE = 0x06,
K500_MODE_BREATHING = 0x07,
K500_MODE_BREATHING_RAINBOW = 0x08,
K500_MODE_STARLIGHT = 0x09,
K500_MODE_STARLIGHT_DUAL = 0x0A,
K500_MODE_SURFING = 0x0B,
};
class LenovoK500Controller
{
public:
LenovoK500Controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~LenovoK500Controller();
std::string GetDeviceLocation();
std::string GetDeviceName();
void SetMode(unsigned char mode_value, std::vector<RGBColor> colors, unsigned int brightness, unsigned int speed);
private:
hid_device* device;
std::string location;
std::string name;
};
@@ -0,0 +1,37 @@
/*---------------------------------------------------------*\
| LenovoK500ControllerDetect.cpp |
| |
| Detector for Lenovo Legion K500 keyboard |
| |
| MX1D 10 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "DetectionManager.h"
#include "RGBController_LenovoK500.h"
#include "LenovoK500Controller.h"
#define LENOVO_VID 0x17EF
#define LEGION_K500_PID 0x60D5
DetectedControllers DetectLenovoLegionK500Controllers(hid_device_info* info, const std::string& name)
{
DetectedControllers detected_controllers;
hid_device* dev;
dev = hid_open_path(info->path);
if(dev)
{
LenovoK500Controller* controller = new LenovoK500Controller(dev, *info, name);
RGBController_LenovoK500* rgb_controller = new RGBController_LenovoK500(controller);
detected_controllers.push_back(rgb_controller);
}
return(detected_controllers);
}
REGISTER_HID_DETECTOR_I("Lenovo Legion K500", DetectLenovoLegionK500Controllers, LENOVO_VID, LEGION_K500_PID, 3);
@@ -0,0 +1,415 @@
/*---------------------------------------------------------*\
| RGBController_LenovoK500.cpp |
| |
| Driver for Lenovo Legion K500 keyboard |
| |
| MX1D 10 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_LenovoK500.h"
#include "RGBControllerKeyNames.h"
/**------------------------------------------------------------------*\
@name Lenovo Legion K500
@category Keyboard
@type USB
@save :robot:
@direct :x:
@effects :white_check_mark:
@detectors DetectLenovoLegionK500Controllers
@comment
\*-------------------------------------------------------------------*/
#define NA 0xFFFFFFFF
static unsigned int matrix_map[6][23] =
{
{ 0 , NA, 1 , 2 , 3 , 4 , NA, 5 , 6 , 7 , 8 , NA, 9 , 10 , 11 , 12 , NA, 13 , 14 , 15 , NA, NA, NA, },
{ 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , NA, 30 , 31 , 32 , NA, 33 , 34 , 35 , 36 , },
{ 37 , NA, 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 , 49 , 50 , 51 , 52 , 53 , NA, 54 , 55 , 56 , 57 , },
{ 58 , NA, 59 , 60 , 61 , 62 , 63 , 64 , 65 , 66 , 67 , 68 , 69 , 70 , NA, NA, NA, NA, NA, 71 , 72 , 73 , NA, },
{ 74 , NA, 75 , 76 , 77 , 78 , 79 , 80 , 81 , 82 , 83 , 84 , 85 , NA, NA, NA, 86 , NA, NA, 87 , 88 , 89 , 90 , },
{ 91 , 92 , 93 , NA, NA, NA, 94 , NA, NA, NA, NA, 95 , 96 , 97 , 98 , 99 , 100, 101, NA, 102, NA, 103, NA, },
};
static const char* led_names[] =
{
KEY_EN_ESCAPE,
KEY_EN_F1,
KEY_EN_F2,
KEY_EN_F3,
KEY_EN_F4,
KEY_EN_F5,
KEY_EN_F6,
KEY_EN_F7,
KEY_EN_F8,
KEY_EN_F9,
KEY_EN_F10,
KEY_EN_F11,
KEY_EN_F12,
KEY_EN_PRINT_SCREEN,
KEY_EN_SCROLL_LOCK,
KEY_EN_PAUSE_BREAK,
KEY_EN_BACK_TICK,
KEY_EN_1,
KEY_EN_2,
KEY_EN_3,
KEY_EN_4,
KEY_EN_5,
KEY_EN_6,
KEY_EN_7,
KEY_EN_8,
KEY_EN_9,
KEY_EN_0,
KEY_EN_MINUS,
KEY_EN_EQUALS,
KEY_EN_BACKSPACE,
KEY_EN_INSERT,
KEY_EN_HOME,
KEY_EN_PAGE_UP,
KEY_EN_NUMPAD_LOCK,
KEY_EN_NUMPAD_DIVIDE,
KEY_EN_NUMPAD_TIMES,
KEY_EN_NUMPAD_MINUS,
KEY_EN_TAB,
KEY_EN_Q,
KEY_EN_W,
KEY_EN_E,
KEY_EN_R,
KEY_EN_T,
KEY_EN_Y,
KEY_EN_U,
KEY_EN_I,
KEY_EN_O,
KEY_EN_P,
KEY_EN_LEFT_BRACKET,
KEY_EN_RIGHT_BRACKET,
KEY_EN_BACK_SLASH,
KEY_EN_DELETE,
KEY_EN_END,
KEY_EN_PAGE_DOWN,
KEY_EN_NUMPAD_7,
KEY_EN_NUMPAD_8,
KEY_EN_NUMPAD_9,
KEY_EN_NUMPAD_PLUS,
KEY_EN_CAPS_LOCK,
KEY_EN_A,
KEY_EN_S,
KEY_EN_D,
KEY_EN_F,
KEY_EN_G,
KEY_EN_H,
KEY_EN_J,
KEY_EN_K,
KEY_EN_L,
KEY_EN_SEMICOLON,
KEY_EN_QUOTE,
KEY_EN_ANSI_ENTER,
KEY_EN_NUMPAD_4,
KEY_EN_NUMPAD_5,
KEY_EN_NUMPAD_6,
KEY_EN_LEFT_SHIFT,
KEY_EN_Z,
KEY_EN_X,
KEY_EN_C,
KEY_EN_V,
KEY_EN_B,
KEY_EN_N,
KEY_EN_M,
KEY_EN_COMMA,
KEY_EN_PERIOD,
KEY_EN_FORWARD_SLASH,
KEY_EN_RIGHT_SHIFT,
KEY_EN_UP_ARROW,
KEY_EN_NUMPAD_1,
KEY_EN_NUMPAD_2,
KEY_EN_NUMPAD_3,
KEY_EN_NUMPAD_ENTER,
KEY_EN_LEFT_CONTROL,
KEY_EN_LEFT_WINDOWS,
KEY_EN_LEFT_ALT,
KEY_EN_SPACE,
KEY_EN_RIGHT_ALT,
KEY_EN_RIGHT_WINDOWS,
KEY_EN_MENU,
KEY_EN_RIGHT_CONTROL,
KEY_EN_LEFT_ARROW,
KEY_EN_DOWN_ARROW,
KEY_EN_RIGHT_ARROW,
KEY_EN_NUMPAD_0,
KEY_EN_NUMPAD_PERIOD,
};
RGBController_LenovoK500::RGBController_LenovoK500(LenovoK500Controller* controller_ptr)
{
controller = controller_ptr;
name = "Lenovo Legion K500";
vendor = "Lenovo";
type = DEVICE_TYPE_KEYBOARD;
description = "Lenovo Legion K500 Device";
location = controller->GetDeviceLocation();
mode Static;
Static.name = "Static";
Static.value = K500_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.colors_min = 1;
Static.colors_max = 1;
Static.brightness_min = K500_BRIGHTNESS_MIN;
Static.brightness_max = K500_BRIGHTNESS_MAX;
Static.brightness = K500_BRIGHTNESS_DEFAULT;
Static.speed_min = K500_SPEED_MIN;
Static.speed_max = K500_SPEED_MAX;
Static.speed = K500_SPEED_DEFAULT;
Static.colors.resize(1);
modes.push_back(Static);
mode Spiral;
Spiral.name = "Spiral";
Spiral.value = K500_MODE_SPIRAL;
Spiral.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Spiral.color_mode = MODE_COLORS_NONE;
Spiral.brightness_min = K500_BRIGHTNESS_MIN;
Spiral.brightness_max = K500_BRIGHTNESS_MAX;
Spiral.brightness = K500_BRIGHTNESS_DEFAULT;
Spiral.speed_min = K500_SPEED_MIN;
Spiral.speed_max = K500_SPEED_MAX;
Spiral.speed = K500_SPEED_DEFAULT;
modes.push_back(Spiral);
mode Laser;
Laser.name = "Laser";
Laser.value = K500_MODE_LASER;
Laser.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Laser.color_mode = MODE_COLORS_NONE;
Laser.brightness_min = K500_BRIGHTNESS_MIN;
Laser.brightness_max = K500_BRIGHTNESS_MAX;
Laser.brightness = K500_BRIGHTNESS_DEFAULT;
Laser.speed_min = K500_SPEED_MIN;
Laser.speed_max = K500_SPEED_MAX;
Laser.speed = K500_SPEED_DEFAULT;
modes.push_back(Laser);
mode Drifting;
Drifting.name = "Drifting";
Drifting.value = K500_MODE_DRIFTING;
Drifting.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Drifting.color_mode = MODE_COLORS_NONE;
Drifting.brightness_min = K500_BRIGHTNESS_MIN;
Drifting.brightness_max = K500_BRIGHTNESS_MAX;
Drifting.brightness = K500_BRIGHTNESS_DEFAULT;
Drifting.speed_min = K500_SPEED_MIN;
Drifting.speed_max = K500_SPEED_MAX;
Drifting.speed = K500_SPEED_DEFAULT;
modes.push_back(Drifting);
mode FadingTrace;
FadingTrace.name = "Fading Trace";
FadingTrace.value = K500_MODE_FADING_TRACE;
FadingTrace.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
FadingTrace.color_mode = MODE_COLORS_MODE_SPECIFIC;
FadingTrace.colors_min = 1;
FadingTrace.colors_max = 1;
FadingTrace.brightness_min = K500_BRIGHTNESS_MIN;
FadingTrace.brightness_max = K500_BRIGHTNESS_MAX;
FadingTrace.brightness = K500_BRIGHTNESS_DEFAULT;
FadingTrace.speed_min = K500_SPEED_MIN;
FadingTrace.speed_max = K500_SPEED_MAX;
FadingTrace.speed = K500_SPEED_DEFAULT;
FadingTrace.colors.resize(1);
modes.push_back(FadingTrace);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = K500_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.brightness_min = K500_BRIGHTNESS_MIN;
Breathing.brightness_max = K500_BRIGHTNESS_MAX;
Breathing.brightness = K500_BRIGHTNESS_DEFAULT;
Breathing.speed_min = K500_SPEED_MIN;
Breathing.speed_max = K500_SPEED_MAX;
Breathing.speed = K500_SPEED_DEFAULT;
Breathing.colors.resize(1);
modes.push_back(Breathing);
mode Customize;
Customize.name = "Custom";
Customize.value = K500_MODE_CUSTOMIZE;
Customize.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Customize.color_mode = MODE_COLORS_PER_LED;
Customize.brightness_min = K500_BRIGHTNESS_MIN;
Customize.brightness_max = K500_BRIGHTNESS_MAX;
Customize.brightness = K500_BRIGHTNESS_DEFAULT;
Customize.speed_min = K500_SPEED_MIN;
Customize.speed_max = K500_SPEED_MAX;
Customize.speed = K500_SPEED_DEFAULT;
Customize.colors.resize(104);
modes.push_back(Customize);
mode BreathingRainbow;
BreathingRainbow.name = "Breathing (Rainbow)";
BreathingRainbow.value = K500_MODE_BREATHING_RAINBOW;
BreathingRainbow.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
BreathingRainbow.color_mode = MODE_COLORS_NONE;
BreathingRainbow.brightness_min = K500_BRIGHTNESS_MIN;
BreathingRainbow.brightness_max = K500_BRIGHTNESS_MAX;
BreathingRainbow.brightness = K500_BRIGHTNESS_DEFAULT;
BreathingRainbow.speed_min = K500_SPEED_MIN;
BreathingRainbow.speed_max = K500_SPEED_MAX;
BreathingRainbow.speed = K500_SPEED_DEFAULT;
modes.push_back(BreathingRainbow);
mode Starlight;
Starlight.name = "Starlight";
Starlight.value = K500_MODE_STARLIGHT;
Starlight.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Starlight.color_mode = MODE_COLORS_MODE_SPECIFIC;
Starlight.colors_min = 1;
Starlight.colors_max = 1;
Starlight.brightness_min = K500_BRIGHTNESS_MIN;
Starlight.brightness_max = K500_BRIGHTNESS_MAX;
Starlight.brightness = K500_BRIGHTNESS_DEFAULT;
Starlight.speed_min = K500_SPEED_MIN;
Starlight.speed_max = K500_SPEED_MAX;
Starlight.speed = K500_SPEED_DEFAULT;
Starlight.colors.resize(1);
modes.push_back(Starlight);
mode StarlightDual;
StarlightDual.name = "Starlight (Dual Colors)";
StarlightDual.value = K500_MODE_STARLIGHT_DUAL;
StarlightDual.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
StarlightDual.color_mode = MODE_COLORS_MODE_SPECIFIC;
StarlightDual.colors_min = 2;
StarlightDual.colors_max = 2;
StarlightDual.brightness_min = K500_BRIGHTNESS_MIN;
StarlightDual.brightness_max = K500_BRIGHTNESS_MAX;
StarlightDual.brightness = K500_BRIGHTNESS_DEFAULT;
StarlightDual.speed_min = K500_SPEED_MIN;
StarlightDual.speed_max = K500_SPEED_MAX;
StarlightDual.speed = K500_SPEED_DEFAULT;
StarlightDual.colors.resize(2);
modes.push_back(StarlightDual);
mode Surfing;
Surfing.name = "Surfing";
Surfing.value = K500_MODE_SURFING;
Surfing.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Surfing.color_mode = MODE_COLORS_NONE;
Surfing.brightness_min = K500_BRIGHTNESS_MIN;
Surfing.brightness_max = K500_BRIGHTNESS_MAX;
Surfing.brightness = K500_BRIGHTNESS_DEFAULT;
Surfing.speed_min = K500_SPEED_MIN;
Surfing.speed_max = K500_SPEED_MAX;
Surfing.speed = K500_SPEED_DEFAULT;
modes.push_back(Surfing);
SetupZones();
}
RGBController_LenovoK500::~RGBController_LenovoK500()
{
Shutdown();
delete controller;
}
void RGBController_LenovoK500::SetupZones()
{
zone new_zone;
new_zone.name = "Keyboard";
new_zone.type = ZONE_TYPE_MATRIX;
new_zone.leds_min = 104;
new_zone.leds_max = 104;
new_zone.leds_count = 104;
new_zone.matrix_map.Set(6, 23, (unsigned int*)&matrix_map);
zones.push_back(new_zone);
for(int i = 0; i < 104; i++)
{
led new_led;
new_led.name = led_names[i];
new_led.value = i;
leds.push_back(new_led);
}
SetupColors();
}
void RGBController_LenovoK500::ResizeZone(int /*zone*/, int /*new_size*/)
{
/* This device does not support resizing zones */
}
void RGBController_LenovoK500::DeviceUpdateLEDs()
{
if (modes[active_mode].value == K500_MODE_CUSTOMIZE)
{
unsigned int custom_color = 0;
for(size_t i = 0; i < colors.size() && i < 104; i++)
{
if(colors[i] != 0 && (last_colors.size() <= i || colors[i] != last_colors[i]))
{
custom_color = colors[i];
break;
}
}
if(custom_color == 0)
{
for(size_t i = 0; i < colors.size() && i < 104; i++)
{
if(colors[i] != 0)
{
custom_color = colors[i];
break;
}
}
}
for(size_t i = 0; i < colors.size() && i < 104; i++)
{
if(colors[i] != 0)
{
colors[i] = custom_color;
}
}
last_colors = colors;
controller->SetMode(modes[active_mode].value, colors, modes[active_mode].brightness, modes[active_mode].speed);
}
else if (active_mode == 0)
{
std::vector<RGBColor> mode_colors = { colors[0] };
controller->SetMode(K500_MODE_STATIC, mode_colors, modes[active_mode].brightness, modes[active_mode].speed);
}
}
void RGBController_LenovoK500::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_LenovoK500::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_LenovoK500::DeviceUpdateMode()
{
if (modes[active_mode].value == K500_MODE_CUSTOMIZE)
{
controller->SetMode(modes[active_mode].value, colors, modes[active_mode].brightness, modes[active_mode].speed);
}
else
{
controller->SetMode(modes[active_mode].value, modes[active_mode].colors, modes[active_mode].brightness, modes[active_mode].speed);
}
}
@@ -0,0 +1,34 @@
/*---------------------------------------------------------*\
| RGBController_LenovoK500.h |
| |
| Driver for Lenovo Legion K500 keyboard |
| |
| MX1D 10 Aug 2026 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "LenovoK500Controller.h"
class RGBController_LenovoK500 : public RGBController
{
public:
RGBController_LenovoK500(LenovoK500Controller* controller_ptr);
~RGBController_LenovoK500();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
LenovoK500Controller* controller;
std::vector<RGBColor> last_colors;
};
@@ -324,12 +324,6 @@ DetectedControllers DetectLianLiUniversalScreen()
return(detected_controllers);
}
/*---------------------------------------------------------------------------------------------------------*\
| Entries for dynamic UDEV rules for libusb devices |
| |
| DUMMY_DEVICE_DETECTOR("Lian Li Uni Hub", DetectLianLiUniHub, 0x0CF2, 0x7750 ) |
| DUMMY_DEVICE_DETECTOR("Lian Li Universal Screen", DetectLianLiUniversalScreen, 0x0416, 0x8050 ) |
\*---------------------------------------------------------------------------------------------------------*/
REGISTER_DETECTOR("Lian Li Uni Hub", DetectLianLiUniHub);
REGISTER_DETECTOR("Lian Li Universal Screen", DetectLianLiUniversalScreen);
@@ -342,3 +336,6 @@ REGISTER_HID_DETECTOR_IPU("Lian Li Uni Hub - SL Infinity", DetectLianLiUniH
REGISTER_HID_DETECTOR_IPU("Lian Li Strimer L Connect", DetectLianLiStrimerControllers, ENE_USB_VID, STRIMER_L_CONNECT_PID, 1, 0xFF72, 0xA1);
REGISTER_HID_DETECTOR_I("Lian Li GA II Trinity", DetectLianLiGAIITrinity, NUVOTON_USB_VID, GAII_USB_PID, 0x02);
REGISTER_HID_DETECTOR_I("Lian Li GA II Trinity Performance", DetectLianLiGAIITrinity, NUVOTON_USB_VID, GAII_Perf_USB_PID, 0x02);
REGISTER_CUSTOM_UDEV_RULE(lianli_uni_hub, "Lian Li Uni Hub", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"0cf2\", ATTRS{idProduct}==\"7750\", TAG+=\"uaccess\", TAG+=\"Lian_Li_Uni_Hub\"");
REGISTER_CUSTOM_UDEV_RULE(lianli_universal_screen, "Lian Li Universal Screen", "SUBSYSTEMS==\"usb|hidraw\", ATTRS{idVendor}==\"0416\", ATTRS{idProduct}==\"8050\", TAG+=\"uaccess\", TAG+=\"Lian_Li_Universal_Screen\"");
File diff suppressed because it is too large Load Diff
@@ -1,154 +0,0 @@
/*---------------------------------------------------------*\
| LogitechG560Controller.cpp |
| |
| Driver for Logitech G560 |
| |
| Cheerpipe 28 Oct 2020 |
| based on TheRogueZeta 31 Aug 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
#include "LogitechG560Controller.h"
using namespace std::chrono_literals;
LogitechG560Controller::LogitechG560Controller(hid_device* dev_handle, const char* path, std::string dev_name)
{
dev = dev_handle;
location = path;
name = dev_name;
}
LogitechG560Controller::~LogitechG560Controller()
{
hid_close(dev);
}
std::string LogitechG560Controller::GetDeviceLocation()
{
return("HID: " + location);
}
std::string LogitechG560Controller::GetDeviceName()
{
return(name);
}
void LogitechG560Controller::SetDirectMode(uint8_t zone)
{
unsigned char usb_buf[LOGI_G560_LED_PACKET_SIZE];
usb_buf[0x00] = 0x11;
usb_buf[0x01] = 0xFF;
usb_buf[0x02] = 0x04;
usb_buf[0x03] = 0xCA;
usb_buf[0x04] = zone;
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
fail_retry_write(dev, usb_buf, LOGI_G560_LED_PACKET_SIZE);
}
void LogitechG560Controller::SetOffMode(uint8_t zone)
{
unsigned char usb_buf[LOGI_G560_LED_PACKET_SIZE];
usb_buf[0x00] = 0x11;
usb_buf[0x01] = 0xFF;
usb_buf[0x02] = 0x04;
usb_buf[0x03] = 0x3F;
usb_buf[0x04] = zone;
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
fail_retry_write(dev, usb_buf, LOGI_G560_LED_PACKET_SIZE);
}
void LogitechG560Controller::SendSpeakerMode
(
unsigned char zone,
unsigned char mode,
unsigned char red,
unsigned char green,
unsigned char blue
)
{
unsigned char usb_buf[LOGI_G560_LED_PACKET_SIZE];
/*-----------------------------------------------------*\
| Zero out buffer |
\*-----------------------------------------------------*/
memset(usb_buf, 0x00, sizeof(usb_buf));
/*-----------------------------------------------------*\
| Set up Lighting Control |
\*-----------------------------------------------------*/
usb_buf[0x00] = 0x11;
usb_buf[0x01] = 0xFF;
usb_buf[0x02] = 0x04;
/*-----------------------------------------------------*\
| This packet sets speaker into direct mode. This mode |
| is used by Lightsync Ambilight and Music Visualizer |
| realtime effect. |
\*-----------------------------------------------------*/
usb_buf[0x03] = 0x3A;
/*-----------------------------------------------------*\
| Set up mode and speed |
\*-----------------------------------------------------*/
usb_buf[0x04] = zone;
usb_buf[0x05] = mode;
/*-----------------------------------------------------*\
| And set up the colors |
\*-----------------------------------------------------*/
usb_buf[0x06] = red;
usb_buf[0x07] = green;
usb_buf[0x08] = blue;
if(mode == LOGITECH_G560_MODE_DIRECT) //G560 only has Direct Mode.
{
usb_buf[0x09] = 0x02;
}
/*-----------------------------------------------------*\
| Send packet |
\*-----------------------------------------------------*/
fail_retry_write(dev, usb_buf, LOGI_G560_LED_PACKET_SIZE);
}
void LogitechG560Controller::fail_retry_write(hid_device *device, const unsigned char *data, size_t length)
{
unsigned char usb_buf_out[LOGI_G560_LED_PACKET_SIZE];
unsigned int write_max_retry = LOGI_G560_LED_COMMAND_SEND_RETRIES;
do
{
std::this_thread::sleep_for(1ms);
int ret = hid_write(device, data, length);
/*-------------------------------------------------------------------------------------*\
| HID write fails if a change led color and set volume command are sent at |
| the same time because RGB controller and volume control shares the same interface. |
\*-------------------------------------------------------------------------------------*/
if(ret == 20)
{
std::this_thread::sleep_for(1ms);
hid_read_timeout(dev, usb_buf_out, LOGI_G560_LED_PACKET_SIZE, 20);
break;
}
else
{
write_max_retry--;
std::this_thread::sleep_for(10ms);
}
}while (write_max_retry > 0);
}
@@ -1,59 +0,0 @@
/*---------------------------------------------------------*\
| LogitechG560Controller.h |
| |
| Driver for Logitech G560 |
| |
| Cheerpipe 28 Oct 2020 |
| based on TheRogueZeta 31 Aug 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define LOGI_G560_LED_PACKET_SIZE 20
#define LOGI_G560_LED_COMMAND_SEND_RETRIES 3
enum
{
LOGITECH_G560_MODE_OFF = 0x00,
LOGITECH_G560_MODE_DIRECT = 0x01,
LOGITECH_G560_MODE_CYCLE = 0x02,
LOGITECH_G560_MODE_BREATHING = 0x03,
};
class LogitechG560Controller
{
public:
LogitechG560Controller(hid_device* dev_handle, const char* path, std::string dev_name);
~LogitechG560Controller();
std::string GetDeviceLocation();
std::string GetDeviceName();
void SetDirectMode(uint8_t zone);
void SetOffMode(uint8_t zone);
void SendSpeakerMode
(
unsigned char zone,
unsigned char mode,
unsigned char red,
unsigned char green,
unsigned char blue
);
private:
hid_device* dev;
std::string location;
std::string name;
void fail_retry_write(hid_device *device, const unsigned char *data, size_t length);
};

Some files were not shown because too many files have changed in this diff Show More