-
Notifications
You must be signed in to change notification settings - Fork 0
/
_window.py
139 lines (113 loc) · 4.63 KB
/
_window.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
from difflib import get_close_matches
from dragonfly import (Grammar,
CompoundRule,
Choice, Dictation, Integer)
from dragonfly.windows.monitor import monitors
from dragonfly.windows.rectangle import Rectangle
from dragonfly.windows.window import Window
from log import logger
class PrintWindowDetails(CompoundRule):
spec = 'print window details'
def _process_recognition(self, node, extras):
window = Window.get_foreground()
logger.info('Window details')
logger.info('title=' + window.title)
logger.info('executable=' + window.executable)
def print_all_window_details():
for window in Window.get_all_windows():
if window.is_visible:
window = Window.get_foreground()
logger.info('Window details')
logger.info('title=' + window.title)
logger.info('executable=' + window.executable)
class FocusWindow(CompoundRule):
spec = 'focus <name>'
extras = [Dictation('name')]
@staticmethod
def clean_unwanted_matches(matches, name):
return [m for m in matches if m not in [
'focus ' + name,
'program manager',
'winsplithookhiddenframe']]
def _process_recognition(self, node, extras):
name = extras['name'].format().lower()
windows = [w for w in Window.get_all_windows() if w.is_visible]
names = [w.executable.lower() for w in windows]
names += [w.title.lower() for w in windows]
matches = get_close_matches(name, names, 10, 0.1)
matches = self.clean_unwanted_matches(matches, name)
if not matches: return
for window in windows:
if matches[0] in [window.executable.lower(), window.title.lower()]:
# In Windows, this is not guaranteed to work. See:
# http://stackoverflow.com/questions/688337/how-do-i-force-my-app-to-come-to-the-front-and-take-focus
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539(v=vs.85).asp
window.set_foreground()
return
class BasicWindowOps(CompoundRule):
spec = '<operation> window'
extras = [
Choice('operation', {
'maximize': Window.maximize,
'minimize': Window.minimize,
'restore': Window.restore
})
]
def _process_recognition(self, node, extras):
window = Window.get_foreground()
extras['operation'](window)
class MoveToMonitorRule(CompoundRule):
spec = 'move window to monitor <monitor>'
extras = [Integer('monitor', 1, 9)]
@staticmethod
def move_to_monitor(window, monitor_number):
monitor = monitors[monitor_number].rectangle
current_monitor = window.get_containing_monitor().rectangle
current_position = window.get_position()
pos = Rectangle(
monitor.x1 + current_position.x1 - current_monitor.x1,
monitor.y1 + current_position.y1 - current_monitor.y1,
current_position.dx,
current_position.dy
)
window.set_position(pos)
def _process_recognition(self, node, extras):
monitor_number = int(extras['monitor']) - 1
self.move_to_monitor(Window.get_foreground(), monitor_number)
class SnapWindowRule(CompoundRule):
spec = 'snap window to <region>'
extras = [
Choice('region', {
'top left': [0, 0, 0.5, 0.5],
'top half': [0, 0, 1, 0.5],
'top right': [0.5, 0, 0.5, 0.5],
'right half': [0.5, 0, 0.5, 1],
'bottom right': [0.5, 0.5, 0.5, 0.5],
'bottom half': [0, 0.5, 1, 0.5],
'bottom left': [0, 0.5, 0.5, 0.5],
'left half': [0, 0, 0.5, 1],
'whole monitor': [0, 0, 1, 1],
})]
@staticmethod
def snap_window(window, region_spec):
monitor = window.get_containing_monitor().rectangle
pos = Rectangle(
monitor.x1 + monitor.dx * region_spec[0],
monitor.y1 + monitor.dy * region_spec[1],
monitor.dx * region_spec[2],
monitor.dy * region_spec[3])
window.restore()
window.set_position(pos)
def _process_recognition(self, node, extras):
self.snap_window(Window.get_foreground(), extras['region'])
window_grammar = Grammar('window control')
window_grammar.add_rule(PrintWindowDetails())
window_grammar.add_rule(BasicWindowOps())
window_grammar.add_rule(SnapWindowRule())
window_grammar.add_rule(MoveToMonitorRule())
window_grammar.add_rule(FocusWindow())
window_grammar.load()
def unload():
global window_grammar
if window_grammar: window_grammar.unload()
window_grammar = None