@@ -229,6 +229,7 @@ module Run
229229 end
230230
231231 @key_handler : Proc (::X11 ::KeyEvent , UInt64 , Char ?, Nil )?
232+ @flush_event_queue = Channel (Nil ).new
232233 def run (* , key_handler)
233234 @key_handler = key_handler
234235 record = @record
@@ -249,7 +250,18 @@ module Run
249250 # Even if XTst Record obliterates the need to read key events, we still need to
250251 # keep the event loop running or otherwise the hotkeys aren't even grabbed
251252 # and use it to get updates on the active window.
252- event_fd = IO ::FileDescriptor .new @display .connection_number
253+ spawn same_thread: true do
254+ event_fd = IO ::FileDescriptor .new @display .connection_number
255+ loop do
256+ # Instead of this, running `next_event` (blocking) in a loop also works but requires a separate thread.
257+ # But that somehow messes up `::exit` so we don't do that.
258+ # This very solution, `wait_readable`, has shown to *sometimes* be unreliable, i.e. hotkeys aren't
259+ # grabbed properly because some pending events somehow aren't visible. To solve this,
260+ # `flush_event_queue` is also called from a few other places.
261+ event_fd.wait_readable
262+ @flush_event_queue .send(nil )
263+ end
264+ end
253265 loop do
254266 while @display .pending != 0
255267 @mutex .lock
@@ -263,10 +275,10 @@ module Run
263275 if active_win > 0
264276 # The mutex doesn't protect against nonsense here yet but the chance for
265277 # this to happen is fairly small
266- @mutex .unlock
267- @hotkeys .each { |h | ungrab_hotkey(h, from_window: active_window_before, unsubscribe: false ) }
268- @hotkeys .each { |h | grab_hotkey(h, subscribe: false ) }
269- @mutex .lock
278+ spawn same_thread: true do
279+ @hotkeys .each { |h | ungrab_hotkey(h, from_window: active_window_before, unsubscribe: false ) }
280+ @hotkeys .each { |h | grab_hotkey(h, subscribe: false ) }
281+ end
270282 end
271283 end
272284 end
@@ -279,7 +291,7 @@ module Run
279291 end
280292 end
281293 end
282- event_fd.wait_readable
294+ @flush_event_queue .receive
283295 end
284296 end
285297
@@ -326,6 +338,7 @@ module Run
326338 end
327339 end
328340 @mutex .unlock
341+ @flush_event_queue .send(nil )
329342 end
330343 # :ditto:
331344 def ungrab_hotkey (hotkey, * , from_window = @last_active_window , unsubscribe = true )
@@ -335,16 +348,19 @@ module Run
335348 @display .ungrab_key(hotkey.keycode, mod, grab_window: from_window)
336349 end
337350 @mutex .unlock
351+ @flush_event_queue .send(nil )
338352 end
339353 def grab_keyboard
340354 @mutex .lock
341355 @display .grab_keyboard(grab_window: @last_active_window , owner_events: true , pointer_mode: ::X11 ::GrabModeAsync , keyboard_mode: ::X11 ::GrabModeAsync , time: ::X11 ::CurrentTime )
342356 @mutex .unlock
357+ @flush_event_queue .send(nil )
343358 end
344359 def ungrab_keyboard
345360 @mutex .lock
346361 @display .ungrab_keyboard(time: ::X11 ::CurrentTime )
347362 @mutex .unlock
363+ @flush_event_queue .send(nil )
348364 end
349365 end
350366end
0 commit comments