add scroll + notifications
oh my god it took far too long to get notifications working...
This commit is contained in:
362
Cargo.lock
generated
362
Cargo.lock
generated
@@ -1,11 +1,58 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.61"
|
||||
@@ -18,11 +65,63 @@ version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dbus"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cd9e78c210146a1860f897db03412fd5091fd73100778e43ee255cca252cf32"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"libdbus-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "evdev-rs"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/daniel5151/evdev-rs.git#0750443a1eb8edfa34cdfcf91e8c5c6cf6a12c3b"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"bitflags 1.2.1",
|
||||
"evdev-sys",
|
||||
"libc",
|
||||
"log",
|
||||
@@ -31,18 +130,45 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "evdev-sys"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/daniel5151/evdev-rs.git#0750443a1eb8edfa34cdfcf91e8c5c6cf6a12c3b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0"
|
||||
dependencies = [
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.11"
|
||||
@@ -52,15 +178,249 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mac-notification-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"chrono",
|
||||
"dirs",
|
||||
"objc-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-rust"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "144acee6a0543dc74893e4b8a33936b5b0a94cc2d4ab024afd0c6daff7afc3c0"
|
||||
dependencies = [
|
||||
"dbus",
|
||||
"mac-notification-sys",
|
||||
"winrt-notification",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-foundation"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||
dependencies = [
|
||||
"block",
|
||||
"objc",
|
||||
"objc_id",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc_id"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||
dependencies = [
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strum"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ca6e4730f517e041e547ffe23d29daab8de6b73af4b6ae2a002108169f5e7da"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3384590878eb0cab3b128e844412e2d010821e7e091211b9d87324173ada7db8"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "surface-dial-daemon"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"evdev-rs",
|
||||
"notify-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.11.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"synom",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synom"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "winrt"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e30cba82e22b083dc5a422c2ee77e20dc7927271a0dc981360c57c1453cb48d"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winrt-notification"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c31a65da50d792c6f9bd2e3216249566c4fb1d2d34f9b7d2d66d2e93f62a242"
|
||||
dependencies = [
|
||||
"strum",
|
||||
"strum_macros",
|
||||
"winapi",
|
||||
"winrt",
|
||||
"xml-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1945e12e16b951721d7976520b0832496ef79c31602c7a29d950de79ba74621"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1",
|
||||
]
|
||||
|
||||
@@ -5,4 +5,6 @@ authors = ["Daniel Prilik <danielprilik@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
evdev-rs = { path = "../evdev-rs/" }
|
||||
# custom fork which implements `Send` on UInputDevice
|
||||
evdev-rs = { git = "https://github.com/daniel5151/evdev-rs.git", sha = "cc9060d" }
|
||||
notify-rust = "4"
|
||||
|
||||
46
README.md
46
README.md
@@ -27,17 +27,24 @@ It would be cool to create some sort of GUI overlay (similar to the Windows one)
|
||||
## Functionality
|
||||
|
||||
- [x] Interpret raw Surface Dial event
|
||||
- [ ] Dynamically switch between operating modes
|
||||
- [ ] Context-sensitive (based on currently open application)
|
||||
- [ ] Using `surface-dial-cli` application
|
||||
- [ ] Using some-sort of on-device mechanism (e.g: long-press)
|
||||
- Various Operating Modes
|
||||
- Operating Modes
|
||||
- [x] Volume Controls
|
||||
- [x] Media Controls
|
||||
- [x] D-Pad (emulated left, right, and space key)
|
||||
- [ ] Scrolling / Zooming
|
||||
- [x] Scrolling / Zooming
|
||||
- [ ] \(meta\) Specify modes via config file(s)
|
||||
- [ ] Dynamically switch between operating modes
|
||||
- _currently required re-compiling the daemon_
|
||||
- [ ] Context-sensitive (based on currently open application)
|
||||
- [ ] Using `surface-dial-cli` application
|
||||
- [ ] Using some-sort of on-device mechanism (e.g: long-press)
|
||||
- [ ] Haptic Feedback
|
||||
- This is tough one, as it doesn't seem like the kernel driver exposes any haptic feedback interface...
|
||||
- [x] Desktop Notifications
|
||||
- [x] On Launch
|
||||
- [x] When switching between sub-modes (e.g: scroll/zoom)
|
||||
|
||||
Feel free to suggest / contribute new features!
|
||||
Feel free to contribute new features!
|
||||
|
||||
## Building
|
||||
|
||||
@@ -90,19 +97,30 @@ If your distro doesn't use `systemd`, you'll have to come up with something your
|
||||
cargo install --path .
|
||||
|
||||
# IMPORTANT: modify the .service file to reflect where you placed the `service-dial-daemon` executable
|
||||
vi surface-dial.service
|
||||
vi ./install/surface-dial.service
|
||||
|
||||
# install the systemd service
|
||||
sudo cp surface-dial.service /etc/systemd/system/surface-dial.service
|
||||
# install the service-dial udev rule
|
||||
sudo cp surface-dial-udev.rules /etc/udev/rules.d/50-surface-dial.rules
|
||||
# create new group for uinput
|
||||
# (the 99-uinput.rules file changes the group of /dev/uinput to this new group)
|
||||
sudo groupdadd -f uinput
|
||||
|
||||
# add self to the new uinput group and the existing /dev/input group
|
||||
sudo gpasswd -a $(whoami) uinput
|
||||
sudo gpasswd -a $(whoami) $(stat -c "%G" /dev/input/event0)
|
||||
|
||||
# install the systemd user service
|
||||
mkdir -p ~/.config/systemd/user/
|
||||
cp ./install/surface-dial.service ~/.config/systemd/user/surface-dial.service
|
||||
|
||||
# install the udev rules
|
||||
sudo cp ./install/99-uinput.rules /etc/udev/rules.d/99-uinput.rules
|
||||
sudo cp ./install/50-surface-dial.rules /etc/udev/rules.d/50-surface-dial.rules
|
||||
|
||||
# reload systemd + udev
|
||||
sudo systemctl daemon-reload
|
||||
systemctl --user daemon-reload
|
||||
sudo udevadm control --reload
|
||||
```
|
||||
|
||||
You many need to disconnect + reconnect the Surface Dial for the `udev` rule to trigger.
|
||||
You may need to reboot to have the various groups / udev rules propagate.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
ACTION=="add", ATTR{name}=="Surface Dial System Multi Axis", TAG+="systemd", ENV{SYSTEMD_WANTS}="surface-dial.service"
|
||||
ACTION=="add", ATTR{name}=="Surface Dial System Multi Axis", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="surface-dial.service"
|
||||
1
install/99-uinput.rules
Normal file
1
install/99-uinput.rules
Normal file
@@ -0,0 +1 @@
|
||||
KERNEL=="uinput", GROUP="uinput", MODE:”0660"
|
||||
5
install/surface-dial.service
Normal file
5
install/surface-dial.service
Normal file
@@ -0,0 +1,5 @@
|
||||
# IMPORTANT: modify the "ExecStart" field to reflect your userid + surface-dial-daemon install dir
|
||||
|
||||
[Service]
|
||||
# HACK: this service needs to run _after_ the /dev/input/eventXX files have been created
|
||||
ExecStart=bash -c 'sleep 1 && /home/danielprilik/.cargo/bin/surface-dial-daemon'
|
||||
234
notes/HID_Report_Descriptor.txt
Normal file
234
notes/HID_Report_Descriptor.txt
Normal file
@@ -0,0 +1,234 @@
|
||||
# extracted using hid-example.c + https://eleccelerator.com/usbdescreqparser/
|
||||
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x0E, // Usage (0x0E)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x01, // Report ID (1)
|
||||
0x05, 0x0D, // Usage Page (Digitizer)
|
||||
0x09, 0x21, // Usage (Puck)
|
||||
0xA1, 0x02, // Collection (Logical)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0xA1, 0x00, // Collection (Physical)
|
||||
0x05, 0x09, // Usage Page (Button)
|
||||
0x09, 0x01, // Usage (0x01)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x05, 0x0D, // Usage Page (Digitizer)
|
||||
0x09, 0x33, // Usage (Touch)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x95, 0x06, // Report Count (6)
|
||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0xA1, 0x02, // Collection (Logical)
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x37, // Usage (Dial)
|
||||
0x16, 0x01, 0x80, // Logical Minimum (-32767)
|
||||
0x26, 0xFF, 0x7F, // Logical Maximum (32767)
|
||||
0x75, 0x10, // Report Size (16)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x35, 0x00, // Physical Minimum (0)
|
||||
0x46, 0x10, 0x0E, // Physical Maximum (3600)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0x10, 0x0E, // Logical Maximum (3600)
|
||||
0x09, 0x48, // Usage (0x48)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x45, 0x00, // Physical Maximum (0)
|
||||
0xC0, // End Collection
|
||||
0x55, 0x0E, // Unit Exponent (-2)
|
||||
0x65, 0x11, // Unit (System: SI Linear, Length: Centimeter)
|
||||
0x46, 0x00, 0x00, // Physical Maximum (0)
|
||||
0x26, 0x00, 0x00, // Logical Maximum (0)
|
||||
0x09, 0x30, // Usage (X)
|
||||
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
|
||||
0x09, 0x31, // Usage (Y)
|
||||
0x46, 0x00, 0x00, // Physical Maximum (0)
|
||||
0x26, 0x00, 0x00, // Logical Maximum (0)
|
||||
0x81, 0x42, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
|
||||
0x05, 0x0D, // Usage Page (Digitizer)
|
||||
0x09, 0x48, // Usage (0x48)
|
||||
0x15, 0x3A, // Logical Minimum (58)
|
||||
0x25, 0x3A, // Logical Maximum (58)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x55, 0x0F, // Unit Exponent (-1)
|
||||
0x35, 0x3A, // Physical Minimum (58)
|
||||
0x45, 0x3A, // Physical Maximum (58)
|
||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x55, 0x00, // Unit Exponent (0)
|
||||
0x65, 0x00, // Unit (None)
|
||||
0x35, 0x00, // Physical Minimum (0)
|
||||
0x45, 0x00, // Physical Maximum (0)
|
||||
0x05, 0x0E, // Usage Page (Reserved 0x0E)
|
||||
0x09, 0x01, // Usage (0x01)
|
||||
0xA1, 0x02, // Collection (Logical)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x26, 0xFF, 0x00, // Logical Maximum (255)
|
||||
0x09, 0x24, // Usage (0x24)
|
||||
0xB1, 0x42, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x09, 0x24, // Usage (0x24)
|
||||
0x91, 0x42, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x15, 0x01, // Logical Minimum (1)
|
||||
0x25, 0x07, // Logical Maximum (7)
|
||||
0x09, 0x20, // Usage (0x20)
|
||||
0xB1, 0x42, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x09, 0x21, // Usage (0x21)
|
||||
0x91, 0x42, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x25, 0x0A, // Logical Maximum (10)
|
||||
0x09, 0x28, // Usage (0x28)
|
||||
0xB1, 0x42, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x75, 0x10, // Report Size (16)
|
||||
0x26, 0xD0, 0x07, // Logical Maximum (2000)
|
||||
0x09, 0x25, // Usage (0x25)
|
||||
0xB1, 0x42, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x09, 0x25, // Usage (0x25)
|
||||
0x91, 0x42, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State,Non-volatile)
|
||||
0x85, 0x02, // Report ID (2)
|
||||
0x75, 0x20, // Report Size (32)
|
||||
0x17, 0x37, 0x00, 0x01, 0x00, // Logical Minimum (65590)
|
||||
0x27, 0x37, 0x00, 0x01, 0x00, // Logical Maximum (65590)
|
||||
0x09, 0x22, // Usage (0x22)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x09, 0x11, // Usage (0x11)
|
||||
0xA1, 0x02, // Collection (Logical)
|
||||
0x05, 0x0A, // Usage Page (Ordinal)
|
||||
0x95, 0x03, // Report Count (3)
|
||||
0x09, 0x03, // Usage (0x03)
|
||||
0x09, 0x04, // Usage (0x04)
|
||||
0x09, 0x05, // Usage (0x05)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0xFF, // Logical Maximum (-1)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0xC0, // End Collection
|
||||
0x05, 0x0E, // Usage Page (Reserved 0x0E)
|
||||
0x09, 0x10, // Usage (0x10)
|
||||
0xA1, 0x02, // Collection (Logical)
|
||||
0x05, 0x0A, // Usage Page (Ordinal)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x15, 0x03, // Logical Minimum (3)
|
||||
0x25, 0x03, // Logical Maximum (3)
|
||||
0x36, 0x03, 0x10, // Physical Minimum (4099)
|
||||
0x46, 0x03, 0x10, // Physical Maximum (4099)
|
||||
0x09, 0x03, // Usage (0x03)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x15, 0x04, // Logical Minimum (4)
|
||||
0x25, 0x04, // Logical Maximum (4)
|
||||
0x36, 0x04, 0x10, // Physical Minimum (4100)
|
||||
0x46, 0x04, 0x10, // Physical Maximum (4100)
|
||||
0x09, 0x04, // Usage (0x04)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x15, 0x05, // Logical Minimum (5)
|
||||
0x25, 0x05, // Logical Maximum (5)
|
||||
0x36, 0x04, 0x10, // Physical Minimum (4100)
|
||||
0x46, 0x04, 0x10, // Physical Maximum (4100)
|
||||
0x09, 0x05, // Usage (0x05)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x35, 0x00, // Physical Minimum (0)
|
||||
0x45, 0x00, // Physical Maximum (0)
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
0xC0, // End Collection
|
||||
0x06, 0x07, 0xFF, // Usage Page (Vendor Defined 0xFF07)
|
||||
0x09, 0x70, // Usage (0x70)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x30, // Report ID (48)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0xFF, // Logical Maximum (-1)
|
||||
0x95, 0x01, // Report Count (1)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x09, 0x00, // Usage (0x00)
|
||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0xC0, // End Collection
|
||||
0x09, 0x71, // Usage (0x71)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0xFF, // Logical Maximum (-1)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x95, 0x48, // Report Count (72)
|
||||
0x85, 0x2A, // Report ID (42)
|
||||
0x09, 0xC6, // Usage (0xC6)
|
||||
0x82, 0x02, 0x01, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Buffered Bytes)
|
||||
0x09, 0xC7, // Usage (0xC7)
|
||||
0x92, 0x02, 0x01, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
|
||||
0x95, 0x34, // Report Count (52)
|
||||
0x09, 0xC8, // Usage (0xC8)
|
||||
0xB2, 0x03, 0x01, // Feature (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
|
||||
0x85, 0x2B, // Report ID (43)
|
||||
0x09, 0xC9, // Usage (0xC9)
|
||||
0x82, 0x02, 0x01, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Buffered Bytes)
|
||||
0x09, 0xCA, // Usage (0xCA)
|
||||
0x92, 0x02, 0x01, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
|
||||
0x09, 0xCB, // Usage (0xCB)
|
||||
0xB2, 0x02, 0x01, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile,Buffered Bytes)
|
||||
0x17, 0x00, 0x00, 0x00, 0x80, // Logical Minimum (-2147483649)
|
||||
0x27, 0xFF, 0xFF, 0xFF, 0x7F, // Logical Maximum (2147483646)
|
||||
0x75, 0x20, // Report Size (32)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x85, 0x2C, // Report ID (44)
|
||||
0x19, 0xCC, // Usage Minimum (0xCC)
|
||||
0x29, 0xCF, // Usage Maximum (0xCF)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x85, 0x2D, // Report ID (45)
|
||||
0x19, 0xD8, // Usage Minimum (0xD8)
|
||||
0x29, 0xDB, // Usage Maximum (0xDB)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x19, 0xDC, // Usage Minimum (0xDC)
|
||||
0x29, 0xDF, // Usage Maximum (0xDF)
|
||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x19, 0xE0, // Usage Minimum (0xE0)
|
||||
0x29, 0xE3, // Usage Maximum (0xE3)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x85, 0x2E, // Report ID (46)
|
||||
0x19, 0xE4, // Usage Minimum (0xE4)
|
||||
0x29, 0xE7, // Usage Maximum (0xE7)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x19, 0xE8, // Usage Minimum (0xE8)
|
||||
0x29, 0xEB, // Usage Maximum (0xEB)
|
||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x95, 0x0B, // Report Count (11)
|
||||
0x19, 0xEC, // Usage Minimum (0xEC)
|
||||
0x29, 0xEF, // Usage Maximum (0xEF)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x95, 0x04, // Report Count (4)
|
||||
0x85, 0x2F, // Report ID (47)
|
||||
0x19, 0xF0, // Usage Minimum (0xF0)
|
||||
0x29, 0xF3, // Usage Maximum (0xF3)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x19, 0xF4, // Usage Minimum (0xF4)
|
||||
0x29, 0xF7, // Usage Maximum (0xF7)
|
||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0x19, 0xF8, // Usage Minimum (0xF8)
|
||||
0x29, 0xFB, // Usage Maximum (0xFB)
|
||||
0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0xC0, // End Collection
|
||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
||||
0x09, 0x80, // Usage (Sys Control)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x32, // Report ID (50)
|
||||
0x09, 0x82, // Usage (Sys Sleep)
|
||||
0x09, 0x83, // Usage (Sys Wake Up)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0x01, // Logical Maximum (1)
|
||||
0x95, 0x02, // Report Count (2)
|
||||
0x75, 0x01, // Report Size (1)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x95, 0x06, // Report Count (6)
|
||||
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0xC0, // End Collection
|
||||
0x09, 0x72, // Usage (0x72)
|
||||
0xA1, 0x01, // Collection (Application)
|
||||
0x85, 0x31, // Report ID (49)
|
||||
0x95, 0x0A, // Report Count (10)
|
||||
0x75, 0x08, // Report Size (8)
|
||||
0x15, 0x00, // Logical Minimum (0)
|
||||
0x25, 0xFF, // Logical Maximum (-1)
|
||||
0x09, 0xC6, // Usage (0xC6)
|
||||
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
||||
0x09, 0xC7, // Usage (0xC7)
|
||||
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
|
||||
0xC0, // End Collection
|
||||
@@ -32,3 +32,17 @@ impl ThresholdHelper {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
use notify_rust::error::Result as NotifyResult;
|
||||
use notify_rust::{Hint, Notification, NotificationHandle, Timeout};
|
||||
|
||||
pub fn action_notification(msg: &str, icon: &str) -> NotifyResult<NotificationHandle> {
|
||||
Notification::new()
|
||||
.hint(Hint::Transient(true))
|
||||
.hint(Hint::Category("device".into()))
|
||||
.timeout(Timeout::Milliseconds(100))
|
||||
.summary("Surface Dial")
|
||||
.body(msg)
|
||||
.icon(icon)
|
||||
.show()
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ impl Worker {
|
||||
Ordering::Greater => self.fake_input.key_press(&[EV_KEY::KEY_RIGHT]).unwrap(),
|
||||
}
|
||||
|
||||
eprintln!("{:?}", self.velocity);
|
||||
// eprintln!("{:?}", self.velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ impl Media {
|
||||
|
||||
impl ControlMode for Media {
|
||||
fn on_btn_press(&mut self) -> DynResult<()> {
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self) -> DynResult<()> {
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
mod dpad;
|
||||
mod media;
|
||||
mod scroll_zoom;
|
||||
mod volume;
|
||||
|
||||
pub use self::dpad::*;
|
||||
pub use self::media::*;
|
||||
pub use self::scroll_zoom::*;
|
||||
pub use self::volume::*;
|
||||
|
||||
68
src/controller/controls/scroll_zoom.rs
Normal file
68
src/controller/controls/scroll_zoom.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use crate::common::{action_notification, DialDir, ThresholdHelper};
|
||||
use crate::controller::ControlMode;
|
||||
use crate::fake_input::{FakeInput, ScrollStep};
|
||||
use crate::DynResult;
|
||||
|
||||
use evdev_rs::enums::EV_KEY;
|
||||
|
||||
pub struct ScrollZoom {
|
||||
thresh: ThresholdHelper,
|
||||
zoom: bool,
|
||||
|
||||
fake_input: FakeInput,
|
||||
}
|
||||
|
||||
impl ScrollZoom {
|
||||
pub fn new(sensitivity: i32) -> ScrollZoom {
|
||||
ScrollZoom {
|
||||
thresh: ThresholdHelper::new(sensitivity),
|
||||
zoom: false,
|
||||
|
||||
fake_input: FakeInput::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ControlMode for ScrollZoom {
|
||||
fn on_btn_press(&mut self) -> DynResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self) -> DynResult<()> {
|
||||
self.zoom = !self.zoom;
|
||||
if self.zoom {
|
||||
action_notification("Zoom Mode", "zoom-in")?;
|
||||
} else {
|
||||
action_notification("ScrollZoom Mode", "input-mouse")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_dial(&mut self, delta: i32) -> DynResult<()> {
|
||||
match self.thresh.update(delta) {
|
||||
None => {}
|
||||
Some(DialDir::Left) => {
|
||||
if self.zoom {
|
||||
eprintln!("zoom out");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_MINUS])?;
|
||||
} else {
|
||||
eprintln!("scroll up");
|
||||
self.fake_input.scroll_step(ScrollStep::Up)?;
|
||||
}
|
||||
}
|
||||
Some(DialDir::Right) => {
|
||||
if self.zoom {
|
||||
eprintln!("zoom in");
|
||||
self.fake_input
|
||||
.key_click(&[EV_KEY::KEY_LEFTCTRL, EV_KEY::KEY_EQUAL])?;
|
||||
} else {
|
||||
eprintln!("scroll down");
|
||||
self.fake_input.scroll_step(ScrollStep::Down)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -24,14 +24,13 @@ impl Volume {
|
||||
impl ControlMode for Volume {
|
||||
fn on_btn_press(&mut self) -> DynResult<()> {
|
||||
// TODO: support double-click to mute
|
||||
|
||||
eprintln!("play/pause");
|
||||
// self.fake_input.mute()?
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_btn_release(&mut self) -> DynResult<()> {
|
||||
eprintln!("play/pause");
|
||||
// self.fake_input.mute()?
|
||||
self.fake_input.key_click(&[EV_KEY::KEY_PLAYPAUSE])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -30,13 +30,14 @@ impl DialDevice {
|
||||
let mut control = None;
|
||||
let mut axis = None;
|
||||
|
||||
for e in fs::read_dir("/dev/input/").map_err(Error::Io)? {
|
||||
let e = e.map_err(Error::Io)?;
|
||||
for e in fs::read_dir("/dev/input/").map_err(Error::OpenDevInputDir)? {
|
||||
let e = e.map_err(Error::OpenDevInputDir)?;
|
||||
if !e.file_name().to_str().unwrap().starts_with("event") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let file = fs::File::open(e.path()).map_err(Error::Io)?;
|
||||
let file =
|
||||
fs::File::open(e.path()).map_err(|err| Error::OpenEventFile(e.path(), err))?;
|
||||
let dev = Device::new_from_fd(file).map_err(Error::Evdev)?;
|
||||
|
||||
match dev.name() {
|
||||
|
||||
13
src/error.rs
13
src/error.rs
@@ -1,24 +1,29 @@
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
|
||||
use evdev_rs::InputEvent;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
OpenDevInputDir(io::Error),
|
||||
OpenEventFile(std::path::PathBuf, io::Error),
|
||||
MissingDial,
|
||||
MultipleDials,
|
||||
UnexpectedEvt(InputEvent),
|
||||
Evdev(std::io::Error),
|
||||
Io(std::io::Error),
|
||||
Evdev(io::Error),
|
||||
Io(io::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::OpenDevInputDir(e) => write!(f, "Could not open /dev/input directory: {}", e),
|
||||
Error::OpenEventFile(path, e) => write!(f, "Could not open {:?}: {}", path, e),
|
||||
Error::MissingDial => write!(f, "Could not find the Surface Dial"),
|
||||
Error::MultipleDials => write!(f, "Found multiple dials"),
|
||||
Error::UnexpectedEvt(evt) => write!(f, "Unexpected event: {:?}", evt),
|
||||
Error::Evdev(e) => write!(f, "Evdev error: {:?}", e),
|
||||
Error::Io(e) => write!(f, "Io error: {:?}", e),
|
||||
Error::Evdev(e) => write!(f, "Evdev error: {}", e),
|
||||
Error::Io(e) => write!(f, "Io error: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,23 +12,35 @@ fn get_fake_input() -> io::Result<&'static UInputDevice> {
|
||||
device.enable(&EventType::EV_SYN)?;
|
||||
device.enable(&EventCode::EV_SYN(EV_SYN::SYN_REPORT))?;
|
||||
|
||||
device.enable(&EventType::EV_KEY)?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFTSHIFT))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_MUTE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEDOWN))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEUP))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_NEXTSONG))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PLAYPAUSE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PREVIOUSSONG))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_RIGHT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_SPACE))?;
|
||||
|
||||
device.enable(&EventType::EV_MSC)?;
|
||||
device.enable(&EventCode::EV_MSC(EV_MSC::MSC_SCAN))?;
|
||||
|
||||
device.enable(&EventType::EV_KEY)?;
|
||||
{
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFTSHIFT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFTCTRL))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_MUTE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEDOWN))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_VOLUMEUP))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_NEXTSONG))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PLAYPAUSE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_PREVIOUSSONG))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_LEFT))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_RIGHT))?;
|
||||
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_SPACE))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_EQUAL))?;
|
||||
device.enable(&EventCode::EV_KEY(EV_KEY::KEY_MINUS))?;
|
||||
}
|
||||
|
||||
device.enable(&EventType::EV_REL)?;
|
||||
{
|
||||
device.enable(&EventCode::EV_REL(EV_REL::REL_WHEEL))?;
|
||||
device.enable(&EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES))?;
|
||||
}
|
||||
|
||||
unsafe { FAKE_INPUT = Some(UInputDevice::create_from_device(&device)?) }
|
||||
}
|
||||
unsafe { Ok(FAKE_INPUT.as_ref().unwrap()) }
|
||||
@@ -99,4 +111,33 @@ impl FakeInput {
|
||||
self.syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn scroll_step(&self, dir: ScrollStep) -> io::Result<()> {
|
||||
// copied from my razer blackwidow chroma mouse
|
||||
self.uinput.write_event(&InputEvent {
|
||||
time: TimeVal::new(0, 0),
|
||||
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL),
|
||||
event_type: EventType::EV_REL,
|
||||
value: match dir {
|
||||
ScrollStep::Down => -1,
|
||||
ScrollStep::Up => 1,
|
||||
},
|
||||
})?;
|
||||
self.uinput.write_event(&InputEvent {
|
||||
time: TimeVal::new(0, 0),
|
||||
event_code: EventCode::EV_REL(EV_REL::REL_WHEEL_HI_RES),
|
||||
event_type: EventType::EV_REL,
|
||||
value: match dir {
|
||||
ScrollStep::Down => -120,
|
||||
ScrollStep::Up => 120,
|
||||
},
|
||||
})?;
|
||||
self.syn_report()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ScrollStep {
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
19
src/main.rs
19
src/main.rs
@@ -10,13 +10,24 @@ use crate::controller::DialController;
|
||||
use crate::dial_device::DialDevice;
|
||||
use crate::error::Error;
|
||||
|
||||
fn main() -> DynResult<()> {
|
||||
fn main() {
|
||||
if let Err(e) = true_main() {
|
||||
println!("{}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn true_main() -> DynResult<()> {
|
||||
println!("Started.");
|
||||
|
||||
let dial = DialDevice::new()?;
|
||||
println!("Found the dial.");
|
||||
|
||||
let default_mode = Box::new(controller::controls::Volume::new(30));
|
||||
// let default_mode = Box::new(controls::Media::new(50));
|
||||
// let default_mode = Box::new(controls::DPad::new());
|
||||
common::action_notification("Active!", "input-mouse")?;
|
||||
|
||||
let default_mode = Box::new(controller::controls::ScrollZoom::new(30));
|
||||
// let default_mode = Box::new(controller::controls::Volume::new(30));
|
||||
// let default_mode = Box::new(controller::controls::Media::new(50));
|
||||
// let default_mode = Box::new(controller::controls::DPad::new());
|
||||
|
||||
let mut controller = DialController::new(dial, default_mode);
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# modify ExecStart to wherever you put surface-dial-daemon
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/home/danielprilik/.cargo/bin/surface-dial-daemon
|
||||
Reference in New Issue
Block a user