@@ -2,6 +2,7 @@ use evdev::{uinput::VirtualDevice, Device, EventType, InputEvent, KeyCode};
22use lay:: config:: LayConfig ;
33use lay:: keyboard:: is_typing_key;
44use std:: os:: fd:: AsRawFd ;
5+ use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
56use std:: sync:: { Arc , Mutex } ;
67
78use super :: boundary_runtime:: {
@@ -16,17 +17,20 @@ use super::manual_trigger_runtime::{
1617 fire_expired_pending_multi_tap, handle_manual_trigger_event, ManualTriggerEventContext ,
1718 PendingMultiTapTimeoutContext ,
1819} ;
20+ use super :: text_context_runtime:: should_advance_text_context;
1921use super :: trigger_dispatch:: { is_single_trigger_id, trigger_key_from_config} ;
2022use super :: typing_key_runtime:: { handle_typing_key_press, TypingKeyContext } ;
2123use super :: {
2224 active_enter_autocorrect_from_env, active_layout_backend, idle_wait_timeout, log,
23- poll_focused_window_state, should_skip_buffer_input, wait_for_keyboard_event_or_timeout,
24- DShiftState , ForceLayoutHotkeyContext , ShiftState , ENTER_AUTOCORRECT_EXPERIMENT_ENV ,
25+ poll_focused_window_state, poll_focused_window_state_for_key_event, should_skip_buffer_input,
26+ wait_for_keyboard_event_or_timeout, DShiftState , ForceLayoutHotkeyContext , ShiftState ,
27+ ENTER_AUTOCORRECT_EXPERIMENT_ENV ,
2528} ;
2629
2730pub ( super ) fn listen_keyboard (
2831 device_path : std:: path:: PathBuf ,
2932 virtual_kbd : Arc < Mutex < Option < VirtualDevice > > > ,
33+ field_context_epoch : Arc < AtomicU64 > ,
3034 verbose : bool ,
3135 cfg : LayConfig ,
3236) -> std:: io:: Result < ( ) > {
@@ -139,7 +143,8 @@ pub(super) fn listen_keyboard(
139143 Err ( e) => return Err ( e) ,
140144 } ;
141145
142- update_focus_state ( & mut state) ;
146+ update_focus_state_for_key_batch ( & events, & mut state) ;
147+ sync_field_context_epoch ( & field_context_epoch, & mut state) ;
143148 if state. focus_ignored {
144149 state. shift_state = ShiftState :: default ( ) ;
145150 state. dshift_state = DShiftState :: Idle ;
@@ -169,6 +174,12 @@ pub(super) fn listen_keyboard(
169174
170175 // ─── modifier tracking ────────────────────────────
171176 state. shift_state . update ( key, value) ;
177+ if should_advance_text_context ( key, value, & state. shift_state ) {
178+ let epoch = field_context_epoch. fetch_add ( 1 , Ordering :: Relaxed ) + 1 ;
179+ if state. switch_field_context_epoch ( epoch) && verbose {
180+ log ( "► text context changed: switched field buffer" ) ;
181+ }
182+ }
172183 if state. force_layout_hotkeys . handle_event (
173184 key,
174185 value,
@@ -339,11 +350,92 @@ pub(super) fn listen_keyboard(
339350 }
340351}
341352
353+ pub ( super ) fn listen_pointer (
354+ device_path : std:: path:: PathBuf ,
355+ field_context_epoch : Arc < AtomicU64 > ,
356+ verbose : bool ,
357+ ) -> std:: io:: Result < ( ) > {
358+ let mut device = Device :: open ( & device_path) ?;
359+ device. set_nonblocking ( true ) ?;
360+ let device_fd = device. as_raw_fd ( ) ;
361+ log ( & format ! (
362+ "► слушаю pointer: {device_path:?} имя={:?}" ,
363+ device. name( ) . unwrap_or( "?" )
364+ ) ) ;
365+
366+ loop {
367+ let fetched_events = {
368+ device
369+ . fetch_events ( )
370+ . map ( |events| events. collect :: < Vec < _ > > ( ) )
371+ } ;
372+ let events: Vec < InputEvent > = match fetched_events {
373+ Ok ( events) => events,
374+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: WouldBlock => {
375+ wait_for_keyboard_event_or_timeout (
376+ device_fd,
377+ std:: time:: Duration :: from_millis ( 500 ) ,
378+ ) ?;
379+ continue ;
380+ }
381+ Err ( e) => return Err ( e) ,
382+ } ;
383+
384+ for event in events {
385+ if event. event_type ( ) != EventType :: KEY || event. value ( ) != 1 {
386+ continue ;
387+ }
388+ let key = KeyCode :: new ( event. code ( ) ) ;
389+ if matches ! (
390+ key,
391+ KeyCode :: BTN_LEFT
392+ | KeyCode :: BTN_RIGHT
393+ | KeyCode :: BTN_MIDDLE
394+ | KeyCode :: BTN_SIDE
395+ | KeyCode :: BTN_EXTRA
396+ | KeyCode :: BTN_FORWARD
397+ | KeyCode :: BTN_BACK
398+ | KeyCode :: BTN_TASK
399+ ) {
400+ let epoch = field_context_epoch. fetch_add ( 1 , Ordering :: Relaxed ) + 1 ;
401+ if verbose {
402+ log ( & format ! ( "► pointer context changed: field epoch {epoch}" ) ) ;
403+ }
404+ }
405+ }
406+ }
407+ }
408+
342409fn update_focus_state ( state : & mut DaemonLoopState ) {
343- let Some ( focus) = poll_focused_window_state ( & mut state. last_focus_ignore_poll ) else {
344- return ;
410+ let focus = poll_focused_window_state ( & mut state. last_focus_ignore_poll ) ;
411+ apply_focus_state ( state, focus) ;
412+ }
413+
414+ fn update_focus_state_for_key_batch ( events : & [ InputEvent ] , state : & mut DaemonLoopState ) {
415+ let has_key_event = events
416+ . iter ( )
417+ . any ( |event| event. event_type ( ) == EventType :: KEY ) ;
418+ let focus = if has_key_event {
419+ poll_focused_window_state_for_key_event ( & mut state. last_focus_ignore_poll )
420+ } else {
421+ poll_focused_window_state ( & mut state. last_focus_ignore_poll )
345422 } ;
423+ apply_focus_state ( state, focus) ;
424+ }
425+
426+ fn sync_field_context_epoch ( field_context_epoch : & AtomicU64 , state : & mut DaemonLoopState ) {
427+ let epoch = field_context_epoch. load ( Ordering :: Relaxed ) ;
428+ if state. switch_field_context_epoch ( epoch) {
429+ log ( "► text context changed: switched field buffer" ) ;
430+ state. dshift_state = DShiftState :: Idle ;
431+ state. pending_multi_tap = None ;
432+ }
433+ }
346434
435+ fn apply_focus_state ( state : & mut DaemonLoopState , focus : Option < super :: FocusedWindowState > ) {
436+ let Some ( focus) = focus else {
437+ return ;
438+ } ;
347439 let identity_changed = state. switch_window_input_state ( focus. identity ) ;
348440 if identity_changed {
349441 log ( "► focused window changed: switched text tail buffer" ) ;
0 commit comments