diff --git a/Cargo.lock b/Cargo.lock index c1c86103..ccfa1bca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,9 +42,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "bitvec" @@ -81,9 +81,9 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "compact_str" @@ -160,9 +160,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -222,9 +222,12 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "indoc" -version = "2.0.6" +version = "2.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] [[package]] name = "instability" @@ -256,9 +259,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "js-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -266,15 +269,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.176" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" - -[[package]] -name = "log" -version = "0.4.28" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "lru" @@ -329,18 +326,18 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -377,6 +374,7 @@ name = "ratzilla" version = "0.2.0" dependencies = [ "beamterm-renderer", + "bitflags", "bitvec", "compact_str 0.9.0", "console_error_panic_hook", @@ -462,9 +460,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" dependencies = [ "proc-macro2", "quote", @@ -520,9 +518,9 @@ checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "unicode-ident" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -555,9 +553,9 @@ checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "wasm-bindgen" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -566,25 +564,11 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.54" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e038d41e478cc73bae0ff9b36c60cff1c98b8f38f8d7e8061e79ee63608ac5c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -595,9 +579,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -605,31 +589,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.104" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.81" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9367c417a924a74cae129e6a2ae3b47fabb1f8995595ab474029da749a8be120" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index 25d5b07d..780976e4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,10 +10,10 @@ repository = "https://github.com/orhun/ratzilla" keywords = ["tui", "webassembly", "ratatui"] categories = ["wasm"] include = ["src/**/*", "Cargo.*", "LICENSE", "README.md", "CHANGELOG.md"] -edition = "2021" +edition = "2024" [dependencies] -web-sys = { version = "0.3.81", features = [ +web-sys = { version = "0.3.82", features = [ 'console', 'CanvasRenderingContext2d', 'Document', @@ -40,6 +40,7 @@ web-sys = { version = "0.3.81", features = [ compact_str = "0.9.0" ratatui = { version = "0.29", default-features = false, features = ["all-widgets"] } console_error_panic_hook = "0.1.7" -thiserror = "2.0.12" +thiserror = "2.0.17" bitvec = { version = "1.0.1", default-features = false, features = ["alloc", "std"] } beamterm-renderer = "0.8.0" +bitflags = "2.10.0" diff --git a/src/backend/canvas.rs b/src/backend/canvas.rs index 33dea067..ce9e1a78 100644 --- a/src/backend/canvas.rs +++ b/src/backend/canvas.rs @@ -3,12 +3,12 @@ use ratatui::layout::Rect; use std::io::Result as IoResult; use crate::{ + CursorShape, backend::{ color::{actual_bg_color, actual_fg_color}, utils::*, }, error::Error, - CursorShape, }; use ratatui::{ backend::WindowSize, diff --git a/src/backend/color.rs b/src/backend/color.rs index e7b3ad67..d8c21ff1 100644 --- a/src/backend/color.rs +++ b/src/backend/color.rs @@ -91,13 +91,7 @@ fn indexed_color_to_rgb(index: u8) -> u32 { // Convert 0-5 range to 0-255 RGB // Values: 0 -> 0, 1 -> 95, 2 -> 135, 3 -> 175, 4 -> 215, 5 -> 255 - let to_rgb = |n: u8| -> u32 { - if n == 0 { - 0 - } else { - 55 + 40 * n as u32 - } - }; + let to_rgb = |n: u8| -> u32 { if n == 0 { 0 } else { 55 + 40 * n as u32 } }; to_rgb(r) << 16 | to_rgb(g) << 8 | to_rgb(b) } diff --git a/src/backend/dom.rs b/src/backend/dom.rs index 2ce52ebd..3fb7dbcf 100644 --- a/src/backend/dom.rs +++ b/src/backend/dom.rs @@ -7,11 +7,12 @@ use ratatui::{ prelude::Backend, }; use web_sys::{ - wasm_bindgen::{prelude::Closure, JsCast}, - window, Document, Element, Window, + Document, Element, Window, + wasm_bindgen::{JsCast, prelude::Closure}, + window, }; -use crate::{backend::utils::*, error::Error, widgets::hyperlink::HYPERLINK_MODIFIER, CursorShape}; +use crate::{CursorShape, backend::utils::*, error::Error, widgets::hyperlink::HYPERLINK_MODIFIER}; /// Options for the [`DomBackend`]. #[derive(Debug, Default)] diff --git a/src/backend/utils.rs b/src/backend/utils.rs index ed9d2565..af46b52b 100644 --- a/src/backend/utils.rs +++ b/src/backend/utils.rs @@ -3,14 +3,15 @@ use crate::{ error::Error, utils::{get_screen_size, get_window_size, is_mobile}, }; -use compact_str::{format_compact, CompactString}; +use compact_str::{CompactString, format_compact}; use ratatui::{ buffer::Cell, style::{Color, Modifier}, }; use web_sys::{ + Document, Element, HtmlCanvasElement, Window, wasm_bindgen::{JsCast, JsValue}, - window, Document, Element, HtmlCanvasElement, Window, + window, }; /// Creates a new `` element with the given cell. diff --git a/src/backend/webgl2.rs b/src/backend/webgl2.rs index 8c95e41b..4124a2f3 100644 --- a/src/backend/webgl2.rs +++ b/src/backend/webgl2.rs @@ -1,11 +1,11 @@ use crate::{ + CursorShape, backend::{color::to_rgb, utils::*}, error::Error, widgets::hyperlink::HYPERLINK_MODIFIER, - CursorShape, }; use beamterm_renderer::{ - mouse::*, select, CellData, GlyphEffect, SelectionMode, Terminal as Beamterm, Terminal, + CellData, GlyphEffect, SelectionMode, Terminal as Beamterm, Terminal, mouse::*, select, }; use bitvec::prelude::BitVec; use compact_str::CompactString; @@ -17,7 +17,7 @@ use ratatui::{ style::{Color, Modifier}, }; use std::{cell::RefCell, io::Result as IoResult, mem::swap, rc::Rc}; -use web_sys::{wasm_bindgen::JsCast, window, Element}; +use web_sys::{Element, wasm_bindgen::JsCast, window}; /// Re-export beamterm's atlas data type. Used by [`WebGl2BackendOptions::font_atlas`]. pub use beamterm_renderer::FontAtlasData; @@ -431,7 +431,7 @@ impl WebGl2Backend { c.style(c.get_style() ^ (GlyphEffect::Underline as u16)); } } - } + }; } /// Measures the beginning of a performance mark. diff --git a/src/event.rs b/src/event.rs deleted file mode 100644 index 07f9590e..00000000 --- a/src/event.rs +++ /dev/null @@ -1,207 +0,0 @@ -/// A key event. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct KeyEvent { - /// The key code. - pub code: KeyCode, - /// Whether the control key is pressed. - pub ctrl: bool, - /// Whether the alt key is pressed. - pub alt: bool, - /// Whether the shift key is pressed. - pub shift: bool, -} - -/// A mouse movement event. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct MouseEvent { - /// The mouse button that was pressed. - pub button: MouseButton, - /// The triggered event. - pub event: MouseEventKind, - /// The x coordinate of the mouse. - pub x: u32, - /// The y coordinate of the mouse. - pub y: u32, - /// Whether the control key is pressed. - pub ctrl: bool, - /// Whether the alt key is pressed. - pub alt: bool, - /// Whether the shift key is pressed. - pub shift: bool, -} - -/// Convert a [`web_sys::KeyboardEvent`] to a [`KeyEvent`]. -impl From for KeyEvent { - fn from(event: web_sys::KeyboardEvent) -> Self { - let ctrl = event.ctrl_key(); - let alt = event.alt_key(); - let shift = event.shift_key(); - KeyEvent { - code: event.into(), - ctrl, - alt, - shift, - } - } -} - -/// A key code. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum KeyCode { - /// Normal letter key input. - Char(char), - /// F keys. - F(u8), - /// Backspace key - Backspace, - /// Enter or return key - Enter, - /// Left arrow key - Left, - /// Right arrow key - Right, - /// Up arrow key - Up, - /// Down arrow key - Down, - /// Tab key - Tab, - /// Delete key - Delete, - /// Home key - Home, - /// End key - End, - /// Page up key - PageUp, - /// Page down key - PageDown, - /// Escape key - Esc, - /// Unidentified. - Unidentified, -} - -/// Convert a [`web_sys::KeyboardEvent`] to a [`KeyCode`]. -impl From for KeyCode { - fn from(event: web_sys::KeyboardEvent) -> Self { - let key = event.key(); - if key.len() == 1 { - let char = key.chars().next(); - if let Some(char) = char { - return KeyCode::Char(char); - } else { - return KeyCode::Unidentified; - } - } - match key.as_str() { - "F1" => KeyCode::F(1), - "F2" => KeyCode::F(2), - "F3" => KeyCode::F(3), - "F4" => KeyCode::F(4), - "F5" => KeyCode::F(5), - "F6" => KeyCode::F(6), - "F7" => KeyCode::F(7), - "F8" => KeyCode::F(8), - "F9" => KeyCode::F(9), - "F10" => KeyCode::F(10), - "F11" => KeyCode::F(11), - "F12" => KeyCode::F(12), - "Backspace" => KeyCode::Backspace, - "Enter" => KeyCode::Enter, - "ArrowLeft" => KeyCode::Left, - "ArrowRight" => KeyCode::Right, - "ArrowUp" => KeyCode::Up, - "ArrowDown" => KeyCode::Down, - "Tab" => KeyCode::Tab, - "Delete" => KeyCode::Delete, - "Home" => KeyCode::Home, - "End" => KeyCode::End, - "PageUp" => KeyCode::PageUp, - "PageDown" => KeyCode::PageDown, - "Escape" => KeyCode::Esc, - _ => KeyCode::Unidentified, - } - } -} - -/// A mouse button. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum MouseButton { - /// Left mouse button - Left, - /// Right mouse button - Right, - /// Middle mouse button - Middle, - /// Back mouse button - Back, - /// Forward mouse button - Forward, - /// Unidentified mouse button - Unidentified, -} - -/// A mouse event. -#[derive(Debug, Clone, Eq, PartialEq)] -pub enum MouseEventKind { - /// Mouse moved - Moved, - /// Mouse button pressed - Pressed, - /// Mouse button released - Released, - /// Unidentified mouse event - Unidentified, -} - -/// Convert a [`web_sys::MouseEvent`] to a [`MouseEvent`]. -impl From for MouseEvent { - fn from(event: web_sys::MouseEvent) -> Self { - let ctrl = event.ctrl_key(); - let alt = event.alt_key(); - let shift = event.shift_key(); - let event_type = event.type_().into(); - MouseEvent { - // Button is only valid if it is a mousedown or mouseup event. - button: if event_type == MouseEventKind::Moved { - MouseButton::Unidentified - } else { - event.button().into() - }, - event: event_type, - x: event.client_x() as u32, - y: event.client_y() as u32, - ctrl, - alt, - shift, - } - } -} - -/// Convert a [`web_sys::MouseEvent`] to a [`MouseButton`]. -impl From for MouseButton { - fn from(button: i16) -> Self { - match button { - 0 => MouseButton::Left, - 1 => MouseButton::Middle, - 2 => MouseButton::Right, - 3 => MouseButton::Back, - 4 => MouseButton::Forward, - _ => MouseButton::Unidentified, - } - } -} - -/// Convert a [`web_sys::MouseEvent`] to a [`MouseEventKind`]. -impl From for MouseEventKind { - fn from(event: String) -> Self { - let event = event.as_str(); - match event { - "mousemove" => MouseEventKind::Moved, - "mousedown" => MouseEventKind::Pressed, - "mouseup" => MouseEventKind::Released, - _ => MouseEventKind::Unidentified, - } - } -} diff --git a/src/event/key.rs b/src/event/key.rs new file mode 100644 index 00000000..958e7840 --- /dev/null +++ b/src/event/key.rs @@ -0,0 +1,173 @@ +//! Module for `KeyEvent` and related structs. + +use bitflags::bitflags; + +/// A key event. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct KeyEvent { + /// The key code. + pub code: KeyCode, + /// Additional key modifiers. + pub modifiers: KeyModifiers, + /// Kind of event. + pub kind: KeyEventKind, + /// Keyboard state. + pub state: KeyEventState, +} + +/// Represents a keyboard event kind. +#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] +pub enum KeyEventKind { + /// A key has been pressed. + /// + /// **Note:** this correlates to `keydown`, not `keypress`. + Press, + /// Any event in which `event.repeat` is true. + /// This is mostly kept for parity. + Repeat, + /// A key has been released. + Release, +} + +bitflags! { + /// Represents key modifiers (shift, control, alt, etc.). + #[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash)] + pub struct KeyModifiers: u8 { + /// Whether the shift key is pressed. + const SHIFT = 0b0000_0001; + /// Whether the control key is pressed. + const CONTROL = 0b0000_0010; + /// Whether the alt key is pressed. + const ALT = 0b0000_0100; + /// Whether the meta key is pressed. + const META = 0b0010_0000; + /// No key is pressed. + const NONE = 0b0000_0000; + } +} + +bitflags! { + /// Represents extra state about the key event. + #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, Hash)] + pub struct KeyEventState: u8 { + /// The key event origins from the keypad. + const KEYPAD = 0b0000_0001; + /// Caps Lock was enabled for this key event. + /// + /// **Note:** this is set for the initial press of Caps Lock itself. + const CAPS_LOCK = 0b0000_0010; + /// Num Lock was enabled for this key event. + /// + /// **Note:** this is set for the initial press of Num Lock itself. + const NUM_LOCK = 0b0000_0100; + /// No other state applied. + const NONE = 0b0000_0000; + } +} + +/// Convert a [`web_sys::KeyboardEvent`] to a [`KeyEvent`]. +impl From for KeyEvent { + fn from(event: web_sys::KeyboardEvent) -> Self { + let shift = if event.shift_key() { + KeyModifiers::SHIFT + } else { + KeyModifiers::NONE + }; + let ctrl = if event.ctrl_key() { + KeyModifiers::CONTROL + } else { + KeyModifiers::NONE + }; + let alt = if event.alt_key() { + KeyModifiers::ALT + } else { + KeyModifiers::NONE + }; + KeyEvent { + code: event.into(), + modifiers: shift | ctrl | alt, + kind: KeyEventKind::Press, + state: KeyEventState::NONE, + } + } +} + +/// A key code. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum KeyCode { + /// Normal letter key input. + Char(char), + /// F keys. + F(u8), + /// Backspace key + Backspace, + /// Enter or return key + Enter, + /// Left arrow key + Left, + /// Right arrow key + Right, + /// Up arrow key + Up, + /// Down arrow key + Down, + /// Tab key + Tab, + /// Delete key + Delete, + /// Home key + Home, + /// End key + End, + /// Page up key + PageUp, + /// Page down key + PageDown, + /// Escape key + Esc, + /// Unidentified. + Unidentified, +} + +/// Convert a [`web_sys::KeyboardEvent`] to a [`KeyCode`]. +impl From for KeyCode { + fn from(event: web_sys::KeyboardEvent) -> Self { + let code = event.code(); + let key = event.key(); + if key.len() == 1 { + if let Some(char) = key.chars().next() { + return KeyCode::Char(char); + } else { + return KeyCode::Unidentified; + } + } + match code.as_str() { + "F1" => KeyCode::F(1), + "F2" => KeyCode::F(2), + "F3" => KeyCode::F(3), + "F4" => KeyCode::F(4), + "F5" => KeyCode::F(5), + "F6" => KeyCode::F(6), + "F7" => KeyCode::F(7), + "F8" => KeyCode::F(8), + "F9" => KeyCode::F(9), + "F10" => KeyCode::F(10), + "F11" => KeyCode::F(11), + "F12" => KeyCode::F(12), + "Backspace" => KeyCode::Backspace, + "Enter" => KeyCode::Enter, + "ArrowLeft" => KeyCode::Left, + "ArrowRight" => KeyCode::Right, + "ArrowUp" => KeyCode::Up, + "ArrowDown" => KeyCode::Down, + "Tab" => KeyCode::Tab, + "Delete" => KeyCode::Delete, + "Home" => KeyCode::Home, + "End" => KeyCode::End, + "PageUp" => KeyCode::PageUp, + "PageDown" => KeyCode::PageDown, + "Escape" => KeyCode::Esc, + _ => KeyCode::Unidentified, + } + } +} diff --git a/src/event/mod.rs b/src/event/mod.rs new file mode 100644 index 00000000..0ff9eadf --- /dev/null +++ b/src/event/mod.rs @@ -0,0 +1,23 @@ +pub mod key; +pub mod mouse; + +pub use key::KeyEvent; +pub use mouse::MouseEvent; + +/// A generic event. +#[non_exhaustive] +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum Event { + /// The terminal gained focus. + FocusGained, + /// The terminal lost focus. + FocusLost, + /// A single key event with additional pressed modifiers. + Key(KeyEvent), + /// A single mouse event with additional pressed modifiers. + Mouse(MouseEvent), + /// A string that was pasted into the terminal. + Paste(String), + /// An resize event with new dimensions after resize (columns, rows). + Resize(u16, u16), +} diff --git a/src/event/mouse.rs b/src/event/mouse.rs new file mode 100644 index 00000000..76b1ea3b --- /dev/null +++ b/src/event/mouse.rs @@ -0,0 +1,101 @@ +//! Module for `MouseEvent` and related structs. + +/// A mouse movement event. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct MouseEvent { + /// The mouse button that was pressed. + pub button: MouseButton, + /// The triggered event. + pub event: MouseEventKind, + /// The x coordinate of the mouse. + pub x: u32, + /// The y coordinate of the mouse. + pub y: u32, + /// Whether the control key is pressed. + pub ctrl: bool, + /// Whether the alt key is pressed. + pub alt: bool, + /// Whether the shift key is pressed. + pub shift: bool, +} + +/// A mouse button. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum MouseButton { + /// Left mouse button + Left, + /// Right mouse button + Right, + /// Middle mouse button + Middle, + /// Back mouse button + Back, + /// Forward mouse button + Forward, + /// Unidentified mouse button + Unidentified, +} + +/// A mouse event. +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum MouseEventKind { + /// Mouse moved + Moved, + /// Mouse button pressed + Pressed, + /// Mouse button released + Released, + /// Unidentified mouse event + Unidentified, +} + +/// Convert a [`web_sys::MouseEvent`] to a [`MouseEvent`]. +impl From for MouseEvent { + fn from(event: web_sys::MouseEvent) -> Self { + let ctrl = event.ctrl_key(); + let alt = event.alt_key(); + let shift = event.shift_key(); + let event_type = event.type_().into(); + MouseEvent { + // Button is only valid if it is a mousedown or mouseup event. + button: if event_type == MouseEventKind::Moved { + MouseButton::Unidentified + } else { + event.button().into() + }, + event: event_type, + x: event.client_x() as u32, + y: event.client_y() as u32, + ctrl, + alt, + shift, + } + } +} + +/// Convert a [`web_sys::MouseEvent`] to a [`MouseButton`]. +impl From for MouseButton { + fn from(button: i16) -> Self { + match button { + 0 => MouseButton::Left, + 1 => MouseButton::Middle, + 2 => MouseButton::Right, + 3 => MouseButton::Back, + 4 => MouseButton::Forward, + _ => MouseButton::Unidentified, + } + } +} + +/// Convert a [`web_sys::MouseEvent`] to a [`MouseEventKind`]. +impl From for MouseEventKind { + fn from(event: String) -> Self { + let event = event.as_str(); + match event { + "mousemove" => MouseEventKind::Moved, + "mousedown" => MouseEventKind::Pressed, + "mouseup" => MouseEventKind::Released, + _ => MouseEventKind::Unidentified, + } + } +} diff --git a/src/render.rs b/src/render.rs index bc559ff8..d67bb34d 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,4 +1,4 @@ -use ratatui::{prelude::Backend, Frame, Terminal}; +use ratatui::{Frame, Terminal, prelude::Backend}; use std::{cell::RefCell, rc::Rc}; use web_sys::{wasm_bindgen::prelude::*, window}; diff --git a/src/utils.rs b/src/utils.rs index 7782080f..128be465 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,7 +7,7 @@ use crate::{ use web_sys::{ js_sys::{Array, Function, Reflect}, - wasm_bindgen::{prelude::*, JsValue}, + wasm_bindgen::{JsValue, prelude::*}, }; /// Sets the document title.