1use std::{collections::HashSet, time::Duration};
20
21use zng_app::{
22 DInstant, HeadlessApp,
23 event::{event, event_args},
24 shortcut::{GestureKey, KeyGesture, ModifierGesture, ModifiersState, Shortcut},
25 view_process::{
26 VIEW_PROCESS_INITED_EVENT,
27 raw_device_events::InputDeviceId,
28 raw_events::{
29 RAW_ANIMATIONS_CONFIG_CHANGED_EVENT, RAW_KEY_INPUT_EVENT, RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT, RAW_WINDOW_FOCUS_EVENT,
30 RawKeyInputArgs,
31 },
32 },
33 widget::info::InteractionPath,
34 window::WindowId,
35};
36use zng_app_context::app_local;
37use zng_clone_move::clmv;
38use zng_ext_window::WINDOWS;
39use zng_layout::unit::{Factor, FactorUnits};
40use zng_txt::Txt;
41use zng_var::{Var, var, var_default};
42use zng_view_api::config::AnimationsConfig;
43pub use zng_view_api::{
44 config::KeyRepeatConfig,
45 keyboard::{Key, KeyCode, KeyLocation, KeyState, NativeKeyCode},
46};
47
48use crate::focus::FOCUS;
49
50event_args! {
51 pub struct KeyInputArgs {
53 pub window_id: WindowId,
55
56 pub device_id: InputDeviceId,
58
59 pub key_code: KeyCode,
61
62 pub key_location: KeyLocation,
64
65 pub state: KeyState,
67
68 pub key: Key,
72 pub key_modified: Key,
76
77 pub text: Txt,
85
86 pub modifiers: ModifiersState,
88
89 pub repeat_count: u32,
93
94 pub target: InteractionPath,
96
97 ..
98
99 fn is_in_target(&self, id: WidgetId) -> bool {
101 self.target.contains(id)
102 }
103 }
104
105 pub struct ModifiersChangedArgs {
107 pub prev_modifiers: ModifiersState,
109
110 pub modifiers: ModifiersState,
112
113 ..
114
115 fn is_in_target(&self, id: WidgetId) -> bool {
117 true
118 }
119 }
120}
121impl KeyInputArgs {
123 pub fn shortcut_key(&self) -> &Key {
125 if matches!(self.key_location, KeyLocation::Numpad) {
126 &self.key_modified
127 } else {
128 &self.key
129 }
130 }
131
132 pub fn editing_shortcut(&self) -> Option<Shortcut> {
143 if matches!(self.state, KeyState::Released) {
144 return None;
145 }
146
147 let source_key = self.shortcut_key();
148 if let Ok(modifier) = ModifierGesture::try_from(source_key)
149 && (self.modifiers.is_empty() || self.modifiers == modifier.modifiers_state())
150 {
151 return Some(Shortcut::Modifier(modifier));
152 }
153 let key = match source_key {
154 Key::Unidentified => GestureKey::try_from(self.key_code).unwrap_or(GestureKey::Key(Key::Unidentified)),
155 key => GestureKey::try_from(key.clone()).unwrap_or(GestureKey::Key(Key::Unidentified)),
156 };
157 Some(Shortcut::Gesture(KeyGesture {
158 modifiers: self.modifiers,
159 key,
160 }))
161 }
162}
163
164impl KeyInputArgs {
171 pub fn is_backspace(&self) -> bool {
173 !self.modifiers.contains(ModifiersState::CTRL) && self.text.contains('\u{8}')
174 }
175
176 pub fn is_delete(&self) -> bool {
178 !self.modifiers.contains(ModifiersState::CTRL) && self.text.contains('\u{7F}')
179 }
180
181 pub fn is_tab(&self) -> bool {
183 !self.modifiers.contains(ModifiersState::CTRL) && self.text.chars().any(|c| "\t\u{B}\u{1F}".contains(c))
184 }
185
186 pub fn is_line_break(&self) -> bool {
188 !self.modifiers.contains(ModifiersState::CTRL) && self.text.chars().any(|c| "\r\n\u{85}".contains(c))
189 }
190
191 pub fn insert_str(&self) -> &str {
199 if self.modifiers.contains(ModifiersState::CTRL) {
200 ""
202 } else if self.is_tab() {
203 "\t"
204 } else if self.is_line_break() {
205 "\n"
206 } else if self.text.chars().any(|c| c.is_ascii_control()) {
207 ""
208 } else {
209 &self.text
210 }
211 }
212}
213
214event! {
215 pub static KEY_INPUT_EVENT: KeyInputArgs {
217 let _ = KEYBOARD_SV.read();
218 };
219
220 pub static MODIFIERS_CHANGED_EVENT: ModifiersChangedArgs {
222 let _ = KEYBOARD_SV.read();
223 };
224}
225
226fn hooks() {
227 RAW_KEY_INPUT_EVENT
228 .hook(|args| {
229 let focused = FOCUS.focused().get();
230 KEYBOARD_SV.write().key_input(args, focused);
231 true
232 })
233 .perm();
234
235 RAW_KEY_REPEAT_CONFIG_CHANGED_EVENT
236 .hook(|args| {
237 let mut kb = KEYBOARD_SV.write();
238 kb.repeat_config.set(args.config);
239 kb.last_key_down = None;
240 true
241 })
242 .perm();
243
244 RAW_ANIMATIONS_CONFIG_CHANGED_EVENT
245 .hook(|args| {
246 let kb = KEYBOARD_SV.read();
247 kb.caret_animation_config
248 .set((args.config.caret_blink_interval, args.config.caret_blink_timeout));
249 true
250 })
251 .perm();
252
253 RAW_WINDOW_FOCUS_EVENT
254 .hook(|args| {
255 if args.new_focus.is_none() {
256 let mut kb = KEYBOARD_SV.write();
257 kb.clear_modifiers();
258 kb.codes.set(vec![]);
259 kb.keys.set(vec![]);
260
261 kb.last_key_down = None;
262 }
263 true
264 })
265 .perm();
266
267 VIEW_PROCESS_INITED_EVENT
268 .hook(|args| {
269 if args.is_respawn {
270 let mut kb = KEYBOARD_SV.write();
271 kb.clear_modifiers();
272 kb.codes.set(vec![]);
273 kb.keys.set(vec![]);
274
275 kb.last_key_down = None;
276 }
277 true
278 })
279 .perm();
280}
281
282pub 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 hooks();
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 self.codes.modify(move |cs| {
410 if !cs.contains(&key_code) {
411 cs.push(key_code);
412 }
413 });
414
415 let key = &args.key;
416 if !matches!(&key, Key::Unidentified) {
417 self.keys.modify(clmv!(key, |ks| {
418 if ks.contains(&key) {
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 self.codes.modify(move |cs| {
433 if let Some(i) = cs.iter().position(|c| *c == key) {
434 cs.swap_remove(i);
435 }
436 });
437
438 let key = &args.key;
439 if !matches!(&key, Key::Unidentified) {
440 self.keys.modify(clmv!(key, |ks| {
441 if let Some(i) = ks.iter().position(|k| k == &key) {
442 ks.swap_remove(i);
443 }
444 }));
445
446 if key.is_modifier() {
447 self.set_modifiers(key.clone(), false);
448 }
449 }
450 }
451 }
452
453 if let Some(target) = focused
455 && (target.window_id() == args.window_id
456 || WINDOWS
457 .vars(target.window_id())
458 .and_then(|v| if v.nest_parent().get().is_some() { v.parent().get() } else { None })
459 == 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, false);
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 _ = KEYBOARD_SV.read();
566
567 let args = RawKeyInputArgs::now(
568 window_id,
569 InputDeviceId::virtual_keyboard(),
570 code,
571 location,
572 state,
573 key.clone(),
574 key,
575 "",
576 );
577 RAW_KEY_INPUT_EVENT.notify(args);
578 }
579
580 fn press_key(&mut self, window_id: WindowId, code: KeyCode, location: KeyLocation, key: Key) {
581 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
582 self.on_keyboard_input(window_id, code, location, key, KeyState::Released);
583 let _ = self.update(false);
584 }
585
586 fn press_modified_key(&mut self, window_id: WindowId, modifiers: ModifiersState, code: KeyCode, location: KeyLocation, key: Key) {
587 if modifiers.is_empty() {
588 self.press_key(window_id, code, location, key);
589 } else {
590 let modifiers = modifiers.keys();
591 for key in &modifiers {
592 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
593 }
594
595 let _ = self.update(false);
597
598 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Pressed);
599 self.on_keyboard_input(window_id, code, location, key.clone(), KeyState::Released);
600
601 let _ = self.update(false);
603
604 for key in modifiers {
605 self.on_keyboard_input(window_id, code, location, key, KeyState::Released);
606 }
607
608 let _ = self.update(false);
610 }
611 }
612}