@@ -29,7 +29,12 @@ pub struct System {
29
29
pub mouse_sensitivity : f32 ,
30
30
31
31
window : Rc < Window > ,
32
+
32
33
wants_capture : bool ,
34
+ occluded : bool ,
35
+ has_focus : bool ,
36
+
37
+ is_mouse_captured : bool ,
33
38
34
39
window_size : Vec2i ,
35
40
}
@@ -83,6 +88,16 @@ impl System {
83
88
pub fn set_capture_mouse ( & mut self , capture : bool ) {
84
89
self . wants_capture = capture;
85
90
91
+ let should_capture = self . should_capture ( ) ;
92
+ if self . is_mouse_captured != should_capture {
93
+ self . try_capture_mouse_internal ( should_capture) ;
94
+ }
95
+ }
96
+
97
+ #[ instrument( skip_all, name="input System::try_capture_mouse_internal" ) ]
98
+ fn try_capture_mouse_internal ( & mut self , capture : bool ) {
99
+ log:: info!( "try_capture_mouse_internal({capture})" ) ;
100
+
86
101
if capture {
87
102
if let Err ( error) = self . window . set_cursor_grab ( CursorGrabMode :: Confined )
88
103
. inspect_err ( |error| log:: warn!( "Failed to capture mouse with 'confined' mode - falling back to 'locked' mode. {error}" ) )
@@ -93,27 +108,39 @@ impl System {
93
108
}
94
109
95
110
self . window . set_cursor_visible ( false ) ;
111
+ self . is_mouse_captured = true ;
96
112
97
113
} else {
98
114
if let Err ( error) = self . window . set_cursor_grab ( CursorGrabMode :: None ) {
99
115
log:: error!( "Failed to release cursor grab: {error}" ) ;
100
116
}
101
117
102
118
self . window . set_cursor_visible ( true ) ;
119
+ self . is_mouse_captured = false ;
103
120
}
104
121
}
122
+
123
+ fn should_capture ( & self ) -> bool {
124
+ self . wants_capture && !self . occluded && self . has_focus
125
+ }
105
126
}
106
127
107
128
108
129
/// Internal. Will be called by core.
109
130
impl System {
110
131
#[ instrument( skip_all, name="input System::new" ) ]
111
132
pub fn new ( window : Rc < Window > ) -> System {
133
+ let has_focus = window. has_focus ( ) ;
134
+
112
135
System {
113
136
tracker : Tracker :: default ( ) ,
114
137
// gil: gilrs::Gilrs::new().unwrap(),
115
138
window,
139
+
116
140
wants_capture : false ,
141
+ occluded : false ,
142
+ has_focus,
143
+ is_mouse_captured : false ,
117
144
118
145
// Default half way between quake and source sdk defaults
119
146
// https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/client/in_mouse.cpp#L85
@@ -126,14 +153,23 @@ impl System {
126
153
127
154
// Clear any 'this frame' state in the tracker and prepare for recieving new inputs
128
155
pub fn reset_tracker ( & mut self ) {
156
+ if self . should_capture ( ) != self . is_mouse_captured {
157
+ self . try_capture_mouse_internal ( self . should_capture ( ) ) ;
158
+ }
159
+
160
+ self . window . set_cursor_visible ( !self . is_mouse_captured ) ;
161
+
129
162
self . tracker . reset ( ) ;
130
163
}
131
164
132
165
/// Called when something (e.g., egui) changes its mind about whether or not it wants to claim input.
133
166
/// We're assuming that when we become _not_ occluded we can safely manage things without interference.
134
167
pub fn set_occluded ( & mut self , occluded : bool ) {
135
- if !occluded {
136
- self . set_capture_mouse ( self . wants_capture ) ;
168
+ self . occluded = occluded;
169
+
170
+ let should_capture = self . should_capture ( ) ;
171
+ if self . is_mouse_captured != should_capture {
172
+ self . try_capture_mouse_internal ( should_capture) ;
137
173
}
138
174
}
139
175
@@ -164,8 +200,19 @@ impl System {
164
200
165
201
WindowEvent :: CursorLeft { ..} => self . tracker . track_mouse_left ( ) ,
166
202
167
- WindowEvent :: Focused ( false ) => self . tracker . track_focus_lost ( ) ,
168
- WindowEvent :: Focused ( true ) => self . tracker . track_focus_gained ( ) ,
203
+ WindowEvent :: Focused ( false ) => {
204
+ self . has_focus = false ;
205
+ self . tracker . track_focus_lost ( ) ;
206
+
207
+ self . try_capture_mouse_internal ( self . should_capture ( ) ) ;
208
+ }
209
+
210
+ WindowEvent :: Focused ( true ) => {
211
+ self . has_focus = true ;
212
+ self . tracker . track_focus_gained ( ) ;
213
+
214
+ self . try_capture_mouse_internal ( self . should_capture ( ) ) ;
215
+ }
169
216
170
217
// TODO(pat.m): track dpi
171
218
0 commit comments