Created
April 28, 2026 09:06
-
-
Save kb10uy/84ce34b8ca4d3eed95d21bf018121dee to your computer and use it in GitHub Desktop.
Win11 の InputHapticsManager の機能を試す
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env rust-script | |
| //! ```cargo | |
| //! [dependencies] | |
| //! softbuffer = "0.4" | |
| //! winit = "0.30" | |
| //! windows = { | |
| //! git = "https://github.com/microsoft/windows-rs", | |
| //! ref = "1742a73cf7852414e0b304aca148d8b83a586546", | |
| //! features = ["Devices_Haptics"] | |
| //! } | |
| //! ``` | |
| use std::num::NonZeroU32; | |
| use std::rc::Rc; | |
| use softbuffer::Surface; | |
| use windows::Devices::Haptics::{InputHapticsManager, KnownSimpleHapticsControllerWaveforms}; | |
| use winit::{ | |
| application::ApplicationHandler, | |
| dpi::PhysicalSize, | |
| event::WindowEvent, | |
| event_loop::{ActiveEventLoop, EventLoop}, | |
| window::{Window, WindowId}, | |
| }; | |
| const GRID_COLS: u32 = 8; | |
| const GRID_ROWS: u32 = 8; | |
| const COLOR_A: u32 = 0x00_2E_2E_2E; // dark gray | |
| const COLOR_B: u32 = 0x00_4A_4A_4A; // lighter gray | |
| fn main() { | |
| let event_loop = EventLoop::new().expect("failed to initialize EventLoop"); | |
| let mut app = App::new(); | |
| event_loop.run_app(&mut app).expect("failed to start"); | |
| } | |
| struct App { | |
| window: Option<Rc<Window>>, | |
| surface: Option<Surface<Rc<Window>, Rc<Window>>>, | |
| current_cell: Option<(u32, u32)>, | |
| } | |
| impl App { | |
| fn new() -> Self { | |
| Self { | |
| window: None, | |
| surface: None, | |
| current_cell: None, | |
| } | |
| } | |
| fn draw_grid(&mut self) { | |
| let (Some(window), Some(surface)) = (&self.window, &mut self.surface) else { | |
| return; | |
| }; | |
| let PhysicalSize { width, height } = window.inner_size(); | |
| if width * height == 0 { | |
| return; | |
| } | |
| surface | |
| .resize( | |
| NonZeroU32::new(width).unwrap(), | |
| NonZeroU32::new(height).unwrap(), | |
| ) | |
| .ok(); | |
| let Ok(mut buffer) = surface.buffer_mut() else { | |
| return; | |
| }; | |
| for y in 0..height { | |
| for x in 0..width { | |
| let col = (x * GRID_COLS / width).min(GRID_COLS - 1); | |
| let row = (y * GRID_ROWS / height).min(GRID_ROWS - 1); | |
| let checkerboard = (col + row).is_multiple_of(2); | |
| buffer[(y * width + x) as usize] = if checkerboard { COLOR_A } else { COLOR_B }; | |
| } | |
| } | |
| buffer.present().ok(); | |
| } | |
| fn send_haptic(&self) { | |
| let Ok(manager) = InputHapticsManager::GetForCurrentThread() else { | |
| return; | |
| }; | |
| manager | |
| .TrySendHapticWaveform( | |
| KnownSimpleHapticsControllerWaveforms::Hover().expect("should have value"), | |
| 0, | |
| ) | |
| .ok(); | |
| } | |
| } | |
| impl ApplicationHandler for App { | |
| fn resumed(&mut self, event_loop: &ActiveEventLoop) { | |
| if self.window.is_none() { | |
| let attrs = Window::default_attributes() | |
| .with_title("InputHapticsManager test (sends when cursor crosses the grid"); | |
| match event_loop.create_window(attrs) { | |
| Ok(window) => { | |
| let window = Rc::new(window); | |
| let context = softbuffer::Context::new(window.clone()).unwrap(); | |
| let surface = Surface::new(&context, window.clone()).unwrap(); | |
| self.window = Some(window); | |
| self.surface = Some(surface); | |
| } | |
| Err(e) => { | |
| eprintln!("Failed to create window: {e}"); | |
| event_loop.exit(); | |
| } | |
| } | |
| } | |
| } | |
| fn window_event(&mut self, event_loop: &ActiveEventLoop, _id: WindowId, event: WindowEvent) { | |
| match event { | |
| WindowEvent::CloseRequested => { | |
| event_loop.exit(); | |
| } | |
| WindowEvent::RedrawRequested => { | |
| self.draw_grid(); | |
| } | |
| WindowEvent::Resized(_) => { | |
| if let Some(window) = &self.window { | |
| window.request_redraw(); | |
| } | |
| } | |
| WindowEvent::CursorMoved { position, .. } => { | |
| if let Some(window) = &self.window { | |
| let size = window.inner_size(); | |
| let col = ((position.x / size.width as f64) * GRID_COLS as f64) as u32; | |
| let row = ((position.y / size.height as f64) * GRID_ROWS as f64) as u32; | |
| let col = col.min(GRID_COLS - 1); | |
| let row = row.min(GRID_ROWS - 1); | |
| let new_cell = (col, row); | |
| if self.current_cell != Some(new_cell) { | |
| if self.current_cell.is_some() { | |
| self.send_haptic(); | |
| } | |
| self.current_cell = Some(new_cell); | |
| } | |
| } | |
| } | |
| _ => {} | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment