@@ -33,6 +33,7 @@ use servo::webrender_api::units::{DeviceIntPoint, DeviceIntRect, DeviceIntSize};
3333use servo:: webrender_surfman:: WebrenderSurfman ;
3434use servo_media:: player:: context:: { GlApi , GlContext as PlayerGLContext , NativeDisplay } ;
3535use std:: cell:: { Cell , RefCell } ;
36+ use std:: collections:: HashMap ;
3637use std:: mem;
3738use std:: rc:: Rc ;
3839#[ cfg( target_os = "linux" ) ]
@@ -73,7 +74,10 @@ pub struct Window {
7374 primary_monitor : winit:: MonitorId ,
7475 event_queue : RefCell < Vec < WindowEvent > > ,
7576 mouse_pos : Cell < Point2D < i32 , DevicePixel > > ,
76- last_pressed : Cell < Option < KeyboardEvent > > ,
77+ last_pressed : Cell < Option < ( KeyboardEvent , Option < VirtualKeyCode > ) > > ,
78+ /// A map of winit's key codes to key values that are interpreted from
79+ /// winit's ReceivedChar events.
80+ keys_down : RefCell < HashMap < VirtualKeyCode , Key > > ,
7781 animation_state : Cell < AnimationState > ,
7882 fullscreen : Cell < bool > ,
7983 device_pixels_per_px : Option < f32 > ,
@@ -166,6 +170,7 @@ impl Window {
166170 mouse_down_point : Cell :: new ( Point2D :: new ( 0 , 0 ) ) ,
167171 mouse_pos : Cell :: new ( Point2D :: new ( 0 , 0 ) ) ,
168172 last_pressed : Cell :: new ( None ) ,
173+ keys_down : RefCell :: new ( HashMap :: new ( ) ) ,
169174 animation_state : Cell :: new ( AnimationState :: Idle ) ,
170175 fullscreen : Cell :: new ( false ) ,
171176 inner_size : Cell :: new ( inner_size) ,
@@ -185,8 +190,8 @@ impl Window {
185190 // shift ASCII control characters to lowercase
186191 ch = ( ch as u8 + 96 ) as char ;
187192 }
188- let mut event = if let Some ( event) = self . last_pressed . replace ( None ) {
189- event
193+ let ( mut event, key_code ) = if let Some ( ( event, key_code ) ) = self . last_pressed . replace ( None ) {
194+ ( event, key_code )
190195 } else if ch. is_ascii ( ) {
191196 // Some keys like Backspace emit a control character in winit
192197 // but they are already dealt with in handle_keyboard_input
@@ -195,9 +200,19 @@ impl Window {
195200 } else {
196201 // For combined characters like the letter e with an acute accent
197202 // no keyboard event is emitted. A dummy event is created in this case.
198- KeyboardEvent :: default ( )
203+ ( KeyboardEvent :: default ( ) , None )
199204 } ;
200205 event. key = Key :: Character ( ch. to_string ( ) ) ;
206+
207+ if event. state == KeyState :: Down {
208+ // Ensure that when we receive a keyup event from winit, we are able
209+ // to infer that it's related to this character and set the event
210+ // properties appropriately.
211+ if let Some ( key_code) = key_code {
212+ self . keys_down . borrow_mut ( ) . insert ( key_code, event. key . clone ( ) ) ;
213+ }
214+ }
215+
201216 let xr_poses = self . xr_window_poses . borrow ( ) ;
202217 for xr_window_pose in & * xr_poses {
203218 xr_window_pose. handle_xr_translation ( & event) ;
@@ -208,11 +223,23 @@ impl Window {
208223 }
209224
210225 fn handle_keyboard_input ( & self , input : KeyboardInput ) {
211- let event = keyboard_event_from_winit ( input) ;
226+ let mut event = keyboard_event_from_winit ( input) ;
227+ trace ! ( "handling {:?}" , event) ;
212228 if event. state == KeyState :: Down && event. key == Key :: Unidentified {
213229 // If pressed and probably printable, we expect a ReceivedCharacter event.
214- self . last_pressed . set ( Some ( event) ) ;
215- } else if event. key != Key :: Unidentified {
230+ // Wait for that to be received and don't queue any event right now.
231+ self . last_pressed . set ( Some ( ( event, input. virtual_keycode ) ) ) ;
232+ return ;
233+ } else if event. state == KeyState :: Up && event. key == Key :: Unidentified {
234+ // If release and probably printable, this is following a ReceiverCharacter event.
235+ if let Some ( key_code) = input. virtual_keycode {
236+ if let Some ( key) = self . keys_down . borrow_mut ( ) . remove ( & key_code) {
237+ event. key = key;
238+ }
239+ }
240+ }
241+
242+ if event. key != Key :: Unidentified {
216243 self . last_pressed . set ( None ) ;
217244 let xr_poses = self . xr_window_poses . borrow ( ) ;
218245 for xr_window_pose in & * xr_poses {
0 commit comments