mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-21 04:53:19 +03:00
macos: enable running lan-mouse on macos (#42)
* macos: initial support - adapted conditional compilation - moved lan-mouse socket to ~/Library/Caches/lan-mouse-socket.sock instead of XDG_RUNTIME_DIR - support for mouse input emulation TODO: Keycode translation, input capture
This commit is contained in:
committed by
GitHub
parent
5a7e0cf89c
commit
e3f9947284
17
.github/workflows/pre-release.yml
vendored
17
.github/workflows/pre-release.yml
vendored
@@ -39,9 +39,23 @@ jobs:
|
|||||||
name: lan-mouse-windows
|
name: lan-mouse-windows
|
||||||
path: target/release/lan-mouse.exe
|
path: target/release/lan-mouse.exe
|
||||||
|
|
||||||
|
macos-release-build:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: install dependencies
|
||||||
|
run: brew install gtk4 libadwaita
|
||||||
|
- name: Release Build
|
||||||
|
run: cargo build --release
|
||||||
|
- name: Upload build artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: lan-mouse-macos
|
||||||
|
path: target/release/lan-mouse
|
||||||
|
|
||||||
pre-release:
|
pre-release:
|
||||||
name: "Pre Release"
|
name: "Pre Release"
|
||||||
needs: [windows-release-build, linux-release-build]
|
needs: [windows-release-build, linux-release-build, macos-release-build]
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
steps:
|
steps:
|
||||||
- name: Download build artifacts
|
- name: Download build artifacts
|
||||||
@@ -56,3 +70,4 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
lan-mouse-linux/lan-mouse
|
lan-mouse-linux/lan-mouse
|
||||||
lan-mouse-windows/lan-mouse.exe
|
lan-mouse-windows/lan-mouse.exe
|
||||||
|
lan-mouse-macos/lan-mouse
|
||||||
|
|||||||
16
.github/workflows/rust.yml
vendored
16
.github/workflows/rust.yml
vendored
@@ -46,3 +46,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: lan-mouse-windows
|
name: lan-mouse-windows
|
||||||
path: target/debug/lan-mouse.exe
|
path: target/debug/lan-mouse.exe
|
||||||
|
|
||||||
|
build-macos:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: install dependencies
|
||||||
|
run: brew install gtk4 libadwaita
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose
|
||||||
|
- name: Upload build artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: lan-mouse-macos
|
||||||
|
path: target/debug/lan-mouse
|
||||||
|
|||||||
17
.github/workflows/tagged-release.yml
vendored
17
.github/workflows/tagged-release.yml
vendored
@@ -35,9 +35,23 @@ jobs:
|
|||||||
name: lan-mouse-windows
|
name: lan-mouse-windows
|
||||||
path: target/release/lan-mouse.exe
|
path: target/release/lan-mouse.exe
|
||||||
|
|
||||||
|
macos-release-build:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: install dependencies
|
||||||
|
run: brew install gtk4 libadwaita
|
||||||
|
- name: Release Build
|
||||||
|
run: cargo build --release
|
||||||
|
- name: Upload build artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: lan-mouse-macos
|
||||||
|
path: target/release/lan-mouse
|
||||||
|
|
||||||
tagged-release:
|
tagged-release:
|
||||||
name: "Tagged Release"
|
name: "Tagged Release"
|
||||||
needs: [windows-release-build, linux-release-build]
|
needs: [windows-release-build, linux-release-build, macos-release-build]
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
steps:
|
steps:
|
||||||
- name: Download build artifacts
|
- name: Download build artifacts
|
||||||
@@ -50,3 +64,4 @@ jobs:
|
|||||||
files: |
|
files: |
|
||||||
lan-mouse-linux/lan-mouse
|
lan-mouse-linux/lan-mouse
|
||||||
lan-mouse-windows/lan-mouse.exe
|
lan-mouse-windows/lan-mouse.exe
|
||||||
|
lan-mouse-macos/lan-mouse
|
||||||
|
|||||||
68
Cargo.lock
generated
68
Cargo.lock
generated
@@ -375,6 +375,46 @@ dependencies = [
|
|||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-foundation-sys"
|
||||||
|
version = "0.8.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-graphics"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"core-graphics-types",
|
||||||
|
"foreign-types",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "core-graphics-types"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"core-foundation",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.9"
|
version = "0.2.9"
|
||||||
@@ -549,6 +589,33 @@ dependencies = [
|
|||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
|
||||||
|
dependencies = [
|
||||||
|
"foreign-types-macros",
|
||||||
|
"foreign-types-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-macros"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.37",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foreign-types-shared"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -1075,6 +1142,7 @@ dependencies = [
|
|||||||
"ashpd",
|
"ashpd",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"clap",
|
"clap",
|
||||||
|
"core-graphics",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"futures",
|
"futures",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
|||||||
11
Cargo.toml
11
Cargo.toml
@@ -29,18 +29,23 @@ futures-core = "0.3.28"
|
|||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
clap = { version="4.4.11", features = ["derive"] }
|
clap = { version="4.4.11", features = ["derive"] }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(all(unix, not(target_os="macos")))'.dependencies]
|
||||||
wayland-client = { version="0.30.2", optional = true }
|
wayland-client = { version="0.30.2", optional = true }
|
||||||
wayland-protocols = { version="0.30.0", features=["client", "staging", "unstable"], optional = true }
|
wayland-protocols = { version="0.30.0", features=["client", "staging", "unstable"], optional = true }
|
||||||
wayland-protocols-wlr = { version="0.1.0", features=["client"], optional = true }
|
wayland-protocols-wlr = { version="0.1.0", features=["client"], optional = true }
|
||||||
wayland-protocols-misc = { version="0.1.0", features=["client"], optional = true }
|
wayland-protocols-misc = { version="0.1.0", features=["client"], optional = true }
|
||||||
wayland-protocols-plasma = { version="0.1.0", features=["client"], optional = true }
|
wayland-protocols-plasma = { version="0.1.0", features=["client"], optional = true }
|
||||||
x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true }
|
x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true }
|
||||||
gtk = { package = "gtk4", version = "0.7.2", features = ["v4_6"], optional = true }
|
|
||||||
adw = { package = "libadwaita", version = "0.5.2", features = ["v1_1"], optional = true }
|
|
||||||
ashpd = { version = "0.6.2", default-features = false, features = ["tokio"], optional = true }
|
ashpd = { version = "0.6.2", default-features = false, features = ["tokio"], optional = true }
|
||||||
reis = { git = "https://github.com/ids1024/reis", features = [ "tokio" ], optional = true }
|
reis = { git = "https://github.com/ids1024/reis", features = [ "tokio" ], optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
gtk = { package = "gtk4", version = "0.7.2", features = ["v4_6"], optional = true }
|
||||||
|
adw = { package = "libadwaita", version = "0.5.2", features = ["v1_1"], optional = true }
|
||||||
|
|
||||||
|
[target.'cfg(target_os="macos")'.dependencies]
|
||||||
|
core-graphics = { version = "0.23", features = ["highsierra"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3.9", features = ["winuser"] }
|
winapi = { version = "0.3.9", features = ["winuser"] }
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "x11"))]
|
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "wayland"))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
pub mod wlroots;
|
pub mod wlroots;
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "xdg_desktop_portal"))]
|
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
||||||
pub mod xdg_desktop_portal;
|
pub mod xdg_desktop_portal;
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "libei"))]
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
pub mod libei;
|
pub mod libei;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
pub mod macos;
|
||||||
|
|||||||
221
src/backend/consumer/macos.rs
Normal file
221
src/backend/consumer/macos.rs
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
use crate::client::{ClientEvent, ClientHandle};
|
||||||
|
use crate::consumer::EventConsumer;
|
||||||
|
use crate::event::{Event, KeyboardEvent, PointerEvent};
|
||||||
|
use anyhow::{anyhow, Result};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use core_graphics::display::CGPoint;
|
||||||
|
use core_graphics::event::{
|
||||||
|
CGEvent, CGEventTapLocation, CGEventType, CGMouseButton, ScrollEventUnit,
|
||||||
|
};
|
||||||
|
use core_graphics::event_source::{CGEventSource, CGEventSourceStateID};
|
||||||
|
use std::ops::{Index, IndexMut};
|
||||||
|
|
||||||
|
pub struct MacOSConsumer {
|
||||||
|
pub event_source: CGEventSource,
|
||||||
|
button_state: ButtonState,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ButtonState {
|
||||||
|
left: bool,
|
||||||
|
right: bool,
|
||||||
|
center: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Index<CGMouseButton> for ButtonState {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
fn index(&self, index: CGMouseButton) -> &Self::Output {
|
||||||
|
match index {
|
||||||
|
CGMouseButton::Left => &self.left,
|
||||||
|
CGMouseButton::Right => &self.right,
|
||||||
|
CGMouseButton::Center => &self.center,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexMut<CGMouseButton> for ButtonState {
|
||||||
|
fn index_mut(&mut self, index: CGMouseButton) -> &mut Self::Output {
|
||||||
|
match index {
|
||||||
|
CGMouseButton::Left => &mut self.left,
|
||||||
|
CGMouseButton::Right => &mut self.right,
|
||||||
|
CGMouseButton::Center => &mut self.center,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for MacOSConsumer {}
|
||||||
|
|
||||||
|
impl MacOSConsumer {
|
||||||
|
pub fn new() -> Result<Self> {
|
||||||
|
let event_source = match CGEventSource::new(CGEventSourceStateID::CombinedSessionState) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(_) => return Err(anyhow!("event source creation failed!")),
|
||||||
|
};
|
||||||
|
let button_state = ButtonState {
|
||||||
|
left: false,
|
||||||
|
right: false,
|
||||||
|
center: false,
|
||||||
|
};
|
||||||
|
Ok(Self {
|
||||||
|
event_source,
|
||||||
|
button_state,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mouse_location(&self) -> Option<CGPoint> {
|
||||||
|
let event: CGEvent = CGEvent::new(self.event_source.clone()).ok()?;
|
||||||
|
Some(event.location())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl EventConsumer for MacOSConsumer {
|
||||||
|
async fn consume(&mut self, event: Event, _client_handle: ClientHandle) {
|
||||||
|
match event {
|
||||||
|
Event::Pointer(pointer_event) => match pointer_event {
|
||||||
|
PointerEvent::Motion {
|
||||||
|
time: _,
|
||||||
|
relative_x,
|
||||||
|
relative_y,
|
||||||
|
} => {
|
||||||
|
let mut mouse_location = match self.get_mouse_location() {
|
||||||
|
Some(l) => l,
|
||||||
|
None => {
|
||||||
|
log::warn!("could not get mouse location!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
mouse_location.x += relative_x;
|
||||||
|
mouse_location.y += relative_y;
|
||||||
|
|
||||||
|
let mut event_type = CGEventType::MouseMoved;
|
||||||
|
if self.button_state.left {
|
||||||
|
event_type = CGEventType::LeftMouseDragged
|
||||||
|
} else if self.button_state.right {
|
||||||
|
event_type = CGEventType::RightMouseDragged
|
||||||
|
} else if self.button_state.center {
|
||||||
|
event_type = CGEventType::OtherMouseDragged
|
||||||
|
};
|
||||||
|
let event = match CGEvent::new_mouse_event(
|
||||||
|
self.event_source.clone(),
|
||||||
|
event_type,
|
||||||
|
mouse_location,
|
||||||
|
CGMouseButton::Left,
|
||||||
|
) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(_) => {
|
||||||
|
log::warn!("mouse event creation failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
event.post(CGEventTapLocation::HID);
|
||||||
|
}
|
||||||
|
PointerEvent::Button {
|
||||||
|
time: _,
|
||||||
|
button,
|
||||||
|
state,
|
||||||
|
} => {
|
||||||
|
let (event_type, mouse_button) = match (button, state) {
|
||||||
|
(b, 1) if b == crate::event::BTN_LEFT => {
|
||||||
|
(CGEventType::LeftMouseDown, CGMouseButton::Left)
|
||||||
|
}
|
||||||
|
(b, 0) if b == crate::event::BTN_LEFT => {
|
||||||
|
(CGEventType::LeftMouseUp, CGMouseButton::Left)
|
||||||
|
}
|
||||||
|
(b, 1) if b == crate::event::BTN_RIGHT => {
|
||||||
|
(CGEventType::RightMouseDown, CGMouseButton::Right)
|
||||||
|
}
|
||||||
|
(b, 0) if b == crate::event::BTN_RIGHT => {
|
||||||
|
(CGEventType::RightMouseUp, CGMouseButton::Right)
|
||||||
|
}
|
||||||
|
(b, 1) if b == crate::event::BTN_MIDDLE => {
|
||||||
|
(CGEventType::OtherMouseDown, CGMouseButton::Center)
|
||||||
|
}
|
||||||
|
(b, 0) if b == crate::event::BTN_MIDDLE => {
|
||||||
|
(CGEventType::OtherMouseUp, CGMouseButton::Center)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
log::warn!("invalid button event: {button},{state}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// store button state
|
||||||
|
self.button_state[mouse_button] = if state == 1 { true } else { false };
|
||||||
|
|
||||||
|
let location = self.get_mouse_location().unwrap();
|
||||||
|
let event = match CGEvent::new_mouse_event(
|
||||||
|
self.event_source.clone(),
|
||||||
|
event_type,
|
||||||
|
location,
|
||||||
|
mouse_button,
|
||||||
|
) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(()) => {
|
||||||
|
log::warn!("mouse event creation failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
event.post(CGEventTapLocation::HID);
|
||||||
|
}
|
||||||
|
PointerEvent::Axis {
|
||||||
|
time: _,
|
||||||
|
axis,
|
||||||
|
value,
|
||||||
|
} => {
|
||||||
|
let value = value as i32 / 10; // FIXME: high precision scroll events
|
||||||
|
let (count, wheel1, wheel2, wheel3) = match axis {
|
||||||
|
0 => (1, value, 0, 0), // 0 = vertical => 1 scroll wheel device (y axis)
|
||||||
|
1 => (2, 0, value, 0), // 1 = horizontal => 2 scroll wheel devices (y, x) -> (0, x)
|
||||||
|
_ => {
|
||||||
|
log::warn!("invalid scroll event: {axis}, {value}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let event = match CGEvent::new_scroll_event(
|
||||||
|
self.event_source.clone(),
|
||||||
|
ScrollEventUnit::LINE,
|
||||||
|
count,
|
||||||
|
wheel1,
|
||||||
|
wheel2,
|
||||||
|
wheel3,
|
||||||
|
) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(()) => {
|
||||||
|
log::warn!("scroll event creation failed!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
event.post(CGEventTapLocation::HID);
|
||||||
|
}
|
||||||
|
PointerEvent::Frame { .. } => {}
|
||||||
|
},
|
||||||
|
Event::Keyboard(keyboard_event) => match keyboard_event {
|
||||||
|
KeyboardEvent::Key { .. } => {
|
||||||
|
/*
|
||||||
|
let code = CGKeyCode::from_le(key as u16);
|
||||||
|
let event = match CGEvent::new_keyboard_event(
|
||||||
|
self.event_source.clone(),
|
||||||
|
code,
|
||||||
|
match state { 1 => true, _ => false }
|
||||||
|
) {
|
||||||
|
Ok(e) => e,
|
||||||
|
Err(_) => {
|
||||||
|
log::warn!("unable to create key event");
|
||||||
|
return
|
||||||
|
}
|
||||||
|
};
|
||||||
|
event.post(CGEventTapLocation::HID);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
KeyboardEvent::Modifiers { .. } => {}
|
||||||
|
},
|
||||||
|
Event::Release() => {}
|
||||||
|
Event::Ping() => {}
|
||||||
|
Event::Pong() => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn notify(&mut self, _client_event: ClientEvent) {}
|
||||||
|
|
||||||
|
async fn destroy(&mut self) {}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
#[cfg(all(unix, feature = "libei"))]
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
pub mod libei;
|
pub mod libei;
|
||||||
#[cfg(all(unix, feature = "wayland"))]
|
#[cfg(target_os = "macos")]
|
||||||
|
pub mod macos;
|
||||||
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
pub mod wayland;
|
pub mod wayland;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub mod windows;
|
pub mod windows;
|
||||||
#[cfg(all(unix, feature = "x11"))]
|
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||||
pub mod x11;
|
pub mod x11;
|
||||||
|
|||||||
28
src/backend/producer/macos.rs
Normal file
28
src/backend/producer/macos.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use crate::client::{ClientEvent, ClientHandle};
|
||||||
|
use crate::event::Event;
|
||||||
|
use crate::producer::EventProducer;
|
||||||
|
use futures_core::Stream;
|
||||||
|
use std::task::{Context, Poll};
|
||||||
|
use std::{io, pin::Pin};
|
||||||
|
|
||||||
|
pub struct MacOSProducer;
|
||||||
|
|
||||||
|
impl MacOSProducer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stream for MacOSProducer {
|
||||||
|
type Item = io::Result<(ClientHandle, Event)>;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
Poll::Pending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EventProducer for MacOSProducer {
|
||||||
|
fn notify(&mut self, _event: ClientEvent) {}
|
||||||
|
|
||||||
|
fn release(&mut self) {}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use std::future;
|
use std::future;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -11,7 +11,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Backend {
|
enum Backend {
|
||||||
Wlroots,
|
Wlroots,
|
||||||
@@ -37,7 +37,10 @@ pub async fn create() -> Result<Box<dyn EventConsumer>> {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
return Ok(Box::new(consumer::windows::WindowsConsumer::new()));
|
return Ok(Box::new(consumer::windows::WindowsConsumer::new()));
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "macos")]
|
||||||
|
return Ok(Box::new(consumer::macos::MacOSConsumer::new()?));
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
let backend = match env::var("XDG_SESSION_TYPE") {
|
let backend = match env::var("XDG_SESSION_TYPE") {
|
||||||
Ok(session_type) => match session_type.as_str() {
|
Ok(session_type) => match session_type.as_str() {
|
||||||
"x11" => {
|
"x11" => {
|
||||||
@@ -87,7 +90,7 @@ pub async fn create() -> Result<Box<dyn EventConsumer>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
match backend {
|
match backend {
|
||||||
Backend::Libei => {
|
Backend::Libei => {
|
||||||
#[cfg(not(feature = "libei"))]
|
#[cfg(not(feature = "libei"))]
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ use std::{
|
|||||||
fmt::{self, Display},
|
fmt::{self, Display},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME
|
||||||
|
pub(crate) const BTN_LEFT: u32 = 0x110;
|
||||||
|
pub(crate) const BTN_RIGHT: u32 = 0x111;
|
||||||
|
pub(crate) const BTN_MIDDLE: u32 = 0x112;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum PointerEvent {
|
pub enum PointerEvent {
|
||||||
Motion {
|
Motion {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ pub struct FrontendListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FrontendListener {
|
impl FrontendListener {
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
pub fn socket_path() -> Result<PathBuf> {
|
pub fn socket_path() -> Result<PathBuf> {
|
||||||
let xdg_runtime_dir = match env::var("XDG_RUNTIME_DIR") {
|
let xdg_runtime_dir = match env::var("XDG_RUNTIME_DIR") {
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
@@ -136,6 +136,20 @@ impl FrontendListener {
|
|||||||
Ok(xdg_runtime_dir.join("lan-mouse-socket.sock"))
|
Ok(xdg_runtime_dir.join("lan-mouse-socket.sock"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, target_os = "macos"))]
|
||||||
|
pub fn socket_path() -> Result<PathBuf> {
|
||||||
|
let home = match env::var("HOME") {
|
||||||
|
Ok(d) => d,
|
||||||
|
Err(e) => return Err(anyhow!("could not find HOME: {e}")),
|
||||||
|
};
|
||||||
|
let home = Path::new(home.as_str());
|
||||||
|
let path = home
|
||||||
|
.join("Library")
|
||||||
|
.join("Caches")
|
||||||
|
.join("lan-mouse-socket.sock");
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn new() -> Option<Result<Self>> {
|
pub async fn new() -> Option<Result<Self>> {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let (socket_path, listener) = {
|
let (socket_path, listener) = {
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ use crate::{
|
|||||||
event::Event,
|
event::Event,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
enum Backend {
|
enum Backend {
|
||||||
LayerShell,
|
LayerShell,
|
||||||
Libei,
|
Libei,
|
||||||
@@ -20,10 +20,13 @@ enum Backend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create() -> Result<Box<dyn EventProducer>> {
|
pub async fn create() -> Result<Box<dyn EventProducer>> {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
return Ok(Box::new(producer::macos::MacOSProducer::new()));
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
return Ok(Box::new(producer::windows::WindowsProducer::new()));
|
return Ok(Box::new(producer::windows::WindowsProducer::new()));
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
let backend = match env::var("XDG_SESSION_TYPE") {
|
let backend = match env::var("XDG_SESSION_TYPE") {
|
||||||
Ok(session_type) => match session_type.as_str() {
|
Ok(session_type) => match session_type.as_str() {
|
||||||
"x11" => {
|
"x11" => {
|
||||||
@@ -56,7 +59,7 @@ pub async fn create() -> Result<Box<dyn EventProducer>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
match backend {
|
match backend {
|
||||||
Backend::X11 => {
|
Backend::X11 => {
|
||||||
#[cfg(not(feature = "x11"))]
|
#[cfg(not(feature = "x11"))]
|
||||||
|
|||||||
Reference in New Issue
Block a user