-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
xmk
executable file
·123 lines (114 loc) · 4.14 KB
/
xmk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#!/usr/bin/env python3
# Copyright 2022 Manna Harbour
# https://github.com/manna-harbour/xmk
import argparse
import datetime
import time
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description='''
See https://github.com/manna-harbour/xmk.
''',
)
parser.add_argument(
'-k',
'--keyboard',
help='Grab and read key events from evdev keyboard device KEYBOARD.')
parser.add_argument(
'-m',
'--map',
help='Translate keycodes to keymap position using map file MAP.')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
'-c',
'--codes',
help='Save keycodes in keymap position order to map file CODES.')
group.add_argument(
'-s',
'--shell',
action="store_true",
help='Output firmware shell commands.')
group.add_argument(
'-r',
'--record',
help='Save timed firmware shell commands to file RECORD.')
group.add_argument(
'-p',
'--play',
help='Read timed firmware shell commands from file PLAY and output firmware shell commands according to timing.')
args = parser.parse_args()
if (args.shell or args.record is not None) and args.map is None:
parser.error("arguments -s/--shell -r/--record require argument -m/--map")
if (args.codes is not None or args.shell or args.record is not None) and args.keyboard is None:
print (args)
parser.error("arguments -c/--codes -s/--shell -r/--record require argument -k/--keyboard")
if args.map is not None:
code_to_index = {}
i = 0
map = open(args.map, 'r')
for line in map.read().splitlines():
codes = line.split()
for code in codes:
if code[0] == '#':
break
else:
code_to_index['KEY_' + code.upper()] = str(i)
i += 1
if args.keyboard is not None:
import evdev
keyboard = evdev.InputDevice(args.keyboard)
keyboard.grab()
if args.record is not None:
record = open(args.record, 'w')
last = datetime.datetime.now()
if args.codes is not None:
codes = open(args.codes, 'w')
if args.codes is not None or args.shell or args.record is not None:
if args.codes is not None:
last_code = None
double = False
for event in keyboard.read_loop():
if event.type == evdev.ecodes.EV_KEY:
if args.codes is not None:
if event.value == 0:
code = evdev.ecodes.KEY[event.code][4:].lower()
if code == last_code:
print ('', flush=True)
print ('', flush=True, file = codes)
if double:
keyboard.close()
codes.close()
exit()
else:
double = True
else:
print (code, end = ' ', flush=True)
print (code, end = ' ', flush=True, file = codes)
last_code = code
double = False
if args.shell or args.record is not None:
code = evdev.ecodes.KEY[event.code]
if code in code_to_index:
index = code_to_index[code]
if event.value == 0:
command = "key release " + index
elif event.value == 1:
command = "key press " + index
else:
command = None
if command is not None:
print (command)
if args.record is not None:
now = datetime.datetime.now()
delta = str((now - last).total_seconds())
last = now
print ('wait ' + delta, file = record)
print (command, file = record)
if args.play is not None:
play = open(args.play, 'r')
for line in play.read().splitlines():
play_args = line.split()
if play_args[0] == 'wait':
time.sleep(float(play_args[1]))
else:
print (line)