ltk/input/keyboard/
shortcuts.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use crate::app::App;
use crate::event_loop::{ AppData, SurfaceFocus };
use crate::tree::{ find_handlers, next_focusable_index };
use crate::Keysym;
use crate::platform::Platform;

use super::super::event::KeyInput;

impl<A: App, P: Platform> AppData<A, P>
{
	pub( super ) fn handle_key_ctrl_a( &mut self, focus: SurfaceFocus )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		if is_text { self.handle_select_all( focus ); }
	}

	pub( super ) fn handle_key_ctrl_c( &mut self, focus: SurfaceFocus )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		if is_text { self.handle_copy( focus ); }
	}

	pub( super ) fn handle_key_ctrl_x( &mut self, focus: SurfaceFocus )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		if is_text { self.handle_cut( focus ); }
	}

	pub( super ) fn handle_key_ctrl_v( &mut self, focus: SurfaceFocus )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		if is_text { self.handle_paste( focus ); }
	}

	pub( super ) fn handle_key_tab( &mut self, focus: SurfaceFocus, event: &KeyInput )
	{
		let reverse  = event.keysym == Keysym::ISO_Left_Tab || self.shift_pressed;
		if !reverse && !self.ctrl_pressed
		{
			let typed = self.surface( focus ).focused_idx
				.and_then( |idx| find_handlers( &self.surface( focus ).frame.widget_rects, idx ) )
				.and_then( |h| h.tab_text().map( str::to_string ) );
			if let Some( text ) = typed
			{
				self.handle_text_insert( focus, &text );
				return;
			}
		}
		let intercepted = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed );
		if let Some( msg ) = intercepted
		{
			self.pending_msgs.push( msg );
		}
		else
		{
			let ss       = self.surface( focus );
			let next_idx = next_focusable_index( &ss.frame.widget_rects, ss.focused_idx, reverse );
			if let Some( next_idx ) = next_idx
			{
				self.show_focus_ring( focus, true );
				self.set_focus( focus, Some( next_idx ) );
			}
		}
	}

	pub( super ) fn handle_key_escape( &mut self, focus: SurfaceFocus, event: &KeyInput )
	{
		// Esc peels off transient UI one layer at a time; with none
		// left it drops focus and lets the app see Esc.
		if self.dismiss_transient( focus ) { return; }
		self.set_focus( focus, None );
		if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
		{
			self.pending_msgs.push( msg );
		}
	}
}