-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusbkeys.py
More file actions
executable file
·164 lines (144 loc) · 5.01 KB
/
Copy pathusbkeys.py
File metadata and controls
executable file
·164 lines (144 loc) · 5.01 KB
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python3
"""
Manipulate kernel scancode translation table or trace USB keyboard events
on a GPD Pocket laptop
Using the 半/全 key requires the Japanese keyboard fw - download at
https://mega.nz/#!B3hA0KzQ!Tf2KdyqDH58klad3OjeNjPQ-qe7K_KOHppJV20VK7fQ
or https://www.gpd.hk/gpdp2firmware . Installer is Windows only. If not
installed the scancode generated is the same as "`" key
"""
import sys, argparse, ctypes, fcntl
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--get", "-g", help="Convert scancode to 'keycode'")
parser.add_argument(
"--set", "-s", nargs=2, help="Args: SCANCODE KEYCODE")
parser.add_argument(
"--trace", action="store_true", help="Print input events")
parser.add_argument(
"--down", action="store_true",
help="Don't print key release events")
parser.add_argument(
"--sysrq", action="store_true",
help="\
Set Japanese Key to SysRq on GPD Pocket 2 keyboard (Japanese firmware)")
parser.add_argument(
"--insert", action="store_true",
help="\
Set Japanese Key to Insert on GPD Pocket 2 keyboard (Japanese firmware)")
parser.add_argument(
"--alt", action="store_true", help="Set CapsLK key to be AltGr")
args = parser.parse_args()
bpfText="""
// For struct hid_usage
#include <linux/hid.h>
// Can have only primitive types. Nested structures not allowed
struct data {
unsigned type;
unsigned scancode;
unsigned keycode;
s32 value;
};
BPF_PERF_OUTPUT(events);
int on_hid_p_e(struct pt_regs *ctx, struct hid_device *hid,
struct hid_field *field, struct hid_usage *usage, s32 value)
{
struct data data = {usage->type, usage->hid, usage->code, value};
events.perf_submit(ctx, &data, sizeof(data));
return 0;
}
"""
class Trace:
def __init__(self, args):
self.args = args
def run(self):
import bcc
self.b = b = bcc.BPF(text=bpfText)
b.attach_kprobe(event="hid_process_event", fn_name="on_hid_p_e")
b["events"].open_perf_buffer(self.print)
sys.stderr.write("Tracing HID events...\n")
while 1:
try:
b.perf_buffer_poll()
except KeyboardInterrupt:
exit()
def print(self, cpu, data, size):
ev = self.b["events"].event(data)
if self.args.down and ev.value != 1:
return
print("type=%d scancode=%d keycode=%d value=%d" % (
ev.type, ev.scancode, ev.keycode, ev.value))
class ScancodeField(ctypes.Union):
_fields_ = ("buffer", ctypes.c_ubyte * 32), ("u32", ctypes.c_uint32)
class InputKeymapEntry(ctypes.Structure):
_fields_ =\
("flags", ctypes.c_ubyte),\
("len", ctypes.c_ubyte),\
("index", ctypes.c_uint16),\
("keycode", ctypes.c_uint32),\
("scancode", ScancodeField)
if ctypes.sizeof(InputKeymapEntry) != 40:
raise Exception(
"sizeof(InputKeymapEntry) = %d" % ctypes.sizeof(InputKeymapEntry))
class Keyboard:
EVIOCGKEYCODE_V2 = 0x80284504
EVIOCSKEYCODE_V2 = 0x40284504
def __init__(self):
self.path =\
"/dev/input/by-id/usb-HAILUCK_CO._LTD_USB_KEYBOARD-event-kbd"
self.f = open(self.path)
def printKeycode(self, scancode):
mem = InputKeymapEntry(len=4)
mem.scancode.u32 = scancode
fcntl.ioctl(self.f, self.EVIOCGKEYCODE_V2, mem)
self.printMapEntry(mem)
def printMapEntry(self, mem, oldKeycode=None):
if oldKeycode is None:
note = ""
elif oldKeycode == mem.keycode:
note = " (not changed)"
else:
note = " (was %d)" % oldKeycode
print("scancode=%d keycode=%d%s" % (
mem.scancode.u32, mem.keycode, note))
def setKeycode(self, scancode, keycode):
scancode = int(scancode)
keycode = int(keycode)
mem = InputKeymapEntry(len=4)
mem.scancode.u32 = scancode
fcntl.ioctl(self.f, self.EVIOCGKEYCODE_V2, mem)
oldKeycode = mem.keycode
mem.keycode = keycode
fcntl.ioctl(self.f, self.EVIOCSKEYCODE_V2, mem)
self.printMapEntry(mem, oldKeycode)
return self
def setupJapaneseKey(self, targetCode):
path = "/proc/sys/kernel/sysrq"
target = "1"
old = open(path).read().strip()
open(path, "w").write(target)
if old != target:
print("Changed %s from '%s' to '%s'" % (path, old, target))
self.setKeycode(458805, targetCode)
# Fix "`"
return self.setKeycode(458889, 41)
def setupAlt(self):
return self.setKeycode(458809, 100)
if args.sysrq:
if args.insert:
sys.stderr.write("Can't be `--sysrq` and ``insert`\n")
sys.exit(1)
Keyboard().setupJapaneseKey(99)
elif args.insert:
Keyboard().setupJapaneseKey(110)
if args.alt:
Keyboard().setupAlt()
if args.set:
Keyboard().setKeycode(*args.set)
if args.get:
Keyboard().printKeycode(int(args.get))
if args.trace or args.down:
Trace(args).run()
if not (args.trace or args.down or args.get or args.set or
args.insert or args.sysrq or args.alt):
parser.print_help()