+
     iB  c                  s   R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	t	^ RI
Ht ^ RIHtHtHt ^ RIt^ RIHtHtHtHtHt ^ RIHtHt ^ RIHt ^ RIHtHt ^ R	IH t  ^ R
I!H"t" ^ RI#H$t$ ^ RI%H&t&H't'H(t( ^ RI)H*t* ^ RI+H,t,H-t- ^ RI.H/t/ ^ RI0H1t1 ^ RI2H3t3 ^ RI4H5t5 Rt6Rt7Rt8Rt9Rt:Rt; ! R R4      t< ! R R4      t= ! R R4      t> ! R R 4      t?R# )!a  Process that sends stuff to the GUI.

It should be started via input-remapper-control and pkexec.

GUIs should not run as root
https://wiki.archlinux.org/index.php/Running_GUI_applications_as_root

The service shouldn't do that even though it has root rights, because that
would enable key-loggers to just ask input-remapper for all user-input.

Instead, the ReaderService is used, which will be stopped when the gui closes.

Whereas for the reader-service to start a password is needed and it stops whe
the ui closes.

This uses the backend injection.event_reader and mapping_handlers to process all the
different input-events into simple on/off events and sends them to the gui.
)annotationsN)defaultdict)SetListTuple)EV_KEYEV_ABSEV_REL
REL_HWHEEL	REL_WHEEL)InputCombinationInputConfig)Mapping)_Groups_Group)EventReader)GlobalUInputs)AbsToBtnHandler)NotifyCallbackInputEventHandlerMappingHandler)RelToBtnHandler)
InputEventEventActions)Pipe)logger)	UserUtils)get_device_hashZ	terminatezstop-readingZrefresh_groupsgroupseventZstatusc                  s   ] tR t^St$ Rt]! R 4      t^]]&   ^]]&   Rt	R]
R&   ^<tR]
R&   R R lt]R R	 l4       t]R
 R l4       t]R R l4       t]R 4       tR tR tR tR tR tR R ltR R ltR tR R ltRtR# )ReaderServicezService that only reads events and is supposed to run as root.

Sends device information and keycodes to the GUI.

Commands are either numbers for generic commands,
or strings to start listening on a specific device.
c                 	s    ^# )i    r       E/usr/lib/python3.14/site-packages/inputremapper/gui/reader_service.pyZ<lambda>ZReaderService.<lambda>_   s    qr    Zint_maximum_lifetime_timeout_tolerancec               s$    V ^8  d   QhRRRRRR/# )   r   r   global_uinputsr   returnZNoner   Zformat   "r!   __annotate__ReaderService.__annotate__m   s&     J Jw J J$ Jr    c                s   \         P                   ! 4       V n        Wn        W n        \	        V P                  4       ^ ,          4      V n        \	        V P                  4       ^,          4      V n        \        P                  ! 4       V n	        \        4       V n        \        P                  ! 4       V n        V P                  P                  R\         RR/4       R# )zDConstruct the reader-service and initialize its communication pipes.typemessageZreadyN)time_start_timer   r%   r   get_pipe_paths_results_pipe_commands_pipemultiprocessing_pipeset_tasksasyncioZEvent_stop_eventsend
MSG_STATUS)selfr   r%      &&&r!   __init__ZReaderService.__init__m   s    99;,!$"5"5"7":;"4#6#6#8#;<$))+
),"==?Y HIr    c                   V ^8  d   QhRR/# )r$   r&   zTuple[str, str]r   r'   r(   r!   r)   r*   |   s     
 
O 
r    c                 sR    R\         P                   R2R\         P                   R23# )z)Get the path where the pipe can be found.z/tmp/input-remapper-z/reader-resultsz/reader-commands)r   Zhomer   r    r!   r/   ZReaderService.get_pipe_paths{   s1     #9>>"2/B"9>>"22BC
 	
r    c               r=   r$   r&   boolr   r'   r(   r!   r)   r*      s     $ $ $r    c                 	s|    \         P                  4       ^ ,           R2p \        P                  P	                  V 4      # )i    Zr)r   r/   ospathZexists)rA   s    r!   pipes_existZReaderService.pipes_exist   s4      ..034A6 ww~~d##r    c               r=   r>   r   r'   r(   r!   r)   r*      s       r    c                 sp     \         P                  ! . RO4       R#   \         P                   d     R# i ; i)z'Check if the reader-service is running.FT)Zpgrepz-fzinput-remapper-reader-service)
subprocessZcheck_outputZCalledProcessErrorr   r    r!   
is_runningZReaderService.is_running   s5    	##$TU  ,, 		s    55c                 s    \         P                  \        P                  8:  d   RMRp RV  2p\         P                  ! RV4       \
        P                  ! V4      pV^ 8w  d   \        RV 24      hR# )z9Start reader-service via pkexec to run in the background.z -dZ z<pkexec input-remapper-control --command start-reader-servicezRunning `%s`z*Failed to pkexec the reader-service, code N)r   ZlevelloggingZDEBUGdebugr@   ZsystemZ	Exception)rF   cmdZ	exit_codes      r!   pkexec_reader_serviceZ#ReaderService.pkexec_reader_service   s`      6BLUGT^S)IIcN	>HTUU r    c                s&  "   \         P                  ! R4       V P                  P                  4        V P	                  4        \
        P                  ! V P                  4       V P                  4       V P                  4       4      G Rj  xL
  R#  L5i)zStart doing stuff.zDiscovering initial groupsN)
r   rF   r   refresh_send_groupsr6   gather_read_commands_timeout_stop_if_pipes_brokenr:      &r!   runZReaderService.run   sg      	12nn!MMO&&(
 	
 	
s   BBB	Bc                s    \         P                  ! R4       V P                  P                  R\        RV P
                  P                  4       /4       R# )zSend the groups to the gui.zSending groupsr+   r,   N)r   rF   r0   r8   
MSG_GROUPSr   ZdumpsrO   rP   r!   rJ   ZReaderService._send_groups   s9    %&Y@Q@Q@S TUr    c                s  "   \         P                  ! V P                  4      G Rj  xL
  V P                  4       '       di   \        P
                  ! R4       \        V P                  4       F9  pV P                  4       '       g    M"\         P                  ! ^4      G Rj  xL
  K;  	  \        P
                  ! R4       \        P                  ! ^4       R#  L L85i)z#Stop automatically after some time.Nz2Waiting a bit longer for the gui to finish readingz&Maximum life-span reached, terminating)
r6   sleepr"   _is_readingr   rF   Zranger#   sysexit)r:   _s   & r!   rM   ZReaderService._timeout   s      mmD22333 LLMN4223''))mmA&&& 4 	=> 	4 's(   $CCCAC C!7CCc                sB  "   \         P                  ! R4       V P                    Rj  xL
  p\         P                  ! RV4       V\        8X  dE   V P	                  4       G Rj  xL
  \         P                  ! R4       \
        P                  ! ^ 4       V\        8X  d-   V P                  P                  4        V P                  4        K  V\        8X  d   V P	                  4       G Rj  xL
  K  V P                  P                  VR7      pVf7   V P                  P                  4        V P                  P                  VR7      pVe-   V P	                  4       G Rj  xL
  V P                  V4       EKR  \         P                  ! RV4       EKl   ELh EL0 L L:EDqR# 5i)zJHandle all unread commands.
this will run until it receives CMD_TERMINATE
zWaiting for commandsNzReceived command "%s"ZTerminating)ZkeyzReceived unknown command "%s")r   rF   r1   CMD_TERMINATE_stop_readingrU   rV   CMD_REFRESH_GROUPSr   rI   rJ   CMD_STOP_READINGZfind_start_readingerror)r:   rG   groups   &  r!   rL   ZReaderService._read_commands   sC     	+,,, 	? 	?#LL0#6m#((***]+((##%!!#&&((***KK$$$-E}##%((S(1 ((***##E*LL8#>9	? + + +1 -s]   #FFFF7F$F%BF*F+A3FF2FFFFFFc                	s  "    \         P                  ! ^4      G Rj  xL
  V P                  4       '       d   K7  V P                  4       G Rj  xL
  \        P
                  ! R4       \        P                  ! ^4       K}   Lb L45i)TNzPipes broken, exiting)r6   rS   rB   rY   r   rF   rU   rV   rO   rP   r!   rN   Z#ReaderService._stop_if_pipes_broken   s]      --"""##%%((***45	 #*s&   BB BBB3BBc               r=   r>   r   r'   r(   r!   r)   r*      s     $ $T $r    c                s2    \        V P                  4      ^ 8  # )zBCheck if the ReaderService is currently sending events to the GUI.)Zlenr5   rO   rP   r!   rT   ZReaderService._is_reading   s    4;;!##r    c               r=   )r$   r^   r   r   r'   r(   r!   r)   r*      s     ? ?F ?r    c                s$   . pVP                    F`  p \        P                  ! V4      pTP                  RR7      p\        T9   g   \        T9   g   \        T9   g   KO  TP                  T4       Kb  	  V P                  V4      pV FV  p\        WdV P                  4      pV P                  P!                  \"        P$                  ! VP'                  4       4      4       KX  	  R#   \        \        3 d    \
        P                  ! RT4         R# i ; i)zWFind all devices of that group, filter interesting ones and send the events
to the gui.zCould not find "%s"NFZabsinfo)ZpathsevdevZInputDeviceZFileNotFoundErrorZOSErrorr   r]   capabilitiesr   r   r   append_create_event_pipeliner   r7   r5   Zaddr6   Zcreate_taskrQ   )r:   r^   sourcesrA   devicera   ZcontextZreaders   &&      r!   r\   ZReaderService._start_reading   s     KKD**40
 "..u.=L,&\)\)v&   --g6F $2B2BCFKKOOG//

=>  &w/ 2D9s   C""(DDc                s  "   V P                   P                  4        V P                  '       d'   \        P                  ! V P                  !  G Rj  xL
  \        4       V n        V P                   P                  4        R#  L/5i)zStop the running event_reader.N)r7   r4   r5   r6   rK   ZclearrO   rP   r!   rY   ZReaderService._stop_reading  sV     ;;;..$++...e  /s   ABB 0Bc                    V ^8  d   QhRRRR/# )r$   rd   zList[evdev.InputDevice]r&   ContextDummyr   r'   r(   r!   r)   r*     s     a a.E a, ar    c           
     s   \        4       pV EF  p\        V4      pVP                  RR7      pVP                  \        4      ;'       g    R F9  p\        \        WdR7      pVP                  V\        V P                  4      4       K;  	  VP                  \        4      ;'       g    R EF  p\        \        V^VR7      p\        \        V.4      RRR7      p\        \        V.4      VV P                  4      p	V	P                  \        V P                  4      4       VP                  Wy4       VP                  RR7      p\        \        V.4      RRR7      p\        \        V.4      VV P                  4      p	V	P                  \        V P                  4      4       VP                  Wy4       EK  	  VP                  \         4      ;'       g    R EF,  p\        \         VV P"                  V,          VR7      p\        \        V.4      RRR	R
R7      p\%        \        V.4      VV P                  4      p	V	P                  \        V P                  4      4       VP                  Wy4       VP                  V P"                  V,          ) R7      p\        \        V.4      RRR	R
R7      p\%        \        V.4      VV P                  4      p	V	P                  \        V P                  4      4       VP                  Wy4       EK/  	  EK  	  V# )zCreate a custom event pipeline for each event code in the capabilities.

Instead of sending the events to an uinput they will be sent to the frontend.
Fr_   )r+   codeorigin_hash)r+   rh   analog_thresholdri   ZkeyboardZKEY_A)input_combinationtarget_uinputoutput_symbol)rj   g333333?T)rk   rl   rm   Zrelease_timeoutZforce_release_timeoutr   i)rg   r   ra   Zgetr   r   add_handlerForwardToUIHandlerr0   r   r   r
   r   r%   Zset_sub_handlermodifyr   rel_xy_speedr   )
r:   rd   Zcontext_dummyre   Zdevice_hashra   Zev_codeinput_configZmappinghandlers
   &&        r!   rc   Z$ReaderService._create_event_pipeline  s   
 %F)&1K!..u.=L'++F399r9*g  )) "4T5G5G"H	 : (++F399r9* %' +	  "&6~&F",")
 +:$l^4''+
 ''(:4;M;M(NO)),@  ,22C2H!&6~&F",")
 *$l^4''
 ''(:4;M;M(NO)),@E :H (++F399r9* %)%6%6w%? +	  "&6~&F",")$'*. *$l^4''
 ''(:4;M;M(NO)),@  ,22&*&7&7&@%@  3   "&6~&F",")$'*. *$l^4''
 ''(:4;M;M(NO)),@Q :a t r    )r1   r3   r0   r.   r7   r5   r%   r   Ni  )__name__
__module____qualname____firstlineno____doc__r   rq   r	   r   r"   Z__annotations__r#   r<   staticmethodr/   rB   rD   rH   rQ   rJ   rM   rL   rN   rT   r\   rY   rc   __static_attributes__r   r    r!   r   r   S   s     y)LL L %s$  J 
 
 $ $   	V 	V
V
2!?F	$?2!a ar    r   c                  s&    ] tR tRt]R 4       tRtR# )ForwardDummyi  c                 	    R # Nr   )rW   s   *r!   writeZForwardDummy.write  s    r    r   N)rt   ru   rv   rw   ry   r~   rz   r   r    r!   r{   r{     s     r    r{   c                  sJ    ] tR tRtRtR tR R ltR R ltR tR	 R
 lt	Rt
R# )rg   i  zIUsed for the reader so that no events are actually written to any uinput.c                	sj    \        4       V n        \        \        4      V n        \        4       V n        R # r}   )r4   	listenersr   Zlist_notify_callbacksr{   forward_dummyrO   rP   r!   r<   ZContextDummy.__init__  s"    !,T!2)^r    c               rf   )r$   rr   r   rs   r   r   r'   r(   r!   r)   ContextDummy.__annotate__  s     U U U>O Ur    c                	sr    V P                   VP                  ,          P                  VP                  4       R # r}   )r   input_match_hashrb   notify)r:   rr   rs   r;   r!   rn   ZContextDummy.add_handler  s%    |<<=DDW^^Tr    c               rf   )r$   input_eventr   r&   zList[NotifyCallback]r   r'   r(   r!   r)   r     s     D D
 D?S Dr    c                	s<    V P                   VP                  ,          # r}   )r   r   )r:   r      &&r!   get_notify_callbacksZ!ContextDummy.get_notify_callbacks  s    %%k&B&BCCr    c                	r|   r}   r   rO   rP   r!   resetZContextDummy.reset      r    c               r=   )r$   r&   zevdev.UInputr   r'   r(   r!   r)   r     s     " " "r    c                s    V P                   # )zDon't actually write anything.)r   )r:   ri   r   r!   get_forward_uinputZContextDummy.get_forward_uinput  s    !!!r    )r   r   r   N)rt   ru   rv   rw   rx   r<   rn   r   r   r   rz   r   r    r!   rg   rg     s%    S,
UD" "r    rg   c                  s<    ] tR tRtRtR R ltR
R R lltR tRtR	# )ro   i  zJImplements the InputEventHandler protocol. Sends all events into the pipe.c               r=   )r$   piper   r   r'   r(   r!   r)   ForwardToUIHandler.__annotate__  s     ? ?T ?r    c                	sH    Wn         \        P                  ! R4      V n        R# )c   N)r   r   r   )r   r   Z
from_tuple_last_event)r:   r   r   r!   r<   ZForwardToUIHandler.__init__  s    	%00>r    c               s(    V ^8  d   QhRRRRRRRR/# )r$   r   r   sourcezevdev.InputDevicesuppressr?   r&   r   r'   r(   r!   r)   r     s2       " 	
 
r    c                s   WP                   8w  d   Wn         \        P                  VP                  9   d   VP	                  RR7      p\
        P                  ! RV4       V P                  P                  R\        RRVP                  RVP                  RVP                  RVP                  RVP                  R	VP                  //4       R
# )z)Filter duplicates and send into the pipe.)valuezSending to %s frontendr+   r,   secusecrh   r   ri   Ti)r   r   Znegative_triggerZactionsrp   r   rF   r   r8   	MSG_EVENTr   r   r+   rh   r   ri   )r:   r   r   r   s   &&&&r!   r   ZForwardToUIHandler.notify  s     $$$$,,=2.LL159IINNIuyy





%u'8'8 
 r    c                	r|   r}   r   rO   rP   r!   r   ZForwardToUIHandler.reset  r   r    )r   r   N)F)	rt   ru   rv   rw   rx   r<   r   r   rz   r   r    r!   ro   ro     s    T?8r    ro   )@rx   Z
__future__r    r6   rE   r2   r@   rC   rU   r-   Zcollectionsr   Ztypingr   r   r   r`   Zevdev.ecodesr   r   r   r   r	   Z"inputremapper.configs.input_configr
   r   Zinputremapper.configs.mappingr   Zinputremapper.groupsr   r   Z$inputremapper.injection.event_readerr   Z&inputremapper.injection.global_uinputsr   Z;inputremapper.injection.mapping_handlers.abs_to_btn_handlerr   Z8inputremapper.injection.mapping_handlers.mapping_handlerr   r   r   Z;inputremapper.injection.mapping_handlers.rel_to_btn_handlerr   Zinputremapper.input_eventr   r   Zinputremapper.ipc.piper   Zinputremapper.logging.loggerr   Zinputremapper.userr   Zinputremapper.utilsr   rX   r[   rZ   rR   r   r9   r   r{   rg   ro   r   r    r!   <module>r      s   (& #    	  
  # # #  F F L 1 0 < @ W 
 X > ' / ( / ! %  
	
m m`	 " ",$ $r    