summaryrefslogtreecommitdiff
path: root/main.py
blob: b4485547953f579dd4f4e6e882c687e3ff4aea0c (plain)
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
import threading
import Xlib
from Xlib.display import Display
from Xlib import X, XK
from Xlib.protocol import event

from normal import normal_mode

class Manager():
    def __init__(self, inkscape_id):
        self.id = inkscape_id
        self.disp = Display()
        self.screen = self.disp.screen()
        self.root = self.screen.root

        self.inkscape = self.disp.create_resource_object('window', inkscape_id)
        self.mode = normal_mode

    def event(self, name, detail, state):
        return name(
            time=X.CurrentTime,
            root=self.root,
            window=self.inkscape,
            same_screen=0, child=Xlib.X.NONE,
            root_x=0, root_y=0, event_x=0, event_y=0,
            state=state,
            detail=detail
        )

    def string_to_keycode(self, key):
        keysym = XK.string_to_keysym(key)
        keycode = self.disp.keysym_to_keycode(keysym)
        return keycode

    def press(self, key, mask=X.NONE):
        keycode = self.string_to_keycode(key)
        self.inkscape.send_event(self.event(event.KeyPress, keycode, mask), propagate=True)
        self.inkscape.send_event(self.event(event.KeyRelease, keycode, mask), propagate=True)
        self.disp.flush()
        self.disp.sync()

    def grab(self):
        self.inkscape.grab_key(X.AnyKey, X.AnyModifier, True, X.GrabModeAsync, X.GrabModeAsync)

        # Ungrab window manager shortcuts (Super + ...)
        self.inkscape.ungrab_key(self.string_to_keycode('Super_L'), X.AnyModifier, True)
        self.inkscape.ungrab_key(self.string_to_keycode('Alt_L'), X.AnyModifier, True)
        self.inkscape.change_attributes(event_mask=X.KeyReleaseMask | X.KeyPressMask | X.StructureNotifyMask)

    def ungrab(self):
        self.inkscape.ungrab_key(X.AnyKey, X.AnyModifier, True)

    def listen(self):
        self.grab()
        while True:
            evt = self.disp.next_event()
            if evt.type in [X.KeyPress, X.KeyRelease]:
                keycode = evt.detail
                keysym = self.disp.keycode_to_keysym(keycode, 0)
                char = XK.keysym_to_string(keysym)
                self.disp.allow_events(X.ReplayKeyboard, X.CurrentTime)

                self.mode(self, evt, char)

            if evt.type == X.DestroyNotify:
                if evt.window.id == self.id:
                    self.ungrab()
                    return


def create(inkscape_id):
    m = Manager(inkscape_id)
    m.listen()

def is_inkscape(window):
    return (window.get_wm_class() and 'inkscape' in window.                        get_wm_class()[0])

def main():
    disp = Display()
    screen = disp.screen()
    root = screen.root

    # First listen for existing windows
    for window in root.query_tree().children:
        if is_inkscape(window):
            print('Found existing window')
            listen = threading.Thread(target=create, args=[window.id])
            listen.start()


    # New windows
    root.change_attributes(event_mask=X.SubstructureNotifyMask)
    while True:
        evt = disp.next_event()
        if evt.type == X.CreateNotify:
            window = evt.window
            try:
                if is_inkscape(window):
                    print('New window!')
                    listen = threading.Thread(target=create, args=[window.id])
                    listen.start()

            except Xlib.error.BadWindow:
                pass

if __name__ == '__main__':
    main()