This repository has been archived by the owner on Nov 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.py
165 lines (134 loc) · 5.58 KB
/
app.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
from pyexpat.errors import messages
from textual import on
from textual.app import App, ComposeResult
from textual.containers import Center
from textual.reactive import reactive
from textual.widgets import Static, Label, Input, Select, Button, Header, Footer
import win32gui
import win32process
import psutil
import json
import serial
import serial.tools.list_ports
loaded_profiles = dict()
active_window = str()
selected_port = str()
def send_values_to_mouse(self):
# Open serial
ser = serial.Serial(selected_port, 25000, timeout=1)
send_list = []
for widget in self.app.query(NewInput):
if active_window in loaded_profiles:
if widget.id in loaded_profiles[active_window]:
widget.value = loaded_profiles[active_window][widget.id]
else:
widget.value = widget.initial_value
send_list.append(f'{widget.id}={widget.value},')
# Remove last comma
send_list[-1] = send_list[-1][:-1]
send_list.append('\n')
message = ''.join(send_list)
ser.write(message.encode('utf-8'))
# Close serial
ser.close()
def load_json():
try:
with open("profiles.json", "r") as profiles:
return json.load(profiles)
except FileNotFoundError:
# If there is no json file, make one
with open('profiles.json', 'w') as profiles:
json.dump({}, profiles)
return {}
def save_json(profiles_to_save):
with open("profiles.json", "w") as profiles:
json.dump(profiles_to_save, profiles)
class ActiveApp(Static):
"""A widget to monitor active window app in order to update Spacemouse profiles"""
active_window = reactive(str('None'))
last_window = reactive(str('None'))
def on_mount(self) -> None:
global loaded_profiles
loaded_profiles = load_json()
if not loaded_profiles:
loaded_profiles = dict()
self.active_window = self.set_interval(0.2, self.get_active_window)
def get_active_window(self):
current_window = win32gui.GetForegroundWindow()
if current_window != self.last_window:
_, pid = win32process.GetWindowThreadProcessId(current_window)
# Sometimes can't get the process PID so we continue and try again
global active_window
try:
process = psutil.Process(pid)
if process.name() in ('WindowsTerminal.exe', 'explorer.exe', 'cmd.exe'):
if self.last_window == 'None':
self.active_window = 'None'
active_window = self.active_window
else:
self.active_window = process.name()
active_window = self.app.sub_title = self.active_window
self.last_window = current_window
send_values_to_mouse(self)
except:
pass
class NewInput(Input):
def __init__(self, in_value, *args, **kwargs):
super().__init__(*args, **kwargs)
self.initial_value = in_value
class InputSensitivity(Static):
def __init__(self, in_label, in_value):
super().__init__()
self.in_label = in_label
self.in_value = in_value
def get_input_initial_value(self):
return self.in_value
def compose(self) -> ComposeResult:
yield Label(f'{self.in_label} (default:{self.in_value})')
yield NewInput(placeholder=self.in_label, type='number', value=self.in_value, in_value=self.in_value,
id=self.in_label, classes='input')
def on_input_changed(self, event: NewInput.Changed) -> None:
global loaded_profiles
input_id = event.input.id
if active_window != '' and active_window != 'None':
if active_window in loaded_profiles:
loaded_profiles[active_window][input_id] = event.input.value
else:
loaded_profiles[active_window] = {input_id: event.input.value}
save_json(loaded_profiles)
class SpacemouseProfiles(App):
ports = [p.device for p in list(serial.tools.list_ports.comports())]
ports = [(line, line) for line in ports]
BINDINGS = [("q", 'quit', "Close app")]
CSS_PATH = 'app.tcss'
def compose(self) -> ComposeResult:
yield Header(name='test')
yield Center(ActiveApp())
yield Label(f'Select COM port:')
yield Select(self.ports, value=self.ports[0][1])
yield Center(InputSensitivity('TRANSX_SENSITIVITY', str(5)))
yield Center(InputSensitivity('TRANSY_SENSITIVITY', str(5)))
yield Center(InputSensitivity('POS_TRANSZ_SENSITIVITY', str(5)))
yield Center(InputSensitivity('NEG_TRANSZ_SENSITIVITY', str(5)))
yield Center(InputSensitivity('GATE_NEG_TRANSZ', str(15)))
yield Center(InputSensitivity('GATE_ROTX', str(15)))
yield Center(InputSensitivity('GATE_ROTY', str(15)))
yield Center(InputSensitivity('GATE_ROTZ', str(75)))
yield Center(InputSensitivity('ROTX_SENSITIVITY', str(1.5)))
yield Center(InputSensitivity('ROTY_SENSITIVITY', str(1.5)))
yield Center(InputSensitivity('ROTZ_SENSITIVITY', str(5)))
yield Center(Button.success("Save"))
yield Footer()
def on_mount(self):
global selected_port
selected_port = self.query_one(Select).value
@on(Select.Changed)
def select_changed(self, event: Select.Changed) -> None:
global selected_port
selected_port = str(event.value)
@on(Button.Pressed)
def button_pressed(self) -> None:
send_values_to_mouse(self)
if __name__ == "__main__":
app = SpacemouseProfiles()
app.run()