From ec40f6e3acc7874b82709ab81b254c741529fdff Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 26 Oct 2026 10:52:04 -0400 Subject: Finish engine --- platforms/tortuise-script-wasm/src/input.rs | 264 ++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 platforms/tortuise-script-wasm/src/input.rs (limited to 'platforms/tortuise-script-wasm/src/input.rs') diff --git a/platforms/tortuise-script-wasm/src/input.rs b/platforms/tortuise-script-wasm/src/input.rs new file mode 100644 index 0000000..07cbe62 --- /dev/null +++ b/platforms/tortuise-script-wasm/src/input.rs @@ -0,0 +1,264 @@ +use serde::{Deserialize, Serialize}; + +use crate::ScriptContext; + +mod tortuise { + #[link(wasm_import_module = "tortuise")] + unsafe extern "C" { + pub safe fn is_key_pressed_this_frame(context: u64, keycode: u32) -> u32; + pub safe fn is_mouse_clicked_this_frame(context: u64) -> u32; + pub safe fn mouse_location(context: u64) -> u32; + pub safe fn scroll_direction_this_frame(context: u64) -> u32; + pub safe fn is_button_pressed_this_frame(context: u64, gamepad_id: u32, button: u32) + -> u32; + pub safe fn is_button_released_this_frame( + context: u64, + gamepad_id: u32, + button: u32, + ) -> u32; + pub safe fn is_button_down(context: u64, gamepad_id: u32, button: u32) -> u32; + pub safe fn axis_value(context: u64, gamepad_id: u32, axis: u32) -> f32; + pub safe fn is_gamepad_connected_this_frame(context: u64) -> u32; + pub safe fn is_gamepad_connected(context: u64, gamepad_id: u32) -> u32; + pub safe fn gamepad_power_info(context: u64, gamepad_id: u32) -> u32; + pub safe fn is_focused(context: u64) -> u32; + pub safe fn was_focused_this_frame(context: u64) -> u32; + pub safe fn was_unfocused_this_frame(context: u64) -> u32; + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Position { + pub x: u16, + pub y: u16, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Direction { + Up = 1, + Down, + Left, + Right, +} + +/// Represents a key. +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)] +pub enum KeyCode { + /// Backspace key (Delete on macOS, Backspace on other platforms). + Backspace, + /// Enter key. + Enter, + /// Left arrow key. + Left, + /// Right arrow key. + Right, + /// Up arrow key. + Up, + /// Down arrow key. + Down, + /// Home key. + Home, + /// End key. + End, + /// Page up key. + PageUp, + /// Page down key. + PageDown, + /// Tab key. + Tab, + /// Shift + Tab key. + BackTab, + /// Delete key. (Fn+Delete on macOS, Delete on other platforms) + Delete, + /// Insert key. + Insert, + /// F key. + /// + /// `KeyCode::F(1)` represents F1 key, etc. + F(u8), + /// A character. + /// + /// `KeyCode::Char('c')` represents `c` character, etc. + Char(char), + /// Null. + Null, + /// Escape key. + Esc, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Button { + // Action Pad + South = 1, + East = 2, + North = 4, + West = 5, + C = 3, + Z = 6, + // Triggers + LeftTrigger = 7, + LeftTrigger2 = 9, + RightTrigger = 8, + RightTrigger2 = 10, + // Menu Pad + Select = 11, + Start = 12, + Mode = 13, + // Sticks + LeftThumb = 14, + RightThumb = 15, + // D-Pad + DPadUp = 16, + DPadDown = 17, + DPadLeft = 18, + DPadRight = 19, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Axis { + LeftStickX = 1, + LeftStickY = 2, + LeftZ = 3, + RightStickX = 4, + RightStickY = 5, + RightZ = 6, + DPadX = 7, + DPadY = 8, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum PowerInfo { + Wired, + Discharging(u8), + Charging(u8), + Charged, + Unknown, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Gamepad(u32); + +impl From for Position { + fn from(value: u32) -> Self { + Self { + x: (value & 0xffff) as u16, + y: ((value >> 16) & 0xffff) as u16, + } + } +} + +impl TryFrom for Direction { + type Error = (); + + fn try_from(value: u32) -> Result { + match value { + 1 => Ok(Direction::Up), + 2 => Ok(Direction::Down), + 3 => Ok(Direction::Left), + 4 => Ok(Direction::Right), + _ => Err(()), + } + } +} + +fn key_code_to_number(key_code: KeyCode) -> u32 { + match key_code { + KeyCode::Null => 0, + KeyCode::Backspace => 1 << 24, + KeyCode::Enter => 2 << 24, + KeyCode::Left => 3 << 24, + KeyCode::Right => 4 << 24, + KeyCode::Up => 5 << 24, + KeyCode::Down => 6 << 24, + KeyCode::Home => 7 << 24, + KeyCode::End => 8 << 24, + KeyCode::PageUp => 9 << 24, + KeyCode::PageDown => 10 << 24, + KeyCode::Tab => 11 << 24, + KeyCode::BackTab => 12 << 24, + KeyCode::Delete => 13 << 24, + KeyCode::Insert => 14 << 24, + KeyCode::F(f) => 15 << 24 | f as u32, + KeyCode::Char(c) => 16 << 24 | c as u32, + KeyCode::Esc => 17 << 24, + } +} + +impl Gamepad { + pub fn is_button_pressed_this_frame(&self, context: &ScriptContext, button: Button) -> bool { + tortuise::is_button_pressed_this_frame(context.0, self.0, button as u32) > 0 + } + + pub fn is_button_released_this_frame(&self, context: &ScriptContext, button: Button) -> bool { + tortuise::is_button_released_this_frame(context.0, self.0, button as u32) > 0 + } + + pub fn is_button_down(&self, context: &ScriptContext, button: Button) -> bool { + tortuise::is_button_down(context.0, self.0, button as u32) > 0 + } + + pub fn axis_value(&self, context: &ScriptContext, axis: Axis) -> f32 { + tortuise::axis_value(context.0, self.0, axis as u32) + } + + pub fn is_connected(&self, context: &ScriptContext) -> bool { + tortuise::is_gamepad_connected(context.0, self.0) > 0 + } + + pub fn power_info(&self, context: &ScriptContext) -> PowerInfo { + const WIRED: u32 = 1 << 16; + const DISCHARGING: u32 = 2 << 16; + const CHARGING: u32 = 3 << 16; + const CHARGED: u32 = 4 << 16; + + match tortuise::gamepad_power_info(context.0, self.0) { + WIRED => PowerInfo::Wired, + power @ DISCHARGING..CHARGING => PowerInfo::Discharging((power & 0xff) as u8), + power @ CHARGING..CHARGED => PowerInfo::Charging((power & 0xff) as u8), + CHARGED => PowerInfo::Charged, + _ => PowerInfo::Unknown, + } + } +} + +impl ScriptContext<'_> { + pub fn is_key_pressed_this_frame(&self, key_code: KeyCode) -> bool { + tortuise::is_key_pressed_this_frame(self.0, key_code_to_number(key_code)) > 0 + } + + pub fn is_mouse_clicked_this_frame(&self) -> bool { + tortuise::is_mouse_clicked_this_frame(self.0) > 0 + } + + pub fn mouse_location(&self) -> Option { + let location = tortuise::mouse_location(self.0); + (location != u32::MAX).then(|| location.into()) + } + + pub fn scroll_direction_this_frame(&self) -> Option { + tortuise::scroll_direction_this_frame(self.0) + .try_into() + .ok() + } + + pub fn is_gamepad_connected_this_frame(&self) -> Option { + let gamepad_id = tortuise::is_gamepad_connected_this_frame(self.0); + if gamepad_id == 0 { + return None; + } + + Some(Gamepad(gamepad_id)) + } + + pub fn is_focused(&self) -> bool { + tortuise::is_focused(self.0) > 0 + } + + pub fn was_focused_this_frame(&self) -> bool { + tortuise::was_focused_this_frame(self.0) > 0 + } + + pub fn was_unfocused_this_frame(&self) -> bool { + tortuise::was_unfocused_this_frame(self.0) > 0 + } +} -- cgit v1.3.1