77//! from the [`InputState`] sent to the host while ImGui reports it captured the previous frame.
88
99use glam:: Vec2 ;
10- use imgui:: { Io , MouseButton as ImGuiMouseButton } ;
10+ use imgui:: { Io , Key as ImGuiKey , MouseButton as ImGuiMouseButton } ;
11+ use winit:: keyboard:: ModifiersState ;
1112
12- use crate :: shared:: InputState ;
13+ use crate :: shared:: { InputState , Key } ;
14+
15+ const SUPPORTED_KEY_EVENTS : & [ ( Key , ImGuiKey ) ] = & [
16+ ( Key :: Tab , ImGuiKey :: Tab ) ,
17+ ( Key :: LeftArrow , ImGuiKey :: LeftArrow ) ,
18+ ( Key :: RightArrow , ImGuiKey :: RightArrow ) ,
19+ ( Key :: UpArrow , ImGuiKey :: UpArrow ) ,
20+ ( Key :: DownArrow , ImGuiKey :: DownArrow ) ,
21+ ( Key :: PageUp , ImGuiKey :: PageUp ) ,
22+ ( Key :: PageDown , ImGuiKey :: PageDown ) ,
23+ ( Key :: Home , ImGuiKey :: Home ) ,
24+ ( Key :: End , ImGuiKey :: End ) ,
25+ ( Key :: Insert , ImGuiKey :: Insert ) ,
26+ ( Key :: Delete , ImGuiKey :: Delete ) ,
27+ ( Key :: Backspace , ImGuiKey :: Backspace ) ,
28+ ( Key :: Space , ImGuiKey :: Space ) ,
29+ ( Key :: Return , ImGuiKey :: Enter ) ,
30+ ( Key :: Escape , ImGuiKey :: Escape ) ,
31+ ( Key :: LeftControl , ImGuiKey :: LeftCtrl ) ,
32+ ( Key :: LeftShift , ImGuiKey :: LeftShift ) ,
33+ ( Key :: LeftAlt , ImGuiKey :: LeftAlt ) ,
34+ ( Key :: LeftWindows , ImGuiKey :: LeftSuper ) ,
35+ ( Key :: RightControl , ImGuiKey :: RightCtrl ) ,
36+ ( Key :: RightShift , ImGuiKey :: RightShift ) ,
37+ ( Key :: RightAlt , ImGuiKey :: RightAlt ) ,
38+ ( Key :: RightWindows , ImGuiKey :: RightSuper ) ,
39+ ( Key :: Menu , ImGuiKey :: Menu ) ,
40+ ( Key :: Alpha0 , ImGuiKey :: Alpha0 ) ,
41+ ( Key :: Alpha1 , ImGuiKey :: Alpha1 ) ,
42+ ( Key :: Alpha2 , ImGuiKey :: Alpha2 ) ,
43+ ( Key :: Alpha3 , ImGuiKey :: Alpha3 ) ,
44+ ( Key :: Alpha4 , ImGuiKey :: Alpha4 ) ,
45+ ( Key :: Alpha5 , ImGuiKey :: Alpha5 ) ,
46+ ( Key :: Alpha6 , ImGuiKey :: Alpha6 ) ,
47+ ( Key :: Alpha7 , ImGuiKey :: Alpha7 ) ,
48+ ( Key :: Alpha8 , ImGuiKey :: Alpha8 ) ,
49+ ( Key :: Alpha9 , ImGuiKey :: Alpha9 ) ,
50+ ( Key :: A , ImGuiKey :: A ) ,
51+ ( Key :: B , ImGuiKey :: B ) ,
52+ ( Key :: C , ImGuiKey :: C ) ,
53+ ( Key :: D , ImGuiKey :: D ) ,
54+ ( Key :: E , ImGuiKey :: E ) ,
55+ ( Key :: F , ImGuiKey :: F ) ,
56+ ( Key :: G , ImGuiKey :: G ) ,
57+ ( Key :: H , ImGuiKey :: H ) ,
58+ ( Key :: I , ImGuiKey :: I ) ,
59+ ( Key :: J , ImGuiKey :: J ) ,
60+ ( Key :: K , ImGuiKey :: K ) ,
61+ ( Key :: L , ImGuiKey :: L ) ,
62+ ( Key :: M , ImGuiKey :: M ) ,
63+ ( Key :: N , ImGuiKey :: N ) ,
64+ ( Key :: O , ImGuiKey :: O ) ,
65+ ( Key :: P , ImGuiKey :: P ) ,
66+ ( Key :: Q , ImGuiKey :: Q ) ,
67+ ( Key :: R , ImGuiKey :: R ) ,
68+ ( Key :: S , ImGuiKey :: S ) ,
69+ ( Key :: T , ImGuiKey :: T ) ,
70+ ( Key :: U , ImGuiKey :: U ) ,
71+ ( Key :: V , ImGuiKey :: V ) ,
72+ ( Key :: W , ImGuiKey :: W ) ,
73+ ( Key :: X , ImGuiKey :: X ) ,
74+ ( Key :: Y , ImGuiKey :: Y ) ,
75+ ( Key :: Z , ImGuiKey :: Z ) ,
76+ ( Key :: F1 , ImGuiKey :: F1 ) ,
77+ ( Key :: F2 , ImGuiKey :: F2 ) ,
78+ ( Key :: F3 , ImGuiKey :: F3 ) ,
79+ ( Key :: F4 , ImGuiKey :: F4 ) ,
80+ ( Key :: F5 , ImGuiKey :: F5 ) ,
81+ ( Key :: F6 , ImGuiKey :: F6 ) ,
82+ ( Key :: F7 , ImGuiKey :: F7 ) ,
83+ ( Key :: F8 , ImGuiKey :: F8 ) ,
84+ ( Key :: F9 , ImGuiKey :: F9 ) ,
85+ ( Key :: F10 , ImGuiKey :: F10 ) ,
86+ ( Key :: F11 , ImGuiKey :: F11 ) ,
87+ ( Key :: F12 , ImGuiKey :: F12 ) ,
88+ ( Key :: Quote , ImGuiKey :: Apostrophe ) ,
89+ ( Key :: Comma , ImGuiKey :: Comma ) ,
90+ ( Key :: Minus , ImGuiKey :: Minus ) ,
91+ ( Key :: Period , ImGuiKey :: Period ) ,
92+ ( Key :: Slash , ImGuiKey :: Slash ) ,
93+ ( Key :: Semicolon , ImGuiKey :: Semicolon ) ,
94+ ( Key :: Equals , ImGuiKey :: Equal ) ,
95+ ( Key :: LeftBracket , ImGuiKey :: LeftBracket ) ,
96+ ( Key :: Backslash , ImGuiKey :: Backslash ) ,
97+ ( Key :: RightBracket , ImGuiKey :: RightBracket ) ,
98+ ( Key :: BackQuote , ImGuiKey :: GraveAccent ) ,
99+ ( Key :: CapsLock , ImGuiKey :: CapsLock ) ,
100+ ( Key :: ScrollLock , ImGuiKey :: ScrollLock ) ,
101+ ( Key :: Numlock , ImGuiKey :: NumLock ) ,
102+ ( Key :: Print , ImGuiKey :: PrintScreen ) ,
103+ ( Key :: Pause , ImGuiKey :: Pause ) ,
104+ ( Key :: Keypad0 , ImGuiKey :: Keypad0 ) ,
105+ ( Key :: Keypad1 , ImGuiKey :: Keypad1 ) ,
106+ ( Key :: Keypad2 , ImGuiKey :: Keypad2 ) ,
107+ ( Key :: Keypad3 , ImGuiKey :: Keypad3 ) ,
108+ ( Key :: Keypad4 , ImGuiKey :: Keypad4 ) ,
109+ ( Key :: Keypad5 , ImGuiKey :: Keypad5 ) ,
110+ ( Key :: Keypad6 , ImGuiKey :: Keypad6 ) ,
111+ ( Key :: Keypad7 , ImGuiKey :: Keypad7 ) ,
112+ ( Key :: Keypad8 , ImGuiKey :: Keypad8 ) ,
113+ ( Key :: Keypad9 , ImGuiKey :: Keypad9 ) ,
114+ ( Key :: KeypadPeriod , ImGuiKey :: KeypadDecimal ) ,
115+ ( Key :: KeypadDivide , ImGuiKey :: KeypadDivide ) ,
116+ ( Key :: KeypadMultiply , ImGuiKey :: KeypadMultiply ) ,
117+ ( Key :: KeypadMinus , ImGuiKey :: KeypadSubtract ) ,
118+ ( Key :: KeypadPlus , ImGuiKey :: KeypadAdd ) ,
119+ ( Key :: KeypadEnter , ImGuiKey :: KeypadEnter ) ,
120+ ( Key :: KeypadEquals , ImGuiKey :: KeypadEqual ) ,
121+ ] ;
13122
14123/// Strips pointer, scroll, drag/drop, and keyboard data from `input` when ImGui reported capture on the previous frame.
15124///
@@ -42,7 +151,7 @@ pub fn sanitize_input_state_for_imgui_host(
42151}
43152
44153/// Pointer and window hints for ImGui, in **physical** pixels where noted.
45- #[ derive( Clone , Copy , Debug , Default ) ]
154+ #[ derive( Clone , Debug , Default ) ]
46155pub struct DebugHudInput {
47156 /// Cursor position in physical pixels (or `[-inf, -inf]` when unavailable).
48157 pub cursor_px : [ f32 ; 2 ] ,
@@ -62,6 +171,12 @@ pub struct DebugHudInput {
62171 pub extra1 : bool ,
63172 /// Fifth mouse button held (e.g. side forward).
64173 pub extra2 : bool ,
174+ /// Current keyboard modifiers from winit.
175+ pub keyboard_modifiers : ModifiersState ,
176+ /// Keys currently held, in host [`Key`] form.
177+ pub held_keys : Vec < Key > ,
178+ /// Text committed since the previous HUD input snapshot.
179+ pub text : String ,
65180}
66181
67182impl DebugHudInput {
@@ -89,6 +204,9 @@ impl DebugHudInput {
89204 middle : acc. middle_held ,
90205 extra1 : acc. button4_held ,
91206 extra2 : acc. button5_held ,
207+ keyboard_modifiers : acc. keyboard_modifiers ( ) ,
208+ held_keys : acc. held_keys . clone ( ) ,
209+ text : acc. take_hud_text ( ) ,
92210 }
93211 }
94212}
@@ -109,6 +227,93 @@ pub(crate) fn apply_input(io: &mut Io, input: &DebugHudInput) {
109227 io. add_mouse_button_event ( ImGuiMouseButton :: Extra1 , input. extra1 ) ;
110228 io. add_mouse_button_event ( ImGuiMouseButton :: Extra2 , input. extra2 ) ;
111229 io. add_mouse_wheel_event ( [ input. mouse_wheel_delta . x , input. mouse_wheel_delta . y ] ) ;
230+ apply_keyboard_input ( io, input) ;
231+ }
232+
233+ fn apply_keyboard_input ( io : & mut Io , input : & DebugHudInput ) {
234+ for ( key, down) in modifier_key_states ( input. keyboard_modifiers ) {
235+ io. add_key_event ( key, down) ;
236+ }
237+ for & ( host_key, imgui_key) in SUPPORTED_KEY_EVENTS {
238+ io. add_key_event ( imgui_key, input. held_keys . contains ( & host_key) ) ;
239+ }
240+ for character in input. text . chars ( ) {
241+ io. add_input_character ( character) ;
242+ }
243+ }
244+
245+ fn modifier_key_states ( modifiers : ModifiersState ) -> [ ( ImGuiKey , bool ) ; 4 ] {
246+ [
247+ ( ImGuiKey :: ModCtrl , modifiers. control_key ( ) ) ,
248+ ( ImGuiKey :: ModShift , modifiers. shift_key ( ) ) ,
249+ ( ImGuiKey :: ModAlt , modifiers. alt_key ( ) ) ,
250+ ( ImGuiKey :: ModSuper , modifiers. meta_key ( ) ) ,
251+ ]
252+ }
253+
254+ #[ cfg( test) ]
255+ fn host_key_to_imgui_key ( key : Key ) -> Option < ImGuiKey > {
256+ SUPPORTED_KEY_EVENTS
257+ . iter ( )
258+ . find_map ( |& ( host_key, imgui_key) | ( host_key == key) . then_some ( imgui_key) )
259+ }
260+
261+ #[ cfg( test) ]
262+ mod input_bridge_tests {
263+ use imgui:: Context ;
264+ use winit:: keyboard:: ModifiersState ;
265+
266+ use super :: {
267+ DebugHudInput , ImGuiKey , Key , apply_input, host_key_to_imgui_key, modifier_key_states,
268+ } ;
269+
270+ #[ test]
271+ fn host_keys_map_to_imgui_keys_needed_by_text_entry ( ) {
272+ for ( host_key, imgui_key) in [
273+ ( Key :: Alpha1 , ImGuiKey :: Alpha1 ) ,
274+ ( Key :: Backspace , ImGuiKey :: Backspace ) ,
275+ ( Key :: Return , ImGuiKey :: Enter ) ,
276+ ( Key :: LeftArrow , ImGuiKey :: LeftArrow ) ,
277+ ( Key :: KeypadPeriod , ImGuiKey :: KeypadDecimal ) ,
278+ ] {
279+ assert_eq ! ( host_key_to_imgui_key( host_key) , Some ( imgui_key) ) ;
280+ }
281+ assert_eq ! ( host_key_to_imgui_key( Key :: F13 ) , None ) ;
282+ }
283+
284+ #[ test]
285+ fn modifier_states_include_ctrl_for_drag_input_activation ( ) {
286+ let states = modifier_key_states ( ModifiersState :: CONTROL | ModifiersState :: SHIFT ) ;
287+
288+ assert ! ( states. contains( & ( ImGuiKey :: ModCtrl , true ) ) ) ;
289+ assert ! ( states. contains( & ( ImGuiKey :: ModShift , true ) ) ) ;
290+ assert ! ( states. contains( & ( ImGuiKey :: ModAlt , false ) ) ) ;
291+ assert ! ( states. contains( & ( ImGuiKey :: ModSuper , false ) ) ) ;
292+ }
293+
294+ #[ test]
295+ fn apply_input_feeds_modifiers_and_held_keys_to_imgui ( ) {
296+ let mut context = Context :: create ( ) ;
297+ context. fonts ( ) . build_rgba32_texture ( ) ;
298+ let input = DebugHudInput {
299+ window_focused : true ,
300+ keyboard_modifiers : ModifiersState :: CONTROL ,
301+ held_keys : vec ! [ Key :: Backspace , Key :: Alpha1 ] ,
302+ text : "12.5" . into ( ) ,
303+ ..Default :: default ( )
304+ } ;
305+
306+ {
307+ let io = context. io_mut ( ) ;
308+ io. display_size = [ 100.0 , 100.0 ] ;
309+ apply_input ( io, & input) ;
310+ }
311+
312+ let ui = context. frame ( ) ;
313+ assert ! ( ui. io( ) . key_ctrl) ;
314+ assert ! ( ui. is_key_down( ImGuiKey :: Backspace ) ) ;
315+ assert ! ( ui. is_key_down( ImGuiKey :: Alpha1 ) ) ;
316+ }
112317}
113318
114319#[ cfg( test) ]
0 commit comments