DeviceHaptics task

This commit is contained in:
galister
2025-12-24 17:27:02 +09:00
parent 1d6a0e4bde
commit 10191385e4
11 changed files with 80 additions and 11 deletions

View File

@@ -10,7 +10,7 @@ use smallvec::{SmallVec, smallvec};
use wlx_common::common::LeftRight;
use wlx_common::windowing::{OverlayWindowState, Positioning};
use crate::backend::task::OverlayTask;
use crate::backend::task::{InputTask, OverlayTask};
use crate::overlays::anchor::{ANCHOR_NAME, GRAB_HELP_NAME};
use crate::overlays::watch::WATCH_NAME;
use crate::state::{AppSession, AppState};
@@ -65,6 +65,18 @@ impl InputState {
}
}
pub fn handle_task(&mut self, task: InputTask) {
match task {
InputTask::Haptics { device, haptics } => {
if let Some(pointer) = self.pointers.get_mut(device) {
pointer.pending_haptics = Some(haptics);
} else {
log::warn!("Can't trigger haptics on non-existing device: {device}");
}
}
}
}
pub const fn pre_update(&mut self) {
self.pointers[0].before = self.pointers[0].now;
self.pointers[1].before = self.pointers[1].now;
@@ -218,6 +230,7 @@ pub struct Pointer {
pub now: PointerState,
pub before: PointerState,
pub last_click: Instant,
pub pending_haptics: Option<Haptics>,
pub(super) interaction: InteractionState,
}
@@ -231,6 +244,7 @@ impl Pointer {
now: PointerState::default(),
before: PointerState::default(),
last_click: Instant::now(),
pending_haptics: None,
interaction: InteractionState::default(),
}
}
@@ -340,6 +354,8 @@ where
{
// already grabbing, ignore everything else
let mut pointer = &mut app.input_state.pointers[idx];
let pending_haptics = pointer.pending_haptics.take();
if let Some(grab_data) = pointer.interaction.grabbed {
if let Some(grabbed) = overlays.mut_by_id(grab_data.grabbed_id) {
handle_grabbed(idx, grabbed, app);
@@ -347,13 +363,13 @@ where
log::warn!("Grabbed overlay {:?} does not exist", grab_data.grabbed_id);
pointer.interaction.grabbed = None;
}
return (0.1, None);
return (0.1, pending_haptics);
}
let hovered_id = pointer.interaction.hovered_id.take();
let (Some(mut hit), haptics) = get_nearest_hit(idx, overlays, app) else {
handle_no_hit(idx, hovered_id, overlays, app);
return (0.0, None); // no hit
return (0.0, pending_haptics); // no hit
};
// focus change
@@ -378,7 +394,7 @@ where
let Some(hovered) = overlays.mut_by_id(hit.overlay) else {
log::warn!("Hit overlay {:?} does not exist", hit.overlay);
return (0.0, None); // no hit
return (0.0, pending_haptics); // no hit
};
pointer = &mut app.input_state.pointers[idx];
pointer.interaction.hovered_id = Some(hit.overlay);
@@ -447,7 +463,7 @@ where
}
}
(hit.dist, haptics)
(hit.dist, haptics.or(pending_haptics))
}
fn handle_no_hit<O>(

View File

@@ -26,7 +26,7 @@ use crate::{
manifest::{install_manifest, uninstall_manifest},
overlay::OpenVrOverlayData,
},
task::{OpenVrTask, OverlayTask, TaskType},
task::{InputTask, OpenVrTask, OverlayTask, TaskType},
},
config::save_state,
graphics::{GpuFutures, init_openvr_graphics},
@@ -220,6 +220,9 @@ pub fn openvr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
while let Some(task) = due_tasks.pop_front() {
match task {
TaskType::Input(task) => {
app.input_state.handle_task(task);
}
TaskType::Overlay(task) => {
overlays.handle_task(&mut app, task)?;
}

View File

@@ -489,6 +489,9 @@ pub fn openxr_run(show_by_default: bool, headless: bool) -> Result<(), BackendEr
app.tasks.retrieve_due(&mut due_tasks);
while let Some(task) = due_tasks.pop_front() {
match task {
TaskType::Input(task) => {
app.input_state.handle_task(task);
}
TaskType::Overlay(task) => {
overlays.handle_task(&mut app, task)?;
}

View File

@@ -8,6 +8,7 @@ use std::{
use serde::Deserialize;
use crate::{
backend::input,
state::AppState,
windowing::{OverlaySelector, window::OverlayWindowConfig},
};
@@ -43,6 +44,13 @@ impl Ord for AppTask {
}
}
pub enum InputTask {
Haptics {
device: usize,
haptics: input::Haptics,
},
}
#[cfg(feature = "openvr")]
pub enum OpenVrTask {
ColorGain(ColorChannel, f32),
@@ -87,6 +95,7 @@ pub enum OverlayTask {
}
pub enum TaskType {
Input(InputTask),
Overlay(OverlayTask),
Playspace(PlayspaceTask),
#[cfg(feature = "openvr")]

View File

@@ -10,7 +10,7 @@ use crate::{
use crate::{
backend::{
self,
task::{OverlayTask, TaskType},
task::{InputTask, OverlayTask, TaskType},
},
ipc::signal::WayVRSignal,
overlays::{self},
@@ -160,6 +160,10 @@ where
wayland_server.pending_haptics = Some(haptics);
}
}
WayVRSignal::DeviceHaptics(device, haptics) => {
app.tasks
.enqueue(TaskType::Input(InputTask::Haptics { device, haptics }));
}
WayVRSignal::DropOverlay(overlay_id) => {
app.tasks
.enqueue(TaskType::Overlay(OverlayTask::Drop(OverlaySelector::Id(

View File

@@ -507,6 +507,21 @@ impl Connection {
}));
}
fn handle_wlx_device_haptics(
params: &mut TickParams,
device: usize,
haptics_params: packet_client::WlxHapticsParams,
) {
params.signals.send(WayVRSignal::DeviceHaptics(
device,
crate::backend::input::Haptics {
duration: haptics_params.duration,
frequency: haptics_params.frequency,
intensity: haptics_params.intensity,
},
));
}
fn handle_wlx_panel(
params: &mut TickParams,
custom_params: packet_client::WlxModifyPanelParams,
@@ -606,6 +621,9 @@ impl Connection {
#[cfg(feature = "wayvr")]
Self::handle_wlx_haptics(params, haptics_params);
}
PacketClient::WlxDeviceHaptics(device, haptics_params) => {
Self::handle_wlx_device_haptics(params, device, haptics_params);
}
PacketClient::WlxModifyPanel(custom_params) => {
Self::handle_wlx_panel(params, custom_params);
}

View File

@@ -14,6 +14,7 @@ pub enum WayVRSignal {
BroadcastStateChanged(wayvr_ipc::packet_server::WvrStateChanged),
#[cfg(feature = "wayvr")]
Haptics(crate::backend::input::Haptics),
DeviceHaptics(usize, crate::backend::input::Haptics),
DropOverlay(crate::windowing::OverlayID),
CustomTask(crate::backend::task::ModifyPanelTask),
}