forked from jakebian/snaptile
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnaptile.py
executable file
·187 lines (154 loc) · 4.96 KB
/
snaptile.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env python3
from __future__ import print_function
import sys, getopt
import signal
from Xlib import display, X
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
from window import position
from keyutil import get_posmap, initkeys
keymaps = {
"qwerty":
(['Q', 'W', 'E', 'R'],
['A', 'S', 'D', 'F'],
['Z', 'X', 'C', 'V']),
"azerty":
(['A', 'Z', 'E', 'R'],
['Q', 'S', 'D', 'F'],
['W', 'X', 'C', 'V']),
"qwertz":
(['Q', 'W', 'E', 'R'],
['A', 'S', 'D', 'F'],
['Y', 'X', 'C', 'V']),
"colemak":
(['Q', 'W', 'F', 'P'],
['A', 'R', 'S', 'T'],
['Z', 'X', 'C', 'V']),
"dvorak":
(['apostrophe', 'comma', 'period', 'P'],
['A', 'O', 'E', 'U'],
['semicolon', 'Q', 'J', 'K']),
}
dualMonitorKeymaps = {
"qwerty":
(['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I'],
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K'],
['Z', 'X', 'C', 'V', 'B', 'N', 'M', 'comma']),
"azerty":
(['A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I'],
['Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K'],
['W', 'X', 'C', 'V', 'B', 'N', 'comma', 'semicolon']),
"qwertz":
(['Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I'],
['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K'],
['Y', 'X', 'C', 'V', 'B', 'N', 'M', 'comma']),
"colemak":
(['Q', 'W', 'F', 'P', 'G', 'J', 'L', 'U'],
['A', 'R', 'S', 'T', 'D', 'H', 'N', 'E'],
['Z', 'X', 'C', 'V', 'B', 'K', 'M', 'comma']),
"dvorak":
(['apostrophe', 'comma', 'period', 'P', 'Y', 'F', 'G', 'C'],
['A', 'O', 'E', 'U', 'I', 'D', 'H', 'T'],
['semicolon', 'Q', 'J', 'K', 'X', 'B', 'M', 'W']),
}
def autodetectKeyboard():
try:
import sdl2
import sdl2.keyboard
from sdl2 import keycode
sdl2.SDL_Init(sdl2.SDL_INIT_VIDEO)
keys = bytes(sdl2.keyboard.SDL_GetKeyFromScancode(sc) for sc in (keycode.SDL_SCANCODE_Q, keycode.SDL_SCANCODE_W, keycode.SDL_SCANCODE_Y))
keyMap = {
b'qwy': 'qwerty',
b'azy': 'azerty',
b'qwz': 'qwertz',
b'qwj': 'colemak',
b'\',f': 'dvorak',
}
if keys in keyMap:
return keyMap.get(keys, 'unknown')
except:
print("Could not detect keyboard (is PySDL2 installed?). Falling back to qwerty.")
return "qwerty"
def global_inital_states():
displ = display.Display()
rt = displ.screen().root
rt.change_attributes(event_mask=X.KeyPressMask)
return (
displ,
rt,
{
'code': 0,
'pressed': False
},
get_posmap(keymap, displ)
)
global disp, root, lastkey_state, posmap, isDualMonitor;
def run():
mask = None
opts, args = getopt.getopt(sys.argv[1:], "hdWk:")
keyboardLayout = autodetectKeyboard()
global isDualMonitor
isDualMonitor = False
for opt in opts:
if opt[0] == '-h':
print ('Snaptile.py')
print ('-d expanded dual-monitor keybinds')
print ('-W use Windows key')
print ('-h this help text')
print ('-k <keymap> to specify a keyboard layout (eg. qwerty)')
sys.exit()
elif opt[0] == '-d':
isDualMonitor = True
elif opt[0] == '-W':
mask = 'Windows'
elif opt[0] == '-k':
keyboardLayout = opt[1]
global keymap;
keymapSource = keymaps
if isDualMonitor:
keymapSource = dualMonitorKeymaps
if keyboardLayout in keymapSource:
keymap = keymapSource[keyboardLayout]
else:
print("Unsupported keyboard layout. Falling back to qwerty.")
keymap = keymapSource["qwerty"]
global disp, root, lastkey_state, posmap
disp, root, lastkey_state, posmap = global_inital_states()
initkeys(keymap, disp, root, mask)
for _ in range(0, root.display.pending_events()):
root.display.next_event()
GObject.io_add_watch(root.display, GObject.IO_IN, checkevt)
print('Snaptile running. Press CTRL+C to quit.')
signal.signal(signal.SIGINT, signal.SIG_DFL)
signal.signal(signal.SIGTERM, signal.SIG_DFL)
Gtk.main()
def checkevt(_, __, handle=None):
global lastkey_state
handle = handle or root.display
for _ in range(0, handle.pending_events()):
event = handle.next_event()
if event.type == X.KeyPress:
if event.detail not in posmap:
break
if not lastkey_state['pressed']:
handleevt(event.detail, event.detail)
else:
handleevt(lastkey_state['code'], event.detail)
lastkey_state = {
'code': event.detail,
'pressed': True
}
if event.type == X.KeyRelease:
if event.detail == lastkey_state['code']:
lastkey_state['pressed'] = False
return True
def handleevt(startkey, endkey):
position(
posmap[startkey],
posmap[endkey],
isDualMonitor,
)
if __name__ == '__main__':
run()