1use std::{collections::HashSet, time::Duration};
4
5use zng_app::{
6 AppExtension, DInstant, HeadlessApp,
7 event::{event, event_args},
8 shortcut::ModifiersState,
9 update::EventUpdate,
10 view_process::{
11 VIEW_PROCESS_INITED_EVENT,
12 raw_device_events::DeviceId,
13 raw_events::{
14 RAW_ANIMATIONS_CONFIG_CHANGED_EVENT, RAW_KEY_INPUT_EVENT, RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT, RAW_WINDOW_FOCUS_EVENT,
15 RawKeyInputArgs,
16 },
17 },
18 widget::{WidgetId, info::InteractionPath},
19 window::WindowId,
20};
21use zng_app_context::app_local;
22use zng_clone_move::clmv;
23use zng_ext_window::WINDOWS;
24use zng_layout::unit::{Factor, FactorUnits};
25use zng_txt::Txt;
26use zng_var::{ArcVar, ReadOnlyArcVar, Var, types::ArcCowVar, var, var_default};
27use zng_view_api::config::AnimationsConfig;
28pub use zng_view_api::{
29 config::KeyRepeatConfig,
30 keyboard::{Key, KeyCode, KeyLocation, KeyState, NativeKeyCode},
31};
32
33use crate::focus::FOCUS;
34
35event_args! {
36 pub struct KeyInputArgs {
38 pub window_id: WindowId,
40
41 pub device_id: DeviceId,
43
44 pub key_code: KeyCode,
46
47 pub key_location: KeyLocation,
49
50 pub state: KeyState,
52
53 pub key: Key,
57 pub key_modified: Key,
61
62 pub text: Txt,
70
71 pub modifiers: ModifiersState,
73
74 pub repeat_count: u32,
78
79 pub target: InteractionPath,
81
82 ..
83
84 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
86 list.insert_wgt(&self.target)
87 }
88 }
89
90 pub struct ModifiersChangedArgs {
92 pub prev_modifiers: ModifiersState,
94
95 pub modifiers: ModifiersState,
97
98 ..
99
100 fn delivery_list(&self, list: &mut UpdateDeliveryList) {
102 list.search_all()
103 }
104 }
105}
106impl KeyInputArgs {
107 pub fn is_enabled(&self, widget_id: WidgetId) -> bool {
111 self.target.interactivity_of(widget_id).map(|i| i.is_enabled()).unwrap_or(false)
112 }
113
114 pub fn is_disabled(&self, widget_id: WidgetId) -> bool {
118 self.target.interactivity_of(widget_id).map(|i| i.is_disabled()).unwrap_or(false)
119 }
120
121 pub fn shortcut_key(&self) -> &Key {
123 if matches!(self.key_location, KeyLocation::Numpad) {
124 &self.key_modified
125 } else {
126 &self.key
127 }
128 }
129}
130
131impl KeyInputArgs {
138 pub fn is_backspace(&self) -> bool {
140 !self.modifiers.contains(ModifiersState::CTRL) && self.text.contains('\u{8}')
141 }
142
143 pub fn is_delete(&self) -> bool {
145 !self.modifiers.contains(ModifiersState::CTRL) && self.text.contains('\u{7F}')
146 }
147
148 pub fn is_tab(&self) -> bool {
150 !self.modifiers.contains(ModifiersState::CTRL) && self.text.chars().any(|c| "\t\u{B}\u{1F}".contains(c))
151 }
152
153 pub fn is_line_break(&self) -> bool {
155 !self.modifiers.contains(ModifiersState::CTRL) && self.text.chars().any(|c| "\r\n\u{85}".contains(c))
156 }
157
158 pub fn insert_str(&self) -> &str {
166 if self.modifiers.contains(ModifiersState::CTRL) {
167 ""
169 } else if self.is_tab() {
170 "\t"
171 } else if self.is_line_break() {
172 "\n"
173 } else if self.text.chars().any(|c| c.is_ascii_control()) {
174 ""
175 } else {
176 &self.text
177 }
178 }
179}
180
181event! {
182 pub static KEY_INPUT_EVENT: KeyInputArgs;
188
189 pub static MODIFIERS_CHANGED_EVENT: ModifiersChangedArgs;
195}
196
197#[derive(Default)]
223pub struct KeyboardManager {}
224impl AppExtension for KeyboardManager {
225 fn event_preview(&mut self, update: &mut EventUpdate) {
226 if let Some(args) = RAW_KEY_INPUT_EVENT.on(update) {
227 let focused = FOCUS.focused().get();
228 KEYBOARD_SV.write().key_input(args, focused);
229 } else if let Some(args) = RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT.on(update) {
230 let mut kb = KEYBOARD_SV.write();
231 kb.repeat_config.set(args.config);
232 kb.last_key_down = None;
233 } else if let Some(args) = RAW_ANIMATIONS_CONFIG_CHANGED_EVENT.on(update) {
234 let kb = KEYBOARD_SV.read();
235 kb.caret_animation_config
236 .set((args.config.caret_blink_interval, args.config.caret_blink_timeout));
237 } else if let Some(args) = RAW_WINDOW_FOCUS_EVENT.on(update) {
238 if args.new_focus.is_none() {
239 let mut kb = KEYBOARD_SV.write();
240 kb.clear_modifiers();
241 kb.codes.set(vec![]);
242 kb.keys.set(vec![]);
243
244 kb.last_key_down = None;
245 }
246 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update) {
247 let mut kb = KEYBOARD_SV.write();
248 kb.repeat_config.set(args.key_repeat_config);
249 kb.caret_animation_config.set((
250 args.animations_config.caret_blink_interval,
251 args.animations_config.caret_blink_timeout,
252 ));
253
254 if args.is_respawn {
255 kb.clear_modifiers();
256 kb.codes.set(vec![]);
257 kb.keys.set(vec![]);
258
259 kb.last_key_down = None;
260 }
261 }
262 }
263}
264
265pub struct KEYBOARD;
271impl KEYBOARD {
272 pub fn modifiers(&self) -> ReadOnlyArcVar<ModifiersState> {
274 KEYBOARD_SV.read().modifiers.read_only()
275 }
276
277 pub fn codes(&self) -> ReadOnlyArcVar<Vec<KeyCode>> {
279 KEYBOARD_SV.read().codes.read_only()
280 }
281
282 pub fn keys(&self) -> ReadOnlyArcVar<Vec<Key>> {
284 KEYBOARD_SV.read().keys.read_only()
285 }
286
287 pub fn repeat_config(&self) -> ArcCowVar<KeyRepeatConfig, ArcVar<KeyRepeatConfig>> {
297 KEYBOARD_SV.read().repeat_config.clone()
298 }
299
300 pub fn sys_repeat_config(&self) -> ReadOnlyArcVar<KeyRepeatConfig> {
304 KEYBOARD_SV.read().sys_repeat_config.read_only()
305 }
306
307 pub fn caret_animation_config(&self) -> ArcCowVar<(Duration, Duration), ArcVar<(Duration, Duration)>> {
319 KEYBOARD_SV.read().caret_animation_config.clone()
320 }
321
322 pub fn sys_caret_animation_config(&self) -> ReadOnlyArcVar<(Duration, Duration)> {
326 KEYBOARD_SV.read().sys_caret_animation_config.read_only()
327 }
328
329 pub fn caret_animation(&self) -> ReadOnlyArcVar<Factor> {
336 KEYBOARD_SV.read().caret_animation()
337 }
338}
339
340app_local! {
341 static KEYBOARD_SV: KeyboardService = {
342 let sys_repeat_config = var_default();
343 let cfg = AnimationsConfig::default();
344 let sys_caret_animation_config = var((cfg.caret_blink_interval, cfg.caret_blink_timeout));
345 KeyboardService {
346 current_modifiers: HashSet::default(),
347 modifiers: var(ModifiersState::empty()),
348 codes: var(vec![]),
349 keys: var(vec![]),
350 repeat_config: sys_repeat_config.cow(),
351 sys_repeat_config,
352 caret_animation_config: sys_caret_animation_config.cow(),
353 sys_caret_animation_config,
354 last_key_down: None,
355 }
356 };
357}
358
359struct KeyboardService {
360 current_modifiers: HashSet<Key>,
361
362 modifiers: ArcVar<ModifiersState>,
363 codes: ArcVar<Vec<KeyCode>>,
364 keys: ArcVar<Vec<Key>>,
365 repeat_config: ArcCowVar<KeyRepeatConfig, ArcVar<KeyRepeatConfig>>,
366 sys_repeat_config: ArcVar<KeyRepeatConfig>,
367 caret_animation_config: ArcCowVar<(Duration, Duration), ArcVar<(Duration, Duration)>>,
368 sys_caret_animation_config: ArcVar<(Duration, Duration)>,
369
370 last_key_down: Option<(DeviceId, KeyCode, DInstant, u32)>,
371}
372impl KeyboardService {
373 fn key_input(&mut self, args: &RawKeyInputArgs, focused: Option<InteractionPath>) {
374 let mut repeat = 0;
375
376 match args.state {
378 KeyState::Pressed => {
379 if let Some((d_id, code, time, count)) = &mut self.last_key_down {
380 let max_t = self.repeat_config.get().start_delay * 2;
381 if args.key_code == *code && args.device_id == *d_id && (args.timestamp - *time) < max_t {
382 *count = (*count).saturating_add(1);
383 repeat = *count;
384 } else {
385 *d_id = args.device_id;
386 *code = args.key_code;
387 *count = 0;
388 }
389 *time = args.timestamp;
390 } else {
391 self.last_key_down = Some((args.device_id, args.key_code, args.timestamp, 0));
392 }
393
394 let key_code = args.key_code;
395 if !self.codes.with(|c| c.contains(&key_code)) {
396 self.codes.modify(move |cs| {
397 cs.to_mut().push(key_code);
398 });
399 }
400
401 let key = &args.key;
402 if !matches!(&key, Key::Unidentified) {
403 if !self.keys.with(|c| c.contains(key)) {
404 self.keys.modify(clmv!(key, |ks| {
405 ks.to_mut().push(key);
406 }));
407 }
408
409 if key.is_modifier() {
410 self.set_modifiers(key.clone(), true);
411 }
412 }
413 }
414 KeyState::Released => {
415 self.last_key_down = None;
416
417 let key = args.key_code;
418 if self.codes.with(|c| c.contains(&key)) {
419 self.codes.modify(move |cs| {
420 if let Some(i) = cs.as_ref().iter().position(|c| *c == key) {
421 cs.to_mut().swap_remove(i);
422 }
423 });
424 }
425
426 let key = &args.key;
427 if !matches!(&key, Key::Unidentified) {
428 if self.keys.with(|c| c.contains(key)) {
429 self.keys.modify(clmv!(key, |ks| {
430 if let Some(i) = ks.as_ref().iter().position(|k| k == &key) {
431 ks.to_mut().swap_remove(i);
432 }
433 }));
434 }
435
436 if key.is_modifier() {
437 self.set_modifiers(key.clone(), false);
438 }
439 }
440 }
441 }
442
443 if let Some(target) = focused {
445 if target.window_id() == args.window_id || WINDOWS.nest_parent(target.window_id()).map(|(p, _)| p) == Some(args.window_id) {
446 let args = KeyInputArgs::now(
447 target.window_id(),
448 args.device_id,
449 args.key_code,
450 args.key_location,
451 args.state,
452 args.key.clone(),
453 args.key_modified.clone(),
454 args.text.clone(),
455 self.current_modifiers(),
456 repeat,
457 target,
458 );
459 KEY_INPUT_EVENT.notify(args);
460 }
461 }
462 }
463 fn set_modifiers(&mut self, key: Key, pressed: bool) {
464 let prev_modifiers = self.current_modifiers();
465
466 if pressed {
467 self.current_modifiers.insert(key);
468 } else {
469 self.current_modifiers.remove(&key);
470 }
471
472 let new_modifiers = self.current_modifiers();
473
474 if prev_modifiers != new_modifiers {
475 self.modifiers.set(new_modifiers);
476 MODIFIERS_CHANGED_EVENT.notify(ModifiersChangedArgs::now(prev_modifiers, new_modifiers));
477 }
478 }
479
480 fn clear_modifiers(&mut self) {
481 let prev_modifiers = self.current_modifiers();
482 self.current_modifiers.clear();
483 let new_modifiers = self.current_modifiers();
484
485 if prev_modifiers != new_modifiers {
486 self.modifiers.set(new_modifiers);
487 MODIFIERS_CHANGED_EVENT.notify(ModifiersChangedArgs::now(prev_modifiers, new_modifiers));
488 }
489 }
490
491 fn current_modifiers(&self) -> ModifiersState {
492 let mut state = ModifiersState::empty();
493 for key in &self.current_modifiers {
494 state |= ModifiersState::from_key(key.clone());
495 }
496 state
497 }
498
499 fn caret_animation(&self) -> ReadOnlyArcVar<Factor> {
500 let var = var(1.fct());
501 let cfg = self.caret_animation_config.clone();
502
503 let zero = 0.fct();
504 let one = 1.fct();
505 let mut init = true;
506
507 var.animate(move |anim, vm| {
508 let (interval, timeout) = cfg.get();
509 if anim.start_time().elapsed() >= timeout || interval == Duration::MAX {
510 if **vm != one {
511 vm.set(one);
512 }
513 anim.stop();
514 } else {
515 if **vm == one {
516 if !std::mem::take(&mut init) {
517 vm.set(zero);
518 }
519 } else {
520 vm.set(one);
521 }
522 anim.sleep(interval);
523 }
524 })
525 .perm();
526
527 var.read_only()
528 }
529}
530
531pub trait HeadlessAppKeyboardExt {
535 fn on_keyboard_input(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key, state: KeyState);
539
540 fn press_key(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key);
542
543 fn press_modified_key(&mut self, window_id: WindowId, modifiers: ModifiersState, code: KeyCode, location: KeyLocation, key: Key);
545}
546impl HeadlessAppKeyboardExt for HeadlessApp {
547 fn on_keyboard_input(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key, state: KeyState) {
548 use zng_app::view_process::raw_events::*;
549
550 let args = RawKeyInputArgs::now(window_id, DeviceId::virtual_keyboard(), code, location, state, key.clone(), key, "");
551 RAW_KEY_INPUT_EVENT.notify(args);
552 }
553
554 fn press_key(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key) {
555 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
556 self.on_keyboard_input(window_id, code, location, key, KeyState::Released);
557 let _ = self.update(false);
558 }
559
560 fn press_modified_key(&mut self, window_id: WindowId, modifiers: ModifiersState, code: KeyCode, location: KeyLocation, key: Key) {
561 if modifiers.is_empty() {
562 self.press_key(window_id, code, location, key);
563 } else {
564 let modifiers = modifiers.keys();
565 for key in &modifiers {
566 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
567 }
568
569 let _ = self.update(false);
571
572 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
573 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Released);
574
575 let _ = self.update(false);
577
578 for key in modifiers {
579 self.on_keyboard_input(window_id, code, location, key, KeyState::Released);
580 }
581
582 let _ = self.update(false);
584 }
585 }
586}