forked from KMKfw/kmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sequences.py
158 lines (115 loc) · 4.57 KB
/
sequences.py
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
import gc
from kmk.consts import UnicodeMode
from kmk.handlers.stock import passthrough
from kmk.keys import KC, make_key
from kmk.types import AttrDict, KeySequenceMeta
def get_wide_ordinal(char):
if len(char) != 2:
return ord(char)
return 0x10000 + (ord(char[0]) - 0xD800) * 0x400 + (ord(char[1]) - 0xDC00)
def sequence_press_handler(key, keyboard, KC, *args, **kwargs):
oldkeys_pressed = keyboard.keys_pressed
keyboard.keys_pressed = set()
for ikey in key.meta.seq:
if not getattr(ikey, 'no_press', None):
keyboard.add_key(ikey)
keyboard._send_hid()
if not getattr(ikey, 'no_release', None):
keyboard.remove_key(ikey)
keyboard._send_hid()
else:
keyboard.tap_key(ikey)
keyboard._send_hid()
keyboard.keys_pressed = oldkeys_pressed
return keyboard
def simple_key_sequence(seq):
return make_key(
meta=KeySequenceMeta(seq),
on_press=sequence_press_handler,
on_release=passthrough,
)
def send_string(message):
seq = []
for char in message:
kc = getattr(KC, char.upper())
if char.isupper():
kc = KC.LSHIFT(kc)
seq.append(kc)
return simple_key_sequence(seq)
IBUS_KEY_COMBO = simple_key_sequence((KC.LCTRL(KC.LSHIFT(KC.U)),))
RALT_KEY = simple_key_sequence((KC.RALT,))
U_KEY = simple_key_sequence((KC.U,))
ENTER_KEY = simple_key_sequence((KC.ENTER,))
RALT_DOWN_NO_RELEASE = simple_key_sequence((KC.RALT(no_release=True),))
RALT_UP_NO_PRESS = simple_key_sequence((KC.RALT(no_press=True),))
def compile_unicode_string_sequences(string_table):
'''
Destructively convert ("compile") unicode strings into key sequences. This
will, for RAM saving reasons, empty the input dictionary and trigger
garbage collection.
'''
target = AttrDict()
for k, v in string_table.items():
target[k] = unicode_string_sequence(v)
# now loop through and kill the input dictionary to save RAM
for k in target.keys():
del string_table[k]
gc.collect()
return target
def unicode_string_sequence(unistring):
'''
Allows sending things like (╯°□°)╯︵ ┻━┻ directly, without
manual conversion to Unicode codepoints.
'''
return unicode_codepoint_sequence([hex(get_wide_ordinal(s))[2:] for s in unistring])
def generate_codepoint_keysym_seq(codepoint, expected_length=4):
# To make MacOS and Windows happy, always try to send
# sequences that are of length 4 at a minimum
# On Linux systems, we can happily send longer strings.
# They will almost certainly break on MacOS and Windows,
# but this is a documentation problem more than anything.
# Not sure how to send emojis on Mac/Windows like that,
# though, since (for example) the Canadian flag is assembled
# from two five-character codepoints, 1f1e8 and 1f1e6
seq = [KC.N0 for _ in range(max(len(codepoint), expected_length))]
for idx, codepoint_fragment in enumerate(reversed(codepoint)):
seq[-(idx + 1)] = KC.__getattr__(codepoint_fragment.upper())
return seq
def unicode_codepoint_sequence(codepoints):
kc_seqs = (generate_codepoint_keysym_seq(codepoint) for codepoint in codepoints)
kc_macros = [simple_key_sequence(kc_seq) for kc_seq in kc_seqs]
def _unicode_sequence(key, keyboard, *args, **kwargs):
if keyboard.unicode_mode == UnicodeMode.IBUS:
keyboard.process_key(
simple_key_sequence(_ibus_unicode_sequence(kc_macros, keyboard)), True
)
elif keyboard.unicode_mode == UnicodeMode.RALT:
keyboard.process_key(
simple_key_sequence(_ralt_unicode_sequence(kc_macros, keyboard)), True
)
elif keyboard.unicode_mode == UnicodeMode.WINC:
keyboard.process_key(
simple_key_sequence(_winc_unicode_sequence(kc_macros, keyboard)), True
)
return make_key(on_press=_unicode_sequence)
def _ralt_unicode_sequence(kc_macros, keyboard):
for kc_macro in kc_macros:
yield RALT_DOWN_NO_RELEASE
yield kc_macro
yield RALT_UP_NO_PRESS
def _ibus_unicode_sequence(kc_macros, keyboard):
for kc_macro in kc_macros:
yield IBUS_KEY_COMBO
yield kc_macro
yield ENTER_KEY
def _winc_unicode_sequence(kc_macros, keyboard):
'''
Send unicode sequence using WinCompose:
http://wincompose.info/
https://github.com/SamHocevar/wincompose
'''
for kc_macro in kc_macros:
yield RALT_KEY
yield U_KEY
yield kc_macro
yield ENTER_KEY