makcu 2.2.1__py3-none-any.whl → 2.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- makcu/README.md +1 -1
- makcu/connection.py +87 -25
- {makcu-2.2.1.dist-info → makcu-2.2.2.dist-info}/METADATA +2 -2
- {makcu-2.2.1.dist-info → makcu-2.2.2.dist-info}/RECORD +7 -7
- {makcu-2.2.1.dist-info → makcu-2.2.2.dist-info}/WHEEL +0 -0
- {makcu-2.2.1.dist-info → makcu-2.2.2.dist-info}/licenses/LICENSE +0 -0
- {makcu-2.2.1.dist-info → makcu-2.2.2.dist-info}/top_level.txt +0 -0
makcu/README.md
CHANGED
makcu/connection.py
CHANGED
@@ -161,31 +161,33 @@ class SerialTransport:
|
|
161
161
|
content = line.decode('ascii', 'ignore').strip()
|
162
162
|
return ParsedResponse(None, content, False)
|
163
163
|
|
164
|
+
|
164
165
|
def _handle_button_data(self, byte_val: int) -> None:
|
165
166
|
if byte_val == self._last_button_mask:
|
166
167
|
return
|
167
|
-
|
168
|
+
|
168
169
|
changed_bits = byte_val ^ self._last_button_mask
|
170
|
+
print("\n", end='')
|
169
171
|
self._log(f"Button state changed: 0x{self._last_button_mask:02X} -> 0x{byte_val:02X}")
|
170
172
|
|
171
|
-
for bit in range(
|
173
|
+
for bit in range(8):
|
172
174
|
if changed_bits & (1 << bit):
|
173
175
|
is_pressed = bool(byte_val & (1 << bit))
|
174
176
|
button_name = self.BUTTON_MAP[bit] if bit < len(self.BUTTON_MAP) else f"bit{bit}"
|
175
|
-
|
177
|
+
|
176
178
|
self._log(f"Button {button_name}: {'PRESSED' if is_pressed else 'RELEASED'}")
|
177
|
-
|
179
|
+
print(">>> ", end='', flush=True)
|
178
180
|
if is_pressed:
|
179
181
|
self._button_states |= (1 << bit)
|
180
182
|
else:
|
181
183
|
self._button_states &= ~(1 << bit)
|
182
|
-
|
184
|
+
|
183
185
|
if self._button_callback and bit < len(self.BUTTON_ENUM_MAP):
|
184
186
|
try:
|
185
187
|
self._button_callback(self.BUTTON_ENUM_MAP[bit], is_pressed)
|
186
188
|
except Exception as e:
|
187
189
|
self._log(f"Button callback failed: {e}", "ERROR")
|
188
|
-
|
190
|
+
|
189
191
|
self._last_button_mask = byte_val
|
190
192
|
|
191
193
|
def _process_pending_commands(self, content: str) -> None:
|
@@ -234,54 +236,114 @@ class SerialTransport:
|
|
234
236
|
|
235
237
|
def _listen(self) -> None:
|
236
238
|
self._log("Starting listener thread")
|
237
|
-
|
238
239
|
read_buffer = bytearray(4096)
|
239
240
|
line_buffer = bytearray(256)
|
240
241
|
line_pos = 0
|
241
|
-
|
242
242
|
|
243
243
|
serial_read = self.serial.read
|
244
244
|
serial_in_waiting = lambda: self.serial.in_waiting
|
245
245
|
is_connected = lambda: self._is_connected
|
246
246
|
stop_requested = self._stop_event.is_set
|
247
|
-
|
248
247
|
|
249
248
|
last_cleanup = time.time()
|
250
249
|
cleanup_interval = 0.05
|
251
250
|
|
251
|
+
expecting_text_mode = False
|
252
|
+
last_byte = None
|
253
|
+
|
252
254
|
while is_connected() and not stop_requested():
|
253
255
|
try:
|
254
256
|
bytes_available = serial_in_waiting()
|
255
257
|
if not bytes_available:
|
256
258
|
time.sleep(0.001)
|
257
259
|
continue
|
258
|
-
|
260
|
+
|
259
261
|
bytes_read = serial_read(min(bytes_available, 4096))
|
260
|
-
|
261
262
|
for byte_val in bytes_read:
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
if
|
263
|
+
|
264
|
+
if last_byte == 0x0D and byte_val == 0x0A:
|
265
|
+
if line_pos > 0:
|
266
|
+
line = bytes(line_buffer[:line_pos])
|
267
|
+
line_pos = 0
|
268
|
+
if line:
|
269
|
+
response = self._parse_response_line(line)
|
270
|
+
if response.content:
|
271
|
+
self._process_pending_commands(response.content)
|
272
|
+
expecting_text_mode = False
|
273
|
+
|
274
|
+
elif byte_val >= 32 or byte_val in (0x09,):
|
275
|
+
expecting_text_mode = True
|
276
|
+
if line_pos < 256:
|
277
|
+
line_buffer[line_pos] = byte_val
|
278
|
+
line_pos += 1
|
279
|
+
|
280
|
+
elif byte_val == 0x0D:
|
281
|
+
if expecting_text_mode or line_pos > 0:
|
282
|
+
expecting_text_mode = True
|
283
|
+
else:
|
284
|
+
pass
|
285
|
+
|
286
|
+
elif byte_val == 0x0A:
|
287
|
+
last_byte_str = f"0x{last_byte:02X}" if last_byte is not None else "None"
|
288
|
+
# self._log(f"LF detected: last_byte={last_byte_str}, expecting_text={expecting_text_mode}, line_pos={line_pos}", "DEBUG")
|
289
|
+
|
290
|
+
button_combination_detected = False
|
291
|
+
|
292
|
+
if (self._last_button_mask != 0 or
|
293
|
+
(last_byte is not None and last_byte < 32 and last_byte != 0x0D) or
|
294
|
+
(line_pos > 0 and not expecting_text_mode)):
|
295
|
+
|
296
|
+
# self._log("LF: Detected as button combination (right + mouse4 = 0x0A)", "DEBUG")
|
297
|
+
self._handle_button_data(byte_val)
|
298
|
+
expecting_text_mode = False
|
299
|
+
button_combination_detected = True
|
300
|
+
line_pos = 0
|
301
|
+
|
302
|
+
if not button_combination_detected:
|
303
|
+
if last_byte == 0x0D:
|
304
|
+
self._log("LF: Completing CRLF sequence", "DEBUG")
|
305
|
+
if line_pos > 0:
|
306
|
+
line = bytes(line_buffer[:line_pos])
|
307
|
+
line_pos = 0
|
308
|
+
if line:
|
309
|
+
response = self._parse_response_line(line)
|
310
|
+
if response.content:
|
311
|
+
self._process_pending_commands(response.content)
|
312
|
+
expecting_text_mode = False
|
313
|
+
elif line_pos > 0 and expecting_text_mode:
|
314
|
+
self._log("LF: Ending line with text in buffer", "DEBUG")
|
268
315
|
line = bytes(line_buffer[:line_pos])
|
269
316
|
line_pos = 0
|
270
|
-
|
271
317
|
if line:
|
272
318
|
response = self._parse_response_line(line)
|
273
319
|
if response.content:
|
274
320
|
self._process_pending_commands(response.content)
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
321
|
+
expecting_text_mode = False
|
322
|
+
elif expecting_text_mode:
|
323
|
+
self._log("LF: Empty line in text mode", "DEBUG")
|
324
|
+
expecting_text_mode = False
|
325
|
+
else:
|
326
|
+
self._log("LF: Treating as button data (no text context)", "DEBUG")
|
327
|
+
self._handle_button_data(byte_val)
|
328
|
+
expecting_text_mode = False
|
329
|
+
line_pos = 0 # Clear any accumulated data
|
330
|
+
|
331
|
+
elif byte_val < 32:
|
332
|
+
if last_byte == 0x0D:
|
333
|
+
self._log(f"Processing delayed CR as button data: 0x0D", "DEBUG")
|
334
|
+
self._handle_button_data(0x0D)
|
335
|
+
|
336
|
+
self._handle_button_data(byte_val)
|
337
|
+
expecting_text_mode = False
|
338
|
+
line_pos = 0
|
339
|
+
|
340
|
+
last_byte = byte_val
|
341
|
+
|
280
342
|
current_time = time.time()
|
281
343
|
if current_time - last_cleanup > cleanup_interval:
|
282
344
|
self._cleanup_timed_out_commands()
|
283
345
|
last_cleanup = current_time
|
284
|
-
|
346
|
+
|
285
347
|
except serial.SerialException as e:
|
286
348
|
self._log(f"Serial exception in listener: {e}", "ERROR")
|
287
349
|
if self.auto_reconnect:
|
@@ -290,7 +352,7 @@ class SerialTransport:
|
|
290
352
|
break
|
291
353
|
except Exception as e:
|
292
354
|
self._log(f"Unexpected exception in listener: {e}", "ERROR")
|
293
|
-
|
355
|
+
|
294
356
|
self._log("Listener thread ending")
|
295
357
|
|
296
358
|
def _attempt_reconnect(self) -> None:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: makcu
|
3
|
-
Version: 2.2.
|
3
|
+
Version: 2.2.2
|
4
4
|
Summary: Python library for Makcu hardware device control
|
5
5
|
Author: SleepyTotem
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -708,7 +708,7 @@ Requires-Dist: twine>=4.0
|
|
708
708
|
Requires-Dist: rich>=14.0
|
709
709
|
Dynamic: license-file
|
710
710
|
|
711
|
-
# 🖱️ Makcu Python Library v2.2.
|
711
|
+
# 🖱️ Makcu Python Library v2.2.2
|
712
712
|
|
713
713
|
[](https://pypi.org/project/makcu/)
|
714
714
|
[](https://pypi.org/project/makcu/)
|
@@ -1,8 +1,8 @@
|
|
1
|
-
makcu/README.md,sha256=
|
1
|
+
makcu/README.md,sha256=2sEl6BpxwLZpv0B5eDMG-1-6vrAXnUijl5im3NDVbck,10788
|
2
2
|
makcu/__init__.py,sha256=lbWpmF383K2bi1-IFpaLA0G12ITD8NjQVq8t3oIzTI0,448
|
3
3
|
makcu/__main__.py,sha256=duRmMpsNqCKZQfQ-Wj57tIUkZ6hbxLV8MBxWnhyKarY,14527
|
4
4
|
makcu/conftest.py,sha256=EoX2T6dnUvWVI_VvJ0KTes6W82KR4Z69kMQVNtsxV7I,201
|
5
|
-
makcu/connection.py,sha256=
|
5
|
+
makcu/connection.py,sha256=xvgFUPz9JBVHhatlVFtj6zhnfTamT7_o8M3msxOjVMs,23767
|
6
6
|
makcu/controller.py,sha256=EBtiScaOU0CV7NmwVdR3CwFpbT5RymdrNveRKo5ehFU,13242
|
7
7
|
makcu/enums.py,sha256=1SvIv5IoMIfXyoMAq8I5r_aKMVKjYR-L_hXkFLJ_5mw,119
|
8
8
|
makcu/errors.py,sha256=hXdeUCHvbzfqWX3uotG12Xv8EPwWs-5aHQ12xpgwx3Y,229
|
@@ -10,8 +10,8 @@ makcu/makcu.pyi,sha256=UfbX7774u_a9oyIa1rweWqIRoQxVAjhhHUuukDp3jiA,237
|
|
10
10
|
makcu/mouse.py,sha256=YZQDA5OGQlCxCDu3Huzwp5bjH__9yb867iLSVTYOKP4,8157
|
11
11
|
makcu/py.typed,sha256=ks2XNwsNldow4qVp9kuCuGBuHTmngmrzgvRnkzWIGMY,110
|
12
12
|
makcu/test_suite.py,sha256=mfzr7L63Eim1z4-l7WHtWs7szGr6bNk2U13vXVlWeM4,4295
|
13
|
-
makcu-2.2.
|
14
|
-
makcu-2.2.
|
15
|
-
makcu-2.2.
|
16
|
-
makcu-2.2.
|
17
|
-
makcu-2.2.
|
13
|
+
makcu-2.2.2.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
|
14
|
+
makcu-2.2.2.dist-info/METADATA,sha256=a1xZlmx3dgZfhwidbupCWnks-oVpeRfUYj1k-WNl18U,53904
|
15
|
+
makcu-2.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
16
|
+
makcu-2.2.2.dist-info/top_level.txt,sha256=IRO1UVb5LK_ovjau0g4oObyXQqy00tVEE-yF5lPgw1w,6
|
17
|
+
makcu-2.2.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|