@@ -27,7 +27,7 @@ const CLASS_ALLOWLIST: [&str; 5] = [
27
27
"Chrome_RenderWidgetHostHWND" , // gross electron apps
28
28
"Microsoft.UI.Content.DesktopChildSiteBridge" , // windows explorer main panel
29
29
"SysTreeView32" , // windows explorer side panel
30
- "TITLE_BAR_SCAFFOLDING_WINDOW_CLASS" , // windows explorer side panel
30
+ "TITLE_BAR_SCAFFOLDING_WINDOW_CLASS" , // windows explorer title bar
31
31
"DirectUIHWND" , // windows explorer after interaction
32
32
] ;
33
33
@@ -119,70 +119,128 @@ fn main() -> Result<()> {
119
119
pub fn listen_for_movements ( hwnds : Option < PathBuf > ) {
120
120
std:: thread:: spawn ( move || {
121
121
let receiver = message_loop:: start ( ) . expect ( "could not start winput message loop" ) ;
122
+
122
123
let mut eligibility_cache = HashMap :: new ( ) ;
123
- let mut map_instantiation_time = Instant :: now ( ) ;
124
- let map_max_age = Duration :: from_secs ( 60 ) * 10 ; // 10 minutes
124
+ let mut class_cache: HashMap < isize , String > = HashMap :: new ( ) ;
125
+ let mut hwnd_pair_cache: HashMap < isize , isize > = HashMap :: new ( ) ;
126
+
127
+ let mut cache_instantiation_time = Instant :: now ( ) ;
128
+ let max_cache_age = Duration :: from_secs ( 60 ) * 10 ; // 10 minutes
125
129
126
130
loop {
127
- // clear our cache every 10 minutes
128
- if map_instantiation_time. elapsed ( ) > map_max_age {
129
- tracing:: info!( "clearing hwnd cache, max map age is >10 minutes" ) ;
131
+ // clear our caches every 10 minutes
132
+ if cache_instantiation_time. elapsed ( ) > max_cache_age {
133
+ tracing:: info!( "clearing caches, cache age is >10 minutes" ) ;
134
+
130
135
eligibility_cache = HashMap :: new ( ) ;
131
- map_instantiation_time = Instant :: now ( ) ;
136
+ class_cache = HashMap :: new ( ) ;
137
+ hwnd_pair_cache = HashMap :: new ( ) ;
138
+
139
+ cache_instantiation_time = Instant :: now ( ) ;
132
140
}
133
141
134
142
if let Event :: MouseMoveRelative { .. } = receiver. next_event ( ) {
135
143
if let ( Ok ( cursor_pos_hwnd) , Ok ( foreground_hwnd) ) =
136
144
( window_at_cursor_pos ( ) , foreground_window ( ) )
137
145
{
138
146
if cursor_pos_hwnd != foreground_hwnd {
147
+ if let Some ( paired_hwnd) = hwnd_pair_cache. get ( & cursor_pos_hwnd) {
148
+ if foreground_hwnd == * paired_hwnd {
149
+ tracing:: trace!( "hwnds {cursor_pos_hwnd} and {foreground_hwnd} are known to refer to the same application, skipping" ) ;
150
+ continue ;
151
+ }
152
+ }
153
+
139
154
let mut should_raise = false ;
140
- let mut should_cache = false ;
155
+ let mut should_cache_eligibility = false ;
156
+
157
+ // check our class cache to avoid syscalls
158
+ let mut cursor_pos_class = class_cache. get ( & cursor_pos_hwnd) . cloned ( ) ;
159
+ let mut foreground_class = class_cache. get ( & foreground_hwnd) . cloned ( ) ;
160
+
161
+ // make syscalls if necessary and populate the class cache
162
+ match & cursor_pos_class {
163
+ None => {
164
+ if let Ok ( class) = real_window_class_w ( cursor_pos_hwnd) {
165
+ class_cache. insert ( cursor_pos_hwnd, class. clone ( ) ) ;
166
+ cursor_pos_class = Some ( class) ;
167
+ }
168
+ }
169
+ Some ( class) => {
170
+ tracing:: debug!(
171
+ "hwnd {cursor_pos_hwnd} class was found in the cache: {class}"
172
+ ) ;
173
+ }
174
+ }
141
175
142
- // check our cache first
143
- if let Some ( eligible) = eligibility_cache. get ( & cursor_pos_hwnd) {
144
- if * eligible {
145
- should_raise = true ;
176
+ // make syscalls if necessary and populate the class cache
177
+ match & foreground_class {
178
+ None => {
179
+ if let Ok ( class) = real_window_class_w ( foreground_hwnd) {
180
+ class_cache. insert ( foreground_hwnd, class. clone ( ) ) ;
181
+ foreground_class = Some ( class) ;
182
+ }
183
+ }
184
+ Some ( class) => {
146
185
tracing:: debug!(
147
- "hwnd {cursor_pos_hwnd} was found as eligible in the cache"
186
+ "hwnd {foreground_hwnd} class was found in the cache: {class} "
148
187
) ;
149
188
}
150
- } else {
151
- should_cache = true ;
152
189
}
153
190
154
- if !should_raise {
155
- // step one: test against known classes
156
- if let ( Ok ( cursor_pos_class ) , Ok ( foreground_class ) ) = (
157
- real_window_class_w ( cursor_pos_hwnd ) ,
158
- real_window_class_w ( foreground_hwnd ) ,
159
- ) {
160
- // windows explorer related focus loop weirdness fixes in this block
191
+ if let ( Some ( cursor_pos_class ) , Some ( foreground_class ) ) =
192
+ ( cursor_pos_class , foreground_class )
193
+ {
194
+ // windows explorer fixes - populate the hwnd pair cache if necessary
195
+ {
196
+ if cursor_pos_class == "DirectUIHWND"
197
+ && foreground_class == "CabinetWClass"
161
198
{
162
- if cursor_pos_class == "DirectUIHWND"
163
- && foreground_class == "CabinetWClass"
164
- {
165
- continue ;
166
- }
199
+ hwnd_pair_cache. insert ( cursor_pos_hwnd, foreground_hwnd) ;
200
+ continue ;
201
+ }
167
202
168
- if cursor_pos_class
169
- == "Microsoft.UI.Content.DesktopChildSiteBridge"
170
- && foreground_class == "CabinetWClass"
171
- {
172
- continue ;
173
- }
203
+ if cursor_pos_class == "Microsoft.UI.Content.DesktopChildSiteBridge"
204
+ && foreground_class == "CabinetWClass"
205
+ {
206
+ hwnd_pair_cache. insert ( cursor_pos_hwnd, foreground_hwnd) ;
207
+ continue ;
208
+ }
209
+ }
210
+
211
+ // steam fixes - populate the hwnd pair cache if necessary
212
+ {
213
+ if cursor_pos_class == "Chrome_RenderWidgetHostHWND"
214
+ && foreground_class == "SDL_app"
215
+ {
216
+ hwnd_pair_cache. insert ( cursor_pos_hwnd, foreground_hwnd) ;
217
+ continue ;
174
218
}
219
+ }
175
220
176
- // fail fast, exit this iteration of the loop and avoid any processing
177
- // if we hit a blocklist entry
178
- if CLASS_BLOCKLIST . contains ( & & * cursor_pos_class) {
221
+ // check our eligibility cache
222
+ if let Some ( eligible) = eligibility_cache. get ( & cursor_pos_hwnd) {
223
+ if * eligible {
224
+ should_raise = true ;
225
+ tracing:: debug!(
226
+ "hwnd {cursor_pos_hwnd} was found as eligible in the cache"
227
+ ) ;
228
+ }
229
+ } else {
230
+ should_cache_eligibility = true ;
231
+ }
232
+
233
+ // if the eligibility for this hwnd isn't cached, then do some tests
234
+ if !should_raise {
235
+ // step one: test against known classes
236
+ if CLASS_BLOCKLIST . contains ( & cursor_pos_class. as_str ( ) ) {
179
237
tracing:: debug!(
180
238
"window class {cursor_pos_class} is blocklisted"
181
239
) ;
182
240
continue ;
183
241
}
184
242
185
- if CLASS_ALLOWLIST . contains ( & & * cursor_pos_class) {
243
+ if CLASS_ALLOWLIST . contains ( & cursor_pos_class. as_str ( ) ) {
186
244
tracing:: debug!(
187
245
"window class {cursor_pos_class} is allowlisted"
188
246
) ;
@@ -192,26 +250,27 @@ pub fn listen_for_movements(hwnds: Option<PathBuf>) {
192
250
if !should_raise {
193
251
tracing:: trace!( "window class is {cursor_pos_class}" ) ;
194
252
}
195
- }
196
253
197
- // step two: if available, test against known hwnds
198
- if !should_raise {
199
- if let Some ( hwnds) = & hwnds {
200
- if let Ok ( raw_hwnds) = std:: fs:: read_to_string ( hwnds) {
201
- if raw_hwnds. contains ( & cursor_pos_hwnd. to_string ( ) ) {
202
- tracing:: debug!(
203
- "hwnd {cursor_pos_hwnd} was found in {}" ,
204
- hwnds. display( )
205
- ) ;
206
- should_raise = true ;
254
+ // step two: if available, test against known hwnds
255
+ if !should_raise {
256
+ if let Some ( hwnds) = & hwnds {
257
+ if let Ok ( raw_hwnds) = std:: fs:: read_to_string ( hwnds) {
258
+ if raw_hwnds. contains ( & cursor_pos_hwnd. to_string ( ) ) {
259
+ tracing:: debug!(
260
+ "hwnd {cursor_pos_hwnd} was found in {}" ,
261
+ hwnds. display( )
262
+ ) ;
263
+ should_raise = true ;
264
+ }
207
265
}
208
266
}
209
267
}
210
268
}
211
269
}
212
270
213
271
if should_raise {
214
- if should_cache {
272
+ if should_cache_eligibility {
273
+ // ensure we cache eligibility to avoid syscalls and tests next time
215
274
eligibility_cache. insert ( cursor_pos_hwnd, true ) ;
216
275
}
217
276
0 commit comments