From 1cbffedaeb4691be02b5b76a5cccfbf827e5a438 Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Sun, 11 Dec 2022 11:50:47 +1300 Subject: [PATCH] Advanced Aura feature Groundwork for 'advanced' aura modes Add single zone + Doom light flash Fix mocking for ROGCC Better prepare & change to mapping of keyboard layouts to models and functions Refactor and begin using new key layout stuff Enable first arg to rogcc to set layout in mocking feature mode Complete refactor of key layouts, and to RON serde --- .editorconfig | 23 + .gitignore | 4 +- CHANGELOG.md | 24 +- Cargo.lock | 100 +-- Cargo.toml | 8 +- Makefile | 6 +- asusctl/examples/anime-diag-png.rs | 8 +- asusctl/examples/anime-diag.rs | 6 +- asusctl/examples/anime-gif.rs | 7 +- asusctl/examples/anime-grid.rs | 6 +- asusctl/examples/anime-outline.rs | 3 +- asusctl/examples/anime-png.rs | 11 +- asusctl/examples/anime-spinning.rs | 16 +- .../{aura-rgb-ball.rs => aura-rgb-ball.rs-} | 2 +- asusctl/examples/aura-rgb-breathe.rs | 59 -- asusctl/examples/aura-rgb-iterate-keys.rs | 34 -- asusctl/examples/aura-zoned-breathe.rs | 70 ++- asusctl/src/aura_cli.rs | 7 +- asusctl/src/cli_opts.rs | 9 +- asusctl/src/main.rs | 33 +- asusctl/src/profiles_cli.rs | 3 +- daemon-user/src/ctrl_anime.rs | 36 +- daemon-user/src/daemon.rs | 31 +- daemon-user/src/user_config.rs | 45 +- daemon-user/src/zbus_anime.rs | 5 +- daemon/src/config.rs | 5 +- daemon/src/ctrl_anime/config.rs | 12 +- daemon/src/ctrl_anime/mod.rs | 48 +- daemon/src/ctrl_anime/trait_impls.rs | 32 +- daemon/src/ctrl_aura/config.rs | 22 +- daemon/src/ctrl_aura/controller.rs | 113 ++-- daemon/src/ctrl_aura/trait_impls.rs | 28 +- daemon/src/ctrl_platform.rs | 31 +- daemon/src/ctrl_power.rs | 21 +- daemon/src/ctrl_profiles/config.rs | 5 +- daemon/src/ctrl_profiles/controller.rs | 17 +- daemon/src/ctrl_profiles/trait_impls.rs | 43 +- daemon/src/ctrl_supported.rs | 33 +- daemon/src/daemon.rs | 31 +- daemon/src/error.rs | 16 +- daemon/src/laptops.rs | 167 ----- daemon/src/lib.rs | 51 +- data/asusd-ledmodes.toml | 204 ------- rog-anime/src/data.rs | 23 +- rog-anime/src/diagonal.rs | 25 +- rog-anime/src/error.rs | 8 +- rog-anime/src/gif.rs | 28 +- rog-anime/src/image.rs | 67 +- rog-anime/src/lib.rs | 8 +- rog-anime/src/sequencer.rs | 35 +- rog-anime/src/usb.rs | 23 +- rog-aura/Cargo.toml | 12 +- rog-aura/README.md | 246 ++++++++ rog-aura/data/aura_support.ron | 450 ++++++++++++++ rog-aura/data/layouts/fa506i_US.ron | 317 ++++++++++ rog-aura/data/layouts/fa507_US.ron | 334 ++++++++++ rog-aura/data/layouts/fx505d_US.ron | 281 +++++++++ rog-aura/data/layouts/g512_US.ron | 312 ++++++++++ rog-aura/data/layouts/g513_US.toml | 161 ----- rog-aura/data/layouts/g513i-per-key_US.ron | 366 +++++++++++ rog-aura/data/layouts/g513i_US.ron | 366 +++++++++++ rog-aura/data/layouts/g533_US.toml | 135 ---- rog-aura/data/layouts/g533q-per-key_US.ron | 293 +++++++++ rog-aura/data/layouts/g533q_US.ron | 294 +++++++++ rog-aura/data/layouts/ga401_US.toml | 154 ----- rog-aura/data/layouts/ga401q_US.ron | 299 +++++++++ rog-aura/data/layouts/gl503_US.ron | 305 ++++++++++ rog-aura/data/layouts/gl504_US.toml | 180 ------ rog-aura/data/layouts/gx502_US.ron | 382 ++++++++++++ rog-aura/data/layouts/gx502_US.toml | 172 ------ rog-aura/data/layouts/gx531-per-key_US.ron | 346 +++++++++++ rog-aura/data/per_key_raw_bytes.ods | Bin 0 -> 34954 bytes rog-aura/src/advanced.rs | 576 ++++++++++++++++++ rog-aura/src/advanced_to_str.rs | 148 +++++ rog-aura/src/aura_detection.rs | 189 ++++++ rog-aura/src/builtin_modes.rs | 15 +- rog-aura/src/effects/base.rs | 33 + rog-aura/src/effects/breathe.rs | 82 +++ rog-aura/src/effects/doom.rs | 164 +++++ rog-aura/src/effects/mod.rs | 291 +++++++++ rog-aura/src/effects/static_.rs | 25 + rog-aura/src/error.rs | 25 +- rog-aura/src/key_to_str.rs | 155 ----- rog-aura/src/keys.rs | 358 ----------- rog-aura/src/layouts.rs | 554 +++++++++++++++++ rog-aura/src/layouts/g513.rs | 170 ------ rog-aura/src/layouts/ga401.rs | 156 ----- rog-aura/src/layouts/gx502.rs | 178 ------ rog-aura/src/layouts/mod.rs | 105 ---- rog-aura/src/layouts/old_gx502.rs | 168 ----- rog-aura/src/lib.rs | 39 +- rog-aura/src/per_key_rgb.rs | 247 -------- rog-aura/src/per_zone.rs | 123 ---- rog-aura/src/sequencer/effects.rs | 250 -------- rog-aura/src/sequencer/mod.rs | 219 ------- rog-aura/src/usb.rs | 37 +- rog-control-center/Cargo.toml | 2 + rog-control-center/src/app.rs | 41 +- rog-control-center/src/cli_options.rs | 19 + rog-control-center/src/config.rs | 10 +- rog-control-center/src/lib.rs | 19 +- rog-control-center/src/main.rs | 145 ++++- rog-control-center/src/mocking.rs | 103 +++- rog-control-center/src/pages/aura_page.rs | 22 +- .../src/pages/fan_curve_page.rs | 25 +- rog-control-center/src/pages/system_page.rs | 13 +- rog-control-center/src/system_state.rs | 119 ++-- rog-control-center/src/tray.rs | 38 +- rog-control-center/src/update_and_notify.rs | 37 +- .../src/widgets/app_settings.rs | 3 +- rog-control-center/src/widgets/aura_modes.rs | 79 ++- rog-control-center/src/widgets/aura_power.rs | 37 +- rog-control-center/src/widgets/fan_graph.rs | 6 +- .../src/widgets/keyboard_layout.rs | 243 +++++--- rog-control-center/src/widgets/rog_bios.rs | 6 +- rog-control-center/src/widgets/side_panel.rs | 2 +- rog-control-center/src/widgets/top_bar.rs | 11 +- rog-dbus/src/zbus_anime.rs | 6 +- rog-dbus/src/zbus_led.rs | 25 +- rog-dbus/src/zbus_platform.rs | 5 +- rog-dbus/src/zbus_power.rs | 5 +- rog-dbus/src/zbus_profile.rs | 25 +- rog-dbus/src/zbus_supported.rs | 5 +- rog-platform/src/error.rs | 7 +- rog-platform/src/hid_raw.rs | 4 +- rog-platform/src/keyboard_led.rs | 41 +- rog-platform/src/lib.rs | 8 +- rog-platform/src/platform.rs | 35 +- rog-platform/src/power.rs | 23 +- rog-platform/src/supported.rs | 45 +- rog-platform/src/usb_raw.rs | 3 +- rog-profiles/src/fan_curve_set.rs | 21 +- rog-profiles/src/lib.rs | 22 +- rustfmt.toml | 15 + 134 files changed, 8249 insertions(+), 4390 deletions(-) create mode 100644 .editorconfig rename asusctl/examples/{aura-rgb-ball.rs => aura-rgb-ball.rs-} (98%) delete mode 100644 asusctl/examples/aura-rgb-breathe.rs delete mode 100644 asusctl/examples/aura-rgb-iterate-keys.rs delete mode 100644 daemon/src/laptops.rs delete mode 100644 data/asusd-ledmodes.toml create mode 100644 rog-aura/data/aura_support.ron create mode 100644 rog-aura/data/layouts/fa506i_US.ron create mode 100644 rog-aura/data/layouts/fa507_US.ron create mode 100644 rog-aura/data/layouts/fx505d_US.ron create mode 100644 rog-aura/data/layouts/g512_US.ron delete mode 100644 rog-aura/data/layouts/g513_US.toml create mode 100644 rog-aura/data/layouts/g513i-per-key_US.ron create mode 100644 rog-aura/data/layouts/g513i_US.ron delete mode 100644 rog-aura/data/layouts/g533_US.toml create mode 100644 rog-aura/data/layouts/g533q-per-key_US.ron create mode 100644 rog-aura/data/layouts/g533q_US.ron delete mode 100644 rog-aura/data/layouts/ga401_US.toml create mode 100644 rog-aura/data/layouts/ga401q_US.ron create mode 100644 rog-aura/data/layouts/gl503_US.ron delete mode 100644 rog-aura/data/layouts/gl504_US.toml create mode 100644 rog-aura/data/layouts/gx502_US.ron delete mode 100644 rog-aura/data/layouts/gx502_US.toml create mode 100644 rog-aura/data/layouts/gx531-per-key_US.ron create mode 100644 rog-aura/data/per_key_raw_bytes.ods create mode 100644 rog-aura/src/advanced.rs create mode 100644 rog-aura/src/advanced_to_str.rs create mode 100644 rog-aura/src/aura_detection.rs create mode 100644 rog-aura/src/effects/base.rs create mode 100644 rog-aura/src/effects/breathe.rs create mode 100644 rog-aura/src/effects/doom.rs create mode 100644 rog-aura/src/effects/mod.rs create mode 100644 rog-aura/src/effects/static_.rs delete mode 100644 rog-aura/src/key_to_str.rs delete mode 100644 rog-aura/src/keys.rs create mode 100644 rog-aura/src/layouts.rs delete mode 100644 rog-aura/src/layouts/g513.rs delete mode 100644 rog-aura/src/layouts/ga401.rs delete mode 100644 rog-aura/src/layouts/gx502.rs delete mode 100644 rog-aura/src/layouts/mod.rs delete mode 100644 rog-aura/src/layouts/old_gx502.rs delete mode 100644 rog-aura/src/per_key_rgb.rs delete mode 100644 rog-aura/src/per_zone.rs delete mode 100644 rog-aura/src/sequencer/effects.rs delete mode 100644 rog-aura/src/sequencer/mod.rs create mode 100644 rog-control-center/src/cli_options.rs create mode 100644 rustfmt.toml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ed6894e5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.rs] +indent_size = 4 + +[tests/**/*.rs] +charset = utf-8 +end_of_line = unset +indent_size = unset +indent_style = unset +trim_trailing_whitespace = unset +insert_final_newline = unset diff --git a/.gitignore b/.gitignore index 047fdb52..39daca04 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ vendor vendor-* vendor_* .vscode-ctags -.vscode \ No newline at end of file +.vscode +.~lock.* +*.ods# \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ad13eef..8d266993 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Added option to set `disable_nvidia_powerd_on_battery` - Add short log entry to throttle_thermal_policy change detection +- ROGCC: Don't notify user if changing to same mux mode +- ROGCC: Add CLI opt for loading a keyboard layout for testing, with live-reload on file change +- ROGCC: Add CLI opt for viewing all layout files + filenames to help find a layout matching your laptop + + Both of these options would hopefully be temporary and replaced with a "wizard" GUI helper +### BREAKING +- Rename aura dbus method from `per_key_raw` to `direct_addressing_raw` and add doc comment +- Changes to aura.conf: +- Changes to asusd-ledmodes.toml: + + Rename `standard` to `basic_modes` + + Rename `multizone` to `basic_zones` + + Raname `per_key` to `advanced` and change type from `bool` to `AdvancedAuraType` + + Removed `prod_family` + + Split all entries to `board_name` (separating `board_names`) (now a huge file) + + removed `asusd-ledmodes.toml` in favour of `aura_support.ron` due to an unsupported type in toml +- Rename and adjust `LedSupportedFunctions` to closely match the above ## [v4.5.8] ### Changed - Fix incorrect stop/start order of nvidia-powerd on AC plug/unplug +## [v4.5.7] +### Changed +- ROGCC: Don't notify user if changing to same mux mode +- + ## [v4.5.7] ### Changed - ROGCC: Don't notify user if changing to same mux mode @@ -576,6 +596,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix small deadlock with awaits -## [1.0.0] - 2020-08-13 - -- Major fork and refactor to use asus-hid patch for ASUS N-Key device +## [1.0.0] \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 16b4cf60..969dc3d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -292,9 +292,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ "proc-macro2", "quote", @@ -349,6 +349,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + [[package]] name = "bindgen" version = "0.54.0" @@ -500,9 +506,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cesu8" @@ -1770,15 +1776,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.2.6" @@ -1866,7 +1863,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" dependencies = [ - "hermit-abi 0.2.6", + "hermit-abi", "io-lifetimes", "rustix", "windows-sys 0.42.0", @@ -1960,9 +1957,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libloading" @@ -2023,9 +2020,9 @@ dependencies = [ [[package]] name = "logind-zbus" -version = "3.0.3" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214b1739f5cf1b467329c1a7b42e9b142aee6dce3f38a86cf902b5b6ac1b55b3" +checksum = "3f2cfc54565c8d002ad7344ec08ce512c269b2de56dea59850708691e4b18fe3" dependencies = [ "serde", "zbus", @@ -2275,11 +2272,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", ] @@ -2520,9 +2517,9 @@ dependencies = [ [[package]] name = "polling" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748" +checksum = "22122d5ec4f9fe1b3916419b76be1e80bcb93f618d071d2edf841b137b2a2bd6" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -2575,9 +2572,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -2593,9 +2590,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -2704,6 +2701,7 @@ dependencies = [ "egui", "env_logger", "gtk", + "gumdrop", "libappindicator", "log", "nix 0.26.1", @@ -2744,10 +2742,11 @@ dependencies = [ name = "rog_aura" version = "4.5.8" dependencies = [ + "log", + "ron", "serde", "serde_derive", - "serde_json", - "toml", + "sysfs-class", "zbus", ] @@ -2788,6 +2787,17 @@ dependencies = [ "zbus", ] +[[package]] +name = "ron" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300a51053b1cb55c80b7a9fde4120726ddf25ca241a1cbb926626f62fb136bff" +dependencies = [ + "base64", + "bitflags", + "serde", +] + [[package]] name = "rusb" version = "0.9.1" @@ -2895,18 +2905,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.149" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256b9932320c590e707b94576e3cc1f7c9024d0ee6612dfbcf1cb106cbe8e055" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.149" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4eae9b04cbffdfd550eb462ed33bc6a1b68c935127d008b27444d08380f94e4" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", @@ -2926,9 +2936,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" +checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e" dependencies = [ "proc-macro2", "quote", @@ -3130,9 +3140,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -3207,18 +3217,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -3319,9 +3329,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] @@ -3436,9 +3446,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" diff --git a/Cargo.toml b/Cargo.toml index 28b731f4..a50fd449 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,18 +6,18 @@ version = "4.5.8" [workspace.dependencies] async-trait = "^0.1" -tokio = { version = "^1.22.0", features = ["macros", "rt-multi-thread", "time", "sync"]} +tokio = { version = "^1.23.0", features = ["macros", "rt-multi-thread", "time", "sync"]} concat-idents = "^1.1" dirs = "^4.0" smol = "^1.3" -zbus = "^3.5" -logind-zbus = { version = "^3.0.3" } #, default-features = false, features = ["non_blocking"] } +zbus = "^3.6" +logind-zbus = { version = "^3.1.0" } #, default-features = false, features = ["non_blocking"] } serde = "^1.0" serde_derive = "^1.0" serde_json = "^1.0" -toml = "^0.5.9" +toml = "^0.5.10" log = "^0.4" env_logger = "^0.10.0" diff --git a/Makefile b/Makefile index 400c7a7f..316ee132 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ BIN_ROG := rog-control-center BIN_C := asusctl BIN_D := asusd BIN_U := asusd-user -LEDCFG := asusd-ledmodes.toml +LEDCFG := aura_support.ron SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs') @@ -42,14 +42,14 @@ install: $(INSTALL_PROGRAM) "./target/release/$(BIN_ROG)" "$(DESTDIR)$(bindir)/$(BIN_ROG)" $(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).desktop" "$(DESTDIR)$(datarootdir)/applications/$(BIN_ROG).desktop" $(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/$(BIN_ROG).png" - cd rog-aura/data/layouts && find . -type f -name "*.toml" -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/rog-gui/layouts/{}" \; + cd rog-aura/data/layouts && find . -type f -name "*.ron" -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/rog-gui/layouts/{}" \; $(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)" $(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)" $(INSTALL_PROGRAM) "./target/release/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)" $(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules" - $(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)" + $(INSTALL_DATA) "./rog-aura/data/$(LEDCFG)" "$(DESTDIR)$(datarootdir)/asusd/$(LEDCFG)" $(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf" $(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service" diff --git a/asusctl/examples/anime-diag-png.rs b/asusctl/examples/anime-diag-png.rs index 889701ec..6c3ca64b 100644 --- a/asusctl/examples/anime-diag-png.rs +++ b/asusctl/examples/anime-diag-png.rs @@ -1,6 +1,10 @@ -use std::{env, error::Error, path::Path, process::exit}; +use std::env; +use std::error::Error; +use std::path::Path; +use std::process::exit; -use rog_anime::{usb::get_anime_type, AnimeDiagonal, AnimeType}; +use rog_anime::usb::get_anime_type; +use rog_anime::{AnimeDiagonal, AnimeType}; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { diff --git a/asusctl/examples/anime-diag.rs b/asusctl/examples/anime-diag.rs index bcbc584c..fa17227f 100644 --- a/asusctl/examples/anime-diag.rs +++ b/asusctl/examples/anime-diag.rs @@ -1,6 +1,8 @@ -use std::{thread::sleep, time::Duration}; +use std::thread::sleep; +use std::time::Duration; -use rog_anime::{usb::get_anime_type, AnimeDiagonal, AnimeType}; +use rog_anime::usb::get_anime_type; +use rog_anime::{AnimeDiagonal, AnimeType}; use rog_dbus::RogDbusClientBlocking; // In usable data: diff --git a/asusctl/examples/anime-gif.rs b/asusctl/examples/anime-gif.rs index 79deecf0..0b73bae6 100644 --- a/asusctl/examples/anime-gif.rs +++ b/asusctl/examples/anime-gif.rs @@ -1,6 +1,9 @@ -use std::{env, path::Path, thread::sleep}; +use std::env; +use std::path::Path; +use std::thread::sleep; -use rog_anime::{usb::get_anime_type, ActionData, ActionLoader, Sequences}; +use rog_anime::usb::get_anime_type; +use rog_anime::{ActionData, ActionLoader, Sequences}; use rog_dbus::RogDbusClientBlocking; fn main() { diff --git a/asusctl/examples/anime-grid.rs b/asusctl/examples/anime-grid.rs index eb115958..b66f8529 100644 --- a/asusctl/examples/anime-grid.rs +++ b/asusctl/examples/anime-grid.rs @@ -1,7 +1,9 @@ -use rog_anime::{usb::get_anime_type, AnimeDataBuffer, AnimeGrid}; -use rog_dbus::RogDbusClientBlocking; use std::convert::TryFrom; +use rog_anime::usb::get_anime_type; +use rog_anime::{AnimeDataBuffer, AnimeGrid}; +use rog_dbus::RogDbusClientBlocking; + // In usable data: // Top row start at 1, ends at 32 diff --git a/asusctl/examples/anime-outline.rs b/asusctl/examples/anime-outline.rs index f7a0fba9..981a736d 100644 --- a/asusctl/examples/anime-outline.rs +++ b/asusctl/examples/anime-outline.rs @@ -1,4 +1,5 @@ -use rog_anime::{usb::get_anime_type, AnimeDataBuffer}; +use rog_anime::usb::get_anime_type; +use rog_anime::AnimeDataBuffer; use rog_dbus::RogDbusClientBlocking; // In usable data: diff --git a/asusctl/examples/anime-png.rs b/asusctl/examples/anime-png.rs index 42cee160..67f30c51 100644 --- a/asusctl/examples/anime-png.rs +++ b/asusctl/examples/anime-png.rs @@ -1,10 +1,11 @@ use std::convert::TryFrom; -use std::{env, error::Error, path::Path, process::exit}; +use std::env; +use std::error::Error; +use std::path::Path; +use std::process::exit; -use rog_anime::{ - usb::get_anime_type, - AnimeDataBuffer, {AnimeImage, Vec2}, -}; +use rog_anime::usb::get_anime_type; +use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2}; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { diff --git a/asusctl/examples/anime-spinning.rs b/asusctl/examples/anime-spinning.rs index f4f9c757..da1ba3b1 100644 --- a/asusctl/examples/anime-spinning.rs +++ b/asusctl/examples/anime-spinning.rs @@ -1,12 +1,14 @@ use std::convert::TryFrom; -use std::{ - env, error::Error, f32::consts::PI, path::Path, process::exit, thread::sleep, time::Duration, -}; +use std::env; +use std::error::Error; +use std::f32::consts::PI; +use std::path::Path; +use std::process::exit; +use std::thread::sleep; +use std::time::Duration; -use rog_anime::{ - usb::get_anime_type, - AnimeDataBuffer, {AnimeImage, Vec2}, -}; +use rog_anime::usb::get_anime_type; +use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2}; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { diff --git a/asusctl/examples/aura-rgb-ball.rs b/asusctl/examples/aura-rgb-ball.rs- similarity index 98% rename from asusctl/examples/aura-rgb-ball.rs rename to asusctl/examples/aura-rgb-ball.rs- index c4081b91..7bc9aaca 100644 --- a/asusctl/examples/aura-rgb-ball.rs +++ b/asusctl/examples/aura-rgb-ball.rs- @@ -106,7 +106,7 @@ fn main() -> Result<(), Box> { c[2] = 255; }; } - dbus.proxies().led().per_key_raw(colours.get())?; + dbus.proxies().led().direct_addressing_raw(colours.get())?; std::thread::sleep(std::time::Duration::from_millis(150)); } diff --git a/asusctl/examples/aura-rgb-breathe.rs b/asusctl/examples/aura-rgb-breathe.rs deleted file mode 100644 index 1f003baf..00000000 --- a/asusctl/examples/aura-rgb-breathe.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! Using a combination of key-colour array plus a key layout to generate outputs. - -use rog_aura::{keys::Key, layouts::KeyLayout, Breathe, Colour, Effect, LedType, Sequences, Speed}; -use rog_dbus::RogDbusClientBlocking; - -fn main() -> Result<(), Box> { - let layout = KeyLayout::gx502_layout(); - - let (client, _) = RogDbusClientBlocking::new().unwrap(); - - let mut seq = Sequences::new(); - let mut key = Effect::Breathe(Breathe::new( - LedType::Key(Key::W), - Colour(255, 127, 0), - Colour(127, 0, 255), - Speed::Med, - )); - - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::A)); - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::S)); - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::D)); - seq.push(key.clone()); - - let mut key = Effect::Breathe(Breathe::new( - LedType::Key(Key::Q), - Colour(127, 127, 127), - Colour(127, 255, 255), - Speed::Low, - )); - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::E)); - seq.push(key.clone()); - - let mut key = Effect::Breathe(Breathe::new( - LedType::Key(Key::N1), - Colour(166, 127, 166), - Colour(127, 155, 20), - Speed::High, - )); - key.set_led_type(LedType::Key(Key::Tilde)); - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::N2)); - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::N3)); - seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::N4)); - seq.push(key.clone()); - - loop { - seq.next_state(&layout); - let packets = seq.create_packets(); - - client.proxies().led().per_key_raw(packets)?; - std::thread::sleep(std::time::Duration::from_millis(60)); - } -} diff --git a/asusctl/examples/aura-rgb-iterate-keys.rs b/asusctl/examples/aura-rgb-iterate-keys.rs deleted file mode 100644 index eaea65b9..00000000 --- a/asusctl/examples/aura-rgb-iterate-keys.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! Using a combination of key-colour array plus a key layout to generate outputs. - -use rog_aura::{layouts::KeyLayout, KeyColourArray}; -use rog_dbus::RogDbusClientBlocking; - -fn main() -> Result<(), Box> { - let (client, _) = RogDbusClientBlocking::new().unwrap(); - let layout = KeyLayout::gx502_layout(); - loop { - let mut key_colours = KeyColourArray::new(); - for row in layout.rows() { - for (k, key) in row.row().enumerate() { - if k != 0 { - if let Some(prev) = row.row().nth(k - 1) { - if let Some(c) = key_colours.rgb_for_key(*prev) { - c[0] = 0; - }; - } - } - - if key.is_placeholder() { - continue; - } - - if let Some(c) = key_colours.rgb_for_key(*key) { - c[0] = 255; - }; - - client.proxies().led().per_key_raw(key_colours.get())?; - std::thread::sleep(std::time::Duration::from_millis(100)); - } - } - } -} diff --git a/asusctl/examples/aura-zoned-breathe.rs b/asusctl/examples/aura-zoned-breathe.rs index 123b429c..bbeb8aef 100644 --- a/asusctl/examples/aura-zoned-breathe.rs +++ b/asusctl/examples/aura-zoned-breathe.rs @@ -1,44 +1,64 @@ -//! Using a combination of key-colour array plus a key layout to generate outputs. +//! Using a combination of key-colour array plus a key layout to generate +//! outputs. -use rog_aura::{layouts::KeyLayout, Breathe, Colour, Effect, LedType, PerZone, Sequences, Speed}; +use rog_aura::advanced::LedCode; +use rog_aura::effects::{AdvancedEffects, Effect}; +use rog_aura::layouts::KeyLayout; +use rog_aura::Colour; use rog_dbus::RogDbusClientBlocking; fn main() -> Result<(), Box> { - let layout = KeyLayout::gx502_layout(); + let layout = KeyLayout::default_layout(); let (client, _) = RogDbusClientBlocking::new().unwrap(); - let mut seq = Sequences::new(); + let mut seq = AdvancedEffects::new(true); - let zone = Effect::Breathe(Breathe::new( - LedType::Zone(PerZone::KeyboardLeft), - Colour(166, 127, 166), - Colour(127, 155, 20), - Speed::High, + // let zone = Effect::Breathe(rog_aura::effects::Breathe::new( + // RgbAddress::Single, + // Colour(166, 127, 166), + // Colour(127, 155, 20), + // rog_aura::Speed::High, + // )); + // seq.push(zone); + + // let zone = Effect::DoomLightFlash(rog_aura::effects::DoomLightFlash::new( + // RgbAddress::Single, + // Colour(200, 0, 0), + // 80, + // 10, + // )); + // seq.push(zone); + + let zone = Effect::DoomFlicker(rog_aura::effects::DoomFlicker::new( + LedCode::SingleZone, + Colour(200, 110, 0), + 100, + 10, )); seq.push(zone); - let zone = Effect::Breathe(Breathe::new( - LedType::Zone(PerZone::KeyboardCenterLeft), - Colour(16, 127, 255), - Colour(127, 15, 20), - Speed::Low, - )); - seq.push(zone); + // let zone = Effect::Breathe(rog_aura::effects::Breathe::new( + // RgbAddress::KeyboardCenterLeft, + // Colour(16, 127, 255), + // Colour(127, 15, 20), + // rog_aura::Speed::Low, + // )); + // seq.push(zone); - let zone = Effect::Breathe(Breathe::new( - LedType::Zone(PerZone::LightbarRightCorner), - Colour(0, 255, 255), - Colour(255, 0, 255), - Speed::Med, - )); - seq.push(zone); + // let zone = Effect::Breathe(rog_aura::effects::Breathe::new( + // RgbAddress::LightbarRightCorner, + // Colour(0, 255, 255), + // Colour(255, 0, 255), + // rog_aura::Speed::Med, + // )); + // seq.push(zone); loop { seq.next_state(&layout); let packets = seq.create_packets(); - client.proxies().led().per_key_raw(packets)?; - std::thread::sleep(std::time::Duration::from_millis(60)); + client.proxies().led().direct_addressing_raw(packets)?; + std::thread::sleep(std::time::Duration::from_millis(33)); } } diff --git a/asusctl/src/aura_cli.rs b/asusctl/src/aura_cli.rs index 98b92c0f..c28c30a2 100644 --- a/asusctl/src/aura_cli.rs +++ b/asusctl/src/aura_cli.rs @@ -1,7 +1,9 @@ -use gumdrop::Options; -use rog_aura::{error::Error, AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed}; use std::str::FromStr; +use gumdrop::Options; +use rog_aura::error::Error; +use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed}; + #[derive(Options)] pub struct LedPowerCommand1 { #[options(help = "print help message")] @@ -220,7 +222,6 @@ pub struct MultiColourSpeed { /// Byte value for setting the built-in mode. /// /// Enum corresponds to the required integer value -/// // NOTE: The option names here must match those in rog-aura crate #[derive(Options)] pub enum SetAuraBuiltin { diff --git a/asusctl/src/cli_opts.rs b/asusctl/src/cli_opts.rs index eada1083..45d8de2b 100644 --- a/asusctl/src/cli_opts.rs +++ b/asusctl/src/cli_opts.rs @@ -1,10 +1,9 @@ -use crate::{ - anime_cli::AnimeCommand, - aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin}, - profiles_cli::{FanCurveCommand, ProfileCommand}, -}; use gumdrop::Options; +use crate::anime_cli::AnimeCommand; +use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin}; +use crate::profiles_cli::{FanCurveCommand, ProfileCommand}; + #[derive(Default, Options)] pub struct CliStart { #[options(help_flag, help = "print help message")] diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 61bb7846..71249256 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -1,16 +1,15 @@ use std::convert::TryFrom; +use std::env::args; +use std::path::Path; use std::process::Command; use std::thread::sleep; -use std::{env::args, path::Path}; - -use aura_cli::{LedPowerCommand1, LedPowerCommand2}; -use gumdrop::{Opt, Options}; use anime_cli::{AnimeActions, AnimeCommand}; +use aura_cli::{LedPowerCommand1, LedPowerCommand2}; +use gumdrop::{Opt, Options}; use profiles_cli::{FanCurveCommand, ProfileCommand}; use rog_anime::usb::get_anime_type; use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2}; - use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{self, AuraEffect}; use rog_dbus::RogDbusClientBlocking; @@ -150,7 +149,7 @@ fn do_parsed( let commands: Vec = cmdlist.lines().map(|s| s.to_owned()).collect(); for command in commands.iter().filter(|command| { if !matches!( - supported.keyboard_led.prod_id, + supported.keyboard_led.dev_id, AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 @@ -159,7 +158,7 @@ fn do_parsed( { return false; } - if supported.keyboard_led.prod_id != AuraDevice::X19B6 + if supported.keyboard_led.dev_id != AuraDevice::X19B6 && command.trim().starts_with("led-pow-2") { return false; @@ -212,7 +211,10 @@ fn do_parsed( } fn do_gfx() { - println!("Please use supergfxctl for graphics switching. supergfxctl is the result of making asusctl graphics switching generic so all laptops can use it"); + println!( + "Please use supergfxctl for graphics switching. supergfxctl is the result of making \ + asusctl graphics switching generic so all laptops can use it" + ); println!("This command will be removed in future"); } @@ -391,7 +393,7 @@ fn handle_led_mode( if let Some(cmdlist) = LedModeCommand::command_list() { let commands: Vec = cmdlist.lines().map(|s| s.to_string()).collect(); for command in commands.iter().filter(|command| { - for mode in &supported.stock_led_modes { + for mode in &supported.basic_modes { if command .trim() .starts_with(&<&str>::from(mode).to_lowercase()) @@ -399,7 +401,7 @@ fn handle_led_mode( return true; } } - if !supported.multizone_led_mode.is_empty() && command.trim().starts_with("multi") { + if !supported.basic_zones.is_empty() && command.trim().starts_with("multi") { return true; } false @@ -452,14 +454,14 @@ fn handle_led_power1( } if matches!( - supported.prod_id, + supported.dev_id, AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 ) { handle_led_power_1_do_1866(dbus, power)?; return Ok(()); } - if matches!(supported.prod_id, AuraDevice::Tuf) { + if matches!(supported.dev_id, AuraDevice::Tuf) { handle_led_power_1_do_tuf(dbus, power)?; return Ok(()); } @@ -576,7 +578,7 @@ fn handle_led_power2( return Ok(()); } - if supported.prod_id != AuraDevice::X19B6 { + if supported.dev_id != AuraDevice::X19B6 { println!("This option applies only to keyboards with product ID 0x19b6"); } @@ -786,7 +788,10 @@ fn handle_bios_option( dbus.proxies() .rog_bios() .set_gpu_mux_mode(GpuMode::from_mux(opt))?; - println!("The mode change is not active until you reboot, on boot the bios will make the required change"); + println!( + "The mode change is not active until you reboot, on boot the bios will make the \ + required change" + ); } if cmd.gpu_mux_mode_get { let res = dbus.proxies().rog_bios().gpu_mux_mode()?; diff --git a/asusctl/src/profiles_cli.rs b/asusctl/src/profiles_cli.rs index 1d53c7c8..1a1e2983 100644 --- a/asusctl/src/profiles_cli.rs +++ b/asusctl/src/profiles_cli.rs @@ -1,5 +1,6 @@ use gumdrop::Options; -use rog_profiles::{fan_curve_set::CurveData, FanCurvePU, Profile}; +use rog_profiles::fan_curve_set::CurveData; +use rog_profiles::{FanCurvePU, Profile}; #[derive(Debug, Clone, Options)] pub struct ProfileCommand { diff --git a/daemon-user/src/ctrl_anime.rs b/daemon-user/src/ctrl_anime.rs index 05e9d077..25f66747 100644 --- a/daemon-user/src/ctrl_anime.rs +++ b/daemon-user/src/ctrl_anime.rs @@ -1,28 +1,24 @@ +use std::path::Path; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; +use std::thread::sleep; +use std::time::{Duration, Instant}; + use rog_anime::error::AnimeError; use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2}; use rog_dbus::RogDbusClientBlocking; use serde_derive::{Deserialize, Serialize}; -use std::time::Duration; -use std::{ - path::Path, - sync::{ - atomic::{AtomicBool, Ordering}, - Mutex, - }, -}; -use std::{sync::Arc, thread::sleep, time::Instant}; -use zbus::{ - dbus_interface, - zvariant::{ObjectPath, Type}, -}; +use zbus::dbus_interface; +use zbus::zvariant::{ObjectPath, Type}; -use crate::user_config::ConfigLoadSave; -use crate::{error::Error, user_config::UserAnimeConfig}; +use crate::error::Error; +use crate::user_config::{ConfigLoadSave, UserAnimeConfig}; #[derive(Debug, Clone, Deserialize, Serialize, Type)] pub struct Timer { type_of: TimeType, - /// If time type is Timer then this is milliseonds, otherwise it is animation loop count + /// If time type is Timer then this is milliseonds, otherwise it is + /// animation loop count count: u64, /// Used only for `TimeType::Timer`, milliseonds to fade the image in for fade_in: Option, @@ -64,8 +60,8 @@ pub enum TimeType { Infinite, } -/// The inner object exists to allow the zbus proxy to share it with a runner thread -/// and a zbus server behind `Arc>` +/// The inner object exists to allow the zbus proxy to share it with a runner +/// thread and a zbus server behind `Arc>` pub struct CtrlAnimeInner<'a> { sequences: Sequences, client: RogDbusClientBlocking<'a>, @@ -84,7 +80,9 @@ impl<'a> CtrlAnimeInner<'static> { do_early_return, }) } - /// To be called on each main loop iteration to pump out commands to the anime + + /// To be called on each main loop iteration to pump out commands to the + /// anime pub fn run(&'a self) -> Result<(), Error> { if self.do_early_return.load(Ordering::SeqCst) { return Ok(()); diff --git a/daemon-user/src/daemon.rs b/daemon-user/src/daemon.rs index b2e1f36c..c6962d60 100644 --- a/daemon-user/src/daemon.rs +++ b/daemon-user/src/daemon.rs @@ -1,18 +1,19 @@ +use std::fs::OpenOptions; +use std::io::Read; +use std::path::PathBuf; +use std::sync::atomic::AtomicBool; +use std::sync::{Arc, Mutex}; + use rog_anime::usb::get_anime_type; +use rog_aura::aura_detection::LaptopLedData; use rog_aura::layouts::KeyLayout; use rog_dbus::RogDbusClientBlocking; -use rog_user::{ - ctrl_anime::{CtrlAnime, CtrlAnimeInner}, - user_config::*, - DBUS_NAME, -}; +use rog_user::ctrl_anime::{CtrlAnime, CtrlAnimeInner}; +use rog_user::user_config::*; +use rog_user::DBUS_NAME; use smol::Executor; -use std::sync::Mutex; -use std::{fs::OpenOptions, io::Read, path::PathBuf, sync::Arc}; use zbus::Connection; -use std::sync::atomic::AtomicBool; - #[cfg(not(feature = "local_data"))] const DATA_DIR: &str = "/usr/share/rog-gui/"; #[cfg(feature = "local_data")] @@ -82,11 +83,13 @@ fn main() -> Result<(), Box> { let mut board_name = String::new(); file.read_to_string(&mut board_name)?; - let layout = KeyLayout::find_layout(board_name.as_str(), PathBuf::from(DATA_DIR)) + let led_support = LaptopLedData::get_data(); + + let layout = KeyLayout::find_layout(led_support, PathBuf::from(DATA_DIR)) .map_err(|e| { println!("{BOARD_NAME}, {e}"); }) - .unwrap_or_else(|_| KeyLayout::ga401_layout()); + .unwrap_or_else(|_| KeyLayout::default_layout()); executor .spawn(async move { @@ -99,7 +102,11 @@ fn main() -> Result<(), Box> { aura_config.aura.next_state(&layout); let packets = aura_config.aura.create_packets(); - client.proxies().led().per_key_raw(packets).unwrap(); + client + .proxies() + .led() + .direct_addressing_raw(packets) + .unwrap(); std::thread::sleep(std::time::Duration::from_millis(33)); } }) diff --git a/daemon-user/src/user_config.rs b/daemon-user/src/user_config.rs index 00045337..70984ca4 100644 --- a/daemon-user/src/user_config.rs +++ b/daemon-user/src/user_config.rs @@ -1,11 +1,11 @@ -use std::{ - fs::{create_dir, OpenOptions}, - io::{Read, Write}, - time::Duration, -}; +use std::fs::{create_dir, OpenOptions}; +use std::io::{Read, Write}; +use std::time::Duration; -use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences, Vec2}; -use rog_aura::{keys::Key, Breathe, Colour, Effect, Flicker, LedType, Speed, Static}; +use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2}; +use rog_aura::advanced::LedCode; +use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static}; +use rog_aura::{Colour, Speed}; use serde::de::DeserializeOwned; use serde_derive::{Deserialize, Serialize}; @@ -87,8 +87,8 @@ pub struct UserAnimeConfig { } impl UserAnimeConfig { - pub fn create(&self, anime_type: AnimeType) -> Result { - let mut seq = Sequences::new(anime_type); + pub fn create(&self, anime_type: AnimeType) -> Result { + let mut seq = AnimeSequences::new(anime_type); for (idx, action) in self.anime.iter().enumerate() { seq.insert(idx, action)?; @@ -175,7 +175,7 @@ impl Default for UserAnimeConfig { #[derive(Debug, Deserialize, Serialize)] pub struct UserAuraConfig { pub name: String, - pub aura: rog_aura::Sequences, + pub aura: AuraSequences, } impl ConfigLoadSave for UserAuraConfig { @@ -193,43 +193,38 @@ impl ConfigLoadSave for UserAuraConfig { impl Default for UserAuraConfig { fn default() -> Self { - let mut seq = rog_aura::Sequences::new(); + let mut seq = AuraSequences::new(false); let mut key = Effect::Breathe(Breathe::new( - LedType::Key(Key::W), + LedCode::W, Colour(255, 0, 20), Colour(20, 255, 0), Speed::Low, )); seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::A)); + key.set_led(LedCode::A); seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::S)); + key.set_led(LedCode::S); seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::D)); + key.set_led(LedCode::D); seq.push(key); let key = Effect::Breathe(Breathe::new( - LedType::Key(Key::F), + LedCode::F, Colour(255, 0, 0), Colour(255, 0, 0), Speed::High, )); seq.push(key); - let mut key = Effect::Static(Static::new(LedType::Key(Key::RCtrl), Colour(0, 0, 255))); + let mut key = Effect::Static(Static::new(LedCode::RCtrl, Colour(0, 0, 255))); seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::LCtrl)); + key.set_led(LedCode::LCtrl); seq.push(key.clone()); - key.set_led_type(LedType::Key(Key::Esc)); + key.set_led(LedCode::Esc); seq.push(key); - let key = Effect::Flicker(Flicker::new( - LedType::Key(Key::N9), - Colour(0, 0, 255), - 80, - 40, - )); + let key = Effect::DoomFlicker(DoomFlicker::new(LedCode::N9, Colour(0, 0, 255), 80, 40)); seq.push(key); Self { diff --git a/daemon-user/src/zbus_anime.rs b/daemon-user/src/zbus_anime.rs index 6a22aa9c..d08c2185 100644 --- a/daemon-user/src/zbus_anime.rs +++ b/daemon-user/src/zbus_anime.rs @@ -1,7 +1,8 @@ //! # DBus interface proxy for: `org.asuslinux.Daemon` //! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Anime' from service 'org.asuslinux.Daemon' on session bus`. +//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection +//! data. Source: `Interface '/org/asuslinux/Anime' from service +//! 'org.asuslinux.Daemon' on session bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! diff --git a/daemon/src/config.rs b/daemon/src/config.rs index 8a832d01..7b320107 100644 --- a/daemon/src/config.rs +++ b/daemon/src/config.rs @@ -1,9 +1,10 @@ -use log::{error, warn}; -use serde_derive::{Deserialize, Serialize}; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; use std::path::PathBuf; +use log::{error, warn}; +use serde_derive::{Deserialize, Serialize}; + pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf"; #[derive(Deserialize, Serialize, Default)] diff --git a/daemon/src/ctrl_anime/config.rs b/daemon/src/ctrl_anime/config.rs index a63a7eac..76e087d2 100644 --- a/daemon/src/ctrl_anime/config.rs +++ b/daemon/src/ctrl_anime/config.rs @@ -1,12 +1,14 @@ -use crate::VERSION; -use log::{error, info, warn}; -use rog_anime::{error::AnimeError, ActionData, ActionLoader, AnimTime, Vec2}; -use rog_anime::{AnimeType, Fade}; -use serde_derive::{Deserialize, Serialize}; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; use std::time::Duration; +use log::{error, info, warn}; +use rog_anime::error::AnimeError; +use rog_anime::{ActionData, ActionLoader, AnimTime, AnimeType, Fade, Vec2}; +use serde_derive::{Deserialize, Serialize}; + +use crate::VERSION; + pub static ANIME_CONFIG_PATH: &str = "/etc/asusd/anime.conf"; pub static ANIME_CACHE_PATH: &str = "/etc/asusd/anime-cache.conf"; diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index b8d4a27e..bde88d6c 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -2,18 +2,24 @@ pub mod config; /// Implements `CtrlTask`, Reloadable, `ZbusRun` pub mod trait_impls; -use self::config::{AnimeConfig, AnimeConfigCached}; -use crate::{error::RogError, GetSupported}; +use std::convert::TryFrom; +use std::error::Error; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Arc; +use std::thread::sleep; + use ::zbus::export::futures_util::lock::Mutex; use log::{error, info, warn}; -use rog_anime::{ - error::AnimeError, - usb::{get_anime_type, pkt_for_flush, pkts_for_init}, - ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, -}; -use rog_platform::{hid_raw::HidRaw, supported::AnimeSupportedFunctions, usb_raw::USBRaw}; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::{convert::TryFrom, error::Error, sync::Arc, thread::sleep}; +use rog_anime::error::AnimeError; +use rog_anime::usb::{get_anime_type, pkt_for_flush, pkts_for_init}; +use rog_anime::{ActionData, AnimeDataBuffer, AnimePacketType, AnimeType}; +use rog_platform::hid_raw::HidRaw; +use rog_platform::supported::AnimeSupportedFunctions; +use rog_platform::usb_raw::USBRaw; + +use self::config::{AnimeConfig, AnimeConfigCached}; +use crate::error::RogError; +use crate::GetSupported; impl GetSupported for CtrlAnime { type A = AnimeSupportedFunctions; @@ -56,13 +62,14 @@ impl CtrlAnime { Ok(ctrl) } + // let device = CtrlAnime::get_device(0x0b05, 0x193b)?; - /// Start an action thread. This is classed as a singleton and there should be only - /// one running - so the thread uses atomics to signal run/exit. + /// Start an action thread. This is classed as a singleton and there should + /// be only one running - so the thread uses atomics to signal run/exit. /// - /// Because this also writes to the usb device, other write tries (display only) *must* - /// get the mutex lock and set the `thread_exit` atomic. + /// Because this also writes to the usb device, other write tries (display + /// only) *must* get the mutex lock and set the `thread_exit` atomic. fn run_thread(inner: Arc>, actions: Vec, mut once: bool) { if actions.is_empty() { warn!("AniMe system actions was empty"); @@ -70,12 +77,15 @@ impl CtrlAnime { } // Loop rules: - // - Lock the mutex **only when required**. That is, the lock must be held for the shortest duration possible. - // - An AtomicBool used for thread exit should be checked in every loop, including nested + // - Lock the mutex **only when required**. That is, the lock must be held for + // the shortest duration possible. + // - An AtomicBool used for thread exit should be checked in every loop, + // including nested - // The only reason for this outer thread is to prevent blocking while waiting for the - // next spawned thread to exit - // TODO: turn this in to async task (maybe? COuld still risk blocking main thread) + // The only reason for this outer thread is to prevent blocking while waiting + // for the next spawned thread to exit + // TODO: turn this in to async task (maybe? COuld still risk blocking main + // thread) std::thread::Builder::new() .name("AniMe system thread start".into()) .spawn(move || { diff --git a/daemon/src/ctrl_anime/trait_impls.rs b/daemon/src/ctrl_anime/trait_impls.rs index 64fb7f9c..0da684c8 100644 --- a/daemon/src/ctrl_anime/trait_impls.rs +++ b/daemon/src/ctrl_anime/trait_impls.rs @@ -1,17 +1,15 @@ -use super::CtrlAnime; -use crate::error::RogError; +use std::sync::atomic::Ordering; +use std::sync::Arc; + use async_trait::async_trait; use log::{info, warn}; -use rog_anime::{ - usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}, - AnimeDataBuffer, AnimePowerStates, -}; -use std::sync::{atomic::Ordering, Arc}; -use zbus::{ - dbus_interface, - export::futures_util::lock::{Mutex, MutexGuard}, - Connection, SignalContext, -}; +use rog_anime::usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}; +use rog_anime::{AnimeDataBuffer, AnimePowerStates}; +use zbus::export::futures_util::lock::{Mutex, MutexGuard}; +use zbus::{dbus_interface, Connection, SignalContext}; + +use super::CtrlAnime; +use crate::error::RogError; pub(super) const ZBUS_PATH: &str = "/org/asuslinux/Anime"; @@ -27,11 +25,12 @@ impl crate::ZbusRun for CtrlAnimeZbus { } // None of these calls can be guarnateed to succeed unless we loop until okay -// If the try_lock *does* succeed then any other thread trying to lock will not grab it -// until we finish. +// If the try_lock *does* succeed then any other thread trying to lock will not +// grab it until we finish. #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlAnimeZbus { - /// Writes a data stream of length. Will force system thread to exit until it is restarted + /// Writes a data stream of length. Will force system thread to exit until + /// it is restarted async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> { let lock = self.0.lock().await; lock.thread_exit.store(true, Ordering::SeqCst); @@ -133,7 +132,8 @@ impl CtrlAnimeZbus { lock.config.boot_anim_enabled } - /// Notify listeners of the status of AniMe LED power and factory system-status animations + /// Notify listeners of the status of AniMe LED power and factory + /// system-status animations #[dbus_interface(signal)] async fn notify_power_states( ctxt: &SignalContext<'_>, diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index 6e9dc2bb..8e52583d 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -1,13 +1,14 @@ -use crate::laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; +use std::collections::{BTreeMap, HashSet}; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; + use log::{error, warn}; +use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT}; use rog_platform::hid_raw::HidRaw; use rog_platform::keyboard_led::KeyboardLed; use serde_derive::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashSet}; -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; @@ -70,6 +71,7 @@ impl AuraPowerConfig { } } } + pub fn set_0x1866(&mut self, power: AuraDev1866, on: bool) { if let Self::AuraDev1866(p) = self { if on { @@ -227,14 +229,14 @@ impl AuraConfig { // create a default config here let mut config = AuraConfig::default(); - for n in &support_data.standard { + for n in &support_data.basic_modes { config .builtins .insert(*n, AuraEffect::default_with_mode(*n)); - if !support_data.multizone.is_empty() { + if !support_data.basic_zones.is_empty() { let mut default = vec![]; - for (i, tmp) in support_data.multizone.iter().enumerate() { + for (i, tmp) in support_data.basic_zones.iter().enumerate() { default.push(AuraEffect { mode: *n, zone: *tmp, @@ -287,7 +289,8 @@ impl AuraConfig { /// Set the mode data, current mode, and if multizone enabled. /// - /// Multipurpose, will accept `AuraEffect` with zones and put in the correct store. + /// Multipurpose, will accept `AuraEffect` with zones and put in the correct + /// store. pub fn set_builtin(&mut self, effect: AuraEffect) { self.current_mode = effect.mode; if effect.zone() == AuraZone::None { @@ -325,9 +328,10 @@ impl AuraConfig { #[cfg(test)] mod tests { - use super::AuraConfig; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; + use super::AuraConfig; + #[test] fn set_multizone_4key_config() { let mut config = AuraConfig::default(); diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index 5d6bfee7..077063a8 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -1,19 +1,17 @@ -use crate::{ - error::RogError, - laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, -}; -use log::{info, warn}; -use rog_aura::{ - usb::{AuraDevice, LED_APPLY, LED_SET}, - AuraEffect, KeyColourArray, LedBrightness, PerKeyRaw, LED_MSG_LEN, -}; -use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; -use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions}; use std::collections::BTreeMap; -use crate::GetSupported; +use log::{info, warn}; +use rog_aura::advanced::{LedUsbPackets, UsbPackets}; +use rog_aura::aura_detection::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; +use rog_aura::usb::{AuraDevice, LED_APPLY, LED_SET}; +use rog_aura::{AuraEffect, AuraZone, Direction, LedBrightness, Speed, GRADIENT, LED_MSG_LEN}; +use rog_platform::hid_raw::HidRaw; +use rog_platform::keyboard_led::KeyboardLed; +use rog_platform::supported::LedSupportedFunctions; use super::config::{AuraConfig, AuraPowerConfig}; +use crate::error::RogError; +use crate::GetSupported; impl GetSupported for CtrlKbdLed { type A = LedSupportedFunctions; @@ -21,9 +19,9 @@ impl GetSupported for CtrlKbdLed { fn get_supported() -> Self::A { // let mode = <&str>::from(&::from(*mode)); let laptop = LaptopLedData::get_data(); - let stock_led_modes = laptop.standard; - let multizone_led_mode = laptop.multizone; - let per_key_led_mode = laptop.per_key; + let stock_led_modes = laptop.basic_modes; + let multizone_led_mode = laptop.basic_zones; + let advanced_type = laptop.advanced_type; let mut prod_id = AuraDevice::Unknown; for prod in &ASUS_KEYBOARD_DEVICES { @@ -41,11 +39,11 @@ impl GetSupported for CtrlKbdLed { } LedSupportedFunctions { - prod_id, - brightness_set: rgb.is_ok(), - stock_led_modes, - multizone_led_mode, - per_key_led_mode, + dev_id: prod_id, + brightness: rgb.is_ok(), + basic_modes: stock_led_modes, + basic_zones: multizone_led_mode, + advanced_type: advanced_type.into(), } } } @@ -152,7 +150,8 @@ impl CtrlKbdLed { self.set_brightness(self.config.brightness) } - /// Set combination state for boot animation/sleep animation/all leds/keys leds/side leds LED active + /// Set combination state for boot animation/sleep animation/all leds/keys + /// leds/side leds LED active pub(super) fn set_power_states(&mut self) -> Result<(), RogError> { if let LEDNode::KbdLed(platform) = &mut self.led_node { if let Some(pwr) = AuraPowerConfig::to_tuf_bool_array(&self.config.enabled) { @@ -173,12 +172,12 @@ impl CtrlKbdLed { /// Set an Aura effect if the effect mode or zone is supported. /// - /// On success the aura config file is read to refresh cached values, then the effect is - /// stored and config written to disk. + /// On success the aura config file is read to refresh cached values, then + /// the effect is stored and config written to disk. pub(crate) fn set_effect(&mut self, effect: AuraEffect) -> Result<(), RogError> { - if !self.supported_modes.standard.contains(&effect.mode) + if !self.supported_modes.basic_modes.contains(&effect.mode) || effect.zone != AuraZone::None - && !self.supported_modes.multizone.contains(&effect.zone) + && !self.supported_modes.basic_zones.contains(&effect.zone) { return Err(RogError::AuraEffectNotSupported); } @@ -193,7 +192,7 @@ impl CtrlKbdLed { /// Write an effect block. This is for per-key, but can be repurposed to /// write the raw factory mode packets - when doing this it is expected that /// only the first `Vec` (`effect[0]`) is valid. - pub fn write_effect_block(&mut self, effect: &PerKeyRaw) -> Result<(), RogError> { + pub fn write_effect_block(&mut self, effect: &UsbPackets) -> Result<(), RogError> { let pkt_type = effect[0][1]; const PER_KEY_TYPE: u8 = 0xbc; @@ -207,7 +206,7 @@ impl CtrlKbdLed { } else { if !self.per_key_mode_active { if let LEDNode::Rog(hid_raw) = &self.led_node { - let init = KeyColourArray::get_init_msg(); + let init = LedUsbPackets::get_init_msg(); hid_raw.write_bytes(&init)?; } self.per_key_mode_active = true; @@ -233,7 +232,7 @@ impl CtrlKbdLed { let current = self.config.current_mode; if let Some(idx) = self .supported_modes - .standard + .basic_modes .iter() .position(|v| *v == current) { @@ -241,17 +240,17 @@ impl CtrlKbdLed { // goes past end of array if reverse { if idx == 0 { - idx = self.supported_modes.standard.len() - 1; + idx = self.supported_modes.basic_modes.len() - 1; } else { idx -= 1; } } else { idx += 1; - if idx == self.supported_modes.standard.len() { + if idx == self.supported_modes.basic_modes.len() { idx = 0; } } - let next = self.supported_modes.standard[idx]; + let next = self.supported_modes.basic_modes[idx]; self.config.read(); // if self.config.builtins.contains_key(&next) { @@ -324,10 +323,11 @@ impl CtrlKbdLed { Ok(()) } - /// Create a default for the `current_mode` if multizone and no config exists. + /// Create a default for the `current_mode` if multizone and no config + /// exists. fn create_multizone_default(&mut self) -> Result<(), RogError> { let mut default = vec![]; - for (i, tmp) in self.supported_modes.multizone.iter().enumerate() { + for (i, tmp) in self.supported_modes.basic_zones.iter().enumerate() { default.push(AuraEffect { mode: self.config.current_mode, zone: *tmp, @@ -354,15 +354,13 @@ impl CtrlKbdLed { #[cfg(test)] mod tests { + use rog_aura::aura_detection::LaptopLedData; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; use rog_platform::keyboard_led::KeyboardLed; - use crate::{ - ctrl_aura::{config::AuraConfig, controller::LEDNode}, - laptops::LaptopLedData, - }; - use super::CtrlKbdLed; + use crate::ctrl_aura::config::AuraConfig; + use crate::ctrl_aura::controller::LEDNode; #[test] // #[ignore = "Must be manually run due to detection stage"] @@ -370,11 +368,11 @@ mod tests { // Checking to ensure set_mode errors when unsupported modes are tried let config = AuraConfig::default(); let supported_modes = LaptopLedData { - prod_family: String::new(), - board_names: vec![], - standard: vec![AuraModeNum::Static], - multizone: vec![], - per_key: false, + board_name: String::new(), + layout_name: "ga401".to_owned(), + basic_modes: vec![AuraModeNum::Static], + basic_zones: vec![], + advanced_type: rog_aura::AdvancedAuraType::None, }; let mut controller = CtrlKbdLed { led_prod: None, @@ -392,7 +390,8 @@ mod tests { ..Default::default() }; - // This error comes from write_bytes because we don't have a keyboard node stored + // This error comes from write_bytes because we don't have a keyboard node + // stored assert_eq!( controller .set_effect(effect.clone()) @@ -420,7 +419,7 @@ mod tests { "Aura effect not supported" ); - controller.supported_modes.multizone.push(AuraZone::Key2); + controller.supported_modes.basic_zones.push(AuraZone::Key2); assert_eq!( controller.set_effect(effect).unwrap_err().to_string(), "No supported Aura keyboard" @@ -432,11 +431,11 @@ mod tests { // Checking to ensure set_mode errors when unsupported modes are tried let config = AuraConfig::default(); let supported_modes = LaptopLedData { - prod_family: String::new(), - board_names: vec![], - standard: vec![AuraModeNum::Static], - multizone: vec![], - per_key: false, + board_name: String::new(), + layout_name: "ga401".to_owned(), + basic_modes: vec![AuraModeNum::Static], + basic_zones: vec![], + advanced_type: rog_aura::AdvancedAuraType::None, }; let mut controller = CtrlKbdLed { led_prod: None, @@ -452,8 +451,8 @@ mod tests { assert!(controller.create_multizone_default().is_err()); assert!(controller.config.multizone.is_none()); - controller.supported_modes.multizone.push(AuraZone::Key1); - controller.supported_modes.multizone.push(AuraZone::Key2); + controller.supported_modes.basic_zones.push(AuraZone::Key1); + controller.supported_modes.basic_zones.push(AuraZone::Key2); assert!(controller.create_multizone_default().is_ok()); assert!(controller.config.multizone.is_some()); @@ -470,11 +469,11 @@ mod tests { // Checking to ensure set_mode errors when unsupported modes are tried let config = AuraConfig::default(); let supported_modes = LaptopLedData { - prod_family: String::new(), - board_names: vec![], - standard: vec![AuraModeNum::Static], - multizone: vec![AuraZone::Key1, AuraZone::Key2], - per_key: false, + board_name: String::new(), + layout_name: "ga401".to_owned(), + basic_modes: vec![AuraModeNum::Static], + basic_zones: vec![AuraZone::Key1, AuraZone::Key2], + advanced_type: rog_aura::AdvancedAuraType::None, }; let mut controller = CtrlKbdLed { led_prod: None, diff --git a/daemon/src/ctrl_aura/trait_impls.rs b/daemon/src/ctrl_aura/trait_impls.rs index 0bc2d4ba..edf0038b 100644 --- a/daemon/src/ctrl_aura/trait_impls.rs +++ b/daemon/src/ctrl_aura/trait_impls.rs @@ -1,19 +1,18 @@ +use std::collections::BTreeMap; +use std::sync::Arc; + use async_trait::async_trait; use log::{error, info, warn}; -use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw}; -use std::{collections::BTreeMap, sync::Arc}; -use zbus::{ - dbus_interface, - export::futures_util::{ - lock::{Mutex, MutexGuard}, - StreamExt, - }, - Connection, SignalContext, -}; - -use crate::{error::RogError, CtrlTask}; +use rog_aura::advanced::UsbPackets; +use rog_aura::usb::AuraPowerDev; +use rog_aura::{AuraEffect, AuraModeNum, LedBrightness}; +use zbus::export::futures_util::lock::{Mutex, MutexGuard}; +use zbus::export::futures_util::StreamExt; +use zbus::{dbus_interface, Connection, SignalContext}; use super::controller::CtrlKbdLed; +use crate::error::RogError; +use crate::CtrlTask; pub(super) const ZBUS_PATH: &str = "/org/asuslinux/Aura"; @@ -207,7 +206,10 @@ impl CtrlKbdLedZbus { ctrl.config.builtins.clone() } - async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> { + /// On machine that have some form of either per-key keyboard or per-zone + /// this can be used to write custom effects over dbus. The input is a + /// nested `Vec>` where `Vec` is a raw USB packet + async fn direct_addressing_raw(&self, data: UsbPackets) -> zbus::fdo::Result<()> { let mut ctrl = self.0.lock().await; ctrl.write_effect_block(&data)?; Ok(()) diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index c004217d..505ebd46 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -1,17 +1,19 @@ -use crate::{config::Config, error::RogError, GetSupported}; -use crate::{task_watch_item, CtrlTask}; -use async_trait::async_trait; -use log::{info, warn}; -use rog_platform::platform::{AsusPlatform, GpuMode}; -use rog_platform::supported::RogBiosSupportedFunctions; use std::fs::OpenOptions; use std::io::{Read, Write}; use std::path::Path; use std::process::Command; use std::sync::Arc; + +use async_trait::async_trait; +use log::{info, warn}; +use rog_platform::platform::{AsusPlatform, GpuMode}; +use rog_platform::supported::RogBiosSupportedFunctions; use zbus::export::futures_util::lock::Mutex; -use zbus::Connection; -use zbus::{dbus_interface, SignalContext}; +use zbus::{dbus_interface, Connection, SignalContext}; + +use crate::config::Config; +use crate::error::RogError; +use crate::{task_watch_item, CtrlTask, GetSupported}; const ZBUS_PATH: &str = "/org/asuslinux/Platform"; const ASUS_POST_LOGO_SOUND: &str = @@ -214,7 +216,8 @@ impl CtrlPlatform { }; } - /// Get the `panel_od` value from platform. Updates the stored value in internal config also. + /// Get the `panel_od` value from platform. Updates the stored value in + /// internal config also. fn panel_od(&self) -> bool { let od = self .platform @@ -317,10 +320,12 @@ impl crate::Reloadable for CtrlPlatform { impl CtrlPlatform { task_watch_item!(panel_od platform); + task_watch_item!(dgpu_disable platform); + task_watch_item!(egpu_enable platform); // NOTE: see note further below - //task_watch_item!(gpu_mux_mode platform); + // task_watch_item!(gpu_mux_mode platform); } #[async_trait] @@ -373,9 +378,9 @@ impl CtrlTask for CtrlPlatform { self.watch_panel_od(signal_ctxt.clone()).await?; self.watch_dgpu_disable(signal_ctxt.clone()).await?; self.watch_egpu_enable(signal_ctxt.clone()).await?; - // NOTE: Can't have this as a watch because on a write to it, it reverts back to booted-with value - // as it does not actually change until reboot. - //self.watch_gpu_mux_mode(signal_ctxt.clone()).await?; + // NOTE: Can't have this as a watch because on a write to it, it reverts back to + // booted-with value as it does not actually change until reboot. + // self.watch_gpu_mux_mode(signal_ctxt.clone()).await?; Ok(()) } diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 20537fd5..66a934b7 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -1,18 +1,19 @@ -use crate::{config::Config, error::RogError, GetSupported}; -use crate::{task_watch_item, CtrlTask}; +use std::process::Command; +use std::sync::Arc; +use std::time::Duration; + use async_trait::async_trait; use log::{error, info, warn}; use rog_platform::power::AsusPower; use rog_platform::supported::ChargeSupportedFunctions; -use std::process::Command; -use std::sync::Arc; -use std::time::Duration; use systemd_zbus::{ManagerProxy as SystemdProxy, Mode, UnitFileState}; use tokio::time::sleep; -use zbus::dbus_interface; use zbus::export::futures_util::lock::Mutex; -use zbus::Connection; -use zbus::SignalContext; +use zbus::{dbus_interface, Connection, SignalContext}; + +use crate::config::Config; +use crate::error::RogError; +use crate::{task_watch_item, CtrlTask, GetSupported}; const ZBUS_PATH: &str = "/org/asuslinux/Power"; const NVIDIA_POWERD: &str = "nvidia-powerd.service"; @@ -118,6 +119,8 @@ impl crate::Reloadable for CtrlPower { } impl CtrlPower { + task_watch_item!(charge_control_end_threshold power); + pub fn new(config: Arc>) -> Result { Ok(CtrlPower { power: AsusPower::new()?, @@ -142,8 +145,6 @@ impl CtrlPower { Ok(()) } - - task_watch_item!(charge_control_end_threshold power); } #[async_trait] diff --git a/daemon/src/ctrl_profiles/config.rs b/daemon/src/ctrl_profiles/config.rs index a116f8fd..4addc171 100644 --- a/daemon/src/ctrl_profiles/config.rs +++ b/daemon/src/ctrl_profiles/config.rs @@ -1,8 +1,9 @@ +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; + use log::{error, warn}; use rog_profiles::{FanCurveProfiles, Profile}; use serde_derive::{Deserialize, Serialize}; -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; #[derive(Deserialize, Serialize, Debug)] pub struct ProfileConfig { diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index 331a1458..d113c405 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,5 +1,3 @@ -use crate::error::RogError; -use crate::GetSupported; use log::{info, warn}; use rog_platform::platform::AsusPlatform; use rog_platform::supported::PlatformProfileFunctions; @@ -7,6 +5,8 @@ use rog_profiles::error::ProfileError; use rog_profiles::{FanCurveProfiles, Profile}; use super::config::ProfileConfig; +use crate::error::RogError; +use crate::GetSupported; pub struct CtrlPlatformProfile { pub config: ProfileConfig, @@ -18,7 +18,10 @@ impl GetSupported for CtrlPlatformProfile { fn get_supported() -> Self::A { if !Profile::is_platform_profile_supported() { - warn!("platform_profile kernel interface not found, your laptop does not support this, or the interface is missing."); + warn!( + "platform_profile kernel interface not found, your laptop does not support this, \ + or the interface is missing." + ); } let res = FanCurveProfiles::is_supported(); @@ -28,7 +31,10 @@ impl GetSupported for CtrlPlatformProfile { }; if !fan_curve_supported { - info!("fan curves kernel interface not found, your laptop does not support this, or the interface is missing."); + info!( + "fan curves kernel interface not found, your laptop does not support this, or the \ + interface is missing." + ); } PlatformProfileFunctions { @@ -74,7 +80,8 @@ impl CtrlPlatformProfile { self.config.write(); } - /// Toggle to next profile in list. This will first read the config, switch, then write out + /// Toggle to next profile in list. This will first read the config, switch, + /// then write out pub(super) fn set_next_profile(&mut self) -> Result<(), RogError> { // Read first just incase the user has modified the config before calling this match self.config.active_profile { diff --git a/daemon/src/ctrl_profiles/trait_impls.rs b/daemon/src/ctrl_profiles/trait_impls.rs index 50708e3a..8a274c59 100644 --- a/daemon/src/ctrl_profiles/trait_impls.rs +++ b/daemon/src/ctrl_profiles/trait_impls.rs @@ -1,22 +1,18 @@ +use std::sync::Arc; + use async_trait::async_trait; use log::info; use log::warn; -use rog_profiles::fan_curve_set::CurveData; -use rog_profiles::fan_curve_set::FanCurveSet; -use rog_profiles::FanCurveProfiles; -use rog_profiles::Profile; +use rog_profiles::fan_curve_set::{CurveData, FanCurveSet}; +use rog_profiles::{FanCurveProfiles, Profile}; use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::StreamExt; -use zbus::Connection; -use zbus::SignalContext; - -use std::sync::Arc; -use zbus::{dbus_interface, fdo::Error}; - -use crate::error::RogError; -use crate::CtrlTask; +use zbus::fdo::Error; +use zbus::{dbus_interface, Connection, SignalContext}; use super::controller::CtrlPlatformProfile; +use crate::error::RogError; +use crate::CtrlTask; const ZBUS_PATH: &str = "/org/asuslinux/Profile"; const UNSUPPORTED_MSG: &str = @@ -91,8 +87,8 @@ impl ProfileZbus { Err(Error::Failed(UNSUPPORTED_MSG.to_owned())) } - /// Set a profile fan curve enabled status. Will also activate a fan curve if in the - /// same profile mode + /// Set a profile fan curve enabled status. Will also activate a fan curve + /// if in the same profile mode async fn set_fan_curve_enabled( &mut self, profile: Profile, @@ -145,10 +141,11 @@ impl ProfileZbus { Ok(()) } - /// Reset the stored (self) and device curve to the defaults of the platform. + /// Reset the stored (self) and device curve to the defaults of the + /// platform. /// - /// Each platform_profile has a different default and the defualt can be read - /// only for the currently active profile. + /// Each platform_profile has a different default and the defualt can be + /// read only for the currently active profile. async fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> { let mut ctrl = self.0.lock().await; ctrl.config.read(); @@ -159,10 +156,11 @@ impl ProfileZbus { Ok(()) } - /// Reset the stored (self) and device curve to the defaults of the platform. + /// Reset the stored (self) and device curve to the defaults of the + /// platform. /// - /// Each platform_profile has a different default and the defualt can be read - /// only for the currently active profile. + /// Each platform_profile has a different default and the defualt can be + /// read only for the currently active profile. async fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> { let mut ctrl = self.0.lock().await; ctrl.config.read(); @@ -244,8 +242,9 @@ impl crate::Reloadable for ProfileZbus { let active = ctrl.config.active_profile; if let Some(curves) = &mut ctrl.config.fan_curves { if let Ok(mut device) = FanCurveProfiles::get_device() { - // There is a possibility that the curve was default zeroed, so this call initialises - // the data from system read and we need to save it after + // There is a possibility that the curve was default zeroed, so this call + // initialises the data from system read and we need to save it + // after curves.write_profile_curve_to_platform(active, &mut device)?; ctrl.config.write(); } diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 5a24b733..3a94db75 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -1,27 +1,22 @@ use async_trait::async_trait; use serde_derive::{Deserialize, Serialize}; -use zbus::{dbus_interface, zvariant::Type, Connection}; +use zbus::zvariant::Type; +use zbus::{dbus_interface, Connection}; -use crate::{ - ctrl_anime::CtrlAnime, ctrl_aura::controller::CtrlKbdLed, ctrl_platform::CtrlPlatform, - ctrl_power::CtrlPower, ctrl_profiles::controller::CtrlPlatformProfile, GetSupported, -}; +use crate::ctrl_anime::CtrlAnime; +use crate::ctrl_aura::controller::CtrlKbdLed; +use crate::ctrl_platform::CtrlPlatform; +use crate::ctrl_power::CtrlPower; +use crate::ctrl_profiles::controller::CtrlPlatformProfile; +use crate::GetSupported; -use rog_platform::supported::*; - -#[derive(Serialize, Deserialize, Type)] -pub struct SupportedFunctions { - pub anime_ctrl: AnimeSupportedFunctions, - pub charge_ctrl: ChargeSupportedFunctions, - pub platform_profile: PlatformProfileFunctions, - pub keyboard_led: LedSupportedFunctions, - pub rog_bios_ctrl: RogBiosSupportedFunctions, -} +#[derive(Serialize, Deserialize, Debug, Type)] +pub struct SupportedFunctions(rog_platform::supported::SupportedFunctions); #[dbus_interface(name = "org.asuslinux.Daemon")] impl SupportedFunctions { - fn supported_functions(&self) -> &SupportedFunctions { - self + pub fn supported_functions(&self) -> &rog_platform::supported::SupportedFunctions { + &self.0 } } @@ -36,12 +31,12 @@ impl GetSupported for SupportedFunctions { type A = SupportedFunctions; fn get_supported() -> Self::A { - SupportedFunctions { + Self(rog_platform::supported::SupportedFunctions { anime_ctrl: CtrlAnime::get_supported(), keyboard_led: CtrlKbdLed::get_supported(), charge_ctrl: CtrlPower::get_supported(), platform_profile: CtrlPlatformProfile::get_supported(), rog_bios_ctrl: CtrlPlatform::get_supported(), - } + }) } } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index 268c3294..7f5feead 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -6,25 +6,26 @@ use std::time::Duration; use ::zbus::export::futures_util::lock::Mutex; use ::zbus::Connection; +use daemon::config::Config; +use daemon::ctrl_anime::config::AnimeConfig; +use daemon::ctrl_anime::trait_impls::CtrlAnimeZbus; use daemon::ctrl_anime::CtrlAnime; -use log::{error, info, warn}; -use tokio::time::sleep; -use zbus::SignalContext; - -use daemon::ctrl_anime::{config::AnimeConfig, trait_impls::CtrlAnimeZbus}; -use daemon::ctrl_aura::{config::AuraConfig, controller::CtrlKbdLed, trait_impls::CtrlKbdLedZbus}; +use daemon::ctrl_aura::config::AuraConfig; +use daemon::ctrl_aura::controller::CtrlKbdLed; +use daemon::ctrl_aura::trait_impls::CtrlKbdLedZbus; use daemon::ctrl_platform::CtrlPlatform; use daemon::ctrl_power::CtrlPower; -use daemon::ctrl_profiles::{ - config::ProfileConfig, controller::CtrlPlatformProfile, trait_impls::ProfileZbus, -}; -use daemon::laptops::LaptopLedData; -use daemon::{ - config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported, -}; -use daemon::{CtrlTask, Reloadable, ZbusRun}; +use daemon::ctrl_profiles::config::ProfileConfig; +use daemon::ctrl_profiles::controller::CtrlPlatformProfile; +use daemon::ctrl_profiles::trait_impls::ProfileZbus; +use daemon::ctrl_supported::SupportedFunctions; +use daemon::{print_board_info, CtrlTask, GetSupported, Reloadable, ZbusRun}; +use log::{error, info, warn}; +use rog_aura::aura_detection::LaptopLedData; use rog_dbus::DBUS_NAME; use rog_profiles::Profile; +use tokio::time::sleep; +use zbus::SignalContext; static PROFILE_CONFIG_PATH: &str = "/etc/asusd/profile.conf"; @@ -66,7 +67,7 @@ async fn main() -> Result<(), Box> { async fn start_daemon() -> Result<(), Box> { let supported = SupportedFunctions::get_supported(); print_board_info(); - println!("{}", serde_json::to_string_pretty(&supported)?); + println!("{}", supported.supported_functions()); // Start zbus server let mut connection = Connection::system().await?; diff --git a/daemon/src/error.rs b/daemon/src/error.rs index 70a884b4..a70450e3 100644 --- a/daemon/src/error.rs +++ b/daemon/src/error.rs @@ -1,8 +1,9 @@ +use std::convert::From; +use std::fmt; + use rog_anime::error::AnimeError; use rog_platform::error::PlatformError; use rog_profiles::error::ProfileError; -use std::convert::From; -use std::fmt; #[derive(Debug)] pub enum RogError { @@ -50,14 +51,21 @@ impl fmt::Display for RogError { RogError::NotFound(deets) => write!(f, "Not found: {}", deets), RogError::DoTask(deets) => write!(f, "Task error: {}", deets), RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), - RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), + RogError::MissingLedBrightNode(path, error) => write!( + f, + "Led node at {} is missing, please check you have the required patch or dkms \ + module installed: {}", + path, error + ), RogError::ReloadFail(deets) => write!(f, "Reload error: {}", deets), RogError::Profiles(deets) => write!(f, "Profile error: {}", deets), RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail), RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail), RogError::Io(detail) => write!(f, "std::io error: {}", detail), RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail), - RogError::ChargeLimit(value) => write!(f, "Invalid charging limit, not in range 20-100%: {}", value), + RogError::ChargeLimit(value) => { + write!(f, "Invalid charging limit, not in range 20-100%: {}", value) + } RogError::AuraEffectNotSupported => write!(f, "Aura effect not supported"), RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), RogError::NoAuraNode => write!(f, "No Aura keyboard node found"), diff --git a/daemon/src/laptops.rs b/daemon/src/laptops.rs deleted file mode 100644 index 2dbab730..00000000 --- a/daemon/src/laptops.rs +++ /dev/null @@ -1,167 +0,0 @@ -use log::{info, warn}; -use rog_aura::{AuraModeNum, AuraZone}; -use serde_derive::{Deserialize, Serialize}; -use std::fs::OpenOptions; -use std::io::Read; - -pub const ASUS_LED_MODE_CONF: &str = "/etc/asusd/asusd-ledmodes.toml"; -pub const ASUS_LED_MODE_USER_CONF: &str = "/etc/asusd/asusd-user-ledmodes.toml"; -pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"]; - -pub fn print_board_info() { - let dmi = sysfs_class::DmiId::default(); - let board_name = dmi.board_name().expect("Could not get board_name"); - let prod_family = dmi.product_family().expect("Could not get product_family"); - - info!("Product family: {}", prod_family.trim()); - info!("Board name: {}", board_name.trim()); -} - -pub fn print_modes(supported_modes: &[u8]) { - if !supported_modes.is_empty() { - info!("Supported Keyboard LED modes are:"); - for mode in supported_modes { - let mode = <&str>::from(&::from(*mode)); - info!("- {}", mode); - } - info!( - "If these modes are incorrect you can edit {}", - ASUS_LED_MODE_CONF - ); - } else { - info!("No RGB control available"); - } -} - -#[derive(Debug, Default, Deserialize, Serialize)] -struct LedSupportFile { - led_data: Vec, -} - -#[derive(Debug, Clone, Default, Deserialize, Serialize)] -#[serde(default)] -pub struct LaptopLedData { - pub prod_family: String, - pub board_names: Vec, - pub standard: Vec, - pub multizone: Vec, - pub per_key: bool, -} - -impl LaptopLedData { - pub fn get_data() -> Self { - let dmi = sysfs_class::DmiId::default(); - let board_name = dmi.board_name().expect("Could not get board_name"); - let prod_family = dmi.product_family().expect("Could not get product_family"); - - if let Some(modes) = LedSupportFile::load_from_config() { - if let Some(data) = modes.matcher(&prod_family, &board_name) { - return data; - } - } - info!("Using generic LED control for keyboard brightness only"); - LaptopLedData { - prod_family, - board_names: vec![board_name], - standard: vec![], - multizone: vec![], - per_key: false, - } - } -} - -impl LedSupportFile { - /// Consumes the `LEDModes` - fn matcher(self, prod_family: &str, board_name: &str) -> Option { - for config in self.led_data { - if prod_family.contains(&config.prod_family) { - for board in &config.board_names { - if board_name.contains(board) { - info!("Matched to {} {}", config.prod_family, board); - return Some(config); - } - } - } - } - None - } - - fn load_from_config() -> Option { - let mut loaded = false; - let mut data = LedSupportFile::default(); - // Load user configs first so they are first to be checked - if let Ok(mut file) = OpenOptions::new().read(true).open(ASUS_LED_MODE_USER_CONF) { - let mut buf = String::new(); - if let Ok(l) = file.read_to_string(&mut buf) { - if l == 0 { - warn!("{} is empty", ASUS_LED_MODE_USER_CONF); - } else { - if let Ok(mut tmp) = toml::from_str::(&buf) { - data.led_data.append(&mut tmp.led_data); - } - info!( - "Loaded user-defined LED support data from {}", - ASUS_LED_MODE_USER_CONF - ); - } - } - } - // Load and append the default LED support data - if let Ok(mut file) = OpenOptions::new().read(true).open(ASUS_LED_MODE_CONF) { - let mut buf = String::new(); - if let Ok(l) = file.read_to_string(&mut buf) { - if l == 0 { - warn!("{} is empty", ASUS_LED_MODE_CONF); - } else { - let mut tmp: LedSupportFile = toml::from_str(&buf) - .unwrap_or_else(|_| panic!("Could not deserialise {}", ASUS_LED_MODE_CONF)); - data.led_data.append(&mut tmp.led_data); - loaded = true; - info!( - "Loaded default LED support data from {}", - ASUS_LED_MODE_CONF - ); - } - } - } - - if loaded { - return Some(data); - } - - warn!("Does {} exist?", ASUS_LED_MODE_USER_CONF); - None - } -} - -#[cfg(test)] -mod tests { - use std::{fs::OpenOptions, io::Read, path::PathBuf}; - - use super::LaptopLedData; - use rog_aura::{AuraModeNum, AuraZone}; - - #[test] - fn check_data_parse() { - let led = LaptopLedData { - prod_family: "Test".to_owned(), - board_names: vec!["Test".to_owned()], - standard: vec![AuraModeNum::Static], - multizone: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft], - per_key: false, - }; - - let toml = toml::to_string_pretty(&led).unwrap(); - println!("{toml}"); - - let mut data = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - data.push("../data/asusd-ledmodes.toml"); - - let mut file = OpenOptions::new().read(true).open(&data).unwrap(); - let mut buf = String::new(); - file.read_to_string(&mut buf).unwrap(); - - let x = toml::to_string_pretty(&buf).unwrap(); - println!("{x}"); - } -} diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 7767543f..d46a0c11 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -11,8 +11,6 @@ pub mod ctrl_platform; pub mod ctrl_power; /// Control platform profiles + fan-curves if available pub mod ctrl_profiles; -/// Laptop matching to determine capabilities -pub mod laptops; /// Fetch all supported functions for the laptop pub mod ctrl_supported; @@ -21,21 +19,27 @@ pub mod error; use std::future::Future; -use crate::error::RogError; use async_trait::async_trait; -use log::{debug, warn}; +use log::{debug, info, warn}; use logind_zbus::manager::ManagerProxy; -use zbus::{export::futures_util::StreamExt, zvariant::ObjectPath, Connection, SignalContext}; +use zbus::export::futures_util::StreamExt; +use zbus::zvariant::ObjectPath; +use zbus::{Connection, SignalContext}; -/// This macro adds a function which spawns an `inotify` task on the passed in `Executor`. +use crate::error::RogError; + +/// This macro adds a function which spawns an `inotify` task on the passed in +/// `Executor`. /// -/// The generated function is `watch_()`. Self requires the following methods to be available: -/// - `() -> SomeValue`, functionally is a getter, but is allowed to have side effects. +/// The generated function is `watch_()`. Self requires the following +/// methods to be available: +/// - `() -> SomeValue`, functionally is a getter, but is allowed to have +/// side effects. /// - `notify_(SignalContext, SomeValue)` /// -/// In most cases if `SomeValue` is stored in a config then `()` getter is expected to update it. -/// The getter should *never* write back to the path or attribute that is being watched or an -/// infinite loop will occur. +/// In most cases if `SomeValue` is stored in a config then `()` getter is +/// expected to update it. The getter should *never* write back to the path or +/// attribute that is being watched or an infinite loop will occur. /// /// # Example /// @@ -80,6 +84,15 @@ macro_rules! task_watch_item { pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +pub fn print_board_info() { + let dmi = sysfs_class::DmiId::default(); + let board_name = dmi.board_name().expect("Could not get board_name"); + let prod_family = dmi.product_family().expect("Could not get product_family"); + + info!("Product family: {}", prod_family.trim()); + info!("Board name: {}", board_name.trim()); +} + #[async_trait] pub trait Reloadable { async fn reload(&mut self) -> Result<(), RogError>; @@ -115,13 +128,14 @@ pub trait CtrlTask { SignalContext::new(connection, Self::zbus_path()) } - /// Implement to set up various tasks that may be required, using the `Executor`. - /// No blocking loops are allowed, or they must be run on a separate thread. + /// Implement to set up various tasks that may be required, using the + /// `Executor`. No blocking loops are allowed, or they must be run on a + /// separate thread. async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>; // /// Create a timed repeating task - // async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + 'static) { - // use std::time::Duration; + // async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + + // 'static) { use std::time::Duration; // use tokio::time; // let mut timer = time::interval(Duration::from_millis(millis)); // tokio::spawn(async move { @@ -130,10 +144,11 @@ pub trait CtrlTask { // }); // } - /// Free helper method to create tasks to run on: sleep, wake, shutdown, boot + /// Free helper method to create tasks to run on: sleep, wake, shutdown, + /// boot /// - /// The closures can potentially block, so execution time should be the minimal possible - /// such as save a variable. + /// The closures can potentially block, so execution time should be the + /// minimal possible such as save a variable. async fn create_sys_event_tasks< Fut1, Fut2, diff --git a/data/asusd-ledmodes.toml b/data/asusd-ledmodes.toml deleted file mode 100644 index 577af09b..00000000 --- a/data/asusd-ledmodes.toml +++ /dev/null @@ -1,204 +0,0 @@ -[[led_data]] -prod_family = "ASUS TUF Gaming F15" -board_names = ["FX506HC"] -standard = ["Static", "Breathe", "Strobe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "TUF" -board_names = ["FA507"] -standard = ["Static", "Breathe", "Strobe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "TUF Gaming" -board_names = ["FX505D"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ASUS TUF Gaming A15" -board_names = ["FA506I"] -standard = ["Static", "Breathe", "Strobe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "Zephyrus S" -board_names = ["GX502", "GX701", "G531", "GL531", "G532"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "Zephyrus M" -board_names = ["GU502G"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "ROG Zephyrus M15" -board_names = ["GU502LU"] -standard = ["Static", "Breathe", "Strobe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Zephyrus M15" -board_names = ["GU502L"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "ROG Zephyrus M16" -board_names = ["GU603Z", "GU603H"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Zephyrus S17" -board_names = ["GX703H"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = [] -per_key = false - - -[[led_data]] -prod_family = "Zephyrus" -board_names = ["GM501G", "GX531"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = ["Key1", "Key2", "Key3", "Key4"] -per_key = false - -[[led_data]] -prod_family = "ROG Strix" -board_names = ["G531GW", "G533QR", "G533QS", "G733Q", "G513QR", "G713QR", "G513QM", "G713IC", "G713RS"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "ROG Strix" -board_names = ["G513QE", "GX531", "G512LV", "G712LV", "G712LW", "G513IH", "G513QY", "G713QM", "G512", "G713RM", "G713RW"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = ["Key1", "Key2", "Key3", "Key4"] -per_key = false - -[[led_data]] -prod_family = "ROG Strix" -board_names = ["G512LI", "G712LI", "G531GD"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Strix" -board_names = ["G513IM"] -standard = ["Flash", "Static", "Breathe", "Strobe", "Rainbow"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "Strix" -board_names = ["G731GV", "G731GW", "G531GV"] -standard = ["Static", "Breathe", "Strobe", "Rainbow"] -multizone = ["Key1", "Key2", "Key3", "Key4"] -per_key = false - -[[led_data]] -prod_family = "Strix" -board_names = ["GL504G"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = ["Key1", "Key2", "Key3", "Key4", "Logo", "BarLeft", "BarRight"] -per_key = false - -[[led_data]] -prod_family = "Strix" -board_names = ["G731GT", "G731GU", "G531GT", "G531GU"] -standard = ["Static", "Breathe", "Strobe", "Rainbow"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "Strix Scar" -board_names = ["G531", "G731"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = ["Key1", "Key2", "Key3", "Key4"] -per_key = true - -[[led_data]] -prod_family = "ROG" -board_names = ["GL553VE"] -standard = ["Static", "Breathe", "Strobe"] -multizone = ["Key1", "Key2", "Key3", "Key4"] -per_key = false - -[[led_data]] -prod_family = "ROG Zephyrus G14" -board_names = ["GA401Q"] -standard = ["Static", "Breathe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Zephyrus G14" -board_names = ["GA402R"] -standard = ["Static", "Breathe", "Pulse", "Rainbow"] -multizone = [] -per_key = false - -# GA503QE at higher priority (first match) than GA503Q -[[led_data]] -prod_family = "ROG Zephyrus G15" -board_names = ["GA503QE"] -standard = ["Static", "Breathe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Zephyrus G15" -board_names = ["GA503Q", "GA503R"] -standard = ["Static", "Breathe", "Pulse", "Rainbow", "Strobe"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Zephyrus" -board_names = ["GX550L"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Star", "Rain", "Highlight", "Laser", "Ripple", "Pulse", "Comet", "Flash"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "ROG Zephyrus Duo 15 SE" -board_names = ["GX551Q"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = [] -per_key = true - -[[led_data]] -prod_family = "ROG Flow X13" -board_names = ["GV301Q"] -standard = ["Static", "Breathe", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Strix" -board_names = ["G513IC", "G513RC", "G513RM"] -standard = ["Static", "Breathe", "Strobe", "Rainbow", "Pulse"] -multizone = [] -per_key = false - -[[led_data]] -prod_family = "ROG Flow X16" -board_names = ["GV601R"] -standard = ["Static", "Breathe", "Strobe", "Pulse"] -multizone = [] -per_key = false diff --git a/rog-anime/src/data.rs b/rog-anime/src/data.rs index e8b410e0..65ead7f4 100644 --- a/rog-anime/src/data.rs +++ b/rog-anime/src/data.rs @@ -1,20 +1,17 @@ -use std::{ - convert::TryFrom, - thread::sleep, - time::{Duration, Instant}, -}; +use std::convert::TryFrom; +use std::thread::sleep; +use std::time::{Duration, Instant}; use log::info; use serde_derive::{Deserialize, Serialize}; #[cfg(feature = "dbus")] use zbus::zvariant::Type; -use crate::{ - error::{AnimeError, Result}, - AnimTime, AnimeGif, -}; +use crate::error::{AnimeError, Result}; +use crate::{AnimTime, AnimeGif}; -/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and `USB_PREFIX2` +/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and +/// `USB_PREFIX2` const BLOCK_START: usize = 7; /// *Not* inclusive, the byte before this is the final for each "pane" const BLOCK_END: usize = 634; @@ -143,9 +140,11 @@ impl TryFrom for AnimePacketType { } } -/// This runs the animations as a blocking loop by using the `callback` to write data +/// This runs the animations as a blocking loop by using the `callback` to write +/// data /// -/// If `callback` is `Ok(true)` then `run_animation` will exit the animation loop early. +/// If `callback` is `Ok(true)` then `run_animation` will exit the animation +/// loop early. pub fn run_animation(frames: &AnimeGif, callback: &dyn Fn(AnimeDataBuffer) -> Result) { let mut count = 0; let start = Instant::now(); diff --git a/rog-anime/src/diagonal.rs b/rog-anime/src/diagonal.rs index 30932a5d..1c99556b 100644 --- a/rog-anime/src/diagonal.rs +++ b/rog-anime/src/diagonal.rs @@ -1,12 +1,12 @@ -use std::{path::Path, time::Duration}; +use std::path::Path; +use std::time::Duration; -use crate::{ - data::AnimeDataBuffer, - error::{AnimeError, Result}, - AnimeType, -}; +use crate::data::AnimeDataBuffer; +use crate::error::{AnimeError, Result}; +use crate::AnimeType; -/// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images) +/// Mostly intended to be used with ASUS gifs, but can be used for other +/// purposes (like images) #[derive(Debug, Clone)] pub struct AnimeDiagonal(AnimeType, Vec>, Option); @@ -25,7 +25,8 @@ impl AnimeDiagonal { &mut self.1 } - /// Get a full diagonal row where `x` `y` is the starting point and `len` is the length of data. + /// Get a full diagonal row where `x` `y` is the starting point and `len` + /// is the length of data. fn get_row(&self, x: usize, y: usize, len: usize) -> Vec { let mut buf = Vec::with_capacity(len); for i in 0..len { @@ -36,8 +37,9 @@ impl AnimeDiagonal { buf } - /// Generate the base image from inputs. The result can be displayed as is or - /// updated via scale, position, or angle then displayed again after `update()`. + /// Generate the base image from inputs. The result can be displayed as is + /// or updated via scale, position, or angle then displayed again after + /// `update()`. #[inline] pub fn from_png( path: &Path, @@ -290,7 +292,8 @@ impl AnimeDiagonal { #[cfg(test)] mod tests { - use std::{convert::TryFrom, path::PathBuf}; + use std::convert::TryFrom; + use std::path::PathBuf; use crate::{AnimeDiagonal, AnimePacketType, AnimeType}; diff --git a/rog-anime/src/error.rs b/rog-anime/src/error.rs index b8c7c585..687862c9 100644 --- a/rog-anime/src/error.rs +++ b/rog-anime/src/error.rs @@ -1,8 +1,9 @@ -use gif::DecodingError; -use png_pong::decode::Error as PngError; use std::error::Error; use std::fmt; +use gif::DecodingError; +use png_pong::decode::Error as PngError; + pub type Result = std::result::Result; #[derive(Debug)] @@ -12,7 +13,8 @@ pub enum AnimeError { Png(PngError), Gif(DecodingError), Format, - /// The input was incorrect size, expected size is `IncorrectSize(width, height)` + /// The input was incorrect size, expected size is `IncorrectSize(width, + /// height)` IncorrectSize(u32, u32), Dbus(String), Udev(String, std::io::Error), diff --git a/rog-anime/src/gif.rs b/rog-anime/src/gif.rs index 28059320..d5d6a4c4 100644 --- a/rog-anime/src/gif.rs +++ b/rog-anime/src/gif.rs @@ -1,15 +1,19 @@ +use std::convert::TryFrom; +use std::fs::File; +use std::path::Path; +use std::time::Duration; + use glam::Vec2; use serde_derive::{Deserialize, Serialize}; -use std::convert::TryFrom; -use std::{fs::File, path::Path, time::Duration}; -use crate::error::AnimeError; -use crate::{error::Result, AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel}; +use crate::error::{AnimeError, Result}; +use crate::{AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel}; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct AnimeFrame { /// Precomputed data for the frame. This can be transferred directly to the - /// the `asusd` daemon over dbus or converted to USB packet with `AnimePacketType::from(buffer)` + /// the `asusd` daemon over dbus or converted to USB packet with + /// `AnimePacketType::from(buffer)` data: AnimeDataBuffer, delay: Duration, } @@ -33,7 +37,8 @@ impl AnimeFrame { pub enum AnimTime { /// Time in milliseconds for animation to run Time(Duration), - /// How many full animation loops to run or how many seconds if image is static + /// How many full animation loops to run or how many seconds if image is + /// static Count(u32), /// Run for infinite time Infinite, @@ -169,8 +174,8 @@ impl AnimeGif { Ok(Self(frames, duration)) } - /// Create an animation using a gif of any size. This method must precompute the - /// result. + /// Create an animation using a gif of any size. This method must precompute + /// the result. #[inline] pub fn from_gif( file_name: &Path, @@ -243,9 +248,10 @@ impl AnimeGif { Ok(Self(frames, duration)) } - /// Make a static gif out of a greyscale png. If no duration is specified then the default - /// will be 1 second long. If `AnimTime::Cycles` is specified for `duration` then this can - /// be considered how many seconds the image will show for. + /// Make a static gif out of a greyscale png. If no duration is specified + /// then the default will be 1 second long. If `AnimTime::Cycles` is + /// specified for `duration` then this can be considered how many + /// seconds the image will show for. #[inline] pub fn from_png( file_name: &Path, diff --git a/rog-anime/src/image.rs b/rog-anime/src/image.rs index 8d42e5a4..6ee6fa5f 100644 --- a/rog-anime/src/image.rs +++ b/rog-anime/src/image.rs @@ -1,13 +1,12 @@ -use std::{convert::TryFrom, path::Path}; +use std::convert::TryFrom; +use std::path::Path; pub use glam::Vec2; use glam::{Mat3, Vec3}; -use crate::{ - data::AnimeDataBuffer, - error::{AnimeError, Result}, - AnimeType, -}; +use crate::data::AnimeDataBuffer; +use crate::error::{AnimeError, Result}; +use crate::AnimeType; /// A single greyscale + alpha pixel in the image #[derive(Copy, Clone, Debug)] @@ -29,8 +28,8 @@ impl Default for Pixel { /// A single LED position and brightness. The intention of this struct /// is to be used to sample an image and set the LED brightness. /// -/// The position of the Led in `LedPositions` determines the placement in the final -/// data packets when written to the `AniMe`. +/// The position of the Led in `LedPositions` determines the placement in the +/// final data packets when written to the `AniMe`. #[derive(Debug, Clone, Copy, PartialEq)] pub struct Led(f32, f32, u8); @@ -73,8 +72,9 @@ pub struct AnimeImage { img_pixels: Vec, /// width of the image width: u32, - /// The type of the display. The GA401 and GA402 use the same controller and therefore same ID, - /// so the identifier must be by laptop model in `AnimeType`. + /// The type of the display. The GA401 and GA402 use the same controller and + /// therefore same ID, so the identifier must be by laptop model in + /// `AnimeType`. anime_type: AnimeType, } @@ -108,9 +108,9 @@ impl AnimeImage { /// Scale ratio in CM /// - /// This is worked out by measuring the physical width of the display from pixel center to - /// center, then dividing by ` + 0.5`, where the LED count is - /// first/longest row. + /// This is worked out by measuring the physical width of the display from + /// pixel center to center, then dividing by ` + + /// 0.5`, where the LED count is first/longest row. /// /// For GA401 this is `26.8 / (33 + 0.5) = 0.8` /// For GA402 this is `27.4 / (35 + 0.5) = 0.77` @@ -123,9 +123,9 @@ impl AnimeImage { /// Scale ratio in CM /// - /// This is worked out by measuring the physical height of the display from pixel center to - /// pixel center, then dividing by ` + 1.0`, where the LED count is - /// first/longest row. + /// This is worked out by measuring the physical height of the display from + /// pixel center to pixel center, then dividing by ` + 1.0`, where the LED count is first/longest row. /// /// For GA401 this is `16.5 / (54.0 + 1.0) = 0.3` /// For GA402 this is `17.3 / (61.0) = 0.283` @@ -136,12 +136,12 @@ impl AnimeImage { } } - /// Get the starting X position for the data we actually require when writing - /// it out to LEDs. + /// Get the starting X position for the data we actually require when + /// writing it out to LEDs. /// - /// In relation to the display itself you should think of it as a full square grid, so `first_x` - /// is the x position on that grid where the LED is actually positioned in relation to the Y. - /// ```text + /// In relation to the display itself you should think of it as a full + /// square grid, so `first_x` is the x position on that grid where the + /// LED is actually positioned in relation to the Y. ```text /// +------------+ /// | | /// | | @@ -251,8 +251,8 @@ impl AnimeImage { &mut self.img_pixels } - /// Generate a list of LED positions. These are then used to sample the Image data, - /// and will contain their resulting brightness. + /// Generate a list of LED positions. These are then used to sample the + /// Image data, and will contain their resulting brightness. #[inline] pub fn generate_image_positioning(anime_type: AnimeType) -> Vec> { (0..AnimeImage::height(anime_type)) @@ -274,8 +274,8 @@ impl AnimeImage { /// samples, the result can then been transformed to the appropriate data /// for displaying. /// - /// The internal for loop iterates over the LED positions, skipping the blank/dead - /// pixels if any. + /// The internal for loop iterates over the LED positions, skipping the + /// blank/dead pixels if any. #[inline] pub fn update(&mut self) { let width = self.width as i32; @@ -343,7 +343,7 @@ impl AnimeImage { } last_was_led = true; } else if last_was_led { - //ends.push(idx); + // ends.push(idx); last_was_led = false; } } @@ -382,8 +382,9 @@ impl AnimeImage { led_from_px.inverse() } - /// Generate the base image from inputs. The result can be displayed as is or - /// updated via scale, position, or angle then displayed again after `update()`. + /// Generate the base image from inputs. The result can be displayed as is + /// or updated via scale, position, or angle then displayed again after + /// `update()`. #[inline] pub fn from_png( path: &Path, @@ -491,8 +492,8 @@ impl AnimeImage { impl TryFrom<&AnimeImage> for AnimeDataBuffer { type Error = AnimeError; - /// Do conversion from the nested Vec in `AnimeDataBuffer` to the two required - /// packets suitable for sending over USB + /// Do conversion from the nested Vec in `AnimeDataBuffer` to the two + /// required packets suitable for sending over USB fn try_from(leds: &AnimeImage) -> Result { let mut l: Vec = leds .led_pos @@ -511,9 +512,11 @@ impl TryFrom<&AnimeImage> for AnimeDataBuffer { #[cfg(test)] mod tests { - use std::{convert::TryFrom, path::PathBuf}; + use std::convert::TryFrom; + use std::path::PathBuf; - use crate::{image::*, AnimTime, AnimeGif, AnimePacketType}; + use crate::image::*; + use crate::{AnimTime, AnimeGif, AnimePacketType}; #[test] fn led_positions() { diff --git a/rog-anime/src/lib.rs b/rog-anime/src/lib.rs index ed1f76d2..63629291 100644 --- a/rog-anime/src/lib.rs +++ b/rog-anime/src/lib.rs @@ -11,8 +11,8 @@ pub use grid::*; mod image; pub use image::*; -/// A grid of data that is intended to be read out and displayed on the `AniMe` as -/// a diagonal +/// A grid of data that is intended to be read out and displayed on the `AniMe` +/// as a diagonal mod diagonal; pub use diagonal::*; @@ -21,8 +21,8 @@ pub use diagonal::*; mod gif; pub use crate::gif::*; -/// A container of images/grids/gifs/pauses which can be iterated over to generate -/// cool effects +/// A container of images/grids/gifs/pauses which can be iterated over to +/// generate cool effects mod sequencer; pub use sequencer::*; diff --git a/rog-anime/src/sequencer.rs b/rog-anime/src/sequencer.rs index a07ba9e8..3a6e6eec 100644 --- a/rog-anime/src/sequencer.rs +++ b/rog-anime/src/sequencer.rs @@ -1,14 +1,15 @@ +use std::convert::TryFrom; +use std::path::PathBuf; +use std::time::Duration; + use glam::Vec2; use serde_derive::{Deserialize, Serialize}; -use std::convert::TryFrom; -use std::{path::PathBuf, time::Duration}; -use crate::{ - error::Result, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType, -}; +use crate::error::Result; +use crate::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType}; -/// All the possible `AniMe` actions that can be used. This enum is intended to be -/// a helper for loading up `ActionData`. +/// All the possible `AniMe` actions that can be used. This enum is intended to +/// be a helper for loading up `ActionData`. #[derive(Debug, Clone, Deserialize, Serialize)] pub enum ActionLoader { /// Full gif sequence. Immutable. @@ -23,7 +24,8 @@ pub enum ActionLoader { time: AnimTime, brightness: f32, }, - /// Animated gif. If the file is a png a static gif is created using the `time` properties + /// Animated gif. If the file is a png a static gif is created using the + /// `time` properties ImageAnimation { file: PathBuf, scale: f32, @@ -44,13 +46,14 @@ pub enum ActionLoader { Pause(Duration), } -/// All the possible `AniMe` actions that can be used. The enum is intended to be -/// used in a array allowing the user to cycle through a series of actions. +/// All the possible `AniMe` actions that can be used. The enum is intended to +/// be used in a array allowing the user to cycle through a series of actions. #[derive(Debug, Clone, Deserialize, Serialize)] pub enum ActionData { /// Full gif sequence. Immutable. Animation(AnimeGif), - /// Basic image, can have properties changed and image updated via those properties + /// Basic image, can have properties changed and image updated via those + /// properties Image(Box), /// A pause to be used between sequences Pause(Duration), @@ -174,8 +177,8 @@ impl Sequences { Self(Vec::new(), anime_type) } - /// Use a base `AnimeAction` to generate the precomputed data and insert in to - /// the run buffer + /// Use a base `AnimeAction` to generate the precomputed data and insert in + /// to the run buffer #[inline] pub fn insert(&mut self, index: usize, action: &ActionLoader) -> Result<()> { self.0 @@ -183,9 +186,9 @@ impl Sequences { Ok(()) } - /// Remove an item at this position from the run buffer. If the `index` supplied - /// is not in range then `None` is returned, otherwise the `ActionData` at that location - /// is yeeted and returned. + /// Remove an item at this position from the run buffer. If the `index` + /// supplied is not in range then `None` is returned, otherwise the + /// `ActionData` at that location is yeeted and returned. #[inline] pub fn remove_item(&mut self, index: usize) -> Option { if index < self.0.len() { diff --git a/rog-anime/src/usb.rs b/rog-anime/src/usb.rs index a3fa2a12..83ef866d 100644 --- a/rog-anime/src/usb.rs +++ b/rog-anime/src/usb.rs @@ -1,13 +1,15 @@ //! Utils for writing to the `AniMe` USB device //! //! Use of the device requires a few steps: -//! 1. Initialise the device by writing the two packets from `get_init_packets()` -//! 2. Write data from `AnimePacketType` -//! 3. Write the packet from `get_flush_packet()`, which tells the device to display the data from step 2 +//! 1. Initialise the device by writing the two packets from +//! `get_init_packets()` 2. Write data from `AnimePacketType` +//! 3. Write the packet from `get_flush_packet()`, which tells the device to +//! display the data from step 2 //! //! Step 1 need to applied only on fresh system boot. -use crate::{error::AnimeError, AnimeType}; +use crate::error::AnimeError; +use crate::AnimeType; const INIT_STR: [u8; 15] = [ 0x5e, b'A', b'S', b'U', b'S', b' ', b'T', b'e', b'c', b'h', b'.', b'I', b'n', b'c', b'.', @@ -17,8 +19,9 @@ const DEV_PAGE: u8 = 0x5e; pub const VENDOR_ID: u16 = 0x0b05; pub const PROD_ID: u16 = 0x193b; -/// `get_anime_type` is very broad, matching on part of the laptop board name only. For this -/// reason `find_node()` must be used also to verify if the USB device is available. +/// `get_anime_type` is very broad, matching on part of the laptop board name +/// only. For this reason `find_node()` must be used also to verify if the USB +/// device is available. /// /// The currently known USB device is `19b6`. #[inline] @@ -34,8 +37,8 @@ pub fn get_anime_type() -> Result { Err(AnimeError::UnsupportedDevice) } -/// Get the two device initialization packets. These are required for device start -/// after the laptop boots. +/// Get the two device initialization packets. These are required for device +/// start after the laptop boots. #[inline] pub const fn pkts_for_init() -> [[u8; PACKET_SIZE]; 2] { let mut packets = [[0; PACKET_SIZE]; 2]; @@ -74,8 +77,8 @@ pub const fn pkt_for_set_boot(status: bool) -> [u8; PACKET_SIZE] { pkt } -/// Get the packet required for setting the device to on. Requires `pkt_for_apply()` -/// to be written after. +/// Get the packet required for setting the device to on. Requires +/// `pkt_for_apply()` to be written after. #[inline] pub const fn pkt_for_set_on(on: bool) -> [u8; PACKET_SIZE] { let mut pkt = [0; PACKET_SIZE]; diff --git a/rog-aura/Cargo.toml b/rog-aura/Cargo.toml index 54e4e9ed..5de63932 100644 --- a/rog-aura/Cargo.toml +++ b/rog-aura/Cargo.toml @@ -13,14 +13,18 @@ edition = "2021" exclude = ["data"] [features] -default = ["dbus", "toml"] +default = ["dbus", "ron"] dbus = ["zbus"] [dependencies] serde.workspace = true serde_derive.workspace = true -toml = { workspace = true, optional = true } zbus = { workspace = true, optional = true } -[dev-dependencies] -serde_json.workspace = true +# cli and logging +log.workspace = true + +# Device control +sysfs-class.workspace = true # used for backlight control and baord ID + +ron = { version = "*", optional = true } \ No newline at end of file diff --git a/rog-aura/README.md b/rog-aura/README.md index e69de29b..3b746bfd 100644 --- a/rog-aura/README.md +++ b/rog-aura/README.md @@ -0,0 +1,246 @@ +# rog-aura + +## What is it? + +rog-aura is a helper crate for interacting with the RGB keyboards found on many ASUS ROG gaming laptops such as the Zephyrus, Strix, TUF, and a few others. + +The crate is primarily used in the asusctl suite of tools. + +The majority of the crate deals with converting from the API to USB packets suitable for sending raw to the USB device. + +## Features + +- Detect USB keyboard type, or if the kayboard is an I2C connected one (typical on TUF) +- Set various basic modes +- Set various basic zones +- Set advanced/direct addressing of: + + Single zone + + Multizone + + Per-key +- Physical layout mapping + +## Config files + +The crate includes config files for helping to determine what laptop models support what feature. This is heavily dependant on folks testing and contributing data. + +It also includes layouts for some laptops. Also heavily dependant on contributions. + +# Support list + +`aura_support.ron` is the support listing file. It functions as a database of which models support which features. + +```ron + ( + board_name: "G513QR", + layout_name: "g513i-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), +``` + +in the above example the board name is found from `cat /sys/devices/virtual/dmi/id/board_name`. In some model ranges the last letter (which is likely the dGPU/feature variant) can be ommited. `layout_name` is the first part of a related filename for the layout as described in the next section - the filename should be postfixed with a locale such as `g513i_US.ron`. + +`basic_modes` are the default inbuilt modes the keyboard supports. Not all keyboards have the same set of modes. `basic_zones` is a secondary part of `basic_modes` where this lists which zones can be set as part of the basic mode. Each zone reauires a full basic mode setting. The zones supported here are + +- `Key1` +- `Key2` +- `Key3` +- `Key4` +- `Logo` +- `BarLeft` +- `BarRight` + +note that the zone support seems to have changed with new generations of keyboards and is shifted to `advanced_type`. The `advanced_type` field is taken in to account when setting advanced effects. It can be combined with the keyboard layout also to be used in a GUI. + +`advanced_type` can be one of: + +- `None`, no advanced aura at all +- `PerKey`, can use any of `LedCode` except for the `Zoned` items below which work in a different way +- `Zoned`, takes an array such as: + + `Zoned([SingleZone])`, only one zone + + `Zoned([ ... ]),`, array with any combination of: + - `ZonedKbLeft` // keyboard left + - `ZonedKbLeftMid` // keyboard left-middle + - `ZonedKbRightMid` // etc + - `ZonedKbRight` + - `LightbarRight` + - `LightbarRightCorner` + - `LightbarRightBottom` + - `LightbarLeftBottom` + - `LightbarLeftCorner` + - `LightbarLeft` + +# Layouts + +The layout structure is kept in a `.ron`, which is "rusty object notation". The way this works is best demonstrated: + +```ron +( + locale: "US", + key_shapes: { + // This is a regular LED spot, it has a size (width x height), and padding around each edge. + // The final size should be (width + pad_left + pad_right, height + pad_top + pad_bottom) + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + // There is nothing in this space but it takes up room + "func_space": Blank( + width: 0.2, + height: 0.0, + ), + // This backspace button is composed of 3 individual LED + "backspace1": Led( + width: 0.65, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backspace2": Led( + width: 0.7, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backspace3": Led( + width: 0.65, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + // Padding generally isn't required but is available just in case + pad_left: 0.1, + pad_top: 0.1, + // Each row is a horizontal row of keys of the keyboard + row: [ + // Declare a tuple of `Key`, and the String name to use from the hashmap above + (Spacing, "rog_spacer"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (Rog, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + // There are two non-led types, `Blocking` which is intended to block something like a row-laser + (Blocking, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + // and `Spacing` which is intended to act like a non-visible LED + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Spacing, "func_space"), + (Del, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace3_1, "backspace1"), + (Backspace3_2, "backspace2"), + (Backspace3_3, "backspace3"), + (Spacing, "func_space"), + (Home, "regular"), + ], + ), + ] +) +``` + +**There are two types of layouts to be considered when building one; per-key, and zoned.** + +A zoned keyboard layout includes single zoned + no zones (but not per-key). The layout for this is fairly freeform, and can be built using regular keys from `LedCode` but can not include these per-key specific codes: + +- `LidLogo` +- `LidLeft` +- `LidRight` + +it can include regular keys and: + +- `SingleZone`, if this is used then the `ZonedKb*` should not be used +- `ZonedKbLeft` +- `ZonedKbLeftMid` +- `ZonedKbRightMid` +- `ZonedKbRight` +- `LightbarRight` +- `LightbarRightCorner` +- `LightbarRightBottom` +- `LightbarLeftBottom` +- `LightbarLeftCorner` +- `LightbarLeft` + +#### `Key` + +Every `Key` in the enum maps to a USB packet + RGB index in that packet. The raw mapping is seen in `per_key_raw_bytes.ods` in the data dir, for example there is a single LED backspace, and a 3-LED backspace. + +#### `key_shapes` + +This is a hashmap of `String`:`ShapeType`, as shown by the previous example such as: + +``` + // This is a regular LED spot, it has a size (width x height), and padding around each edge. + // The final size should be (width + pad_left + pad_right, height + pad_top + pad_bottom) + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), +``` + +"regular" being the key used by the keys in each key row. + +# Testing + +When working with Rog Control Center you can test layouts by starting the app on CLI with options: + +``` + -h, --help print help message + -v, --version show program version number + -b, --board-name set board name for testing, this will make ROGCC show only the keyboard page + -l, --layout-viewing put ROGCC in layout viewing mode - this is helpful for finding existing layouts that might match your laptop +``` \ No newline at end of file diff --git a/rog-aura/data/aura_support.ron b/rog-aura/data/aura_support.ron new file mode 100644 index 00000000..507ecf61 --- /dev/null +++ b/rog-aura/data/aura_support.ron @@ -0,0 +1,450 @@ +([ + ( + board_name: "FA506I", + layout_name: "fa506i", + basic_modes: [Static, Breathe, Strobe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "FA506Q", + layout_name: "fa506i", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "FA507", + layout_name: "fa507", + basic_modes: [Static, Breathe, Strobe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "FX505D", + layout_name: "fx505d", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "FX506HC", + layout_name: "fa506i", + basic_modes: [Static, Breathe, Strobe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G512", + layout_name: "g512", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G512LI", + layout_name: "gl503", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G512LV", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G513IC", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]), + ), + ( + board_name: "G513IH", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G513IM", + layout_name: "g513i-per-key", + basic_modes: [Flash, Static, Breathe, Strobe, Rainbow], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G513QE", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G513QM", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G513QR", + layout_name: "g513i-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G513QY", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G513RC", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]), + ), + ( + board_name: "G513RM", + layout_name: "g513i", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: Zoned([ZonedKbLeft, ZonedKbLeftMid, ZonedKbRightMid, ZonedKbRight, LightbarRight, LightbarRightCorner, LightbarRightBottom, LightbarLeftBottom, LightbarLeftCorner, LightbarLeft]), + ), + ( + board_name: "G531", + layout_name: "g513i-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G531", + layout_name: "g513i-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: PerKey, + ), + ( + board_name: "G531GD", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G531GT", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G531GU", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G531GV", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G531GW", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G532", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G533Q", + layout_name: "g533q-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G712LI", + layout_name: "gl503", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G712LV", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G712LW", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G713IC", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G713QM", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G713QR", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G713RM", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G713RS", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "G713RW", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G731", + layout_name: "g533q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: PerKey, + ), + ( + board_name: "G731GT", + layout_name: "g533q", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G731GU", + layout_name: "g533q", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "G731GV", + layout_name: "g533q", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G731GW", + layout_name: "g533q", + basic_modes: [Static, Breathe, Strobe, Rainbow], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "G733Q", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GA402R", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Pulse, Rainbow], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GA503Q", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GA503QE", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GA503R", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Pulse, Rainbow, Strobe], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GL504G", + layout_name: "gl503", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4, Logo, BarLeft, BarRight], + advanced_type: None, + ), + ( + board_name: "GL531", + layout_name: "g512", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GL553VE", + layout_name: "g533q", + basic_modes: [Static, Breathe, Strobe], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "GM501G", + layout_name: "fa507", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "GU502", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GU502G", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GU502L", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GU502LU", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GU603H", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: Zoned([SingleZone]), + ), + ( + board_name: "GU603Z", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: Zoned([SingleZone]), + ), + ( + board_name: "GV301Q", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GV601R", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Strobe, Pulse], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "GX502", + layout_name: "gx502", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GX531", + layout_name: "gx531-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [Key1, Key2, Key3, Key4], + advanced_type: None, + ), + ( + board_name: "GX550L", + layout_name: "gx531-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GX551Q", + layout_name: "gx531-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Pulse], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GX701", + layout_name: "gx531-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: PerKey, + ), + ( + board_name: "GX703H", + layout_name: "gx531-per-key", + basic_modes: [Static, Breathe, Strobe, Rainbow, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash], + basic_zones: [], + advanced_type: None, + ), + ( + board_name: "ga401qQ", + layout_name: "ga401q", + basic_modes: [Static, Breathe, Pulse], + basic_zones: [], + advanced_type: None, + ), +]) \ No newline at end of file diff --git a/rog-aura/data/layouts/fa506i_US.ron b/rog-aura/data/layouts/fa506i_US.ron new file mode 100644 index 00000000..b9163632 --- /dev/null +++ b/rog-aura/data/layouts/fa506i_US.ron @@ -0,0 +1,317 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular2": Led( + width: 1.0, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "func_key": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.1, + ), + "func_space": Blank( + width: 0.5, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "backspace": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bkslash": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 1.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.3, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.5, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 2.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.7, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.9, + pad_right: 1.4, + pad_top: 0.1, + pad_bottom: 0.0, + ), + "arrows_spacer": Blank( + width: 14.5, + height: 0.0, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.4, + pad_bottom: 0.1, + ), + "numpad_tall": Led( + width: 1.0, + height: 2.2, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: -1.2, + ), + "numpad_wide": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Spacing, "func_space"), + (Del, "func_key"), + (NumPadPause, "func_key"), + (NumPadPrtSc, "func_key"), + (NumPadHome, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (Spacing, "func_space"), + (NumLock, "regular"), + (FwdSlash, "regular"), + (Star, "regular"), + (Hyphen, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "bkslash"), + (Spacing, "func_space"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (NumPadPlus, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (Spacing, "func_space"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (Spacing, "func_space"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (NumPadEnter, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular2"), + (Meta, "regular2"), + (LAlt, "regular2"), + (Spacebar, "spacebar"), + (RAlt, "regular2"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + (Spacing, "func_space"), + (N0, "numpad_wide"), + (NumPadDel, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/fa507_US.ron b/rog-aura/data/layouts/fa507_US.ron new file mode 100644 index 00000000..61d3aad1 --- /dev/null +++ b/rog-aura/data/layouts/fa507_US.ron @@ -0,0 +1,334 @@ +( + locale: "US", + key_shapes: { + "rog_spacer": Blank( + width: 2.5, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.2, + pad_bottom: 0.5, + ), + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular2": Led( + width: 1.0, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "func_key": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.1, + ), + "func_space": Blank( + width: 0.5, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "backspace": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bkslash": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 1.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.3, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.5, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 2.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.7, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.9, + pad_right: 1.4, + pad_top: 0.1, + pad_bottom: 0.0, + ), + "arrows_spacer": Blank( + width: 14.5, + height: 0.0, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.4, + pad_bottom: 0.1, + ), + "numpad_tall": Led( + width: 1.0, + height: 2.2, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: -1.2, + ), + "numpad_wide": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Spacing, "rog_spacer"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Del, "func_key"), + (NumPadPause, "func_key"), + (NumPadPrtSc, "func_key"), + (NumPadHome, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (NumLock, "regular"), + (FwdSlash, "regular"), + (Star, "regular"), + (Hyphen, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "bkslash"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (NumPadPlus, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (NumPadEnter, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular2"), + (Meta, "regular2"), + (LAlt, "regular2"), + (Spacebar, "spacebar"), + (RAlt, "regular2"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + (N0, "numpad_wide"), + (NumPadDel, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/fx505d_US.ron b/rog-aura/data/layouts/fx505d_US.ron new file mode 100644 index 00000000..e2d7881e --- /dev/null +++ b/rog-aura/data/layouts/fx505d_US.ron @@ -0,0 +1,281 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular2": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.2, + pad_bottom: 0.1, + ), + "func_key": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.1, + ), + "func_space": Blank( + width: 0.5, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "backspace": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bkslash": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 1.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.3, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.5, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.7, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows_spacer": Blank( + width: 16.6, + height: 0.0, + ), + "numpad_tall": Led( + width: 1.0, + height: 2.2, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: -1.2, + ), + "right_wide": Led( + width: 2.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Del, "func_key"), + (NumPadPause, "func_key"), + (NumPadPrtSc, "func_key"), + (NumPadHome, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (NumLock, "regular"), + (FwdSlash, "regular"), + (Star, "regular"), + (Hyphen, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "bkslash"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (NumPadPlus, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "right_wide"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (NumPadEnter, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (RAlt, "regular"), + (RAlt, "regular"), + (RCtrl, "right_wide"), + (Up, "regular"), + (N0, "regular"), + (NumPadDel, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "regular2"), + (Down, "regular2"), + (Right, "regular2"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/g512_US.ron b/rog-aura/data/layouts/g512_US.ron new file mode 100644 index 00000000..8965a105 --- /dev/null +++ b/rog-aura/data/layouts/g512_US.ron @@ -0,0 +1,312 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.6, + ), + "rog_row_blocking": Blank( + width: 1.2, + height: 0.0, + ), + "func_space": Blank( + width: 0.6, + height: 0.0, + ), + "backspace": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backslash": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 3.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.1, + pad_right: 1.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows_spacer": Blank( + width: 15.0, + height: 0.0, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.1, + pad_bottom: 0.1, + ), + "row_end_spacing": Blank( + width: 0.4, + height: 0.0, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Blocking, "rog_row_blocking"), + (Blocking, "rog_row_blocking"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogFan, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Esc, "regular"), + (Spacing, "regular_spacing"), + (F1, "regular"), + (F2, "regular"), + (F3, "regular"), + (F4, "regular"), + (Spacing, "func_space"), + (F5, "regular"), + (F6, "regular"), + (F7, "regular"), + (F8, "regular"), + (Spacing, "func_space"), + (F9, "regular"), + (F10, "regular"), + (F11, "regular"), + (F12, "regular"), + (Spacing, "row_end_spacing"), + (Del, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (Spacing, "row_end_spacing"), + (Home, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "backslash"), + (Spacing, "row_end_spacing"), + (PgUp, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (Spacing, "row_end_spacing"), + (PgDn, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (Spacing, "row_end_spacing"), + (End, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (PrtSc, "regular"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + (Spacing, "row_end_spacing"), + (PrtSc, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/g513_US.toml b/rog-aura/data/layouts/g513_US.toml deleted file mode 100644 index dbefeae8..00000000 --- a/rog-aura/data/layouts/g513_US.toml +++ /dev/null @@ -1,161 +0,0 @@ -matches = [ - 'G513', -] - -locale = "US" - -[[rows]] -height = 0.8 -row = [ - 'NormalSpacer', - 'FuncSpacer', - 'VolDown', - 'VolUp', - 'MicMute', - 'Fan', - 'Rog', -] - -[[rows]] -height = 0.8 -row = [ - 'Esc', - 'FuncSpacer', - 'F1', - 'F2', - 'F3', - 'F4', - 'FuncSpacer', - 'F5', - 'F6', - 'F7', - 'F8', - 'FuncSpacer', - 'F9', - 'F10', - 'F11', - 'F12', - 'RowEndSpacer', - 'NumPadDel', -] - -[[rows]] -height = 1.0 -row = [ - 'Tilde', - 'N1', - 'N2', - 'N3', - 'N4', - 'N5', - 'N6', - 'N7', - 'N8', - 'N9', - 'N0', - 'Hyphen', - 'Equals', - 'BkSpc', - 'RowEndSpacer', - 'Home', -] - -[[rows]] -height = 1.0 -row = [ - 'Tab', - 'Q', - 'W', - 'E', - 'R', - 'T', - 'Y', - 'U', - 'I', - 'O', - 'P', - 'LBracket', - 'RBracket', - 'BackSlash', - 'RowEndSpacer', - 'PgUp', -] - -[[rows]] -height = 1.0 -row = [ - 'Caps', - 'A', - 'S', - 'D', - 'F', - 'G', - 'H', - 'J', - 'K', - 'L', - 'SemiColon', - 'Quote', - 'Return', - 'RowEndSpacer', - 'PgDn', -] - -[[rows]] -height = 1.0 -row = [ - 'LShift', - 'Z', - 'X', - 'C', - 'V', - 'B', - 'N', - 'M', - 'Comma', - 'Period', - 'FwdSlash', - 'Rshift', - 'RowEndSpacer', - 'End', -] - -[[rows]] -height = 1.2 -row = [ - 'LCtrl', - 'LFn', - 'Meta', - 'LAlt', - 'Space', - 'RAlt', - 'PrtSc', - 'RCtrl', - 'ArrowSpacer', - 'Up', - 'ArrowSpacer', - 'RowEndSpacer', - 'RFn', -] - -[[rows]] -height = 0.8 -row = [ - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'ArrowSpacer', - 'Left', - 'Down', - 'Right', - 'ArrowSpacer', -] diff --git a/rog-aura/data/layouts/g513i-per-key_US.ron b/rog-aura/data/layouts/g513i-per-key_US.ron new file mode 100644 index 00000000..4ea6b631 --- /dev/null +++ b/rog-aura/data/layouts/g513i-per-key_US.ron @@ -0,0 +1,366 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.6, + ), + "rog_row_blocking": Blank( + width: 1.2, + height: 0.0, + ), + "func_space": Blank( + width: 0.6, + height: 0.0, + ), + "backspace": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backslash": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 3.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.1, + pad_right: 1.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows_spacer": Blank( + width: 15.0, + height: 0.0, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.1, + pad_bottom: 0.1, + ), + "row_end_spacing": Blank( + width: 0.4, + height: 0.0, + ), + "lightbar_left": Led( + width: 0.4, + height: 3.0, + pad_left: -1.0, + pad_right: 0.1, + pad_top: -2.7, + pad_bottom: 0.1, + ), + "lightbar_corner_left": Led( + width: 0.4, + height: 0.4, + pad_left: -0.5, + pad_right: 0.1, + pad_top: 0.5, + pad_bottom: 0.1, + ), + "lightbar_bottom": Led( + width: 10.1, + height: 0.4, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.5, + pad_bottom: 0.1, + ), + "lightbar_corner_right": Led( + width: 0.4, + height: 0.4, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.5, + pad_bottom: 0.1, + ), + "lightbar_right": Led( + width: 0.4, + height: 3.0, + pad_left: -0.5, + pad_right: 0.1, + pad_top: -2.7, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Blocking, "rog_row_blocking"), + (Blocking, "rog_row_blocking"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogFan, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Esc, "regular"), + (Spacing, "regular_spacing"), + (F1, "regular"), + (F2, "regular"), + (F3, "regular"), + (F4, "regular"), + (Spacing, "func_space"), + (F5, "regular"), + (F6, "regular"), + (F7, "regular"), + (F8, "regular"), + (Spacing, "func_space"), + (F9, "regular"), + (F10, "regular"), + (F11, "regular"), + (F12, "regular"), + (Spacing, "row_end_spacing"), + (Del, "regular"), // Should be super/insert + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (Spacing, "row_end_spacing"), + (MediaPlay, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "backslash"), + (Spacing, "row_end_spacing"), + (MediaStop, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (Spacing, "row_end_spacing"), + (MediaNext, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (Spacing, "row_end_spacing"), + (MediaPrev, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (PrtSc, "regular"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + (Spacing, "row_end_spacing"), + (PrtSc, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LightbarLeft, "lightbar_left"), + (LightbarLeftCorner, "lightbar_corner_left"), + (LightbarLeftBottom, "lightbar_bottom"), + (LightbarRightBottom, "lightbar_bottom"), + (LightbarRightCorner, "lightbar_corner_right"), + (LightbarRight, "lightbar_right"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/g513i_US.ron b/rog-aura/data/layouts/g513i_US.ron new file mode 100644 index 00000000..4ea6b631 --- /dev/null +++ b/rog-aura/data/layouts/g513i_US.ron @@ -0,0 +1,366 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.6, + ), + "rog_row_blocking": Blank( + width: 1.2, + height: 0.0, + ), + "func_space": Blank( + width: 0.6, + height: 0.0, + ), + "backspace": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backslash": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 3.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.1, + pad_right: 1.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows_spacer": Blank( + width: 15.0, + height: 0.0, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.1, + pad_bottom: 0.1, + ), + "row_end_spacing": Blank( + width: 0.4, + height: 0.0, + ), + "lightbar_left": Led( + width: 0.4, + height: 3.0, + pad_left: -1.0, + pad_right: 0.1, + pad_top: -2.7, + pad_bottom: 0.1, + ), + "lightbar_corner_left": Led( + width: 0.4, + height: 0.4, + pad_left: -0.5, + pad_right: 0.1, + pad_top: 0.5, + pad_bottom: 0.1, + ), + "lightbar_bottom": Led( + width: 10.1, + height: 0.4, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.5, + pad_bottom: 0.1, + ), + "lightbar_corner_right": Led( + width: 0.4, + height: 0.4, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.5, + pad_bottom: 0.1, + ), + "lightbar_right": Led( + width: 0.4, + height: 3.0, + pad_left: -0.5, + pad_right: 0.1, + pad_top: -2.7, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Blocking, "rog_row_blocking"), + (Blocking, "rog_row_blocking"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogFan, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Esc, "regular"), + (Spacing, "regular_spacing"), + (F1, "regular"), + (F2, "regular"), + (F3, "regular"), + (F4, "regular"), + (Spacing, "func_space"), + (F5, "regular"), + (F6, "regular"), + (F7, "regular"), + (F8, "regular"), + (Spacing, "func_space"), + (F9, "regular"), + (F10, "regular"), + (F11, "regular"), + (F12, "regular"), + (Spacing, "row_end_spacing"), + (Del, "regular"), // Should be super/insert + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (Spacing, "row_end_spacing"), + (MediaPlay, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "backslash"), + (Spacing, "row_end_spacing"), + (MediaStop, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (Spacing, "row_end_spacing"), + (MediaNext, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (Spacing, "row_end_spacing"), + (MediaPrev, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (PrtSc, "regular"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + (Spacing, "row_end_spacing"), + (PrtSc, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LightbarLeft, "lightbar_left"), + (LightbarLeftCorner, "lightbar_corner_left"), + (LightbarLeftBottom, "lightbar_bottom"), + (LightbarRightBottom, "lightbar_bottom"), + (LightbarRightCorner, "lightbar_corner_right"), + (LightbarRight, "lightbar_right"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/g533_US.toml b/rog-aura/data/layouts/g533_US.toml deleted file mode 100644 index 2533fa28..00000000 --- a/rog-aura/data/layouts/g533_US.toml +++ /dev/null @@ -1,135 +0,0 @@ -matches = [ - 'G533', -] - -locale = "US" - -[[rows]] -height = 0.8 -row = [ - 'NormalSpacer', - 'FuncSpacer', - 'VolDown', - 'VolUp', - 'MicMute', - 'Fan', - 'Rog', -] - -[[rows]] -height = 0.8 -row = [ - 'Esc', - 'FuncSpacer', - 'F1', - 'F2', - 'F3', - 'F4', - 'FuncSpacer', - 'F5', - 'F6', - 'F7', - 'F8', - 'FuncSpacer', - 'F9', - 'F10', - 'F11', - 'F12', - 'Del', -] - -[[rows]] -height = 1.0 -row = [ - 'Tilde', - 'N1', - 'N2', - 'N3', - 'N4', - 'N5', - 'N6', - 'N7', - 'N8', - 'N9', - 'N0', - 'Hyphen', - 'Equals', - 'BkSpc', - 'MediaPlay', -] - -[[rows]] -height = 1.0 -row = [ - 'Tab', - 'Q', - 'W', - 'E', - 'R', - 'T', - 'Y', - 'U', - 'I', - 'O', - 'P', - 'LBracket', - 'RBracket', - 'BackSlash', - 'MediaStop', -] - -[[rows]] -height = 1.0 -row = [ - 'Caps', - 'A', - 'S', - 'D', - 'F', - 'G', - 'H', - 'J', - 'K', - 'L', - 'SemiColon', - 'Quote', - 'Return', - 'MediaPrev', -] - -[[rows]] -height = 1.0 -row = [ - 'LShift', - 'Z', - 'X', - 'C', - 'V', - 'B', - 'N', - 'M', - 'Comma', - 'Period', - 'FwdSlash', - 'RshiftSmall', - 'UpRegular', - 'MediaNext', -] - -[[rows]] -height = 1.0 -row = [ - 'LCtrlMed', - 'LFn', - 'Meta', - 'LAlt', - 'Space', - 'RAlt', - 'PrtSc', - 'RCtrl', - 'ArrowRegularSpacer', - 'LeftRegular', - 'DownRegular', - 'RightRegular', -] - diff --git a/rog-aura/data/layouts/g533q-per-key_US.ron b/rog-aura/data/layouts/g533q-per-key_US.ron new file mode 100644 index 00000000..5be64903 --- /dev/null +++ b/rog-aura/data/layouts/g533q-per-key_US.ron @@ -0,0 +1,293 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.6, + ), + "rog_row_blocking": Blank( + width: 1.2, + height: 0.0, + ), + "func_space": Blank( + width: 0.6, + height: 0.0, + ), + "backspace": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backslash": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 1.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrow_space": Blank( + width: 0.8, + height: 0.0, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Blocking, "rog_row_blocking"), + (Blocking, "rog_row_blocking"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogFan, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Esc, "regular"), + (Spacing, "regular_spacing"), + (F1, "regular"), + (F2, "regular"), + (F3, "regular"), + (F4, "regular"), + (Spacing, "func_space"), + (F5, "regular"), + (F6, "regular"), + (F7, "regular"), + (F8, "regular"), + (Spacing, "func_space"), + (F9, "regular"), + (F10, "regular"), + (F11, "regular"), + (F12, "regular"), + (Del, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (MediaPlay, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "backslash"), + (MediaStop, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (MediaPrev, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (Up, "up_arrow"), + (MediaNext, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (PrtSc, "regular"), + (RCtrl, "rctrl"), + (Spacing, "arrow_space"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/g533q_US.ron b/rog-aura/data/layouts/g533q_US.ron new file mode 100644 index 00000000..b64f9740 --- /dev/null +++ b/rog-aura/data/layouts/g533q_US.ron @@ -0,0 +1,294 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "rog_row_blocking": Blank( + width: 1.2, + height: 0.0, + ), + "func_space": Blank( + width: 0.6, + height: 0.0, + ), + "backspace": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backslash": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 3.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 1.0, + height: 1.0, + pad_left: 1.0, + pad_right: 1.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows_spacer": Blank( + width: 14.7, + height: 0.0, + ), + "arrows": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Blocking, "rog_row_blocking"), + (Blocking, "rog_row_blocking"), + (VolDown, "regular"), + (VolUp, "regular"), + (MicMute, "regular"), + (RogFan, "regular"), + (RogApp, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Esc, "regular"), + (Spacing, "regular_spacing"), + (F1, "regular"), + (F2, "regular"), + (F3, "regular"), + (F4, "regular"), + (Spacing, "func_space"), + (F5, "regular"), + (F6, "regular"), + (F7, "regular"), + (F8, "regular"), + (Spacing, "func_space"), + (F9, "regular"), + (F10, "regular"), + (F11, "regular"), + (F12, "regular"), + (Del, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (Home, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "backslash"), + (PgUp, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (PgDn, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + (End, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (PrtSc, "regular"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + (RFn, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) diff --git a/rog-aura/data/layouts/ga401_US.toml b/rog-aura/data/layouts/ga401_US.toml deleted file mode 100644 index 2bcb2f2a..00000000 --- a/rog-aura/data/layouts/ga401_US.toml +++ /dev/null @@ -1,154 +0,0 @@ -matches = [ - 'GA401', - 'GA402', - 'GU603', - 'GV301', - 'GA502', - 'GA503', -] - -locale = "US" - -[[rows]] -height = 0.8 -row = [ - 'NormalSpacer', - 'FuncSpacer', - 'VolDown', - 'VolUp', - 'MicMute', - 'Rog', -] - -[[rows]] -height = 0.8 -row = [ - 'Esc', - 'FuncSpacer', - 'F1', - 'F2', - 'F3', - 'F4', - 'FuncSpacer', - 'F5', - 'F6', - 'F7', - 'F8', - 'FuncSpacer', - 'F9', - 'F10', - 'F11', - 'F12', -] - -[[rows]] -height = 1.0 -row = [ - 'Tilde', - 'N1', - 'N2', - 'N3', - 'N4', - 'N5', - 'N6', - 'N7', - 'N8', - 'N9', - 'N0', - 'Hyphen', - 'Equals', - 'BkSpc', -] - -[[rows]] -height = 1.0 -row = [ - 'Tab', - 'Q', - 'W', - 'E', - 'R', - 'T', - 'Y', - 'U', - 'I', - 'O', - 'P', - 'LBracket', - 'RBracket', - 'BackSlash', -] - -[[rows]] -height = 1.0 -row = [ - 'Caps', - 'A', - 'S', - 'D', - 'F', - 'G', - 'H', - 'J', - 'K', - 'L', - 'SemiColon', - 'Quote', - 'Return', -] - -[[rows]] -height = 1.0 -row = [ - 'LShift', - 'Z', - 'X', - 'C', - 'V', - 'B', - 'N', - 'M', - 'Comma', - 'Period', - 'FwdSlash', - 'Rshift', -] - -[[rows]] -height = 1.2 -row = [ - 'LCtrl', - 'LFn', - 'Meta', - 'LAlt', - 'Space', - 'RAlt', - 'PrtSc', - 'RCtrl', - 'ArrowSpacer', - 'Up', - 'ArrowSpacer', -] - -[[rows]] -height = 0.8 -row = [ - 'FuncSpacer', - 'FuncSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'Left', - 'Down', - 'Right', - 'ArrowSpacer', -] - diff --git a/rog-aura/data/layouts/ga401q_US.ron b/rog-aura/data/layouts/ga401q_US.ron new file mode 100644 index 00000000..b67dc4ab --- /dev/null +++ b/rog-aura/data/layouts/ga401q_US.ron @@ -0,0 +1,299 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular2": Led( + width: 1.0, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rog_spacer": Blank( + width: 2.5, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.2, + pad_bottom: 0.5, + ), + "func_key": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.1, + ), + "func_space": Blank( + width: 0.2, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 0.6, + height: 0.0, + ), + "backspace": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bkslash": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift": Led( + width: 3.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.8, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rctrl": Led( + width: 1.2, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 1.0, + height: 0.6, + pad_left: 1.6, + pad_right: 1.6, + pad_top: 0.1, + pad_bottom: 0.0, + ), + "arrows_spacer": Blank( + width: 14.1, + height: 0.0, + ), + "arrows": Led( + width: 1.0, + height: 0.6, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.7, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Spacing, "rog_spacer"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Spacing, "func_space"), + (Del, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "bkslash"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "rshift"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular2"), + (Meta, "regular2"), + (LAlt, "regular2"), + (Spacebar, "spacebar"), + (RAlt, "regular2"), + (RCtrl, "rctrl"), + (Up, "up_arrow"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/gl503_US.ron b/rog-aura/data/layouts/gl503_US.ron new file mode 100644 index 00000000..8cf17e91 --- /dev/null +++ b/rog-aura/data/layouts/gl503_US.ron @@ -0,0 +1,305 @@ +( + locale: "US", + key_shapes: { + "rog_row_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.2, + pad_bottom: 0.6, + ), + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "regular2": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.2, + pad_bottom: 0.1, + ), + "func_key": Led( + width: 1.0, + height: 0.7, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.1, + ), + "func_space": Blank( + width: 0.5, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 1.2, + height: 0.0, + ), + "backspace": Led( + width: 2.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bkslash": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 1.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return": Led( + width: 2.3, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.5, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lctrl": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar": Led( + width: 5.7, + height: 1.3, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows_spacer": Blank( + width: 16.6, + height: 0.0, + ), + "numpad_tall": Led( + width: 1.0, + height: 2.2, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: -1.2, + ), + "right_wide": Led( + width: 2.9, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Blocking, "rog_row_spacing"), + (Blocking, "rog_row_spacing"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Del, "func_key"), + (NumPadPause, "func_key"), + (NumPadPrtSc, "func_key"), + (NumPadHome, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tilde, "regular"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace, "backspace"), + (NumLock, "regular"), + (FwdSlash, "regular"), + (Star, "regular"), + (Hyphen, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "bkslash"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (NumPadPlus, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return, "return"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift, "right_wide"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (NumPadEnter, "numpad_tall"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (LCtrl, "lctrl"), + (LFn, "regular"), + (Meta, "regular"), + (LAlt, "regular"), + (Spacebar, "spacebar"), + (RAlt, "regular"), + (RAlt, "regular"), + (RAlt, "regular"), + (RCtrl, "right_wide"), + (Up, "regular"), + (N0, "regular"), + (NumPadDel, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + row: [ + (Spacing, "arrows_spacer"), + (Left, "regular2"), + (Down, "regular2"), + (Right, "regular2"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/gl504_US.toml b/rog-aura/data/layouts/gl504_US.toml deleted file mode 100644 index 0258c086..00000000 --- a/rog-aura/data/layouts/gl504_US.toml +++ /dev/null @@ -1,180 +0,0 @@ -matches = [ - 'GL504', -] - -locale = "US" - -[[rows]] -height = 0.8 -row = [ - 'NormalSpacer', - 'FuncSpacer', - 'VolDown', - 'VolUp', - 'MicMute', - 'Rog', -] - -[[rows]] -height = 0.8 -row = [ - 'Esc', - 'FuncSpacer', - 'F1', - 'F2', - 'F3', - 'F4', - 'FuncSpacer', - 'F5', - 'F6', - 'F7', - 'F8', - 'FuncSpacer', - 'F9', - 'F10', - 'F11', - 'F12', - 'RowEndSpacer', - 'Del', - 'NumPadPause', - 'NumPadPrtSc', - 'NumPadHome', -] - -[[rows]] -height = 1.0 -row = [ - 'Tilde', - 'N1', - 'N2', - 'N3', - 'N4', - 'N5', - 'N6', - 'N7', - 'N8', - 'N9', - 'N0', - 'Hyphen', - 'Equals', - 'BkSpc', - 'RowEndSpacer', - 'NumLock', - 'FwdSlash', - 'Star', - 'Hyphen', -] - -[[rows]] -height = 1.0 -row = [ - 'Tab', - 'Q', - 'W', - 'E', - 'R', - 'T', - 'Y', - 'U', - 'I', - 'O', - 'P', - 'LBracket', - 'RBracket', - 'BackSlash', - 'RowEndSpacer', - 'N7', - 'N8', - 'N9', - 'NumPadPlus', -] - -[[rows]] -height = 1.0 -row = [ - 'Caps', - 'A', - 'S', - 'D', - 'F', - 'G', - 'H', - 'J', - 'K', - 'L', - 'SemiColon', - 'Quote', - 'Return', - 'RowEndSpacer', - 'N4', - 'N5', - 'N6', - 'NumPadPlus', -] - -[[rows]] -height = 1.0 -row = [ - 'LShift', - 'Z', - 'X', - 'C', - 'V', - 'B', - 'N', - 'M', - 'Comma', - 'Period', - 'FwdSlash', - 'Rshift', - 'RowEndSpacer', - 'N1', - 'N2', - 'N3', - 'NumPadEnter', -] - -[[rows]] -height = 1.0 -row = [ - 'LCtrl', - 'LFn', - 'Meta', - 'LAlt', - 'Space', - 'RAlt', - 'RFn', - 'RFn', - 'RCtrlLarge', - 'RowEndSpacer', - 'UpRegular', - 'N0', - 'NumPadDel', - 'NumPadEnter', -] - -[[rows]] -height = 1.0 -row = [ - 'FuncSpacer', - 'FuncSpacer', - 'FuncSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'LeftRegular', - 'RowEndSpacer', - 'DownRegular', - 'RightRegular', - 'NormalSpacer', -] - diff --git a/rog-aura/data/layouts/gx502_US.ron b/rog-aura/data/layouts/gx502_US.ron new file mode 100644 index 00000000..ca9779ee --- /dev/null +++ b/rog-aura/data/layouts/gx502_US.ron @@ -0,0 +1,382 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bottom_row": Led( + width: 1.0, + height: 1.2, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rog_row_spacing": Blank( + width: 0.9, + height: 0.0, + ), + "rog_row": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.2, + pad_bottom: 0.4, + ), + "func_key": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.4, + ), + "func_space": Blank( + width: 0.7, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 0.6, + height: 0.0, + ), + "end_space": Blank( + width: 0.4, + height: 0.0, + ), + "ctrl_bkslash": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tilde": Led( + width: 0.7, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + // The backspace button is composed of 3 individual LED + "backspace1": Led( + width: 0.7, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backspace2": Led( + width: 0.7, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backspace3": Led( + width: 0.7, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return1": Led( + width: 0.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return2": Led( + width: 0.8, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return3": Led( + width: 0.8, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift1": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift2": Led( + width: 1.0, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift3": Led( + width: 1.0, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar_left": Led( + width: 1.1, + height: 1.4, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar_mid": Led( + width: 1.2, + height: 1.4, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar_right": Led( + width: 1.1, + height: 1.4, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.2, + pad_right: 1.2, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.5, + pad_bottom: 0.1, + ), + "arrow_row_blocking": Blank( + width: 1.115, + height: 0.0, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Blocking, "rog_row_spacing"), + (Blocking, "rog_row_spacing"), + (VolDown, "rog_row"), + (VolUp, "rog_row"), + (MicMute, "rog_row"), + (RogApp, "rog_row"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (Spacing, "end_space"), + (Del, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Tilde, "tilde"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace3_1, "backspace1"), + (Backspace3_2, "backspace2"), + (Backspace3_3, "backspace3"), + (Spacing, "end_space"), + (Home, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "ctrl_bkslash"), + (Spacing, "end_space"), + (PgUp, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return3_1, "return1"), + (Return3_2, "return2"), + (Return3_3, "return3"), + (Spacing, "end_space"), + (PgDn, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift3_1, "rshift1"), + (Rshift3_2, "rshift2"), + (Rshift3_3, "rshift3"), + (Spacing, "end_space"), + (End, "regular"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (LCtrl, "bottom_row"), + (LFn, "bottom_row"), + (Meta, "bottom_row"), + (LAlt, "bottom_row"), + (Spacebar5_1, "spacebar_left"), + (Spacebar5_2, "spacebar_mid"), + (Spacebar5_3, "spacebar_mid"), + (Spacebar5_4, "spacebar_mid"), + (Spacebar5_5, "spacebar_right"), + (RAlt, "bottom_row"), + (PrtSc, "bottom_row"), + (RCtrl, "bottom_row"), + (Up, "up_arrow"), + (Spacing, "end_space"), + (RFn, "bottom_row"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/layouts/gx502_US.toml b/rog-aura/data/layouts/gx502_US.toml deleted file mode 100644 index 624de569..00000000 --- a/rog-aura/data/layouts/gx502_US.toml +++ /dev/null @@ -1,172 +0,0 @@ -matches = [ - 'GX502', - 'GU502', -] - -locale = "US" - -[[rows]] -height = 0.8 -row = [ - 'NormalSpacer', - 'FuncSpacer', - 'VolDown', - 'VolUp', - 'MicMute', - 'Rog', -] - -[[rows]] -height = 0.8 -row = [ - 'Esc', - 'FuncSpacer', - 'F1', - 'F2', - 'F3', - 'F4', - 'FuncSpacer', - 'F5', - 'F6', - 'F7', - 'F8', - 'FuncSpacer', - 'F9', - 'F10', - 'F11', - 'F12', - 'RowEndSpacer', - 'Del', -] - -[[rows]] -height = 1.0 -row = [ - 'Tilde', - 'N1', - 'N2', - 'N3', - 'N4', - 'N5', - 'N6', - 'N7', - 'N8', - 'N9', - 'N0', - 'Hyphen', - 'Equals', - 'BkSpc3_1', - 'BkSpc3_2', - 'BkSpc3_3', - 'RowEndSpacer', - 'Home', -] - -[[rows]] -height = 1.0 -row = [ - 'Tab', - 'Q', - 'W', - 'E', - 'R', - 'T', - 'Y', - 'U', - 'I', - 'O', - 'P', - 'LBracket', - 'RBracket', - 'BackSlash', - 'RowEndSpacer', - 'PgUp', -] - -[[rows]] -height = 1.0 -row = [ - 'Caps', - 'A', - 'S', - 'D', - 'F', - 'G', - 'H', - 'J', - 'K', - 'L', - 'SemiColon', - 'Quote', - 'Return3_1', - 'Return3_2', - 'Return3_3', - 'RowEndSpacer', - 'PgDn', -] - -[[rows]] -height = 1.0 -row = [ - 'LShift', - 'Z', - 'X', - 'C', - 'V', - 'B', - 'N', - 'M', - 'Comma', - 'Period', - 'FwdSlash', - 'Rshift3_1', - 'Rshift3_2', - 'Rshift3_3', - 'RowEndSpacer', - 'End', -] - -[[rows]] -height = 1.2 -row = [ - 'LCtrl', - 'LFn', - 'Meta', - 'LAlt', - 'Space5_1', - 'Space5_2', - 'Space5_3', - 'Space5_4', - 'Space5_5', - 'RAlt', - 'PrtSc', - 'RCtrl', - 'ArrowSpacer', - 'Up', - 'ArrowSpacer', - 'RowEndSpacer', - 'RFn', -] - -[[rows]] -height = 0.8 -row = [ - 'FuncSpacer', - 'FuncSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'NormalSpacer', - 'Left', - 'Down', - 'Right', - 'ArrowSpacer', -] - diff --git a/rog-aura/data/layouts/gx531-per-key_US.ron b/rog-aura/data/layouts/gx531-per-key_US.ron new file mode 100644 index 00000000..f9e71833 --- /dev/null +++ b/rog-aura/data/layouts/gx531-per-key_US.ron @@ -0,0 +1,346 @@ +( + locale: "US", + key_shapes: { + "regular": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "bottom_row": Led( + width: 1.0, + height: 1.2, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "func_key": Led( + width: 1.0, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.0, + pad_bottom: 0.4, + ), + "func_space": Blank( + width: 0.7, + height: 0.0, + ), + "esc_func_spacing": Blank( + width: 0.6, + height: 0.0, + ), + "ctrl_bkslash": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tilde": Led( + width: 0.7, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "tab": Led( + width: 1.4, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "capsplonk": Led( + width: 1.6, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + // The backspace button is composed of 3 individual LED + "backspace1": Led( + width: 0.7, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backspace2": Led( + width: 0.7, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "backspace3": Led( + width: 0.7, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return1": Led( + width: 0.8, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return2": Led( + width: 0.8, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "return3": Led( + width: 0.8, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "lshift": Led( + width: 2.2, + height: 1.0, + pad_left: 0.1, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift1": Led( + width: 1.0, + height: 1.0, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift2": Led( + width: 1.0, + height: 1.0, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "rshift3": Led( + width: 1.0, + height: 1.0, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar_left": Led( + width: 1.1, + height: 1.4, + pad_left: 0.1, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar_mid": Led( + width: 1.2, + height: 1.4, + pad_left: 0.0, + pad_right: 0.0, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "spacebar_right": Led( + width: 1.1, + height: 1.4, + pad_left: 0.0, + pad_right: 0.1, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "up_arrow": Led( + width: 0.8, + height: 0.8, + pad_left: 1.2, + pad_right: 1.2, + pad_top: 0.1, + pad_bottom: 0.1, + ), + "arrows": Led( + width: 0.8, + height: 0.8, + pad_left: 0.1, + pad_right: 0.1, + pad_top: -0.5, + pad_bottom: 0.1, + ), + "arrow_row_blocking": Blank( + width: 1.115, + height: 0.0, + ), + }, + key_rows: [ + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Esc, "func_key"), + (Spacing, "esc_func_spacing"), + (F1, "func_key"), + (F2, "func_key"), + (F3, "func_key"), + (F4, "func_key"), + (Spacing, "func_space"), + (F5, "func_key"), + (F6, "func_key"), + (F7, "func_key"), + (F8, "func_key"), + (Spacing, "func_space"), + (F9, "func_key"), + (F10, "func_key"), + (F11, "func_key"), + (F12, "func_key"), + (RogApp, "func_key"), + (RogApp, "func_key"), + (Pause, "func_key"), + (PgDn, "func_key"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Tilde, "tilde"), + (N1, "regular"), + (N2, "regular"), + (N3, "regular"), + (N4, "regular"), + (N5, "regular"), + (N6, "regular"), + (N7, "regular"), + (N8, "regular"), + (N9, "regular"), + (N0, "regular"), + (Hyphen, "regular"), + (Equals, "regular"), + (Backspace3_1, "backspace1"), + (Backspace3_2, "backspace2"), + (Backspace3_3, "backspace3"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Tab, "tab"), + (Q, "regular"), + (W, "regular"), + (E, "regular"), + (R, "regular"), + (T, "regular"), + (Y, "regular"), + (U, "regular"), + (I, "regular"), + (O, "regular"), + (P, "regular"), + (LBracket, "regular"), + (RBracket, "regular"), + (BackSlash, "ctrl_bkslash"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Caps, "capsplonk"), + (A, "regular"), + (S, "regular"), + (D, "regular"), + (F, "regular"), + (G, "regular"), + (H, "regular"), + (J, "regular"), + (K, "regular"), + (L, "regular"), + (SemiColon, "regular"), + (Quote, "regular"), + (Return3_1, "return1"), + (Return3_2, "return2"), + (Return3_3, "return3"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (LShift, "lshift"), + (Z, "regular"), + (X, "regular"), + (C, "regular"), + (V, "regular"), + (B, "regular"), + (N, "regular"), + (M, "regular"), + (Comma, "regular"), + (Period, "regular"), + (FwdSlash, "regular"), + (Rshift3_1, "rshift1"), + (Rshift3_2, "rshift2"), + (Rshift3_3, "rshift3"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (LCtrl, "bottom_row"), + (LFn, "bottom_row"), + (Meta, "bottom_row"), + (LAlt, "bottom_row"), + (Spacebar5_1, "spacebar_left"), + (Spacebar5_2, "spacebar_mid"), + (Spacebar5_3, "spacebar_mid"), + (Spacebar5_4, "spacebar_mid"), + (Spacebar5_5, "spacebar_right"), + (RAlt, "bottom_row"), + (PrtSc, "bottom_row"), + (RCtrl, "bottom_row"), + (Up, "up_arrow"), + ], + ), + ( + pad_left: 0.1, + pad_top: 0.1, + row: [ + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Blocking, "arrow_row_blocking"), + (Left, "arrows"), + (Down, "arrows"), + (Right, "arrows"), + ], + ), + ], +) \ No newline at end of file diff --git a/rog-aura/data/per_key_raw_bytes.ods b/rog-aura/data/per_key_raw_bytes.ods new file mode 100644 index 0000000000000000000000000000000000000000..7543233eeed94a48e087aa7c4ac32e817ca844d8 GIT binary patch literal 34954 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 V2g03SxpEu$vjmKNWWm3${vW?o#$x~g literal 0 HcmV?d00001 diff --git a/rog-aura/src/advanced.rs b/rog-aura/src/advanced.rs new file mode 100644 index 00000000..fbaf669e --- /dev/null +++ b/rog-aura/src/advanced.rs @@ -0,0 +1,576 @@ +use log::warn; +use serde::{Deserialize, Serialize}; +#[cfg(feature = "dbus")] +use zbus::zvariant::Type; + +/// The `LedCode` used in setting up keyboard layouts is important because it +/// determines the idexing for an RGB value in the final USB packets (for +/// per-key addressable keyboards). +#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] +pub enum LedCode { + VolUp, + VolDown, + MicMute, + #[default] + RogApp, + RogFan, + Esc, + F1, + F2, + F3, + F4, + F5, + F6, + F7, + F8, + F9, + F10, + F11, + F12, + Del, + Tilde, + N1, + N2, + N3, + N4, + N5, + N6, + N7, + N8, + N9, + N0, + Hyphen, + Equals, + Backspace, + /// For keyboards where the backspace button has 3 LED + Backspace3_1, + Backspace3_2, + Backspace3_3, + Home, + Tab, + Q, + W, + E, + R, + T, + Y, + U, + I, + O, + P, + LBracket, + RBracket, + BackSlash, + PgUp, + Caps, + A, + S, + D, + F, + G, + H, + J, + K, + L, + SemiColon, + Quote, + Return, + /// For keyboards where the return button has 3 LED + Return3_1, + Return3_2, + Return3_3, + PgDn, + LShift, + /// For keyboards where the left shift button has 3 LED + LShift3_1, + LShift3_2, + LShift3_3, + Z, + X, + C, + V, + B, + N, + M, + Comma, + Period, + FwdSlash, + Star, + NumPadDel, + NumPadPlus, + NumPadEnter, + NumPadPause, + NumPadPrtSc, + NumPadHome, + NumLock, + Rshift, + Rshift3_1, + Rshift3_2, + Rshift3_3, + End, + LCtrl, + LFn, + Meta, + LAlt, + Spacebar, + /// For keyboards where the spacebar button has 5 LED + Spacebar5_1, + Spacebar5_2, + Spacebar5_3, + Spacebar5_4, + Spacebar5_5, + Pause, + RAlt, + PrtSc, + RCtrl, + Up, + Down, + Left, + Right, + RFn, + MediaPlay, + MediaStop, + MediaNext, + MediaPrev, + LidLogo, + LidLeft, + LidRight, + /// Used by per-key and multizoned + LightbarRight, + /// Used by per-key and multizoned + LightbarRightCorner, + /// Used by per-key and multizoned + LightbarRightBottom, + /// Used by per-key and multizoned + LightbarLeftBottom, + /// Used by per-key and multizoned + LightbarLeftCorner, + /// Used by per-key and multizoned + LightbarLeft, + /// Use if the keyboard supports only a single zone. This zone uses the same + /// packet data as the `Zoned*` below + SingleZone, + /// Use if the keyboard supports 4 zones, this is the left zone + ZonedKbLeft, + /// Use if the keyboard supports 4 zones, this is the left-center zone + ZonedKbLeftMid, + /// Use if the keyboard supports 4 zones, this is the right-center zone + ZonedKbRightMid, + /// Use if the keyboard supports 4 zones, this is the right zone + ZonedKbRight, + /// To be ignored by effects + Spacing, + /// To be ignored by effects + Blocking, +} + +impl LedCode { + pub fn is_placeholder(&self) -> bool { + matches!(self, Self::Spacing | Self::Blocking) + } + + pub fn is_keyboard_zone(&self) -> bool { + matches!( + self, + Self::ZonedKbLeft | Self::ZonedKbLeftMid | Self::ZonedKbRightMid | Self::ZonedKbRight + ) + } + + pub fn is_lightbar_zone(&self) -> bool { + matches!( + self, + Self::LightbarLeft + | Self::LightbarLeftCorner + | Self::LightbarLeftBottom + | Self::LightbarRightBottom + | Self::LightbarRightCorner + | Self::LightbarRight + ) + } +} + +/// Represents the per-key raw USB packets +pub type UsbPackets = Vec>; + +/// A `UsbPackets` contains all data to change the full set of keyboard +/// key colours individually. +/// +/// Each row of the internal array is a full HID packet that can be sent +/// to the keyboard EC. One row controls one group of keys, these keys are not +/// necessarily all on the same row of the keyboard, with some splitting between +/// two rows. +#[cfg_attr(feature = "dbus", derive(Type))] +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct LedUsbPackets { + /// The packet data used to send data to the USB keyboard + usb_packets: UsbPackets, + /// Wether or not this packet collection is zoned. The determines which + /// starting bytes are used and what the indexing is for lightbar RGB + /// colours + zoned: bool, +} + +impl Default for LedUsbPackets { + fn default() -> Self { + Self::new_per_key() + } +} + +impl LedUsbPackets { + /// Set up a series of per-key packets. This includes setting all the + /// required starting bytes per packet, but does not set any colours. + /// + /// These packets will not work with per-zone keyboards + pub fn new_per_key() -> Self { + let mut set = vec![vec![0u8; 64]; 11]; + // set[0].copy_from_slice(&KeyColourArray::get_init_msg()); + for (count, row) in set.iter_mut().enumerate() { + row[0] = 0x5d; // Report ID + row[1] = 0xbc; // Mode = custom??, 0xb3 is builtin + row[2] = 0x00; + row[3] = 0x01; // ?? + row[4] = 0x01; // ??, 4,5,6 are normally RGB for builtin mode colours + row[5] = 0x01; // ?? + row[6] = (count as u8) << 4; // Key group + if count == 10 { + row[7] = 0x08; // 0b00001000 + } else { + row[7] = 0x10; // 0b00010000 addressing? flips for group a0 + } + row[8] = 0x00; + } + Self { + usb_packets: set, + zoned: false, + } + } + + /// Create new zoned packets. Although the result is a nested `Vec` only the + /// first vector is available. The final packet is slightly different + /// for single-zoned compared to multizoned. + /// + /// This packet will not work with per-key keyboards + /// + /// Wireshark captures show: + /// ```ignore + /// 5d,bc,01,01,00,00,00,00,00,ff,00,00, RED, single zone + /// 5d,bc,01,01,04,00,00,00,00,ff,00,00, RED, multizone + /// ``` + pub fn new_zoned(multizoned: bool) -> Self { + let mut pkt = vec![0u8; 64]; + pkt[0] = 0x5d; // Report ID + pkt[1] = 0xbc; // Mode = custom??, 0xb3 is builtin + pkt[2] = 0x01; + pkt[3] = 0x01; // ?? + if !multizoned { + pkt[4] = 0x00; // This doesn't actually seem to matter on this + // keyboard? + } else { + pkt[4] = 0x04; // ??, 4,5,6 are normally RGB for builtin mode + // colours + } + Self { + usb_packets: vec![pkt], + zoned: true, + } + } + + /// Initialise and clear the keyboard for custom effects, this must be done + /// for every time mode switches from builtin to custom + #[inline] + pub const fn get_init_msg() -> [u8; 64] { + let mut init = [0u8; 64]; + init[0] = 0x5d; // Report ID + init[1] = 0xbc; // Mode = custom??, 0xb3 is builtin + init + } + + /// Set the RGB colour of an `LedCode` + #[inline] + pub fn set(&mut self, key: LedCode, r: u8, g: u8, b: u8) { + if let Some(c) = self.rgb_for_led_code(key) { + c[0] = r; + c[1] = g; + c[2] = b; + } + } + + /// Indexes in to `UsbPackets` at the correct row and column + /// to set a series of three bytes to the chosen R,G,B values + /// + /// Indexing is different for `zoned` and assumes that only one packet is + /// generated for all the zones + fn rgb_for_led_code(&mut self, led_code: LedCode) -> Option<&mut [u8]> { + let zoned = self.zoned; + // Tuples are indexes in to array + let (row, col) = match led_code { + LedCode::VolDown => (0, 15), + LedCode::VolUp => (0, 18), + LedCode::MicMute => (0, 21), + LedCode::RogApp => (0, 24), + // + LedCode::Esc => (1, 24), + LedCode::F1 => (1, 30), + LedCode::F2 => (1, 33), + LedCode::F3 => (1, 36), + LedCode::F4 => (1, 39), + LedCode::F5 => (1, 45), + LedCode::F6 => (1, 48), + LedCode::F7 => (1, 51), + LedCode::F8 => (1, 54), + // + LedCode::F9 => (2, 12), + LedCode::F10 => (2, 15), + LedCode::F11 => (2, 18), + LedCode::F12 => (2, 21), + LedCode::Del => (2, 24), + LedCode::Tilde => (2, 39), + LedCode::N1 => (2, 42), + LedCode::N2 => (2, 45), + LedCode::N3 => (2, 48), + LedCode::N4 => (2, 51), + LedCode::N5 => (2, 54), + // + LedCode::N6 => (3, 9), + LedCode::N7 => (3, 12), + LedCode::N8 => (3, 15), + LedCode::N9 => (3, 18), + LedCode::N0 => (3, 21), + LedCode::Hyphen => (3, 24), + LedCode::Equals => (3, 27), + LedCode::Backspace3_1 => (3, 30), + LedCode::Backspace3_2 => (3, 33), + LedCode::Backspace3_3 => (3, 36), + LedCode::Home => (3, 39), + LedCode::Tab => (3, 54), + // + LedCode::Q => (4, 9), + LedCode::W => (4, 12), + LedCode::E => (4, 15), + LedCode::R => (4, 18), + LedCode::T => (4, 21), + LedCode::Y => (4, 24), + LedCode::U => (4, 27), + LedCode::I => (4, 30), + LedCode::O => (4, 33), + LedCode::P => (4, 36), + LedCode::LBracket => (4, 39), + LedCode::RBracket => (4, 42), + LedCode::BackSlash => (4, 45), + LedCode::PgUp => (4, 54), + // + LedCode::Caps => (5, 21), + LedCode::A => (5, 24), + LedCode::S => (5, 27), + LedCode::D => (5, 30), + LedCode::F => (5, 33), + LedCode::G => (5, 36), + LedCode::H => (5, 39), + LedCode::J => (5, 42), + LedCode::K => (5, 45), + LedCode::L => (5, 48), + LedCode::SemiColon => (5, 51), + LedCode::Quote => (5, 54), + // + LedCode::Return => (6, 9), + LedCode::Return3_1 => (6, 12), + LedCode::Return3_2 => (6, 15), + LedCode::Return3_3 => (6, 18), + LedCode::PgDn => (6, 21), + LedCode::LShift => (6, 36), + // TODO: Find correct locations + LedCode::LShift3_1 => (6, 36), + LedCode::LShift3_2 => (6, 36), + LedCode::LShift3_3 => (6, 36), + LedCode::Z => (6, 42), + LedCode::X => (6, 45), + LedCode::C => (6, 48), + LedCode::V => (6, 51), + LedCode::B => (6, 54), + // + LedCode::N => (7, 9), + LedCode::M => (7, 12), + LedCode::Comma => (7, 15), + LedCode::Period => (7, 18), + LedCode::FwdSlash => (7, 21), + LedCode::Rshift => (7, 24), + LedCode::Rshift3_1 => (7, 27), + LedCode::Rshift3_2 => (7, 30), + LedCode::Rshift3_3 => (7, 33), + LedCode::End => (7, 36), + LedCode::LCtrl => (7, 51), + LedCode::LFn => (7, 54), + // + LedCode::Meta => (8, 9), + LedCode::LAlt => (8, 12), + LedCode::Spacebar5_1 => (8, 15), + LedCode::Spacebar5_2 => (8, 18), + LedCode::Spacebar5_3 => (8, 21), + LedCode::Spacebar5_4 => (8, 24), + LedCode::Spacebar5_5 => (8, 27), + LedCode::RAlt => (8, 30), + LedCode::PrtSc => (8, 33), + LedCode::RCtrl => (8, 36), + LedCode::Up => (8, 42), + LedCode::RFn => (8, 51), + // + LedCode::Left => (9, 54), + // + LedCode::Down => (10, 9), + LedCode::Right => (10, 12), + LedCode::LidLogo => (11, 9), + LedCode::LidLeft => (11, 36), + LedCode::LidRight => (11, 39), + // + LedCode::SingleZone | LedCode::ZonedKbLeft => (0, 9), + LedCode::ZonedKbLeftMid => (0, 12), + LedCode::ZonedKbRightMid => (0, 15), + LedCode::ZonedKbRight => (0, 18), + LedCode::LightbarRight => if zoned {(0, 27)} else { (11, 15)}, + LedCode::LightbarRightCorner => if zoned {(0, 30)} else {(11, 18)}, + LedCode::LightbarRightBottom => if zoned {(0, 33)} else{(11, 21)}, + LedCode::LightbarLeftBottom => if zoned {(0, 36)} else{(11, 24)}, + LedCode::LightbarLeftCorner => if zoned {(0, 39)} else{(11, 27)}, + LedCode::LightbarLeft => if zoned {(0, 42)} else{(11, 30)}, + // + LedCode::Spacing + | LedCode::Blocking + // TODO: the addressing of the following + | LedCode::MediaPlay + | LedCode::MediaStop + | LedCode::MediaPrev + | LedCode::MediaNext + | LedCode::Pause + | LedCode::NumLock + | LedCode::Star + | LedCode::NumPadDel + | LedCode::NumPadPlus + | LedCode::NumPadEnter + | LedCode::NumPadPause + | LedCode::NumPadPrtSc + | LedCode::NumPadHome + | LedCode::RogFan + | LedCode::Spacebar + | LedCode::Backspace => return None, + }; + + if self.zoned && row > 0 { + warn!( + "LedCode {led_code:?} for zoned is not correct or out of Zone range. Setting to 0", + ); + return None; + } + + Some(&mut self.usb_packets[row][col..=col + 2]) + } + + #[inline] + pub fn get(&self) -> UsbPackets { + self.usb_packets.clone() + } + + #[inline] + pub fn get_ref(&self) -> &UsbPackets { + &self.usb_packets + } + + #[inline] + pub fn get_mut(&mut self) -> &mut UsbPackets { + &mut self.usb_packets + } +} + +impl From for UsbPackets { + fn from(k: LedUsbPackets) -> Self { + k.usb_packets + } +} + +#[cfg(test)] +mod tests { + use crate::advanced::{LedCode, LedUsbPackets, UsbPackets}; + + macro_rules! colour_check_zoned { + ($zone:expr, $pkt_idx_start:expr) => { + let mut zone = LedUsbPackets::new_zoned(true); + let c = zone.rgb_for_led_code($zone).unwrap(); + c[0] = 255; + c[1] = 255; + c[2] = 255; + + let pkt: UsbPackets = zone.into(); + assert_eq!(pkt[0][$pkt_idx_start], 0xff); + assert_eq!(pkt[0][$pkt_idx_start + 1], 0xff); + assert_eq!(pkt[0][$pkt_idx_start + 2], 0xff); + }; + } + + #[test] + fn zone_to_packet_check() { + let zone = LedUsbPackets::new_zoned(true); + let pkt: UsbPackets = zone.into(); + assert_eq!(pkt[0][0], 0x5d); + assert_eq!(pkt[0][1], 0xbc); + assert_eq!(pkt[0][2], 0x01); + assert_eq!(pkt[0][3], 0x01); + assert_eq!(pkt[0][4], 0x04); + + colour_check_zoned!(LedCode::ZonedKbLeft, 9); + colour_check_zoned!(LedCode::ZonedKbLeftMid, 12); + colour_check_zoned!(LedCode::ZonedKbRightMid, 15); + colour_check_zoned!(LedCode::ZonedKbRight, 18); + + colour_check_zoned!(LedCode::LightbarRight, 27); + colour_check_zoned!(LedCode::LightbarRightCorner, 30); + colour_check_zoned!(LedCode::LightbarRightBottom, 33); + colour_check_zoned!(LedCode::LightbarLeftBottom, 36); + colour_check_zoned!(LedCode::LightbarLeftCorner, 39); + colour_check_zoned!(LedCode::LightbarLeft, 42); + } + + #[test] + fn perkey_to_packet_check() { + let per_key = LedUsbPackets::new_per_key(); + let pkt: UsbPackets = per_key.into(); + assert_eq!(pkt[0][0], 0x5d); + assert_eq!(pkt[0][1], 0xbc); + assert_eq!(pkt[0][2], 0x00); + assert_eq!(pkt[0][3], 0x01); + assert_eq!(pkt[0][4], 0x01); + assert_eq!(pkt[0][5], 0x01); + + let mut per_key = LedUsbPackets::new_per_key(); + let c = per_key.rgb_for_led_code(LedCode::D).unwrap(); + c[0] = 255; + c[1] = 255; + c[2] = 255; + let c = per_key.rgb_for_led_code(LedCode::O).unwrap(); + c[0] = 255; + c[1] = 255; + c[2] = 255; + let c = per_key.rgb_for_led_code(LedCode::N0).unwrap(); + c[0] = 255; + c[1] = 255; + c[2] = 255; + let c = per_key.rgb_for_led_code(LedCode::M).unwrap(); + c[0] = 255; + c[1] = 255; + c[2] = 255; + + let pkt: UsbPackets = per_key.into(); + assert_eq!(pkt[5][30], 0xff); // D, red + assert_eq!(pkt[5][31], 0xff); // D + assert_eq!(pkt[5][32], 0xff); // D + assert_eq!(pkt[5][33], 0x00); // D + + assert_eq!(pkt[4][33], 0xff); // O, red + assert_eq!(pkt[4][34], 0xff); // O + assert_eq!(pkt[4][35], 0xff); // O + assert_eq!(pkt[4][36], 0x00); // O + + assert_eq!(pkt[7][12], 0xff); // M, red + assert_eq!(pkt[7][13], 0xff); // M + assert_eq!(pkt[7][14], 0xff); // M + assert_eq!(pkt[7][15], 0x00); // M + } +} diff --git a/rog-aura/src/advanced_to_str.rs b/rog-aura/src/advanced_to_str.rs new file mode 100644 index 00000000..95fb1ac2 --- /dev/null +++ b/rog-aura/src/advanced_to_str.rs @@ -0,0 +1,148 @@ +use crate::advanced::LedCode; + +impl From for &str { + fn from(k: LedCode) -> Self { + (&k).into() + } +} + +impl From<&LedCode> for &str { + fn from(k: &LedCode) -> Self { + match k { + LedCode::VolUp => "Volume Up", + LedCode::VolDown => "Volume Down", + LedCode::MicMute => "Mute Mic", + LedCode::RogApp => "ROG", + LedCode::RogFan => "Fan Control", + LedCode::Esc => "Escape", + LedCode::F1 => "F1", + LedCode::F2 => "F2", + LedCode::F3 => "F3", + LedCode::F4 => "F4", + LedCode::F5 => "F5", + LedCode::F6 => "F6", + LedCode::F7 => "F7", + LedCode::F8 => "F8", + LedCode::F9 => "F9", + LedCode::F10 => "F10", + LedCode::F11 => "F11", + LedCode::F12 => "F12", + LedCode::Del => "Delete", + LedCode::Tilde => "Tilde", + LedCode::N1 => "1", + LedCode::N2 => "2", + LedCode::N3 => "3", + LedCode::N4 => "4", + LedCode::N5 => "5", + LedCode::N6 => "6", + LedCode::N7 => "7", + LedCode::N8 => "8", + LedCode::N9 => "9", + LedCode::N0 => "0", + LedCode::Hyphen => "-", + LedCode::Equals => "=", + LedCode::Backspace => "Backspace", + LedCode::Backspace3_1 => "Backspace LED 1", + LedCode::Backspace3_2 => "Backspace LED 2", + LedCode::Backspace3_3 => "Backspace LED 3", + LedCode::Home => "Home", + LedCode::Tab => "Tab", + LedCode::Q => "Q", + LedCode::W => "W", + LedCode::E => "E", + LedCode::R => "R", + LedCode::T => "T", + LedCode::Y => "Y", + LedCode::U => "U", + LedCode::I => "I", + LedCode::O => "O", + LedCode::P => "P", + LedCode::LBracket => "[", + LedCode::RBracket => "]", + LedCode::BackSlash => "\\", + LedCode::PgUp => "Page Up", + LedCode::Caps => "Caps Lock", + LedCode::A => "A", + LedCode::S => "S", + LedCode::D => "D", + LedCode::F => "F", + LedCode::G => "G", + LedCode::H => "H", + LedCode::J => "J", + LedCode::K => "K", + LedCode::L => "L", + LedCode::SemiColon => ";", + LedCode::Quote => "'", + LedCode::Return => "Return", + LedCode::Return3_1 => "Return LED 1", + LedCode::Return3_2 => "Return LED 2", + LedCode::Return3_3 => "Return LED 3", + LedCode::PgDn => "Page Down", + LedCode::LShift => "Left Shift", + LedCode::LShift3_1 => "Left Shift LED 1", + LedCode::LShift3_2 => "Left Shift LED 2", + LedCode::LShift3_3 => "Left Shift LED 3", + LedCode::Z => "Z", + LedCode::X => "X", + LedCode::C => "C", + LedCode::V => "V", + LedCode::B => "B", + LedCode::N => "N", + LedCode::M => "M", + LedCode::Comma => ",", + LedCode::Period => ".", + LedCode::Star => "*", + LedCode::NumPadDel => "Delete", + LedCode::NumPadPlus => "+", + LedCode::NumPadEnter => "Enter", + LedCode::NumPadPause => "Pause", + LedCode::NumPadPrtSc => "Print Screen", + LedCode::NumPadHome => "Home", + LedCode::NumLock => "Num-Lock", + LedCode::FwdSlash => "/", + LedCode::Rshift => "Right Shift", + LedCode::Rshift3_1 => "Right Shift LED 1", + LedCode::Rshift3_2 => "Right Shift LED 2", + LedCode::Rshift3_3 => "Right Shift LED 3", + LedCode::End => "End", + LedCode::LCtrl => "Left Control", + LedCode::LFn => "Left Fn", + LedCode::Meta => "Meta", + LedCode::LAlt => "Left Alt", + LedCode::Spacebar => "Space", + LedCode::Spacebar5_1 => "Space LED 1", + LedCode::Spacebar5_2 => "Space LED 2", + LedCode::Spacebar5_3 => "Space LED 3", + LedCode::Spacebar5_4 => "Space LED 4", + LedCode::Spacebar5_5 => "Space LED 5", + LedCode::RAlt => "Right Alt", + LedCode::PrtSc => "Print Screen", + LedCode::RCtrl => "Right Control", + LedCode::Pause => "Pause", + LedCode::Up => "Up", + LedCode::Down => "Down", + LedCode::Left => "Left", + LedCode::Right => "Right", + LedCode::RFn => "Right Fn", + LedCode::MediaPlay => "Media Play", + LedCode::MediaStop => "Media Stop", + LedCode::MediaNext => "Media Next", + LedCode::MediaPrev => "Media Previous", + LedCode::LidLogo => "Lid Logo", + LedCode::LidLeft => "Lid Left", + LedCode::LidRight => "Lid Right", + LedCode::LightbarRight => "Lightbar Right", + LedCode::LightbarRightCorner => "Lightbar Right Corner", + LedCode::LightbarRightBottom => "Lightbar Right Bottom", + LedCode::LightbarLeftBottom => "Lightbar Left Bottom", + LedCode::LightbarLeftCorner => "Lightbar Left Corner", + LedCode::LightbarLeft => "Lightbar Left", + LedCode::Spacing | LedCode::Blocking => "", + LedCode::SingleZone => "Single Zoned Keyboard", + LedCode::ZonedKbLeft => "Left Zone (zone 1)", + LedCode::ZonedKbLeftMid => "Center-left Zone (zone 2)", + LedCode::ZonedKbRightMid => "Center-right Zone (zone 3)", + LedCode::ZonedKbRight => "Right Zone (zone 4)", + } + } +} diff --git a/rog-aura/src/aura_detection.rs b/rog-aura/src/aura_detection.rs new file mode 100644 index 00000000..ae2451de --- /dev/null +++ b/rog-aura/src/aura_detection.rs @@ -0,0 +1,189 @@ +use std::fs::OpenOptions; +use std::io::Read; + +use log::{error, info, warn}; +use serde_derive::{Deserialize, Serialize}; + +use crate::{AdvancedAuraType, AuraModeNum, AuraZone}; + +pub const ASUS_LED_MODE_CONF: &str = "/usr/share/asusd/aura_support.ron"; +pub const ASUS_LED_MODE_USER_CONF: &str = "/etc/asusd/asusd_user_ledmodes.ron"; +pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"]; + +#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] +pub struct LedSupportFile(Vec); + +#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)] +pub struct LaptopLedData { + /// Found via `cat /sys/class/dmi/id/board_name`, e.g `GU603ZW`. + /// The match doesn't have to be the complete model number as it is + /// typically broken down such: + /// - GU = product + /// - 603 = model/platform + /// - Z = variant/year or perhaps dGPU model (such as RTX 3xxx) + /// - W = possibly dGPU model (such as RTX 3060Ti) + pub board_name: String, + pub layout_name: String, + pub basic_modes: Vec, + pub basic_zones: Vec, + pub advanced_type: AdvancedAuraType, +} + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct LaptopLedData456 { + pub prod_family: String, + pub board_names: Vec, + pub standard: Vec, + pub multizone: Vec, + pub per_key: bool, +} + +impl LaptopLedData { + pub fn get_data() -> Self { + let dmi = sysfs_class::DmiId::default(); + let board_name = dmi.board_name().expect("Could not get board_name"); + // let prod_family = dmi.product_family().expect("Could not get + // product_family"); + + if let Some(modes) = LedSupportFile::load_from_config() { + if let Some(data) = modes.matcher(&board_name) { + return data; + } + } + info!("Using generic LED control for keyboard brightness only"); + LaptopLedData::default() + } +} + +impl LedSupportFile { + pub fn get(&self) -> &[LaptopLedData] { + &self.0 + } + + /// The list is stored in ordered format, so the iterator must be reversed + /// to ensure we match to *whole names* first before doing a glob match + pub fn matcher(self, board_name: &str) -> Option { + for config in self.0.iter().rev() { + if board_name.contains(&config.board_name) { + info!("LedSupport: Matched to {}", config.board_name); + return Some(config.clone()); + } + } + None + } + + pub fn load_from_config() -> Option { + let mut loaded = false; + let mut data = LedSupportFile::default(); + // Load user configs first so they are first to be checked + if let Ok(mut file) = OpenOptions::new().read(true).open(ASUS_LED_MODE_USER_CONF) { + let mut buf = String::new(); + if let Ok(l) = file.read_to_string(&mut buf) { + if l == 0 { + warn!("{} is empty", ASUS_LED_MODE_USER_CONF); + } else { + if let Ok(mut tmp) = ron::from_str::(&buf) { + data.0.append(&mut tmp.0); + } + info!( + "Loaded user-defined LED support data from {}", + ASUS_LED_MODE_USER_CONF + ); + } + } + } + // Load and append the default LED support data + if let Ok(mut file) = OpenOptions::new().read(true).open(ASUS_LED_MODE_CONF) { + let mut buf = String::new(); + if let Ok(l) = file.read_to_string(&mut buf) { + if l == 0 { + warn!("{} is empty", ASUS_LED_MODE_CONF); + } else { + let mut tmp: LedSupportFile = ron::from_str(&buf) + .map_err(|e| error!("{e}")) + .unwrap_or_else(|_| panic!("Could not deserialise {}", ASUS_LED_MODE_CONF)); + data.0.append(&mut tmp.0); + loaded = true; + info!( + "Loaded default LED support data from {}", + ASUS_LED_MODE_CONF + ); + } + } + } + data.0.sort_by(|a, b| a.board_name.cmp(&b.board_name)); + + if loaded { + return Some(data); + } + + warn!("Does {} exist?", ASUS_LED_MODE_USER_CONF); + None + } +} + +#[cfg(test)] +mod tests { + use std::fs::OpenOptions; + use std::io::{Read, Write}; + use std::path::PathBuf; + + use ron::ser::PrettyConfig; + + use super::LaptopLedData; + use crate::advanced::LedCode; + use crate::aura_detection::LedSupportFile; + // use crate::zoned::Zone; + use crate::{AdvancedAuraType, AuraModeNum, AuraZone}; + + #[test] + fn check_data_parse() { + let led = LaptopLedData { + board_name: "Test".to_owned(), + layout_name: "ga401".to_owned(), + basic_modes: vec![AuraModeNum::Static], + basic_zones: vec![AuraZone::Key1, AuraZone::Logo, AuraZone::BarLeft], + advanced_type: AdvancedAuraType::Zoned(vec![LedCode::LightbarRight]), + }; + + assert!(ron::to_string(&led).is_ok()); + // assert_eq!(json, String::new()); + } + + #[test] + fn check_data_file_parse() { + let mut data = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + data.push("data/aura_support.ron"); + + let mut file = OpenOptions::new().read(true).open(&data).unwrap(); + let mut buf = String::new(); + file.read_to_string(&mut buf).unwrap(); + + let tmp = ron::from_str::(&buf).unwrap(); + + // Ensure the data is sorted + let mut tmp_sort = tmp.clone(); + tmp_sort.0.sort_by(|a, b| a.board_name.cmp(&b.board_name)); + if tmp != tmp_sort { + let sorted = + ron::ser::to_string_pretty(&tmp_sort, PrettyConfig::new().depth_limit(2)).unwrap(); + let mut file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&data) + .unwrap(); + file.write_all(sorted.as_bytes()).unwrap(); + panic!( + "aura_support.ron not sorted, should be {sorted}. File rewritten with correct \ + order, run test again" + ) + } + + let my_config = PrettyConfig::new().depth_limit(2); + println!( + "RON: {}", + ron::ser::to_string_pretty(&tmp, my_config).unwrap() + ); + } +} diff --git a/rog-aura/src/builtin_modes.rs b/rog-aura/src/builtin_modes.rs index f16f7cc3..ddae1fe0 100644 --- a/rog-aura/src/builtin_modes.rs +++ b/rog-aura/src/builtin_modes.rs @@ -4,12 +4,15 @@ pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08]; pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08]; +use std::fmt::Display; +use std::str::FromStr; + use serde_derive::{Deserialize, Serialize}; -use std::{fmt::Display, str::FromStr}; #[cfg(feature = "dbus")] use zbus::zvariant::Type; -use crate::{error::Error, LED_MSG_LEN}; +use crate::error::Error; +use crate::LED_MSG_LEN; #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)] @@ -280,8 +283,8 @@ impl FromStr for AuraZone { } } -/// Default factory modes structure. This easily converts to an USB HID packet with: -/// ```rust +/// Default factory modes structure. This easily converts to an USB HID packet +/// with: ```rust /// // let bytes: [u8; LED_MSG_LEN] = mode.into(); /// ``` #[cfg_attr(feature = "dbus", derive(Type))] @@ -366,8 +369,8 @@ impl AuraParameters { } impl AuraEffect { - /// A helper to provide detail on what effects have which parameters, e.g the static - /// factory mode accepts only one colour. + /// A helper to provide detail on what effects have which parameters, e.g + /// the static factory mode accepts only one colour. pub const fn allowed_parameters(mode: AuraModeNum) -> AuraParameters { match mode { AuraModeNum::Static diff --git a/rog-aura/src/effects/base.rs b/rog-aura/src/effects/base.rs new file mode 100644 index 00000000..dd57116f --- /dev/null +++ b/rog-aura/src/effects/base.rs @@ -0,0 +1,33 @@ +use super::{EffectState, InputForEffect}; +use crate::advanced::LedCode; +use crate::Colour; + +pub struct InputBased { + address: LedCode, + colour: Colour, + /// - audio + /// - cpu freq + /// - temperature + /// - fan speed + /// - time + input: Box, +} + +impl EffectState for InputBased { + fn next_colour_state(&mut self, _layout: &crate::layouts::KeyLayout) { + self.input.next_colour_state(); + self.colour = self.input.get_colour(); + } + + fn get_colour(&self) -> Colour { + self.colour + } + + fn get_led(&self) -> LedCode { + self.address + } + + fn set_led(&mut self, address: LedCode) { + self.address = address + } +} diff --git a/rog-aura/src/effects/breathe.rs b/rog-aura/src/effects/breathe.rs new file mode 100644 index 00000000..8b74f1c4 --- /dev/null +++ b/rog-aura/src/effects/breathe.rs @@ -0,0 +1,82 @@ +use serde::{Deserialize, Serialize}; + +use super::EffectState; +use crate::advanced::LedCode; +use crate::layouts::KeyLayout; +use crate::{effect_state_impl, Colour, Speed}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Breathe { + address: LedCode, + /// The starting colour + start_colour1: Colour, + /// The secondary starting colour + start_colour2: Colour, + /// The speed at which to cycle between the colours + speed: Speed, + /// Temporary data to help keep state + #[serde(skip)] + colour: Colour, + #[serde(skip)] + count_flipped: bool, + #[serde(skip)] + use_colour1: bool, +} + +impl Breathe { + pub fn new(address: LedCode, colour1: Colour, colour2: Colour, speed: Speed) -> Self { + Self { + address, + start_colour1: colour1, + start_colour2: colour2, + speed, + colour: colour1, + count_flipped: false, + use_colour1: true, + } + } +} + +impl EffectState for Breathe { + effect_state_impl!(); + + fn next_colour_state(&mut self, _layout: &KeyLayout) { + let Self { + start_colour1: colour1, + start_colour2: colour2, + speed, + colour: colour_actual, + count_flipped: flipped, + use_colour1, + .. + } = self; + + let speed = 4 - ::from(*speed); + + if *colour_actual == Colour(0, 0, 0) { + *use_colour1 = !*use_colour1; + } + + let colour = if !*use_colour1 { colour2 } else { colour1 }; + + let r1_scale = colour.0 / speed / 2; + let g1_scale = colour.1 / speed / 2; + let b1_scale = colour.2 / speed / 2; + + if *colour_actual == Colour(0, 0, 0) { + *flipped = true; + } else if colour_actual >= colour { + *flipped = false; + } + + if !*flipped { + colour_actual.0 = colour_actual.0.saturating_sub(r1_scale); + colour_actual.1 = colour_actual.1.saturating_sub(g1_scale); + colour_actual.2 = colour_actual.2.saturating_sub(b1_scale); + } else { + colour_actual.0 = colour_actual.0.saturating_add(r1_scale); + colour_actual.1 = colour_actual.1.saturating_add(g1_scale); + colour_actual.2 = colour_actual.2.saturating_add(b1_scale); + } + } +} diff --git a/rog-aura/src/effects/doom.rs b/rog-aura/src/effects/doom.rs new file mode 100644 index 00000000..ab23efc3 --- /dev/null +++ b/rog-aura/src/effects/doom.rs @@ -0,0 +1,164 @@ +use serde::{Deserialize, Serialize}; + +use crate::advanced::LedCode; +use crate::effects::{p_random, EffectState}; +use crate::layouts::KeyLayout; +use crate::{effect_state_impl, Colour}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct DoomFlicker { + address: LedCode, + start_colour: Colour, + max_percentage: u8, + min_percentage: u8, + #[serde(skip)] + count: u8, + #[serde(skip)] + colour: Colour, +} + +impl DoomFlicker { + pub fn new(address: LedCode, colour: Colour, max_percentage: u8, min_percentage: u8) -> Self { + Self { + address, + colour, + count: 4, + max_percentage, + min_percentage, + start_colour: colour, + } + } +} + +impl EffectState for DoomFlicker { + effect_state_impl!(); + + fn next_colour_state(&mut self, _layout: &KeyLayout) { + let Self { + max_percentage, + min_percentage, + colour, + start_colour, + .. + } = self; + + if self.count == 0 { + self.count = 4; + } + self.count -= 1; + if self.count != 0 { + return; + } + + // TODO: make a "percentage" method on Colour. + let max_light = Colour( + (start_colour.0 as f32 / 100.0 * *max_percentage as f32) as u8, + (start_colour.1 as f32 / 100.0 * *max_percentage as f32) as u8, + (start_colour.2 as f32 / 100.0 * *max_percentage as f32) as u8, + ); + // min light is a percentage of the set colour + let min_light = Colour( + (start_colour.0 as f32 / 100.0 * *min_percentage as f32) as u8, + (start_colour.1 as f32 / 100.0 * *min_percentage as f32) as u8, + (start_colour.2 as f32 / 100.0 * *min_percentage as f32) as u8, + ); + + // Convert the 255 to percentage + let amount = (p_random() & 7) as f32 * 8.0; + + let set_colour = |colour: &mut u8, max: f32, min: f32| { + let pc = amount / max * 100.0; + let min_amount = pc * min / 100.0; // percentage of min colour + let max_amount = pc * max / 100.0; // percentage of max colour + if *colour as f32 - min_amount < min { + *colour = min as u8; + } else { + *colour = (max - max_amount) as u8; + } + }; + set_colour(&mut colour.0, max_light.0 as f32, min_light.0 as f32); + set_colour(&mut colour.1, max_light.1 as f32, min_light.1 as f32); + set_colour(&mut colour.2, max_light.2 as f32, min_light.2 as f32); + + self.count = 4; + } +} + +pub struct LightFlash { + pub count: i32, + pub max_light: i32, + pub min_light: i32, + pub max_time: i32, + pub min_time: i32, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct DoomLightFlash { + address: LedCode, + start_colour: Colour, + max_percentage: u8, + min_percentage: u8, + #[serde(skip)] + max_time: i32, + #[serde(skip)] + min_time: i32, + #[serde(skip)] + count: u8, + #[serde(skip)] + colour: Colour, +} + +impl DoomLightFlash { + pub fn new(address: LedCode, colour: Colour, max_percentage: u8, min_percentage: u8) -> Self { + Self { + address, + colour, + count: 4, + max_percentage, + min_percentage, + start_colour: colour, + max_time: 32, + min_time: 7, + } + } +} + +impl EffectState for DoomLightFlash { + effect_state_impl!(); + + fn next_colour_state(&mut self, _layout: &KeyLayout) { + let Self { + max_percentage, + min_percentage, + colour, + start_colour, + .. + } = self; + + self.count -= 1; + if self.count != 0 { + return; + } + + // TODO: make a "percentage" method on Colour. + let max_light = Colour( + (start_colour.0 as f32 / 100.0 * *max_percentage as f32) as u8, + (start_colour.1 as f32 / 100.0 * *max_percentage as f32) as u8, + (start_colour.2 as f32 / 100.0 * *max_percentage as f32) as u8, + ); + // min light is a percentage of the set colour + let min_light = Colour( + (start_colour.0 as f32 / 100.0 * *min_percentage as f32) as u8, + (start_colour.1 as f32 / 100.0 * *min_percentage as f32) as u8, + (start_colour.2 as f32 / 100.0 * *min_percentage as f32) as u8, + ); + + if *colour == max_light { + *colour = min_light; + self.count = ((p_random() & self.min_time) + 1) as u8; + } else { + *colour = max_light; + self.count = ((p_random() & self.max_time) + 1) as u8; + } + } +} diff --git a/rog-aura/src/effects/mod.rs b/rog-aura/src/effects/mod.rs new file mode 100644 index 00000000..f479518d --- /dev/null +++ b/rog-aura/src/effects/mod.rs @@ -0,0 +1,291 @@ +use serde_derive::{Deserialize, Serialize}; + +mod doom; +pub use doom::*; + +mod base; +pub use base::*; + +mod breathe; +pub use breathe::*; + +mod static_; +pub use static_::*; + +use crate::advanced::{LedCode, LedUsbPackets, UsbPackets}; +use crate::layouts::KeyLayout; +use crate::Colour; + +// static mut RNDINDEX: usize = 0; +static mut PRNDINDEX: usize = 0; + +/// Pseudo random table ripped straight out of room4doom +pub const RNDTABLE: [i32; 256] = [ + 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21, 211, 47, 80, 242, 154, + 27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, + 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, 149, 104, 25, 178, 252, 182, + 202, 182, 141, 197, 4, 81, 181, 242, 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, + 249, 0, 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235, 25, 92, 20, 145, 138, + 77, 69, 166, 78, 176, 173, 212, 166, 113, 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, + 171, 75, 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196, 135, 106, 63, 197, 195, + 86, 96, 203, 113, 101, 170, 247, 181, 113, 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, + 166, 103, 241, 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224, 145, 224, 81, + 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95, 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, + 54, 14, 109, 226, 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, 17, 46, 52, + 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 197, 242, 98, 43, 39, 175, 254, 145, 190, + 84, 118, 222, 187, 136, 120, 163, 236, 249, +]; + +pub fn p_random() -> i32 { + unsafe { + PRNDINDEX = (PRNDINDEX + 1) & 0xff; + RNDTABLE[PRNDINDEX] + } +} + +pub trait InputForEffect { + /// Calculate the next colour state + fn next_colour_state(&mut self); + + /// Return the resulting colour. Implementers should store the colour to + /// return it. + fn get_colour(&self) -> Colour; +} + +pub(crate) trait EffectState { + /// Calculate the next colour state + fn next_colour_state(&mut self, _layout: &KeyLayout); + + /// Return the resulting colour. Implementers should store the colour to + /// return it. + fn get_colour(&self) -> Colour; + + fn get_led(&self) -> LedCode; + + fn set_led(&mut self, address: LedCode); +} + +#[derive(Debug, Deserialize, Serialize, Default)] +pub struct AdvancedEffects { + effects: Vec, + zoned: bool, +} + +impl AdvancedEffects { + #[inline] + pub fn new(zoned: bool) -> Self { + Self { + effects: Default::default(), + zoned, + } + } + + #[inline] + pub fn push(&mut self, action: Effect) { + self.effects.push(action); + } + + #[inline] + pub fn insert(&mut self, index: usize, action: Effect) { + self.effects.insert(index, action); + } + + /// Remove an item at this position from the run buffer. If the `index` + /// supplied is not in range then `None` is returned, otherwise the + /// `ActionData` at that location is yeeted and returned. + #[inline] + pub fn remove_item(&mut self, index: usize) -> Option { + if index < self.effects.len() { + return Some(self.effects.remove(index)); + } + None + } + + pub fn next_state(&mut self, layout: &KeyLayout) { + for effect in &mut self.effects { + effect.next_state(layout); + } + } + + pub fn create_packets(&self) -> UsbPackets { + let mut usb_packets = if self.zoned { + // TODO: figure out if that single byte difference for multizone actually + // matters + LedUsbPackets::new_zoned(true) + } else { + LedUsbPackets::new_per_key() + }; + + for effect in &self.effects { + let c = effect.colour(); + usb_packets.set(effect.led(), c.0, c.1, c.2); + } + usb_packets.into() + } +} + +// how to be lazy +#[macro_export] +macro_rules! effect_state_impl { + () => { + fn get_colour(&self) -> $crate::Colour { + self.colour + } + + fn get_led(&self) -> $crate::advanced::LedCode { + self.address.clone() + } + + /// Change the led type + fn set_led(&mut self, address: $crate::advanced::LedCode) { + self.address = address; + } + }; +} + +/// A helper macro to quickly add new effects to the matching on `Effect` +macro_rules! effect_impl { + ($($effect:ident),*) => { + impl Effect { + /// Get the type of LED set + pub fn led(&self) -> $crate::advanced::LedCode { + match self { + $(Effect::$effect(c) => c.get_led(),)* + } + } + + /// Change the led type (can be used to change location of the effect) + pub fn set_led(&mut self, address: $crate::advanced::LedCode) { + match self { + $(Effect::$effect(c) => c.set_led(address),)* + } + } + + /// Calculate the next state of the effect + pub fn next_state(&mut self, layout: &KeyLayout) { + match self { + $(Effect::$effect(c) => c.next_colour_state(layout),)* + } + } + + /// Get the calculated colour + pub fn colour(&self) -> $crate::Colour { + match self { + $(Effect::$effect(c) => c.get_colour(),)* + } + } + } + }; +} + +/// The main effect container, a sequencer will call various methods on this to +/// update states and get colours +/// +/// Every effect is added here to quickly and easily match within `Effect` +#[derive(Debug, Clone, Deserialize, Serialize)] +pub enum Effect { + Static(Static), + Breathe(Breathe), + DoomFlicker(DoomFlicker), + DoomLightFlash(DoomLightFlash), +} + +impl Default for Effect { + fn default() -> Self { + Self::Static(Static::new(LedCode::default(), Colour::default())) + } +} + +effect_impl!(Static, Breathe, DoomFlicker, DoomLightFlash); + +#[cfg(test)] +mod tests { + use crate::advanced::LedCode; + use crate::effects::{AdvancedEffects, Breathe, DoomFlicker, Effect, Static}; + use crate::layouts::KeyLayout; + use crate::{Colour, Speed}; + + #[test] + fn single_key_next_state_then_create() { + let layout = KeyLayout::default_layout(); + let mut seq = AdvancedEffects::new(false); + seq.effects + .push(Effect::Static(Static::new(LedCode::F, Colour(255, 127, 0)))); + + seq.next_state(&layout); + let packets = seq.create_packets(); + + assert_eq!(packets[0][0], 0x5d); + assert_eq!(packets[5][33], 255); + assert_eq!(packets[5][34], 127); + assert_eq!(packets[5][35], 0); + } + + #[test] + fn cycle_breathe() { + let layout = KeyLayout::default_layout(); + let mut seq = AdvancedEffects::new(false); + seq.effects.push(Effect::Breathe(Breathe::new( + LedCode::F, + Colour(255, 127, 0), + Colour(127, 0, 255), + Speed::Med, + ))); + + let s = + ron::ser::to_string_pretty(&seq, ron::ser::PrettyConfig::new().depth_limit(4)).unwrap(); + println!("{s}"); + + seq.next_state(&layout); + let packets = seq.create_packets(); + + assert_eq!(packets[0][0], 0x5d); + assert_eq!(packets[5][33], 213); + assert_eq!(packets[5][34], 106); + assert_eq!(packets[5][35], 0); + + // dbg!(&packets[5][33..=35]); + + seq.next_state(&layout); + let packets = seq.create_packets(); + + assert_eq!(packets[0][0], 0x5d); + assert_eq!(packets[5][33], 171); + assert_eq!(packets[5][34], 85); + assert_eq!(packets[5][35], 0); + } + + #[test] + fn cycle_flicker() { + let layout = KeyLayout::default_layout(); + let mut seq = AdvancedEffects::new(false); + seq.effects.push(Effect::DoomFlicker(DoomFlicker::new( + LedCode::F, + Colour(255, 127, 80), + 100, + 10, + ))); + + seq.next_state(&layout); + let packets = seq.create_packets(); + + assert_eq!(packets[0][0], 0x5d); + assert_eq!(packets[5][33], 255); + assert_eq!(packets[5][34], 127); + assert_eq!(packets[5][35], 80); + + // The random is deterministic + seq.next_state(&layout); + seq.next_state(&layout); + seq.next_state(&layout); + seq.next_state(&layout); + seq.next_state(&layout); + seq.next_state(&layout); + seq.next_state(&layout); + + let packets = seq.create_packets(); + assert_eq!(packets[5][33], 215); + assert_eq!(packets[5][34], 87); + assert_eq!(packets[5][35], 40); + } +} diff --git a/rog-aura/src/effects/static_.rs b/rog-aura/src/effects/static_.rs new file mode 100644 index 00000000..18925a83 --- /dev/null +++ b/rog-aura/src/effects/static_.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +use super::EffectState; +use crate::advanced::LedCode; +use crate::layouts::KeyLayout; +use crate::{effect_state_impl, Colour}; + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Static { + address: LedCode, + /// The starting colour + colour: Colour, +} + +impl Static { + pub fn new(address: LedCode, colour: Colour) -> Self { + Self { address, colour } + } +} + +impl EffectState for Static { + effect_state_impl!(); + + fn next_colour_state(&mut self, _layout: &KeyLayout) {} +} diff --git a/rog-aura/src/error.rs b/rog-aura/src/error.rs index 2d6c0b81..2e7c86de 100644 --- a/rog-aura/src/error.rs +++ b/rog-aura/src/error.rs @@ -1,5 +1,4 @@ -use std::error; -use std::fmt; +use std::{error, fmt}; #[derive(Debug)] pub enum Error { @@ -7,8 +6,9 @@ pub enum Error { ParseSpeed, ParseDirection, ParseBrightness, - Io(std::io::Error), - Toml(toml::de::Error), + IoPath(String, std::io::Error), + Ron(ron::Error), + RonParse(ron::error::SpannedError), } impl fmt::Display for Error { @@ -19,22 +19,23 @@ impl fmt::Display for Error { Error::ParseSpeed => write!(f, "Could not parse speed"), Error::ParseDirection => write!(f, "Could not parse direction"), Error::ParseBrightness => write!(f, "Could not parse brightness"), - Error::Io(io) => write!(f, "IO Error: {io}"), - Error::Toml(e) => write!(f, "TOML Parse Error: {e}"), + Error::IoPath(path, io) => write!(f, "IO Error: {path}, {io}"), + Error::Ron(e) => write!(f, "RON Parse Error: {e}"), + Error::RonParse(e) => write!(f, "RON Parse Error: {e}"), } } } impl error::Error for Error {} -impl From for Error { - fn from(e: std::io::Error) -> Self { - Self::Io(e) +impl From for Error { + fn from(e: ron::Error) -> Self { + Self::Ron(e) } } -impl From for Error { - fn from(e: toml::de::Error) -> Self { - Self::Toml(e) +impl From for Error { + fn from(e: ron::error::SpannedError) -> Self { + Self::RonParse(e) } } diff --git a/rog-aura/src/key_to_str.rs b/rog-aura/src/key_to_str.rs deleted file mode 100644 index e215a689..00000000 --- a/rog-aura/src/key_to_str.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::keys::Key; - -impl From for &str { - fn from(k: Key) -> Self { - (&k).into() - } -} - -impl From<&Key> for &str { - fn from(k: &Key) -> Self { - match k { - Key::VolUp => "Volume Up", - Key::VolDown => "Volume Down", - Key::MicMute => "Mute Mic", - Key::Rog => "ROG", - Key::Fan => "Fan Control", - Key::Esc => "Escape", - Key::F1 => "F1", - Key::F2 => "F2", - Key::F3 => "F3", - Key::F4 => "F4", - Key::F5 => "F5", - Key::F6 => "F6", - Key::F7 => "F7", - Key::F8 => "F8", - Key::F9 => "F9", - Key::F10 => "F10", - Key::F11 => "F11", - Key::F12 => "F12", - Key::Del => "Delete", - Key::Tilde => "Tilde", - Key::N1 => "1", - Key::N2 => "2", - Key::N3 => "3", - Key::N4 => "4", - Key::N5 => "5", - Key::N6 => "6", - Key::N7 => "7", - Key::N8 => "8", - Key::N9 => "9", - Key::N0 => "0", - Key::Hyphen => "-", - Key::Equals => "=", - Key::BkSpc => "Backspace", - Key::BkSpc3_1 => "Backspace LED 1", - Key::BkSpc3_2 => "Backspace LED 2", - Key::BkSpc3_3 => "Backspace LED 3", - Key::Home => "Home", - Key::Tab => "Tab", - Key::Q => "Q", - Key::W => "W", - Key::E => "E", - Key::R => "R", - Key::T => "T", - Key::Y => "Y", - Key::U => "U", - Key::I => "I", - Key::O => "O", - Key::P => "P", - Key::LBracket => "[", - Key::RBracket => "]", - Key::BackSlash => "\\", - Key::PgUp => "Page Up", - Key::Caps => "Caps Lock", - Key::A => "A", - Key::S => "S", - Key::D => "D", - Key::F => "F", - Key::G => "G", - Key::H => "H", - Key::J => "J", - Key::K => "K", - Key::L => "L", - Key::SemiColon => ";", - Key::Quote => "'", - Key::Return => "Return", - Key::Return3_1 => "Return LED 1", - Key::Return3_2 => "Return LED 2", - Key::Return3_3 => "Return LED 3", - Key::PgDn => "Page Down", - Key::LShift => "Left Shift", - Key::LShift3_1 => "Left Shift LED 1", - Key::LShift3_2 => "Left Shift LED 2", - Key::LShift3_3 => "Left Shift LED 3", - Key::Z => "Z", - Key::X => "X", - Key::C => "C", - Key::V => "V", - Key::B => "B", - Key::N => "N", - Key::M => "M", - Key::Comma => ",", - Key::Period => ".", - Key::Star => "*", - Key::NumPadDel => "Delete", - Key::NumPadPlus => "+", - Key::NumPadEnter => "Enter", - Key::NumPadPause => "Pause", - Key::NumPadPrtSc => "Print Screen", - Key::NumPadHome => "Home", - Key::NumLock => "Num-Lock", - Key::FwdSlash => "/", - Key::Rshift => "Right Shift", - Key::RshiftSmall => "Right Shift", - Key::Rshift3_1 => "Right Shift LED 1", - Key::Rshift3_2 => "Right Shift LED 2", - Key::Rshift3_3 => "Right Shift LED 3", - Key::End => "End", - Key::LCtrl => "Left Control", - Key::LCtrlMed => "Left Control", - Key::LFn => "Left Fn", - Key::Meta => "Meta", - Key::LAlt => "Left Alt", - Key::Space => "Space", - Key::Space5_1 => "Space LED 1", - Key::Space5_2 => "Space LED 2", - Key::Space5_3 => "Space LED 3", - Key::Space5_4 => "Space LED 4", - Key::Space5_5 => "Space LED 5", - Key::RAlt => "Right Alt", - Key::PrtSc => "Print Screen", - Key::RCtrl => "Right Control", - Key::RCtrlLarge => "Right Control", - Key::Pause => "Pause", - Key::Up => "Up", - Key::Down => "Down", - Key::Left => "Left", - Key::Right => "Right", - Key::UpRegular => "Up", - Key::DownRegular => "Down", - Key::LeftRegular => "Left", - Key::RightRegular => "Right", - Key::UpSplit => "Up", - Key::DownSplit => "Down", - Key::LeftSplit => "Left", - Key::RightSplit => "Right", - Key::RFn => "Right Fn", - Key::MediaPlay => "Media Play", - Key::MediaStop => "Media Stop", - Key::MediaNext => "Media Next", - Key::MediaPrev => "Media Previous", - Key::NormalBlank - | Key::NormalSpacer - | Key::FuncBlank - | Key::FuncSpacer - | Key::ArrowBlank - | Key::ArrowSpacer - | Key::ArrowRegularBlank - | Key::ArrowRegularSpacer - | Key::ArrowSplitBlank - | Key::ArrowSplitSpacer - | Key::RowEndSpacer => "", - } - } -} diff --git a/rog-aura/src/keys.rs b/rog-aura/src/keys.rs deleted file mode 100644 index 9e9c97ac..00000000 --- a/rog-aura/src/keys.rs +++ /dev/null @@ -1,358 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Default, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)] -pub enum Key { - VolUp, - VolDown, - MicMute, - #[default] - Rog, - Fan, - Esc, - F1, - F2, - F3, - F4, - F5, - F6, - F7, - F8, - F9, - F10, - F11, - F12, - Del, - Tilde, - N1, - N2, - N3, - N4, - N5, - N6, - N7, - N8, - N9, - N0, - Hyphen, - Equals, - BkSpc, - BkSpc3_1, - BkSpc3_2, - BkSpc3_3, - Home, - Tab, - Q, - W, - E, - R, - T, - Y, - U, - I, - O, - P, - LBracket, - RBracket, - BackSlash, - PgUp, - Caps, - A, - S, - D, - F, - G, - H, - J, - K, - L, - SemiColon, - Quote, - Return, - Return3_1, - Return3_2, - Return3_3, - PgDn, - LShift, - LShift3_1, - LShift3_2, - LShift3_3, - Z, - X, - C, - V, - B, - N, - M, - Comma, - Period, - FwdSlash, - Star, - NumPadDel, - NumPadPlus, - NumPadEnter, - NumPadPause, - NumPadPrtSc, - NumPadHome, - NumLock, - Rshift, - RshiftSmall, - Rshift3_1, - Rshift3_2, - Rshift3_3, - End, - LCtrl, - LCtrlMed, - LFn, - Meta, - LAlt, - Space, - Space5_1, - Space5_2, - Space5_3, - Space5_4, - Space5_5, - Pause, - RAlt, - PrtSc, - RCtrl, - RCtrlLarge, - Up, - Down, - Left, - Right, - UpRegular, - DownRegular, - LeftRegular, - RightRegular, - UpSplit, - DownSplit, - LeftSplit, - RightSplit, - RFn, - MediaPlay, - MediaStop, - MediaNext, - MediaPrev, - NormalBlank, - /// To be ignored by per-key effects - NormalSpacer, - FuncBlank, - /// To be ignored by per-key effects - FuncSpacer, - ArrowBlank, - /// To be ignored by per-key effects - ArrowSpacer, - ArrowRegularBlank, - /// To be ignored by per-key effects - ArrowRegularSpacer, - ArrowSplitBlank, - /// To be ignored by per-key effects - ArrowSplitSpacer, - /// A gap between regular rows and the rightside buttons - RowEndSpacer, -} - -impl Key { - pub fn is_placeholder(&self) -> bool { - let shape = KeyShape::from(self); - shape.is_blank() || shape.is_spacer() - } -} - -/// Types of shapes of LED on keyboards. The shape is used for visual representations -/// -/// A post fix of Spacer *must be ignored by per-key effects -#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize)] -pub enum KeyShape { - Tilde, - #[default] - Normal, - NormalBlank, - NormalSpacer, - Func, - FuncBlank, - FuncSpacer, - Space, - Space5, - LCtrlMed, - LShift, - /// Used in a group of 3 (LED's) - LShift3, - RShift, - RshiftSmall, - /// Used in a group of 3 (LED's) - RShift3, - Return, - Return3, - Tab, - Caps, - Backspace, - /// Used in a group of 3 (LED's) - Backspace3, - Arrow, - ArrowBlank, - ArrowSpacer, - ArrowSplit, - ArrowSplitBlank, - ArrowSplitSpacer, - ArrowRegularBlank, - ArrowRegularSpacer, - RowEndSpacer, -} - -impl KeyShape { - pub const fn width(&self) -> f32 { - match self { - Self::Tilde | Self::Arrow => 0.8, - Self::Normal - | Self::NormalBlank - | Self::NormalSpacer - | Self::Func - | Self::FuncBlank - | Self::Space5 - | Self::ArrowBlank - | Self::ArrowSpacer - | Self::ArrowSplit - | Self::ArrowSplitBlank - | Self::ArrowSplitSpacer => 1.0, - Self::FuncSpacer => 0.6, - Self::Space => 5.0, - Self::LCtrlMed => 1.1, - Self::LShift | Self::Backspace => 2.0, - Self::LShift3 => 0.67, - Self::RShift => 2.8, - Self::RshiftSmall => 1.8, - Self::RShift3 => 0.93, - Self::Return => 2.2, - Self::Return3 => 0.7333, - Self::Tab => 1.4, - Self::Caps => 1.6, - Self::Backspace3 => 0.666, - Self::ArrowRegularBlank | Self::ArrowRegularSpacer => 0.7, - - Self::RowEndSpacer => 0.1, - } - } - - /// A blank is used to space keys out in GUI's and can be used or ignored - /// depednign on the per-key effect - pub const fn is_blank(&self) -> bool { - matches!( - self, - Self::NormalBlank - | Self::FuncBlank - | Self::ArrowBlank - | Self::ArrowSplitBlank - | Self::ArrowRegularBlank - ) - } - - /// A spacer is used to space keys out in GUI's, but ignored in per-key effects - pub const fn is_spacer(&self) -> bool { - matches!( - self, - Self::FuncSpacer - | Self::NormalSpacer - | Self::ArrowSpacer - | Self::ArrowSplitSpacer - | Self::ArrowRegularSpacer - ) - } - - /// All keys with a postfix of some number - pub const fn is_group(&self) -> bool { - matches!( - self, - Self::LShift3 | Self::RShift3 | Self::Return3 | Self::Space5 | Self::Backspace3 - ) - } - - /// Mostly intended as a helper for signalling when to draw a - /// split/compact arrow cluster - pub const fn is_arrow_cluster(&self) -> bool { - matches!(self, Self::Arrow | Self::ArrowBlank | Self::ArrowSpacer) - } - - pub const fn is_arrow_splits(&self) -> bool { - matches!(self, Self::Arrow | Self::ArrowBlank | Self::ArrowSpacer) - } -} - -impl From for KeyShape { - fn from(k: Key) -> Self { - match k { - Key::VolUp - | Key::VolDown - | Key::MicMute - | Key::Rog - | Key::Fan - | Key::Esc - | Key::F1 - | Key::F2 - | Key::F3 - | Key::F4 - | Key::F5 - | Key::F6 - | Key::F7 - | Key::F8 - | Key::F9 - | Key::F10 - | Key::F11 - | Key::F12 - | Key::Del => KeyShape::Func, - Key::Tilde => KeyShape::Tilde, - - Key::BkSpc => KeyShape::Backspace, - Key::BkSpc3_1 | Key::BkSpc3_2 | Key::BkSpc3_3 => KeyShape::Backspace3, - Key::Tab | Key::BackSlash => KeyShape::Tab, - Key::Caps => KeyShape::Caps, - - Key::Return => KeyShape::Return, - Key::Return3_1 | Key::Return3_2 | Key::Return3_3 => KeyShape::Return3, - Key::LCtrlMed => KeyShape::LCtrlMed, - Key::LShift => KeyShape::LShift, - - Key::Rshift | Key::RCtrlLarge => KeyShape::RShift, - Key::RshiftSmall => KeyShape::RshiftSmall, - Key::Rshift3_1 | Key::Rshift3_2 | Key::Rshift3_3 => KeyShape::RShift3, - - Key::Space => KeyShape::Space, - Key::Space5_1 | Key::Space5_2 | Key::Space5_3 | Key::Space5_4 | Key::Space5_5 => { - KeyShape::Space5 - } - - Key::NumPadPause | Key::NumPadPrtSc | Key::NumPadHome | Key::NumPadDel => { - KeyShape::Func - } - - Key::NormalBlank => KeyShape::NormalBlank, - Key::NormalSpacer => KeyShape::NormalSpacer, - - Key::FuncBlank => KeyShape::FuncBlank, - Key::FuncSpacer => KeyShape::FuncSpacer, - - Key::Up | Key::Down | Key::Left | Key::Right => KeyShape::Arrow, - Key::ArrowBlank => KeyShape::ArrowBlank, - Key::ArrowSpacer => KeyShape::ArrowSpacer, - - Key::ArrowRegularBlank => KeyShape::ArrowRegularBlank, - Key::ArrowRegularSpacer => KeyShape::ArrowRegularSpacer, - - Key::UpSplit | Key::LeftSplit | Key::DownSplit | Key::RightSplit => { - KeyShape::ArrowSplit - } - Key::ArrowSplitBlank => KeyShape::ArrowSplitBlank, - Key::ArrowSplitSpacer => KeyShape::ArrowSplitSpacer, - - Key::RowEndSpacer => KeyShape::RowEndSpacer, - - _ => KeyShape::Normal, - } - } -} - -impl From<&Key> for KeyShape { - fn from(k: &Key) -> Self { - (*k).into() - } -} diff --git a/rog-aura/src/layouts.rs b/rog-aura/src/layouts.rs new file mode 100644 index 00000000..dfd0ed14 --- /dev/null +++ b/rog-aura/src/layouts.rs @@ -0,0 +1,554 @@ +//! A series of pre-defined layouts. These were mostly used to generate an +//! editable config. + +use std::collections::{HashMap, HashSet}; +use std::fs::{self, OpenOptions}; +use std::io::Read; +use std::path::{Path, PathBuf}; +use std::slice::Iter; + +use log::warn; +use serde::{Deserialize, Serialize}; + +use crate::advanced::LedCode; +use crate::aura_detection::LaptopLedData; +use crate::error::Error; +use crate::{AdvancedAuraType, AuraModeNum, AuraZone}; + +/// The `key_type` plays a role in effects (eventually). You could for example +/// add a `ShapeType::Spacing` to pad out an effect, such as a laserbeam across +/// a row so that it doesn't appear to *jump* across a gap +/// +/// w=1.0, h=1.0 should be considered the size of a typical key like 'A' +#[derive(Debug, Deserialize, Serialize, Clone)] +pub enum KeyShape { + Led { + width: f32, + height: f32, + pad_left: f32, + pad_right: f32, + pad_top: f32, + pad_bottom: f32, + }, + Blank { + width: f32, + height: f32, + }, +} + +impl KeyShape { + pub fn new_led( + width: f32, + height: f32, + pad_left: f32, + pad_right: f32, + pad_top: f32, + pad_bottom: f32, + ) -> Self { + Self::Led { + width, + height, + pad_left, + pad_right, + pad_top, + pad_bottom, + } + } + + pub fn new_blank(width: f32, height: f32) -> Self { + Self::Blank { width, height } + } + + /// Scale the shape up/down. Intended for use in UI on a clone + pub fn scale(&mut self, scale: f32) { + match self { + KeyShape::Led { + width, + height, + pad_left, + pad_right, + pad_top, + pad_bottom, + } => { + *width *= scale; + *height *= scale; + *pad_left *= scale; + *pad_right *= scale; + *pad_top *= scale; + *pad_bottom *= scale; + } + KeyShape::Blank { width, height } => { + *width *= scale; + *height *= scale; + } + } + } +} + +/// The first `Key` will determine the row height. +/// +/// Every row is considered to start a x=0, with the first row being y=0, +/// and following rows starting after the previous row_y+pad_top and +/// row_x+pad_left +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct KeyRow { + pad_left: f32, + pad_top: f32, + /// The `Key` is what provides an RGB index location in the final USB + /// packets + row: Vec<(LedCode, String)>, + /// The final data structure merged key_shapes and rows + #[serde(skip)] + built_row: Vec<(LedCode, KeyShape)>, +} + +impl KeyRow { + pub fn new(pad_left: f32, pad_top: f32, row: Vec<(LedCode, String)>) -> Self { + Self { + pad_left, + pad_top, + row, + built_row: Default::default(), + } + } + + pub fn row(&self) -> Iter<'_, (LedCode, KeyShape)> { + self.built_row.iter() + } + + pub fn row_ref(&self) -> &[(LedCode, KeyShape)] { + &self.built_row + } + + /// Find and return the heightest height of this row + pub fn height(&self) -> f32 { + if self.built_row.is_empty() { + return 0.0; + } + let mut h = 0.0; + for k in &self.built_row { + let height = match &k.1 { + KeyShape::Led { + height, + pad_top, + pad_bottom, + .. + } => height + pad_top + pad_bottom, + KeyShape::Blank { height, .. } => *height, + }; + + if h < height { + h = height + } + } + h + } + + /// Return the total row width + pub fn width(&self) -> f32 { + if self.built_row.is_empty() { + return 0.0; + } + let mut w = 0.0; + for k in &self.built_row { + match &k.1 { + KeyShape::Led { + width, + pad_left, + pad_right, + .. + } => w += width + pad_left + pad_right, + KeyShape::Blank { width, .. } => w += width, + } + } + w + } +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct KeyLayout { + /// Localization of this keyboard layout + locale: String, + /// The shapes of keys used + key_shapes: HashMap, + /// The rows of keys of this layout + key_rows: Vec, + /// Should be copied from the `LaptopLedData` as laptops may have the same + /// layout, but different EC features + #[serde(skip)] + basic_modes: Vec, + /// Should be copied from the `LaptopLedData` as laptops may have the same + /// layout, but different EC features + #[serde(skip)] + basic_zones: Vec, + /// Paired with the key selection in UI. Determines if individual keys are + /// selectable, zones, or single zone. + /// + /// Should be copied from the `LaptopLedData` as laptops may have the same + /// layout, but different EC features. + #[serde(skip)] + advanced_type: AdvancedAuraType, +} + +impl KeyLayout { + pub fn from_file(path: &Path) -> Result { + let mut file = OpenOptions::new() + .read(true) + .open(path) + .map_err(|e| Error::IoPath(path.to_string_lossy().to_string(), e))?; + let mut buf = String::new(); + let read_len = file + .read_to_string(&mut buf) + .map_err(|e| Error::IoPath(path.to_string_lossy().to_string(), e))?; + if read_len == 0 { + Err(Error::IoPath( + path.to_string_lossy().to_string(), + std::io::ErrorKind::InvalidData.into(), + )) + } else { + let mut data = ron::from_str::(&buf)?; + + let mut unused = HashSet::new(); + for k in data.key_shapes.keys() { + unused.insert(k); + } + + let rows = &mut data.key_rows; + for row in rows { + for k in &mut row.row { + if let Some(shape) = data.key_shapes.get(&k.1) { + row.built_row.push((k.0, shape.clone())); + unused.remove(&k.1); + } else { + warn!("Key {:?} was missing matching shape {}", k.0, k.1); + } + } + } + + if !unused.is_empty() { + warn!("The layout {path:?} had unused shapes {unused:?}",); + } + + Ok(data) + } + } + + pub fn rows(&self) -> Iter { + self.key_rows.iter() + } + + pub fn rows_ref(&self) -> &[KeyRow] { + &self.key_rows + } + + pub fn basic_modes(&self) -> &[AuraModeNum] { + &self.basic_modes + } + + pub fn basic_zones(&self) -> &[AuraZone] { + &self.basic_zones + } + + pub fn advanced_type(&self) -> &AdvancedAuraType { + &self.advanced_type + } + + pub fn max_height(&self) -> f32 { + let mut height = 0.0; + for r in &self.key_rows { + height += r.height(); + } + height + } + + pub fn max_width(&self) -> f32 { + let mut width = 0.0; + for r in &self.key_rows { + let tmp = r.width(); + if width < tmp { + width = tmp + } + } + width + } + + /// Find a layout matching the name in `LaptopLedData` in the provided dir + pub fn find_layout(led_data: LaptopLedData, mut data_path: PathBuf) -> Result { + // TODO: locales + let layout_file = format!("{}_US.ron", led_data.layout_name); + data_path.push("layouts"); + data_path.push(layout_file); + let path = data_path.as_path(); + + let mut tmp = KeyLayout::from_file(path)?; + tmp.basic_modes = led_data.basic_modes; + tmp.basic_zones = led_data.basic_zones; + tmp.advanced_type = led_data.advanced_type; + + Ok(tmp) + } + + pub fn layout_files(mut data_path: PathBuf) -> Result, Error> { + data_path.push("layouts"); + let path = data_path.as_path(); + let mut files = Vec::new(); + fs::read_dir(path) + .map_err(|e| { + println!("{:?}, {e}", path); + e + }) + .unwrap() + .for_each(|p| { + if let Ok(p) = p { + files.push(p.path()); + } + }); + + Ok(files) + } +} + +impl KeyLayout { + pub fn default_layout() -> Self { + Self { + locale: "US".to_owned(), + basic_modes: vec![ + AuraModeNum::Static, + AuraModeNum::Breathe, + AuraModeNum::Pulse, + ], + basic_zones: vec![AuraZone::None], + advanced_type: AdvancedAuraType::None, + key_shapes: HashMap::from([( + "regular".to_owned(), + KeyShape::new_led(1.0, 1.0, 0.1, 0.1, 0.1, 0.1), + )]), + key_rows: vec![ + KeyRow::new( + 0.1, + 0.1, + vec![ + (LedCode::Esc, "regular".to_owned()), + (LedCode::F1, "regular".to_owned()), + (LedCode::F2, "regular".to_owned()), + (LedCode::F3, "regular".to_owned()), + (LedCode::F4, "regular".to_owned()), + // not sure which key to put here + (LedCode::F5, "regular".to_owned()), + (LedCode::F6, "regular".to_owned()), + (LedCode::F7, "regular".to_owned()), + (LedCode::F8, "regular".to_owned()), + (LedCode::F9, "regular".to_owned()), + (LedCode::F10, "regular".to_owned()), + (LedCode::F11, "regular".to_owned()), + (LedCode::F12, "regular".to_owned()), + ], + ), + KeyRow::new( + 0.1, + 0.1, + vec![ + (LedCode::Tilde, "regular".to_owned()), + (LedCode::N1, "regular".to_owned()), + (LedCode::N2, "regular".to_owned()), + (LedCode::N3, "regular".to_owned()), + (LedCode::N4, "regular".to_owned()), + (LedCode::N5, "regular".to_owned()), + (LedCode::N6, "regular".to_owned()), + (LedCode::N7, "regular".to_owned()), + (LedCode::N8, "regular".to_owned()), + (LedCode::N9, "regular".to_owned()), + (LedCode::N0, "regular".to_owned()), + (LedCode::Hyphen, "regular".to_owned()), + (LedCode::Equals, "regular".to_owned()), + (LedCode::Backspace, "regular".to_owned()), + ], + ), + KeyRow::new( + 0.1, + 0.1, + vec![ + (LedCode::Tab, "regular".to_owned()), + (LedCode::Q, "regular".to_owned()), + (LedCode::W, "regular".to_owned()), + (LedCode::E, "regular".to_owned()), + (LedCode::R, "regular".to_owned()), + (LedCode::T, "regular".to_owned()), + (LedCode::Y, "regular".to_owned()), + (LedCode::U, "regular".to_owned()), + (LedCode::I, "regular".to_owned()), + (LedCode::O, "regular".to_owned()), + (LedCode::P, "regular".to_owned()), + (LedCode::LBracket, "regular".to_owned()), + (LedCode::RBracket, "regular".to_owned()), + (LedCode::BackSlash, "regular".to_owned()), + ], + ), + KeyRow::new( + 0.1, + 0.1, + vec![ + (LedCode::Caps, "regular".to_owned()), + (LedCode::A, "regular".to_owned()), + (LedCode::S, "regular".to_owned()), + (LedCode::D, "regular".to_owned()), + (LedCode::F, "regular".to_owned()), + (LedCode::G, "regular".to_owned()), + (LedCode::H, "regular".to_owned()), + (LedCode::J, "regular".to_owned()), + (LedCode::K, "regular".to_owned()), + (LedCode::L, "regular".to_owned()), + (LedCode::SemiColon, "regular".to_owned()), + (LedCode::Quote, "regular".to_owned()), + (LedCode::Return, "regular".to_owned()), + ], + ), + KeyRow::new( + 0.1, + 0.1, + vec![ + (LedCode::LShift, "regular".to_owned()), + (LedCode::Z, "regular".to_owned()), + (LedCode::X, "regular".to_owned()), + (LedCode::C, "regular".to_owned()), + (LedCode::V, "regular".to_owned()), + (LedCode::B, "regular".to_owned()), + (LedCode::N, "regular".to_owned()), + (LedCode::M, "regular".to_owned()), + (LedCode::Comma, "regular".to_owned()), + (LedCode::Period, "regular".to_owned()), + (LedCode::FwdSlash, "regular".to_owned()), + (LedCode::Rshift, "regular".to_owned()), + ], + ), + KeyRow::new( + 0.1, + 0.1, + vec![ + (LedCode::LCtrl, "regular".to_owned()), + (LedCode::LFn, "regular".to_owned()), + (LedCode::Meta, "regular".to_owned()), + (LedCode::LAlt, "regular".to_owned()), + (LedCode::Spacebar, "regular".to_owned()), + (LedCode::RAlt, "regular".to_owned()), + (LedCode::PrtSc, "regular".to_owned()), + (LedCode::RCtrl, "regular".to_owned()), + ], + ), + ], + } + } +} + +#[cfg(test)] +mod tests { + use std::collections::HashSet; + use std::fs::{self, OpenOptions}; + use std::io::Read; + use std::path::PathBuf; + + use crate::aura_detection::LedSupportFile; + use crate::layouts::KeyLayout; + + #[test] + fn check_parse_all() { + const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR"); + let mut data_path = PathBuf::from(DATA_DIR); + + data_path.push("data"); + data_path.push("layouts"); + let path = data_path.as_path(); + let mut buf = String::new(); + for p in fs::read_dir(path) + .map_err(|e| { + println!("{:?}, {e}", path); + e + }) + .unwrap() + { + let path = p.unwrap().path(); + let mut file = OpenOptions::new().read(true).open(&path).unwrap(); + file.read_to_string(&mut buf).unwrap(); + + let data: KeyLayout = ron::from_str(&buf).unwrap(); + + let mut unused = HashSet::new(); + for k in data.key_shapes.keys() { + unused.insert(k); + } + + let rows = &data.key_rows; + for row in rows { + for k in &row.row { + if data.key_shapes.get(&k.1).is_some() { + unused.remove(&k.1); + } else { + panic!("Key {:?} was missing matching shape {}", k.0, k.1); + } + } + } + + if !unused.is_empty() { + panic!("The layout {path:?} had unused shapes {unused:?}",); + } + buf.clear(); + } + + // println!( + // "RON: {}", + // ron::ser::to_string_pretty(&tmp, + // PrettyConfig::new().depth_limit(4)).unwrap() ); + + // let mut data = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // data.push("data/aura-support2.json"); + + // let mut file = + // OpenOptions::new().write(true).create(true).truncate(true).open(& + // data).unwrap(); file.write_all(json.as_bytes()).unwrap(); + } + + #[test] + fn check_layout_file_links() { + const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR"); + let mut data_path = PathBuf::from(DATA_DIR); + data_path.push("data"); + data_path.push("aura_support.ron"); + + let mut buf = String::new(); + let mut file = OpenOptions::new().read(true).open(&data_path).unwrap(); + file.read_to_string(&mut buf).unwrap(); + let data: LedSupportFile = ron::from_str(&buf).unwrap(); + + data_path.pop(); + data_path.push("layouts"); + data_path.push("loop_prep"); + + for config in data.get().iter().rev() { + buf.clear(); + + let layout_file = format!("{}_US.ron", config.layout_name); + data_path.pop(); + data_path.push(&layout_file); + + let mut file = OpenOptions::new() + .read(true) + .open(&data_path) + .map_err(|e| { + panic!( + "Error checking {data_path:?} for {} : {e:?}", + config.board_name + ) + }) + .unwrap(); + if let Err(e) = file.read_to_string(&mut buf) { + panic!( + "Error checking {data_path:?} for {} : {e:?}", + config.board_name + ) + } + if let Err(e) = ron::from_str::(&buf) { + panic!("Error checking {data_path:?} : {e:?}") + } + } + } +} diff --git a/rog-aura/src/layouts/g513.rs b/rog-aura/src/layouts/g513.rs deleted file mode 100644 index bb347b08..00000000 --- a/rog-aura/src/layouts/g513.rs +++ /dev/null @@ -1,170 +0,0 @@ -use super::{KeyLayout, KeyRow}; -use crate::keys::Key; - -impl KeyLayout { - /// Similar to GX502, but not per-key enabled - pub fn g513_layout() -> Self { - Self { - matches: vec!["G513".into()], - locale: "US".to_owned(), - rows: vec![ - KeyRow::new( - 0.8, - vec![ - Key::NormalSpacer, - Key::FuncSpacer, - Key::VolDown, - Key::VolUp, - Key::MicMute, - Key::Fan, - Key::Rog, - ], - ), - KeyRow::new( - 0.8, - vec![ - Key::Esc, - Key::FuncSpacer, - Key::F1, - Key::F2, - Key::F3, - Key::F4, - Key::FuncSpacer, // not sure which key to put here - Key::F5, - Key::F6, - Key::F7, - Key::F8, - Key::FuncSpacer, - Key::F9, - Key::F10, - Key::F11, - Key::F12, - Key::RowEndSpacer, - Key::Del, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Tilde, - Key::N1, - Key::N2, - Key::N3, - Key::N4, - Key::N5, - Key::N6, - Key::N7, - Key::N8, - Key::N9, - Key::N0, - Key::Hyphen, - Key::Equals, - Key::BkSpc, - Key::RowEndSpacer, - Key::Home, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Tab, - Key::Q, - Key::W, - Key::E, - Key::R, - Key::T, - Key::Y, - Key::U, - Key::I, - Key::O, - Key::P, - Key::LBracket, - Key::RBracket, - Key::BackSlash, - Key::RowEndSpacer, - Key::PgUp, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Caps, - Key::A, - Key::S, - Key::D, - Key::F, - Key::G, - Key::H, - Key::J, - Key::K, - Key::L, - Key::SemiColon, - Key::Quote, - Key::Return, - Key::RowEndSpacer, - Key::PgDn, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::LShift, - Key::Z, - Key::X, - Key::C, - Key::V, - Key::B, - Key::N, - Key::M, - Key::Comma, - Key::Period, - Key::FwdSlash, - Key::Rshift, - Key::RowEndSpacer, - Key::End, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::LCtrl, - Key::LFn, - Key::Meta, - Key::LAlt, - Key::Space, - Key::RAlt, - Key::PrtSc, - Key::RCtrl, - Key::ArrowSpacer, - Key::Up, - Key::ArrowSpacer, - Key::RowEndSpacer, - Key::RFn, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::Left, - Key::Down, - Key::Right, - Key::ArrowSpacer, - ], - ), - ], - } - } -} diff --git a/rog-aura/src/layouts/ga401.rs b/rog-aura/src/layouts/ga401.rs deleted file mode 100644 index f44556aa..00000000 --- a/rog-aura/src/layouts/ga401.rs +++ /dev/null @@ -1,156 +0,0 @@ -use super::{KeyLayout, KeyRow}; -use crate::keys::Key; - -impl KeyLayout { - pub fn ga401_layout() -> Self { - Self { - matches: vec!["GA401".into(), "GA402".into()], - locale: "US".to_owned(), - rows: vec![ - KeyRow::new( - 0.8, - vec![ - Key::NormalSpacer, - Key::FuncSpacer, - Key::VolDown, - Key::VolUp, - Key::MicMute, - Key::Rog, - ], - ), - KeyRow::new( - 0.8, - vec![ - Key::Esc, - Key::FuncSpacer, - Key::F1, - Key::F2, - Key::F3, - Key::F4, - Key::FuncSpacer, // not sure which key to put here - Key::F5, - Key::F6, - Key::F7, - Key::F8, - Key::FuncSpacer, - Key::F9, - Key::F10, - Key::F11, - Key::F12, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Tilde, - Key::N1, - Key::N2, - Key::N3, - Key::N4, - Key::N5, - Key::N6, - Key::N7, - Key::N8, - Key::N9, - Key::N0, - Key::Hyphen, - Key::Equals, - Key::BkSpc, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Tab, - Key::Q, - Key::W, - Key::E, - Key::R, - Key::T, - Key::Y, - Key::U, - Key::I, - Key::O, - Key::P, - Key::LBracket, - Key::RBracket, - Key::BackSlash, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Caps, - Key::A, - Key::S, - Key::D, - Key::F, - Key::G, - Key::H, - Key::J, - Key::K, - Key::L, - Key::SemiColon, - Key::Quote, - Key::Return, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::LShift, - Key::Z, - Key::X, - Key::C, - Key::V, - Key::B, - Key::N, - Key::M, - Key::Comma, - Key::Period, - Key::FwdSlash, - Key::Rshift, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::LCtrl, - Key::LFn, - Key::Meta, - Key::LAlt, - Key::Space, - Key::RAlt, - Key::PrtSc, - Key::RCtrl, - Key::ArrowSpacer, - Key::Up, - Key::ArrowSpacer, - ], - ), - KeyRow::new( - 1.2, - vec![ - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::Left, - Key::Down, - Key::Right, - Key::ArrowSpacer, - ], - ), - ], - } - } -} diff --git a/rog-aura/src/layouts/gx502.rs b/rog-aura/src/layouts/gx502.rs deleted file mode 100644 index 5b7fce6b..00000000 --- a/rog-aura/src/layouts/gx502.rs +++ /dev/null @@ -1,178 +0,0 @@ -use super::{KeyLayout, KeyRow}; -use crate::keys::Key; - -impl KeyLayout { - pub fn gx502_layout() -> Self { - Self { - matches: vec!["GX502".into(), "GU502".into()], - locale: "US".to_owned(), - rows: vec![ - KeyRow::new( - 0.8, - vec![ - Key::NormalSpacer, - Key::FuncSpacer, - Key::VolDown, - Key::VolUp, - Key::MicMute, - Key::Rog, - ], - ), - KeyRow::new( - 0.8, - vec![ - Key::Esc, - Key::FuncSpacer, - Key::F1, - Key::F2, - Key::F3, - Key::F4, - Key::FuncSpacer, // not sure which key to put here - Key::F5, - Key::F6, - Key::F7, - Key::F8, - Key::FuncSpacer, - Key::F9, - Key::F10, - Key::F11, - Key::F12, - Key::RowEndSpacer, - Key::Del, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Tilde, - Key::N1, - Key::N2, - Key::N3, - Key::N4, - Key::N5, - Key::N6, - Key::N7, - Key::N8, - Key::N9, - Key::N0, - Key::Hyphen, - Key::Equals, - Key::BkSpc3_1, - Key::BkSpc3_2, - Key::BkSpc3_3, - Key::RowEndSpacer, - Key::Home, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Tab, - Key::Q, - Key::W, - Key::E, - Key::R, - Key::T, - Key::Y, - Key::U, - Key::I, - Key::O, - Key::P, - Key::LBracket, - Key::RBracket, - Key::BackSlash, - Key::RowEndSpacer, - Key::PgUp, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::Caps, - Key::A, - Key::S, - Key::D, - Key::F, - Key::G, - Key::H, - Key::J, - Key::K, - Key::L, - Key::SemiColon, - Key::Quote, - Key::Return3_1, - Key::Return3_2, - Key::Return3_3, - Key::RowEndSpacer, - Key::PgDn, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::LShift, - Key::Z, - Key::X, - Key::C, - Key::V, - Key::B, - Key::N, - Key::M, - Key::Comma, - Key::Period, - Key::FwdSlash, - Key::Rshift3_1, - Key::Rshift3_2, - Key::Rshift3_3, - Key::RowEndSpacer, - Key::End, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::LCtrl, - Key::LFn, - Key::Meta, - Key::LAlt, - Key::Space5_1, - Key::Space5_2, - Key::Space5_3, - Key::Space5_4, - Key::Space5_5, - Key::RAlt, - Key::PrtSc, - Key::RCtrl, - Key::ArrowSpacer, - Key::Up, - Key::ArrowSpacer, - Key::RowEndSpacer, - Key::RFn, - ], - ), - KeyRow::new( - 1.0, - vec![ - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::ArrowSpacer, - Key::Left, - Key::Down, - Key::Right, - Key::ArrowSpacer, - ], - ), - ], - } - } -} diff --git a/rog-aura/src/layouts/mod.rs b/rog-aura/src/layouts/mod.rs deleted file mode 100644 index f25656da..00000000 --- a/rog-aura/src/layouts/mod.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! A series of pre-defined layouts. These were mostly used to generate an editable -//! config. - -/// Hardcoded layout. Was used to generate a toml default -pub mod g513; -/// Hardcoded layout. Was used to generate a toml default -pub mod ga401; -/// Hardcoded layout. Was used to generate a toml default -pub mod gx502; - -use crate::{error::Error, keys::Key}; -use serde::{Deserialize, Serialize}; -use std::{ - fs::{self, OpenOptions}, - io::Read, - path::{Path, PathBuf}, - slice::Iter, -}; - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct KeyLayout { - /// A series of board names that this layout can be used for. The board names - /// stored with the layout can be globbed, e.g, GA401 will match all of the - /// GA401I and GA401Q range variants. - /// - /// `/sys/class/dmi/id/board_name` - matches: Vec, - locale: String, - rows: Vec, -} - -impl KeyLayout { - pub fn from_file(path: &Path) -> Result { - let mut file = OpenOptions::new().read(true).open(path)?; - let mut buf = String::new(); - let read_len = file.read_to_string(&mut buf)?; - if read_len == 0 { - Err(Error::Io(std::io::ErrorKind::InvalidData.into())) - } else { - Ok(toml::from_str::(&buf)?) - } - } - - pub fn matches(&self, board_name: &str) -> bool { - let board = board_name.to_ascii_uppercase(); - for tmp in &self.matches { - if board.contains(tmp.as_str()) { - return true; - } - } - false - } - - pub fn rows(&self) -> Iter { - self.rows.iter() - } - - pub fn rows_ref(&self) -> &[KeyRow] { - &self.rows - } - - /// Find a layout matching the provided board name in the provided dir - pub fn find_layout(board_name: &str, mut data_path: PathBuf) -> Result { - let mut layout = KeyLayout::ga401_layout(); // default - - data_path.push("layouts"); - let path = data_path.as_path(); - for p in fs::read_dir(path).map_err(|e| { - println!("{:?}, {e}", path); - e - })? { - let tmp = KeyLayout::from_file(&p?.path()).unwrap(); - if tmp.matches(board_name) { - layout = tmp; - break; - } - } - - Ok(layout) - } -} - -#[derive(Debug, Deserialize, Serialize, Clone)] -pub struct KeyRow { - height: f32, - row: Vec, -} - -impl KeyRow { - pub fn new(height: f32, row: Vec) -> Self { - Self { height, row } - } - - pub fn row(&self) -> Iter<'_, Key> { - self.row.iter() - } - - pub fn row_ref(&self) -> &[Key] { - &self.row - } - - pub fn height(&self) -> f32 { - self.height - } -} diff --git a/rog-aura/src/layouts/old_gx502.rs b/rog-aura/src/layouts/old_gx502.rs deleted file mode 100644 index c142a1b1..00000000 --- a/rog-aura/src/layouts/old_gx502.rs +++ /dev/null @@ -1,168 +0,0 @@ - -#[allow(clippy::upper_case_acronyms)] -pub struct GX502Layout(Vec<[Key; 17]>); - -impl KeyLayout for GX502Layout { - fn get_rows(&self) -> &Vec<[Key; 17]> { - &self.0 - } -} - -impl Default for GX502Layout { - fn default() -> Self { - GX502Layout(vec![ - [ - Key::NormalSpacer, - Key::FuncSpacer, - Key::VolDown, - Key::VolUp, - Key::MicMute, - Key::Rog, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - ], - [ - Key::Esc, - Key::NormalBlank, - Key::F1, - Key::F2, - Key::F3, - Key::F4, - Key::NormalBlank, // not sure which key to put here - Key::F5, - Key::F6, - Key::F7, - Key::F8, - Key::NormalBlank, - Key::F9, - Key::F10, - Key::F11, - Key::F12, - Key::Del, - ], - [ - Key::Tilde, - Key::N1, - Key::N2, - Key::N3, - Key::N4, - Key::N5, - Key::N6, - Key::N7, - Key::N8, - Key::N9, - Key::N0, - Key::Hyphen, - Key::Equals, - Key::BkSpc3_1, - Key::BkSpc3_2, - Key::BkSpc3_3, - Key::Home, - ], - [ - Key::Tab, - Key::Q, - Key::W, - Key::E, - Key::R, - Key::T, - Key::Y, - Key::U, - Key::I, - Key::O, - Key::P, - Key::LBracket, - Key::RBracket, - Key::BackSlash, - Key::BackSlash, - Key::BackSlash, - Key::PgUp, - ], - [ - Key::Caps, - Key::A, - Key::S, - Key::D, - Key::F, - Key::G, - Key::H, - Key::J, - Key::K, - Key::L, - Key::SemiColon, - Key::Quote, - Key::Quote, - Key::Return3_1, - Key::Return3_2, - Key::Return3_3, - Key::PgDn, - ], - [ - Key::LShift, - Key::LShift, - Key::Z, - Key::X, - Key::C, - Key::V, - Key::B, - Key::N, - Key::M, - Key::Comma, - Key::Period, - Key::FwdSlash, - Key::FwdSlash, - Key::Rshift3_1, - Key::Rshift3_2, - Key::Rshift3_3, - Key::End, - ], - [ - Key::LCtrl, - Key::LFn, - Key::Meta, - Key::LAlt, - Key::Space5_1, - Key::Space5_2, - Key::Space5_3, - Key::Space5_4, - Key::Space5_5, - Key::RAlt, - Key::PrtSc, - Key::RCtrl, - Key::RCtrl, - Key::Left, - Key::Up, - Key::Right, - Key::RFn, - ], - [ - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::NormalBlank, - Key::Left, - Key::Down, - Key::Right, - Key::NormalBlank, - ], - ]) - } -} \ No newline at end of file diff --git a/rog-aura/src/lib.rs b/rog-aura/src/lib.rs index bc9e530c..232662cd 100644 --- a/rog-aura/src/lib.rs +++ b/rog-aura/src/lib.rs @@ -1,21 +1,20 @@ -/// A container of images/grids/gifs/pauses which can be iterated over to generate -/// cool effects -mod sequencer; -pub use sequencer::*; - mod builtin_modes; +use advanced::LedCode; pub use builtin_modes::*; -mod per_key_rgb; -pub use per_key_rgb::*; - -mod per_zone; -pub use per_zone::*; +/// A container of images/grids/gifs/pauses which can be iterated over to +/// generate cool effects +pub mod effects; +/// All handling for `RgbAddress`ing. +pub mod advanced; +/// Convert the `RgbAddress` to `&str` labels +pub mod advanced_to_str; pub mod error; -pub mod key_to_str; -pub mod keys; -pub use key_to_str::*; +pub use advanced_to_str::*; +/// Helper for detecting what is available +pub mod aura_detection; +/// Helpers for consructing keyboard layouts for UI use and effects pub mod layouts; pub mod usb; @@ -25,8 +24,18 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); pub const RED: Colour = Colour(0xff, 0x00, 0x00); pub const GREEN: Colour = Colour(0x00, 0xff, 0x00); pub const BLUE: Colour = Colour(0x00, 0x00, 0xff); -pub const VIOLET: Colour = Colour(0x9B, 0x26, 0xB6); -pub const TEAL: Colour = Colour(0x00, 0x7C, 0x80); +pub const VIOLET: Colour = Colour(0x9b, 0x26, 0xb6); +pub const TEAL: Colour = Colour(0x00, 0x7c, 0x80); pub const YELLOW: Colour = Colour(0xff, 0xef, 0x00); pub const ORANGE: Colour = Colour(0xff, 0xa4, 0x00); pub const GRADIENT: [Colour; 7] = [RED, VIOLET, BLUE, TEAL, GREEN, YELLOW, ORANGE]; + +#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Deserialize, serde::Serialize)] +pub enum AdvancedAuraType { + /// A `None` will apply the effect to the whole keyboard via basic-static + /// mode + #[default] + None, + Zoned(Vec), + PerKey, +} diff --git a/rog-aura/src/per_key_rgb.rs b/rog-aura/src/per_key_rgb.rs deleted file mode 100644 index 7ea76678..00000000 --- a/rog-aura/src/per_key_rgb.rs +++ /dev/null @@ -1,247 +0,0 @@ -use crate::keys::Key; -use serde_derive::{Deserialize, Serialize}; -#[cfg(feature = "dbus")] -use zbus::zvariant::Type; - -/// Represents the per-key raw USB packets -pub type PerKeyRaw = Vec>; - -/// A `KeyColourArray` contains all data to change the full set of keyboard -/// key colours individually. -/// -/// Each row of the internal array is a full HID packet that can be sent -/// to the keyboard EC. One row controls one group of keys, these keys are not -/// necessarily all on the same row of the keyboard, with some splitting between -/// two rows. -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct KeyColourArray(PerKeyRaw); - -impl Default for KeyColourArray { - fn default() -> Self { - Self::new() - } -} - -impl KeyColourArray { - pub fn new() -> Self { - let mut set = vec![vec![0u8; 64]; 11]; - // set[0].copy_from_slice(&KeyColourArray::get_init_msg()); - for (count, row) in set.iter_mut().enumerate() { - row[0] = 0x5d; // Report ID - row[1] = 0xbc; // Mode = custom??, 0xb3 is builtin - row[2] = 0x00; - row[3] = 0x01; // ?? - row[4] = 0x01; // ??, 4,5,6 are normally RGB for builtin mode colours - row[5] = 0x01; // ?? - row[6] = (count as u8) << 4; // Key group - if count == 10 { - row[7] = 0x08; // 0b00001000 - } else { - row[7] = 0x10; // 0b00010000 addressing? flips for group a0 - } - row[8] = 0x00; - } - KeyColourArray(set) - } - - /// Initialise and clear the keyboard for custom effects, this must be done for - /// every time mode switches from builtin to custom - #[inline] - pub const fn get_init_msg() -> [u8; 64] { - let mut init = [0u8; 64]; - init[0] = 0x5d; // Report ID - init[1] = 0xbc; // Mode = custom??, 0xb3 is builtin - init - } - - #[inline] - pub fn set(&mut self, key: Key, r: u8, g: u8, b: u8) { - if let Some(c) = self.rgb_for_key(key) { - c[0] = r; - c[1] = g; - c[2] = b; - } - } - - /// Indexes in to `KeyColourArray` at the correct row and column - /// to set a series of three bytes to the chosen R,G,B values - pub fn rgb_for_key(&mut self, key: Key) -> Option<&mut [u8]> { - // Tuples are indexes in to array - let (row, col) = match key { - Key::VolDown => (0, 15), - Key::VolUp => (0, 18), - Key::MicMute => (0, 21), - Key::Rog => (0, 24), - // - Key::Esc => (1, 24), - Key::F1 => (1, 30), - Key::F2 => (1, 33), - Key::F3 => (1, 36), - Key::F4 => (1, 39), - Key::F5 => (1, 45), - Key::F6 => (1, 48), - Key::F7 => (1, 51), - Key::F8 => (1, 54), - // - Key::F9 => (2, 12), - Key::F10 => (2, 15), - Key::F11 => (2, 18), - Key::F12 => (2, 21), - Key::Del => (2, 24), - Key::Tilde => (2, 39), - Key::N1 => (2, 42), - Key::N2 => (2, 45), - Key::N3 => (2, 48), - Key::N4 => (2, 51), - Key::N5 => (2, 54), - // - Key::N6 => (3, 9), - Key::N7 => (3, 12), - Key::N8 => (3, 15), - Key::N9 => (3, 18), - Key::N0 => (3, 21), - Key::Hyphen => (3, 24), - Key::Equals => (3, 27), - Key::BkSpc3_1 => (3, 30), - Key::BkSpc3_2 => (3, 33), - Key::BkSpc3_3 => (3, 36), - Key::Home => (3, 39), - Key::Tab => (3, 54), - // - Key::Q => (4, 9), - Key::W => (4, 12), - Key::E => (4, 15), - Key::R => (4, 18), - Key::T => (4, 21), - Key::Y => (4, 24), - Key::U => (4, 27), - Key::I => (4, 30), - Key::O => (4, 33), - Key::P => (4, 36), - Key::LBracket => (4, 39), - Key::RBracket => (4, 42), - Key::BackSlash => (4, 45), - Key::PgUp => (4, 54), - // - Key::Caps => (5, 21), - Key::A => (5, 24), - Key::S => (5, 27), - Key::D => (5, 30), - Key::F => (5, 33), - Key::G => (5, 36), - Key::H => (5, 39), - Key::J => (5, 42), - Key::K => (5, 45), - Key::L => (5, 48), - Key::SemiColon => (5, 51), - Key::Quote => (5, 54), - // - Key::Return => (6, 9), - Key::Return3_1 => (6, 12), - Key::Return3_2 => (6, 15), - Key::Return3_3 => (6, 18), - Key::PgDn => (6, 21), - Key::LShift => (6, 36), - // TODO: Find correct locations - Key::LShift3_1 => (6, 36), - Key::LShift3_2 => (6, 36), - Key::LShift3_3 => (6, 36), - Key::Z => (6, 42), - Key::X => (6, 45), - Key::C => (6, 48), - Key::V => (6, 51), - Key::B => (6, 54), - // - Key::N => (7, 9), - Key::M => (7, 12), - Key::Comma => (7, 15), - Key::Period => (7, 18), - Key::FwdSlash => (7, 21), - Key::Rshift => (7, 24), - Key::Rshift3_1 => (7, 27), - Key::Rshift3_2 => (7, 30), - Key::Rshift3_3 => (7, 33), - Key::End => (7, 36), - Key::LCtrl => (7, 51), - Key::LFn => (7, 54), - // - Key::Meta => (8, 9), - Key::LAlt => (8, 12), - Key::Space5_1 => (8, 15), - Key::Space5_2 => (8, 18), - Key::Space5_3 => (8, 21), - Key::Space5_4 => (8, 24), - Key::Space5_5 => (8, 27), - Key::RAlt => (8, 30), - Key::PrtSc => (8, 33), - Key::RCtrl => (8, 36), - Key::Up => (8, 42), - Key::RFn => (8, 51), - // - Key::Left => (9, 54), - // - Key::Down => (10, 9), - Key::Right => (10, 12), - Key::NormalBlank - | Key::FuncBlank - | Key::NormalSpacer - | Key::FuncSpacer - | Key::ArrowBlank - | Key::ArrowSpacer - | Key::UpRegular - | Key::DownRegular - | Key::LeftRegular - | Key::RightRegular - | Key::UpSplit - | Key::DownSplit - | Key::LeftSplit - | Key::RightSplit - | Key::ArrowRegularBlank - | Key::ArrowRegularSpacer - | Key::ArrowSplitBlank - | Key::ArrowSplitSpacer - | Key::RshiftSmall - | Key::LCtrlMed - | Key::MediaPlay - | Key::MediaStop - | Key::MediaPrev - | Key::MediaNext - | Key::Pause - | Key::NumLock - | Key::Star - | Key::NumPadDel - | Key::NumPadPlus - | Key::NumPadEnter - | Key::NumPadPause - | Key::NumPadPrtSc - | Key::NumPadHome - | Key::RCtrlLarge - | Key::RowEndSpacer => return None, - Key::Fan | Key::Space | Key::BkSpc => return None, - }; - - Some(&mut self.0[row][col..=col + 2]) - } - - #[inline] - pub fn get(&self) -> PerKeyRaw { - self.0.clone() - } - - #[inline] - pub fn get_ref(&self) -> &PerKeyRaw { - &self.0 - } - - #[inline] - pub fn get_mut(&mut self) -> &mut PerKeyRaw { - &mut self.0 - } -} - -impl From for PerKeyRaw { - fn from(k: KeyColourArray) -> Self { - k.0 - } -} diff --git a/rog-aura/src/per_zone.rs b/rog-aura/src/per_zone.rs deleted file mode 100644 index b743c995..00000000 --- a/rog-aura/src/per_zone.rs +++ /dev/null @@ -1,123 +0,0 @@ -use serde_derive::{Deserialize, Serialize}; -#[cfg(feature = "dbus")] -use zbus::zvariant::Type; - -/// Represents the zoned raw USB packets -pub type ZonedRaw = Vec; - -#[derive(Debug, Clone, Copy, Deserialize, Serialize)] -pub enum PerZone { - None, - KeyboardLeft, - KeyboardCenterLeft, - KeyboardCenterRight, - KeyboardRight, - LightbarRight, - LightbarRightCorner, - LightbarRightBottom, - LightbarLeftBottom, - LightbarLeftCorner, - LightbarLeft, -} - -#[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ZonedColourArray(ZonedRaw); - -impl Default for ZonedColourArray { - fn default() -> Self { - Self::new() - } -} - -impl ZonedColourArray { - pub fn new() -> Self { - let mut pkt = vec![0u8; 64]; - pkt[0] = 0x5d; // Report ID - pkt[1] = 0xbc; // Mode = custom??, 0xb3 is builtin - pkt[2] = 0x01; - pkt[3] = 0x01; // ?? - pkt[4] = 0x04; // ??, 4,5,6 are normally RGB for builtin mode colours - ZonedColourArray(pkt) - } - - pub fn rgb_for_zone(&mut self, zone: PerZone) -> &mut [u8] { - match zone { - PerZone::None | PerZone::KeyboardLeft => &mut self.0[9..=11], - PerZone::KeyboardCenterLeft => &mut self.0[12..=14], - PerZone::KeyboardCenterRight => &mut self.0[15..=17], - PerZone::KeyboardRight => &mut self.0[18..=20], - // Two sections missing here? - PerZone::LightbarRight => &mut self.0[27..=29], - PerZone::LightbarRightCorner => &mut self.0[30..=32], - PerZone::LightbarRightBottom => &mut self.0[33..=35], - PerZone::LightbarLeftBottom => &mut self.0[36..=38], - PerZone::LightbarLeftCorner => &mut self.0[39..=41], - PerZone::LightbarLeft => &mut self.0[42..=44], - } - } - - #[inline] - pub fn get(&self) -> ZonedRaw { - self.0.clone() - } - - #[inline] - pub fn get_ref(&self) -> &ZonedRaw { - &self.0 - } - - #[inline] - pub fn get_mut(&mut self) -> &mut ZonedRaw { - &mut self.0 - } -} - -impl From for ZonedRaw { - fn from(k: ZonedColourArray) -> Self { - k.0 - } -} - -#[cfg(test)] -mod tests { - use crate::{PerZone, ZonedColourArray, ZonedRaw}; - - macro_rules! colour_check { - ($zone:expr, $pkt_idx_start:expr) => { - let mut zone = ZonedColourArray::new(); - let c = zone.rgb_for_zone($zone); - c[0] = 255; - c[1] = 255; - c[2] = 255; - - let pkt: ZonedRaw = zone.get(); - assert_eq!(pkt[$pkt_idx_start], 0xff); - assert_eq!(pkt[$pkt_idx_start + 1], 0xff); - assert_eq!(pkt[$pkt_idx_start + 2], 0xff); - }; - } - - #[test] - fn zone_to_packet_check() { - let zone = ZonedColourArray::new(); - let pkt: ZonedRaw = zone.into(); - assert_eq!(pkt[0], 0x5d); - assert_eq!(pkt[1], 0xbc); - assert_eq!(pkt[2], 0x01); - assert_eq!(pkt[3], 0x01); - assert_eq!(pkt[4], 0x04); - - colour_check!(PerZone::KeyboardLeft, 9); - colour_check!(PerZone::KeyboardCenterLeft, 12); - colour_check!(PerZone::KeyboardCenterRight, 15); - colour_check!(PerZone::KeyboardRight, 18); - - colour_check!(PerZone::LightbarRight, 27); - colour_check!(PerZone::LightbarRightCorner, 30); - colour_check!(PerZone::LightbarRightBottom, 33); - colour_check!(PerZone::LightbarLeftBottom, 36); - colour_check!(PerZone::LightbarLeftCorner, 39); - colour_check!(PerZone::LightbarLeft, 42); - } -} diff --git a/rog-aura/src/sequencer/effects.rs b/rog-aura/src/sequencer/effects.rs deleted file mode 100644 index 74bfde2a..00000000 --- a/rog-aura/src/sequencer/effects.rs +++ /dev/null @@ -1,250 +0,0 @@ -use crate::{layouts::KeyLayout, p_random, Colour, EffectState, LedType, Speed}; -use serde_derive::{Deserialize, Serialize}; - -macro_rules! effect_state_impl { - () => { - fn get_colour(&self) -> Colour { - self.colour - } - - fn get_led_type(&self) -> LedType { - self.led_type.clone() - } - - /// Change the led type - fn set_led_type(&mut self, led_type: LedType) { - self.led_type = led_type; - } - }; -} - -macro_rules! effect_impl { - ($($effect:ident),*) => { - impl Effect { - /// Get the type of LED set - pub fn get_led_type(&self) -> LedType { - match self { - $(Effect::$effect(c) => c.get_led_type(),)* - } - } - - /// Change the led type - pub fn set_led_type(&mut self, led_type: LedType) { - match self { - $(Effect::$effect(c) => c.set_led_type(led_type),)* - } - } - - /// Calculate the next state of the effect - pub fn next_state(&mut self, layout: &KeyLayout) { - match self { - $(Effect::$effect(c) => c.next_colour_state(layout),)* - } - } - - /// Get the calculated colour - pub fn get_colour(&self) -> Colour { - match self { - $(Effect::$effect(c) => c.get_colour(),)* - } - } - } - }; -} - -/**************************************************************************************************/ - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub enum Effect { - Static(Static), - Breathe(Breathe), - Flicker(Flicker), -} - -impl Default for Effect { - fn default() -> Self { - Self::Static(Static::new(LedType::default(), Colour::default())) - } -} - -effect_impl!(Static, Breathe, Flicker); - -/**************************************************************************************************/ - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Static { - led_type: LedType, - /// The starting colour - colour: Colour, -} - -impl Static { - pub fn new(led_type: LedType, colour: Colour) -> Self { - Self { led_type, colour } - } -} - -impl EffectState for Static { - fn next_colour_state(&mut self, _layout: &KeyLayout) {} - - effect_state_impl!(); -} - -/**************************************************************************************************/ - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Breathe { - led_type: LedType, - /// The starting colour - start_colour1: Colour, - /// The secondary starting colour - start_colour2: Colour, - /// The speed at which to cycle between the colours - speed: Speed, - /// Temporary data to help keep state - #[serde(skip)] - colour: Colour, - #[serde(skip)] - count_flipped: bool, - #[serde(skip)] - use_colour1: bool, -} - -impl Breathe { - pub fn new(led_type: LedType, colour1: Colour, colour2: Colour, speed: Speed) -> Self { - Self { - led_type, - start_colour1: colour1, - start_colour2: colour2, - speed, - colour: colour1, - count_flipped: false, - use_colour1: true, - } - } -} - -impl EffectState for Breathe { - fn next_colour_state(&mut self, _layout: &KeyLayout) { - let Self { - start_colour1: colour1, - start_colour2: colour2, - speed, - colour: colour_actual, - count_flipped: flipped, - use_colour1, - .. - } = self; - - let speed = 4 - ::from(*speed); - - if *colour_actual == Colour(0, 0, 0) { - *use_colour1 = !*use_colour1; - } - - let colour = if !*use_colour1 { colour2 } else { colour1 }; - - let r1_scale = colour.0 / speed / 2; - let g1_scale = colour.1 / speed / 2; - let b1_scale = colour.2 / speed / 2; - - if *colour_actual == Colour(0, 0, 0) { - *flipped = true; - } else if colour_actual >= colour { - *flipped = false; - } - - if !*flipped { - colour_actual.0 = colour_actual.0.saturating_sub(r1_scale); - colour_actual.1 = colour_actual.1.saturating_sub(g1_scale); - colour_actual.2 = colour_actual.2.saturating_sub(b1_scale); - } else { - colour_actual.0 = colour_actual.0.saturating_add(r1_scale); - colour_actual.1 = colour_actual.1.saturating_add(g1_scale); - colour_actual.2 = colour_actual.2.saturating_add(b1_scale); - } - } - - effect_state_impl!(); -} - -/**************************************************************************************************/ - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Flicker { - led_type: LedType, - start_colour: Colour, - max_percentage: u8, - min_percentage: u8, - #[serde(skip)] - count: u8, - #[serde(skip)] - colour: Colour, -} - -impl Flicker { - pub fn new(led_type: LedType, colour: Colour, max_percentage: u8, min_percentage: u8) -> Self { - Self { - led_type, - colour, - count: 4, - max_percentage, - min_percentage, - start_colour: colour, - } - } -} - -impl EffectState for Flicker { - fn next_colour_state(&mut self, _layout: &KeyLayout) { - let Self { - max_percentage, - min_percentage, - colour, - start_colour, - .. - } = self; - - if self.count == 0 { - self.count = 4; - } - self.count -= 1; - if self.count != 0 { - return; - } - - // TODO: make a "percentage" method on Colour. - let max_light = Colour( - (start_colour.0 as f32 / 100.0 * *max_percentage as f32) as u8, - (start_colour.1 as f32 / 100.0 * *max_percentage as f32) as u8, - (start_colour.2 as f32 / 100.0 * *max_percentage as f32) as u8, - ); - // min light is a percentage of the set colour - let min_light = Colour( - (start_colour.0 as f32 / 100.0 * *min_percentage as f32) as u8, - (start_colour.1 as f32 / 100.0 * *min_percentage as f32) as u8, - (start_colour.2 as f32 / 100.0 * *min_percentage as f32) as u8, - ); - - // Convert the 255 to percentage - let amount = (p_random() & 7) as f32 * 8.0; - - let set_colour = |colour: &mut u8, max: f32, min: f32| { - let pc = amount / max * 100.0; - let min_amount = pc * min / 100.0; // percentage of min colour - let max_amount = pc * max / 100.0; // percentage of max colour - if *colour as f32 - min_amount < min { - *colour = min as u8; - } else { - *colour = (max - max_amount) as u8; - } - }; - set_colour(&mut colour.0, max_light.0 as f32, min_light.0 as f32); - set_colour(&mut colour.1, max_light.1 as f32, min_light.1 as f32); - set_colour(&mut colour.2, max_light.2 as f32, min_light.2 as f32); - - self.count = 4; - } - - effect_state_impl!(); -} diff --git a/rog-aura/src/sequencer/mod.rs b/rog-aura/src/sequencer/mod.rs deleted file mode 100644 index 9882dc4a..00000000 --- a/rog-aura/src/sequencer/mod.rs +++ /dev/null @@ -1,219 +0,0 @@ -mod effects; -pub use effects::*; - -use crate::{ - keys::Key, layouts::KeyLayout, Colour, KeyColourArray, PerKeyRaw, PerZone, ZonedColourArray, -}; -use serde_derive::{Deserialize, Serialize}; - -// static mut RNDINDEX: usize = 0; -static mut PRNDINDEX: usize = 0; - -/// Pseudo random table ripped straight out of room4doom -pub const RNDTABLE: [i32; 256] = [ - 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21, 211, 47, 80, 242, 154, - 27, 205, 128, 161, 89, 77, 36, 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, - 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, 149, 104, 25, 178, 252, 182, - 202, 182, 141, 197, 4, 81, 181, 242, 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, - 249, 0, 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235, 25, 92, 20, 145, 138, - 77, 69, 166, 78, 176, 173, 212, 166, 113, 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, - 171, 75, 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196, 135, 106, 63, 197, 195, - 86, 96, 203, 113, 101, 170, 247, 181, 113, 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, - 166, 103, 241, 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224, 145, 224, 81, - 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95, 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, - 54, 14, 109, 226, 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, 17, 46, 52, - 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 197, 242, 98, 43, 39, 175, 254, 145, 190, - 84, 118, 222, 187, 136, 120, 163, 236, 249, -]; - -pub fn p_random() -> i32 { - unsafe { - PRNDINDEX = (PRNDINDEX + 1) & 0xFF; - RNDTABLE[PRNDINDEX] - } -} - -pub(crate) trait EffectState { - /// Calculate the next colour state - fn next_colour_state(&mut self, _layout: &KeyLayout); - - /// Return the resulting colour. Implementers should store the colour to return it. - fn get_colour(&self) -> Colour; - - fn get_led_type(&self) -> LedType; - - fn set_led_type(&mut self, led_type: LedType); -} - -#[derive(Debug, Clone, Deserialize, Serialize)] -pub enum LedType { - Key(Key), - Zone(PerZone), -} - -impl Default for LedType { - fn default() -> Self { - Self::Zone(PerZone::None) - } -} - -#[derive(Debug, Deserialize, Serialize, Default)] -pub struct Sequences(Vec); - -impl Sequences { - #[inline] - pub fn new() -> Self { - Self(Vec::new()) - } - - #[inline] - pub fn push(&mut self, action: Effect) { - self.0.push(action); - } - - #[inline] - pub fn insert(&mut self, index: usize, action: Effect) { - self.0.insert(index, action); - } - - /// Remove an item at this position from the run buffer. If the `index` supplied - /// is not in range then `None` is returned, otherwise the `ActionData` at that location - /// is yeeted and returned. - #[inline] - pub fn remove_item(&mut self, index: usize) -> Option { - if index < self.0.len() { - return Some(self.0.remove(index)); - } - None - } - - pub fn next_state(&mut self, layout: &KeyLayout) { - for effect in &mut self.0 { - effect.next_state(layout); - } - } - - pub fn create_packets(&self) -> PerKeyRaw { - let mut keys = KeyColourArray::new(); - let mut zones = ZonedColourArray::new(); - let mut is_per_key = false; - for effect in &self.0 { - match effect.get_led_type() { - LedType::Key(key) => { - is_per_key = true; - if let Some(rgb) = keys.rgb_for_key(key) { - let c = effect.get_colour(); - rgb[0] = c.0; - rgb[1] = c.1; - rgb[2] = c.2; - } - } - LedType::Zone(z) => { - let rgb = zones.rgb_for_zone(z); - let c = effect.get_colour(); - rgb[0] = c.0; - rgb[1] = c.1; - rgb[2] = c.2; - } - } - } - if is_per_key { - keys.into() - } else { - vec![zones.into()] - } - } -} - -#[cfg(test)] -mod tests { - use crate::{ - keys::Key, layouts::KeyLayout, Breathe, Colour, Effect, Flicker, LedType, Sequences, Speed, - Static, - }; - - #[test] - fn single_key_next_state_then_create() { - let layout = KeyLayout::gx502_layout(); - let mut seq = Sequences::new(); - seq.0.push(Effect::Static(Static::new( - LedType::Key(Key::F), - Colour(255, 127, 0), - ))); - - seq.next_state(&layout); - let packets = seq.create_packets(); - - assert_eq!(packets[0][0], 0x5d); - assert_eq!(packets[5][33], 255); - assert_eq!(packets[5][34], 127); - assert_eq!(packets[5][35], 0); - } - - #[test] - fn cycle_breathe() { - let layout = KeyLayout::gx502_layout(); - let mut seq = Sequences::new(); - seq.0.push(Effect::Breathe(Breathe::new( - LedType::Key(Key::F), - Colour(255, 127, 0), - Colour(127, 0, 255), - Speed::Med, - ))); - - let s = serde_json::to_string_pretty(&seq).unwrap(); - println!("{s}"); - - seq.next_state(&layout); - let packets = seq.create_packets(); - - assert_eq!(packets[0][0], 0x5d); - assert_eq!(packets[5][33], 213); - assert_eq!(packets[5][34], 106); - assert_eq!(packets[5][35], 0); - - // dbg!(&packets[5][33..=35]); - - seq.next_state(&layout); - let packets = seq.create_packets(); - - assert_eq!(packets[0][0], 0x5d); - assert_eq!(packets[5][33], 171); - assert_eq!(packets[5][34], 85); - assert_eq!(packets[5][35], 0); - } - - #[test] - fn cycle_flicker() { - let layout = KeyLayout::gx502_layout(); - let mut seq = Sequences::new(); - seq.0.push(Effect::Flicker(Flicker::new( - LedType::Key(Key::F), - Colour(255, 127, 80), - 100, - 10, - ))); - - seq.next_state(&layout); - let packets = seq.create_packets(); - - assert_eq!(packets[0][0], 0x5d); - assert_eq!(packets[5][33], 255); - assert_eq!(packets[5][34], 127); - assert_eq!(packets[5][35], 80); - - // The random is deterministic - seq.next_state(&layout); - seq.next_state(&layout); - seq.next_state(&layout); - seq.next_state(&layout); - seq.next_state(&layout); - seq.next_state(&layout); - seq.next_state(&layout); - - let packets = seq.create_packets(); - assert_eq!(packets[5][33], 215); - assert_eq!(packets[5][34], 87); - assert_eq!(packets[5][35], 40); - } -} diff --git a/rog-aura/src/usb.rs b/rog-aura/src/usb.rs index ee074389..dcdc72fd 100644 --- a/rog-aura/src/usb.rs +++ b/rog-aura/src/usb.rs @@ -1,5 +1,7 @@ -use serde::{Deserialize, Serialize}; +use std::fmt::Debug; use std::ops::{BitAnd, BitOr}; + +use serde::{Deserialize, Serialize}; #[cfg(feature = "dbus")] use zbus::zvariant::Type; @@ -16,12 +18,12 @@ pub const LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /// Writes out the correct byte string for brightness pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] { [ - 0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0x5a, 0xba, 0xc5, 0xc4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] } #[cfg_attr(feature = "dbus", derive(Type))] -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Serialize, Deserialize, Default)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Serialize, Deserialize, Default)] pub enum AuraDevice { Tuf, X1854, @@ -45,6 +47,19 @@ impl From<&str> for AuraDevice { } } +impl Debug for AuraDevice { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Tuf => write!(f, "Tuf"), + Self::X1854 => write!(f, "0x1854"), + Self::X1869 => write!(f, "0x1869"), + Self::X1866 => write!(f, "0x1866"), + Self::X19B6 => write!(f, "0x19B6"), + Self::Unknown => write!(f, "Unknown"), + } + } +} + /// This struct is intended as a helper to pass args to generic dbus interface #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Clone, Default, Debug, Serialize, Deserialize)] @@ -73,7 +88,8 @@ impl AuraDevTuf { /// # Bits for older 0x1866 keyboard model /// /// Keybord and Lightbar require Awake, Boot and Sleep apply to both -/// Keybord and Lightbar regardless of if either are enabled (or Awake is enabled) +/// Keybord and Lightbar regardless of if either are enabled (or Awake is +/// enabled) /// /// | Byte 1 | Byte 2 | Byte 3 | function | hex | /// |------------|------------|------------|----------|----------| @@ -83,7 +99,6 @@ impl AuraDevTuf { /// | 1100, 0011 | 0001, 0010 | 0000, 1001 | Boot/Sht | c3,12,09 | /// | 0011, 0000 | 0000, 1000 | 0000, 0100 | Sleep | 30,08,04 | /// | 1111, 1111 | 0001, 1111 | 0000, 1111 | all on | | -/// #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] #[repr(u32)] @@ -161,7 +176,6 @@ impl BitAnd for AuraDev1866 { /// | 0000 | 0100 | 04 | lightbar on | bit 3 | /// | 0000 | 1000 | 08 | lightbar off sleep | bit 4 | /// | 0001 | 0000 | 10 | lightbar shtdn off | bit 5 | -/// #[cfg_attr(feature = "dbus", derive(Type))] #[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Eq, Ord, Hash, Serialize, Deserialize)] #[repr(u32)] @@ -226,9 +240,8 @@ impl BitAnd for AuraDev19b6 { #[cfg(test)] mod tests { - use crate::usb::AuraDev19b6; - use super::AuraDev1866; + use crate::usb::AuraDev19b6; #[test] fn check_0x1866_control_bytes() { @@ -370,7 +383,7 @@ mod tests { assert_eq!(bytes[2], 0x0f); let byte3 = [ - //AuraDev19b6::AwakeLid, + // AuraDev19b6::AwakeLid, AuraDev19b6::BootLid, AuraDev19b6::SleepLid, AuraDev19b6::ShutdownLid, @@ -393,7 +406,7 @@ mod tests { AuraDev19b6::AwakeLid, AuraDev19b6::BootLid, AuraDev19b6::SleepLid, - //AuraDev19b6::ShutdownLid, + // AuraDev19b6::ShutdownLid, ]; let bytes = AuraDev19b6::to_bytes(&byte3); println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); @@ -401,9 +414,9 @@ mod tests { let byte3 = [ AuraDev19b6::AwakeLid, - //AuraDev19b6::BootLid, + // AuraDev19b6::BootLid, AuraDev19b6::SleepLid, - //AuraDev19b6::ShutdownLid, + // AuraDev19b6::ShutdownLid, ]; let bytes = AuraDev19b6::to_bytes(&byte3); println!("{:08b}, {:08b}, {:08b}", bytes[0], bytes[1], bytes[2]); diff --git a/rog-control-center/Cargo.toml b/rog-control-center/Cargo.toml index c9fff538..5f4fcd7a 100644 --- a/rog-control-center/Cargo.toml +++ b/rog-control-center/Cargo.toml @@ -6,6 +6,7 @@ authors = ["Luke D. Jones "] edition = "2021" [features] +#default = ["mocking"] mocking = [] [dependencies] @@ -23,6 +24,7 @@ rog_profiles = { path = "../rog-profiles" } rog_platform = { path = "../rog-platform" } supergfxctl = { git = "https://gitlab.com/asus-linux/supergfxctl.git", default-features = false } +gumdrop.workspace = true log.workspace = true env_logger.workspace = true diff --git a/rog-control-center/src/app.rs b/rog-control-center/src/app.rs index 537c0fec..d37e51e3 100644 --- a/rog-control-center/src/app.rs +++ b/rog-control-center/src/app.rs @@ -1,18 +1,16 @@ -use std::{ - f64::consts::PI, - sync::{ - atomic::{AtomicBool, AtomicU8, Ordering}, - Arc, Mutex, - }, - time::{Duration, Instant}, -}; +use std::f64::consts::PI; +use std::sync::atomic::{AtomicBool, AtomicU8, Ordering}; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, Instant}; use egui::{Button, RichText}; +use rog_aura::layouts::KeyLayout; use rog_platform::supported::SupportedFunctions; -use crate::{ - config::Config, error::Result, system_state::SystemState, Page, RogDbusClientBlocking, -}; +use crate::config::Config; +use crate::error::Result; +use crate::system_state::SystemState; +use crate::{Page, RogDbusClientBlocking}; pub struct RogApp { pub page: Page, @@ -103,8 +101,9 @@ impl RogApp { } impl eframe::App for RogApp { - /// Called each time the UI needs repainting, which may be many times per second. - /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. + /// Called each time the UI needs repainting, which may be many times per + /// second. Put your widgets into a `SidePanel`, `TopPanel`, + /// `CentralPanel`, `Window` or `Area`. fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { let states = self.states.clone(); @@ -115,6 +114,21 @@ impl eframe::App for RogApp { } } + // Shortcut typical display stuff + if let Ok(mut states) = states.try_lock() { + let layout_testing = states.aura_creation.layout_testing.clone(); + if let Some(path) = &layout_testing { + let modified = path.metadata().unwrap().modified().unwrap(); + if states.aura_creation.layout_last_modified < modified { + states.aura_creation.layout_last_modified = modified; + // time to reload the config + states.aura_creation.keyboard_layout = KeyLayout::from_file(path).unwrap(); + } + self.aura_page(&mut states, ctx); + return; + } + } + let page = self.page; self.top_bar(ctx, frame); @@ -146,6 +160,7 @@ impl eframe::App for RogApp { }); } } + if !was_error { if let Ok(mut states) = states.try_lock() { if page == Page::System { diff --git a/rog-control-center/src/cli_options.rs b/rog-control-center/src/cli_options.rs new file mode 100644 index 00000000..d6040eba --- /dev/null +++ b/rog-control-center/src/cli_options.rs @@ -0,0 +1,19 @@ +use gumdrop::Options; + +#[derive(Default, Options)] +pub struct CliStart { + #[options(help_flag, help = "print help message")] + pub help: bool, + #[options(help = "show program version number")] + pub version: bool, + #[options( + meta = "", + help = "set board name for testing, this will make ROGCC show only the keyboard page" + )] + pub board_name: Option, + #[options( + help = "put ROGCC in layout viewing mode - this is helpful for finding existing layouts \ + that might match your laptop" + )] + pub layout_viewing: bool, +} diff --git a/rog-control-center/src/config.rs b/rog-control-center/src/config.rs index c74c6ced..bad72070 100644 --- a/rog-control-center/src/config.rs +++ b/rog-control-center/src/config.rs @@ -1,11 +1,11 @@ +use std::fs::{create_dir, OpenOptions}; +use std::io::{Read, Write}; + use log::{error, info, warn}; use serde_derive::{Deserialize, Serialize}; -use std::{ - fs::{create_dir, OpenOptions}, - io::{Read, Write}, -}; -use crate::{error::Error, update_and_notify::EnabledNotifications}; +use crate::error::Error; +use crate::update_and_notify::EnabledNotifications; const CFG_DIR: &str = "rog"; const CFG_FILE_NAME: &str = "rog-control-center.cfg"; diff --git a/rog-control-center/src/lib.rs b/rog-control-center/src/lib.rs index 799a9d26..f03a7ca2 100644 --- a/rog-control-center/src/lib.rs +++ b/rog-control-center/src/lib.rs @@ -1,14 +1,13 @@ pub mod app; -use std::{ - fs::{remove_dir_all, File, OpenOptions}, - io::{Read, Write}, - process::exit, - thread::sleep, - time::Duration, -}; +use std::fs::{remove_dir_all, File, OpenOptions}; +use std::io::{Read, Write}; +use std::process::exit; +use std::thread::sleep; +use std::time::Duration; pub use app::RogApp; +pub mod cli_options; pub mod config; pub mod error; #[cfg(feature = "mocking")] @@ -22,12 +21,12 @@ pub mod widgets; #[cfg(feature = "mocking")] pub use mocking::RogDbusClientBlocking; +use nix::sys::stat; +use nix::unistd; #[cfg(not(feature = "mocking"))] pub use rog_dbus::RogDbusClientBlocking; - -use nix::{sys::stat, unistd}; use tempfile::TempDir; -//use log::{error, info, warn}; +// use log::{error, info, warn}; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/rog-control-center/src/main.rs b/rog-control-center/src/main.rs index edbe81b2..9adf0f66 100644 --- a/rog-control-center/src/main.rs +++ b/rog-control-center/src/main.rs @@ -1,21 +1,26 @@ +use std::env::args; +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use std::sync::{Arc, Mutex}; + use eframe::{IconData, NativeOptions}; -use log::{error, info}; +use gumdrop::Options; +use log::{error, info, warn}; +use rog_aura::aura_detection::{LaptopLedData, LedSupportFile}; use rog_aura::layouts::KeyLayout; +use rog_control_center::cli_options::CliStart; +use rog_control_center::config::Config; +use rog_control_center::error::Result; +use rog_control_center::startup_error::AppErrorShow; +use rog_control_center::system_state::SystemState; use rog_control_center::tray::init_tray; -use rog_control_center::update_and_notify::EnabledNotifications; +use rog_control_center::update_and_notify::{start_notifications, EnabledNotifications}; use rog_control_center::{ - config::Config, error::Result, get_ipc_file, on_tmp_dir_exists, print_versions, - startup_error::AppErrorShow, system_state::SystemState, update_and_notify::start_notifications, - RogApp, RogDbusClientBlocking, SHOWING_GUI, SHOW_GUI, + get_ipc_file, on_tmp_dir_exists, print_versions, RogApp, RogDbusClientBlocking, SHOWING_GUI, + SHOW_GUI, }; use rog_platform::supported::SupportedFunctions; -use std::sync::Mutex; -use std::{ - fs::OpenOptions, - io::{Read, Write}, - path::PathBuf, - sync::Arc, -}; use tokio::runtime::Runtime; #[cfg(not(feature = "mocking"))] @@ -26,7 +31,19 @@ const BOARD_NAME: &str = "/sys/class/dmi/id/board_name"; const APP_ICON_PATH: &str = "/usr/share/icons/hicolor/512x512/apps/rog-control-center.png"; fn main() -> Result<()> { - print_versions(); + let args: Vec = args().skip(1).collect(); + + let parsed = match CliStart::parse_args_default(&args) { + Ok(p) => p, + Err(err) => { + panic!("source {}", err); + } + }; + + if do_cli_help(&parsed) { + return Ok(()); + } + let mut logger = env_logger::Builder::new(); logger .parse_default_env() @@ -43,8 +60,8 @@ fn main() -> Result<()> { vsync: true, decorated: true, transparent: false, - min_window_size: Some(egui::vec2(840.0, 600.0)), - max_window_size: Some(egui::vec2(840.0, 600.0)), + min_window_size: Some(egui::vec2(900.0, 600.0)), + max_window_size: Some(egui::vec2(900.0, 600.0)), run_and_return: true, icon_data: Some(load_icon()), ..Default::default() @@ -88,25 +105,66 @@ fn main() -> Result<()> { .read(true) .open(PathBuf::from(BOARD_NAME)) .map_err(|e| { - println!("{BOARD_NAME}, {e}"); + println!("DOH! {BOARD_NAME}, {e}"); e })?; let mut board_name = String::new(); file.read_to_string(&mut board_name)?; - #[cfg(feature = "mocking")] - { - board_name = "gl504".to_string(); + let mut led_support = LaptopLedData::get_data(); + + let mut path = PathBuf::from(DATA_DIR); + let mut layout_name = None; + let mut layouts = Vec::new(); + if parsed.board_name.is_some() || parsed.layout_viewing { path.pop(); path.push("rog-aura"); path.push("data"); + layouts = KeyLayout::layout_files(path.to_owned()).unwrap(); + + if let Some(name) = &parsed.board_name { + if let Some(modes) = LedSupportFile::load_from_config() { + if let Some(data) = modes.matcher(name) { + led_support = data; + } + } + board_name = name.to_owned(); + for layout in &layouts { + if layout + .file_name() + .unwrap() + .to_string_lossy() + .contains(&led_support.layout_name.to_lowercase()) + { + layout_name = Some(layout.to_owned()); + } + } + } else { + board_name = "GQ401QM".to_string() + }; + + if parsed.layout_viewing { + layout_name = Some(layouts[0].clone()); + board_name = layouts[0] + .file_name() + .unwrap() + .to_string_lossy() + .split_once('_') + .unwrap() + .0 + .to_owned(); + led_support.layout_name = board_name.clone(); + } } - let layout = KeyLayout::find_layout(board_name.as_str(), PathBuf::from(DATA_DIR)) + let layout = KeyLayout::find_layout(led_support, path) .map_err(|e| { - println!("{BOARD_NAME}, {e}"); + println!("DERP! , {e}"); }) - .unwrap_or_else(|_| KeyLayout::ga401_layout()); + .unwrap_or_else(|_| { + warn!("Did not find a keyboard layout matching {board_name}"); + KeyLayout::default_layout() + }); // tmp-dir must live to the end of program life let _tmp_dir = match tempfile::Builder::new() @@ -118,7 +176,14 @@ fn main() -> Result<()> { Err(_) => on_tmp_dir_exists().unwrap(), }; - let states = setup_page_state_and_notifs(layout, enabled_notifications, &config, &supported)?; + let states = setup_page_state_and_notifs( + layout_name, + layout, + layouts, + enabled_notifications, + &config, + &supported, + )?; init_tray(supported, states.clone()); @@ -128,7 +193,7 @@ fn main() -> Result<()> { } let config = Config::load()?; - if !config.run_in_background { + if !config.run_in_background || parsed.board_name.is_some() || parsed.layout_viewing { break; } @@ -151,13 +216,17 @@ fn main() -> Result<()> { } fn setup_page_state_and_notifs( + layout_testing: Option, keyboard_layout: KeyLayout, + keyboard_layouts: Vec, enabled_notifications: Arc>, config: &Config, supported: &SupportedFunctions, ) -> Result>> { let page_states = Arc::new(Mutex::new(SystemState::new( + layout_testing, keyboard_layout, + keyboard_layouts, enabled_notifications.clone(), supported, )?)); @@ -216,3 +285,31 @@ fn load_icon() -> IconData { rgba, } } + +fn do_cli_help(parsed: &CliStart) -> bool { + if parsed.help { + println!("{}", CliStart::usage()); + println!(); + if let Some(cmdlist) = CliStart::command_list() { + let commands: Vec = cmdlist.lines().map(|s| s.to_owned()).collect(); + for command in commands.iter() { + println!("{}", command); + } + } + } + + if parsed.version { + print_versions(); + println!(); + } + + parsed.help +} + +pub fn get_layout_path(path: &Path, layout_name: &str) -> PathBuf { + let mut data_path = PathBuf::from(path); + let layout_file = format!("{}_US.ron", layout_name); + data_path.push("layouts"); + data_path.push(layout_file); + data_path +} diff --git a/rog-control-center/src/mocking.rs b/rog-control-center/src/mocking.rs index 7291c44c..d99cfe16 100644 --- a/rog-control-center/src/mocking.rs +++ b/rog-control-center/src/mocking.rs @@ -1,35 +1,48 @@ use std::collections::BTreeMap; -use rog_aura::{ - usb::{AuraDev19b6, AuraDevice, AuraPowerDev}, - AuraEffect, AuraModeNum, AuraZone, -}; -use rog_profiles::fan_curve_set::{CurveData, FanCurveSet}; -use rog_supported::{ - AnimeSupportedFunctions, ChargeSupportedFunctions, LedSupportedFunctions, +use rog_aura::usb::{AuraDev19b6, AuraDevice, AuraPowerDev}; +use rog_aura::{AuraEffect, AuraModeNum, AuraZone}; +use rog_platform::platform::GpuMode; +use rog_platform::supported::{ + AdvancedAura, AnimeSupportedFunctions, ChargeSupportedFunctions, LedSupportedFunctions, PlatformProfileFunctions, RogBiosSupportedFunctions, SupportedFunctions, }; +use rog_profiles::fan_curve_set::{CurveData, FanCurveSet}; +use supergfxctl::pci_device::{GfxMode, GfxPower}; use crate::error::Result; -const NOPE: &'static str = ""; +const NOPE: &str = ""; -pub struct RogDbusClientBlocking<'a> { +#[derive(Default)] +pub struct DaemonProxyBlocking<'a> { _phantom: &'a str, } -impl<'a> Default for RogDbusClientBlocking<'a> { - fn default() -> Self { - Self { - _phantom: Default::default(), - } +impl<'a> DaemonProxyBlocking<'a> { + pub fn new(_c: &bool) -> Result { + Ok(Self { _phantom: NOPE }) } + + pub fn mode(&self) -> Result { + Ok(GfxMode::None) + } + + pub fn power(&self) -> Result { + Ok(GfxPower::Suspended) + } +} + +#[derive(Default)] +pub struct RogDbusClientBlocking<'a> { + _phantom: &'a str, } impl<'a> RogDbusClientBlocking<'a> { pub fn new() -> Result<(Self, bool)> { Ok((Self { _phantom: NOPE }, true)) } + pub fn proxies(&self) -> Proxies { Proxies } @@ -40,18 +53,23 @@ impl Proxies { pub fn rog_bios(&self) -> Bios { Bios } + pub fn profile(&self) -> Profile { Profile } + pub fn led(&self) -> Led { Led } + pub fn anime(&self) -> Anime { Anime } + pub fn charge(&self) -> Profile { Profile } + pub fn supported(&self) -> Supported { Supported } @@ -62,18 +80,23 @@ impl Bios { pub fn post_boot_sound(&self) -> Result { Ok(1) } - pub fn gpu_mux_mode(&self) -> Result { - Ok(1) + + pub fn gpu_mux_mode(&self) -> Result { + Ok(GpuMode::Optimus) } - pub fn panel_od(&self) -> Result { - Ok(1) + + pub fn panel_od(&self) -> Result { + Ok(true) } + pub fn set_post_boot_sound(&self, _b: bool) -> Result<()> { Ok(()) } - pub fn set_gpu_mux_mode(&self, _b: bool) -> Result<()> { + + pub fn set_gpu_mux_mode(&self, _b: GpuMode) -> Result<()> { Ok(()) } + pub fn set_panel_od(&self, _b: bool) -> Result<()> { Ok(()) } @@ -88,15 +111,18 @@ impl Profile { rog_profiles::Profile::Quiet, ]) } + pub fn active_profile(&self) -> Result { Ok(rog_profiles::Profile::Performance) } + pub fn enabled_fan_profiles(&self) -> Result> { Ok(vec![ rog_profiles::Profile::Performance, rog_profiles::Profile::Balanced, ]) } + pub fn fan_curve_data(&self, _p: rog_profiles::Profile) -> Result { let mut curve = FanCurveSet::default(); curve.cpu.pwm = [30, 40, 60, 100, 140, 180, 200, 250]; @@ -105,21 +131,34 @@ impl Profile { curve.gpu.temp = [20, 30, 40, 50, 70, 80, 90, 100]; Ok(curve) } + pub fn set_fan_curve(&self, _p: rog_profiles::Profile, _c: CurveData) -> Result<()> { Ok(()) } + pub fn set_fan_curve_enabled(&self, _p: rog_profiles::Profile, _b: bool) -> Result<()> { Ok(()) } - pub fn limit(&self) -> Result { + + pub fn charge_control_end_threshold(&self) -> Result { Ok(66) } - pub fn set_limit(&self, _l: u8) -> Result<()> { + + pub fn set_charge_control_end_threshold(&self, _l: u8) -> Result<()> { Ok(()) } + pub fn set_active_profile(&self, _p: rog_profiles::Profile) -> Result<()> { Ok(()) } + + pub fn mains_online(&self) -> Result { + Ok(true) + } + + pub fn reset_profile_curves(&self, _p: rog_profiles::Profile) -> Result { + Ok(true) + } } pub struct Led; @@ -139,12 +178,15 @@ impl Led { data.insert(AuraModeNum::Pulse, AuraEffect::default()); Ok(data) } + pub fn led_mode(&self) -> Result { Ok(AuraModeNum::Rainbow) } + pub fn led_brightness(&self) -> Result { Ok(1) } + pub fn leds_enabled(&self) -> Result { Ok(AuraPowerDev { tuf: vec![], @@ -157,9 +199,11 @@ impl Led { ], }) } + pub fn set_leds_power(&self, _a: AuraPowerDev, _b: bool) -> Result<()> { Ok(()) } + pub fn set_led_mode(&self, _a: &AuraEffect) -> Result<()> { Ok(()) } @@ -170,12 +214,15 @@ impl Anime { pub fn boot_enabled(&self) -> Result { Ok(true) } + pub fn awake_enabled(&self) -> Result { Ok(true) } + pub fn set_on_off(&self, _b: bool) -> Result<()> { Ok(()) } + pub fn set_boot_on_off(&self, _b: bool) -> Result<()> { Ok(()) } @@ -194,16 +241,16 @@ impl Supported { fan_curves: true, }, keyboard_led: LedSupportedFunctions { - prod_id: AuraDevice::X19B6, - brightness_set: true, - stock_led_modes: vec![ + dev_id: AuraDevice::X19B6, + brightness: true, + basic_modes: vec![ AuraModeNum::Rain, AuraModeNum::Rainbow, AuraModeNum::Star, AuraModeNum::Static, AuraModeNum::Strobe, ], - multizone_led_mode: vec![ + basic_zones: vec![ AuraZone::Key1, AuraZone::Key2, AuraZone::Key3, @@ -212,12 +259,12 @@ impl Supported { AuraZone::BarRight, AuraZone::Logo, ], - per_key_led_mode: true, + advanced_type: AdvancedAura::PerKey, }, rog_bios_ctrl: RogBiosSupportedFunctions { post_sound: true, - dedicated_gfx: true, - panel_od: true, + gpu_mux: true, + panel_overdrive: true, dgpu_disable: true, egpu_enable: true, }, diff --git a/rog-control-center/src/pages/aura_page.rs b/rog-control-center/src/pages/aura_page.rs index 3c07c54b..b99dc0c6 100644 --- a/rog-control-center/src/pages/aura_page.rs +++ b/rog-control-center/src/pages/aura_page.rs @@ -1,18 +1,16 @@ -use std::{sync::atomic::Ordering, time::Duration}; +use std::sync::atomic::Ordering; +use std::time::Duration; use egui::Color32; use rog_aura::{AuraEffect, AuraModeNum}; -use crate::{ - system_state::SystemState, - widgets::{aura_modes_group, keyboard}, - RogApp, -}; +use crate::system_state::SystemState; +use crate::widgets::{aura_modes_group, keyboard}; +use crate::RogApp; impl RogApp { pub fn aura_page(&mut self, states: &mut SystemState, ctx: &egui::Context) { let Self { - supported, oscillator1, oscillator2, oscillator3, @@ -70,9 +68,13 @@ impl RogApp { // TODO: animation of colour changes/periods/blending egui::CentralPanel::default().show(ctx, |ui| { - aura_modes_group(supported, states, oscillator_freq, ui); - - keyboard(ui, &states.keyboard_layout, &mut states.aura, colour); + aura_modes_group(states, oscillator_freq, ui); + keyboard( + ui, + &states.aura_creation.keyboard_layout, + &mut states.aura, + colour, + ); }); // Only do repaint request if on this page diff --git a/rog-control-center/src/pages/fan_curve_page.rs b/rog-control-center/src/pages/fan_curve_page.rs index e2cb324b..e9725575 100644 --- a/rog-control-center/src/pages/fan_curve_page.rs +++ b/rog-control-center/src/pages/fan_curve_page.rs @@ -1,28 +1,37 @@ -use crate::{ - system_state::{FanCurvesState, ProfilesState, SystemState}, - widgets::fan_graphs, - RogApp, RogDbusClientBlocking, -}; use egui::Ui; use rog_platform::supported::SupportedFunctions; use rog_profiles::Profile; +use crate::system_state::{FanCurvesState, ProfilesState, SystemState}; +use crate::widgets::fan_graphs; +use crate::{RogApp, RogDbusClientBlocking}; + impl RogApp { pub fn fan_curve_page(&mut self, states: &mut SystemState, ctx: &egui::Context) { let Self { supported, .. } = self; egui::CentralPanel::default().show(ctx, |ui| { ui.heading("Custom fan curves"); - ui.label("A fan curve is only active when the related profile is active and the curve is enabled"); + ui.label( + "A fan curve is only active when the related profile is active and the curve is \ + enabled", + ); Self::fan_curve( supported, &mut states.profiles, &mut states.fan_curves, - &states.asus_dbus, &mut states.error, + &states.asus_dbus, + &mut states.error, ui, ); - fan_graphs(supported, &mut states.fan_curves, &states.asus_dbus, &mut states.error, ui); + fan_graphs( + supported, + &mut states.fan_curves, + &states.asus_dbus, + &mut states.error, + ui, + ); }); } diff --git a/rog-control-center/src/pages/system_page.rs b/rog-control-center/src/pages/system_page.rs index 17a4cb56..ae1b9212 100644 --- a/rog-control-center/src/pages/system_page.rs +++ b/rog-control-center/src/pages/system_page.rs @@ -1,10 +1,8 @@ -use crate::{ - system_state::SystemState, - widgets::{ - anime_power_group, app_settings, aura_power_group, platform_profile, rog_bios_group, - }, - RogApp, +use crate::system_state::SystemState; +use crate::widgets::{ + anime_power_group, app_settings, aura_power_group, platform_profile, rog_bios_group, }; +use crate::RogApp; impl RogApp { pub fn system_page(&mut self, states: &mut SystemState, ctx: &egui::Context) { @@ -21,7 +19,6 @@ impl RogApp { egui::Grid::new("grid_of_bits") .min_col_width(rect.width() / 2.0) .show(ui, |ui| { - /******************************************************/ ui.vertical(|ui| { ui.separator(); if supported.platform_profile.platform_profile { @@ -34,7 +31,6 @@ impl RogApp { }); ui.end_row(); - /******************************************************/ ui.vertical(|ui| { ui.separator(); app_settings(config, states, ui); @@ -45,7 +41,6 @@ impl RogApp { }); ui.end_row(); - /******************************************************/ ui.vertical(|ui| { ui.separator(); if supported.anime_ctrl.0 { diff --git a/rog-control-center/src/system_state.rs b/rog-control-center/src/system_state.rs index 100921b4..3f7e465f 100644 --- a/rog-control-center/src/system_state.rs +++ b/rog-control-center/src/system_state.rs @@ -1,19 +1,26 @@ -use std::{ - collections::{BTreeMap, HashSet}, - sync::{Arc, Mutex}, -}; +use std::collections::{BTreeMap, HashSet}; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; +use std::time::SystemTime; use egui::Vec2; -use rog_aura::{layouts::KeyLayout, usb::AuraPowerDev, AuraEffect, AuraModeNum}; -use rog_platform::{platform::GpuMode, supported::SupportedFunctions}; -use rog_profiles::{fan_curve_set::FanCurveSet, FanCurvePU, Profile}; -use supergfxctl::{ - pci_device::{GfxMode, GfxPower}, - zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking, -}; - -use crate::{error::Result, update_and_notify::EnabledNotifications, RogDbusClientBlocking}; use log::error; +use rog_aura::layouts::KeyLayout; +use rog_aura::usb::AuraPowerDev; +use rog_aura::{AuraEffect, AuraModeNum}; +use rog_platform::platform::GpuMode; +use rog_platform::supported::SupportedFunctions; +use rog_profiles::fan_curve_set::FanCurveSet; +use rog_profiles::{FanCurvePU, Profile}; +use supergfxctl::pci_device::{GfxMode, GfxPower}; +#[cfg(not(feature = "mocking"))] +use supergfxctl::zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking; + +use crate::error::Result; +#[cfg(feature = "mocking")] +use crate::mocking::DaemonProxyBlocking as GfxProxyBlocking; +use crate::update_and_notify::EnabledNotifications; +use crate::RogDbusClientBlocking; #[derive(Clone, Debug, Default)] pub struct BiosState { @@ -149,25 +156,21 @@ pub struct AuraState { } impl AuraState { - pub fn new(supported: &SupportedFunctions, dbus: &RogDbusClientBlocking<'_>) -> Result { + pub fn new(layout: &KeyLayout, dbus: &RogDbusClientBlocking<'_>) -> Result { Ok(Self { - current_mode: if !supported.keyboard_led.stock_led_modes.is_empty() { + current_mode: if !layout.basic_modes().is_empty() { dbus.proxies().led().led_mode().unwrap_or_default() } else { AuraModeNum::Static }, - modes: if !supported.keyboard_led.stock_led_modes.is_empty() { + modes: if !layout.basic_modes().is_empty() { dbus.proxies().led().led_modes().unwrap_or_default() } else { BTreeMap::new() }, enabled: dbus.proxies().led().leds_enabled().unwrap_or_default(), - bright: if !supported.keyboard_led.brightness_set { - dbus.proxies().led().led_brightness().unwrap_or_default() - } else { - 2 - }, + bright: dbus.proxies().led().led_brightness().unwrap_or_default(), wave_red: [0u8; 22], wave_green: [0u8; 22], wave_blue: [0u8; 22], @@ -259,13 +262,42 @@ impl PowerState { } } -/// State stored from system daemons. This is shared with: tray, zbus notifications thread -/// and the GUI app thread. -pub struct SystemState { +#[derive(Clone, Debug)] +pub struct AuraCreation { + /// Specifically for testing the development of keyboard layouts (combined + /// with `--layout-name` CLI option) + pub layout_testing: Option, + pub layout_last_modified: SystemTime, pub keyboard_layout: KeyLayout, + pub keyboard_layouts: Vec, + /// current index in to `self.keyboard_layouts` + pub keyboard_layout_index: usize, +} + +impl AuraCreation { + pub fn new( + layout_testing: Option, + keyboard_layout: KeyLayout, + keyboard_layouts: Vec, + ) -> Self { + Self { + layout_testing, + layout_last_modified: SystemTime::now(), + keyboard_layout, + keyboard_layouts, + keyboard_layout_index: 0, + } + } +} + +/// State stored from system daemons. This is shared with: tray, zbus +/// notifications thread and the GUI app thread. +pub struct SystemState { + pub aura_creation: AuraCreation, + //-- pub enabled_notifications: Arc>, - /// Because much of the app state here is the same as `RogBiosSupportedFunctions` - /// we can re-use that structure. + /// Because much of the app state here is the same as + /// `RogBiosSupportedFunctions` we can re-use that structure. pub bios: BiosState, pub aura: AuraState, pub anime: AnimeState, @@ -274,8 +306,8 @@ pub struct SystemState { pub gfx_state: GfxState, pub power_state: PowerState, pub error: Option, - /// Specific field for the tray only so that we can know when it does need update. - /// The tray should set this to false when done. + /// Specific field for the tray only so that we can know when it does need + /// update. The tray should set this to false when done. pub tray_should_update: bool, pub app_should_update: bool, pub asus_dbus: RogDbusClientBlocking<'static>, @@ -283,17 +315,28 @@ pub struct SystemState { } impl SystemState { - /// Creates self, including the relevant dbus connections and proixies for internal use + /// Creates self, including the relevant dbus connections and proixies for + /// internal use pub fn new( + layout_testing: Option, keyboard_layout: KeyLayout, + keyboard_layouts: Vec, enabled_notifications: Arc>, supported: &SupportedFunctions, ) -> Result { let (asus_dbus, conn) = RogDbusClientBlocking::new()?; let mut error = None; let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd"); + let aura = AuraState::new(&keyboard_layout, &asus_dbus) + .map_err(|e| { + let e = format!("Could not get AuraState state: {e}"); + error!("{e}"); + error = Some(e); + }) + .unwrap_or_default(); + Ok(Self { - keyboard_layout, + aura_creation: AuraCreation::new(layout_testing, keyboard_layout, keyboard_layouts), enabled_notifications, power_state: PowerState::new(supported, &asus_dbus) .map_err(|e| { @@ -309,13 +352,7 @@ impl SystemState { error = Some(e); }) .unwrap_or_default(), - aura: AuraState::new(supported, &asus_dbus) - .map_err(|e| { - let e = format!("Could not get AuraState state: {e}"); - error!("{e}"); - error = Some(e); - }) - .unwrap_or_default(), + aura, anime: AnimeState::new(supported, &asus_dbus) .map_err(|e| { let e = format!("Could not get AanimeState state: {e}"); @@ -364,7 +401,13 @@ impl Default for SystemState { let gfx_dbus = GfxProxyBlocking::new(&conn).expect("Couldn't connect to supergfxd"); Self { - keyboard_layout: KeyLayout::ga401_layout(), + aura_creation: AuraCreation { + layout_testing: None, + layout_last_modified: SystemTime::now(), + keyboard_layout: KeyLayout::default_layout(), + keyboard_layouts: Default::default(), + keyboard_layout_index: 0, + }, enabled_notifications: Default::default(), bios: BiosState { post_sound: Default::default(), diff --git a/rog-control-center/src/tray.rs b/rog-control-center/src/tray.rs index d2399f9e..6b3261e3 100644 --- a/rog-control-center/src/tray.rs +++ b/rog-control-center/src/tray.rs @@ -1,28 +1,25 @@ //! A seld-contained tray icon with menus. The control of app<->tray is done via //! commands over an MPSC channel. -use std::{ - io::Write, - sync::{ - atomic::{AtomicBool, Ordering}, - mpsc::{channel, Receiver}, - Arc, Mutex, - }, - time::Duration, -}; +use std::io::Write; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::mpsc::{channel, Receiver}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; -use gtk::{gio::Icon, prelude::*}; -use rog_dbus::zbus_platform::RogBiosProxyBlocking; -use rog_platform::{platform::GpuMode, supported::SupportedFunctions}; - -use crate::{error::Result, get_ipc_file, system_state::SystemState, SHOW_GUI}; +use gtk::gio::Icon; +use gtk::prelude::*; use libappindicator::{AppIndicator, AppIndicatorStatus}; -use supergfxctl::{ - pci_device::{GfxMode, GfxPower}, - zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking, -}; - use log::{debug, error, info, trace, warn}; +use rog_dbus::zbus_platform::RogBiosProxyBlocking; +use rog_platform::platform::GpuMode; +use rog_platform::supported::SupportedFunctions; +use supergfxctl::pci_device::{GfxMode, GfxPower}; +use supergfxctl::zbus_proxy::DaemonProxyBlocking as GfxProxyBlocking; + +use crate::error::Result; +use crate::system_state::SystemState; +use crate::{get_ipc_file, SHOW_GUI}; const TRAY_APP_ICON: &str = "rog-control-center"; const TRAY_LABEL: &str = "ROG Control Center"; @@ -433,7 +430,8 @@ impl ROGTray { debug!("ROGTray: cleared self"); } - /// Reset GTK menu to internal state, this can be called after clearing and rebuilding the menu too. + /// Reset GTK menu to internal state, this can be called after clearing and + /// rebuilding the menu too. fn menu_update(&mut self) { self.tray.set_menu(&mut self.menu); self.set_icon(self.icon); diff --git a/rog-control-center/src/update_and_notify.rs b/rog-control-center/src/update_and_notify.rs index 8846a7da..7a9bf25b 100644 --- a/rog-control-center/src/update_and_notify.rs +++ b/rog-control-center/src/update_and_notify.rs @@ -1,27 +1,31 @@ -//! `update_and_notify` is responsible for both notifications *and* updating stored statuses -//! about the system state. This is done through either direct, intoify, zbus notifications -//! or similar methods. +//! `update_and_notify` is responsible for both notifications *and* updating +//! stored statuses about the system state. This is done through either direct, +//! intoify, zbus notifications or similar methods. + +use std::fmt::Display; +use std::process::Command; +use std::sync::{Arc, Mutex}; +use std::time::Duration; -use crate::{config::Config, error::Result, system_state::SystemState}; use log::{error, info, trace, warn}; use notify_rust::{Hint, Notification, NotificationHandle, Urgency}; -use rog_dbus::{ - zbus_anime::AnimeProxy, zbus_led::LedProxy, zbus_platform::RogBiosProxy, - zbus_power::PowerProxy, zbus_profile::ProfileProxy, -}; +use rog_dbus::zbus_anime::AnimeProxy; +use rog_dbus::zbus_led::LedProxy; +use rog_dbus::zbus_platform::RogBiosProxy; +use rog_dbus::zbus_power::PowerProxy; +use rog_dbus::zbus_profile::ProfileProxy; use rog_platform::platform::GpuMode; use rog_profiles::Profile; use serde::{Deserialize, Serialize}; -use std::{ - fmt::Display, - process::Command, - sync::{Arc, Mutex}, - time::Duration, -}; -use supergfxctl::{pci_device::GfxPower, zbus_proxy::DaemonProxy as SuperProxy}; +use supergfxctl::pci_device::GfxPower; +use supergfxctl::zbus_proxy::DaemonProxy as SuperProxy; use tokio::time::sleep; use zbus::export::futures_util::{future, StreamExt}; +use crate::config::Config; +use crate::error::Result; +use crate::system_state::SystemState; + const NOTIF_HEADER: &str = "ROG Control"; static mut POWER_AC_CMD: Option = None; @@ -356,7 +360,8 @@ pub fn start_notifications( if status != GfxPower::Unknown && status != last_status { if let Ok(config) = notifs_enabled1.lock() { if config.all_enabled && config.receive_notify_gfx_status { - // Required check because status cycles through active/unknown/suspended + // Required check because status cycles through + // active/unknown/suspended if let Ok(ref mut lock) = last_notif.lock() { notify!( do_gpu_status_notif( diff --git a/rog-control-center/src/widgets/app_settings.rs b/rog-control-center/src/widgets/app_settings.rs index bf1f3809..d822014d 100644 --- a/rog-control-center/src/widgets/app_settings.rs +++ b/rog-control-center/src/widgets/app_settings.rs @@ -1,6 +1,7 @@ use egui::Ui; -use crate::{config::Config, system_state::SystemState}; +use crate::config::Config; +use crate::system_state::SystemState; pub fn app_settings(config: &mut Config, states: &mut SystemState, ui: &mut Ui) { ui.heading("ROG GUI Settings"); diff --git a/rog-control-center/src/widgets/aura_modes.rs b/rog-control-center/src/widgets/aura_modes.rs index d172b6dd..70be2c7c 100644 --- a/rog-control-center/src/widgets/aura_modes.rs +++ b/rog-control-center/src/widgets/aura_modes.rs @@ -1,42 +1,41 @@ -use std::sync::{ - atomic::{AtomicU8, Ordering}, - Arc, -}; +use std::sync::atomic::{AtomicU8, Ordering}; +use std::sync::Arc; use egui::{RichText, Ui}; +use rog_aura::layouts::KeyLayout; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Speed}; -use rog_platform::supported::SupportedFunctions; use crate::system_state::{AuraState, SystemState}; -pub fn aura_modes_group( - supported: &SupportedFunctions, - states: &mut SystemState, - freq: &mut Arc, - ui: &mut Ui, -) { +pub fn aura_modes_group(states: &mut SystemState, freq: &mut Arc, ui: &mut Ui) { let mut changed = false; let mut selected = states.aura.current_mode; let allowed = AuraEffect::allowed_parameters(selected); - let has_keyzones = supported - .keyboard_led - .multizone_led_mode + let SystemState { aura_creation, .. } = states; + + let has_keyzones = aura_creation + .keyboard_layout + .basic_zones() .contains(&AuraZone::Key2); - let has_logo = supported - .keyboard_led - .multizone_led_mode + let has_logo = aura_creation + .keyboard_layout + .basic_zones() .contains(&AuraZone::Logo); - let has_lightbar = supported - .keyboard_led - .multizone_led_mode + let has_lightbar = aura_creation + .keyboard_layout + .basic_zones() .contains(&AuraZone::BarLeft) - || supported - .keyboard_led - .multizone_led_mode + || aura_creation + .keyboard_layout + .basic_zones() .contains(&AuraZone::BarRight); - ui.heading("Aura modes"); + if let Some(p) = aura_creation.layout_testing.as_ref() { + ui.heading(format!("{p:?}")); + } else { + ui.heading("Aura modes"); + } let mut item = |a: AuraModeNum, ui: &mut Ui| { if ui .selectable_value(&mut selected, a, format!("{:?}", a)) @@ -168,7 +167,7 @@ pub fn aura_modes_group( ui.separator(); ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { if ui.add(egui::Button::new("Cancel")).clicked() { - match AuraState::new(supported, &states.asus_dbus) { + match AuraState::new(&aura_creation.keyboard_layout, &states.asus_dbus) { Ok(a) => states.aura.modes = a.modes, Err(e) => states.error = Some(e.to_string()), } @@ -177,6 +176,32 @@ pub fn aura_modes_group( if ui.add(egui::Button::new("Apply")).clicked() { changed = true; } + + if aura_creation.layout_testing.is_some() { + if ui.add(egui::Button::new("Next layout")).clicked() { + if aura_creation.keyboard_layout_index < aura_creation.keyboard_layouts.len() - 1 { + aura_creation.keyboard_layout_index += 1; + } + aura_creation.layout_testing = Some( + aura_creation.keyboard_layouts[aura_creation.keyboard_layout_index].clone(), + ); + aura_creation.keyboard_layout = + KeyLayout::from_file(aura_creation.layout_testing.as_ref().unwrap().as_path()) + .unwrap(); + } + + if ui.add(egui::Button::new("Prev layout")).clicked() { + if aura_creation.keyboard_layout_index > 0 { + aura_creation.keyboard_layout_index -= 1; + } + aura_creation.layout_testing = Some( + aura_creation.keyboard_layouts[aura_creation.keyboard_layout_index].clone(), + ); + aura_creation.keyboard_layout = + KeyLayout::from_file(aura_creation.layout_testing.as_ref().unwrap().as_path()) + .unwrap(); + } + } }); // egui::TopBottomPanel::bottom("error_bar") @@ -185,8 +210,8 @@ pub fn aura_modes_group( // ui.with_layout(egui::Layout::right_to_left(egui::Align::TOP), |ui| { // if ui.add(egui::Button::new("Cancel")).clicked() { // let notif = states.aura.was_notified.clone(); - // states.aura.modes = AuraState::new(notif, supported, dbus).modes; - // } + // states.aura.modes = AuraState::new(notif, supported, + // dbus).modes; } // if ui.add(egui::Button::new("Apply")).clicked() { // changed = true; diff --git a/rog-control-center/src/widgets/aura_power.rs b/rog-control-center/src/widgets/aura_power.rs index 54eb162c..d5afe702 100644 --- a/rog-control-center/src/widgets/aura_power.rs +++ b/rog-control-center/src/widgets/aura_power.rs @@ -1,8 +1,6 @@ use egui::{RichText, Ui}; -use rog_aura::{ - usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}, - AuraZone, -}; +use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; +use rog_aura::AuraZone; use rog_platform::supported::SupportedFunctions; use crate::system_state::SystemState; @@ -10,7 +8,7 @@ use crate::system_state::SystemState; pub fn aura_power_group(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) { ui.heading("LED settings"); - match supported.keyboard_led.prod_id { + match supported.keyboard_led.dev_id { AuraDevice::X1854 | AuraDevice::X1869 | AuraDevice::X1866 => { aura_power1(supported, states, ui); } @@ -26,7 +24,7 @@ fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu let mut sleep = enabled_states.x1866.contains(&AuraDev1866::Sleep); let mut keyboard = enabled_states.x1866.contains(&AuraDev1866::Keyboard); let mut lightbar = enabled_states.x1866.contains(&AuraDev1866::Lightbar); - if supported.keyboard_led.prod_id == AuraDevice::Tuf { + if supported.keyboard_led.dev_id == AuraDevice::Tuf { boot = enabled_states.tuf.contains(&AuraDevTuf::Boot); sleep = enabled_states.tuf.contains(&AuraDevTuf::Sleep); keyboard = enabled_states.tuf.contains(&AuraDevTuf::Awake); @@ -63,7 +61,7 @@ fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu if ui.toggle_value(&mut keyboard, "Keyboard").changed() { changed = true; } - if !supported.keyboard_led.multizone_led_mode.is_empty() + if !supported.keyboard_led.basic_zones.is_empty() && ui.toggle_value(&mut lightbar, "Lightbar").changed() { changed = true; @@ -84,8 +82,8 @@ fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu // )) // .changed() // { - // let bright = LedBrightness::from(states.aura.bright as u32); - // dbus.proxies() + // let bright = LedBrightness::from(states.aura.bright as + // u32); dbus.proxies() // .led() // .set_brightness(bright) // .map_err(|err| { @@ -98,7 +96,7 @@ fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu }); if changed { - if supported.keyboard_led.prod_id == AuraDevice::Tuf { + if supported.keyboard_led.dev_id == AuraDevice::Tuf { let mut enabled = Vec::new(); let mut disabled = Vec::new(); @@ -174,7 +172,7 @@ fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu modify_x1866(boot, AuraDev1866::Boot); modify_x1866(sleep, AuraDev1866::Sleep); modify_x1866(keyboard, AuraDev1866::Keyboard); - if !supported.keyboard_led.multizone_led_mode.is_empty() { + if !supported.keyboard_led.basic_zones.is_empty() { modify_x1866(lightbar, AuraDev1866::Lightbar); } @@ -203,17 +201,14 @@ fn aura_power1(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu fn aura_power2(supported: &SupportedFunctions, states: &mut SystemState, ui: &mut Ui) { let enabled_states = &mut states.aura.enabled; - let has_logo = supported - .keyboard_led - .multizone_led_mode - .contains(&AuraZone::Logo); + let has_logo = supported.keyboard_led.basic_zones.contains(&AuraZone::Logo); let has_lightbar = supported .keyboard_led - .multizone_led_mode + .basic_zones .contains(&AuraZone::BarLeft) || supported .keyboard_led - .multizone_led_mode + .basic_zones .contains(&AuraZone::BarRight); let boot_bar = &mut enabled_states.x19b6.contains(&AuraDev19b6::AwakeBar); @@ -294,18 +289,14 @@ fn aura_power2(supported: &SupportedFunctions, states: &mut SystemState, ui: &mu modify(*boot_keyb, AuraDev19b6::BootKeyb); modify(*sleep_keyb, AuraDev19b6::SleepKeyb); modify(*awake_keyb, AuraDev19b6::AwakeKeyb); - if supported - .keyboard_led - .multizone_led_mode - .contains(&AuraZone::Logo) - { + if supported.keyboard_led.basic_zones.contains(&AuraZone::Logo) { modify(*boot_logo, AuraDev19b6::BootLogo); modify(*sleep_logo, AuraDev19b6::SleepLogo); modify(*awake_logo, AuraDev19b6::AwakeLogo); } if supported .keyboard_led - .multizone_led_mode + .basic_zones .contains(&AuraZone::BarLeft) { modify(*boot_bar, AuraDev19b6::AwakeBar); diff --git a/rog-control-center/src/widgets/fan_graph.rs b/rog-control-center/src/widgets/fan_graph.rs index 584ad397..a51711cc 100644 --- a/rog-control-center/src/widgets/fan_graph.rs +++ b/rog-control-center/src/widgets/fan_graph.rs @@ -1,8 +1,10 @@ -use egui::{plot::Points, Ui}; +use egui::plot::Points; +use egui::Ui; use rog_platform::supported::SupportedFunctions; use rog_profiles::{FanCurvePU, Profile}; -use crate::{system_state::FanCurvesState, RogDbusClientBlocking}; +use crate::system_state::FanCurvesState; +use crate::RogDbusClientBlocking; pub fn fan_graphs( supported: &SupportedFunctions, diff --git a/rog-control-center/src/widgets/keyboard_layout.rs b/rog-control-center/src/widgets/keyboard_layout.rs index e5dcc7a6..3597cbc9 100644 --- a/rog-control-center/src/widgets/keyboard_layout.rs +++ b/rog-control-center/src/widgets/keyboard_layout.rs @@ -1,59 +1,152 @@ -use egui::{Align, Color32, Vec2}; -use rog_aura::{keys::KeyShape, layouts::KeyLayout, AuraModeNum}; +use egui::{Color32, Pos2}; +use rog_aura::advanced::LedCode; +use rog_aura::layouts::{KeyLayout, KeyShape}; +use rog_aura::{AdvancedAuraType, AuraModeNum}; use crate::system_state::AuraState; +const SCALE: f32 = 2.0; + +// TODO: +// - Multizone: draw regions? While iterating keys check if located in one of +// the 4 regions and mark +// - Tab for advanced effects +// - Keys need to select colour themselves + pub fn keyboard( ui: &mut egui::Ui, keyboard_layout: &KeyLayout, states: &mut AuraState, - mut colour: Color32, + colour: Color32, ) { + let mut key_colour = colour; + let mut input_colour = colour; + let (keyboard_is_multizoned, keyboard_width, keyboard_is_per_key) = + match keyboard_layout.advanced_type() { + AdvancedAuraType::PerKey => (false, 0.0, true), + AdvancedAuraType::None => (false, keyboard_layout.max_width(), false), + AdvancedAuraType::Zoned(zones) => { + let width = if let Some(row) = keyboard_layout.rows_ref().get(2) { + row.width() as f32 + } else { + 0.0 + }; + (!zones.contains(&LedCode::SingleZone), width, false) + } + }; + let mut start_pos = None; + + let y = ui.spacing().interact_size.y; + let this_size = ui.available_size(); + let keys_width = keyboard_layout.max_width() * SCALE * y; + let keys_height = keyboard_layout.max_height() * SCALE * y; + let x_start = (this_size.x - keys_width) / SCALE; + let y_start = (this_size.y - keys_height) / SCALE; + ui.spacing_mut().item_spacing = egui::vec2(0.0, 0.0); - let mut arrows_done = false; - let mut rog_done = false; + blank(ui, 0.0, y_start / y); + // Need to exclude the lightbar row if there is one + let mut keyboard_height = 0.0; for row in keyboard_layout.rows() { ui.horizontal_top(|ui| { + blank(ui, x_start / y, 0.0); for (i, key) in row.row().enumerate() { + if !key.0.is_lightbar_zone() && i == 0 { + keyboard_height += row.height() as f32 * SCALE; + } if states.current_mode == AuraModeNum::Rainbow { - colour = Color32::from_rgb( + key_colour = Color32::from_rgb( (states.wave_red[i] as u32 * 255 / 100) as u8, (states.wave_green[i] as u32 * 255 / 100) as u8, (states.wave_blue[i] as u32 * 255 / 100) as u8, ); } - // your boat - let height = if rog_done { - row.height() - } else { - // Use the first item (always a blank) to stand off the row - rog_done = true; - 1.2 - }; - let shape = KeyShape::from(key); + if (keyboard_is_multizoned && !key.0.is_lightbar_zone()) + && states.current_mode == AuraModeNum::Rainbow + { + input_colour = key_colour; + key_colour = Color32::TRANSPARENT; + } - let label = <&str>::from(key); - if shape.is_arrow_cluster() { - if !arrows_done { - arrow_cluster(ui, colour); - arrows_done = true; + let label = <&str>::from(key.0); + let mut shape = key.1.clone(); + shape.scale(SCALE); + + match shape { + KeyShape::Led { + width, + height, + pad_left, + pad_right, + pad_top, + pad_bottom, + } => { + let (pos, response) = key_shape( + ui, key_colour, width, height, pad_left, pad_right, pad_top, pad_bottom, + ); + if start_pos.is_none() { + start_pos = Some(pos); + } else if let Some(old_pos) = start_pos.as_mut() { + if !key.0.is_lightbar_zone() { + if pos.x < old_pos.x { + old_pos.x = pos.x; + } + if pos.y < old_pos.y { + old_pos.y = pos.y; + } + } + } + if response.on_hover_text(label).clicked() && keyboard_is_per_key { + // TODO: set an effect on the LedCode + } + } + KeyShape::Blank { width, height } => { + blank(ui, width, height); } - } else if shape.is_blank() || shape.is_spacer() { - blank(ui, shape.width(), height); - } else if shape.is_group() { - key_group(ui, colour, shape.width(), height).on_hover_text(label); - } else { - key_shape(ui, colour, shape.width(), height).on_hover_text(label); } } }); } + + if keyboard_is_multizoned { + let zone_width = keyboard_width * SCALE / 4.0 - 0.1; + for n in 0..4 { + if states.current_mode == AuraModeNum::Rainbow { + input_colour = Color32::from_rgba_unmultiplied( + (states.wave_red[n] as u32 * 255 / 100) as u8, + (states.wave_green[n] as u32 * 255 / 100) as u8, + (states.wave_blue[n] as u32 * 255 / 100) as u8, + 70, + ); + } + if let Some(mut pos) = start_pos { + pos.x += n as f32 * zone_width * y; + let response = zone_shape(ui, input_colour, pos, zone_width, keyboard_height); + let label = format!("Zone {}", 1 + n); + if response.on_hover_text(label).clicked() { + // TODO: set an effect on the zone + } + } + } + } } -fn key_shape(ui: &mut egui::Ui, colour: Color32, ux: f32, uy: f32) -> egui::Response { - let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0 * ux, 2.0 * uy); +#[allow(clippy::too_many_arguments)] +fn key_shape( + ui: &mut egui::Ui, + colour: Color32, + width: f32, + height: f32, + pad_left: f32, + pad_right: f32, + pad_top: f32, + pad_bottom: f32, +) -> (egui::Pos2, egui::Response) { + // First, get some space + let y = ui.spacing().interact_size.y; + let desired_size = y * egui::vec2(width + pad_left + pad_right, height + pad_top + pad_bottom); let (mut rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click()); - rect = rect.shrink(3.0); + // rect = rect.shrink(3.0); if response.clicked() { response.mark_changed(); } @@ -62,62 +155,56 @@ fn key_shape(ui: &mut egui::Ui, colour: Color32, ux: f32, uy: f32) -> egui::Resp }); if ui.is_rect_visible(rect) { + // Now set the actual visible rect let visuals = ui.style().interact_selectable(&response, true); - let rect = rect.expand(visuals.expansion); + let size = y * egui::vec2(width, height); + rect.set_width(size.x); + rect.set_height(size.y); + let center = Pos2::new( + rect.center().x + pad_left * y, + rect.center().y + pad_top * y, + ); + rect.set_center(center); + // let rect = rect.expand(visuals.expansion); + ui.painter().rect(rect, 0.1, colour, visuals.fg_stroke); + } + + (rect.left_top(), response) +} + +#[allow(clippy::too_many_arguments)] +fn zone_shape( + ui: &mut egui::Ui, + mut colour: Color32, + pos: Pos2, + width: f32, + height: f32, +) -> egui::Response { + // First, get some space + let y = ui.spacing().interact_size.y; + let desired_size = y * egui::vec2(width, height); + let rect = egui::Rect::from_min_size(pos, desired_size); + let mut response = ui.allocate_rect(rect, egui::Sense::click()); + // rect = rect.shrink(3.0); + if response.clicked() { + response.mark_changed(); + } + response.widget_info(|| { + egui::WidgetInfo::selected(egui::WidgetType::Checkbox, response.clicked(), "") + }); + + if ui.is_rect_visible(rect) { + // Now set the actual visible rect + let visuals = ui.style().interact_selectable(&response, true); + // let rect = rect.expand(visuals.expansion); + colour[3] = 20; ui.painter().rect(rect, 0.1, colour, visuals.fg_stroke); } response } -fn key_group(ui: &mut egui::Ui, colour: Color32, ux: f32, uy: f32) -> egui::Response { - let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0 * ux, 2.0 * uy); - let (mut rect, mut response) = ui.allocate_exact_size(desired_size, egui::Sense::click()); - rect = rect.shrink2(Vec2::new(3.0, 3.0)); - if response.clicked() { - response.mark_changed(); - } - response.widget_info(|| { - egui::WidgetInfo::selected(egui::WidgetType::Checkbox, response.clicked(), "") - }); - - if ui.is_rect_visible(rect) { - let visuals = ui.style().interact_selectable(&response, true); - let rect = rect.expand(visuals.expansion); - let mut stroke = visuals.fg_stroke; - stroke.color = visuals.bg_fill; - ui.painter().rect(rect, 0.1, colour, stroke); - } - - response -} - fn blank(ui: &mut egui::Ui, ux: f32, uy: f32) { - let desired_size = ui.spacing().interact_size.y * egui::vec2(2.0 * ux, 2.0 * uy); + let desired_size = ui.spacing().interact_size.y * egui::vec2(ux, uy); ui.allocate_exact_size(desired_size, egui::Sense::click()); } - -/// Draws entire arrow cluster block. This is visibly different to the split-arrows. -fn arrow_cluster(ui: &mut egui::Ui, colour: Color32) { - let height = 0.7; - let space = KeyShape::ArrowSpacer; - let shape = KeyShape::Arrow; - ui.horizontal_top(|ui| { - ui.with_layout(egui::Layout::top_down(Align::LEFT), |ui| { - blank(ui, space.width(), height); - ui.horizontal(|ui| { - blank(ui, KeyShape::RowEndSpacer.width(), height); - blank(ui, KeyShape::RowEndSpacer.width(), height); - key_shape(ui, colour, shape.width(), height).on_hover_text("Left"); - }); - }); - ui.with_layout(egui::Layout::top_down(Align::LEFT), |ui| { - key_shape(ui, colour, shape.width(), height).on_hover_text("Up"); - key_shape(ui, colour, shape.width(), height).on_hover_text("Down"); - }); - ui.with_layout(egui::Layout::top_down(Align::LEFT), |ui| { - blank(ui, space.width(), height); - key_shape(ui, colour, shape.width(), height).on_hover_text("Right"); - }); - }); -} diff --git a/rog-control-center/src/widgets/rog_bios.rs b/rog-control-center/src/widgets/rog_bios.rs index 8bdeb100..7a22039d 100644 --- a/rog-control-center/src/widgets/rog_bios.rs +++ b/rog-control-center/src/widgets/rog_bios.rs @@ -1,8 +1,10 @@ -use crate::system_state::SystemState; use egui::Ui; -use rog_platform::{platform::GpuMode, supported::SupportedFunctions}; +use rog_platform::platform::GpuMode; +use rog_platform::supported::SupportedFunctions; use rog_profiles::Profile; +use crate::system_state::SystemState; + pub fn platform_profile(states: &mut SystemState, ui: &mut Ui) { ui.heading("Platform profile"); diff --git a/rog-control-center/src/widgets/side_panel.rs b/rog-control-center/src/widgets/side_panel.rs index 40c14a23..b90792f5 100644 --- a/rog-control-center/src/widgets/side_panel.rs +++ b/rog-control-center/src/widgets/side_panel.rs @@ -28,7 +28,7 @@ impl RogApp { } } - if !self.supported.keyboard_led.stock_led_modes.is_empty() { + if !self.supported.keyboard_led.basic_modes.is_empty() { ui.separator(); if ui .selectable_value(page, Page::AuraEffects, "Keyboard Aura") diff --git a/rog-control-center/src/widgets/top_bar.rs b/rog-control-center/src/widgets/top_bar.rs index cc062bca..fd727034 100644 --- a/rog-control-center/src/widgets/top_bar.rs +++ b/rog-control-center/src/widgets/top_bar.rs @@ -12,7 +12,6 @@ impl RogApp { egui::warn_if_debug_build(ui); }); - /***********************************************************/ // Drag area let text_color = ctx.style().visuals.text_color(); let mut titlebar_rect = ui.available_rect_before_wrap(); @@ -23,8 +22,9 @@ impl RogApp { { frame.drag_window(); } - /***********************************************************/ + let height = titlebar_rect.height(); + // Paint the title: ui.painter().text( titlebar_rect.right_top() + vec2(0.0, height / 2.0), @@ -35,9 +35,10 @@ impl RogApp { ); // // Add the close button: // let close_response = ui.put( - // Rect::from_min_size(titlebar_rect.right_top(), Vec2::splat(height)), - // Button::new(RichText::new("❌").size(height - 4.0)).frame(false), - // ); + // Rect::from_min_size(titlebar_rect.right_top(), + // Vec2::splat(height)), + // Button::new(RichText::new("❌").size(height - + // 4.0)).frame(false), ); // if close_response.clicked() { // frame.close(); // } diff --git a/rog-dbus/src/zbus_anime.rs b/rog-dbus/src/zbus_anime.rs index fa129faa..228a0830 100644 --- a/rog-dbus/src/zbus_anime.rs +++ b/rog-dbus/src/zbus_anime.rs @@ -15,7 +15,8 @@ trait Anime { /// Set whether the AniMe is displaying images/data fn set_on_off(&self, status: bool) -> zbus::Result<()>; - /// Writes a data stream of length. Will force system thread to exit until it is restarted + /// Writes a data stream of length. Will force system thread to exit until + /// it is restarted fn write(&self, input: AnimeDataBuffer) -> zbus::Result<()>; /// Get status of if the AniMe LEDs are on @@ -26,7 +27,8 @@ trait Anime { #[dbus_proxy(property)] fn boot_enabled(&self) -> zbus::Result; - /// Notify listeners of the status of AniMe LED power and factory system-status animations + /// Notify listeners of the status of AniMe LED power and factory + /// system-status animations #[dbus_proxy(signal)] fn power_states(&self, data: AnimePowerStates) -> zbus::Result<()>; } diff --git a/rog-dbus/src/zbus_led.rs b/rog-dbus/src/zbus_led.rs index 0f7b4cf5..17f2bdd2 100644 --- a/rog-dbus/src/zbus_led.rs +++ b/rog-dbus/src/zbus_led.rs @@ -1,7 +1,8 @@ //! # DBus interface proxy for: `org.asuslinux.Daemon` //! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Aura' from service 'org.asuslinux.Daemon' on system bus`. +//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection +//! data. Source: `Interface '/org/asuslinux/Aura' from service +//! 'org.asuslinux.Daemon' on system bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! @@ -21,12 +22,13 @@ use std::collections::BTreeMap; -use zbus::dbus_proxy; -use zbus::{blocking::Connection, Result}; +use rog_aura::advanced::UsbPackets; +use rog_aura::usb::AuraPowerDev; +use rog_aura::{AuraEffect, AuraModeNum, LedBrightness}; +use zbus::blocking::Connection; +use zbus::{dbus_proxy, Result}; -use rog_aura::{usb::AuraPowerDev, AuraEffect, AuraModeNum, LedBrightness, PerKeyRaw}; - -const BLOCKING_TIME: u64 = 40; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS +const BLOCKING_TIME: u64 = 33; // 100ms = 10 FPS, max 50ms = 20 FPS, 40ms = 25 FPS #[dbus_proxy( interface = "org.asuslinux.Daemon", @@ -53,7 +55,10 @@ trait Led { fn set_leds_power(&self, options: AuraPowerDev, enabled: bool) -> zbus::Result<()>; - fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()>; + /// On machine that have some form of either per-key keyboard or per-zone + /// this can be used to write custom effects over dbus. The input is a + /// nested `Vec>` where `Vec` is a raw USB packet + fn direct_addressing_raw(&self, data: UsbPackets) -> zbus::fdo::Result<()>; /// NotifyLed signal #[dbus_proxy(signal)] @@ -95,8 +100,8 @@ impl<'a> LedProxyPerkey<'a> { /// Intentionally blocks for 10ms after sending to allow the block to /// be written to the keyboard EC. This should not be async. #[inline] - pub fn set_per_key(&self, per_key_raw: PerKeyRaw) -> Result<()> { - self.0.per_key_raw(per_key_raw)?; + pub fn direct_addressing_raw(&self, direct_raw: UsbPackets) -> Result<()> { + self.0.direct_addressing_raw(direct_raw)?; std::thread::sleep(std::time::Duration::from_millis(BLOCKING_TIME)); Ok(()) } diff --git a/rog-dbus/src/zbus_platform.rs b/rog-dbus/src/zbus_platform.rs index 498a724d..b59e8f5f 100644 --- a/rog-dbus/src/zbus_platform.rs +++ b/rog-dbus/src/zbus_platform.rs @@ -1,7 +1,8 @@ //! # DBus interface proxy for: `org.asuslinux.Daemon` //! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Platform' from service 'org.asuslinux.Daemon' on system bus`. +//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection +//! data. Source: `Interface '/org/asuslinux/Platform' from service +//! 'org.asuslinux.Daemon' on system bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! diff --git a/rog-dbus/src/zbus_power.rs b/rog-dbus/src/zbus_power.rs index 55160737..3a16e34e 100644 --- a/rog-dbus/src/zbus_power.rs +++ b/rog-dbus/src/zbus_power.rs @@ -1,7 +1,8 @@ //! # DBus interface proxy for: `org.asuslinux.Daemon` //! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Charge' from service 'org.asuslinux.Daemon' on system bus`. +//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection +//! data. Source: `Interface '/org/asuslinux/Charge' from service +//! 'org.asuslinux.Daemon' on system bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! diff --git a/rog-dbus/src/zbus_profile.rs b/rog-dbus/src/zbus_profile.rs index 2f340c08..24a58b5d 100644 --- a/rog-dbus/src/zbus_profile.rs +++ b/rog-dbus/src/zbus_profile.rs @@ -1,7 +1,8 @@ //! # DBus interface proxy for: `org.asuslinux.Daemon` //! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Profile' from service 'org.asuslinux.Daemon' on system bus`. +//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection +//! data. Source: `Interface '/org/asuslinux/Profile' from service +//! 'org.asuslinux.Daemon' on system bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! @@ -19,10 +20,8 @@ //! //! …consequently `zbus-xmlgen` did not generate code for the above interfaces. -use rog_profiles::{ - fan_curve_set::{CurveData, FanCurveSet}, - Profile, -}; +use rog_profiles::fan_curve_set::{CurveData, FanCurveSet}; +use rog_profiles::Profile; use zbus::dbus_proxy; #[dbus_proxy( @@ -56,16 +55,18 @@ trait Profile { /// currently in if profile == None. Will also activate the fan curve. fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::Result<()>; - /// Reset the stored (self) and device curve to the defaults of the platform. + /// Reset the stored (self) and device curve to the defaults of the + /// platform. /// - /// Each platform_profile has a different default and the defualt can be read - /// only for the currently active profile. + /// Each platform_profile has a different default and the defualt can be + /// read only for the currently active profile. fn set_active_curve_to_defaults(&self) -> zbus::Result<()>; - /// Reset the stored (self) and device curve to the defaults of the platform. + /// Reset the stored (self) and device curve to the defaults of the + /// platform. /// - /// Each platform_profile has a different default and the defualt can be read - /// only for the currently active profile. + /// Each platform_profile has a different default and the defualt can be + /// read only for the currently active profile. fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()>; /// NotifyProfile signal diff --git a/rog-dbus/src/zbus_supported.rs b/rog-dbus/src/zbus_supported.rs index 649e5f5d..4862ca2c 100644 --- a/rog-dbus/src/zbus_supported.rs +++ b/rog-dbus/src/zbus_supported.rs @@ -1,7 +1,8 @@ //! # DBus interface proxy for: `org.asuslinux.Daemon` //! -//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection data. -//! Source: `Interface '/org/asuslinux/Supported' from service 'org.asuslinux.Daemon' on system bus`. +//! This code was generated by `zbus-xmlgen` `1.0.0` from DBus introspection +//! data. Source: `Interface '/org/asuslinux/Supported' from service +//! 'org.asuslinux.Daemon' on system bus`. //! //! You may prefer to adapt it, instead of using it verbatim. //! diff --git a/rog-platform/src/error.rs b/rog-platform/src/error.rs index 992e8a5b..e8c14ab8 100644 --- a/rog-platform/src/error.rs +++ b/rog-platform/src/error.rs @@ -36,7 +36,12 @@ impl fmt::Display for PlatformError { PlatformError::AttrNotFound(deets) => write!(f, "Attribute not found: {}", deets), PlatformError::Io(deets) => write!(f, "std::io error: {}", deets), PlatformError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), - PlatformError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), + PlatformError::MissingLedBrightNode(path, error) => write!( + f, + "Led node at {} is missing, please check you have the required patch or dkms \ + module installed: {}", + path, error + ), PlatformError::IoPath(path, detail) => write!(f, "{} {}", path, detail), PlatformError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), PlatformError::NoAuraNode => write!(f, "No Aura keyboard node found"), diff --git a/rog-platform/src/hid_raw.rs b/rog-platform/src/hid_raw.rs index 3d7d9f7f..46fbe994 100644 --- a/rog-platform/src/hid_raw.rs +++ b/rog-platform/src/hid_raw.rs @@ -1,4 +1,6 @@ -use std::{fs::OpenOptions, io::Write, path::PathBuf}; +use std::fs::OpenOptions; +use std::io::Write; +use std::path::PathBuf; use log::{info, warn}; diff --git a/rog-platform/src/keyboard_led.rs b/rog-platform/src/keyboard_led.rs index d5bba6a0..056091d1 100644 --- a/rog-platform/src/keyboard_led.rs +++ b/rog-platform/src/keyboard_led.rs @@ -2,11 +2,8 @@ use std::path::PathBuf; use log::{info, warn}; -use crate::{ - attr_u8, - error::{PlatformError, Result}, - has_attr, set_attr_u8_array, to_device, -}; +use crate::error::{PlatformError, Result}; +use crate::{attr_u8, has_attr, set_attr_u8_array, to_device}; #[derive(Debug, Default, PartialEq, Eq, PartialOrd, Clone)] pub struct KeyboardLed { @@ -14,6 +11,24 @@ pub struct KeyboardLed { } impl KeyboardLed { + attr_u8!("brightness", path); + + has_attr!("kbd_rgb_mode" path); + + set_attr_u8_array!( + /// kbd_rgb_mode can only be set, not read back + "kbd_rgb_mode" + path + ); + + has_attr!("kbd_rgb_state" path); + + set_attr_u8_array!( + /// kbd_rgb_state can only be set, not read back + "kbd_rgb_state" + path + ); + pub fn new() -> Result { let mut enumerator = udev::Enumerator::new().map_err(|err| { warn!("{}", err); @@ -47,20 +62,4 @@ impl KeyboardLed { "asus::kbd_backlight not found".into(), )) } - - attr_u8!("brightness", path); - - has_attr!("kbd_rgb_mode" path); - set_attr_u8_array!( - /// kbd_rgb_mode can only be set, not read back - "kbd_rgb_mode" - path - ); - - has_attr!("kbd_rgb_state" path); - set_attr_u8_array!( - /// kbd_rgb_state can only be set, not read back - "kbd_rgb_state" - path - ); } diff --git a/rog-platform/src/lib.rs b/rog-platform/src/lib.rs index c4c030d6..ffc3a89a 100644 --- a/rog-platform/src/lib.rs +++ b/rog-platform/src/lib.rs @@ -118,13 +118,13 @@ mod tests { // .parent_with_subsystem_devtype("usb", "usb_device") // .map_err(|err| { // warn!("{}", err); -// PlatformError::Udev("parent_with_subsystem_devtype failed".into(), err) -// })? +// PlatformError::Udev("parent_with_subsystem_devtype +// failed".into(), err) })? // { // if parent // .attribute_value("idProduct") -// .ok_or_else(|| PlatformError::NotFound("LED idProduct".into()))? -// == id_product +// .ok_or_else(|| PlatformError::NotFound("LED +// idProduct".into()))? == id_product // { // if let Some(dev_node) = device.devnode() { // info!("Using device at: {:?} for LED control", dev_node); diff --git a/rog-platform/src/platform.rs b/rog-platform/src/platform.rs index ef84db77..c208d653 100644 --- a/rog-platform/src/platform.rs +++ b/rog-platform/src/platform.rs @@ -1,14 +1,13 @@ -use std::{fmt::Display, path::PathBuf, str::FromStr}; +use std::fmt::Display; +use std::path::PathBuf; +use std::str::FromStr; use log::{info, warn}; use serde::{Deserialize, Serialize}; use zbus::zvariant::Type; -use crate::{ - attr_bool, attr_u8, - error::{PlatformError, Result}, - to_device, -}; +use crate::error::{PlatformError, Result}; +use crate::{attr_bool, attr_u8, to_device}; /// The "platform" device provides access to things like: /// - `dgpu_disable` @@ -24,6 +23,21 @@ pub struct AsusPlatform { } impl AsusPlatform { + attr_bool!("dgpu_disable", path); + + attr_bool!("egpu_enable", path); + + attr_bool!("panel_od", path); + + attr_bool!("gpu_mux_mode", path); + + // This is technically the same as `platform_profile` since both are tied + // in-kernel + attr_u8!("throttle_thermal_policy", path); + + // The acpi platform_profile support + attr_u8!("platform_profile", pp_path); + pub fn new() -> Result { let mut enumerator = udev::Enumerator::new().map_err(|err| { warn!("{}", err); @@ -54,15 +68,6 @@ impl AsusPlatform { "asus-nb-wmi not found".into(), )) } - - attr_bool!("dgpu_disable", path); - attr_bool!("egpu_enable", path); - attr_bool!("panel_od", path); - attr_bool!("gpu_mux_mode", path); - // This is technically the same as `platform_profile` since both are tied in-kernel - attr_u8!("throttle_thermal_policy", path); - // The acpi platform_profile support - attr_u8!("platform_profile", pp_path); } #[derive(Serialize, Deserialize, Default, Type, Debug, PartialEq, Eq, Clone, Copy)] diff --git a/rog-platform/src/power.rs b/rog-platform/src/power.rs index a4b80c4d..9c5ef43f 100644 --- a/rog-platform/src/power.rs +++ b/rog-platform/src/power.rs @@ -2,11 +2,8 @@ use std::path::PathBuf; use log::{info, warn}; -use crate::{ - attr_u8, - error::{PlatformError, Result}, - to_device, -}; +use crate::error::{PlatformError, Result}; +use crate::{attr_u8, to_device}; /// The "platform" device provides access to things like: /// - `dgpu_disable` @@ -23,9 +20,14 @@ pub struct AsusPower { } impl AsusPower { + attr_u8!("charge_control_end_threshold", battery); + + attr_u8!("online", mains); + /// When checking for battery this will look in order: /// - if attr `manufacturer` contains `asus` - /// - if attr `charge_control_end_threshold` exists and `energy_full_design` >= 50 watt + /// - if attr `charge_control_end_threshold` exists and `energy_full_design` + /// >= 50 watt /// - if syspath end conatins `BAT` /// - if attr `type` is `battery` (last resort) pub fn new() -> Result { @@ -62,7 +64,11 @@ impl AsusPower { .attribute_value("charge_control_end_threshold") .is_some() { - info!("Found battery power at {:?}, matched charge_control_end_threshold", device.sysname()); + info!( + "Found battery power at {:?}, matched \ + charge_control_end_threshold", + device.sysname() + ); battery = Some(device.syspath().to_path_buf()); } else if device.sysname().to_string_lossy().starts_with("BAT") { info!( @@ -100,7 +106,4 @@ impl AsusPower { "Did not find a battery".to_owned(), )) } - - attr_u8!("charge_control_end_threshold", battery); - attr_u8!("online", mains); } diff --git a/rog-platform/src/supported.rs b/rog-platform/src/supported.rs index 4c46e9ad..084977bb 100644 --- a/rog-platform/src/supported.rs +++ b/rog-platform/src/supported.rs @@ -1,6 +1,8 @@ -use rog_aura::{usb::AuraDevice, AuraModeNum, AuraZone}; -use serde_derive::{Deserialize, Serialize}; use std::fmt; + +use rog_aura::usb::AuraDevice; +use rog_aura::{AdvancedAuraType, AuraModeNum, AuraZone}; +use serde_derive::{Deserialize, Serialize}; use zbus::zvariant::Type; #[derive(Serialize, Deserialize, Type, Debug, Default, Clone)] @@ -26,13 +28,31 @@ pub struct PlatformProfileFunctions { pub fan_curves: bool, } +#[derive(Serialize, Deserialize, Default, Type, Debug, Clone)] +pub enum AdvancedAura { + #[default] + None, + Zoned, + PerKey, +} + +impl From for AdvancedAura { + fn from(a: AdvancedAuraType) -> Self { + match a { + AdvancedAuraType::None => Self::None, + AdvancedAuraType::Zoned(_) => Self::Zoned, + AdvancedAuraType::PerKey => Self::PerKey, + } + } +} + #[derive(Serialize, Deserialize, Type, Debug, Default, Clone)] pub struct LedSupportedFunctions { - pub prod_id: AuraDevice, - pub brightness_set: bool, - pub stock_led_modes: Vec, - pub multizone_led_mode: Vec, - pub per_key_led_mode: bool, + pub dev_id: AuraDevice, + pub brightness: bool, + pub basic_modes: Vec, + pub basic_zones: Vec, + pub advanced_type: AdvancedAura, } #[derive(Serialize, Deserialize, Type, Debug, Default, Clone)] @@ -46,7 +66,7 @@ pub struct RogBiosSupportedFunctions { impl fmt::Display for SupportedFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "{}", self.anime_ctrl)?; + writeln!(f, "\n{}", self.anime_ctrl)?; writeln!(f, "{}", self.charge_ctrl)?; writeln!(f, "{}", self.platform_profile)?; writeln!(f, "{}", self.keyboard_led)?; @@ -80,10 +100,11 @@ impl fmt::Display for PlatformProfileFunctions { impl fmt::Display for LedSupportedFunctions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "LED:")?; - writeln!(f, "\tBrightness control: {}", self.brightness_set)?; - writeln!(f, "\tStock LED modes: {:?}", self.stock_led_modes)?; - writeln!(f, "\tMultizone LED mode: {:?}", self.multizone_led_mode)?; - writeln!(f, "\tPer key LED mode: {}", self.per_key_led_mode) + writeln!(f, "\tDevice ID: {:?}", self.dev_id)?; + writeln!(f, "\tBrightness control: {}", self.brightness)?; + writeln!(f, "\tBasic modes: {:?}", self.basic_modes)?; + writeln!(f, "\tBasic zones: {:?}", self.basic_zones)?; + writeln!(f, "\tAdvanced modes: {:?}", self.advanced_type) } } impl fmt::Display for RogBiosSupportedFunctions { diff --git a/rog-platform/src/usb_raw.rs b/rog-platform/src/usb_raw.rs index b28db657..9670959d 100644 --- a/rog-platform/src/usb_raw.rs +++ b/rog-platform/src/usb_raw.rs @@ -1,6 +1,7 @@ -use rusb::{Device, DeviceHandle}; use std::time::Duration; +use rusb::{Device, DeviceHandle}; + use crate::error::{PlatformError, Result}; #[derive(Debug, PartialEq, Eq)] diff --git a/rog-profiles/src/fan_curve_set.rs b/rog-profiles/src/fan_curve_set.rs index eea11a02..fb47881a 100644 --- a/rog-profiles/src/fan_curve_set.rs +++ b/rog-profiles/src/fan_curve_set.rs @@ -1,10 +1,10 @@ use serde_derive::{Deserialize, Serialize}; - use udev::Device; #[cfg(feature = "dbus")] use zbus::zvariant::Type; -use crate::{error::ProfileError, FanCurvePU}; +use crate::error::ProfileError; +use crate::FanCurvePU; pub(crate) fn pwm_str(fan: char, index: usize) -> String { let mut buf = "pwm1_auto_point1_pwm".to_string(); @@ -62,12 +62,15 @@ impl From<&CurveData> for String { impl std::str::FromStr for CurveData { type Err = ProfileError; - /// Parse a string to the correct values that the fan curve kernel driver expects + /// Parse a string to the correct values that the fan curve kernel driver + /// expects /// - /// If the fan curve is given with percentage char '%' then the fan power values are converted - /// otherwise the expected fan power range is 0-255. + /// If the fan curve is given with percentage char '%' then the fan power + /// values are converted otherwise the expected fan power range is + /// 0-255. /// - /// Temperature range is 0-255 in degrees C. You don't want to be setting over 100. + /// Temperature range is 0-255 in degrees C. You don't want to be setting + /// over 100. fn from_str(input: &str) -> Result { let mut temp = [0u8; 8]; let mut pwm = [0u8; 8]; @@ -313,6 +316,10 @@ mod tests { fn set_to_string() { let set = FanCurveSet::default(); let string = String::from(&set); - assert_eq!(string.as_str(), "Enabled: false, CPU: 0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%, GPU: 0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%"); + assert_eq!( + string.as_str(), + "Enabled: false, CPU: 0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%, GPU: \ + 0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%,0c:0%" + ); } } diff --git a/rog-profiles/src/lib.rs b/rog-profiles/src/lib.rs index 00667c74..aaf8f030 100644 --- a/rog-profiles/src/lib.rs +++ b/rog-profiles/src/lib.rs @@ -1,17 +1,14 @@ pub mod error; pub mod fan_curve_set; -use std::{ - fmt::Display, - fs::OpenOptions, - io::{Read, Write}, - path::Path, -}; +use std::fmt::Display; +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::path::Path; use error::ProfileError; use fan_curve_set::{CurveData, FanCurveSet}; use serde_derive::{Deserialize, Serialize}; - use udev::Device; #[cfg(feature = "dbus")] use zbus::zvariant::Type; @@ -207,10 +204,11 @@ impl FanCurveProfiles { } } - /// Reset the stored (self) and device curve to the defaults of the platform. + /// Reset the stored (self) and device curve to the defaults of the + /// platform. /// - /// Each `platform_profile` has a different default and the defualt can be read - /// only for the currently active profile. + /// Each `platform_profile` has a different default and the defualt can be + /// read only for the currently active profile. pub fn set_active_curve_to_defaults( &mut self, profile: Profile, @@ -232,8 +230,8 @@ impl FanCurveProfiles { } /// Write the curves for the selected profile to the device. If the curve is - /// in the enabled list it will become active. If the curve is zeroed it will be initialised - /// to a default read from the system. + /// in the enabled list it will become active. If the curve is zeroed it + /// will be initialised to a default read from the system. // TODO: Make this return an error if curve is zeroed pub fn write_profile_curve_to_platform( &mut self, diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..b22a925c --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,15 @@ +condense_wildcard_suffixes = true +edition = "2021" +format_strings = true +group_imports = "StdExternalCrate" +hex_literal_case = "Lower" +imports_granularity = "Module" +max_width = 100 +normalize_comments = true +normalize_doc_attributes = true +reorder_impl_items = true +reorder_imports = true +reorder_modules = true +unstable_features = true +use_field_init_shorthand = true +wrap_comments = true