mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-28 04:45:13 +00:00
Add support for dispatching key events through the public platform API
This change adds `KeyPress` and `KeyRelease` variants to the `WindowEvent` enum, along with the new `slint::Key` enum, that allows encoding keys.
This commit is contained in:
parent
e3838543fe
commit
61c39b5fa1
36 changed files with 681 additions and 315 deletions
|
@ -10,12 +10,16 @@ All notable changes to this project are documented in this file.
|
|||
- `Window`'s `default-font-size` property is now always set to a non-zero value, provided by
|
||||
either the style or the backend.
|
||||
- In the interpreter, calling `set_property` or `get_property` on properties of the base no longer works.
|
||||
- Renamed the `Keys` namespace for use in `key-pressed`/`key-released` callbacks to `Key`. The
|
||||
old name continues to work.
|
||||
|
||||
### Added
|
||||
|
||||
- Added `material` style with `material-light` and `fluent-dark` as explicit styles
|
||||
- Added `Window::is_visible`
|
||||
- Added `From<char>` for `SharedString` in Rust.
|
||||
- Added `KeyPressed` and `KeyReleased` variants to `slint::WindowEvent` in Rust, along
|
||||
with `slint::Key`, for use by custom platform backends.
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -1005,15 +1005,25 @@ namespace slint::testing {
|
|||
|
||||
using cbindgen_private::KeyboardModifiers;
|
||||
|
||||
/// Send a key events to the given component instance
|
||||
inline void send_keyboard_char(const slint::interpreter::ComponentInstance *component,
|
||||
const slint::SharedString &str, bool pressed)
|
||||
{
|
||||
const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;
|
||||
cbindgen_private::slint_interpreter_component_instance_window(
|
||||
reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(component), &win_ptr);
|
||||
cbindgen_private::slint_send_keyboard_char(
|
||||
&str, pressed, reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr));
|
||||
}
|
||||
|
||||
/// Send a key events to the given component instance
|
||||
inline void send_keyboard_string_sequence(const slint::interpreter::ComponentInstance *component,
|
||||
const slint::SharedString &str,
|
||||
KeyboardModifiers modifiers = {})
|
||||
const slint::SharedString &str)
|
||||
{
|
||||
const cbindgen_private::WindowAdapterRcOpaque *win_ptr = nullptr;
|
||||
cbindgen_private::slint_interpreter_component_instance_window(
|
||||
reinterpret_cast<const cbindgen_private::ErasedComponentBox *>(component), &win_ptr);
|
||||
cbindgen_private::send_keyboard_string_sequence(
|
||||
&str, modifiers, reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr));
|
||||
&str, reinterpret_cast<const cbindgen_private::WindowAdapterRc *>(win_ptr));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,17 @@ inline void send_mouse_click(const Component *component, float x, float y)
|
|||
}
|
||||
|
||||
template<typename Component>
|
||||
inline void send_keyboard_string_sequence(const Component *component,
|
||||
const slint::SharedString &str,
|
||||
cbindgen_private::KeyboardModifiers modifiers = {})
|
||||
inline void send_keyboard_char(const Component *component, const slint::SharedString &str,
|
||||
bool pressed)
|
||||
{
|
||||
cbindgen_private::send_keyboard_string_sequence(&str, modifiers,
|
||||
&component->m_window.window_handle());
|
||||
cbindgen_private::slint_send_keyboard_char(&str, pressed, &component->m_window.window_handle());
|
||||
}
|
||||
|
||||
template<typename Component>
|
||||
inline void send_keyboard_string_sequence(const Component *component,
|
||||
const slint::SharedString &str)
|
||||
{
|
||||
cbindgen_private::send_keyboard_string_sequence(&str, &component->m_window.window_handle());
|
||||
}
|
||||
|
||||
#define assert_eq(A, B) \
|
||||
|
|
|
@ -478,7 +478,9 @@ SCENARIO("Send key events")
|
|||
property <string> result;
|
||||
scope := FocusScope {
|
||||
key-pressed(event) => {
|
||||
if (event.text != Key.Shift && event.text != Key.Control) {
|
||||
result += event.text;
|
||||
}
|
||||
return accept;
|
||||
}
|
||||
}
|
||||
|
@ -487,7 +489,7 @@ SCENARIO("Send key events")
|
|||
"");
|
||||
REQUIRE(comp_def.has_value());
|
||||
auto instance = comp_def->create();
|
||||
slint::testing::send_keyboard_string_sequence(&*instance, "Hello keys!", {});
|
||||
slint::testing::send_keyboard_string_sequence(&*instance, "Hello keys!");
|
||||
REQUIRE(*instance->get_property("result")->to_string() == "Hello keys!");
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,8 @@ pub mod re_exports {
|
|||
};
|
||||
pub use i_slint_core::graphics::*;
|
||||
pub use i_slint_core::input::{
|
||||
FocusEvent, InputEventResult, KeyEvent, KeyEventResult, KeyboardModifiers, MouseEvent,
|
||||
key_codes::Key, FocusEvent, InputEventResult, KeyEvent, KeyEventResult, KeyboardModifiers,
|
||||
MouseEvent,
|
||||
};
|
||||
pub use i_slint_core::item_tree::{
|
||||
visit_item_tree, ItemTreeNode, ItemVisitorRefMut, ItemVisitorVTable, ItemWeak,
|
||||
|
|
|
@ -494,7 +494,7 @@ The FocusScope exposes callback to intercept the pressed key when it has focus.
|
|||
|
||||
The KeyEvent has a text property which is a character of the key entered.
|
||||
When a non-printable key is pressed, the character will be either a control character,
|
||||
or it will be mapped to a private unicode character. The mapping of these non-printable, special characters is available in the [`Keys`](#keys) namespace
|
||||
or it will be mapped to a private unicode character. The mapping of these non-printable, special characters is available in the [`Key`](#key) namespace
|
||||
|
||||
### Properties
|
||||
|
||||
|
@ -522,7 +522,7 @@ Example := Window {
|
|||
if (event.modifiers.control) {
|
||||
debug("control was pressed during this event");
|
||||
}
|
||||
if (event.text == Keys.Escape) {
|
||||
if (event.text == Key.Escape) {
|
||||
debug("Esc key was pressed")
|
||||
}
|
||||
accept
|
||||
|
@ -820,9 +820,9 @@ This structure is generated and passed to the `pointer-event` callback of the `T
|
|||
|
||||
The following namespaces provide access to common constants such as special keys or named colors.
|
||||
|
||||
## `Keys`
|
||||
## `Key`
|
||||
|
||||
Use the constants in the `Keys` namespace to handle pressing of keys that don't have a printable character. Check the value of [`KeyEvent`](#keyevent)'s `text` property
|
||||
Use the constants in the `Key` namespace to handle pressing of keys that don't have a printable character. Check the value of [`KeyEvent`](#keyevent)'s `text` property
|
||||
against the constants below.
|
||||
|
||||
* **`Backspace`**
|
||||
|
@ -831,6 +831,15 @@ against the constants below.
|
|||
* **`Escape`**
|
||||
* **`Backtab`**
|
||||
* **`Delete`**
|
||||
* **`Shift`**
|
||||
* **`Control`**
|
||||
* **`Alt`**
|
||||
* **`AltGr`**
|
||||
* **`CapsLock`**
|
||||
* **`ShiftR`**
|
||||
* **`ControlR`**
|
||||
* **`Meta`**
|
||||
* **`MetaR`**
|
||||
* **`UpArrow`**
|
||||
* **`DownArrow`**
|
||||
* **`LeftArrow`**
|
||||
|
|
|
@ -28,17 +28,17 @@ export Carousel := FocusScope {
|
|||
|
||||
focus-scope:= FocusScope {
|
||||
key-pressed(event) => {
|
||||
if(event.text == Keys.UpArrow) {
|
||||
if(event.text == Key.UpArrow) {
|
||||
root.move-focus-up();
|
||||
return accept;
|
||||
}
|
||||
|
||||
if(event.text == Keys.RightArrow) {
|
||||
if(event.text == Key.RightArrow) {
|
||||
root.move-right();
|
||||
return accept;
|
||||
}
|
||||
|
||||
if(event.text == Keys.LeftArrow) {
|
||||
if(event.text == Key.LeftArrow) {
|
||||
root.move-left();
|
||||
return accept;
|
||||
}
|
||||
|
|
|
@ -74,11 +74,11 @@ export SideBar := Rectangle {
|
|||
current-item = current-focused;
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.UpArrow) {
|
||||
if (event.text == Key.UpArrow) {
|
||||
focused-tab = Math.max(focused-tab - 1, 0);
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.DownArrow) {
|
||||
if (event.text == Key.DownArrow) {
|
||||
focused-tab = Math.min(focused-tab + 1, model.length - 1);
|
||||
return accept;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use i_slint_core::graphics::rendering_metrics_collector::{
|
|||
RenderingMetrics, RenderingMetricsCollector,
|
||||
};
|
||||
use i_slint_core::graphics::{euclid, Brush, Color, FontRequest, Image, Point, SharedImageBuffer};
|
||||
use i_slint_core::input::{KeyEvent, KeyEventType, MouseEvent};
|
||||
use i_slint_core::input::{KeyEventType, KeyInputEvent, MouseEvent};
|
||||
use i_slint_core::item_rendering::{ItemCache, ItemRenderer};
|
||||
use i_slint_core::items::{
|
||||
self, FillRule, ImageRendering, InputType, ItemRc, ItemRef, Layer, MouseCursor, Opacity,
|
||||
|
@ -172,19 +172,17 @@ cpp! {{
|
|||
}
|
||||
|
||||
void keyPressEvent(QKeyEvent *event) override {
|
||||
uint modifiers = uint(event->modifiers());
|
||||
QString text = event->text();
|
||||
int key = event->key();
|
||||
rust!(Slint_keyPress [rust_window: &QtWindow as "void*", key: i32 as "int", text: qttypes::QString as "QString", modifiers: u32 as "uint"] {
|
||||
rust_window.key_event(key, text.clone(), modifiers, false);
|
||||
rust!(Slint_keyPress [rust_window: &QtWindow as "void*", key: i32 as "int", text: qttypes::QString as "QString"] {
|
||||
rust_window.key_event(key, text.clone(), false);
|
||||
});
|
||||
}
|
||||
void keyReleaseEvent(QKeyEvent *event) override {
|
||||
uint modifiers = uint(event->modifiers());
|
||||
QString text = event->text();
|
||||
int key = event->key();
|
||||
rust!(Slint_keyRelease [rust_window: &QtWindow as "void*", key: i32 as "int", text: qttypes::QString as "QString", modifiers: u32 as "uint"] {
|
||||
rust_window.key_event(key, text.clone(), modifiers, true);
|
||||
rust!(Slint_keyRelease [rust_window: &QtWindow as "void*", key: i32 as "int", text: qttypes::QString as "QString"] {
|
||||
rust_window.key_event(key, text.clone(), true);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -280,23 +278,23 @@ cpp! {{
|
|||
let runtime_window = WindowInner::from_pub(&rust_window.window);
|
||||
|
||||
if !preedit_string.is_empty() {
|
||||
let event = KeyEvent {
|
||||
let event = KeyInputEvent {
|
||||
event_type: KeyEventType::UpdateComposition,
|
||||
text: preedit_string.to_string().into(),
|
||||
preedit_selection_start: replacement_start as usize,
|
||||
preedit_selection_end: replacement_start as usize + replacement_length as usize,
|
||||
..Default::default()
|
||||
};
|
||||
runtime_window.process_key_input(&event);
|
||||
runtime_window.process_key_input(event);
|
||||
}
|
||||
|
||||
if !commit_string.is_empty() {
|
||||
let event = KeyEvent {
|
||||
let event = KeyInputEvent {
|
||||
event_type: KeyEventType::CommitComposition,
|
||||
text: commit_string.to_string().into(),
|
||||
..Default::default()
|
||||
};
|
||||
runtime_window.process_key_input(&event);
|
||||
runtime_window.process_key_input(event);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1419,25 +1417,18 @@ impl QtWindow {
|
|||
timer_event();
|
||||
}
|
||||
|
||||
fn key_event(&self, key: i32, text: qttypes::QString, qt_modifiers: u32, released: bool) {
|
||||
fn key_event(&self, key: i32, text: qttypes::QString, released: bool) {
|
||||
i_slint_core::animations::update_animations();
|
||||
let text: String = text.into();
|
||||
let modifiers = i_slint_core::input::KeyboardModifiers {
|
||||
control: (qt_modifiers & key_generated::Qt_KeyboardModifier_ControlModifier) != 0,
|
||||
alt: (qt_modifiers & key_generated::Qt_KeyboardModifier_AltModifier) != 0,
|
||||
shift: (qt_modifiers & key_generated::Qt_KeyboardModifier_ShiftModifier) != 0,
|
||||
meta: (qt_modifiers & key_generated::Qt_KeyboardModifier_MetaModifier) != 0,
|
||||
};
|
||||
|
||||
let text = qt_key_to_string(key as key_generated::Qt_Key, text);
|
||||
|
||||
let event = KeyEvent {
|
||||
let event = KeyInputEvent {
|
||||
event_type: if released { KeyEventType::KeyReleased } else { KeyEventType::KeyPressed },
|
||||
text,
|
||||
modifiers,
|
||||
..Default::default()
|
||||
};
|
||||
WindowInner::from_pub(&self.window).process_key_input(&event);
|
||||
WindowInner::from_pub(&self.window).process_key_input(event);
|
||||
|
||||
timer_event();
|
||||
}
|
||||
|
@ -2024,8 +2015,7 @@ mod key_codes {
|
|||
$($(key_generated::$qt => $char,)*)*
|
||||
_ => return None,
|
||||
};
|
||||
let mut buffer = [0; 6];
|
||||
Some(i_slint_core::SharedString::from(char.encode_utf8(&mut buffer) as &str))
|
||||
Some(char.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -132,14 +132,11 @@ pub fn init() {
|
|||
|
||||
/// This module contains functions useful for unit tests
|
||||
mod for_unit_test {
|
||||
use core::cell::Cell;
|
||||
use i_slint_core::api::ComponentHandle;
|
||||
pub use i_slint_core::tests::slint_mock_elapsed_time as mock_elapsed_time;
|
||||
use i_slint_core::window::WindowInner;
|
||||
use i_slint_core::SharedString;
|
||||
|
||||
thread_local!(static KEYBOARD_MODIFIERS : Cell<i_slint_core::input::KeyboardModifiers> = Default::default());
|
||||
|
||||
/// Simulate a mouse click
|
||||
pub fn send_mouse_click<
|
||||
X: vtable::HasStaticVTable<i_slint_core::component::ComponentVTable> + 'static,
|
||||
|
@ -159,15 +156,20 @@ mod for_unit_test {
|
|||
);
|
||||
}
|
||||
|
||||
/// Simulate a change in keyboard modifiers being pressed
|
||||
pub fn set_current_keyboard_modifiers<
|
||||
/// Simulate entering a sequence of ascii characters key by (pressed or released).
|
||||
pub fn send_keyboard_char<
|
||||
X: vtable::HasStaticVTable<i_slint_core::component::ComponentVTable>,
|
||||
Component: Into<vtable::VRc<i_slint_core::component::ComponentVTable, X>> + ComponentHandle,
|
||||
>(
|
||||
_component: &Component,
|
||||
modifiers: i_slint_core::input::KeyboardModifiers,
|
||||
component: &Component,
|
||||
string: char,
|
||||
pressed: bool,
|
||||
) {
|
||||
KEYBOARD_MODIFIERS.with(|x| x.set(modifiers))
|
||||
i_slint_core::tests::slint_send_keyboard_char(
|
||||
&SharedString::from(string),
|
||||
pressed,
|
||||
&WindowInner::from_pub(component.window()).window_adapter(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Simulate entering a sequence of ascii characters key by key.
|
||||
|
@ -180,7 +182,6 @@ mod for_unit_test {
|
|||
) {
|
||||
i_slint_core::tests::send_keyboard_string_sequence(
|
||||
&SharedString::from(sequence),
|
||||
KEYBOARD_MODIFIERS.with(|x| x.get()),
|
||||
&WindowInner::from_pub(component.window()).window_adapter(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use i_slint_core as corelib;
|
|||
|
||||
use corelib::api::EventLoopError;
|
||||
use corelib::graphics::euclid;
|
||||
use corelib::input::{KeyEvent, KeyEventType, KeyboardModifiers, MouseEvent};
|
||||
use corelib::input::{KeyEventType, KeyInputEvent, MouseEvent};
|
||||
use corelib::window::*;
|
||||
use corelib::{Coord, SharedString};
|
||||
use std::cell::{Cell, RefCell, RefMut};
|
||||
|
@ -30,7 +30,6 @@ pub(crate) static QUIT_ON_LAST_WINDOW_CLOSED: std::sync::atomic::AtomicBool =
|
|||
|
||||
pub trait WinitWindow: WindowAdapter {
|
||||
fn currently_pressed_key_code(&self) -> &Cell<Option<winit::event::VirtualKeyCode>>;
|
||||
fn current_keyboard_modifiers(&self) -> &Cell<KeyboardModifiers>;
|
||||
/// Returns true if during the drawing request_redraw() was called.
|
||||
fn draw(&self) -> bool;
|
||||
fn with_window_handle(&self, callback: &mut dyn FnMut(&winit::window::Window));
|
||||
|
@ -225,8 +224,7 @@ mod key_codes {
|
|||
$($(winit::event::VirtualKeyCode::$winit => $char,)*)*
|
||||
_ => return None,
|
||||
};
|
||||
let mut buffer = [0; 6];
|
||||
Some(i_slint_core::SharedString::from(char.encode_utf8(&mut buffer) as &str))
|
||||
Some(char.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -239,23 +237,6 @@ fn process_window_event(
|
|||
cursor_pos: &mut LogicalPoint,
|
||||
pressed: &mut bool,
|
||||
) {
|
||||
fn key_event(
|
||||
event_type: KeyEventType,
|
||||
text: SharedString,
|
||||
modifiers: KeyboardModifiers,
|
||||
) -> KeyEvent {
|
||||
let mut event = KeyEvent { event_type, text, modifiers, ..Default::default() };
|
||||
|
||||
let tab = String::from(corelib::input::key_codes::Tab);
|
||||
|
||||
// map Shift-Tab into (Shift) Backtab to have a similar behavior as Qt backend
|
||||
if event.text == tab && modifiers.shift {
|
||||
event.text = SharedString::from(String::from(corelib::input::key_codes::Backtab));
|
||||
}
|
||||
|
||||
event
|
||||
}
|
||||
|
||||
let runtime_window = WindowInner::from_pub(window.window());
|
||||
match event {
|
||||
WindowEvent::Resized(size) => {
|
||||
|
@ -279,7 +260,7 @@ fn process_window_event(
|
|||
.and_then(winit_key_code_to_string)
|
||||
.filter(|key_text| !key_text.starts_with(char::is_control))
|
||||
} else {
|
||||
Some(ch.to_string().into())
|
||||
Some(SharedString::from(ch))
|
||||
};
|
||||
|
||||
let text = match text {
|
||||
|
@ -287,13 +268,16 @@ fn process_window_event(
|
|||
None => return,
|
||||
};
|
||||
|
||||
let modifiers = window.current_keyboard_modifiers().get();
|
||||
|
||||
let mut event = key_event(KeyEventType::KeyPressed, text, modifiers);
|
||||
|
||||
runtime_window.process_key_input(&event);
|
||||
event.event_type = KeyEventType::KeyReleased;
|
||||
runtime_window.process_key_input(&event);
|
||||
runtime_window.process_key_input(KeyInputEvent {
|
||||
event_type: KeyEventType::KeyPressed,
|
||||
text: text.clone(),
|
||||
..Default::default()
|
||||
});
|
||||
runtime_window.process_key_input(KeyInputEvent {
|
||||
event_type: KeyEventType::KeyReleased,
|
||||
text: text.clone(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
WindowEvent::Focused(have_focus) => {
|
||||
let have_focus = have_focus || window.input_method_focused();
|
||||
|
@ -305,63 +289,51 @@ fn process_window_event(
|
|||
}
|
||||
}
|
||||
WindowEvent::KeyboardInput { ref input, .. } => {
|
||||
// For now: Match Qt's behavior of mapping command to control and control to meta (LWin/RWin).
|
||||
let key_code = input.virtual_keycode.map(|key_code| match key_code {
|
||||
#[cfg(target_os = "macos")]
|
||||
winit::event::VirtualKeyCode::LControl => winit::event::VirtualKeyCode::LWin,
|
||||
#[cfg(target_os = "macos")]
|
||||
winit::event::VirtualKeyCode::RControl => winit::event::VirtualKeyCode::RWin,
|
||||
#[cfg(target_os = "macos")]
|
||||
winit::event::VirtualKeyCode::LWin => winit::event::VirtualKeyCode::LControl,
|
||||
#[cfg(target_os = "macos")]
|
||||
winit::event::VirtualKeyCode::RWin => winit::event::VirtualKeyCode::RControl,
|
||||
code @ _ => code,
|
||||
});
|
||||
window.currently_pressed_key_code().set(match input.state {
|
||||
winit::event::ElementState::Pressed => input.virtual_keycode,
|
||||
winit::event::ElementState::Pressed => key_code,
|
||||
_ => None,
|
||||
});
|
||||
if let Some(text) = input.virtual_keycode.and_then(key_codes::winit_key_to_string) {
|
||||
#[allow(unused_mut)]
|
||||
let mut modifiers = window.current_keyboard_modifiers().get();
|
||||
// On wasm, the WindowEvent::ModifiersChanged event is not received
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
modifiers.shift |= input.modifiers.shift();
|
||||
modifiers.control |= input.modifiers.ctrl();
|
||||
modifiers.meta |= input.modifiers.logo();
|
||||
modifiers.alt |= input.modifiers.alt();
|
||||
}
|
||||
|
||||
let event = key_event(
|
||||
match input.state {
|
||||
if let Some(text) = key_code.and_then(key_codes::winit_key_to_string) {
|
||||
runtime_window.process_key_input(KeyInputEvent {
|
||||
event_type: match input.state {
|
||||
winit::event::ElementState::Pressed => KeyEventType::KeyPressed,
|
||||
winit::event::ElementState::Released => KeyEventType::KeyReleased,
|
||||
},
|
||||
text,
|
||||
modifiers,
|
||||
);
|
||||
runtime_window.process_key_input(&event);
|
||||
..Default::default()
|
||||
});
|
||||
};
|
||||
}
|
||||
WindowEvent::Ime(winit::event::Ime::Preedit(string, preedit_selection)) => {
|
||||
let preedit_selection = preedit_selection.unwrap_or((0, 0));
|
||||
let event = KeyEvent {
|
||||
let event = KeyInputEvent {
|
||||
event_type: KeyEventType::UpdateComposition,
|
||||
text: string.into(),
|
||||
preedit_selection_start: preedit_selection.0,
|
||||
preedit_selection_end: preedit_selection.1,
|
||||
..Default::default()
|
||||
};
|
||||
runtime_window.process_key_input(&event);
|
||||
runtime_window.process_key_input(event);
|
||||
}
|
||||
WindowEvent::Ime(winit::event::Ime::Commit(string)) => {
|
||||
let event = KeyEvent {
|
||||
let event = KeyInputEvent {
|
||||
event_type: KeyEventType::CommitComposition,
|
||||
text: string.into(),
|
||||
..Default::default()
|
||||
};
|
||||
runtime_window.process_key_input(&event);
|
||||
}
|
||||
WindowEvent::ModifiersChanged(state) => {
|
||||
// To provide an easier cross-platform behavior, we map the command key to control
|
||||
// on macOS, and control to meta.
|
||||
#[cfg(target_os = "macos")]
|
||||
let (control, meta) = (state.logo(), state.ctrl());
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let (control, meta) = (state.ctrl(), state.logo());
|
||||
let modifiers =
|
||||
KeyboardModifiers { shift: state.shift(), alt: state.alt(), control, meta };
|
||||
window.current_keyboard_modifiers().set(modifiers);
|
||||
runtime_window.process_key_input(event);
|
||||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let position = position.to_logical(runtime_window.scale_factor() as f64);
|
||||
|
|
|
@ -14,7 +14,6 @@ use crate::renderer::{WinitCompatibleCanvas, WinitCompatibleRenderer};
|
|||
use const_field_offset::FieldOffsets;
|
||||
use corelib::component::ComponentRc;
|
||||
use corelib::graphics::euclid::num::Zero;
|
||||
use corelib::input::KeyboardModifiers;
|
||||
use corelib::items::{ItemRef, MouseCursor};
|
||||
use corelib::layout::Orientation;
|
||||
use corelib::lengths::{LogicalLength, LogicalPoint, LogicalSize};
|
||||
|
@ -83,7 +82,6 @@ pub(crate) struct GLWindow<Renderer: WinitCompatibleRenderer + 'static> {
|
|||
window: corelib::api::Window,
|
||||
self_weak: Weak<Self>,
|
||||
map_state: RefCell<GraphicsWindowBackendState<Renderer>>,
|
||||
keyboard_modifiers: std::cell::Cell<KeyboardModifiers>,
|
||||
currently_pressed_key_code: std::cell::Cell<Option<winit::event::VirtualKeyCode>>,
|
||||
pending_redraw: Cell<bool>,
|
||||
|
||||
|
@ -108,7 +106,6 @@ impl<Renderer: WinitCompatibleRenderer + 'static> GLWindow<Renderer> {
|
|||
requested_position: None,
|
||||
requested_size: None,
|
||||
}),
|
||||
keyboard_modifiers: Default::default(),
|
||||
currently_pressed_key_code: Default::default(),
|
||||
pending_redraw: Cell::new(false),
|
||||
renderer: Renderer::new(
|
||||
|
@ -184,10 +181,6 @@ impl<Renderer: WinitCompatibleRenderer + 'static> WinitWindow for GLWindow<Rende
|
|||
&self.currently_pressed_key_code
|
||||
}
|
||||
|
||||
fn current_keyboard_modifiers(&self) -> &Cell<KeyboardModifiers> {
|
||||
&self.keyboard_modifiers
|
||||
}
|
||||
|
||||
/// Draw the items of the specified `component` in the given window.
|
||||
fn draw(&self) -> bool {
|
||||
let window = match self.borrow_mapped_window() {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
use std::cell::RefCell;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use i_slint_core::input::{KeyEvent, KeyEventType, KeyboardModifiers};
|
||||
use i_slint_core::input::{KeyEventType, KeyInputEvent};
|
||||
use i_slint_core::window::{WindowAdapter, WindowInner};
|
||||
use i_slint_core::SharedString;
|
||||
use wasm_bindgen::closure::Closure;
|
||||
|
@ -83,8 +83,7 @@ impl WasmInputHelper {
|
|||
if let (Some(window_adapter), Some(text)) = (win.upgrade(), event_text(&e)) {
|
||||
e.prevent_default();
|
||||
shared_state2.borrow_mut().has_key_down = true;
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(&KeyEvent {
|
||||
modifiers: modifiers(&e),
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
text,
|
||||
event_type: KeyEventType::KeyPressed,
|
||||
..Default::default()
|
||||
|
@ -98,8 +97,7 @@ impl WasmInputHelper {
|
|||
if let (Some(window_adapter), Some(text)) = (win.upgrade(), event_text(&e)) {
|
||||
e.prevent_default();
|
||||
shared_state2.borrow_mut().has_key_down = false;
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(&KeyEvent {
|
||||
modifiers: modifiers(&e),
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
text,
|
||||
event_type: KeyEventType::KeyReleased,
|
||||
..Default::default()
|
||||
|
@ -116,12 +114,12 @@ impl WasmInputHelper {
|
|||
if !shared_state2.borrow_mut().has_key_down {
|
||||
let window_inner = WindowInner::from_pub(window_adapter.window());
|
||||
let text = SharedString::from(data.as_str());
|
||||
window_inner.process_key_input(&KeyEvent {
|
||||
window_inner.process_key_input(KeyInputEvent {
|
||||
text: text.clone(),
|
||||
event_type: KeyEventType::KeyPressed,
|
||||
..Default::default()
|
||||
});
|
||||
window_inner.process_key_input(&KeyEvent {
|
||||
window_inner.process_key_input(KeyInputEvent {
|
||||
text,
|
||||
event_type: KeyEventType::KeyReleased,
|
||||
..Default::default()
|
||||
|
@ -138,7 +136,7 @@ impl WasmInputHelper {
|
|||
h.add_event_listener("compositionend", move |e: web_sys::CompositionEvent| {
|
||||
if let (Some(window_adapter), Some(data)) = (win.upgrade(), e.data()) {
|
||||
let window_inner = WindowInner::from_pub(window_adapter.window());
|
||||
window_inner.process_key_input(&KeyEvent {
|
||||
window_inner.process_key_input(KeyInputEvent {
|
||||
text: data.into(),
|
||||
event_type: KeyEventType::CommitComposition,
|
||||
..Default::default()
|
||||
|
@ -153,7 +151,7 @@ impl WasmInputHelper {
|
|||
let window_inner = WindowInner::from_pub(window_adapter.window());
|
||||
let text: SharedString = data.into();
|
||||
let preedit_cursor_pos = text.len();
|
||||
window_inner.process_key_input(&KeyEvent {
|
||||
window_inner.process_key_input(KeyInputEvent {
|
||||
text,
|
||||
event_type: KeyEventType::UpdateComposition,
|
||||
preedit_selection_start: preedit_cursor_pos,
|
||||
|
@ -214,10 +212,7 @@ fn event_text(e: &web_sys::KeyboardEvent) -> Option<SharedString> {
|
|||
|
||||
let key = e.key();
|
||||
|
||||
let convert = |char: char| {
|
||||
let mut buffer = [0; 6];
|
||||
Some(SharedString::from(char.encode_utf8(&mut buffer) as &str))
|
||||
};
|
||||
let convert = |char: char| Some(char.into());
|
||||
|
||||
macro_rules! check_non_printable_code {
|
||||
($($char:literal # $name:ident # $($_qt:ident)|* # $($_winit:ident)|* ;)*) => {
|
||||
|
@ -243,12 +238,3 @@ fn event_text(e: &web_sys::KeyboardEvent) -> Option<SharedString> {
|
|||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn modifiers(e: &web_sys::KeyboardEvent) -> KeyboardModifiers {
|
||||
KeyboardModifiers {
|
||||
alt: e.alt_key(),
|
||||
control: e.ctrl_key(),
|
||||
meta: e.meta_key(),
|
||||
shift: e.shift_key(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,20 @@ macro_rules! for_each_special_keys {
|
|||
'\u{0019}' # Backtab # Qt_Key_Key_Backtab # ;
|
||||
'\u{007f}' # Delete # Qt_Key_Key_Delete # Delete ;
|
||||
|
||||
// The modifier key codes comes from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode.
|
||||
'\u{0010}' # Shift # Qt_Key_Key_Shift # LShift ;
|
||||
'\u{0011}' # Control # Qt_Key_Key_Meta # LControl ;
|
||||
'\u{0012}' # Alt # Qt_Key_Key_Alt # LAlt ;
|
||||
'\u{0013}' # AltGr # Qt_Key_Key_AltGr # RAlt ;
|
||||
'\u{0014}' # CapsLock # Qt_Key_Key_CapsLock # ;
|
||||
|
||||
'\u{0015}' # ShiftR # # RShift ;
|
||||
'\u{0016}' # ControlR # # RControl ;
|
||||
|
||||
// meta defines the macos command key (check DOM_VK_META on https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode)
|
||||
'\u{00E0}' # Meta # Qt_Key_Key_Control # LWin ;
|
||||
'\u{00E1}' # MetaR # # RWin ;
|
||||
|
||||
'\u{F700}' # UpArrow # Qt_Key_Key_Up # Up ;
|
||||
'\u{F701}' # DownArrow # Qt_Key_Key_Down # Down ;
|
||||
'\u{F702}' # LeftArrow # Qt_Key_Key_Left # Left ;
|
||||
|
|
|
@ -89,6 +89,7 @@ pub enum BuiltinNamespace {
|
|||
Colors,
|
||||
Math,
|
||||
Keys,
|
||||
Key,
|
||||
SlintInternal,
|
||||
}
|
||||
|
||||
|
@ -102,6 +103,7 @@ impl LookupResult {
|
|||
pub fn deprecated(&self) -> Option<&str> {
|
||||
match self {
|
||||
Self::Expression { deprecated: Some(x), .. } => Some(x.as_str()),
|
||||
Self::Namespace(BuiltinNamespace::Keys) => Some("Key"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -152,6 +154,7 @@ impl LookupObject for LookupResult {
|
|||
}
|
||||
LookupResult::Namespace(BuiltinNamespace::Math) => MathFunctions.for_each_entry(ctx, f),
|
||||
LookupResult::Namespace(BuiltinNamespace::Keys) => KeysLookup.for_each_entry(ctx, f),
|
||||
LookupResult::Namespace(BuiltinNamespace::Key) => KeysLookup.for_each_entry(ctx, f),
|
||||
LookupResult::Namespace(BuiltinNamespace::SlintInternal) => {
|
||||
SlintInternal.for_each_entry(ctx, f)
|
||||
}
|
||||
|
@ -167,6 +170,7 @@ impl LookupObject for LookupResult {
|
|||
}
|
||||
LookupResult::Namespace(BuiltinNamespace::Math) => MathFunctions.lookup(ctx, name),
|
||||
LookupResult::Namespace(BuiltinNamespace::Keys) => KeysLookup.lookup(ctx, name),
|
||||
LookupResult::Namespace(BuiltinNamespace::Key) => KeysLookup.lookup(ctx, name),
|
||||
LookupResult::Namespace(BuiltinNamespace::SlintInternal) => {
|
||||
SlintInternal.lookup(ctx, name)
|
||||
}
|
||||
|
@ -701,6 +705,7 @@ impl LookupObject for BuiltinNamespaceLookup {
|
|||
None.or_else(|| f("Colors", LookupResult::Namespace(BuiltinNamespace::Colors)))
|
||||
.or_else(|| f("Math", LookupResult::Namespace(BuiltinNamespace::Math)))
|
||||
.or_else(|| f("Keys", LookupResult::Namespace(BuiltinNamespace::Keys)))
|
||||
.or_else(|| f("Key", LookupResult::Namespace(BuiltinNamespace::Key)))
|
||||
.or_else(|| {
|
||||
f("SlintInternal", LookupResult::Namespace(BuiltinNamespace::SlintInternal))
|
||||
})
|
||||
|
|
|
@ -23,4 +23,15 @@ Xxx := Rectangle {
|
|||
color = #000000;
|
||||
// ^warning{The property 'color' has been deprecated. Please use 'background' instead}
|
||||
}
|
||||
|
||||
Foo := FocusScope {
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.Escape) {
|
||||
// ^warning{The property 'Keys' has been deprecated. Please use 'Key' instead}
|
||||
debug("Esc key was pressed")
|
||||
}
|
||||
accept
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -202,10 +202,10 @@ export SpinBox := FocusScope {
|
|||
}
|
||||
|
||||
key-pressed(event) => {
|
||||
if (enabled && event.text == Keys.UpArrow && value < maximum) {
|
||||
if (enabled && event.text == Key.UpArrow && value < maximum) {
|
||||
value += 1;
|
||||
accept
|
||||
} else if (enabled && event.text == Keys.DownArrow && value > minimum) {
|
||||
} else if (enabled && event.text == Key.DownArrow && value > minimum) {
|
||||
value -= 1;
|
||||
accept
|
||||
} else {
|
||||
|
@ -291,10 +291,10 @@ export Slider := Rectangle {
|
|||
width: 0px;
|
||||
|
||||
key-pressed(event) => {
|
||||
if (enabled && event.text == Keys.RightArrow) {
|
||||
if (enabled && event.text == Key.RightArrow) {
|
||||
value = Math.min(value + 1, maximum);
|
||||
accept
|
||||
} else if (enabled && event.text == Keys.LeftArrow) {
|
||||
} else if (enabled && event.text == Key.LeftArrow) {
|
||||
value = Math.max(value - 1, minimum);
|
||||
accept
|
||||
} else {
|
||||
|
@ -431,11 +431,11 @@ export TabBarImpl := Rectangle {
|
|||
current = current-focused;
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.LeftArrow) {
|
||||
if (event.text == Key.LeftArrow) {
|
||||
focused-tab = Math.max(focused-tab - 1, 0);
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.RightArrow) {
|
||||
if (event.text == Key.RightArrow) {
|
||||
focused-tab = Math.min(focused-tab + 1, num-tabs - 1);
|
||||
return accept;
|
||||
}
|
||||
|
@ -516,10 +516,10 @@ export StandardListView := ListView {
|
|||
}
|
||||
FocusScope {
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.UpArrow && current-item > 0) {
|
||||
if (event.text == Key.UpArrow && current-item > 0) {
|
||||
current-item -= 1;
|
||||
return accept;
|
||||
} else if (event.text == Keys.DownArrow && current-item + 1 < model.length) {
|
||||
} else if (event.text == Key.DownArrow && current-item + 1 < model.length) {
|
||||
current-item += 1;
|
||||
return accept;
|
||||
}
|
||||
|
@ -539,16 +539,16 @@ export ComboBox := FocusScope {
|
|||
accessible-value <=> current-value;
|
||||
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.UpArrow) {
|
||||
if (event.text == Key.UpArrow) {
|
||||
current-index = Math.max(current-index - 1, 0);
|
||||
current-value = model[current-index];
|
||||
return accept;
|
||||
} else if (event.text == Keys.DownArrow) {
|
||||
} else if (event.text == Key.DownArrow) {
|
||||
current-index = Math.min(current-index + 1, model.length - 1);
|
||||
current-value = model[current-index];
|
||||
return accept;
|
||||
// PopupWindow can not get hidden again at this time, so do not allow to pop that up.
|
||||
// } else if (event.text == Keys.Return) {
|
||||
// } else if (event.text == Key.Return) {
|
||||
// touch.clicked()
|
||||
// return accept;
|
||||
}
|
||||
|
|
|
@ -88,11 +88,11 @@ export ComboBox := FocusScope {
|
|||
}
|
||||
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.UpArrow) {
|
||||
if (event.text == Key.UpArrow) {
|
||||
current-index = Math.max(current-index - 1, 0);
|
||||
current-value = model[current-index];
|
||||
return accept;
|
||||
} else if (event.text == Keys.DownArrow) {
|
||||
} else if (event.text == Key.DownArrow) {
|
||||
current-index = Math.min(current-index + 1, model.length - 1);
|
||||
current-value = model[current-index];
|
||||
return accept;
|
||||
|
|
|
@ -23,10 +23,10 @@ export StandardListView := ListView {
|
|||
|
||||
FocusScope {
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.UpArrow && current-item > 0) {
|
||||
if (event.text == Key.UpArrow && current-item > 0) {
|
||||
current-item -= 1;
|
||||
return accept;
|
||||
} else if (event.text == Keys.DownArrow && current-item + 1 < model.length) {
|
||||
} else if (event.text == Key.DownArrow && current-item + 1 < model.length) {
|
||||
current-item += 1;
|
||||
return accept;
|
||||
}
|
||||
|
|
|
@ -86,10 +86,10 @@ export Slider := Rectangle {
|
|||
width: 0px;
|
||||
|
||||
key-pressed(event) => {
|
||||
if (enabled && event.text == Keys.RightArrow) {
|
||||
if (enabled && event.text == Key.RightArrow) {
|
||||
value = Math.min(value + 1, maximum);
|
||||
accept
|
||||
} else if (enabled && event.text == Keys.LeftArrow) {
|
||||
} else if (enabled && event.text == Key.LeftArrow) {
|
||||
value = Math.max(value - 1, minimum);
|
||||
accept
|
||||
} else {
|
||||
|
|
|
@ -149,10 +149,10 @@ export SpinBox := FocusScope {
|
|||
}
|
||||
|
||||
key-pressed(event) => {
|
||||
if (enabled && event.text == Keys.UpArrow && value < maximum) {
|
||||
if (enabled && event.text == Key.UpArrow && value < maximum) {
|
||||
value += 1;
|
||||
accept
|
||||
} else if (enabled && event.text == Keys.DownArrow && value > minimum) {
|
||||
} else if (enabled && event.text == Key.DownArrow && value > minimum) {
|
||||
value -= 1;
|
||||
accept
|
||||
} else {
|
||||
|
|
|
@ -112,11 +112,11 @@ export TabBarImpl := Rectangle {
|
|||
current = current-focused;
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.LeftArrow) {
|
||||
if (event.text == Key.LeftArrow) {
|
||||
focused-tab = Math.max(focused-tab - 1, 0);
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.RightArrow) {
|
||||
if (event.text == Key.RightArrow) {
|
||||
focused-tab = Math.min(focused-tab + 1, num-tabs - 1);
|
||||
return accept;
|
||||
}
|
||||
|
|
|
@ -58,10 +58,10 @@ export Slider := NativeSlider {
|
|||
width: 0px;
|
||||
|
||||
key-pressed(event) => {
|
||||
if (root.enabled && event.text == Keys.RightArrow) {
|
||||
if (root.enabled && event.text == Key.RightArrow) {
|
||||
root.value = Math.min(root.value + 1, root.maximum);
|
||||
accept
|
||||
} else if (root.enabled && event.text == Keys.LeftArrow) {
|
||||
} else if (root.enabled && event.text == Key.LeftArrow) {
|
||||
root.value = Math.max(root.value - 1, root.minimum);
|
||||
accept
|
||||
} else {
|
||||
|
@ -127,10 +127,10 @@ export StandardListView := ListView {
|
|||
}
|
||||
FocusScope {
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.UpArrow && current-item > 0) {
|
||||
if (event.text == Key.UpArrow && current-item > 0) {
|
||||
current-item -= 1;
|
||||
accept
|
||||
} else if (event.text == Keys.DownArrow && current-item + 1 < model.length) {
|
||||
} else if (event.text == Key.DownArrow && current-item + 1 < model.length) {
|
||||
current-item += 1;
|
||||
accept
|
||||
} else {
|
||||
|
@ -180,16 +180,16 @@ export ComboBox := NativeComboBox {
|
|||
|
||||
fs := FocusScope {
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.UpArrow) {
|
||||
if (event.text == Key.UpArrow) {
|
||||
root.current-index = Math.max(root.current-index - 1, 0);
|
||||
root.current-value = model[root.current-index];
|
||||
return accept;
|
||||
} else if (event.text == Keys.DownArrow) {
|
||||
} else if (event.text == Key.DownArrow) {
|
||||
root.current-index = Math.min(root.current-index + 1, root.model.length - 1);
|
||||
root.current-value = model[root.current-index];
|
||||
return accept;
|
||||
// PopupWindow can not get hidden again at this time, so do not allow to pop that up.
|
||||
// } else if (event.text == Keys.Return) {
|
||||
// } else if (event.text == Key.Return) {
|
||||
// touch.clicked()
|
||||
// return accept;
|
||||
}
|
||||
|
@ -223,11 +223,11 @@ export TabBarImpl := Rectangle {
|
|||
fs := FocusScope {
|
||||
width: 0px; // Do not react on clicks
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.LeftArrow) {
|
||||
if (event.text == Key.LeftArrow) {
|
||||
root.current = Math.max(root.current - 1, 0);
|
||||
return accept;
|
||||
}
|
||||
if (event.text == Keys.RightArrow) {
|
||||
if (event.text == Key.RightArrow) {
|
||||
root.current = Math.min(root.current + 1, num-tabs - 1);
|
||||
return accept;
|
||||
}
|
||||
|
|
|
@ -10,8 +10,12 @@ This module contains types that are public and re-exported in the slint-rs as we
|
|||
use alloc::boxed::Box;
|
||||
|
||||
use crate::component::ComponentVTable;
|
||||
use crate::input::{KeyEventType, KeyInputEvent, MouseEvent};
|
||||
use crate::window::{WindowAdapter, WindowInner};
|
||||
|
||||
// reexport key enum to the public api
|
||||
pub use crate::input::key_codes::Key;
|
||||
|
||||
/// A position represented in the coordinate space of logical pixels. That is the space before applying
|
||||
/// a display device specific scale factor.
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq)]
|
||||
|
@ -421,7 +425,44 @@ impl Window {
|
|||
/// Any position fields in the event must be in the logical pixel coordinate system relative to
|
||||
/// the top left corner of the window.
|
||||
pub fn dispatch_event(&self, event: WindowEvent) {
|
||||
self.0.process_mouse_input(event.into())
|
||||
match event {
|
||||
WindowEvent::PointerPressed { position, button } => {
|
||||
self.0.process_mouse_input(MouseEvent::Pressed {
|
||||
position: position.to_euclid().cast(),
|
||||
button,
|
||||
});
|
||||
}
|
||||
WindowEvent::PointerReleased { position, button } => {
|
||||
self.0.process_mouse_input(MouseEvent::Released {
|
||||
position: position.to_euclid().cast(),
|
||||
button,
|
||||
});
|
||||
}
|
||||
WindowEvent::PointerMoved { position } => {
|
||||
self.0.process_mouse_input(MouseEvent::Moved {
|
||||
position: position.to_euclid().cast(),
|
||||
});
|
||||
}
|
||||
WindowEvent::PointerScrolled { position, delta_x, delta_y } => {
|
||||
self.0.process_mouse_input(MouseEvent::Wheel {
|
||||
position: position.to_euclid().cast(),
|
||||
delta_x,
|
||||
delta_y,
|
||||
});
|
||||
}
|
||||
WindowEvent::PointerExited => self.0.process_mouse_input(MouseEvent::Exit),
|
||||
|
||||
WindowEvent::KeyPressed { text } => self.0.process_key_input(KeyInputEvent {
|
||||
text: SharedString::from(text),
|
||||
event_type: KeyEventType::KeyPressed,
|
||||
..Default::default()
|
||||
}),
|
||||
WindowEvent::KeyReleased { text } => self.0.process_key_input(KeyInputEvent {
|
||||
text: SharedString::from(text),
|
||||
event_type: KeyEventType::KeyReleased,
|
||||
..Default::default()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if there is an animation currently active on any property in the Window; false otherwise.
|
||||
|
@ -438,6 +479,7 @@ impl Window {
|
|||
}
|
||||
|
||||
pub use crate::input::PointerEventButton;
|
||||
pub use crate::SharedString;
|
||||
|
||||
/// A event that describes user input.
|
||||
///
|
||||
|
@ -449,7 +491,7 @@ pub use crate::input::PointerEventButton;
|
|||
///
|
||||
/// All position fields are in logical window coordinates.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum WindowEvent {
|
||||
/// A pointer was pressed.
|
||||
|
@ -476,6 +518,30 @@ pub enum WindowEvent {
|
|||
},
|
||||
/// The pointer exited the window.
|
||||
PointerExited,
|
||||
/// A key was pressed.
|
||||
KeyPressed {
|
||||
// FIXME: use SharedString instead of char (breaking change)
|
||||
/// The unicode representation of the key pressed.
|
||||
///
|
||||
/// # Example
|
||||
/// A specific key can be mapped to a unicode by using the `Key` enum
|
||||
/// ```rust
|
||||
/// let _ = slint::WindowEvent::KeyPressed { text: slint::Key::Shift.into() };
|
||||
/// ```
|
||||
text: char,
|
||||
},
|
||||
/// A key was pressed.
|
||||
KeyReleased {
|
||||
// FIXME: use SharedString instead of char (breaking change)
|
||||
/// The unicode representation of the key released.
|
||||
/// ///
|
||||
/// # Example
|
||||
/// A specific key can be mapped to a unicode by using the `Key` enum
|
||||
/// ```rust
|
||||
/// let _ = slint::WindowEvent::KeyReleased { text: slint::Key::Shift.into() };
|
||||
/// ```
|
||||
text: char,
|
||||
},
|
||||
}
|
||||
|
||||
impl WindowEvent {
|
||||
|
@ -486,7 +552,7 @@ impl WindowEvent {
|
|||
WindowEvent::PointerReleased { position, .. } => Some(*position),
|
||||
WindowEvent::PointerMoved { position } => Some(*position),
|
||||
WindowEvent::PointerScrolled { position, .. } => Some(*position),
|
||||
WindowEvent::PointerExited => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,26 +68,6 @@ impl MouseEvent {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<crate::api::WindowEvent> for MouseEvent {
|
||||
fn from(event: crate::api::WindowEvent) -> Self {
|
||||
match event {
|
||||
crate::api::WindowEvent::PointerPressed { position, button } => {
|
||||
MouseEvent::Pressed { position: position.to_euclid().cast(), button }
|
||||
}
|
||||
crate::api::WindowEvent::PointerReleased { position, button } => {
|
||||
MouseEvent::Released { position: position.to_euclid().cast(), button }
|
||||
}
|
||||
crate::api::WindowEvent::PointerMoved { position } => {
|
||||
MouseEvent::Moved { position: position.to_euclid().cast() }
|
||||
}
|
||||
crate::api::WindowEvent::PointerScrolled { position, delta_x, delta_y } => {
|
||||
MouseEvent::Wheel { position: position.to_euclid().cast(), delta_x, delta_y }
|
||||
}
|
||||
crate::api::WindowEvent::PointerExited => MouseEvent::Exit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This value is returned by the `input_event` function of an Item
|
||||
/// to notify the run-time about how the event was handled and
|
||||
/// what the next steps are.
|
||||
|
@ -145,18 +125,87 @@ impl Default for InputEventFilterResult {
|
|||
}
|
||||
}
|
||||
|
||||
/// This module contains the constant character code used to represent the keys
|
||||
/// This module contains the constant character code used to represent the keys.
|
||||
#[allow(missing_docs, non_upper_case_globals)]
|
||||
pub mod key_codes {
|
||||
macro_rules! declare_consts_for_special_keys {
|
||||
($($char:literal # $name:ident # $($_qt:ident)|* # $($_winit:ident)|* ;)*) => {
|
||||
$(pub const $name : char = $char;)*
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
#[repr(C)]
|
||||
/// The `Key` enum is used to map a specific key by name e.g. `Key::Control` to an
|
||||
/// internal used unicode representation. The enum is convertible to [`std::char`] and [`slint::SharedString`](`crate::SharedString`).
|
||||
/// Use this with [`slint::WindowEvent`](`crate::api::WindowEvent`) to supply key events to Slint's platform abstraction.
|
||||
///
|
||||
/// ```
|
||||
/// let slint_key_code: char = slint::Key::Tab.into();
|
||||
/// assert_eq!(slint_key_code, '\t')
|
||||
/// ```
|
||||
pub enum Key {
|
||||
$($name,)*
|
||||
}
|
||||
|
||||
impl From<Key> for char {
|
||||
fn from(k: Key) -> Self {
|
||||
match k {
|
||||
$(Key::$name => $name,)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Key> for crate::SharedString {
|
||||
fn from(k: Key) -> Self {
|
||||
char::from(k).into()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
i_slint_common::for_each_special_keys!(declare_consts_for_special_keys);
|
||||
}
|
||||
|
||||
/// Internal struct to maintain the pressed/released state of the keys that
|
||||
/// map to keyboard modifiers.
|
||||
#[derive(Clone, Copy, Default, Debug)]
|
||||
pub(crate) struct InternalKeyboardModifierState {
|
||||
left_alt: bool,
|
||||
right_alt: bool,
|
||||
left_control: bool,
|
||||
right_control: bool,
|
||||
left_meta: bool,
|
||||
right_meta: bool,
|
||||
left_shift: bool,
|
||||
right_shift: bool,
|
||||
}
|
||||
|
||||
impl InternalKeyboardModifierState {
|
||||
/// Updates a flag of the modifiers if the key of the given text is pressed.
|
||||
/// Returns an updated modifier if detected; None otherwise;
|
||||
pub(crate) fn state_update(mut self, pressed: bool, text: &SharedString) -> Option<Self> {
|
||||
if let Some(key_code) = text.chars().next() {
|
||||
match key_code {
|
||||
key_codes::Alt => self.left_alt = pressed,
|
||||
key_codes::Control => self.left_control = pressed,
|
||||
key_codes::ControlR => self.right_control = pressed,
|
||||
key_codes::Shift => self.left_shift = pressed,
|
||||
key_codes::ShiftR => self.right_shift = pressed,
|
||||
key_codes::Meta => self.left_meta = pressed,
|
||||
key_codes::MetaR => self.right_meta = pressed,
|
||||
_ => return None,
|
||||
};
|
||||
// Encoded keyboard modifiers must appear as individual key events. This could
|
||||
// be relaxed by implementing a string split, but right now WindowEvent::KeyPressed
|
||||
// holds only a single char.
|
||||
debug_assert_eq!(key_code.len_utf8(), text.len());
|
||||
}
|
||||
|
||||
Some(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// KeyboardModifier provides booleans to indicate possible modifier keys
|
||||
/// on a keyboard, such as Shift, Control, etc.
|
||||
///
|
||||
|
@ -170,12 +219,23 @@ pub struct KeyboardModifiers {
|
|||
pub alt: bool,
|
||||
/// Indicates the control key on a keyboard.
|
||||
pub control: bool,
|
||||
/// Indicates the logo key on macOS and the windows key on Windows.
|
||||
/// Indicates the command key on macos.
|
||||
pub meta: bool,
|
||||
/// Indicates the shift key on a keyboard.
|
||||
pub shift: bool,
|
||||
}
|
||||
|
||||
impl From<InternalKeyboardModifierState> for KeyboardModifiers {
|
||||
fn from(internal_state: InternalKeyboardModifierState) -> Self {
|
||||
Self {
|
||||
alt: internal_state.left_alt | internal_state.right_alt,
|
||||
control: internal_state.left_control | internal_state.right_control,
|
||||
meta: internal_state.left_meta | internal_state.right_meta,
|
||||
shift: internal_state.left_shift | internal_state.right_shift,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This enum defines the different kinds of key events that can happen.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
|
@ -200,9 +260,29 @@ impl Default for KeyEventType {
|
|||
/// Represents a key event sent by the windowing system.
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[repr(C)]
|
||||
pub struct KeyInputEvent {
|
||||
/// The unicode representation of the key pressed.
|
||||
pub text: SharedString,
|
||||
|
||||
// note: this field is not exported in the .slint in the KeyEvent builtin struct
|
||||
/// Indicates whether the key was pressed or released
|
||||
pub event_type: KeyEventType,
|
||||
|
||||
/// If the event type is KeyEventType::UpdateComposition, then this field specifies
|
||||
/// the start of the selection as byte offsets within the preedit text.
|
||||
pub preedit_selection_start: usize,
|
||||
/// If the event type is KeyEventType::UpdateComposition, then this field specifies
|
||||
/// the end of the selection as byte offsets within the preedit text.
|
||||
pub preedit_selection_end: usize,
|
||||
}
|
||||
|
||||
/// Represents a key event.
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
#[repr(C)]
|
||||
pub struct KeyEvent {
|
||||
/// The keyboard modifiers active at the time of the key press event.
|
||||
pub modifiers: KeyboardModifiers,
|
||||
|
||||
/// The unicode representation of the key pressed.
|
||||
pub text: SharedString,
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#![warn(missing_docs)]
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use crate::input::{KeyEvent, KeyEventType, KeyboardModifiers, MouseEvent};
|
||||
use crate::input::{key_codes::Key, KeyEventType, KeyInputEvent, MouseEvent};
|
||||
use crate::window::WindowInner;
|
||||
use crate::Coord;
|
||||
use crate::SharedString;
|
||||
|
@ -57,33 +57,54 @@ pub extern "C" fn slint_send_mouse_click(
|
|||
);
|
||||
}
|
||||
|
||||
/// Simulate a character input event (pressed or released).
|
||||
#[no_mangle]
|
||||
pub extern "C" fn slint_send_keyboard_char(
|
||||
string: &crate::SharedString,
|
||||
pressed: bool,
|
||||
window_adapter: &crate::window::WindowAdapterRc,
|
||||
) {
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
event_type: if pressed { KeyEventType::KeyPressed } else { KeyEventType::KeyReleased },
|
||||
text: string.clone(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
/// Simulate a character input event.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn send_keyboard_string_sequence(
|
||||
sequence: &crate::SharedString,
|
||||
modifiers: KeyboardModifiers,
|
||||
window_adapter: &crate::window::WindowAdapterRc,
|
||||
) {
|
||||
for ch in sequence.chars() {
|
||||
let mut modifiers = modifiers;
|
||||
if ch.is_ascii_uppercase() {
|
||||
modifiers.shift = true;
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
event_type: KeyEventType::KeyPressed,
|
||||
text: Key::Shift.into(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
let mut buffer = [0; 6];
|
||||
let text = SharedString::from(ch.encode_utf8(&mut buffer) as &str);
|
||||
let text = SharedString::from(ch);
|
||||
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(&KeyEvent {
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
event_type: KeyEventType::KeyPressed,
|
||||
text: text.clone(),
|
||||
modifiers,
|
||||
..Default::default()
|
||||
});
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(&KeyEvent {
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
event_type: KeyEventType::KeyReleased,
|
||||
text,
|
||||
modifiers,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
if ch.is_ascii_uppercase() {
|
||||
WindowInner::from_pub(window_adapter.window()).process_key_input(KeyInputEvent {
|
||||
event_type: KeyEventType::KeyReleased,
|
||||
text: Key::Shift.into(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ use crate::api::{
|
|||
use crate::component::{ComponentRc, ComponentRef, ComponentVTable, ComponentWeak};
|
||||
use crate::graphics::Point;
|
||||
use crate::input::{
|
||||
key_codes, KeyEvent, KeyEventType, MouseEvent, MouseInputState, TextCursorBlinker,
|
||||
key_codes, InternalKeyboardModifierState, KeyEvent, KeyEventType, KeyInputEvent,
|
||||
KeyboardModifiers, MouseEvent, MouseInputState, TextCursorBlinker,
|
||||
};
|
||||
use crate::item_tree::ItemRc;
|
||||
use crate::items::{ItemRef, MouseCursor};
|
||||
|
@ -35,6 +36,17 @@ fn previous_focus_item(item: ItemRc) -> ItemRc {
|
|||
item.previous_focus_item()
|
||||
}
|
||||
|
||||
/// Transforms a `KeyInputEvent` into an `KeyEvent` with the given `KeyboardModifiers`.
|
||||
fn input_as_key_event(input: KeyInputEvent, modifiers: KeyboardModifiers) -> KeyEvent {
|
||||
KeyEvent {
|
||||
modifiers,
|
||||
text: input.text,
|
||||
event_type: input.event_type,
|
||||
preedit_selection_start: input.preedit_selection_start,
|
||||
preedit_selection_end: input.preedit_selection_end,
|
||||
}
|
||||
}
|
||||
|
||||
/// This trait represents the adaptation layer between the [`Window`] API, and the
|
||||
/// internal type from the backend that provides functionality such as device-independent pixels,
|
||||
/// window resizing, and other typically windowing system related tasks.
|
||||
|
@ -202,6 +214,7 @@ pub struct WindowInner {
|
|||
window_adapter_weak: Weak<dyn WindowAdapter>,
|
||||
component: RefCell<ComponentWeak>,
|
||||
mouse_input_state: Cell<MouseInputState>,
|
||||
modifiers: Cell<InternalKeyboardModifierState>,
|
||||
redraw_tracker: Pin<Box<PropertyTracker<WindowRedrawTracker>>>,
|
||||
/// Gets dirty when the layout restrictions, or some other property of the windows change
|
||||
window_properties_tracker: Pin<Box<PropertyTracker<WindowPropertiesTracker>>>,
|
||||
|
@ -251,6 +264,7 @@ impl WindowInner {
|
|||
window_adapter_weak,
|
||||
component: Default::default(),
|
||||
mouse_input_state: Default::default(),
|
||||
modifiers: Default::default(),
|
||||
redraw_tracker: Box::pin(redraw_tracker),
|
||||
window_properties_tracker: Box::pin(window_properties_tracker),
|
||||
focus_item: Default::default(),
|
||||
|
@ -271,6 +285,7 @@ impl WindowInner {
|
|||
self.close_popup();
|
||||
self.focus_item.replace(Default::default());
|
||||
self.mouse_input_state.replace(Default::default());
|
||||
self.modifiers.replace(Default::default());
|
||||
self.component.replace(ComponentRc::downgrade(component));
|
||||
self.window_properties_tracker.set_dirty(); // component changed, layout constraints for sure must be re-calculated
|
||||
let window_adapter = self.window_adapter();
|
||||
|
@ -370,7 +385,18 @@ impl WindowInner {
|
|||
/// Arguments:
|
||||
/// * `event`: The key event received by the windowing system.
|
||||
/// * `component`: The Slint compiled component that provides the tree of items.
|
||||
pub fn process_key_input(&self, event: &KeyEvent) {
|
||||
pub fn process_key_input(&self, event: KeyInputEvent) {
|
||||
if let Some(updated_modifier) = self
|
||||
.modifiers
|
||||
.get()
|
||||
.state_update(event.event_type == KeyEventType::KeyPressed, &event.text)
|
||||
{
|
||||
// Updates the key modifiers depending on the key code and pressed state.
|
||||
self.modifiers.set(updated_modifier);
|
||||
}
|
||||
|
||||
let event = input_as_key_event(event, self.modifiers.get().into());
|
||||
|
||||
let mut item = self.focus_item.borrow().clone().upgrade();
|
||||
while let Some(focus_item) = item {
|
||||
if !focus_item.is_visible() {
|
||||
|
@ -378,7 +404,7 @@ impl WindowInner {
|
|||
self.take_focus_item();
|
||||
} else {
|
||||
if focus_item.borrow().as_ref().key_event(
|
||||
event,
|
||||
&event,
|
||||
&self.window_adapter(),
|
||||
&focus_item,
|
||||
) == crate::input::KeyEventResult::EventAccepted
|
||||
|
@ -390,9 +416,13 @@ impl WindowInner {
|
|||
}
|
||||
|
||||
// Make Tab/Backtab handle keyboard focus
|
||||
if event.text.starts_with(key_codes::Tab) && event.event_type == KeyEventType::KeyPressed {
|
||||
if event.text.starts_with(key_codes::Tab)
|
||||
&& !event.modifiers.shift
|
||||
&& event.event_type == KeyEventType::KeyPressed
|
||||
{
|
||||
self.focus_next_item();
|
||||
} else if event.text.starts_with(key_codes::Backtab)
|
||||
} else if (event.text.starts_with(key_codes::Backtab)
|
||||
|| (event.text.starts_with(key_codes::Tab) && event.modifiers.shift))
|
||||
&& event.event_type == KeyEventType::KeyPressed
|
||||
{
|
||||
self.focus_previous_item();
|
||||
|
|
|
@ -1108,6 +1108,18 @@ pub mod testing {
|
|||
&WindowInner::from_pub(comp.window()).window_adapter(),
|
||||
);
|
||||
}
|
||||
/// Wrapper around [`i_slint_core::tests::slint_send_keyboard_char`]
|
||||
pub fn send_keyboard_char(
|
||||
comp: &super::ComponentInstance,
|
||||
string: i_slint_core::SharedString,
|
||||
pressed: bool,
|
||||
) {
|
||||
i_slint_core::tests::slint_send_keyboard_char(
|
||||
&string,
|
||||
pressed,
|
||||
&WindowInner::from_pub(comp.window()).window_adapter(),
|
||||
);
|
||||
}
|
||||
/// Wrapper around [`i_slint_core::tests::send_keyboard_string_sequence`]
|
||||
pub fn send_keyboard_string_sequence(
|
||||
comp: &super::ComponentInstance,
|
||||
|
@ -1115,7 +1127,6 @@ pub mod testing {
|
|||
) {
|
||||
i_slint_core::tests::send_keyboard_string_sequence(
|
||||
&string,
|
||||
Default::default(),
|
||||
&WindowInner::from_pub(comp.window()).window_adapter(),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,10 @@ W := Window {
|
|||
field := FocusScope {
|
||||
vertical_stretch: 1;
|
||||
key-pressed(event) => {
|
||||
if (event.text == Keys.F1) {
|
||||
if (event.text == Key.F1) {
|
||||
debug("F1");
|
||||
}
|
||||
if (event.text == Keys.PageUp) {
|
||||
if (event.text == Key.PageUp) {
|
||||
debug("PageUp");
|
||||
}
|
||||
if (event.modifiers.control) {
|
||||
|
|
|
@ -13,7 +13,9 @@ TestCase := Rectangle {
|
|||
FocusScope {
|
||||
width: 75%;
|
||||
key-pressed(event) => {
|
||||
if (event.text != Key.Shift && event.text != Key.Control) {
|
||||
received += event.text;
|
||||
}
|
||||
accept
|
||||
}
|
||||
|
||||
|
@ -39,12 +41,6 @@ TestCase := Rectangle {
|
|||
}
|
||||
|
||||
/*
|
||||
```rust
|
||||
let ctrl_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let instance = TestCase::new();
|
||||
|
||||
assert!(!instance.get_input1_focused());
|
||||
|
@ -55,7 +51,7 @@ assert_eq!(instance.get_input2_text(), "Hello");
|
|||
assert_eq!(instance.get_input1_text(), "");
|
||||
assert_eq!(instance.get_received(), "");
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, ctrl_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, "ß");
|
||||
assert_eq!(instance.get_input2_text(), "Hello");
|
||||
assert_eq!(instance.get_input1_text(), "");
|
||||
|
@ -63,9 +59,6 @@ assert_eq!(instance.get_received(), "ß");
|
|||
```
|
||||
|
||||
```cpp
|
||||
slint::cbindgen_private::KeyboardModifiers ctrl_modifier{};
|
||||
ctrl_modifier.control = true;
|
||||
|
||||
auto handle = TestCase::create();
|
||||
const TestCase &instance = *handle;
|
||||
|
||||
|
@ -77,7 +70,9 @@ assert_eq(instance.get_input2_text(), "Hello");
|
|||
assert_eq(instance.get_input1_text(), "");
|
||||
assert_eq(instance.get_received(), "");
|
||||
|
||||
slint_testing::send_keyboard_string_sequence(&instance, "ß", ctrl_modifier);
|
||||
// Control key
|
||||
slint_testing::send_keyboard_char(&instance, slint::SharedString(u8"\U00000011"), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, "ß");
|
||||
assert_eq(instance.get_input2_text(), "Hello");
|
||||
assert_eq(instance.get_input1_text(), "");
|
||||
assert_eq(instance.get_received(), "ß");
|
||||
|
|
|
@ -21,23 +21,27 @@ const RIGHT_CODE: char = '\u{F703}';
|
|||
const DEL_CODE: char = '\u{007f}';
|
||||
const BACK_CODE: char = '\u{0008}'; // backspace \b
|
||||
|
||||
let shift_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
shift: true,
|
||||
..Default::default()
|
||||
};
|
||||
fn send_move_mod_modifier(instance: &TestCase, pressed: bool) {
|
||||
if cfg!(not(target_os = "macos")) {
|
||||
slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), pressed);
|
||||
}
|
||||
|
||||
let move_mod_shift_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
shift: true,
|
||||
control: cfg!(not(target_os = "macos")),
|
||||
alt: cfg!(target_os = "macos"),
|
||||
..Default::default()
|
||||
};
|
||||
if cfg!(target_os = "macos") {
|
||||
slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Alt.into(), pressed);
|
||||
}
|
||||
}
|
||||
|
||||
let move_mod_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
control: cfg!(not(target_os = "macos")),
|
||||
alt: cfg!(target_os = "macos"),
|
||||
..Default::default()
|
||||
};
|
||||
fn send_move_mod_shift_modifier(instance: &TestCase, pressed: bool) {
|
||||
slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Shift.into(), pressed);
|
||||
|
||||
if cfg!(not(target_os = "macos")) {
|
||||
slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Control.into(), pressed);
|
||||
}
|
||||
|
||||
if cfg!(target_os = "macos") {
|
||||
slint_testing::send_keyboard_char(instance, slint::private_unstable_api::re_exports::Key::Alt.into(), pressed);
|
||||
}
|
||||
}
|
||||
|
||||
let instance = TestCase::new();
|
||||
slint_testing::send_mouse_click(&instance, 50., 50.);
|
||||
|
@ -47,9 +51,9 @@ slint_testing::send_keyboard_string_sequence(&instance, "Test");
|
|||
assert_eq!(instance.get_test_text(), "Test");
|
||||
assert!(!instance.get_has_selection());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, shift_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);
|
||||
assert!(instance.get_has_selection());
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
assert!(!instance.get_has_selection());
|
||||
|
@ -69,9 +73,9 @@ slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
|||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
assert_eq!(instance.get_test_cursor_pos(), 0);
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_shift_modifier);
|
||||
send_move_mod_shift_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &DOWN_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_shift_modifier(&instance, false);
|
||||
assert!(instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_cursor_pos(), 2);
|
||||
assert_eq!(instance.get_test_anchor_pos(), 0);
|
||||
|
@ -79,20 +83,17 @@ assert_eq!(instance.get_test_anchor_pos(), 0);
|
|||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
assert!(!instance.get_has_selection());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_shift_modifier);
|
||||
send_move_mod_shift_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &UP_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_shift_modifier(&instance, false);
|
||||
assert!(instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_cursor_pos(), 0);
|
||||
assert_eq!(instance.get_test_anchor_pos(), 1);
|
||||
|
||||
// Select all and start over
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
});
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &"a");
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
assert!(!instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_text(), "");
|
||||
|
@ -108,15 +109,15 @@ assert_eq!(instance.get_test_cursor_pos(), 22);
|
|||
|
||||
// Delete word backwards when the cursor is between the 'F' of Fifth and the leading space.
|
||||
// -> Delete "Word"
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_modifier);
|
||||
send_move_mod_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_modifier(&instance, false);
|
||||
assert_eq!(instance.get_test_text(), "First Word Third Fifth");
|
||||
|
||||
// Once more :-)
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_modifier);
|
||||
send_move_mod_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_modifier(&instance, false);
|
||||
assert_eq!(instance.get_test_text(), "First Word Fifth");
|
||||
|
||||
// Move cursor between the "d" of "Word" and the trailing space
|
||||
|
@ -128,18 +129,15 @@ slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
|||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
|
||||
// Delete word forwards
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_modifier);
|
||||
send_move_mod_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &DEL_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_modifier(&instance, false);
|
||||
assert_eq!(instance.get_test_text(), "First Fifth");
|
||||
|
||||
// Select all and start over
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
});
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &"a");
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
assert!(!instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_text(), "");
|
||||
|
@ -150,16 +148,16 @@ assert_eq!(instance.get_test_text(), "First Second");
|
|||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, shift_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);
|
||||
assert!(instance.get_has_selection());
|
||||
|
||||
// When there's an existing selection, always just delete that
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_modifier);
|
||||
send_move_mod_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_modifier(&instance, false);
|
||||
assert_eq!(instance.get_test_text(), "First Send");
|
||||
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
|
@ -168,15 +166,15 @@ slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
|||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, shift_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);
|
||||
assert!(instance.get_has_selection());
|
||||
|
||||
// When there's an existing selection, always just delete that
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, move_mod_modifier);
|
||||
send_move_mod_modifier(&instance, true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &DEL_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
send_move_mod_modifier(&instance, false);
|
||||
assert_eq!(instance.get_test_text(), "Fist Send");
|
||||
```
|
||||
*/
|
||||
|
|
|
@ -17,11 +17,6 @@ TestCase := TextInput {
|
|||
const LEFT_CODE: char = '\u{F702}';
|
||||
const BACK_CODE: char = '\u{0008}'; // backspace \b
|
||||
|
||||
let shift_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
shift: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let instance = TestCase::new();
|
||||
slint_testing::send_mouse_click(&instance, 50., 50.);
|
||||
assert!(instance.get_input_focused());
|
||||
|
@ -31,9 +26,9 @@ assert_eq!(instance.get_test_text(), "e\u{0301}");
|
|||
assert!(!instance.get_has_selection());
|
||||
|
||||
// Test that selecting the grapheme works
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, shift_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);
|
||||
assert!(instance.get_has_selection());
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &BACK_CODE.to_string());
|
||||
|
||||
|
|
|
@ -16,16 +16,6 @@ TestCase := TextInput {
|
|||
|
||||
const LEFT_CODE: char = '\u{F702}';
|
||||
|
||||
let shift_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
shift: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let control_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let instance = TestCase::new();
|
||||
slint_testing::send_mouse_click(&instance, 50., 50.);
|
||||
assert!(instance.get_input_focused());
|
||||
|
@ -34,14 +24,16 @@ slint_testing::send_keyboard_string_sequence(&instance, "Test");
|
|||
assert_eq!(instance.get_test_text(), "Test");
|
||||
assert!(!instance.get_has_selection());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, control_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, "a");
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, shift_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, control_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), false);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, "x");
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), false);
|
||||
assert!(!instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_text(), "st");
|
||||
assert_eq!(instance.get_test_cursor_pos(), 0);
|
||||
|
|
186
tests/cases/text/keyboard_modifiers.slint
Normal file
186
tests/cases/text/keyboard_modifiers.slint
Normal file
|
@ -0,0 +1,186 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint-ui.com>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial
|
||||
|
||||
TestCase := Window {
|
||||
width: 100phx;
|
||||
height: 100phx;
|
||||
ti := FocusScope {
|
||||
key-pressed(event) => {
|
||||
debug("pressy");
|
||||
debug(event.modifiers.shift);
|
||||
shift_modifier = event.modifiers.shift;
|
||||
alt_modifier = event.modifiers.alt;
|
||||
control_modifier = event.modifiers.control;
|
||||
meta_modifier = event.modifiers.meta;
|
||||
accept;
|
||||
}
|
||||
key-released(event) => {
|
||||
shift_modifier = event.modifiers.shift;
|
||||
alt_modifier = event.modifiers.alt;
|
||||
control_modifier = event.modifiers.control;
|
||||
meta_modifier = event.modifiers.meta;
|
||||
accept;
|
||||
}
|
||||
}
|
||||
|
||||
property <bool> input_focused: ti.has_focus;
|
||||
property <bool> shift_modifier;
|
||||
property <bool> alt_modifier;
|
||||
property <bool> control_modifier;
|
||||
property <bool> meta_modifier;
|
||||
}
|
||||
|
||||
/*
|
||||
```rust
|
||||
|
||||
const SHIFT_CODE: char = '\u{0010}';
|
||||
const SHIFTR_CODE: char = '\u{0015}';
|
||||
const ALT_CODE: char = '\u{0012}';
|
||||
const ALTGR_CODE: char = '\u{0013}';
|
||||
const CONTROL_CODE: char = '\u{0011}';
|
||||
const CONTROLR_CODE: char = '\u{0016}';
|
||||
const META_CODE: char = '\u{00E0}';
|
||||
const METAR_CODE: char = '\u{00E1}';
|
||||
|
||||
let instance = TestCase::new();
|
||||
slint_testing::send_mouse_click(&instance, 5., 5.);
|
||||
assert!(instance.get_input_focused());
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, SHIFT_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), true);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, SHIFTR_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), true);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, SHIFT_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), true);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, SHIFTR_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, ALT_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), true);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, ALTGR_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), true);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
// AltGr does not set the alt modifier
|
||||
slint_testing::send_keyboard_char(&instance, ALT_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, ALTGR_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, CONTROL_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), true);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, CONTROLR_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), true);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, CONTROL_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), true);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, CONTROLR_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, META_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), true);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, METAR_CODE, true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), true);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, META_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), true);
|
||||
|
||||
slint_testing::send_keyboard_char(&instance, METAR_CODE, false);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', true);
|
||||
slint_testing::send_keyboard_char(&instance, 'a', false);
|
||||
assert_eq!(instance.get_shift_modifier(), false);
|
||||
assert_eq!(instance.get_alt_modifier(), false);
|
||||
assert_eq!(instance.get_control_modifier(), false);
|
||||
assert_eq!(instance.get_meta_modifier(), false);
|
||||
|
||||
```
|
||||
*/
|
|
@ -14,12 +14,6 @@ TestCase := TextInput {
|
|||
/*
|
||||
```rust
|
||||
|
||||
|
||||
let control_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
control: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let instance = TestCase::new();
|
||||
slint_testing::send_mouse_click(&instance, 50., 50.);
|
||||
assert!(instance.get_input_focused());
|
||||
|
@ -28,9 +22,9 @@ slint_testing::send_keyboard_string_sequence(&instance, "Test");
|
|||
assert_eq!(instance.get_test_text(), "Test");
|
||||
assert!(!instance.get_has_selection());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, control_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, "a");
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, slint::private_unstable_api::re_exports::KeyboardModifiers::default());
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Control.into(), true);
|
||||
assert!(instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_cursor_pos(), 4);
|
||||
assert_eq!(instance.get_test_anchor_pos(), 0);
|
||||
|
|
|
@ -17,11 +17,6 @@ TestCase := TextInput {
|
|||
const LEFT_CODE: char = '\u{F702}';
|
||||
const BACK_CODE: char = '\u{0008}'; // backspace \b
|
||||
|
||||
let shift_modifier = slint::private_unstable_api::re_exports::KeyboardModifiers {
|
||||
shift: true,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let instance = TestCase::new();
|
||||
slint_testing::send_mouse_click(&instance, 50., 50.);
|
||||
assert!(instance.get_input_focused());
|
||||
|
@ -30,7 +25,7 @@ slint_testing::send_keyboard_string_sequence(&instance, "😍");
|
|||
assert_eq!(instance.get_test_text(), "😍");
|
||||
assert!(!instance.get_has_selection());
|
||||
|
||||
slint_testing::set_current_keyboard_modifiers(&instance, shift_modifier);
|
||||
slint_testing::send_keyboard_char(&instance, slint::private_unstable_api::re_exports::Key::Shift.into(), true);
|
||||
slint_testing::send_keyboard_string_sequence(&instance, &LEFT_CODE.to_string());
|
||||
assert!(instance.get_has_selection());
|
||||
assert_eq!(instance.get_test_cursor_pos(), 0);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue