makcu 2.2.0__tar.gz → 2.2.1__tar.gz
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-2.2.0 → makcu-2.2.1}/PKG-INFO +3 -2
- {makcu-2.2.0 → makcu-2.2.1}/makcu/README.md +406 -405
- {makcu-2.2.0 → makcu-2.2.1}/makcu/__init__.py +21 -21
- {makcu-2.2.0 → makcu-2.2.1}/makcu/__main__.py +27 -14
- makcu-2.2.1/makcu/conftest.py +8 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu/connection.py +4 -5
- {makcu-2.2.0 → makcu-2.2.1}/makcu/py.typed +1 -1
- {makcu-2.2.0 → makcu-2.2.1}/makcu/test_suite.py +20 -3
- {makcu-2.2.0 → makcu-2.2.1}/makcu.egg-info/PKG-INFO +3 -2
- {makcu-2.2.0 → makcu-2.2.1}/pyproject.toml +1 -1
- makcu-2.2.0/makcu/conftest.py +0 -34
- {makcu-2.2.0 → makcu-2.2.1}/LICENSE +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu/controller.py +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu/enums.py +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu/errors.py +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu/makcu.pyi +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu/mouse.py +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu.egg-info/SOURCES.txt +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu.egg-info/dependency_links.txt +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu.egg-info/requires.txt +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/makcu.egg-info/top_level.txt +0 -0
- {makcu-2.2.0 → makcu-2.2.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: makcu
|
3
|
-
Version: 2.2.
|
3
|
+
Version: 2.2.1
|
4
4
|
Summary: Python library for Makcu hardware device control
|
5
5
|
Author: SleepyTotem
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -1112,4 +1112,5 @@ GPL License © SleepyTotem
|
|
1112
1112
|
|
1113
1113
|
- [GitHub Repository](https://github.com/SleepyTotem/makcu-py-lib)
|
1114
1114
|
- [PyPI Package](https://pypi.org/project/makcu/)
|
1115
|
-
- [Documentation](https://makcu.readthedocs.io/)
|
1115
|
+
- [Documentation](https://makcu-py-lib.readthedocs.io/)
|
1116
|
+
- [Changelog](https://makcu-py-lib.readthedocs.io/en/latest/changelog.html)
|
@@ -1,405 +1,406 @@
|
|
1
|
-
# 🖱️ Makcu Python Library v2.2.0
|
2
|
-
|
3
|
-
[](https://pypi.org/project/makcu/)
|
4
|
-
[](https://pypi.org/project/makcu/)
|
5
|
-
[](LICENSE)
|
6
|
-
|
7
|
-
Makcu Py Lib is a high-performance Python library for controlling Makcu devices — now with **async/await support**, **zero-delay command execution**, and **automatic reconnection**!
|
8
|
-
|
9
|
-
---
|
10
|
-
|
11
|
-
## 📦 Installation
|
12
|
-
|
13
|
-
### Recommended: PyPI
|
14
|
-
|
15
|
-
```bash
|
16
|
-
pip install makcu
|
17
|
-
```
|
18
|
-
|
19
|
-
### From Source
|
20
|
-
|
21
|
-
```bash
|
22
|
-
git clone https://github.com/SleepyTotem/makcu-py-lib
|
23
|
-
cd makcu-py-lib
|
24
|
-
pip install .
|
25
|
-
```
|
26
|
-
|
27
|
-
---
|
28
|
-
|
29
|
-
## 🧠 Quick Start
|
30
|
-
|
31
|
-
### Synchronous API (Classic)
|
32
|
-
|
33
|
-
```python
|
34
|
-
from makcu import create_controller, MouseButton
|
35
|
-
|
36
|
-
# Create and connect
|
37
|
-
makcu = create_controller(debug=True, auto_reconnect=True)
|
38
|
-
|
39
|
-
# Basic operations
|
40
|
-
makcu.click(MouseButton.LEFT)
|
41
|
-
makcu.move(100, 50)
|
42
|
-
makcu.scroll(-1)
|
43
|
-
|
44
|
-
# Human-like interaction
|
45
|
-
makcu.click_human_like(MouseButton.LEFT, count=2, profile="gaming", jitter=3)
|
46
|
-
|
47
|
-
# Clean disconnect
|
48
|
-
makcu.disconnect()
|
49
|
-
```
|
50
|
-
|
51
|
-
### Asynchronous API (New!)
|
52
|
-
|
53
|
-
```python
|
54
|
-
import asyncio
|
55
|
-
from makcu import create_async_controller, MouseButton
|
56
|
-
|
57
|
-
async def main():
|
58
|
-
# Auto-connect with context manager
|
59
|
-
async with await create_async_controller(debug=True) as makcu:
|
60
|
-
# Parallel operations
|
61
|
-
await asyncio.gather(
|
62
|
-
makcu.move(100, 0),
|
63
|
-
makcu.click(MouseButton.LEFT),
|
64
|
-
makcu.scroll(-1)
|
65
|
-
)
|
66
|
-
|
67
|
-
# Human-like clicking
|
68
|
-
await makcu.click_human_like(MouseButton.RIGHT, count=3)
|
69
|
-
|
70
|
-
asyncio.run(main())
|
71
|
-
```
|
72
|
-
|
73
|
-
---
|
74
|
-
|
75
|
-
## 🎮 Core Features
|
76
|
-
|
77
|
-
### Mouse Control
|
78
|
-
|
79
|
-
```python
|
80
|
-
# Button actions
|
81
|
-
await makcu.click(MouseButton.LEFT)
|
82
|
-
await makcu.double_click(MouseButton.RIGHT)
|
83
|
-
await makcu.press(MouseButton.MIDDLE)
|
84
|
-
await makcu.release(MouseButton.MIDDLE)
|
85
|
-
|
86
|
-
# Movement
|
87
|
-
await makcu.move(100, 50) # Relative movement
|
88
|
-
await makcu.move_smooth(200, 100, segments=20) # Smooth interpolation
|
89
|
-
await makcu.move_bezier(150, 150, segments=30, ctrl_x=75, ctrl_y=200) # Bezier curve
|
90
|
-
|
91
|
-
# Scrolling
|
92
|
-
await makcu.scroll(-5) # Scroll down
|
93
|
-
await makcu.scroll(3) # Scroll up
|
94
|
-
|
95
|
-
# Dragging
|
96
|
-
await makcu.drag(0, 0, 300, 200, button=MouseButton.LEFT, duration=1.5)
|
97
|
-
```
|
98
|
-
|
99
|
-
### Button & Axis Locking
|
100
|
-
|
101
|
-
```python
|
102
|
-
# New unified locking API
|
103
|
-
await makcu.lock(MouseButton.LEFT) # Lock left button
|
104
|
-
await makcu.unlock(MouseButton.RIGHT) # Unlock right button
|
105
|
-
await makcu.lock("X") # Lock X-axis movement
|
106
|
-
await makcu.unlock("Y") # Unlock Y-axis movement
|
107
|
-
|
108
|
-
# Query lock states (no delays!)
|
109
|
-
is_locked = await makcu.is_locked(MouseButton.LEFT)
|
110
|
-
all_states = await makcu.get_all_lock_states()
|
111
|
-
# Returns: {"LEFT": True, "RIGHT": False, "X": True, ...}
|
112
|
-
```
|
113
|
-
|
114
|
-
### Human-like Interactions
|
115
|
-
|
116
|
-
```python
|
117
|
-
# Realistic clicking with timing variations
|
118
|
-
await makcu.click_human_like(
|
119
|
-
button=MouseButton.LEFT,
|
120
|
-
count=5,
|
121
|
-
profile="gaming", # "fast", "normal", "slow", "variable", "gaming"
|
122
|
-
jitter=5 # Random mouse movement between clicks
|
123
|
-
)
|
124
|
-
```
|
125
|
-
|
126
|
-
### Button Event Monitoring
|
127
|
-
|
128
|
-
```python
|
129
|
-
# Real-time button monitoring
|
130
|
-
def on_button_event(button: MouseButton, pressed: bool):
|
131
|
-
print(f"{button.name} {'pressed' if pressed else 'released'}")
|
132
|
-
|
133
|
-
makcu.set_button_callback(on_button_event)
|
134
|
-
await makcu.enable_button_monitoring(True)
|
135
|
-
|
136
|
-
# Check current button states
|
137
|
-
states = makcu.get_button_states()
|
138
|
-
if makcu.is_pressed(MouseButton.RIGHT):
|
139
|
-
print("Right button is pressed")
|
140
|
-
```
|
141
|
-
|
142
|
-
### Connection Management
|
143
|
-
|
144
|
-
```python
|
145
|
-
# Auto-reconnection on disconnect
|
146
|
-
makcu = await create_async_controller(auto_reconnect=True)
|
147
|
-
|
148
|
-
# Connection status callbacks
|
149
|
-
@makcu.on_connection_change
|
150
|
-
async def handle_connection(connected: bool):
|
151
|
-
if connected:
|
152
|
-
print("Device reconnected!")
|
153
|
-
else:
|
154
|
-
print("Device disconnected!")
|
155
|
-
|
156
|
-
# Manual reconnection
|
157
|
-
if not makcu.is_connected():
|
158
|
-
await makcu.connect()
|
159
|
-
```
|
160
|
-
|
161
|
-
---
|
162
|
-
|
163
|
-
## 🔧 Advanced Features
|
164
|
-
|
165
|
-
### Batch Operations
|
166
|
-
|
167
|
-
```python
|
168
|
-
# Execute multiple commands efficiently
|
169
|
-
async def combo_action():
|
170
|
-
await makcu.batch_execute([
|
171
|
-
lambda: makcu.move(50, 0),
|
172
|
-
lambda: makcu.click(MouseButton.LEFT),
|
173
|
-
lambda: makcu.move(-50, 0),
|
174
|
-
lambda: makcu.click(MouseButton.RIGHT)
|
175
|
-
])
|
176
|
-
```
|
177
|
-
|
178
|
-
### Device Information
|
179
|
-
|
180
|
-
```python
|
181
|
-
# Get device details
|
182
|
-
info = await makcu.get_device_info()
|
183
|
-
# {'port': 'COM3', 'vid': '0x1a86', 'pid': '0x55d3', ...}
|
184
|
-
|
185
|
-
# Firmware version
|
186
|
-
version = await makcu.get_firmware_version()
|
187
|
-
```
|
188
|
-
|
189
|
-
### Serial Spoofing
|
190
|
-
|
191
|
-
```python
|
192
|
-
# Spoof device serial
|
193
|
-
await makcu.spoof_serial("CUSTOM123456")
|
194
|
-
|
195
|
-
# Reset to default
|
196
|
-
await makcu.reset_serial()
|
197
|
-
```
|
198
|
-
|
199
|
-
### Low-Level Access
|
200
|
-
|
201
|
-
```python
|
202
|
-
# Send raw commands with tracked responses
|
203
|
-
response = await makcu.transport.async_send_command(
|
204
|
-
"km.version()",
|
205
|
-
expect_response=True,
|
206
|
-
timeout=0.1 # Optimized for gaming
|
207
|
-
)
|
208
|
-
```
|
209
|
-
|
210
|
-
---
|
211
|
-
|
212
|
-
## 🧪 Command-Line Tools
|
213
|
-
|
214
|
-
```bash
|
215
|
-
# Interactive debug console
|
216
|
-
python -m makcu --debug
|
217
|
-
|
218
|
-
# Test specific port
|
219
|
-
python -m makcu --testPort COM3
|
220
|
-
|
221
|
-
# Run automated tests
|
222
|
-
python -m makcu --runtest
|
223
|
-
```
|
224
|
-
|
225
|
-
### Tool Descriptions
|
226
|
-
|
227
|
-
- `--debug`: Launches an interactive console where you can type raw device commands and see live responses.
|
228
|
-
- `--testPort COMx`: Attempts to connect to the given COM port and reports success or failure.
|
229
|
-
- `--runtest`: Runs `test_suite.py` using `pytest` and opens a detailed HTML test report.
|
230
|
-
|
231
|
-
---
|
232
|
-
|
233
|
-
### Test Suite
|
234
|
-
|
235
|
-
- File: `test_suite.py`
|
236
|
-
- Run with: `python -m makcu --runtest`
|
237
|
-
- Output: `latest_pytest.html`
|
238
|
-
|
239
|
-
Includes tests for:
|
240
|
-
- Port connection
|
241
|
-
- Firmware version check
|
242
|
-
- Mouse movement and button control
|
243
|
-
- Button masking and locking
|
244
|
-
|
245
|
-
---
|
246
|
-
|
247
|
-
## Test Timings (v1.3 vs v1.4 vs v2.0)
|
248
|
-
|
249
|
-
| Test Name | v1.3 | v1.4 | v2.0 | Improvement (v1.3 → v2.0) |
|
250
|
-
|--------------------------|--------|-------|-------|----------------------------|
|
251
|
-
| connect_to_port | ~100ms | ~55ms | **46ms** | ~2.2x faster |
|
252
|
-
| press_and_release | ~18ms | ~9ms | **1ms** | ~18x faster |
|
253
|
-
| firmware_version | ~20ms | ~9ms | **1ms** | ~20x faster |
|
254
|
-
| middle_click | ~18ms | ~9ms | **1ms** | ~18x faster |
|
255
|
-
| device_info | ~25ms | ~13ms | **6ms** | ~4.1x faster |
|
256
|
-
| port_connection | ~20ms | ~9ms | **1ms** | ~20x faster |
|
257
|
-
| button_mask | ~17ms | ~8ms | **1ms** | ~17x faster |
|
258
|
-
| get_button_states | ~18ms | ~9ms | **1ms** | ~18x faster |
|
259
|
-
| lock_state | ~33ms | ~10ms | **1ms** | ~33x faster |
|
260
|
-
| makcu_behavior | ~20ms | ~10ms | **1ms** | ~20x faster |
|
261
|
-
| batch_commands | ~350ms | ~90ms | **3ms** | ~117x faster |
|
262
|
-
| rapid_moves | ~17ms | ~8ms | **2ms** | ~8.5x faster |
|
263
|
-
| button_performance | ~18ms | ~9ms | **2ms** | ~9x faster |
|
264
|
-
| mixed_operations | ~22ms | ~10ms | **2ms** | ~11x faster |
|
265
|
-
|
266
|
-
Based on the measured test suite, v2.0 is on average **~17× faster** than v1.3 across all core operations.
|
267
|
-
|
268
|
-
|
269
|
-
### Gaming Performance Targets (v2.0)
|
270
|
-
|
271
|
-
- **144Hz Gaming**: 7ms frame time — ✅ Easily met (avg 1–3ms per operation)
|
272
|
-
- **240Hz Gaming**: 4.2ms frame time — ✅ Consistently met (most ops ≤ 2ms)
|
273
|
-
- **360Hz Gaming**: 2.8ms frame time — ⚡ Achievable for atomic/single ops
|
274
|
-
|
275
|
-
---
|
276
|
-
|
277
|
-
## 🏎️ Performance Optimization Details
|
278
|
-
|
279
|
-
### Version History & Performance
|
280
|
-
|
281
|
-
- **v1.3 and earlier**: Original implementation with sleep delays
|
282
|
-
- **v1.4**: Initial optimizations, removed some sleep delays
|
283
|
-
- **v2.0**: Complete rewrite with zero-delay architecture
|
284
|
-
|
285
|
-
### Key Optimizations in v2.0
|
286
|
-
|
287
|
-
1. **Pre-computed Commands**: All commands are pre-formatted at initialization
|
288
|
-
2. **Bitwise Operations**: Button states use single integer with bit manipulation
|
289
|
-
3. **Zero-Copy Buffers**: Pre-allocated buffers for parsing
|
290
|
-
4. **Reduced Timeouts**: Gaming-optimized timeouts (100ms default)
|
291
|
-
5. **Cache Everything**: Connection states, lock states, and device info cached
|
292
|
-
6. **Minimal Allocations**: Reuse objects and avoid string formatting
|
293
|
-
7. **Fast Serial Settings**: 1ms read timeout, 10ms write timeout
|
294
|
-
8. **Optimized Listener**: Batch processing with minimal overhead
|
295
|
-
|
296
|
-
### Tips for Maximum Performance
|
297
|
-
|
298
|
-
```python
|
299
|
-
# Disable debug mode in production
|
300
|
-
makcu = create_controller(debug=False)
|
301
|
-
|
302
|
-
# Use cached connection checks
|
303
|
-
if makcu.is_connected(): # Cached, no serial check
|
304
|
-
makcu.click(MouseButton.LEFT)
|
305
|
-
|
306
|
-
# Batch similar operations
|
307
|
-
with makcu: # Context manager ensures connection
|
308
|
-
for _ in range(10):
|
309
|
-
makcu.move(10, 0) # No connection check per call
|
310
|
-
```
|
311
|
-
|
312
|
-
---
|
313
|
-
|
314
|
-
## 🔍 Debugging
|
315
|
-
|
316
|
-
Enable debug mode for detailed logging:
|
317
|
-
|
318
|
-
```python
|
319
|
-
makcu = await create_async_controller(debug=True)
|
320
|
-
|
321
|
-
# View command flow (optimized timestamps)
|
322
|
-
# [123.456] [INFO] Sent command #42: km.move(100,50)
|
323
|
-
# [123.458] [DEBUG] Command #42 completed in 0.002s
|
324
|
-
```
|
325
|
-
|
326
|
-
---
|
327
|
-
|
328
|
-
## 🏗️ Migration from v1.x
|
329
|
-
|
330
|
-
Most code works without changes! Key differences:
|
331
|
-
|
332
|
-
```python
|
333
|
-
# v1.x (still works)
|
334
|
-
makcu = create_controller()
|
335
|
-
makcu.move(100, 100)
|
336
|
-
|
337
|
-
# v2.0 (async)
|
338
|
-
makcu = await create_async_controller()
|
339
|
-
await makcu.move(100, 100)
|
340
|
-
|
341
|
-
# v2.0 context manager (auto cleanup)
|
342
|
-
async with await create_async_controller() as makcu:
|
343
|
-
await makcu.click(MouseButton.LEFT)
|
344
|
-
```
|
345
|
-
|
346
|
-
---
|
347
|
-
|
348
|
-
## 📚 API Reference
|
349
|
-
|
350
|
-
### Enumerations
|
351
|
-
|
352
|
-
```python
|
353
|
-
from makcu import MouseButton
|
354
|
-
|
355
|
-
MouseButton.LEFT # Left mouse button
|
356
|
-
MouseButton.RIGHT # Right mouse button
|
357
|
-
MouseButton.MIDDLE # Middle mouse button
|
358
|
-
MouseButton.MOUSE4 # Side button 1
|
359
|
-
MouseButton.MOUSE5 # Side button 2
|
360
|
-
```
|
361
|
-
|
362
|
-
### Exception Handling
|
363
|
-
|
364
|
-
```python
|
365
|
-
from makcu import MakcuError, MakcuConnectionError, MakcuTimeoutError
|
366
|
-
|
367
|
-
try:
|
368
|
-
makcu = await create_async_controller()
|
369
|
-
except MakcuConnectionError as e:
|
370
|
-
print(f"Connection failed: {e}")
|
371
|
-
except MakcuTimeoutError as e:
|
372
|
-
print(f"Command timed out: {e}")
|
373
|
-
```
|
374
|
-
|
375
|
-
---
|
376
|
-
|
377
|
-
## 🛠️ Technical Details
|
378
|
-
|
379
|
-
- **Protocol**: CH343 USB serial at 4Mbps
|
380
|
-
- **Command Format**: ASCII with optional ID tracking (`command#ID`)
|
381
|
-
- **Response Format**: `>>> #ID:response` for tracked commands
|
382
|
-
- **Threading**: High-priority listener thread with async bridge
|
383
|
-
- **Auto-Discovery**: VID:PID=1A86:55D3 detection
|
384
|
-
- **Buffer Size**: 4KB read buffer, 256B line buffer
|
385
|
-
- **Cleanup Interval**: 50ms for timed-out commands
|
386
|
-
|
387
|
-
---
|
388
|
-
|
389
|
-
## 📜 License
|
390
|
-
|
391
|
-
GPL License © SleepyTotem
|
392
|
-
|
393
|
-
---
|
394
|
-
|
395
|
-
## 🙋 Support
|
396
|
-
|
397
|
-
- **Issues**: [GitHub Issues](https://github.com/SleepyTotem/makcu-py-lib/issues)
|
398
|
-
|
399
|
-
---
|
400
|
-
|
401
|
-
## 🌐 Links
|
402
|
-
|
403
|
-
- [GitHub Repository](https://github.com/SleepyTotem/makcu-py-lib)
|
404
|
-
- [PyPI Package](https://pypi.org/project/makcu/)
|
405
|
-
- [Documentation](https://makcu.readthedocs.io/)
|
1
|
+
# 🖱️ Makcu Python Library v2.2.0
|
2
|
+
|
3
|
+
[](https://pypi.org/project/makcu/)
|
4
|
+
[](https://pypi.org/project/makcu/)
|
5
|
+
[](LICENSE)
|
6
|
+
|
7
|
+
Makcu Py Lib is a high-performance Python library for controlling Makcu devices — now with **async/await support**, **zero-delay command execution**, and **automatic reconnection**!
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
## 📦 Installation
|
12
|
+
|
13
|
+
### Recommended: PyPI
|
14
|
+
|
15
|
+
```bash
|
16
|
+
pip install makcu
|
17
|
+
```
|
18
|
+
|
19
|
+
### From Source
|
20
|
+
|
21
|
+
```bash
|
22
|
+
git clone https://github.com/SleepyTotem/makcu-py-lib
|
23
|
+
cd makcu-py-lib
|
24
|
+
pip install .
|
25
|
+
```
|
26
|
+
|
27
|
+
---
|
28
|
+
|
29
|
+
## 🧠 Quick Start
|
30
|
+
|
31
|
+
### Synchronous API (Classic)
|
32
|
+
|
33
|
+
```python
|
34
|
+
from makcu import create_controller, MouseButton
|
35
|
+
|
36
|
+
# Create and connect
|
37
|
+
makcu = create_controller(debug=True, auto_reconnect=True)
|
38
|
+
|
39
|
+
# Basic operations
|
40
|
+
makcu.click(MouseButton.LEFT)
|
41
|
+
makcu.move(100, 50)
|
42
|
+
makcu.scroll(-1)
|
43
|
+
|
44
|
+
# Human-like interaction
|
45
|
+
makcu.click_human_like(MouseButton.LEFT, count=2, profile="gaming", jitter=3)
|
46
|
+
|
47
|
+
# Clean disconnect
|
48
|
+
makcu.disconnect()
|
49
|
+
```
|
50
|
+
|
51
|
+
### Asynchronous API (New!)
|
52
|
+
|
53
|
+
```python
|
54
|
+
import asyncio
|
55
|
+
from makcu import create_async_controller, MouseButton
|
56
|
+
|
57
|
+
async def main():
|
58
|
+
# Auto-connect with context manager
|
59
|
+
async with await create_async_controller(debug=True) as makcu:
|
60
|
+
# Parallel operations
|
61
|
+
await asyncio.gather(
|
62
|
+
makcu.move(100, 0),
|
63
|
+
makcu.click(MouseButton.LEFT),
|
64
|
+
makcu.scroll(-1)
|
65
|
+
)
|
66
|
+
|
67
|
+
# Human-like clicking
|
68
|
+
await makcu.click_human_like(MouseButton.RIGHT, count=3)
|
69
|
+
|
70
|
+
asyncio.run(main())
|
71
|
+
```
|
72
|
+
|
73
|
+
---
|
74
|
+
|
75
|
+
## 🎮 Core Features
|
76
|
+
|
77
|
+
### Mouse Control
|
78
|
+
|
79
|
+
```python
|
80
|
+
# Button actions
|
81
|
+
await makcu.click(MouseButton.LEFT)
|
82
|
+
await makcu.double_click(MouseButton.RIGHT)
|
83
|
+
await makcu.press(MouseButton.MIDDLE)
|
84
|
+
await makcu.release(MouseButton.MIDDLE)
|
85
|
+
|
86
|
+
# Movement
|
87
|
+
await makcu.move(100, 50) # Relative movement
|
88
|
+
await makcu.move_smooth(200, 100, segments=20) # Smooth interpolation
|
89
|
+
await makcu.move_bezier(150, 150, segments=30, ctrl_x=75, ctrl_y=200) # Bezier curve
|
90
|
+
|
91
|
+
# Scrolling
|
92
|
+
await makcu.scroll(-5) # Scroll down
|
93
|
+
await makcu.scroll(3) # Scroll up
|
94
|
+
|
95
|
+
# Dragging
|
96
|
+
await makcu.drag(0, 0, 300, 200, button=MouseButton.LEFT, duration=1.5)
|
97
|
+
```
|
98
|
+
|
99
|
+
### Button & Axis Locking
|
100
|
+
|
101
|
+
```python
|
102
|
+
# New unified locking API
|
103
|
+
await makcu.lock(MouseButton.LEFT) # Lock left button
|
104
|
+
await makcu.unlock(MouseButton.RIGHT) # Unlock right button
|
105
|
+
await makcu.lock("X") # Lock X-axis movement
|
106
|
+
await makcu.unlock("Y") # Unlock Y-axis movement
|
107
|
+
|
108
|
+
# Query lock states (no delays!)
|
109
|
+
is_locked = await makcu.is_locked(MouseButton.LEFT)
|
110
|
+
all_states = await makcu.get_all_lock_states()
|
111
|
+
# Returns: {"LEFT": True, "RIGHT": False, "X": True, ...}
|
112
|
+
```
|
113
|
+
|
114
|
+
### Human-like Interactions
|
115
|
+
|
116
|
+
```python
|
117
|
+
# Realistic clicking with timing variations
|
118
|
+
await makcu.click_human_like(
|
119
|
+
button=MouseButton.LEFT,
|
120
|
+
count=5,
|
121
|
+
profile="gaming", # "fast", "normal", "slow", "variable", "gaming"
|
122
|
+
jitter=5 # Random mouse movement between clicks
|
123
|
+
)
|
124
|
+
```
|
125
|
+
|
126
|
+
### Button Event Monitoring
|
127
|
+
|
128
|
+
```python
|
129
|
+
# Real-time button monitoring
|
130
|
+
def on_button_event(button: MouseButton, pressed: bool):
|
131
|
+
print(f"{button.name} {'pressed' if pressed else 'released'}")
|
132
|
+
|
133
|
+
makcu.set_button_callback(on_button_event)
|
134
|
+
await makcu.enable_button_monitoring(True)
|
135
|
+
|
136
|
+
# Check current button states
|
137
|
+
states = makcu.get_button_states()
|
138
|
+
if makcu.is_pressed(MouseButton.RIGHT):
|
139
|
+
print("Right button is pressed")
|
140
|
+
```
|
141
|
+
|
142
|
+
### Connection Management
|
143
|
+
|
144
|
+
```python
|
145
|
+
# Auto-reconnection on disconnect
|
146
|
+
makcu = await create_async_controller(auto_reconnect=True)
|
147
|
+
|
148
|
+
# Connection status callbacks
|
149
|
+
@makcu.on_connection_change
|
150
|
+
async def handle_connection(connected: bool):
|
151
|
+
if connected:
|
152
|
+
print("Device reconnected!")
|
153
|
+
else:
|
154
|
+
print("Device disconnected!")
|
155
|
+
|
156
|
+
# Manual reconnection
|
157
|
+
if not makcu.is_connected():
|
158
|
+
await makcu.connect()
|
159
|
+
```
|
160
|
+
|
161
|
+
---
|
162
|
+
|
163
|
+
## 🔧 Advanced Features
|
164
|
+
|
165
|
+
### Batch Operations
|
166
|
+
|
167
|
+
```python
|
168
|
+
# Execute multiple commands efficiently
|
169
|
+
async def combo_action():
|
170
|
+
await makcu.batch_execute([
|
171
|
+
lambda: makcu.move(50, 0),
|
172
|
+
lambda: makcu.click(MouseButton.LEFT),
|
173
|
+
lambda: makcu.move(-50, 0),
|
174
|
+
lambda: makcu.click(MouseButton.RIGHT)
|
175
|
+
])
|
176
|
+
```
|
177
|
+
|
178
|
+
### Device Information
|
179
|
+
|
180
|
+
```python
|
181
|
+
# Get device details
|
182
|
+
info = await makcu.get_device_info()
|
183
|
+
# {'port': 'COM3', 'vid': '0x1a86', 'pid': '0x55d3', ...}
|
184
|
+
|
185
|
+
# Firmware version
|
186
|
+
version = await makcu.get_firmware_version()
|
187
|
+
```
|
188
|
+
|
189
|
+
### Serial Spoofing
|
190
|
+
|
191
|
+
```python
|
192
|
+
# Spoof device serial
|
193
|
+
await makcu.spoof_serial("CUSTOM123456")
|
194
|
+
|
195
|
+
# Reset to default
|
196
|
+
await makcu.reset_serial()
|
197
|
+
```
|
198
|
+
|
199
|
+
### Low-Level Access
|
200
|
+
|
201
|
+
```python
|
202
|
+
# Send raw commands with tracked responses
|
203
|
+
response = await makcu.transport.async_send_command(
|
204
|
+
"km.version()",
|
205
|
+
expect_response=True,
|
206
|
+
timeout=0.1 # Optimized for gaming
|
207
|
+
)
|
208
|
+
```
|
209
|
+
|
210
|
+
---
|
211
|
+
|
212
|
+
## 🧪 Command-Line Tools
|
213
|
+
|
214
|
+
```bash
|
215
|
+
# Interactive debug console
|
216
|
+
python -m makcu --debug
|
217
|
+
|
218
|
+
# Test specific port
|
219
|
+
python -m makcu --testPort COM3
|
220
|
+
|
221
|
+
# Run automated tests
|
222
|
+
python -m makcu --runtest
|
223
|
+
```
|
224
|
+
|
225
|
+
### Tool Descriptions
|
226
|
+
|
227
|
+
- `--debug`: Launches an interactive console where you can type raw device commands and see live responses.
|
228
|
+
- `--testPort COMx`: Attempts to connect to the given COM port and reports success or failure.
|
229
|
+
- `--runtest`: Runs `test_suite.py` using `pytest` and opens a detailed HTML test report.
|
230
|
+
|
231
|
+
---
|
232
|
+
|
233
|
+
### Test Suite
|
234
|
+
|
235
|
+
- File: `test_suite.py`
|
236
|
+
- Run with: `python -m makcu --runtest`
|
237
|
+
- Output: `latest_pytest.html`
|
238
|
+
|
239
|
+
Includes tests for:
|
240
|
+
- Port connection
|
241
|
+
- Firmware version check
|
242
|
+
- Mouse movement and button control
|
243
|
+
- Button masking and locking
|
244
|
+
|
245
|
+
---
|
246
|
+
|
247
|
+
## Test Timings (v1.3 vs v1.4 vs v2.0)
|
248
|
+
|
249
|
+
| Test Name | v1.3 | v1.4 | v2.0 | Improvement (v1.3 → v2.0) |
|
250
|
+
|--------------------------|--------|-------|-------|----------------------------|
|
251
|
+
| connect_to_port | ~100ms | ~55ms | **46ms** | ~2.2x faster |
|
252
|
+
| press_and_release | ~18ms | ~9ms | **1ms** | ~18x faster |
|
253
|
+
| firmware_version | ~20ms | ~9ms | **1ms** | ~20x faster |
|
254
|
+
| middle_click | ~18ms | ~9ms | **1ms** | ~18x faster |
|
255
|
+
| device_info | ~25ms | ~13ms | **6ms** | ~4.1x faster |
|
256
|
+
| port_connection | ~20ms | ~9ms | **1ms** | ~20x faster |
|
257
|
+
| button_mask | ~17ms | ~8ms | **1ms** | ~17x faster |
|
258
|
+
| get_button_states | ~18ms | ~9ms | **1ms** | ~18x faster |
|
259
|
+
| lock_state | ~33ms | ~10ms | **1ms** | ~33x faster |
|
260
|
+
| makcu_behavior | ~20ms | ~10ms | **1ms** | ~20x faster |
|
261
|
+
| batch_commands | ~350ms | ~90ms | **3ms** | ~117x faster |
|
262
|
+
| rapid_moves | ~17ms | ~8ms | **2ms** | ~8.5x faster |
|
263
|
+
| button_performance | ~18ms | ~9ms | **2ms** | ~9x faster |
|
264
|
+
| mixed_operations | ~22ms | ~10ms | **2ms** | ~11x faster |
|
265
|
+
|
266
|
+
Based on the measured test suite, v2.0 is on average **~17× faster** than v1.3 across all core operations.
|
267
|
+
|
268
|
+
|
269
|
+
### Gaming Performance Targets (v2.0)
|
270
|
+
|
271
|
+
- **144Hz Gaming**: 7ms frame time — ✅ Easily met (avg 1–3ms per operation)
|
272
|
+
- **240Hz Gaming**: 4.2ms frame time — ✅ Consistently met (most ops ≤ 2ms)
|
273
|
+
- **360Hz Gaming**: 2.8ms frame time — ⚡ Achievable for atomic/single ops
|
274
|
+
|
275
|
+
---
|
276
|
+
|
277
|
+
## 🏎️ Performance Optimization Details
|
278
|
+
|
279
|
+
### Version History & Performance
|
280
|
+
|
281
|
+
- **v1.3 and earlier**: Original implementation with sleep delays
|
282
|
+
- **v1.4**: Initial optimizations, removed some sleep delays
|
283
|
+
- **v2.0**: Complete rewrite with zero-delay architecture
|
284
|
+
|
285
|
+
### Key Optimizations in v2.0
|
286
|
+
|
287
|
+
1. **Pre-computed Commands**: All commands are pre-formatted at initialization
|
288
|
+
2. **Bitwise Operations**: Button states use single integer with bit manipulation
|
289
|
+
3. **Zero-Copy Buffers**: Pre-allocated buffers for parsing
|
290
|
+
4. **Reduced Timeouts**: Gaming-optimized timeouts (100ms default)
|
291
|
+
5. **Cache Everything**: Connection states, lock states, and device info cached
|
292
|
+
6. **Minimal Allocations**: Reuse objects and avoid string formatting
|
293
|
+
7. **Fast Serial Settings**: 1ms read timeout, 10ms write timeout
|
294
|
+
8. **Optimized Listener**: Batch processing with minimal overhead
|
295
|
+
|
296
|
+
### Tips for Maximum Performance
|
297
|
+
|
298
|
+
```python
|
299
|
+
# Disable debug mode in production
|
300
|
+
makcu = create_controller(debug=False)
|
301
|
+
|
302
|
+
# Use cached connection checks
|
303
|
+
if makcu.is_connected(): # Cached, no serial check
|
304
|
+
makcu.click(MouseButton.LEFT)
|
305
|
+
|
306
|
+
# Batch similar operations
|
307
|
+
with makcu: # Context manager ensures connection
|
308
|
+
for _ in range(10):
|
309
|
+
makcu.move(10, 0) # No connection check per call
|
310
|
+
```
|
311
|
+
|
312
|
+
---
|
313
|
+
|
314
|
+
## 🔍 Debugging
|
315
|
+
|
316
|
+
Enable debug mode for detailed logging:
|
317
|
+
|
318
|
+
```python
|
319
|
+
makcu = await create_async_controller(debug=True)
|
320
|
+
|
321
|
+
# View command flow (optimized timestamps)
|
322
|
+
# [123.456] [INFO] Sent command #42: km.move(100,50)
|
323
|
+
# [123.458] [DEBUG] Command #42 completed in 0.002s
|
324
|
+
```
|
325
|
+
|
326
|
+
---
|
327
|
+
|
328
|
+
## 🏗️ Migration from v1.x
|
329
|
+
|
330
|
+
Most code works without changes! Key differences:
|
331
|
+
|
332
|
+
```python
|
333
|
+
# v1.x (still works)
|
334
|
+
makcu = create_controller()
|
335
|
+
makcu.move(100, 100)
|
336
|
+
|
337
|
+
# v2.0 (async)
|
338
|
+
makcu = await create_async_controller()
|
339
|
+
await makcu.move(100, 100)
|
340
|
+
|
341
|
+
# v2.0 context manager (auto cleanup)
|
342
|
+
async with await create_async_controller() as makcu:
|
343
|
+
await makcu.click(MouseButton.LEFT)
|
344
|
+
```
|
345
|
+
|
346
|
+
---
|
347
|
+
|
348
|
+
## 📚 API Reference
|
349
|
+
|
350
|
+
### Enumerations
|
351
|
+
|
352
|
+
```python
|
353
|
+
from makcu import MouseButton
|
354
|
+
|
355
|
+
MouseButton.LEFT # Left mouse button
|
356
|
+
MouseButton.RIGHT # Right mouse button
|
357
|
+
MouseButton.MIDDLE # Middle mouse button
|
358
|
+
MouseButton.MOUSE4 # Side button 1
|
359
|
+
MouseButton.MOUSE5 # Side button 2
|
360
|
+
```
|
361
|
+
|
362
|
+
### Exception Handling
|
363
|
+
|
364
|
+
```python
|
365
|
+
from makcu import MakcuError, MakcuConnectionError, MakcuTimeoutError
|
366
|
+
|
367
|
+
try:
|
368
|
+
makcu = await create_async_controller()
|
369
|
+
except MakcuConnectionError as e:
|
370
|
+
print(f"Connection failed: {e}")
|
371
|
+
except MakcuTimeoutError as e:
|
372
|
+
print(f"Command timed out: {e}")
|
373
|
+
```
|
374
|
+
|
375
|
+
---
|
376
|
+
|
377
|
+
## 🛠️ Technical Details
|
378
|
+
|
379
|
+
- **Protocol**: CH343 USB serial at 4Mbps
|
380
|
+
- **Command Format**: ASCII with optional ID tracking (`command#ID`)
|
381
|
+
- **Response Format**: `>>> #ID:response` for tracked commands
|
382
|
+
- **Threading**: High-priority listener thread with async bridge
|
383
|
+
- **Auto-Discovery**: VID:PID=1A86:55D3 detection
|
384
|
+
- **Buffer Size**: 4KB read buffer, 256B line buffer
|
385
|
+
- **Cleanup Interval**: 50ms for timed-out commands
|
386
|
+
|
387
|
+
---
|
388
|
+
|
389
|
+
## 📜 License
|
390
|
+
|
391
|
+
GPL License © SleepyTotem
|
392
|
+
|
393
|
+
---
|
394
|
+
|
395
|
+
## 🙋 Support
|
396
|
+
|
397
|
+
- **Issues**: [GitHub Issues](https://github.com/SleepyTotem/makcu-py-lib/issues)
|
398
|
+
|
399
|
+
---
|
400
|
+
|
401
|
+
## 🌐 Links
|
402
|
+
|
403
|
+
- [GitHub Repository](https://github.com/SleepyTotem/makcu-py-lib)
|
404
|
+
- [PyPI Package](https://pypi.org/project/makcu/)
|
405
|
+
- [Documentation](https://makcu-py-lib.readthedocs.io/)
|
406
|
+
- [Changelog](https://makcu-py-lib.readthedocs.io/en/latest/changelog.html)
|
@@ -1,22 +1,22 @@
|
|
1
|
-
from .controller import (
|
2
|
-
MakcuController,
|
3
|
-
create_controller,
|
4
|
-
create_async_controller,
|
5
|
-
maybe_async
|
6
|
-
)
|
7
|
-
from .enums import MouseButton
|
8
|
-
from .errors import MakcuConnectionError
|
9
|
-
|
10
|
-
# Version info
|
11
|
-
__version__ = "2.2.
|
12
|
-
__author__ = "SleepyTotem"
|
13
|
-
|
14
|
-
# Main exports
|
15
|
-
__all__ = [
|
16
|
-
'MakcuController',
|
17
|
-
'MouseButton',
|
18
|
-
'MakcuConnectionError',
|
19
|
-
'create_controller',
|
20
|
-
'create_async_controller',
|
21
|
-
'maybe_async'
|
1
|
+
from .controller import (
|
2
|
+
MakcuController,
|
3
|
+
create_controller,
|
4
|
+
create_async_controller,
|
5
|
+
maybe_async
|
6
|
+
)
|
7
|
+
from .enums import MouseButton
|
8
|
+
from .errors import MakcuConnectionError
|
9
|
+
|
10
|
+
# Version info
|
11
|
+
__version__ = "2.2.1"
|
12
|
+
__author__ = "SleepyTotem"
|
13
|
+
|
14
|
+
# Main exports
|
15
|
+
__all__ = [
|
16
|
+
'MakcuController',
|
17
|
+
'MouseButton',
|
18
|
+
'MakcuConnectionError',
|
19
|
+
'create_controller',
|
20
|
+
'create_async_controller',
|
21
|
+
'maybe_async'
|
22
22
|
]
|
@@ -91,42 +91,48 @@ def find_writable_directory() -> Path:
|
|
91
91
|
def parse_html_results(html_file: Path) -> Tuple[List[Tuple[str, str, int]], int]:
|
92
92
|
if not html_file.exists():
|
93
93
|
raise FileNotFoundError(f"HTML report not found: {html_file}")
|
94
|
-
|
94
|
+
|
95
95
|
with open(html_file, 'r', encoding='utf-8') as f:
|
96
96
|
content = f.read()
|
97
|
-
|
97
|
+
|
98
98
|
match = re.search(r'data-jsonblob="([^"]*)"', content)
|
99
99
|
if not match:
|
100
100
|
raise ValueError("Could not find JSON data in HTML report")
|
101
|
-
|
101
|
+
|
102
102
|
json_str = match.group(1)
|
103
103
|
json_str = json_str.replace('"', '"').replace(''', "'").replace('&', '&')
|
104
|
-
|
104
|
+
|
105
105
|
try:
|
106
106
|
data = json.loads(json_str)
|
107
107
|
except json.JSONDecodeError as e:
|
108
108
|
raise ValueError(f"Failed to parse JSON data: {e}")
|
109
|
-
|
109
|
+
|
110
110
|
test_results = []
|
111
111
|
total_ms = 0
|
112
|
-
|
112
|
+
|
113
113
|
skip_tests = {'test_connect_to_port'}
|
114
|
-
|
114
|
+
|
115
115
|
for test_id, test_data_list in data.get('tests', {}).items():
|
116
116
|
test_name = test_id.split('::')[-1]
|
117
|
+
|
118
|
+
# Skip tests that are in skip_tests
|
117
119
|
if test_name in skip_tests:
|
118
120
|
continue
|
119
|
-
|
121
|
+
|
120
122
|
for test_data in test_data_list:
|
121
123
|
status = test_data.get('result', 'UNKNOWN')
|
122
124
|
duration_str = test_data.get('duration', '0 ms')
|
123
|
-
|
125
|
+
|
124
126
|
duration_match = re.search(r'(\d+)\s*ms', duration_str)
|
125
127
|
duration_ms = int(duration_match.group(1)) if duration_match else 0
|
126
|
-
total_ms += duration_ms
|
127
128
|
|
129
|
+
# Always add test to results
|
128
130
|
test_results.append((test_name, status, duration_ms))
|
129
|
-
|
131
|
+
|
132
|
+
# Only add time to total if it's not a cleanup test
|
133
|
+
if 'cleanup' not in test_name.lower():
|
134
|
+
total_ms += duration_ms
|
135
|
+
|
130
136
|
return test_results, total_ms
|
131
137
|
|
132
138
|
def run_tests() -> NoReturn:
|
@@ -244,8 +250,12 @@ def run_tests() -> NoReturn:
|
|
244
250
|
display_name = test_name.replace("test_", "").replace("_", " ").title()
|
245
251
|
|
246
252
|
if status.upper() == "PASSED":
|
247
|
-
|
248
|
-
|
253
|
+
if display_name.lower().startswith("cleanup"):
|
254
|
+
status_text = ""
|
255
|
+
passed += 1
|
256
|
+
else:
|
257
|
+
status_text = "[green]✅ PASSED[/green]"
|
258
|
+
passed += 1
|
249
259
|
elif status.upper() == "FAILED":
|
250
260
|
status_text = "[red]❌ FAILED[/red]"
|
251
261
|
failed += 1
|
@@ -263,7 +273,10 @@ def run_tests() -> NoReturn:
|
|
263
273
|
elif duration_ms <= 10:
|
264
274
|
perf = "[yellow]Good[/yellow]"
|
265
275
|
elif duration_ms > 0:
|
266
|
-
|
276
|
+
if display_name.lower().startswith("cleanup"):
|
277
|
+
perf = ""
|
278
|
+
else:
|
279
|
+
perf = "[red]🐌 Needs work[/red]"
|
267
280
|
else:
|
268
281
|
perf = "-"
|
269
282
|
|
@@ -449,7 +449,7 @@ class SerialTransport:
|
|
449
449
|
self.serial = None
|
450
450
|
self._log("Disconnection completed")
|
451
451
|
|
452
|
-
def send_command(self, command: str, expect_response: bool =
|
452
|
+
def send_command(self, command: str, expect_response: bool = False,
|
453
453
|
timeout: float = DEFAULT_TIMEOUT) -> Optional[str]:
|
454
454
|
command_start = time.time()
|
455
455
|
|
@@ -457,11 +457,10 @@ class SerialTransport:
|
|
457
457
|
raise MakcuConnectionError("Not connected")
|
458
458
|
|
459
459
|
if not expect_response:
|
460
|
-
|
461
|
-
self.serial.write(cmd_bytes)
|
460
|
+
self.serial.write(f"{command}\r\n".encode('ascii'))
|
462
461
|
self.serial.flush()
|
463
462
|
send_time = time.time() - command_start
|
464
|
-
self._log(f"Command '{command}' sent in {send_time:.
|
463
|
+
self._log(f"Command '{command}' sent in {send_time:.5f}s (no response expected)")
|
465
464
|
return command
|
466
465
|
|
467
466
|
cmd_id = self._generate_command_id()
|
@@ -488,7 +487,7 @@ class SerialTransport:
|
|
488
487
|
|
489
488
|
response = result.split('#')[0] if '#' in result else result
|
490
489
|
total_time = time.time() - command_start
|
491
|
-
self._log(f"Command '{command}' completed in {total_time:.
|
490
|
+
self._log(f"Command '{command}' completed in {total_time:.5f}s total")
|
492
491
|
return response
|
493
492
|
|
494
493
|
except TimeoutError:
|
@@ -1,2 +1,2 @@
|
|
1
|
-
# This file is intentionally empty.
|
1
|
+
# This file is intentionally empty.
|
2
2
|
# It serves as a marker to indicate that this package supports type hints.
|
@@ -137,6 +137,23 @@ def test_mixed_operations(makcu):
|
|
137
137
|
assert elapsed_ms < 15
|
138
138
|
|
139
139
|
|
140
|
-
|
141
|
-
|
142
|
-
|
140
|
+
def test_cleanup(makcu):
|
141
|
+
time.sleep(0.1)
|
142
|
+
|
143
|
+
makcu.lock_left(False)
|
144
|
+
makcu.lock_right(False)
|
145
|
+
makcu.lock_middle(False)
|
146
|
+
makcu.lock_side1(False)
|
147
|
+
makcu.lock_side2(False)
|
148
|
+
makcu.lock_x(False)
|
149
|
+
makcu.lock_y(False)
|
150
|
+
|
151
|
+
makcu.release(MouseButton.LEFT)
|
152
|
+
makcu.release(MouseButton.RIGHT)
|
153
|
+
makcu.release(MouseButton.MIDDLE)
|
154
|
+
makcu.release(MouseButton.MOUSE4)
|
155
|
+
makcu.release(MouseButton.MOUSE5)
|
156
|
+
|
157
|
+
makcu.enable_button_monitoring(False)
|
158
|
+
makcu.disconnect()
|
159
|
+
assert not makcu.is_connected(), "Failed to disconnect from the makcu"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: makcu
|
3
|
-
Version: 2.2.
|
3
|
+
Version: 2.2.1
|
4
4
|
Summary: Python library for Makcu hardware device control
|
5
5
|
Author: SleepyTotem
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
@@ -1112,4 +1112,5 @@ GPL License © SleepyTotem
|
|
1112
1112
|
|
1113
1113
|
- [GitHub Repository](https://github.com/SleepyTotem/makcu-py-lib)
|
1114
1114
|
- [PyPI Package](https://pypi.org/project/makcu/)
|
1115
|
-
- [Documentation](https://makcu.readthedocs.io/)
|
1115
|
+
- [Documentation](https://makcu-py-lib.readthedocs.io/)
|
1116
|
+
- [Changelog](https://makcu-py-lib.readthedocs.io/en/latest/changelog.html)
|
makcu-2.2.0/makcu/conftest.py
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
import pytest
|
2
|
-
import time
|
3
|
-
from makcu import MakcuController, MouseButton
|
4
|
-
|
5
|
-
@pytest.fixture(scope="session")
|
6
|
-
def makcu(request):
|
7
|
-
ctrl = MakcuController(fallback_com_port="COM1", debug=False)
|
8
|
-
|
9
|
-
def cleanup():
|
10
|
-
if ctrl.is_connected():
|
11
|
-
|
12
|
-
time.sleep(0.1)
|
13
|
-
|
14
|
-
ctrl.lock_left(False)
|
15
|
-
ctrl.lock_right(False)
|
16
|
-
ctrl.lock_middle(False)
|
17
|
-
ctrl.lock_side1(False)
|
18
|
-
ctrl.lock_side2(False)
|
19
|
-
ctrl.lock_x(False)
|
20
|
-
ctrl.lock_y(False)
|
21
|
-
|
22
|
-
ctrl.release(MouseButton.LEFT)
|
23
|
-
ctrl.release(MouseButton.RIGHT)
|
24
|
-
ctrl.release(MouseButton.MIDDLE)
|
25
|
-
ctrl.release(MouseButton.MOUSE4)
|
26
|
-
ctrl.release(MouseButton.MOUSE5)
|
27
|
-
|
28
|
-
ctrl.enable_button_monitoring(False)
|
29
|
-
|
30
|
-
ctrl.disconnect()
|
31
|
-
|
32
|
-
request.addfinalizer(cleanup)
|
33
|
-
|
34
|
-
return ctrl
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|