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
|
#!/usr/bin/env python3
# vim_layer.py - System-wide Vim bindings
import evdev
from evdev import InputDevice, categorize, ecodes
import subprocess
import threading
class VimLayer:
def __init__(self):
self.insert_mode = True
self.devices = self.find_keyboards()
def find_keyboards(self):
devices = []
for path in evdev.list_devices():
device = InputDevice(path)
if ecodes.EV_KEY in device.capabilities():
devices.append(device)
return devices
def toggle_mode(self):
self.insert_mode = not self.insert_mode
print(f"Mode: {'INSERT' if self.insert_mode else 'NORMAL'}")
def handle_normal_mode(self, key):
"""Handle Vim-like commands in normal mode"""
key_mappings = {
'h': 'xdotool key Left',
'j': 'xdotool key Down',
'k': 'xdotool key Up',
'l': 'xdotool key Right',
'w': 'xdotool key ctrl+Right',
'b': 'xdotool key ctrl+Left',
'0': 'xdotool key Home',
'$': 'xdotool key End',
'gg': 'xdotool key ctrl+Home',
'G': 'xdotool key ctrl+End',
'dd': 'xdotool key Home shift+End Delete',
'yy': 'xdotool key Home shift+End ctrl+c',
'p': 'xdotool key ctrl+v',
'i': lambda: self.toggle_mode(),
'a': lambda: [subprocess.run(['xdotool', 'key', 'Right']), self.toggle_mode()],
}
if key in key_mappings:
action = key_mappings[key]
if callable(action):
action()
else:
subprocess.run(action.split())
def listen(self):
for device in self.devices:
threading.Thread(target=self.process_device, args=(device,)).start()
def process_device(self, device):
for event in device.read_loop():
if event.type == ecodes.EV_KEY and event.value == 1: # Key press
key = ecodes.KEY[event.code]
if key == 'KEY_ESC':
self.insert_mode = False
elif not self.insert_mode:
self.handle_normal_mode(key.replace('KEY_', '').lower())
if __name__ == '__main__':
vim_layer = VimLayer()
vim_layer.listen()
|