Finished the driver and installed it. Saving for archive.
This commit is contained in:
@@ -24,6 +24,12 @@ Regular wheel mode:
|
|||||||
cargo run --manifest-path renewed_driver/Cargo.toml -- --mode wheel
|
cargo run --manifest-path renewed_driver/Cargo.toml -- --mode wheel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Multitouch timing can be tuned without recompiling:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo run --manifest-path renewed_driver/Cargo.toml -- --mode multitouch --mt-idle-ms 100 --mt-idle-max-ms 1500 --mt-settle-ms 80
|
||||||
|
```
|
||||||
|
|
||||||
The process still needs access to the Surface Dial event device and
|
The process still needs access to the Surface Dial event device and
|
||||||
`/dev/uinput`, just like the original daemon.
|
`/dev/uinput`, just like the original daemon.
|
||||||
|
|
||||||
|
|||||||
+28
-7
@@ -19,14 +19,35 @@ surface-dial-renewed --mode wheel
|
|||||||
Normal Dial rotation emits a synthetic two-finger touchpad scroll through
|
Normal Dial rotation emits a synthetic two-finger touchpad scroll through
|
||||||
`Surface Dial Renewed Touchpad`.
|
`Surface Dial Renewed Touchpad`.
|
||||||
|
|
||||||
The driver starts a virtual two-finger contact on the first rotation event,
|
The driver starts a virtual two-finger contact on the first rotation event and
|
||||||
moves both virtual fingers vertically, and ends the touch gesture after no
|
moves both virtual fingers vertically. Gesture release is dynamic:
|
||||||
rotation has arrived for 2 seconds.
|
|
||||||
|
|
||||||
The 2 second hold is intentional. Very slow physical Dial movement can emit
|
- normal and fast rotation releases after about `100ms`
|
||||||
sparse `REL_DIAL` events. If the virtual fingers are lifted too quickly, libinput
|
- sparse precision movement can stretch release up to `1500ms`
|
||||||
can treat those sparse movements as many tiny gestures and ignore them. Holding
|
|
||||||
the contact makes slow and precise movement accumulate into one gesture.
|
The `100ms` minimum matches the old driver's multitouch control. The timeout is
|
||||||
|
based on the time gap between rotation events, not the raw delta size. That is
|
||||||
|
important because the Dial can emit `delta=1` even during normal fast scrolling.
|
||||||
|
If the virtual fingers are lifted too quickly during sparse movement, libinput
|
||||||
|
can treat those sparse events as many tiny gestures and ignore them. If the hold
|
||||||
|
is too long, page-edge overscroll animations can remain stretched for too long
|
||||||
|
before bouncing back.
|
||||||
|
|
||||||
|
The driver keeps the last rotation timestamp even after a virtual touch gesture
|
||||||
|
ends. This matters because sparse precision events can arrive after the 100ms
|
||||||
|
gesture has already been released. The next event still sees the previous event
|
||||||
|
gap and can stretch the new gesture timeout. A gap of `2500ms` or more is
|
||||||
|
treated as a real pause and resets back to the `100ms` minimum.
|
||||||
|
|
||||||
|
Timing is configurable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
surface-dial-renewed --mt-idle-ms 100 --mt-idle-max-ms 1500 --mt-settle-ms 80
|
||||||
|
```
|
||||||
|
|
||||||
|
`--mt-idle-ms` controls the fast-scroll minimum release timeout.
|
||||||
|
`--mt-idle-max-ms` controls the slow/precision maximum release timeout.
|
||||||
|
`--mt-settle-ms` controls the short stationary frame before the fingers lift.
|
||||||
|
|
||||||
## Sensitivity Selector
|
## Sensitivity Selector
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,25 @@ The service runs:
|
|||||||
|
|
||||||
It restarts on failure with a 2 second delay.
|
It restarts on failure with a 2 second delay.
|
||||||
|
|
||||||
|
To tune multitouch timing in the service, edit:
|
||||||
|
|
||||||
|
```text
|
||||||
|
~/.config/systemd/user/surface-dial-renewed.service
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ExecStart=%h/.cargo/bin/surface-dial-renewed --mode multitouch --mt-idle-ms 100 --mt-idle-max-ms 1500 --mt-settle-ms 80
|
||||||
|
```
|
||||||
|
|
||||||
|
Then reload and restart:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user restart surface-dial-renewed.service
|
||||||
|
```
|
||||||
|
|
||||||
Useful commands:
|
Useful commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
@@ -56,6 +56,27 @@ systemctl --user status surface-dial-renewed.service
|
|||||||
journalctl --user -u surface-dial-renewed.service -f
|
journalctl --user -u surface-dial-renewed.service -f
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Tune Multitouch Timing
|
||||||
|
|
||||||
|
Edit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/.config/systemd/user/surface-dial-renewed.service
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ExecStart=%h/.cargo/bin/surface-dial-renewed --mode multitouch --mt-idle-ms 100 --mt-idle-max-ms 1500 --mt-settle-ms 80
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
systemctl --user restart surface-dial-renewed.service
|
||||||
|
```
|
||||||
|
|
||||||
## Uninstall
|
## Uninstall
|
||||||
|
|
||||||
Automatic uninstall from the repository root:
|
Automatic uninstall from the repository root:
|
||||||
|
|||||||
+141
-25
@@ -5,7 +5,7 @@ mod notify;
|
|||||||
mod sensitivity;
|
mod sensitivity;
|
||||||
mod virtual_input;
|
mod virtual_input;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use dial::{DialEvent, DialEventKind, DialReader};
|
use dial::{DialEvent, DialEventKind, DialReader};
|
||||||
use error::Result;
|
use error::Result;
|
||||||
@@ -14,8 +14,12 @@ use notify::SensitivityNotifier;
|
|||||||
use sensitivity::Sensitivity;
|
use sensitivity::Sensitivity;
|
||||||
use virtual_input::{VirtualInput, WheelDirection};
|
use virtual_input::{VirtualInput, WheelDirection};
|
||||||
|
|
||||||
const MULTITOUCH_IDLE_TIMEOUT: Duration = Duration::from_millis(2_000);
|
const DEFAULT_MULTITOUCH_IDLE_TIMEOUT: Duration = Duration::from_millis(100);
|
||||||
const MULTITOUCH_SETTLE_TIMEOUT: Duration = Duration::from_millis(80);
|
const DEFAULT_MULTITOUCH_MAX_IDLE_TIMEOUT: Duration = Duration::from_millis(1_500);
|
||||||
|
const DEFAULT_MULTITOUCH_SETTLE_TIMEOUT: Duration = Duration::from_millis(80);
|
||||||
|
const DYNAMIC_IDLE_FAST_EVENT_MS: u128 = 80;
|
||||||
|
const DYNAMIC_IDLE_SLOW_EVENT_MS: u128 = 450;
|
||||||
|
const DYNAMIC_IDLE_RESET_MS: u128 = 2_500;
|
||||||
const SENSITIVITY_STEP_UNITS: i32 = 48;
|
const SENSITIVITY_STEP_UNITS: i32 = 48;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||||
@@ -24,6 +28,25 @@ enum OutputMode {
|
|||||||
Wheel,
|
Wheel,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct DriverConfig {
|
||||||
|
mode: OutputMode,
|
||||||
|
multitouch_idle_timeout: Duration,
|
||||||
|
multitouch_max_idle_timeout: Duration,
|
||||||
|
multitouch_settle_timeout: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DriverConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mode: OutputMode::Multitouch,
|
||||||
|
multitouch_idle_timeout: DEFAULT_MULTITOUCH_IDLE_TIMEOUT,
|
||||||
|
multitouch_max_idle_timeout: DEFAULT_MULTITOUCH_MAX_IDLE_TIMEOUT,
|
||||||
|
multitouch_settle_timeout: DEFAULT_MULTITOUCH_SETTLE_TIMEOUT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct DriverState {
|
struct DriverState {
|
||||||
mode: OutputMode,
|
mode: OutputMode,
|
||||||
@@ -36,6 +59,8 @@ struct DriverState {
|
|||||||
mt_active: bool,
|
mt_active: bool,
|
||||||
mt_position: i32,
|
mt_position: i32,
|
||||||
mt_remainder_milli: i32,
|
mt_remainder_milli: i32,
|
||||||
|
mt_current_idle_timeout: Duration,
|
||||||
|
mt_last_rotation_at: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DriverState {
|
impl DriverState {
|
||||||
@@ -49,6 +74,8 @@ impl DriverState {
|
|||||||
mt_active: false,
|
mt_active: false,
|
||||||
mt_position: 0,
|
mt_position: 0,
|
||||||
mt_remainder_milli: 0,
|
mt_remainder_milli: 0,
|
||||||
|
mt_current_idle_timeout: DEFAULT_MULTITOUCH_IDLE_TIMEOUT,
|
||||||
|
mt_last_rotation_at: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,8 +88,8 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> Result<()> {
|
fn run() -> Result<()> {
|
||||||
let mode = parse_mode(std::env::args().skip(1));
|
let config = parse_config(std::env::args().skip(1));
|
||||||
let mut state = DriverState::new(mode);
|
let mut state = DriverState::new(config.mode);
|
||||||
// Input reading runs on a worker thread; output devices stay owned by the
|
// Input reading runs on a worker thread; output devices stay owned by the
|
||||||
// main thread to avoid sharing uinput handles across threads.
|
// main thread to avoid sharing uinput handles across threads.
|
||||||
let mut dial = DialReader::spawn(Duration::from_millis(750))?;
|
let mut dial = DialReader::spawn(Duration::from_millis(750))?;
|
||||||
@@ -70,25 +97,38 @@ fn run() -> Result<()> {
|
|||||||
let mut notifier = SensitivityNotifier::new();
|
let mut notifier = SensitivityNotifier::new();
|
||||||
let mut haptics = Haptics::new();
|
let mut haptics = Haptics::new();
|
||||||
|
|
||||||
eprintln!("surface-dial-renewed: running in {mode:?} mode");
|
eprintln!(
|
||||||
|
"surface-dial-renewed: running in {:?} mode, mt_idle={}ms, mt_idle_max={}ms, mt_settle={}ms",
|
||||||
|
config.mode,
|
||||||
|
config.multitouch_idle_timeout.as_millis(),
|
||||||
|
config.multitouch_max_idle_timeout.as_millis(),
|
||||||
|
config.multitouch_settle_timeout.as_millis()
|
||||||
|
);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// While a synthetic two-finger gesture is active, recv with a timeout.
|
// While a synthetic two-finger gesture is active, recv with a timeout.
|
||||||
// Timeout means "the user stopped rotating", so the virtual fingers can
|
// Timeout means "the user stopped rotating", so the virtual fingers can
|
||||||
// be lifted. The 2s delay is deliberate: very slow Dial movement emits
|
// be lifted. The timeout is dynamic: normal/fast scrolling uses the old
|
||||||
// sparse REL_DIAL events, and libinput needs one continuous gesture to
|
// driver's 100ms release behavior, while sparse precision movement can
|
||||||
// recognize those as precise scroll movement.
|
// stretch toward the configured maximum. The last rotation timestamp is
|
||||||
|
// kept across gesture endings so slow events are not all treated as
|
||||||
|
// unrelated first events.
|
||||||
let timeout = if state.mt_active {
|
let timeout = if state.mt_active {
|
||||||
Some(MULTITOUCH_IDLE_TIMEOUT)
|
Some(state.mt_current_idle_timeout)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
match dial.next_event(timeout)? {
|
match dial.next_event(timeout)? {
|
||||||
Some(event) => {
|
Some(event) => handle_event(
|
||||||
handle_event(event, &mut state, &mut output, &mut notifier, &mut haptics)?
|
event,
|
||||||
}
|
&mut state,
|
||||||
None => end_multitouch_if_active(&mut state, &mut output)?,
|
&mut output,
|
||||||
|
&mut notifier,
|
||||||
|
&mut haptics,
|
||||||
|
&config,
|
||||||
|
)?,
|
||||||
|
None => end_multitouch_if_active(&mut state, &mut output, &config)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,6 +139,7 @@ fn handle_event(
|
|||||||
output: &mut VirtualInput,
|
output: &mut VirtualInput,
|
||||||
notifier: &mut SensitivityNotifier,
|
notifier: &mut SensitivityNotifier,
|
||||||
haptics: &mut Haptics,
|
haptics: &mut Haptics,
|
||||||
|
config: &DriverConfig,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
DialEventKind::Connected => {
|
DialEventKind::Connected => {
|
||||||
@@ -108,7 +149,7 @@ fn handle_event(
|
|||||||
haptics.reconnect();
|
haptics.reconnect();
|
||||||
}
|
}
|
||||||
DialEventKind::Disconnected => {
|
DialEventKind::Disconnected => {
|
||||||
end_multitouch_if_active(state, output)?;
|
end_multitouch_if_active(state, output, config)?;
|
||||||
haptics.disconnect();
|
haptics.disconnect();
|
||||||
eprintln!("surface-dial-renewed: dial disconnected");
|
eprintln!("surface-dial-renewed: dial disconnected");
|
||||||
}
|
}
|
||||||
@@ -133,13 +174,13 @@ fn handle_event(
|
|||||||
// Never scroll while the sensitivity selector is active. End a
|
// Never scroll while the sensitivity selector is active. End a
|
||||||
// pending touchpad gesture before showing the selector so the
|
// pending touchpad gesture before showing the selector so the
|
||||||
// desktop does not see overlapping scroll and adjustment input.
|
// desktop does not see overlapping scroll and adjustment input.
|
||||||
end_multitouch_if_active(state, output)?;
|
end_multitouch_if_active(state, output, config)?;
|
||||||
adjust_sensitivity(delta, state, notifier, haptics)?;
|
adjust_sensitivity(delta, state, notifier, haptics)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
match state.mode {
|
match state.mode {
|
||||||
OutputMode::Multitouch => multitouch_scroll(delta, state, output)?,
|
OutputMode::Multitouch => multitouch_scroll(delta, state, output, config)?,
|
||||||
OutputMode::Wheel => wheel_scroll(delta, state, output)?,
|
OutputMode::Wheel => wheel_scroll(delta, state, output)?,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +219,14 @@ fn adjust_sensitivity(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multitouch_scroll(delta: i32, state: &mut DriverState, output: &mut VirtualInput) -> Result<()> {
|
fn multitouch_scroll(
|
||||||
|
delta: i32,
|
||||||
|
state: &mut DriverState,
|
||||||
|
output: &mut VirtualInput,
|
||||||
|
config: &DriverConfig,
|
||||||
|
) -> Result<()> {
|
||||||
|
update_multitouch_idle_timeout(delta, state, config);
|
||||||
|
|
||||||
if !state.mt_active {
|
if !state.mt_active {
|
||||||
state.mt_position = 0;
|
state.mt_position = 0;
|
||||||
output.multitouch_start()?;
|
output.multitouch_start()?;
|
||||||
@@ -216,6 +264,38 @@ fn multitouch_scroll(delta: i32, state: &mut DriverState, output: &mut VirtualIn
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_multitouch_idle_timeout(_delta: i32, state: &mut DriverState, config: &DriverConfig) {
|
||||||
|
let now = Instant::now();
|
||||||
|
let event_gap = state
|
||||||
|
.mt_last_rotation_at
|
||||||
|
.map(|last| now.saturating_duration_since(last));
|
||||||
|
state.mt_last_rotation_at = Some(now);
|
||||||
|
|
||||||
|
let Some(event_gap) = event_gap else {
|
||||||
|
state.mt_current_idle_timeout = config.multitouch_idle_timeout;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let gap_ms = event_gap.as_millis();
|
||||||
|
state.mt_current_idle_timeout = if gap_ms >= DYNAMIC_IDLE_RESET_MS {
|
||||||
|
// A genuine pause should not make the first new scroll linger.
|
||||||
|
config.multitouch_idle_timeout
|
||||||
|
} else if gap_ms >= DYNAMIC_IDLE_SLOW_EVENT_MS {
|
||||||
|
config.multitouch_max_idle_timeout
|
||||||
|
} else if gap_ms <= DYNAMIC_IDLE_FAST_EVENT_MS {
|
||||||
|
config.multitouch_idle_timeout
|
||||||
|
} else {
|
||||||
|
let fast = DYNAMIC_IDLE_FAST_EVENT_MS;
|
||||||
|
let slow = DYNAMIC_IDLE_SLOW_EVENT_MS;
|
||||||
|
let span = slow.saturating_sub(fast).max(1);
|
||||||
|
let progress = gap_ms.saturating_sub(fast).min(span);
|
||||||
|
let min_ms = config.multitouch_idle_timeout.as_millis();
|
||||||
|
let max_ms = config.multitouch_max_idle_timeout.as_millis().max(min_ms);
|
||||||
|
let dynamic_ms = min_ms + ((max_ms - min_ms) * progress) / span;
|
||||||
|
Duration::from_millis(dynamic_ms as u64)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn wheel_scroll(delta: i32, state: &DriverState, output: &mut VirtualInput) -> Result<()> {
|
fn wheel_scroll(delta: i32, state: &DriverState, output: &mut VirtualInput) -> Result<()> {
|
||||||
let ticks = delta.abs().saturating_mul(state.sensitivity.wheel_ticks());
|
let ticks = delta.abs().saturating_mul(state.sensitivity.wheel_ticks());
|
||||||
let direction = if delta > 0 {
|
let direction = if delta > 0 {
|
||||||
@@ -231,36 +311,72 @@ fn wheel_scroll(delta: i32, state: &DriverState, output: &mut VirtualInput) -> R
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_multitouch_if_active(state: &mut DriverState, output: &mut VirtualInput) -> Result<()> {
|
fn end_multitouch_if_active(
|
||||||
|
state: &mut DriverState,
|
||||||
|
output: &mut VirtualInput,
|
||||||
|
config: &DriverConfig,
|
||||||
|
) -> Result<()> {
|
||||||
if state.mt_active {
|
if state.mt_active {
|
||||||
// Emit one stationary frame and wait briefly before lifting fingers.
|
// Emit one stationary frame and wait briefly before lifting fingers.
|
||||||
// This made libinput less likely to interpret the final delta as a
|
// This made libinput less likely to interpret the final delta as a
|
||||||
// touchpad flick/coast.
|
// touchpad flick/coast.
|
||||||
output.multitouch_settle(state.mt_position)?;
|
output.multitouch_settle(state.mt_position)?;
|
||||||
std::thread::sleep(MULTITOUCH_SETTLE_TIMEOUT);
|
std::thread::sleep(config.multitouch_settle_timeout);
|
||||||
output.multitouch_end()?;
|
output.multitouch_end()?;
|
||||||
state.mt_active = false;
|
state.mt_active = false;
|
||||||
state.mt_position = 0;
|
state.mt_position = 0;
|
||||||
state.mt_remainder_milli = 0;
|
state.mt_remainder_milli = 0;
|
||||||
|
state.mt_current_idle_timeout = config.multitouch_idle_timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_mode(args: impl Iterator<Item = String>) -> OutputMode {
|
fn parse_config(args: impl Iterator<Item = String>) -> DriverConfig {
|
||||||
let mut mode = OutputMode::Multitouch;
|
let mut config = DriverConfig::default();
|
||||||
let mut previous = String::new();
|
let mut previous = String::new();
|
||||||
|
|
||||||
for arg in args {
|
for arg in args {
|
||||||
if previous == "--mode" {
|
if previous == "--mode" {
|
||||||
mode = parse_mode_value(&arg);
|
config.mode = parse_mode_value(&arg);
|
||||||
|
} else if previous == "--mt-idle-ms" {
|
||||||
|
config.multitouch_idle_timeout = Duration::from_millis(parse_ms(&arg, "mt-idle-ms"));
|
||||||
|
} else if previous == "--mt-idle-max-ms" {
|
||||||
|
config.multitouch_max_idle_timeout =
|
||||||
|
Duration::from_millis(parse_ms(&arg, "mt-idle-max-ms"));
|
||||||
|
} else if previous == "--mt-settle-ms" {
|
||||||
|
config.multitouch_settle_timeout =
|
||||||
|
Duration::from_millis(parse_ms(&arg, "mt-settle-ms"));
|
||||||
} else if let Some(value) = arg.strip_prefix("--mode=") {
|
} else if let Some(value) = arg.strip_prefix("--mode=") {
|
||||||
mode = parse_mode_value(value);
|
config.mode = parse_mode_value(value);
|
||||||
|
} else if let Some(value) = arg.strip_prefix("--mt-idle-ms=") {
|
||||||
|
config.multitouch_idle_timeout = Duration::from_millis(parse_ms(value, "mt-idle-ms"));
|
||||||
|
} else if let Some(value) = arg.strip_prefix("--mt-idle-max-ms=") {
|
||||||
|
config.multitouch_max_idle_timeout =
|
||||||
|
Duration::from_millis(parse_ms(value, "mt-idle-max-ms"));
|
||||||
|
} else if let Some(value) = arg.strip_prefix("--mt-settle-ms=") {
|
||||||
|
config.multitouch_settle_timeout =
|
||||||
|
Duration::from_millis(parse_ms(value, "mt-settle-ms"));
|
||||||
}
|
}
|
||||||
previous = arg;
|
previous = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
mode
|
config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_ms(value: &str, name: &str) -> u64 {
|
||||||
|
match value.parse::<u64>() {
|
||||||
|
Ok(ms) => ms,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("surface-dial-renewed: invalid --{name} '{value}', using default");
|
||||||
|
match name {
|
||||||
|
"mt-idle-ms" => DEFAULT_MULTITOUCH_IDLE_TIMEOUT.as_millis() as u64,
|
||||||
|
"mt-idle-max-ms" => DEFAULT_MULTITOUCH_MAX_IDLE_TIMEOUT.as_millis() as u64,
|
||||||
|
"mt-settle-ms" => DEFAULT_MULTITOUCH_SETTLE_TIMEOUT.as_millis() as u64,
|
||||||
|
_ => 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_mode_value(value: &str) -> OutputMode {
|
fn parse_mode_value(value: &str) -> OutputMode {
|
||||||
|
|||||||
Reference in New Issue
Block a user