1use std::{collections::HashSet, time::Duration};
4
5use zng_app::{
6 APP, AppExtension, DInstant, HeadlessApp,
7 event::{event, event_args},
8 shortcut::{GestureKey, KeyGesture, ModifierGesture, ModifiersState, Shortcut},
9 update::EventUpdate,
10 view_process::{
11 VIEW_PROCESS_INITED_EVENT,
12 raw_device_events::InputDeviceId,
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::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::{Var, 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: InputDeviceId,
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 {
108 pub fn shortcut_key(&self) -> &Key {
110 if matches!(self.key_location, KeyLocation::Numpad) {
111 &self.key_modified
112 } else {
113 &self.key
114 }
115 }
116
117 pub fn editing_shortcut(&self) -> Option<Shortcut> {
128 if matches!(self.state, KeyState::Released) {
129 return None;
130 }
131
132 let source_key = self.shortcut_key();
133 if let Ok(modifier) = ModifierGesture::try_from(source_key)
134 && (self.modifiers.is_empty() || self.modifiers == modifier.modifiers_state())
135 {
136 return Some(Shortcut::Modifier(modifier));
137 }
138 let key = match source_key {
139 Key::Unidentified => GestureKey::try_from(self.key_code).unwrap_or(GestureKey::Key(Key::Unidentified)),
140 key => GestureKey::try_from(key.clone()).unwrap_or(GestureKey::Key(Key::Unidentified)),
141 };
142 Some(Shortcut::Gesture(KeyGesture {
143 modifiers: self.modifiers,
144 key,
145 }))
146 }
147}
148
149impl KeyInputArgs {
156 pub fn is_backspace(&self) -> bool {
158 !self.modifiers.contains(ModifiersState::CTRL) && self.text.contains('\u{8}')
159 }
160
161 pub fn is_delete(&self) -> bool {
163 !self.modifiers.contains(ModifiersState::CTRL) && self.text.contains('\u{7F}')
164 }
165
166 pub fn is_tab(&self) -> bool {
168 !self.modifiers.contains(ModifiersState::CTRL) && self.text.chars().any(|c| "\t\u{B}\u{1F}".contains(c))
169 }
170
171 pub fn is_line_break(&self) -> bool {
173 !self.modifiers.contains(ModifiersState::CTRL) && self.text.chars().any(|c| "\r\n\u{85}".contains(c))
174 }
175
176 pub fn insert_str(&self) -> &str {
184 if self.modifiers.contains(ModifiersState::CTRL) {
185 ""
187 } else if self.is_tab() {
188 "\t"
189 } else if self.is_line_break() {
190 "\n"
191 } else if self.text.chars().any(|c| c.is_ascii_control()) {
192 ""
193 } else {
194 &self.text
195 }
196 }
197}
198
199event! {
200 pub static KEY_INPUT_EVENT: KeyInputArgs;
206
207 pub static MODIFIERS_CHANGED_EVENT: ModifiersChangedArgs;
213}
214
215#[derive(Default)]
241pub struct KeyboardManager {}
242impl AppExtension for KeyboardManager {
243 fn event_preview(&mut self, update: &mut EventUpdate) {
244 if let Some(args) = RAW_KEY_INPUT_EVENT.on(update) {
245 let focused = FOCUS.focused().get();
246 KEYBOARD_SV.write().key_input(args, focused);
247 } else if let Some(args) = RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT.on(update) {
248 let mut kb = KEYBOARD_SV.write();
249 kb.repeat_config.set(args.config);
250 kb.last_key_down = None;
251 } else if let Some(args) = RAW_ANIMATIONS_CONFIG_CHANGED_EVENT.on(update) {
252 let kb = KEYBOARD_SV.read();
253 kb.caret_animation_config
254 .set((args.config.caret_blink_interval, args.config.caret_blink_timeout));
255 } else if let Some(args) = RAW_WINDOW_FOCUS_EVENT.on(update) {
256 if args.new_focus.is_none() {
257 let mut kb = KEYBOARD_SV.write();
258 kb.clear_modifiers();
259 kb.codes.set(vec![]);
260 kb.keys.set(vec![]);
261
262 kb.last_key_down = None;
263 }
264 } else if let Some(args) = VIEW_PROCESS_INITED_EVENT.on(update) {
265 let mut kb = KEYBOARD_SV.write();
266
267 if args.is_respawn {
268 kb.clear_modifiers();
269 kb.codes.set(vec![]);
270 kb.keys.set(vec![]);
271
272 kb.last_key_down = None;
273 }
274 }
275 }
276}
277
278pub struct KEYBOARD;
284impl KEYBOARD {
285 pub fn modifiers(&self) -> Var<ModifiersState> {
287 KEYBOARD_SV.read().modifiers.read_only()
288 }
289
290 pub fn codes(&self) -> Var<Vec<KeyCode>> {
292 KEYBOARD_SV.read().codes.read_only()
293 }
294
295 pub fn keys(&self) -> Var<Vec<Key>> {
297 KEYBOARD_SV.read().keys.read_only()
298 }
299
300 pub fn repeat_config(&self) -> Var<KeyRepeatConfig> {
310 KEYBOARD_SV.read().repeat_config.clone()
311 }
312
313 pub fn sys_repeat_config(&self) -> Var<KeyRepeatConfig> {
317 KEYBOARD_SV.read().sys_repeat_config.read_only()
318 }
319
320 pub fn caret_animation_config(&self) -> Var<(Duration, Duration)> {
332 KEYBOARD_SV.read().caret_animation_config.clone()
333 }
334
335 pub fn sys_caret_animation_config(&self) -> Var<(Duration, Duration)> {
339 KEYBOARD_SV.read().sys_caret_animation_config.read_only()
340 }
341
342 pub fn caret_animation(&self) -> Var<Factor> {
349 KEYBOARD_SV.read().caret_animation()
350 }
351}
352
353app_local! {
354 static KEYBOARD_SV: KeyboardService = {
355 APP.extensions().require::<KeyboardManager>();
356 let sys_repeat_config = var_default();
357 let cfg = AnimationsConfig::default();
358 let sys_caret_animation_config = var((cfg.caret_blink_interval, cfg.caret_blink_timeout));
359 KeyboardService {
360 current_modifiers: HashSet::default(),
361 modifiers: var(ModifiersState::empty()),
362 codes: var(vec![]),
363 keys: var(vec![]),
364 repeat_config: sys_repeat_config.cow(),
365 sys_repeat_config,
366 caret_animation_config: sys_caret_animation_config.cow(),
367 sys_caret_animation_config,
368 last_key_down: None,
369 }
370 };
371}
372
373struct KeyboardService {
374 current_modifiers: HashSet<Key>,
375
376 modifiers: Var<ModifiersState>,
377 codes: Var<Vec<KeyCode>>,
378 keys: Var<Vec<Key>>,
379 repeat_config: Var<KeyRepeatConfig>,
380 sys_repeat_config: Var<KeyRepeatConfig>,
381 caret_animation_config: Var<(Duration, Duration)>,
382 sys_caret_animation_config: Var<(Duration, Duration)>,
383
384 last_key_down: Option<(InputDeviceId, KeyCode, DInstant, u32)>,
385}
386impl KeyboardService {
387 fn key_input(&mut self, args: &RawKeyInputArgs, focused: Option<InteractionPath>) {
388 let mut repeat = 0;
389
390 match args.state {
392 KeyState::Pressed => {
393 if let Some((d_id, code, time, count)) = &mut self.last_key_down {
394 let max_t = self.repeat_config.get().start_delay * 2;
395 if args.key_code == *code && args.device_id == *d_id && (args.timestamp - *time) < max_t {
396 *count = (*count).saturating_add(1);
397 repeat = *count;
398 } else {
399 *d_id = args.device_id;
400 *code = args.key_code;
401 *count = 0;
402 }
403 *time = args.timestamp;
404 } else {
405 self.last_key_down = Some((args.device_id, args.key_code, args.timestamp, 0));
406 }
407
408 let key_code = args.key_code;
409 if !self.codes.with(|c| c.contains(&key_code)) {
410 self.codes.modify(move |cs| {
411 cs.push(key_code);
412 });
413 }
414
415 let key = &args.key;
416 if !matches!(&key, Key::Unidentified) {
417 if !self.keys.with(|c| c.contains(key)) {
418 self.keys.modify(clmv!(key, |ks| {
419 ks.push(key);
420 }));
421 }
422
423 if key.is_modifier() {
424 self.set_modifiers(key.clone(), true);
425 }
426 }
427 }
428 KeyState::Released => {
429 self.last_key_down = None;
430
431 let key = args.key_code;
432 if self.codes.with(|c| c.contains(&key)) {
433 self.codes.modify(move |cs| {
434 if let Some(i) = cs.iter().position(|c| *c == key) {
435 cs.swap_remove(i);
436 }
437 });
438 }
439
440 let key = &args.key;
441 if !matches!(&key, Key::Unidentified) {
442 if self.keys.with(|c| c.contains(key)) {
443 self.keys.modify(clmv!(key, |ks| {
444 if let Some(i) = ks.iter().position(|k| k == &key) {
445 ks.swap_remove(i);
446 }
447 }));
448 }
449
450 if key.is_modifier() {
451 self.set_modifiers(key.clone(), false);
452 }
453 }
454 }
455 }
456
457 if let Some(target) = focused
459 && (target.window_id() == args.window_id || WINDOWS.nest_parent(target.window_id()).map(|(p, _)| p) == Some(args.window_id))
460 {
461 let args = KeyInputArgs::now(
462 target.window_id(),
463 args.device_id,
464 args.key_code,
465 args.key_location,
466 args.state,
467 args.key.clone(),
468 args.key_modified.clone(),
469 args.text.clone(),
470 self.current_modifiers(),
471 repeat,
472 target,
473 );
474 KEY_INPUT_EVENT.notify(args);
475 }
476 }
477 fn set_modifiers(&mut self, key: Key, pressed: bool) {
478 let prev_modifiers = self.current_modifiers();
479
480 if pressed {
481 self.current_modifiers.insert(key);
482 } else {
483 self.current_modifiers.remove(&key);
484 }
485
486 let new_modifiers = self.current_modifiers();
487
488 if prev_modifiers != new_modifiers {
489 self.modifiers.set(new_modifiers);
490 MODIFIERS_CHANGED_EVENT.notify(ModifiersChangedArgs::now(prev_modifiers, new_modifiers));
491 }
492 }
493
494 fn clear_modifiers(&mut self) {
495 let prev_modifiers = self.current_modifiers();
496 self.current_modifiers.clear();
497 let new_modifiers = self.current_modifiers();
498
499 if prev_modifiers != new_modifiers {
500 self.modifiers.set(new_modifiers);
501 MODIFIERS_CHANGED_EVENT.notify(ModifiersChangedArgs::now(prev_modifiers, new_modifiers));
502 }
503 }
504
505 fn current_modifiers(&self) -> ModifiersState {
506 let mut state = ModifiersState::empty();
507 for key in &self.current_modifiers {
508 state |= ModifiersState::from_key(key.clone());
509 }
510 state
511 }
512
513 fn caret_animation(&self) -> Var<Factor> {
514 let var = var(1.fct());
515 let cfg = self.caret_animation_config.clone();
516
517 let zero = 0.fct();
518 let one = 1.fct();
519 let mut init = true;
520
521 var.animate(move |anim, vm| {
522 let (interval, timeout) = cfg.get();
523 if anim.start_time().elapsed() >= timeout || interval == Duration::MAX {
524 if **vm != one {
525 vm.set(one);
526 }
527 anim.stop();
528 } else {
529 if **vm == one {
530 if !std::mem::take(&mut init) {
531 vm.set(zero);
532 }
533 } else {
534 vm.set(one);
535 }
536 anim.sleep(interval);
537 }
538 })
539 .perm();
540
541 var.read_only()
542 }
543}
544
545pub trait HeadlessAppKeyboardExt {
549 fn on_keyboard_input(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key, state: KeyState);
553
554 fn press_key(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key);
556
557 fn press_modified_key(&mut self, window_id: WindowId, modifiers: ModifiersState, code: KeyCode, location: KeyLocation, key: Key);
559}
560impl HeadlessAppKeyboardExt for HeadlessApp {
561 fn on_keyboard_input(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key, state: KeyState) {
562 use zng_app::view_process::raw_events::*;
563
564 let args = RawKeyInputArgs::now(
565 window_id,
566 InputDeviceId::virtual_keyboard(),
567 code,
568 location,
569 state,
570 key.clone(),
571 key,
572 "",
573 );
574 RAW_KEY_INPUT_EVENT.notify(args);
575 }
576
577 fn press_key(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key) {
578 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
579 self.on_keyboard_input(window_id, code, location, key, KeyState::Released);
580 let _ = self.update(false);
581 }
582
583 fn press_modified_key(&mut self, window_id: WindowId, modifiers: ModifiersState, code: KeyCode, location: KeyLocation, key: Key) {
584 if modifiers.is_empty() {
585 self.press_key(window_id, code, location, key);
586 } else {
587 let modifiers = modifiers.keys();
588 for key in &modifiers {
589 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
590 }
591
592 let _ = self.update(false);
594
595 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
596 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Released);
597
598 let _ = self.update(false);
600
601 for key in modifiers {
602 self.on_keyboard_input(window_id, code, location, key, KeyState::Released);
603 }
604
605 let _ = self.update(false);
607 }
608 }
609}