mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 12:43:08 +00:00
Merge pull request #406 from rMazeiks/rusty-events
Rustify events api for WheelData and KeyboardData
This commit is contained in:
commit
dde9ca6ce0
25 changed files with 824 additions and 382 deletions
|
@ -204,7 +204,6 @@ fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
|
|||
fn ctrl_key(&self) -> bool { self.0.ctrl_key() }
|
||||
fn key(&self) -> String { self.0.key() }
|
||||
fn key_code(&self) -> usize { self.0.key_code() }
|
||||
fn locale(&self) -> String { self.0.locale() }
|
||||
fn location(&self) -> usize { self.0.location() }
|
||||
fn meta_key(&self) -> bool { self.0.meta_key() }
|
||||
fn repeat(&self) -> bool { self.0.repeat() }
|
||||
|
|
|
@ -206,7 +206,6 @@ fn virtual_event_from_websys_event(event: &web_sys::Event) -> VirtualEvent {
|
|||
ctrl_key: event.ctrl_key(),
|
||||
meta_key: event.meta_key(),
|
||||
shift_key: event.shift_key(),
|
||||
locale: "".to_string(),
|
||||
location: event.location(),
|
||||
repeat: event.repeat(),
|
||||
which: event.which(),
|
||||
|
|
85
examples/all_events.rs
Normal file
85
examples/all_events.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_html::on::{FocusData, KeyboardData, MouseData, WheelData};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
dioxus::desktop::launch(app);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Event {
|
||||
MouseMove(Arc<MouseData>),
|
||||
MouseClick(Arc<MouseData>),
|
||||
MouseDoubleClick(Arc<MouseData>),
|
||||
MouseDown(Arc<MouseData>),
|
||||
MouseUp(Arc<MouseData>),
|
||||
|
||||
Wheel(Arc<WheelData>),
|
||||
|
||||
KeyDown(Arc<KeyboardData>),
|
||||
KeyUp(Arc<KeyboardData>),
|
||||
KeyPress(Arc<KeyboardData>),
|
||||
|
||||
FocusIn(Arc<FocusData>),
|
||||
FocusOut(Arc<FocusData>),
|
||||
}
|
||||
|
||||
const MAX_EVENTS: usize = 8;
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let container_style = r#"
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
"#;
|
||||
let rect_style = r#"
|
||||
background: deepskyblue;
|
||||
height: 50vh;
|
||||
width: 50vw;
|
||||
color: white;
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
text-aligh: center;
|
||||
"#;
|
||||
|
||||
let events = use_ref(&cx, || Vec::new());
|
||||
|
||||
let events_lock = events.read();
|
||||
let first_index = events_lock.len().saturating_sub(MAX_EVENTS);
|
||||
let events_rendered = events_lock[first_index..]
|
||||
.iter()
|
||||
.map(|event| cx.render(rsx!(div {"{event:?}"})));
|
||||
|
||||
let log_event = move |event: Event| {
|
||||
events.write().push(event);
|
||||
};
|
||||
|
||||
cx.render(rsx! (
|
||||
div {
|
||||
style: "{container_style}",
|
||||
div {
|
||||
style: "{rect_style}",
|
||||
// focusing is necessary to catch keyboard events
|
||||
tabindex: "0",
|
||||
|
||||
onmousemove: move |event| log_event(Event::MouseMove(event.data)),
|
||||
onclick: move |event| log_event(Event::MouseClick(event.data)),
|
||||
ondblclick: move |event| log_event(Event::MouseDoubleClick(event.data)),
|
||||
onmousedown: move |event| log_event(Event::MouseDown(event.data)),
|
||||
onmouseup: move |event| log_event(Event::MouseUp(event.data)),
|
||||
|
||||
onwheel: move |event| log_event(Event::Wheel(event.data)),
|
||||
|
||||
onkeydown: move |event| log_event(Event::KeyDown(event.data)),
|
||||
onkeyup: move |event| log_event(Event::KeyUp(event.data)),
|
||||
onkeypress: move |event| log_event(Event::KeyPress(event.data)),
|
||||
|
||||
onfocusin: move |event| log_event(Event::FocusIn(event.data)),
|
||||
onfocusout: move |event| log_event(Event::FocusOut(event.data)),
|
||||
|
||||
"Hover, click, type or scroll to see the info down below"
|
||||
}
|
||||
div { events_rendered },
|
||||
},
|
||||
))
|
||||
}
|
|
@ -5,6 +5,7 @@ This calculator version uses React-style state management. All state is held as
|
|||
|
||||
use dioxus::events::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_html::input_data::keyboard_types::Key;
|
||||
|
||||
fn main() {
|
||||
use dioxus::desktop::tao::dpi::LogicalSize;
|
||||
|
@ -29,33 +30,38 @@ fn app(cx: Scope) -> Element {
|
|||
|
||||
let input_operator = move |key: &str| val.make_mut().push_str(key);
|
||||
|
||||
let handle_key_down_event = move |evt: KeyboardEvent| match evt.key() {
|
||||
Key::Backspace => {
|
||||
if !val.len() != 0 {
|
||||
val.make_mut().pop();
|
||||
}
|
||||
}
|
||||
Key::Character(character) => match character.as_str() {
|
||||
"+" => input_operator("+"),
|
||||
"-" => input_operator("-"),
|
||||
"/" => input_operator("/"),
|
||||
"*" => input_operator("*"),
|
||||
"0" => input_digit(0),
|
||||
"1" => input_digit(1),
|
||||
"2" => input_digit(2),
|
||||
"3" => input_digit(3),
|
||||
"4" => input_digit(4),
|
||||
"5" => input_digit(5),
|
||||
"6" => input_digit(6),
|
||||
"7" => input_digit(7),
|
||||
"8" => input_digit(8),
|
||||
"9" => input_digit(9),
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
};
|
||||
|
||||
cx.render(rsx!(
|
||||
style { [include_str!("./assets/calculator.css")] }
|
||||
div { id: "wrapper",
|
||||
div { class: "app",
|
||||
div { class: "calculator",
|
||||
onkeydown: move |evt| match evt.key_code {
|
||||
KeyCode::Add => input_operator("+"),
|
||||
KeyCode::Subtract => input_operator("-"),
|
||||
KeyCode::Divide => input_operator("/"),
|
||||
KeyCode::Multiply => input_operator("*"),
|
||||
KeyCode::Num0 => input_digit(0),
|
||||
KeyCode::Num1 => input_digit(1),
|
||||
KeyCode::Num2 => input_digit(2),
|
||||
KeyCode::Num3 => input_digit(3),
|
||||
KeyCode::Num4 => input_digit(4),
|
||||
KeyCode::Num5 => input_digit(5),
|
||||
KeyCode::Num6 => input_digit(6),
|
||||
KeyCode::Num7 => input_digit(7),
|
||||
KeyCode::Num8 => input_digit(8),
|
||||
KeyCode::Num9 => input_digit(9),
|
||||
KeyCode::Backspace => {
|
||||
if !val.len() != 0 {
|
||||
val.make_mut().pop();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
onkeydown: handle_key_down_event,
|
||||
div { class: "calculator-display", [val.to_string()] }
|
||||
div { class: "calculator-keypad",
|
||||
div { class: "input-keys",
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
use dioxus::prelude::*;
|
||||
|
||||
fn main() {
|
||||
dioxus::desktop::launch(app);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
button {
|
||||
ondblclick: move |_| {
|
||||
//
|
||||
println!("double clicked!");
|
||||
},
|
||||
"Click me!"
|
||||
}
|
||||
input {
|
||||
onfocusin: move |_| {
|
||||
//
|
||||
println!("blurred!");
|
||||
},
|
||||
"onblur": "console.log('blurred!')"
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_core::UiEvent;
|
||||
use dioxus_html::on::MouseData;
|
||||
|
||||
fn main() {
|
||||
dioxus::desktop::launch(app);
|
||||
}
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let page_coordinates = use_state(&cx, || "".to_string());
|
||||
let screen_coordinates = use_state(&cx, || "".to_string());
|
||||
let element_coordinates = use_state(&cx, || "".to_string());
|
||||
let buttons = use_state(&cx, || "".to_string());
|
||||
let modifiers = use_state(&cx, || "".to_string());
|
||||
|
||||
let container_style = r#"
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
"#;
|
||||
let rect_style = r#"
|
||||
background: deepskyblue;
|
||||
height: 50vh;
|
||||
width: 50vw;
|
||||
"#;
|
||||
|
||||
let update_mouse_position = move |event: UiEvent<MouseData>| {
|
||||
let mouse_data = event.data;
|
||||
|
||||
page_coordinates.set(format!("{:?}", mouse_data.page_coordinates()));
|
||||
screen_coordinates.set(format!("{:?}", mouse_data.screen_coordinates()));
|
||||
element_coordinates.set(format!("{:?}", mouse_data.element_coordinates()));
|
||||
|
||||
// Note: client coordinates are also available, but they would be the same as the page coordinates in this example, because there is no scrolling.
|
||||
|
||||
buttons.set(format!("{:?}", mouse_data.held_buttons()));
|
||||
modifiers.set(format!("{:?}", mouse_data.modifiers()));
|
||||
};
|
||||
|
||||
cx.render(rsx! (
|
||||
div {
|
||||
style: "{container_style}",
|
||||
"Hover over to display coordinates:",
|
||||
div {
|
||||
style: "{rect_style}",
|
||||
onmousemove: update_mouse_position,
|
||||
prevent_default: "mousedown",
|
||||
}
|
||||
div {"Page coordinates: {page_coordinates}"},
|
||||
div {"Screen coordinates: {screen_coordinates}"},
|
||||
div {"Element coordinates: {element_coordinates}"},
|
||||
div {"Buttons: {buttons}"},
|
||||
div {"Modifiers: {modifiers}"},
|
||||
}
|
||||
))
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
use dioxus::desktop::wry::application::dpi::LogicalSize;
|
||||
use dioxus::events::*;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_html::input_data::keyboard_types::Key;
|
||||
|
||||
fn main() {
|
||||
dioxus::desktop::launch_cfg(app, |cfg| {
|
||||
|
@ -212,22 +213,26 @@ impl Calculator {
|
|||
self.waiting_for_operand = true;
|
||||
}
|
||||
fn handle_keydown(&mut self, evt: KeyboardEvent) {
|
||||
match evt.key_code {
|
||||
KeyCode::Backspace => self.backspace(),
|
||||
KeyCode::Num0 => self.input_digit(0),
|
||||
KeyCode::Num1 => self.input_digit(1),
|
||||
KeyCode::Num2 => self.input_digit(2),
|
||||
KeyCode::Num3 => self.input_digit(3),
|
||||
KeyCode::Num4 => self.input_digit(4),
|
||||
KeyCode::Num5 => self.input_digit(5),
|
||||
KeyCode::Num6 => self.input_digit(6),
|
||||
KeyCode::Num7 => self.input_digit(7),
|
||||
KeyCode::Num8 => self.input_digit(8),
|
||||
KeyCode::Num9 => self.input_digit(9),
|
||||
KeyCode::Add => self.operator = Some(Operator::Add),
|
||||
KeyCode::Subtract => self.operator = Some(Operator::Sub),
|
||||
KeyCode::Divide => self.operator = Some(Operator::Div),
|
||||
KeyCode::Multiply => self.operator = Some(Operator::Mul),
|
||||
match evt.key() {
|
||||
Key::Backspace => self.backspace(),
|
||||
Key::Character(c) => match c.as_str() {
|
||||
"0" => self.input_digit(0),
|
||||
"1" => self.input_digit(1),
|
||||
"2" => self.input_digit(2),
|
||||
"3" => self.input_digit(3),
|
||||
"4" => self.input_digit(4),
|
||||
"5" => self.input_digit(5),
|
||||
"6" => self.input_digit(6),
|
||||
"7" => self.input_digit(7),
|
||||
"8" => self.input_digit(8),
|
||||
"9" => self.input_digit(9),
|
||||
"+" => self.operator = Some(Operator::Add),
|
||||
"-" => self.operator = Some(Operator::Sub),
|
||||
"/" => self.operator = Some(Operator::Div),
|
||||
"*" => self.operator = Some(Operator::Mul),
|
||||
_ => {}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_elements::input_data::keyboard_types::Key;
|
||||
|
||||
fn main() {
|
||||
dioxus::desktop::launch(app);
|
||||
|
@ -56,7 +57,7 @@ pub fn app(cx: Scope<()>) -> Element {
|
|||
autofocus: "true",
|
||||
oninput: move |evt| draft.set(evt.value.clone()),
|
||||
onkeydown: move |evt| {
|
||||
if evt.key == "Enter" && !draft.is_empty() {
|
||||
if evt.key() == Key::Enter && !draft.is_empty() {
|
||||
todos.make_mut().insert(
|
||||
**todo_id,
|
||||
TodoItem {
|
||||
|
@ -148,8 +149,8 @@ pub fn todo_entry<'a>(cx: Scope<'a, TodoEntryProps<'a>>) -> Element {
|
|||
autofocus: "true",
|
||||
onfocusout: move |_| is_editing.set(false),
|
||||
onkeydown: move |evt| {
|
||||
match evt.key.as_str() {
|
||||
"Enter" | "Escape" | "Tab" => is_editing.set(false),
|
||||
match evt.key() {
|
||||
Key::Enter | Key::Escape | Key::Tab => is_editing.set(false),
|
||||
_ => {}
|
||||
}
|
||||
},
|
||||
|
|
85
examples/tui_all_events.rs
Normal file
85
examples/tui_all_events.rs
Normal file
|
@ -0,0 +1,85 @@
|
|||
use dioxus::prelude::*;
|
||||
use dioxus_html::on::{FocusData, KeyboardData, MouseData, WheelData};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
dioxus::tui::launch(app);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Event {
|
||||
MouseMove(Arc<MouseData>),
|
||||
MouseClick(Arc<MouseData>),
|
||||
MouseDoubleClick(Arc<MouseData>),
|
||||
MouseDown(Arc<MouseData>),
|
||||
MouseUp(Arc<MouseData>),
|
||||
|
||||
Wheel(Arc<WheelData>),
|
||||
|
||||
KeyDown(Arc<KeyboardData>),
|
||||
KeyUp(Arc<KeyboardData>),
|
||||
KeyPress(Arc<KeyboardData>),
|
||||
|
||||
FocusIn(Arc<FocusData>),
|
||||
FocusOut(Arc<FocusData>),
|
||||
}
|
||||
|
||||
const MAX_EVENTS: usize = 8;
|
||||
|
||||
fn app(cx: Scope) -> Element {
|
||||
let events = use_ref(&cx, || Vec::new());
|
||||
|
||||
let events_lock = events.read();
|
||||
let first_index = events_lock.len().saturating_sub(MAX_EVENTS);
|
||||
let events_rendered = events_lock[first_index..].iter().map(|event| {
|
||||
// TUI panics if text overflows (https://github.com/DioxusLabs/dioxus/issues/371)
|
||||
// temporary hack: just trim the strings (and make sure viewport is big enough)
|
||||
// todo: remove
|
||||
let mut trimmed = format!("{event:?}");
|
||||
trimmed.truncate(200);
|
||||
cx.render(rsx!(p { "{trimmed}" }))
|
||||
});
|
||||
|
||||
let log_event = move |event: Event| {
|
||||
events.write().push(event);
|
||||
};
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
flex_direction: "column",
|
||||
div {
|
||||
width: "80%",
|
||||
height: "50%",
|
||||
border_width: "1px",
|
||||
justify_content: "center",
|
||||
align_items: "center",
|
||||
background_color: "hsl(248, 53%, 58%)",
|
||||
|
||||
onmousemove: move |event| log_event(Event::MouseMove(event.data)),
|
||||
onclick: move |event| log_event(Event::MouseClick(event.data)),
|
||||
ondblclick: move |event| log_event(Event::MouseDoubleClick(event.data)),
|
||||
onmousedown: move |event| log_event(Event::MouseDown(event.data)),
|
||||
onmouseup: move |event| log_event(Event::MouseUp(event.data)),
|
||||
|
||||
onwheel: move |event| log_event(Event::Wheel(event.data)),
|
||||
|
||||
onkeydown: move |event| log_event(Event::KeyDown(event.data)),
|
||||
onkeyup: move |event| log_event(Event::KeyUp(event.data)),
|
||||
onkeypress: move |event| log_event(Event::KeyPress(event.data)),
|
||||
|
||||
onfocusin: move |event| log_event(Event::FocusIn(event.data)),
|
||||
onfocusout: move |event| log_event(Event::FocusOut(event.data)),
|
||||
|
||||
"Hover, click, type or scroll to see the info down below"
|
||||
},
|
||||
div {
|
||||
width: "80%",
|
||||
height: "50%",
|
||||
flex_direction: "column",
|
||||
events_rendered,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
|
@ -14,7 +14,7 @@ fn app(cx: Scope) -> Element {
|
|||
justify_content: "center",
|
||||
align_items: "center",
|
||||
background_color: "hsl(248, 53%, 58%)",
|
||||
onwheel: move |w| radius.modify(|r| (r + w.delta_y as i8).abs()),
|
||||
onwheel: move |w| radius.modify(|r| (r + w.delta().strip_units().y as i8).abs()),
|
||||
|
||||
border_style: "solid none solid double",
|
||||
border_width: "thick",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use dioxus::{events::KeyCode, prelude::*};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_html::input_data::keyboard_types::Code;
|
||||
|
||||
fn main() {
|
||||
dioxus::tui::launch(app);
|
||||
|
@ -27,7 +28,7 @@ fn Button(cx: Scope<ButtonProps>) -> Element {
|
|||
background_color: "{color}",
|
||||
tabindex: "{cx.props.layer}",
|
||||
onkeydown: |e| {
|
||||
if let KeyCode::Space = e.data.key_code{
|
||||
if let Code::Space = e.data.code() {
|
||||
toggle.modify(|f| !f);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -65,7 +65,7 @@ fn app(cx: Scope) -> Element {
|
|||
onmouseenter: move |m| q1_color.set([get_brightness(m.data), 0, 0]),
|
||||
onmousedown: move |m| q1_color.set([get_brightness(m.data), 0, 0]),
|
||||
onmouseup: move |m| q1_color.set([get_brightness(m.data), 0, 0]),
|
||||
onwheel: move |w| q1_color.set([q1_color[0] + (10.0*w.delta_y) as i32, 0, 0]),
|
||||
onwheel: move |w| q1_color.set([q1_color[0] + (10.0*w.delta().strip_units().y) as i32, 0, 0]),
|
||||
onmouseleave: move |_| q1_color.set([200; 3]),
|
||||
onmousemove: update_data,
|
||||
"click me"
|
||||
|
@ -79,7 +79,7 @@ fn app(cx: Scope) -> Element {
|
|||
onmouseenter: move |m| q2_color.set([get_brightness(m.data); 3]),
|
||||
onmousedown: move |m| q2_color.set([get_brightness(m.data); 3]),
|
||||
onmouseup: move |m| q2_color.set([get_brightness(m.data); 3]),
|
||||
onwheel: move |w| q2_color.set([q2_color[0] + (10.0*w.delta_y) as i32;3]),
|
||||
onwheel: move |w| q2_color.set([q2_color[0] + (10.0*w.delta().strip_units().y) as i32;3]),
|
||||
onmouseleave: move |_| q2_color.set([200; 3]),
|
||||
onmousemove: update_data,
|
||||
"click me"
|
||||
|
@ -99,7 +99,7 @@ fn app(cx: Scope) -> Element {
|
|||
onmouseenter: move |m| q3_color.set([0, get_brightness(m.data), 0]),
|
||||
onmousedown: move |m| q3_color.set([0, get_brightness(m.data), 0]),
|
||||
onmouseup: move |m| q3_color.set([0, get_brightness(m.data), 0]),
|
||||
onwheel: move |w| q3_color.set([0, q3_color[1] + (10.0*w.delta_y) as i32, 0]),
|
||||
onwheel: move |w| q3_color.set([0, q3_color[1] + (10.0*w.delta().strip_units().y) as i32, 0]),
|
||||
onmouseleave: move |_| q3_color.set([200; 3]),
|
||||
onmousemove: update_data,
|
||||
"click me"
|
||||
|
@ -113,7 +113,7 @@ fn app(cx: Scope) -> Element {
|
|||
onmouseenter: move |m| q4_color.set([0, 0, get_brightness(m.data)]),
|
||||
onmousedown: move |m| q4_color.set([0, 0, get_brightness(m.data)]),
|
||||
onmouseup: move |m| q4_color.set([0, 0, get_brightness(m.data)]),
|
||||
onwheel: move |w| q4_color.set([0, 0, q4_color[2] + (10.0*w.delta_y) as i32]),
|
||||
onwheel: move |w| q4_color.set([0, 0, q4_color[2] + (10.0*w.delta().strip_units().y) as i32]),
|
||||
onmouseleave: move |_| q4_color.set([200; 3]),
|
||||
onmousemove: update_data,
|
||||
"click me"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use dioxus::events::WheelEvent;
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_html::geometry::ScreenPoint;
|
||||
use dioxus_html::input_data::keyboard_types::Code;
|
||||
use dioxus_html::input_data::MouseButtonSet;
|
||||
use dioxus_html::on::{KeyboardEvent, MouseEvent};
|
||||
use dioxus_html::KeyCode;
|
||||
|
||||
fn main() {
|
||||
dioxus::tui::launch(app);
|
||||
|
@ -16,6 +16,21 @@ fn app(cx: Scope) -> Element {
|
|||
let buttons = use_state(&cx, MouseButtonSet::empty);
|
||||
let mouse_clicked = use_state(&cx, || false);
|
||||
|
||||
let key_down_handler = move |evt: KeyboardEvent| {
|
||||
match evt.data.code() {
|
||||
Code::ArrowLeft => count.set(count + 1),
|
||||
Code::ArrowRight => count.set(count - 1),
|
||||
Code::ArrowUp => count.set(count + 10),
|
||||
Code::ArrowDown => count.set(count - 10),
|
||||
_ => {}
|
||||
}
|
||||
key.set(format!(
|
||||
"{:?} repeating: {:?}",
|
||||
evt.key(),
|
||||
evt.is_auto_repeating()
|
||||
));
|
||||
};
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
width: "100%",
|
||||
|
@ -24,18 +39,9 @@ fn app(cx: Scope) -> Element {
|
|||
justify_content: "center",
|
||||
align_items: "center",
|
||||
flex_direction: "column",
|
||||
onkeydown: move |evt: KeyboardEvent| {
|
||||
match evt.data.key_code {
|
||||
KeyCode::LeftArrow => count.set(count + 1),
|
||||
KeyCode::RightArrow => count.set(count - 1),
|
||||
KeyCode::UpArrow => count.set(count + 10),
|
||||
KeyCode::DownArrow => count.set(count - 10),
|
||||
_ => {},
|
||||
}
|
||||
key.set(format!("{:?} repeating: {:?}", evt.key, evt.repeat));
|
||||
},
|
||||
onkeydown: key_down_handler,
|
||||
onwheel: move |evt: WheelEvent| {
|
||||
count.set(count + evt.data.delta_y as i64);
|
||||
count.set(count + evt.data.delta().strip_units().y as i64);
|
||||
},
|
||||
ondrag: move |evt: MouseEvent| {
|
||||
mouse.set(evt.data.screen_coordinates());
|
||||
|
|
|
@ -12,7 +12,7 @@ fn app(cx: Scope) -> Element {
|
|||
width: "100%",
|
||||
height: "100%",
|
||||
flex_direction: "column",
|
||||
onwheel: move |evt| alpha.set((**alpha + evt.data.delta_y as i64).min(100).max(0)),
|
||||
onwheel: move |evt| alpha.set((**alpha + evt.data.delta().strip_units().y as i64).min(100).max(0)),
|
||||
|
||||
p {
|
||||
background_color: "black",
|
||||
|
|
|
@ -40,5 +40,5 @@ features = [
|
|||
|
||||
[features]
|
||||
default = []
|
||||
serialize = ["serde", "serde_repr"]
|
||||
serialize = ["serde", "serde_repr", "euclid/serde", "keyboard-types/serde"]
|
||||
wasm-bind = ["web-sys", "wasm-bindgen"]
|
||||
|
|
|
@ -5,12 +5,20 @@ use dioxus_core::*;
|
|||
pub mod on {
|
||||
//! Input events and associated data
|
||||
|
||||
use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
|
||||
use crate::input_data::{
|
||||
decode_mouse_button_set, encode_mouse_button_set, MouseButton, MouseButtonSet,
|
||||
use crate::geometry::{
|
||||
ClientPoint, Coordinates, ElementPoint, LinesVector, PagePoint, PagesVector, PixelsVector,
|
||||
ScreenPoint, WheelDelta,
|
||||
};
|
||||
use keyboard_types::Modifiers;
|
||||
use crate::input_data::{
|
||||
decode_key_location, decode_mouse_button_set, encode_key_location, encode_mouse_button_set,
|
||||
MouseButton, MouseButtonSet,
|
||||
};
|
||||
use euclid::UnknownUnit;
|
||||
use keyboard_types::{Code, Key, Location, Modifiers};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryInto;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use super::*;
|
||||
macro_rules! event_directory {
|
||||
|
@ -419,71 +427,142 @@ pub mod on {
|
|||
|
||||
pub type KeyboardEvent = UiEvent<KeyboardData>;
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct KeyboardData {
|
||||
#[deprecated(
|
||||
since = "0.3.0",
|
||||
note = "This may not work in all environments. Use key() instead."
|
||||
)]
|
||||
pub char_code: u32,
|
||||
|
||||
/// Identify which "key" was entered.
|
||||
///
|
||||
/// This is the best method to use for all languages. They key gets mapped to a String sequence which you can match on.
|
||||
/// The key isn't an enum because there are just so many context-dependent keys.
|
||||
///
|
||||
/// A full list on which keys to use is available at:
|
||||
/// <https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values>
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// match event.key().as_str() {
|
||||
/// "Esc" | "Escape" => {}
|
||||
/// "ArrowDown" => {}
|
||||
/// "ArrowLeft" => {}
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
#[deprecated(since = "0.3.0", note = "use key() instead")]
|
||||
pub key: String,
|
||||
|
||||
/// Get the key code as an enum Variant.
|
||||
///
|
||||
/// This is intended for things like arrow keys, escape keys, function keys, and other non-international keys.
|
||||
/// To match on unicode sequences, use the [`KeyboardData::key`] method - this will return a string identifier instead of a limited enum.
|
||||
///
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust, ignore
|
||||
/// use dioxus::KeyCode;
|
||||
/// match event.key_code() {
|
||||
/// KeyCode::Escape => {}
|
||||
/// KeyCode::LeftArrow => {}
|
||||
/// KeyCode::RightArrow => {}
|
||||
/// _ => {}
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
#[deprecated(
|
||||
since = "0.3.0",
|
||||
note = "This may not work in all environments. Use code() instead."
|
||||
)]
|
||||
pub key_code: KeyCode,
|
||||
|
||||
/// the physical key on the keyboard
|
||||
code: Code,
|
||||
|
||||
/// Indicate if the `alt` modifier key was pressed during this keyboard event
|
||||
#[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
||||
pub alt_key: bool,
|
||||
|
||||
/// Indicate if the `ctrl` modifier key was pressed during this keyboard event
|
||||
#[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
||||
pub ctrl_key: bool,
|
||||
|
||||
/// Indicate if the `meta` modifier key was pressed during this keyboard event
|
||||
#[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
||||
pub meta_key: bool,
|
||||
|
||||
/// Indicate if the `shift` modifier key was pressed during this keyboard event
|
||||
#[deprecated(since = "0.3.0", note = "use modifiers() instead")]
|
||||
pub shift_key: bool,
|
||||
|
||||
pub locale: String,
|
||||
|
||||
#[deprecated(since = "0.3.0", note = "use location() instead")]
|
||||
pub location: usize,
|
||||
|
||||
#[deprecated(since = "0.3.0", note = "use is_auto_repeating() instead")]
|
||||
pub repeat: bool,
|
||||
|
||||
#[deprecated(since = "0.3.0", note = "use code() or key() instead")]
|
||||
pub which: usize,
|
||||
// get_modifier_state: bool,
|
||||
}
|
||||
|
||||
impl KeyboardData {
|
||||
pub fn new(
|
||||
key: Key,
|
||||
code: Code,
|
||||
location: Location,
|
||||
is_auto_repeating: bool,
|
||||
modifiers: Modifiers,
|
||||
) -> Self {
|
||||
#[allow(deprecated)]
|
||||
KeyboardData {
|
||||
char_code: key.legacy_charcode(),
|
||||
key: key.to_string(),
|
||||
key_code: KeyCode::from_raw_code(
|
||||
key.legacy_keycode()
|
||||
.try_into()
|
||||
.expect("could not convert keycode to u8"),
|
||||
),
|
||||
code,
|
||||
alt_key: modifiers.contains(Modifiers::ALT),
|
||||
ctrl_key: modifiers.contains(Modifiers::CONTROL),
|
||||
meta_key: modifiers.contains(Modifiers::META),
|
||||
shift_key: modifiers.contains(Modifiers::SHIFT),
|
||||
location: encode_key_location(location),
|
||||
repeat: is_auto_repeating,
|
||||
which: key
|
||||
.legacy_charcode()
|
||||
.try_into()
|
||||
.expect("could not convert charcode to usize"),
|
||||
}
|
||||
}
|
||||
|
||||
/// The value of the key pressed by the user, taking into consideration the state of modifier keys such as Shift as well as the keyboard locale and layout.
|
||||
pub fn key(&self) -> Key {
|
||||
#[allow(deprecated)]
|
||||
FromStr::from_str(&self.key).expect("could not parse")
|
||||
}
|
||||
|
||||
/// A physical key on the keyboard (as opposed to the character generated by pressing the key). In other words, this property returns a value that isn't altered by keyboard layout or the state of the modifier keys.
|
||||
pub fn code(&self) -> Code {
|
||||
self.code
|
||||
}
|
||||
|
||||
/// The set of modifier keys which were pressed when the event occurred
|
||||
pub fn modifiers(&self) -> Modifiers {
|
||||
let mut modifiers = Modifiers::empty();
|
||||
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
if self.alt_key {
|
||||
modifiers.insert(Modifiers::ALT);
|
||||
}
|
||||
if self.ctrl_key {
|
||||
modifiers.insert(Modifiers::CONTROL);
|
||||
}
|
||||
if self.meta_key {
|
||||
modifiers.insert(Modifiers::META);
|
||||
}
|
||||
if self.shift_key {
|
||||
modifiers.insert(Modifiers::SHIFT);
|
||||
}
|
||||
}
|
||||
|
||||
modifiers
|
||||
}
|
||||
|
||||
/// The location of the key on the keyboard or other input device.
|
||||
pub fn location(&self) -> Location {
|
||||
#[allow(deprecated)]
|
||||
decode_key_location(self.location)
|
||||
}
|
||||
|
||||
/// `true` iff the key is being held down such that it is automatically repeating.
|
||||
pub fn is_auto_repeating(&self) -> bool {
|
||||
#[allow(deprecated)]
|
||||
self.repeat
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for KeyboardData {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("KeyboardData")
|
||||
.field("key", &self.key())
|
||||
.field("code", &self.code())
|
||||
.field("modifiers", &self.modifiers())
|
||||
.field("location", &self.location())
|
||||
.field("is_auto_repeating", &self.is_auto_repeating())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type FocusEvent = UiEvent<FocusData>;
|
||||
|
@ -502,7 +581,7 @@ pub mod on {
|
|||
|
||||
pub type MouseEvent = UiEvent<MouseData>;
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
/// Data associated with a mouse event
|
||||
///
|
||||
/// Do not use the deprecated fields; they may change or become private in the future.
|
||||
|
@ -687,6 +766,17 @@ pub mod on {
|
|||
}
|
||||
}
|
||||
|
||||
impl Debug for MouseData {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MouseData")
|
||||
.field("coordinates", &self.coordinates())
|
||||
.field("modifiers", &self.modifiers())
|
||||
.field("held_buttons", &self.held_buttons())
|
||||
.field("trigger_button", &self.trigger_button())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type PointerEvent = UiEvent<PointerData>;
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -738,14 +828,75 @@ pub mod on {
|
|||
|
||||
pub type WheelEvent = UiEvent<WheelData>;
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct WheelData {
|
||||
#[deprecated(since = "0.3.0", note = "use delta() instead")]
|
||||
pub delta_mode: u32,
|
||||
#[deprecated(since = "0.3.0", note = "use delta() instead")]
|
||||
pub delta_x: f64,
|
||||
#[deprecated(since = "0.3.0", note = "use delta() instead")]
|
||||
pub delta_y: f64,
|
||||
#[deprecated(since = "0.3.0", note = "use delta() instead")]
|
||||
pub delta_z: f64,
|
||||
}
|
||||
|
||||
impl WheelData {
|
||||
/// Construct a new WheelData with the specified wheel movement delta
|
||||
pub fn new(delta: WheelDelta) -> Self {
|
||||
let (delta_mode, vector) = match delta {
|
||||
WheelDelta::Pixels(v) => (0, v.cast_unit::<UnknownUnit>()),
|
||||
WheelDelta::Lines(v) => (1, v.cast_unit::<UnknownUnit>()),
|
||||
WheelDelta::Pages(v) => (2, v.cast_unit::<UnknownUnit>()),
|
||||
};
|
||||
|
||||
#[allow(deprecated)]
|
||||
WheelData {
|
||||
delta_mode,
|
||||
delta_x: vector.x,
|
||||
delta_y: vector.y,
|
||||
delta_z: vector.z,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct from the attributes of the web wheel event
|
||||
pub fn from_web_attributes(
|
||||
delta_mode: u32,
|
||||
delta_x: f64,
|
||||
delta_y: f64,
|
||||
delta_z: f64,
|
||||
) -> Self {
|
||||
#[allow(deprecated)]
|
||||
Self {
|
||||
delta_mode,
|
||||
delta_x,
|
||||
delta_y,
|
||||
delta_z,
|
||||
}
|
||||
}
|
||||
|
||||
/// The amount of wheel movement
|
||||
#[allow(deprecated)]
|
||||
pub fn delta(&self) -> WheelDelta {
|
||||
let x = self.delta_x;
|
||||
let y = self.delta_y;
|
||||
let z = self.delta_z;
|
||||
match self.delta_mode {
|
||||
0 => WheelDelta::Pixels(PixelsVector::new(x, y, z)),
|
||||
1 => WheelDelta::Lines(LinesVector::new(x, y, z)),
|
||||
2 => WheelDelta::Pages(PagesVector::new(x, y, z)),
|
||||
_ => panic!("Invalid delta mode, {:?}", self.delta_mode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for WheelData {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("WheelData")
|
||||
.field("delta", &self.delta())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub type MediaEvent = UiEvent<MediaData>;
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -25,7 +25,78 @@ pub struct PageSpace;
|
|||
/// A point in PageSpace
|
||||
pub type PagePoint = Point2D<f64, PageSpace>;
|
||||
|
||||
/// A pixel unit: one unit corresponds to 1 pixel
|
||||
pub struct Pixels;
|
||||
/// A vector expressed in Pixels
|
||||
pub type PixelsVector = Vector3D<f64, Pixels>;
|
||||
|
||||
/// A unit in terms of Lines
|
||||
///
|
||||
/// One unit is relative to the size of one line
|
||||
pub struct Lines;
|
||||
/// A vector expressed in Lines
|
||||
pub type LinesVector = Vector3D<f64, Lines>;
|
||||
|
||||
/// A unit in terms of Screens:
|
||||
///
|
||||
/// One unit is relative to the size of a page
|
||||
pub struct Pages;
|
||||
/// A vector expressed in Pages
|
||||
pub type PagesVector = Vector3D<f64, Pages>;
|
||||
|
||||
/// A vector representing the amount the mouse wheel was moved
|
||||
///
|
||||
/// This may be expressed in Pixels, Lines or Pages
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub enum WheelDelta {
|
||||
/// Movement in Pixels
|
||||
Pixels(PixelsVector),
|
||||
/// Movement in Lines
|
||||
Lines(LinesVector),
|
||||
/// Movement in Pages
|
||||
Pages(PagesVector),
|
||||
}
|
||||
|
||||
impl WheelDelta {
|
||||
/// Convenience function for constructing a WheelDelta with pixel units
|
||||
pub fn pixels(x: f64, y: f64, z: f64) -> Self {
|
||||
WheelDelta::Pixels(PixelsVector::new(x, y, z))
|
||||
}
|
||||
|
||||
/// Convenience function for constructing a WheelDelta with line units
|
||||
pub fn lines(x: f64, y: f64, z: f64) -> Self {
|
||||
WheelDelta::Lines(LinesVector::new(x, y, z))
|
||||
}
|
||||
|
||||
/// Convenience function for constructing a WheelDelta with page units
|
||||
pub fn pages(x: f64, y: f64, z: f64) -> Self {
|
||||
WheelDelta::Pages(PagesVector::new(x, y, z))
|
||||
}
|
||||
|
||||
/// Returns true iff there is no wheel movement
|
||||
///
|
||||
/// i.e. the x, y and z delta is zero (disregards units)
|
||||
pub fn is_zero(&self) -> bool {
|
||||
self.strip_units() == Vector3D::new(0., 0., 0.)
|
||||
}
|
||||
|
||||
/// A Vector3D proportional to the amount scrolled
|
||||
///
|
||||
/// Note that this disregards the 3 possible units: this could be expressed in terms of pixels, lines, or pages.
|
||||
///
|
||||
/// In most cases, to properly handle scrolling, you should handle all 3 possible enum variants instead of stripping units. Otherwise, if you assume that the units will always be pixels, the user may experience some unexpectedly slow scrolling if their mouse/OS sends values expressed in lines or pages.
|
||||
pub fn strip_units(&self) -> Vector3D<f64, UnknownUnit> {
|
||||
match self {
|
||||
WheelDelta::Pixels(v) => v.cast_unit(),
|
||||
WheelDelta::Lines(v) => v.cast_unit(),
|
||||
WheelDelta::Pages(v) => v.cast_unit(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Coordinates of a point in the app's interface
|
||||
#[derive(Debug)]
|
||||
pub struct Coordinates {
|
||||
screen: ScreenPoint,
|
||||
client: ClientPoint,
|
||||
|
|
|
@ -3,6 +3,7 @@ use enumset::{EnumSet, EnumSetType};
|
|||
|
||||
/// A re-export of keyboard_types
|
||||
pub use keyboard_types;
|
||||
use keyboard_types::Location;
|
||||
|
||||
/// A mouse button type (such as Primary/Secondary)
|
||||
// note: EnumSetType also derives Copy and Clone for some reason
|
||||
|
@ -118,3 +119,25 @@ pub fn encode_mouse_button_set(set: MouseButtonSet) -> u16 {
|
|||
|
||||
code
|
||||
}
|
||||
|
||||
pub fn decode_key_location(code: usize) -> Location {
|
||||
match code {
|
||||
0 => Location::Standard,
|
||||
1 => Location::Left,
|
||||
2 => Location::Right,
|
||||
3 => Location::Numpad,
|
||||
// keyboard_types doesn't yet support mobile/joystick locations
|
||||
4 | 5 => Location::Standard,
|
||||
// unknown location; Standard seems better than panicking
|
||||
_ => Location::Standard,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encode_key_location(location: Location) -> usize {
|
||||
match location {
|
||||
Location::Standard => 0,
|
||||
Location::Left => 1,
|
||||
Location::Right => 2,
|
||||
Location::Numpad => 3,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
|
||||
use crate::input_data::{decode_mouse_button_set, MouseButton};
|
||||
use crate::input_data::{decode_key_location, decode_mouse_button_set, MouseButton};
|
||||
use crate::on::{
|
||||
AnimationData, CompositionData, KeyboardData, MouseData, PointerData, TouchData,
|
||||
TransitionData, WheelData,
|
||||
};
|
||||
use crate::KeyCode;
|
||||
use keyboard_types::Modifiers;
|
||||
use keyboard_types::{Code, Key, Modifiers};
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
use wasm_bindgen::JsCast;
|
||||
use web_sys::{
|
||||
AnimationEvent, CompositionEvent, Event, KeyboardEvent, MouseEvent, PointerEvent, TouchEvent,
|
||||
|
@ -56,19 +57,32 @@ impl From<&CompositionEvent> for CompositionData {
|
|||
|
||||
impl From<&KeyboardEvent> for KeyboardData {
|
||||
fn from(e: &KeyboardEvent) -> Self {
|
||||
Self {
|
||||
alt_key: e.alt_key(),
|
||||
char_code: e.char_code(),
|
||||
key: e.key(),
|
||||
key_code: KeyCode::from_raw_code(e.key_code() as u8),
|
||||
ctrl_key: e.ctrl_key(),
|
||||
locale: "not implemented".to_string(),
|
||||
location: e.location() as usize,
|
||||
meta_key: e.meta_key(),
|
||||
repeat: e.repeat(),
|
||||
shift_key: e.shift_key(),
|
||||
which: e.which() as usize,
|
||||
let mut modifiers = Modifiers::empty();
|
||||
|
||||
if e.alt_key() {
|
||||
modifiers.insert(Modifiers::ALT);
|
||||
}
|
||||
if e.ctrl_key() {
|
||||
modifiers.insert(Modifiers::CONTROL);
|
||||
}
|
||||
if e.meta_key() {
|
||||
modifiers.insert(Modifiers::META);
|
||||
}
|
||||
if e.shift_key() {
|
||||
modifiers.insert(Modifiers::SHIFT);
|
||||
}
|
||||
|
||||
Self::new(
|
||||
Key::from_str(&e.key()).expect("could not parse key"),
|
||||
Code::from_str(&e.code()).expect("could not parse code"),
|
||||
decode_key_location(
|
||||
e.location()
|
||||
.try_into()
|
||||
.expect("could not convert location to u32"),
|
||||
),
|
||||
e.repeat(),
|
||||
modifiers,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,12 +160,7 @@ impl From<&PointerEvent> for PointerData {
|
|||
|
||||
impl From<&WheelEvent> for WheelData {
|
||||
fn from(e: &WheelEvent) -> Self {
|
||||
Self {
|
||||
delta_x: e.delta_x(),
|
||||
delta_y: e.delta_y(),
|
||||
delta_z: e.delta_z(),
|
||||
delta_mode: e.delta_mode(),
|
||||
}
|
||||
WheelData::from_web_attributes(e.delta_mode(), e.delta_x(), e.delta_y(), e.delta_z())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -388,6 +388,7 @@ export function serialize_event(event) {
|
|||
location,
|
||||
repeat,
|
||||
which,
|
||||
code,
|
||||
} = event;
|
||||
return {
|
||||
char_code: charCode,
|
||||
|
@ -400,7 +401,7 @@ export function serialize_event(event) {
|
|||
location: location,
|
||||
repeat: repeat,
|
||||
which: which,
|
||||
locale: "locale",
|
||||
code,
|
||||
};
|
||||
}
|
||||
case "focus":
|
||||
|
|
|
@ -358,7 +358,6 @@ function serialize_event(event) {
|
|||
location: location,
|
||||
repeat: repeat,
|
||||
which: which,
|
||||
locale: "locale",
|
||||
};
|
||||
}
|
||||
case "focus":
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#![cfg(target_arch = "wasm32")]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_router::*;
|
||||
use gloo_utils::document;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
@ -47,7 +47,7 @@ fn simple_test() {
|
|||
}
|
||||
|
||||
fn BlogPost(cx: Scope) -> Element {
|
||||
let id = use_route(&cx).parse_segment::<usize>("id")?;
|
||||
let _id = use_route(&cx).parse_segment::<usize>("id")?;
|
||||
|
||||
cx.render(rsx! {
|
||||
div {
|
||||
|
@ -58,5 +58,5 @@ fn simple_test() {
|
|||
|
||||
main();
|
||||
|
||||
let element = gloo_utils::document();
|
||||
let _ = document();
|
||||
}
|
||||
|
|
|
@ -5,11 +5,13 @@ use dioxus_core::*;
|
|||
use fxhash::{FxHashMap, FxHashSet};
|
||||
|
||||
use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D};
|
||||
use dioxus_html::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
|
||||
use dioxus_html::input_data::keyboard_types::Modifiers;
|
||||
use dioxus_html::geometry::{
|
||||
ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint, WheelDelta,
|
||||
};
|
||||
use dioxus_html::input_data::keyboard_types::{Code, Key, Location, Modifiers};
|
||||
use dioxus_html::input_data::MouseButtonSet as DioxusMouseButtons;
|
||||
use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet};
|
||||
use dioxus_html::{event_bubbles, on::*, KeyCode};
|
||||
use dioxus_html::{event_bubbles, on::*};
|
||||
use std::{
|
||||
any::Any,
|
||||
cell::{RefCell, RefMut},
|
||||
|
@ -140,14 +142,20 @@ impl InnerInputState {
|
|||
EventData::Wheel(ref w) => self.wheel = Some(w.clone()),
|
||||
EventData::Screen(ref s) => self.screen = Some(*s),
|
||||
EventData::Keyboard(ref mut k) => {
|
||||
let repeat = self
|
||||
let is_repeating = self
|
||||
.last_key_pressed
|
||||
.as_ref()
|
||||
.filter(|k2| k2.0.key == k.key && k2.1.elapsed() < MAX_REPEAT_TIME)
|
||||
// heuristic for guessing which presses are auto-repeating. not necessarily accurate
|
||||
.filter(|(last_data, last_instant)| {
|
||||
last_data.key() == k.key() && last_instant.elapsed() < MAX_REPEAT_TIME
|
||||
})
|
||||
.is_some();
|
||||
k.repeat = repeat;
|
||||
let new = k.clone();
|
||||
self.last_key_pressed = Some((new, Instant::now()));
|
||||
|
||||
if is_repeating {
|
||||
*k = KeyboardData::new(k.key(), k.code(), k.location(), true, k.modifiers());
|
||||
}
|
||||
|
||||
self.last_key_pressed = Some((k.clone(), Instant::now()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,8 +174,10 @@ impl InnerInputState {
|
|||
let old_focus = self.focus_state.last_focused_id;
|
||||
|
||||
evts.retain(|e| match &e.1 {
|
||||
EventData::Keyboard(k) => match k.key_code {
|
||||
KeyCode::Tab => !self.focus_state.progress(dom, !k.shift_key),
|
||||
EventData::Keyboard(k) => match k.code() {
|
||||
Code::Tab => !self
|
||||
.focus_state
|
||||
.progress(dom, !k.modifiers().contains(Modifiers::SHIFT)),
|
||||
_ => true,
|
||||
},
|
||||
_ => true,
|
||||
|
@ -293,7 +303,10 @@ impl InnerInputState {
|
|||
// a mouse button is released if a button was down and is now not down
|
||||
let was_released = !(previous_buttons - mouse_data.held_buttons()).is_empty();
|
||||
|
||||
let wheel_delta = self.wheel.as_ref().map_or(0.0, |w| w.delta_y);
|
||||
let was_scrolled = self
|
||||
.wheel
|
||||
.as_ref()
|
||||
.map_or(false, |data| !data.delta().is_zero());
|
||||
let wheel_data = &self.wheel;
|
||||
|
||||
{
|
||||
|
@ -457,7 +470,7 @@ impl InnerInputState {
|
|||
{
|
||||
// wheel
|
||||
if let Some(w) = wheel_data {
|
||||
if wheel_delta != 0.0 {
|
||||
if was_scrolled {
|
||||
let mut will_bubble = FxHashSet::default();
|
||||
for node in dom.get_listening_sorted("wheel") {
|
||||
let node_layout = get_abs_layout(node, dom, layout);
|
||||
|
@ -723,13 +736,8 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
|
|||
};
|
||||
|
||||
let get_wheel_data = |up| {
|
||||
// from https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
|
||||
EventData::Wheel(WheelData {
|
||||
delta_mode: 0x01,
|
||||
delta_x: 0.0,
|
||||
delta_y: if up { -1.0 } else { 1.0 },
|
||||
delta_z: 0.0,
|
||||
})
|
||||
let y = if up { -1.0 } else { 1.0 };
|
||||
EventData::Wheel(WheelData::new(WheelDelta::lines(0., y, 0.)))
|
||||
};
|
||||
|
||||
match m.kind {
|
||||
|
@ -748,147 +756,222 @@ fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
|
|||
}
|
||||
|
||||
fn translate_key_event(event: crossterm::event::KeyEvent) -> Option<EventData> {
|
||||
let (code, key_str);
|
||||
let mut shift_key = event.modifiers.contains(KeyModifiers::SHIFT);
|
||||
if let TermKeyCode::Char(c) = event.code {
|
||||
code = match c {
|
||||
'A'..='Z' | 'a'..='z' => match c.to_ascii_uppercase() {
|
||||
'A' => KeyCode::A,
|
||||
'B' => KeyCode::B,
|
||||
'C' => KeyCode::C,
|
||||
'D' => KeyCode::D,
|
||||
'E' => KeyCode::E,
|
||||
'F' => KeyCode::F,
|
||||
'G' => KeyCode::G,
|
||||
'H' => KeyCode::H,
|
||||
'I' => KeyCode::I,
|
||||
'J' => KeyCode::J,
|
||||
'K' => KeyCode::K,
|
||||
'L' => KeyCode::L,
|
||||
'M' => KeyCode::M,
|
||||
'N' => KeyCode::N,
|
||||
'O' => KeyCode::O,
|
||||
'P' => KeyCode::P,
|
||||
'Q' => KeyCode::Q,
|
||||
'R' => KeyCode::R,
|
||||
'S' => KeyCode::S,
|
||||
'T' => KeyCode::T,
|
||||
'U' => KeyCode::U,
|
||||
'V' => KeyCode::V,
|
||||
'W' => KeyCode::W,
|
||||
'X' => KeyCode::X,
|
||||
'Y' => KeyCode::Y,
|
||||
'Z' => KeyCode::Z,
|
||||
_ => return None,
|
||||
},
|
||||
' ' => KeyCode::Space,
|
||||
'[' => KeyCode::OpenBracket,
|
||||
'{' => KeyCode::OpenBracket,
|
||||
']' => KeyCode::CloseBraket,
|
||||
'}' => KeyCode::CloseBraket,
|
||||
';' => KeyCode::Semicolon,
|
||||
':' => KeyCode::Semicolon,
|
||||
',' => KeyCode::Comma,
|
||||
'<' => KeyCode::Comma,
|
||||
'.' => KeyCode::Period,
|
||||
'>' => KeyCode::Period,
|
||||
'1' => KeyCode::Num1,
|
||||
'2' => KeyCode::Num2,
|
||||
'3' => KeyCode::Num3,
|
||||
'4' => KeyCode::Num4,
|
||||
'5' => KeyCode::Num5,
|
||||
'6' => KeyCode::Num6,
|
||||
'7' => KeyCode::Num7,
|
||||
'8' => KeyCode::Num8,
|
||||
'9' => KeyCode::Num9,
|
||||
'0' => KeyCode::Num0,
|
||||
'!' => KeyCode::Num1,
|
||||
'@' => KeyCode::Num2,
|
||||
'#' => KeyCode::Num3,
|
||||
'$' => KeyCode::Num4,
|
||||
'%' => KeyCode::Num5,
|
||||
'^' => KeyCode::Num6,
|
||||
'&' => KeyCode::Num7,
|
||||
'*' => KeyCode::Num8,
|
||||
'(' => KeyCode::Num9,
|
||||
')' => KeyCode::Num0,
|
||||
// numpad charicter are ambiguous to tui
|
||||
// '*' => KeyCode::Multiply,
|
||||
// '/' => KeyCode::Divide,
|
||||
// '-' => KeyCode::Subtract,
|
||||
// '+' => KeyCode::Add,
|
||||
'+' => KeyCode::EqualSign,
|
||||
'-' => KeyCode::Dash,
|
||||
'_' => KeyCode::Dash,
|
||||
'\'' => KeyCode::SingleQuote,
|
||||
'"' => KeyCode::SingleQuote,
|
||||
'\\' => KeyCode::BackSlash,
|
||||
'|' => KeyCode::BackSlash,
|
||||
'/' => KeyCode::ForwardSlash,
|
||||
'?' => KeyCode::ForwardSlash,
|
||||
'=' => KeyCode::EqualSign,
|
||||
'`' => KeyCode::GraveAccent,
|
||||
'~' => KeyCode::GraveAccent,
|
||||
_ => return None,
|
||||
};
|
||||
key_str = c.to_string();
|
||||
} else {
|
||||
code = match event.code {
|
||||
TermKeyCode::Esc => KeyCode::Escape,
|
||||
TermKeyCode::Backspace => KeyCode::Backspace,
|
||||
TermKeyCode::Enter => KeyCode::Enter,
|
||||
TermKeyCode::Left => KeyCode::LeftArrow,
|
||||
TermKeyCode::Right => KeyCode::RightArrow,
|
||||
TermKeyCode::Up => KeyCode::UpArrow,
|
||||
TermKeyCode::Down => KeyCode::DownArrow,
|
||||
TermKeyCode::Home => KeyCode::Home,
|
||||
TermKeyCode::End => KeyCode::End,
|
||||
TermKeyCode::PageUp => KeyCode::PageUp,
|
||||
TermKeyCode::PageDown => KeyCode::PageDown,
|
||||
TermKeyCode::Tab => KeyCode::Tab,
|
||||
TermKeyCode::Delete => KeyCode::Delete,
|
||||
TermKeyCode::Insert => KeyCode::Insert,
|
||||
TermKeyCode::F(fn_num) => match fn_num {
|
||||
1 => KeyCode::F1,
|
||||
2 => KeyCode::F2,
|
||||
3 => KeyCode::F3,
|
||||
4 => KeyCode::F4,
|
||||
5 => KeyCode::F5,
|
||||
6 => KeyCode::F6,
|
||||
7 => KeyCode::F7,
|
||||
8 => KeyCode::F8,
|
||||
9 => KeyCode::F9,
|
||||
10 => KeyCode::F10,
|
||||
11 => KeyCode::F11,
|
||||
12 => KeyCode::F12,
|
||||
_ => return None,
|
||||
},
|
||||
// backtab is Shift + Tab
|
||||
TermKeyCode::BackTab => {
|
||||
shift_key = true;
|
||||
KeyCode::Tab
|
||||
}
|
||||
TermKeyCode::Null => return None,
|
||||
_ => return None,
|
||||
};
|
||||
key_str = if let KeyCode::BackSlash = code {
|
||||
"\\".to_string()
|
||||
} else {
|
||||
format!("{code:?}")
|
||||
}
|
||||
};
|
||||
// from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
|
||||
Some(EventData::Keyboard(KeyboardData {
|
||||
char_code: code.raw_code(),
|
||||
key: key_str,
|
||||
key_code: code,
|
||||
alt_key: event.modifiers.contains(KeyModifiers::ALT),
|
||||
ctrl_key: event.modifiers.contains(KeyModifiers::CONTROL),
|
||||
meta_key: false,
|
||||
shift_key,
|
||||
locale: Default::default(),
|
||||
location: 0x00,
|
||||
repeat: Default::default(),
|
||||
which: Default::default(),
|
||||
}))
|
||||
let key = key_from_crossterm_key_code(event.code);
|
||||
// crossterm does not provide code. we make a guess as to which key might have been pressed
|
||||
// this is probably garbage if the user has a custom keyboard layout
|
||||
let code = guess_code_from_crossterm_key_code(event.code)?;
|
||||
let modifiers = modifiers_from_crossterm_modifiers(event.modifiers);
|
||||
|
||||
Some(EventData::Keyboard(KeyboardData::new(
|
||||
key,
|
||||
code,
|
||||
Location::Standard,
|
||||
false,
|
||||
modifiers,
|
||||
)))
|
||||
}
|
||||
|
||||
/// The crossterm key_code nicely represents the meaning of the key and we can mostly convert it without any issues
|
||||
///
|
||||
/// Exceptions:
|
||||
/// BackTab is converted to Key::Tab, and Null is converted to Key::Unidentified
|
||||
fn key_from_crossterm_key_code(key_code: TermKeyCode) -> Key {
|
||||
match key_code {
|
||||
TermKeyCode::Backspace => Key::Backspace,
|
||||
TermKeyCode::Enter => Key::Enter,
|
||||
TermKeyCode::Left => Key::ArrowLeft,
|
||||
TermKeyCode::Right => Key::ArrowRight,
|
||||
TermKeyCode::Up => Key::ArrowUp,
|
||||
TermKeyCode::Down => Key::ArrowDown,
|
||||
TermKeyCode::Home => Key::Home,
|
||||
TermKeyCode::End => Key::End,
|
||||
TermKeyCode::PageUp => Key::PageUp,
|
||||
TermKeyCode::PageDown => Key::PageDown,
|
||||
TermKeyCode::Tab => Key::Tab,
|
||||
// ? no corresponding Key
|
||||
TermKeyCode::BackTab => Key::Tab,
|
||||
TermKeyCode::Delete => Key::Delete,
|
||||
TermKeyCode::Insert => Key::Insert,
|
||||
TermKeyCode::F(1) => Key::F1,
|
||||
TermKeyCode::F(2) => Key::F2,
|
||||
TermKeyCode::F(3) => Key::F3,
|
||||
TermKeyCode::F(4) => Key::F4,
|
||||
TermKeyCode::F(5) => Key::F5,
|
||||
TermKeyCode::F(6) => Key::F6,
|
||||
TermKeyCode::F(7) => Key::F7,
|
||||
TermKeyCode::F(8) => Key::F8,
|
||||
TermKeyCode::F(9) => Key::F9,
|
||||
TermKeyCode::F(10) => Key::F10,
|
||||
TermKeyCode::F(11) => Key::F11,
|
||||
TermKeyCode::F(12) => Key::F12,
|
||||
TermKeyCode::F(13) => Key::F13,
|
||||
TermKeyCode::F(14) => Key::F14,
|
||||
TermKeyCode::F(15) => Key::F15,
|
||||
TermKeyCode::F(16) => Key::F16,
|
||||
TermKeyCode::F(17) => Key::F17,
|
||||
TermKeyCode::F(18) => Key::F18,
|
||||
TermKeyCode::F(19) => Key::F19,
|
||||
TermKeyCode::F(20) => Key::F20,
|
||||
TermKeyCode::F(21) => Key::F21,
|
||||
TermKeyCode::F(22) => Key::F22,
|
||||
TermKeyCode::F(23) => Key::F23,
|
||||
TermKeyCode::F(24) => Key::F24,
|
||||
TermKeyCode::F(other) => {
|
||||
panic!("Unexpected function key: {other:?}")
|
||||
}
|
||||
TermKeyCode::Char(c) => Key::Character(c.to_string()),
|
||||
TermKeyCode::Null => Key::Unidentified,
|
||||
TermKeyCode::Esc => Key::Escape,
|
||||
}
|
||||
}
|
||||
|
||||
// Crossterm does not provide a way to get the `code` (physical key on keyboard)
|
||||
// So we make a guess based on their `key_code`, but this is probably going to break on anything other than a very standard european keyboard
|
||||
// It may look fine, but it's a horrible hack. But there's nothing better we can do.
|
||||
fn guess_code_from_crossterm_key_code(key_code: TermKeyCode) -> Option<Code> {
|
||||
let code = match key_code {
|
||||
TermKeyCode::Backspace => Code::Backspace,
|
||||
TermKeyCode::Enter => Code::Enter,
|
||||
TermKeyCode::Left => Code::ArrowLeft,
|
||||
TermKeyCode::Right => Code::ArrowRight,
|
||||
TermKeyCode::Up => Code::ArrowUp,
|
||||
TermKeyCode::Down => Code::ArrowDown,
|
||||
TermKeyCode::Home => Code::Home,
|
||||
TermKeyCode::End => Code::End,
|
||||
TermKeyCode::PageUp => Code::PageUp,
|
||||
TermKeyCode::PageDown => Code::PageDown,
|
||||
TermKeyCode::Tab => Code::Tab,
|
||||
// ? Apparently you get BackTab by pressing Tab
|
||||
TermKeyCode::BackTab => Code::Tab,
|
||||
TermKeyCode::Delete => Code::Delete,
|
||||
TermKeyCode::Insert => Code::Insert,
|
||||
TermKeyCode::F(1) => Code::F1,
|
||||
TermKeyCode::F(2) => Code::F2,
|
||||
TermKeyCode::F(3) => Code::F3,
|
||||
TermKeyCode::F(4) => Code::F4,
|
||||
TermKeyCode::F(5) => Code::F5,
|
||||
TermKeyCode::F(6) => Code::F6,
|
||||
TermKeyCode::F(7) => Code::F7,
|
||||
TermKeyCode::F(8) => Code::F8,
|
||||
TermKeyCode::F(9) => Code::F9,
|
||||
TermKeyCode::F(10) => Code::F10,
|
||||
TermKeyCode::F(11) => Code::F11,
|
||||
TermKeyCode::F(12) => Code::F12,
|
||||
TermKeyCode::F(13) => Code::F13,
|
||||
TermKeyCode::F(14) => Code::F14,
|
||||
TermKeyCode::F(15) => Code::F15,
|
||||
TermKeyCode::F(16) => Code::F16,
|
||||
TermKeyCode::F(17) => Code::F17,
|
||||
TermKeyCode::F(18) => Code::F18,
|
||||
TermKeyCode::F(19) => Code::F19,
|
||||
TermKeyCode::F(20) => Code::F20,
|
||||
TermKeyCode::F(21) => Code::F21,
|
||||
TermKeyCode::F(22) => Code::F22,
|
||||
TermKeyCode::F(23) => Code::F23,
|
||||
TermKeyCode::F(24) => Code::F24,
|
||||
TermKeyCode::F(other) => {
|
||||
panic!("Unexpected function key: {other:?}")
|
||||
}
|
||||
// this is a horrible way for crossterm to represent keys but we have to deal with it
|
||||
TermKeyCode::Char(c) => match c {
|
||||
'A'..='Z' | 'a'..='z' => match c.to_ascii_uppercase() {
|
||||
'A' => Code::KeyA,
|
||||
'B' => Code::KeyB,
|
||||
'C' => Code::KeyC,
|
||||
'D' => Code::KeyD,
|
||||
'E' => Code::KeyE,
|
||||
'F' => Code::KeyF,
|
||||
'G' => Code::KeyG,
|
||||
'H' => Code::KeyH,
|
||||
'I' => Code::KeyI,
|
||||
'J' => Code::KeyJ,
|
||||
'K' => Code::KeyK,
|
||||
'L' => Code::KeyL,
|
||||
'M' => Code::KeyM,
|
||||
'N' => Code::KeyN,
|
||||
'O' => Code::KeyO,
|
||||
'P' => Code::KeyP,
|
||||
'Q' => Code::KeyQ,
|
||||
'R' => Code::KeyR,
|
||||
'S' => Code::KeyS,
|
||||
'T' => Code::KeyT,
|
||||
'U' => Code::KeyU,
|
||||
'V' => Code::KeyV,
|
||||
'W' => Code::KeyW,
|
||||
'X' => Code::KeyX,
|
||||
'Y' => Code::KeyY,
|
||||
'Z' => Code::KeyZ,
|
||||
_ => unreachable!("Exhaustively checked all characters in range A..Z"),
|
||||
},
|
||||
' ' => Code::Space,
|
||||
'[' | '{' => Code::BracketLeft,
|
||||
']' | '}' => Code::BracketRight,
|
||||
';' => Code::Semicolon,
|
||||
':' => Code::Semicolon,
|
||||
',' => Code::Comma,
|
||||
'<' => Code::Comma,
|
||||
'.' => Code::Period,
|
||||
'>' => Code::Period,
|
||||
'1' => Code::Digit1,
|
||||
'2' => Code::Digit2,
|
||||
'3' => Code::Digit3,
|
||||
'4' => Code::Digit4,
|
||||
'5' => Code::Digit5,
|
||||
'6' => Code::Digit6,
|
||||
'7' => Code::Digit7,
|
||||
'8' => Code::Digit8,
|
||||
'9' => Code::Digit9,
|
||||
'0' => Code::Digit0,
|
||||
'!' => Code::Digit1,
|
||||
'@' => Code::Digit2,
|
||||
'#' => Code::Digit3,
|
||||
'$' => Code::Digit4,
|
||||
'%' => Code::Digit5,
|
||||
'^' => Code::Digit6,
|
||||
'&' => Code::Digit7,
|
||||
'*' => Code::Digit8,
|
||||
'(' => Code::Digit9,
|
||||
')' => Code::Digit0,
|
||||
// numpad characters are ambiguous; we don't know which key was really pressed
|
||||
// it could be also:
|
||||
// '*' => Code::Multiply,
|
||||
// '/' => Code::Divide,
|
||||
// '-' => Code::Subtract,
|
||||
// '+' => Code::Add,
|
||||
'+' => Code::Equal,
|
||||
'-' | '_' => Code::Minus,
|
||||
'\'' => Code::Quote,
|
||||
'"' => Code::Quote,
|
||||
'\\' => Code::Backslash,
|
||||
'|' => Code::Backslash,
|
||||
'/' => Code::Slash,
|
||||
'?' => Code::Slash,
|
||||
'=' => Code::Equal,
|
||||
'`' => Code::Backquote,
|
||||
'~' => Code::Backquote,
|
||||
_ => return None,
|
||||
},
|
||||
TermKeyCode::Null => return None,
|
||||
TermKeyCode::Esc => Code::Escape,
|
||||
};
|
||||
|
||||
Some(code)
|
||||
}
|
||||
|
||||
fn modifiers_from_crossterm_modifiers(src: KeyModifiers) -> Modifiers {
|
||||
let mut modifiers = Modifiers::empty();
|
||||
|
||||
if src.contains(KeyModifiers::SHIFT) {
|
||||
modifiers.insert(Modifiers::SHIFT);
|
||||
}
|
||||
|
||||
if src.contains(KeyModifiers::ALT) {
|
||||
modifiers.insert(Modifiers::ALT);
|
||||
}
|
||||
|
||||
if src.contains(KeyModifiers::CONTROL) {
|
||||
modifiers.insert(Modifiers::CONTROL);
|
||||
}
|
||||
|
||||
modifiers
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent};
|
||||
use dioxus::prelude::*;
|
||||
use dioxus_html::input_data::keyboard_types::Code;
|
||||
use dioxus_tui::TuiContext;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
|
@ -56,7 +57,7 @@ fn key_down() {
|
|||
width: "100%",
|
||||
height: "100%",
|
||||
onkeydown: move |evt| {
|
||||
assert_eq!(evt.data.key_code, dioxus_html::KeyCode::A);
|
||||
assert_eq!(evt.data.code(), Code::KeyA);
|
||||
tui_ctx.quit();
|
||||
},
|
||||
}
|
||||
|
@ -286,7 +287,7 @@ fn wheel() {
|
|||
width: "100%",
|
||||
height: "100%",
|
||||
onwheel: move |evt| {
|
||||
assert!(evt.data.delta_y > 0.0);
|
||||
assert!(evt.data.delta().strip_units().y > 0.0);
|
||||
tui_ctx.quit();
|
||||
},
|
||||
}
|
||||
|
|
|
@ -521,7 +521,6 @@ fn virtual_event_from_websys_event(event: web_sys::Event) -> Arc<dyn Any + Send
|
|||
key: evt.key(),
|
||||
key_code: KeyCode::from_raw_code(evt.key_code() as u8),
|
||||
ctrl_key: evt.ctrl_key(),
|
||||
locale: "not implemented".to_string(),
|
||||
location: evt.location() as usize,
|
||||
meta_key: evt.meta_key(),
|
||||
repeat: evt.repeat(),
|
||||
|
|
Loading…
Reference in a new issue