WIP: Work on Infrastructure to Listen to the Touchinfo
This commit is contained in:
parent
1c1d98ca48
commit
d7fdb2a10f
7 changed files with 287 additions and 44 deletions
86
drivers/simple-cider/Cargo.lock
generated
86
drivers/simple-cider/Cargo.lock
generated
|
@ -61,24 +61,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hid"
|
name = "hidapi"
|
||||||
version = "0.4.1"
|
version = "2.6.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "526208586d017ea587be6f1c65f6d5491a60d15a6667da110ad2520662a265cb"
|
checksum = "03b876ecf37e86b359573c16c8366bc3eba52b689884a0fc42ba3f67203d2a8b"
|
||||||
dependencies = [
|
|
||||||
"hidapi-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hidapi-sys"
|
|
||||||
version = "0.1.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dd8a9410aec7ca9f4571ff40c7b1813a28503c2a664a028921fc973073dcd4bf"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -150,7 +142,7 @@ name = "simple-cider"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"evdev",
|
"evdev",
|
||||||
"hid",
|
"hidapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -196,6 +188,72 @@ version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wyz"
|
name = "wyz"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
|
|
|
@ -5,4 +5,4 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
evdev = "0.12.2"
|
evdev = "0.12.2"
|
||||||
hid = "0.4.1"
|
hidapi = "2.6.3"
|
||||||
|
|
|
@ -1,4 +1,33 @@
|
||||||
# Simple Cider
|
# Simple Cider
|
||||||
|
|
||||||
|
## Driver Collisions
|
||||||
|
|
||||||
|
The touchbar has a fallback mode, where it is only in Function Mode.
|
||||||
|
To disable this mode, to not have any collisions with out driver, we should unbind it.
|
||||||
|
|
||||||
|
### Temporary
|
||||||
|
|
||||||
|
run
|
||||||
|
|
||||||
|
```sh
|
||||||
|
echo -n "1-3:1.2" | sudo tee /sys/bus/usb/drivers/usbhid/unbind
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permanent
|
||||||
|
|
||||||
|
create a udev rule: `/etc/udev/rules.d/99-ibridge.rules`
|
||||||
|
|
||||||
|
```udev
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="05ac", ATTR{idProduct}=="8600", ATTR{interfaces}=="*:*:*:*:03:01:01", RUN+="/bin/sh -c 'echo -n $env{BUSNUM}-$env{DEVNUM}:$env{INTERFACE} > /sys/bus/usb/drivers/usbhid/unbind'"
|
||||||
|
```
|
||||||
|
|
||||||
|
to apply these rules without reboot run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo udevadm control --reload-rules
|
||||||
|
sudo udevadm trigger
|
||||||
|
```
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
- `hidapi-devel`
|
- `hidapi-devel`
|
||||||
|
|
|
@ -5,10 +5,11 @@ use evdev::{Device, Key};
|
||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut device = Device::open("/dev/input/event4")?;
|
let mut device = Device::open("/dev/input/event14")?; //This changes a lot, need a better way
|
||||||
let hid_manager = hid::init()?;
|
|
||||||
|
|
||||||
let mut touchbar = TouchbarImp::new(&hid_manager)?;
|
let hidapi = hidapi::HidApi::new()?;
|
||||||
|
|
||||||
|
let mut touchbar = TouchbarImp::new(&hidapi)?;
|
||||||
let mut fn_key_pressed = false;
|
let mut fn_key_pressed = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -16,11 +17,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if let evdev::InputEventKind::Key(key) = event.kind() {
|
if let evdev::InputEventKind::Key(key) = event.kind() {
|
||||||
match event.value() {
|
match event.value() {
|
||||||
0 if key == Key::KEY_FN && fn_key_pressed => {
|
0 if key == Key::KEY_FN && fn_key_pressed => {
|
||||||
touchbar.set_mode(tb::Mode::Special)?;
|
touchbar.set_mode(tb::TouchbarMode::Special)?;
|
||||||
fn_key_pressed = false;
|
fn_key_pressed = false;
|
||||||
}
|
}
|
||||||
1 if key == Key::KEY_FN && !fn_key_pressed => {
|
1 if key == Key::KEY_FN && !fn_key_pressed => {
|
||||||
touchbar.set_mode(tb::Mode::Function)?;
|
touchbar.set_mode(tb::TouchbarMode::Function)?;
|
||||||
fn_key_pressed = true;
|
fn_key_pressed = true;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -1,20 +1,53 @@
|
||||||
use std::fmt;
|
use std::{
|
||||||
|
fmt,
|
||||||
|
sync::{MutexGuard, PoisonError},
|
||||||
|
};
|
||||||
|
|
||||||
|
use hidapi::HidError;
|
||||||
|
|
||||||
|
use super::TouchbarMode;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum TouchbarError {
|
pub enum TouchbarError {
|
||||||
DeviceNotFound,
|
Init(HidError),
|
||||||
CantOpenDevice,
|
PoisionCantChangeMode,
|
||||||
WriteError,
|
PoisionCantSendEvent,
|
||||||
|
AlreadyListening,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TouchbarError {
|
impl fmt::Display for TouchbarError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TouchbarError::DeviceNotFound => write!(f, "Touchbar device not found"),
|
TouchbarError::PoisionCantChangeMode => write!(
|
||||||
TouchbarError::CantOpenDevice => write!(f, "Cannot open the Touchbar device"),
|
f,
|
||||||
TouchbarError::WriteError => write!(f, "Error writing to the Touchbar device"),
|
"Unable to Change Mode, because previous thread was posioned"
|
||||||
|
),
|
||||||
|
TouchbarError::PoisionCantSendEvent => {
|
||||||
|
write!(f, "Unable to Send Event, previous thread was poisioned")
|
||||||
|
}
|
||||||
|
TouchbarError::AlreadyListening => {
|
||||||
|
write!(f, "There is Allready a Listenr Thread running.")
|
||||||
|
}
|
||||||
|
TouchbarError::Init(hid_err) => hid_err.fmt(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for TouchbarError {}
|
impl std::error::Error for TouchbarError {}
|
||||||
|
|
||||||
|
impl From<PoisonError<MutexGuard<'_, TouchbarMode>>> for TouchbarError {
|
||||||
|
fn from(_: PoisonError<MutexGuard<TouchbarMode>>) -> Self {
|
||||||
|
Self::PoisionCantChangeMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl From<PoisonError<MutexGuard<'_, bool>>> for TouchbarError {
|
||||||
|
fn from(_: PoisonError<MutexGuard<bool>>) -> Self {
|
||||||
|
Self::PoisionCantSendEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HidError> for TouchbarError {
|
||||||
|
fn from(err: HidError) -> Self {
|
||||||
|
TouchbarError::Init(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,34 +1,110 @@
|
||||||
use crate::tb::{Mode, Touchbar};
|
use hidapi::{HidApi, HidDevice};
|
||||||
|
|
||||||
use super::TouchbarError;
|
use super::{TouchbarError, TouchbarEventListener};
|
||||||
|
use crate::tb::{Touchbar, TouchbarEvent, TouchbarMediaEvent, TouchbarMode};
|
||||||
|
use std::{
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
thread::{spawn, JoinHandle},
|
||||||
|
};
|
||||||
|
|
||||||
const TOUCHBAR_VENDOR_ID: u16 = 0x05ac;
|
const TOUCHBAR_VENDOR_ID: u16 = 0x05ac;
|
||||||
const TOUCHBAR_PRODUCT_ID: u16 = 0x8600;
|
const TOUCHBAR_PRODUCT_ID: u16 = 0x8600;
|
||||||
const TOUCHBAR_MODE_PAYLOAD: u8 = 0x02;
|
const TOUCHBAR_MODE_PAYLOAD: u8 = 0x02;
|
||||||
|
const TOUCHBAR_MAX_PAYLOAD_SIZE: usize = 64;
|
||||||
|
|
||||||
pub struct TouchbarImp {
|
pub struct TouchbarImp {
|
||||||
device: hid::Handle,
|
device: Arc<Mutex<HidDevice>>,
|
||||||
|
mode: Mutex<TouchbarMode>,
|
||||||
|
listeners: Arc<Mutex<Vec<Box<dyn TouchbarEventListener>>>>,
|
||||||
|
listener_handle: Option<JoinHandle<()>>,
|
||||||
|
listener_running: Arc<Mutex<bool>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TouchbarImp {
|
impl TouchbarImp {
|
||||||
pub fn new(hid_manager: &hid::Manager) -> Result<Self, TouchbarError> {
|
pub fn new(hid: &HidApi) -> Result<Self, TouchbarError> {
|
||||||
let device = hid_manager
|
Self::from(hid, TouchbarMode::Special)
|
||||||
.find(Some(TOUCHBAR_VENDOR_ID), Some(TOUCHBAR_PRODUCT_ID))
|
}
|
||||||
.next()
|
|
||||||
.ok_or(TouchbarError::DeviceNotFound)?;
|
|
||||||
|
|
||||||
let handle = device.open().map_err(|_| TouchbarError::CantOpenDevice)?;
|
pub fn from(hid: &HidApi, default_mode: TouchbarMode) -> Result<Self, TouchbarError> {
|
||||||
|
let device: HidDevice = hid.open(TOUCHBAR_VENDOR_ID, TOUCHBAR_PRODUCT_ID)?;
|
||||||
|
|
||||||
Ok(TouchbarImp { device: handle })
|
let mut this = TouchbarImp {
|
||||||
|
device: Arc::new(Mutex::new(device)),
|
||||||
|
mode: Mutex::new(default_mode),
|
||||||
|
listeners: Arc::new(Mutex::new(vec![])),
|
||||||
|
listener_handle: None,
|
||||||
|
listener_running: Arc::new(Mutex::new(false)),
|
||||||
|
};
|
||||||
|
this.set_mode(default_mode)?;
|
||||||
|
|
||||||
|
Ok(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Touchbar for TouchbarImp {
|
impl Touchbar for TouchbarImp {
|
||||||
fn set_mode(&mut self, mode: Mode) -> Result<(), TouchbarError> {
|
fn set_mode(&mut self, mode: TouchbarMode) -> Result<(), TouchbarError> {
|
||||||
|
let mut mode_guard = self.mode.lock()?;
|
||||||
|
*mode_guard = mode;
|
||||||
|
|
||||||
|
//TODO: Do real Error handeling here
|
||||||
self.device
|
self.device
|
||||||
.data()
|
.lock()
|
||||||
.write([TOUCHBAR_MODE_PAYLOAD, mode as u8])
|
.unwrap()
|
||||||
.map_err(|_| TouchbarError::WriteError)?;
|
.write(&[TOUCHBAR_MODE_PAYLOAD, mode as u8])?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_listener(&mut self, listener: Box<dyn super::TouchbarEventListener>) {
|
||||||
|
//TODO: Remove Unwrap with Real Error handeling
|
||||||
|
self.listeners.lock().unwrap().push(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_listening_input(&mut self) -> Result<(), TouchbarError> {
|
||||||
|
let mut running = self.listener_running.lock()?;
|
||||||
|
if *running {
|
||||||
|
return Err(TouchbarError::AlreadyListening);
|
||||||
|
}
|
||||||
|
|
||||||
|
*running = true;
|
||||||
|
|
||||||
|
let device = Arc::clone(&self.device);
|
||||||
|
let running = Arc::clone(&self.listener_running);
|
||||||
|
let listeners = Arc::clone(&self.listeners);
|
||||||
|
|
||||||
|
self.listener_handle = Some(spawn(move || {
|
||||||
|
//TODO: Real Error Handeling instead of unwraps
|
||||||
|
while *running.lock().unwrap() {
|
||||||
|
//TODO: replace unwrap with real error handeling
|
||||||
|
|
||||||
|
match device
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.read(&mut [0u8; TOUCHBAR_MAX_PAYLOAD_SIZE])
|
||||||
|
{
|
||||||
|
Ok(data) => {
|
||||||
|
//println!("data: {}", data);
|
||||||
|
//TODO: Parse Event
|
||||||
|
let event = TouchbarEvent::Media(TouchbarMediaEvent::VolumeUp);
|
||||||
|
//TODO: remove unwrap with real error Handeling
|
||||||
|
let listener_lock = listeners.lock().unwrap();
|
||||||
|
for listener in listener_lock.iter() {
|
||||||
|
listener.on_event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
//TODO: Real Error Handeling
|
||||||
|
println!("Error reading data: {:?}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_listening_input(&mut self) -> Result<(), TouchbarError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,61 @@
|
||||||
mod err;
|
mod err;
|
||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
pub use err::*;
|
pub use err::*;
|
||||||
pub use imp::*;
|
pub use imp::*;
|
||||||
|
|
||||||
pub enum Mode {
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum TouchbarMode {
|
||||||
EscOnly = 0x00,
|
EscOnly = 0x00,
|
||||||
Function = 0x01,
|
Function = 0x01,
|
||||||
Special = 0x02,
|
Special = 0x02,
|
||||||
Off = 0x03,
|
Off = 0x03,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Touchbar {
|
#[derive(Clone, Copy)]
|
||||||
fn set_mode(&mut self, mode: Mode) -> Result<(), TouchbarError>;
|
pub enum TouchbarEvent {
|
||||||
|
Esc,
|
||||||
|
Function(TouchbarFunctionEvent),
|
||||||
|
BrightnessDown,
|
||||||
|
BrightnessUp,
|
||||||
|
BacklightDown,
|
||||||
|
BacklightUp,
|
||||||
|
Media(TouchbarMediaEvent),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum TouchbarFunctionEvent {
|
||||||
|
F1,
|
||||||
|
F2,
|
||||||
|
F3,
|
||||||
|
F4,
|
||||||
|
F5,
|
||||||
|
F6,
|
||||||
|
F7,
|
||||||
|
F8,
|
||||||
|
F9,
|
||||||
|
F10,
|
||||||
|
F11,
|
||||||
|
F12,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum TouchbarMediaEvent {
|
||||||
|
SkipBack,
|
||||||
|
PauseResume,
|
||||||
|
SkipForward,
|
||||||
|
MuteVolume,
|
||||||
|
VolumeDown,
|
||||||
|
VolumeUp,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TouchbarEventListener: Send {
|
||||||
|
fn on_event(&self, event: TouchbarEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Touchbar {
|
||||||
|
fn set_mode(&mut self, mode: TouchbarMode) -> Result<(), TouchbarError>;
|
||||||
|
fn add_listener(&mut self, listener: Box<dyn TouchbarEventListener>);
|
||||||
|
fn start_listening_input(&mut self) -> Result<(), TouchbarError>;
|
||||||
|
fn stop_listening_input(&mut self) -> Result<(), TouchbarError>;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue