2323
2424import argparse
2525import asyncio
26+ import functools
27+ import signal
2628from asyncio .events import AbstractEventLoop
2729from collections .abc import Iterable
28- import functools
2930from pathlib import Path
30- import signal
31- from typing import Optional , Sequence , cast
32-
31+ from typing import Any , Collection , Optional , Sequence , TypedDict , cast
3332
3433import evdev
35- from evdev import KeyEvent , ecodes , InputDevice , UInput
3634import pyudev
37- from xdg import BaseDirectory
3835import yaml
36+ from evdev import InputDevice , InputEvent , KeyEvent , UInput , ecodes
37+ from xdg import BaseDirectory
3938
4039DEFAULT_RATE = 0.1 # seconds
41- repeat_tasks = {}
42- remapped_tasks = {}
43- registered_devices = {}
40+ repeat_tasks : dict [int , asyncio .Task ] = {}
41+ remapped_tasks : dict [int , int ] = {}
42+ registered_devices : dict [str , dict [str , Any ]] = {}
43+
44+
45+ class Remapping (TypedDict ):
46+ code : int
47+ value : list [int ]
48+ repeat : bool
49+ count : int
50+ modifier_group : str
51+
52+
53+ type Remappings = dict [int , list [Remapping ]]
54+ type ModifierGroups = dict [str , Remappings ]
55+
56+
57+ class Device (TypedDict ):
58+ input_name : str
59+ input_fn : str
60+ output_name : str
61+ remappings : Remappings
62+ modifier_groups : ModifierGroups
63+
64+
65+ class Config (TypedDict ):
66+ devices : list [Device ]
67+
68+
69+ class ActiveGroup (TypedDict ):
70+ name : str
71+ code : int
4472
4573
4674async def handle_events (
47- input : InputDevice , output : UInput , remappings , modifier_groups
75+ input : InputDevice ,
76+ output : UInput ,
77+ remappings : Remappings ,
78+ modifier_groups : ModifierGroups ,
4879):
49- active_group = {}
80+ active_group : Optional [ ActiveGroup ] = None
5081 try :
5182 async for event in input .async_read_loop ():
83+ event = cast (InputEvent , event )
5284 if not active_group :
5385 active_mappings = remappings
5486 else :
5587 active_mappings = modifier_groups [active_group ["name" ]]
5688
57- if event .code == active_group .get ("code" ) or (
89+ if ( active_group and event .code == active_group .get ("code" ) ) or (
5890 event .code in active_mappings
59- and "modifier_group" in active_mappings . get ( event .code ) [0 ]
91+ and "modifier_group" in active_mappings [ event .code ] [0 ]
6092 ):
6193 if event .value == 1 :
62- active_group [ "name" ] = active_mappings [ event . code ][ 0 ][
63- "modifier_group"
64- ]
65- active_group [ "code" ] = event . code
94+ active_group = {
95+ "name" : active_mappings [ event . code ][ 0 ][ " modifier_group"],
96+ "code" : event . code ,
97+ }
6698 elif event .value == 0 :
67- active_group = {}
99+ active_group = None
68100 else :
69101 if event .code in active_mappings :
70102 remap_event (output , event , active_mappings [event .code ])
@@ -80,7 +112,9 @@ async def handle_events(
80112 input .close ()
81113
82114
83- async def repeat_event (event , rate , count , values , output ):
115+ async def repeat_event (
116+ event : InputEvent , rate : float , count : int , values : list [int ], output : UInput
117+ ):
84118 if count == 0 :
85119 count = - 1
86120 while count != 0 :
@@ -92,7 +126,7 @@ async def repeat_event(event, rate, count, values, output):
92126 await asyncio .sleep (rate )
93127
94128
95- def remap_event (output , event , event_remapping ):
129+ def remap_event (output : UInput , event : InputEvent , event_remapping : list [ Remapping ] ):
96130 for remapping in event_remapping :
97131 original_code = event .code
98132 event .code = remapping ["code" ]
@@ -176,7 +210,7 @@ def remap_event(output, event, event_remapping):
176210# 'mod1': { -- is the same as 'remappings' --}
177211# }
178212# }]
179- def load_config (config_override ):
213+ def load_config (config_override : str ):
180214 conf_path = None
181215 if config_override is None :
182216 for dir in BaseDirectory .load_config_paths ("evdevremapkeys" ):
@@ -191,11 +225,11 @@ def load_config(config_override):
191225 raise NameError ("Cannot open %s" % config_override )
192226
193227 with open (conf_path .as_posix (), "r" ) as fd :
194- config = yaml .safe_load (fd )
228+ config : dict [ str , Any ] = yaml .safe_load (fd )
195229 return parse_config (config )
196230
197231
198- def parse_config (config ) :
232+ def parse_config (config : dict [ str , Any ]) -> Config :
199233 for device in config ["devices" ]:
200234 device ["remappings" ] = normalize_config (device ["remappings" ])
201235 device ["remappings" ] = resolve_ecodes (device ["remappings" ])
@@ -208,7 +242,7 @@ def parse_config(config):
208242 device ["modifier_groups" ][group ]
209243 )
210244
211- return config
245+ return cast ( Config , config )
212246
213247
214248# Converts general config schema
@@ -229,7 +263,7 @@ def parse_config(config):
229263# {'code': 'KEY_Y', 'value': [1,0]]}
230264# ]
231265# }}
232- def normalize_config (remappings ):
266+ def normalize_config (remappings : dict [ str , Any ] ):
233267 norm = {}
234268 for key , mappings in remappings .items ():
235269 new_mappings = []
@@ -243,14 +277,14 @@ def normalize_config(remappings):
243277 return norm
244278
245279
246- def normalize_value (mapping ):
280+ def normalize_value (mapping : dict [ str , Any ] ):
247281 value = mapping .get ("value" )
248282 if value is None or type (value ) is list :
249283 return
250284 mapping ["value" ] = [mapping ["value" ]]
251285
252286
253- def resolve_ecodes (by_name ):
287+ def resolve_ecodes (by_name : dict [ str , Any ] ):
254288 def resolve_mapping (mapping ):
255289 if "code" in mapping :
256290 code = mapping ["code" ]
@@ -270,7 +304,7 @@ def resolve_mapping(mapping):
270304 }
271305
272306
273- def find_input (device ):
307+ def find_input (device : Device ):
274308 name = device .get ("input_name" , None )
275309 phys = device .get ("input_phys" , None )
276310 fn = device .get ("input_fn" , None )
@@ -295,7 +329,7 @@ def find_input(device):
295329 return None
296330
297331
298- def register_device (device , loop : AbstractEventLoop ):
332+ def register_device (device : Device , loop : AbstractEventLoop ):
299333 for value in registered_devices .values ():
300334 if device == value ["device" ]:
301335 return value ["task" ]
@@ -312,11 +346,11 @@ def register_device(device, loop: AbstractEventLoop):
312346 remappings = device ["remappings" ]
313347 extended = set (caps [ecodes .EV_KEY ])
314348
315- modifier_groups = []
349+ modifier_groups : ModifierGroups = {}
316350 if "modifier_groups" in device :
317351 modifier_groups = device ["modifier_groups" ]
318352
319- def flatmap (lst ):
353+ def flatmap (lst : Collection [ Collection [ Any ]] ):
320354 return [l2 for l1 in lst for l2 in l1 ]
321355
322356 for remapping in flatmap (remappings .values ()):
@@ -353,7 +387,7 @@ async def shutdown(loop: AbstractEventLoop):
353387 loop .stop ()
354388
355389
356- def handle_udev_event (monitor , config , loop ):
390+ def handle_udev_event (monitor : pyudev . Monitor , config : Config , loop : AbstractEventLoop ):
357391 count = 0
358392 while True :
359393 device = monitor .poll (0 )
@@ -370,7 +404,7 @@ def create_shutdown_task(loop: AbstractEventLoop):
370404 return loop .create_task (shutdown (loop ))
371405
372406
373- def run_loop (args ):
407+ def run_loop (args : argparse . Namespace ):
374408 context = pyudev .Context ()
375409 monitor = pyudev .Monitor .from_netlink (context )
376410 monitor .filter_by ("input" )
@@ -409,7 +443,7 @@ def list_devices():
409443 yield [device .path , device .phys , device .name ]
410444
411445
412- def read_events (req_device ):
446+ def read_events (req_device : str ):
413447 found : Optional [InputDevice ] = None
414448 for device in list_devices ():
415449 # Look in all 3 identifiers + event number
0 commit comments