makcu 0.1.1__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/mouse.py ADDED
@@ -0,0 +1,134 @@
1
+ from .enums import MouseButton
2
+ from .errors import MakcuCommandError
3
+ from serial.tools import list_ports
4
+
5
+ class Mouse:
6
+ def __init__(self, transport):
7
+ self.transport = transport
8
+
9
+ def press(self, button: MouseButton):
10
+ cmd = {
11
+ MouseButton.LEFT: "km.left(1)",
12
+ MouseButton.RIGHT: "km.right(1)",
13
+ MouseButton.MIDDLE: "km.middle(1)"
14
+ }.get(button)
15
+ if cmd:
16
+ self.transport.send_command(cmd)
17
+ else:
18
+ raise MakcuCommandError(f"Unsupported button for press(): {button}")
19
+
20
+ def release(self, button: MouseButton):
21
+ cmd = {
22
+ MouseButton.LEFT: "km.left(0)",
23
+ MouseButton.RIGHT: "km.right(0)",
24
+ MouseButton.MIDDLE: "km.middle(0)"
25
+ }.get(button)
26
+ if cmd:
27
+ self.transport.send_command(cmd)
28
+ else:
29
+ raise MakcuCommandError(f"Unsupported button for release(): {button}")
30
+
31
+ def move(self, x: int, y: int):
32
+ self.transport.send_command(f"km.move({x},{y})")
33
+
34
+ def move_smooth(self, x: int, y: int, segments: int):
35
+ self.transport.send_command(f"km.move({x},{y},{segments})")
36
+
37
+ def move_bezier(self, x: int, y: int, segments: int, ctrl_x: int, ctrl_y: int):
38
+ self.transport.send_command(f"km.move({x},{y},{segments},{ctrl_x},{ctrl_y})")
39
+
40
+ def scroll(self, delta: int):
41
+ self.transport.send_command(f"km.wheel({delta})")
42
+
43
+ def lock_left(self, lock: bool): self.transport.send_command(f"km.lock_ml({int(lock)})")
44
+ def lock_middle(self, lock: bool): self.transport.send_command(f"km.lock_mm({int(lock)})")
45
+ def lock_right(self, lock: bool): self.transport.send_command(f"km.lock_mr({int(lock)})")
46
+ def lock_side1(self, lock: bool): self.transport.send_command(f"km.lock_ms1({int(lock)})")
47
+ def lock_side2(self, lock: bool): self.transport.send_command(f"km.lock_ms2({int(lock)})")
48
+ def lock_x(self, lock: bool): self.transport.send_command(f"km.lock_mx({int(lock)})")
49
+ def lock_y(self, lock: bool): self.transport.send_command(f"km.lock_my({int(lock)})")
50
+
51
+ def spoof_serial(self, serial: str): self.transport.send_command(f"km.serial('{serial}')")
52
+ def reset_serial(self): self.transport.send_command("km.serial(0)")
53
+
54
+ def get_device_info(self) -> dict:
55
+ port_name = self.transport.port
56
+ is_connected = self.transport.is_connected()
57
+ info = {
58
+ "port": port_name,
59
+ "description": "Unknown",
60
+ "vid": "Unknown",
61
+ "pid": "Unknown",
62
+ "isConnected": is_connected
63
+ }
64
+ for port in list_ports.comports():
65
+ if port.device == port_name:
66
+ info.update({
67
+ "description": port.description,
68
+ "vid": hex(port.vid) if port.vid is not None else "Unknown",
69
+ "pid": hex(port.pid) if port.pid is not None else "Unknown"
70
+ })
71
+ break
72
+ return info
73
+
74
+ def get_firmware_version(self) -> str:
75
+ return self.transport.send_command("km.version()", expect_response=True)
76
+
77
+ def is_locked(self, target: str) -> bool:
78
+ target = target.upper()
79
+ commands = {
80
+ "X": "km.lock_mx()",
81
+ "Y": "km.lock_my()",
82
+ "LEFT": "km.lock_ml()",
83
+ "MIDDLE": "km.lock_mm()",
84
+ "RIGHT": "km.lock_mr()",
85
+ "MOUSE4": "km.lock_ms1()",
86
+ "MOUSE5": "km.lock_ms2()",
87
+ }
88
+ if target not in commands:
89
+ raise ValueError(f"Unsupported lock target: {target}")
90
+ try:
91
+ result = self.transport.send_command(commands[target], expect_response=True)
92
+ return result.strip() == "1"
93
+ except Exception:
94
+ return False
95
+
96
+ def is_button_locked(self, button: MouseButton) -> bool:
97
+ name_map = {
98
+ MouseButton.LEFT: "LEFT",
99
+ MouseButton.RIGHT: "RIGHT",
100
+ MouseButton.MIDDLE: "MIDDLE",
101
+ MouseButton.MOUSE4: "MOUSE4",
102
+ MouseButton.MOUSE5: "MOUSE5"
103
+ }
104
+ return self.is_locked(name_map[button])
105
+
106
+ def begin_capture(self, button: str):
107
+ """
108
+ Assumes lock_<button>(1) has already been called.
109
+ Sends catch_<button>(0) to begin capturing click cycles.
110
+ """
111
+ self.transport.catch_button(button)
112
+
113
+ def stop_capturing_clicks(self, button: str) -> int:
114
+ """
115
+ Assumes lock_<button>(0) has already been called.
116
+ Returns the total number of clicks since begin_capture.
117
+ """
118
+ return self.transport.read_captured_clicks(button)
119
+
120
+ def get_captured_clicks_enum(self, button: MouseButton) -> int:
121
+ mapping = {
122
+ MouseButton.LEFT: "LEFT",
123
+ MouseButton.RIGHT: "RIGHT",
124
+ MouseButton.MIDDLE: "MIDDLE",
125
+ MouseButton.MOUSE4: "MOUSE4",
126
+ MouseButton.MOUSE5: "MOUSE5",
127
+ }
128
+ return self.stop_capturing_clicks(mapping[button])
129
+
130
+ def get_all_lock_states(self) -> dict:
131
+ return {
132
+ target: self.is_locked(target)
133
+ for target in ["X", "Y", "LEFT", "RIGHT", "MIDDLE", "MOUSE4", "MOUSE5"]
134
+ }
makcu/utils.py ADDED
@@ -0,0 +1,7 @@
1
+ from serial.tools import list_ports
2
+
3
+ def find_makcu_port():
4
+ for port in list_ports.comports():
5
+ if "CH343" in port.description:
6
+ return port.device
7
+ return None
@@ -0,0 +1,315 @@
1
+ Metadata-Version: 2.4
2
+ Name: makcu
3
+ Version: 0.1.1
4
+ Summary: Python library to interact with Makcu devices.
5
+ Author: SleepyTotem
6
+ License: GPL
7
+ Project-URL: Homepage, https://github.com/SleepyTotem/makcu-py-lib
8
+ Requires-Python: >=3.7
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Dynamic: license-file
12
+
13
+ # ๐Ÿ–ฑ๏ธ Makcu Python Library
14
+
15
+ Makcu Py Lib is a Python library for controlling Makcu devices โ€” enabling software-driven mouse input, movement simulation, locking, monitoring, and more.
16
+
17
+ ---
18
+
19
+ ## ๐Ÿ“ฆ Installation
20
+
21
+ ### โœ… Recommended: PyPI
22
+
23
+ ```bash
24
+ pip install makcu
25
+ ```
26
+
27
+ ### ๐Ÿงช Alternative: Install from Source
28
+
29
+ ```bash
30
+ git clone https://github.com/SleepyTotem/makcu-py-lib
31
+ cd makcu-py-lib
32
+ pip install .
33
+ ```
34
+
35
+ ---
36
+
37
+ ## ๐Ÿš€ Command-Line Usage
38
+
39
+ After installation, use:
40
+
41
+ ```bash
42
+ python -m makcu [command]
43
+ ```
44
+
45
+ ### Available Commands
46
+
47
+ | Command | Description |
48
+ |---------|-------------|
49
+ | `--debug` | Opens interactive console to send raw `km.*` commands |
50
+ | `--testPort COM3` | Tests a specific COM port for connectivity |
51
+ | `--runtest` | Runs all automated tests and opens a test report |
52
+
53
+ ### Examples
54
+
55
+ ```bash
56
+ python -m makcu --debug
57
+ python -m makcu --testPort COM3
58
+ python -m makcu --runtest
59
+ ```
60
+
61
+ ---
62
+
63
+ ## ๐Ÿง  Quickstart (Python)
64
+
65
+ ```python
66
+ from makcu import create_controller, MouseButton
67
+
68
+ makcu = create_controller()
69
+ makcu.click(MouseButton.LEFT)
70
+ makcu.move(100, 50)
71
+ makcu.scroll(-1)
72
+ makcu.disconnect()
73
+ ```
74
+
75
+ ---
76
+
77
+ ## ๐Ÿงฉ API Reference
78
+
79
+ ### ๐Ÿ”ง Initialization
80
+
81
+ ```python
82
+ makcu = create_controller(debug=True, send_init=True)
83
+ ```
84
+
85
+ #### Set fallback port manually
86
+
87
+ ```python
88
+ makcu.set_port("COM4") # use before create_controller()
89
+ ```
90
+
91
+ ---
92
+
93
+ ### ๐ŸŽฎ Mouse Control
94
+
95
+ #### Clicks
96
+
97
+ ```python
98
+ makcu.click(MouseButton.LEFT)
99
+ makcu.press(MouseButton.RIGHT)
100
+ makcu.release(MouseButton.RIGHT)
101
+ ```
102
+
103
+ #### Movement
104
+
105
+ ```python
106
+ makcu.move(dx=30, dy=20)
107
+ makcu.move_smooth(100, 40, segments=10)
108
+ makcu.move_bezier(50, 50, 15, ctrl_x=25, ctrl_y=25)
109
+ ```
110
+
111
+ #### Scrolling
112
+
113
+ ```python
114
+ makcu.scroll(-3) # Scroll down
115
+ makcu.scroll(3) # Scroll up
116
+ ```
117
+
118
+ ---
119
+
120
+ ### ๐Ÿ”’ Locking and Unlocking
121
+
122
+ ```python
123
+ makcu.lock_left(True)
124
+ makcu.lock_right(True)
125
+ makcu.lock_middle(False)
126
+ makcu.lock_side1(True)
127
+ makcu.lock_side2(False)
128
+ makcu.lock_mouse_x(True)
129
+ makcu.lock_mouse_y(False)
130
+ ```
131
+
132
+ #### Lock Status
133
+
134
+ ```python
135
+ makcu.is_button_locked(MouseButton.LEFT)
136
+ makcu.get_all_lock_states()
137
+ ```
138
+
139
+ ---
140
+
141
+ ### ๐Ÿ‘ค Human-like Click Simulation
142
+
143
+ ```python
144
+ makcu.click_human_like(
145
+ button=MouseButton.LEFT,
146
+ count=5,
147
+ profile="normal", # "fast", "slow" also available
148
+ jitter=3
149
+ )
150
+ ```
151
+
152
+ ---
153
+
154
+ ### ๐Ÿ” Device Info & Firmware
155
+
156
+ ```python
157
+ info = makcu.get_device_info()
158
+ print(info)
159
+
160
+ version = makcu.get_firmware_version()
161
+ print(version)
162
+ ```
163
+
164
+ ---
165
+
166
+ ### ๐Ÿ” Serial Spoofing
167
+
168
+ ```python
169
+ makcu.spoof_serial("FAKE123456")
170
+ makcu.reset_serial()
171
+ ```
172
+
173
+ ---
174
+
175
+ ## ๐Ÿงช Button Monitoring & Capture
176
+
177
+ ### Enable Real-time Monitoring
178
+
179
+ ```python
180
+ makcu.enable_button_monitoring(True)
181
+ ```
182
+
183
+ ### Set Callback Function
184
+
185
+ ```python
186
+ def on_button_event(button, pressed):
187
+ print(f"{button.name} is {'pressed' if pressed else 'released'}")
188
+
189
+ makcu.set_button_callback(on_button_event)
190
+ ```
191
+
192
+ ### Configure Debounce
193
+
194
+ ```python
195
+ makcu.set_callback_debounce_time(100) # milliseconds
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Click Capturing
201
+
202
+ ### โŒ **Currently broken (Pending Firmware Update)**
203
+
204
+ Click capturing will allow you to detect and count click events in software.
205
+
206
+ ```python
207
+ makcu.mouse.lock_right(True)
208
+ makcu.capture(MouseButton.RIGHT)
209
+
210
+ # User clicks however many times
211
+
212
+ makcu.mouse.lock_right(False)
213
+ count = makcu.get_captured_clicks(MouseButton.RIGHT)
214
+ print(f"Captured clicks: {count}")
215
+ ```
216
+
217
+ > โš ๏ธ This feature is currently broken in firmware. Do not rely on it yet.
218
+
219
+ ---
220
+
221
+ ## ๐Ÿ”ข Bitmask & Button States
222
+
223
+ ### Get Bitmask of Active Buttons
224
+
225
+ ```python
226
+ mask = makcu.get_button_mask()
227
+ print(f"Button mask: {mask}")
228
+ ```
229
+
230
+ ### Get Raw Button State Map
231
+
232
+ ```python
233
+ states = makcu.get_button_states()
234
+ print(states) # {'left': False, 'right': True, ...}
235
+ ```
236
+
237
+ ### Check if a Specific Button Is Pressed
238
+
239
+ ```python
240
+ if makcu.is_button_pressed(MouseButton.RIGHT):
241
+ print("Right button is pressed")
242
+ ```
243
+
244
+ ---
245
+
246
+ ## โš™๏ธ Low-Level Command Access
247
+
248
+ ### Send raw serial commands
249
+
250
+ ```python
251
+ response = makcu.transport.send_command("km.version()", expect_response=True)
252
+ print(response)
253
+ ```
254
+
255
+ ---
256
+
257
+ ## ๐Ÿงช Test Suite
258
+
259
+ Run all tests and generate HTML report:
260
+
261
+ ```bash
262
+ python -m makcu --runtest
263
+ ```
264
+
265
+ ---
266
+
267
+ ## ๐Ÿ“š Enumerations
268
+
269
+ ```python
270
+ from makcu import MouseButton
271
+
272
+ MouseButton.LEFT
273
+ MouseButton.RIGHT
274
+ MouseButton.MIDDLE
275
+ MouseButton.MOUSE4
276
+ MouseButton.MOUSE5
277
+ ```
278
+
279
+ ---
280
+
281
+ ## ๐Ÿงฏ Exception Handling
282
+
283
+ ```python
284
+ from makcu import MakcuError, MakcuConnectionError
285
+
286
+ try:
287
+ makcu = create_controller()
288
+ except MakcuConnectionError as e:
289
+ print("Connection failed:", e)
290
+ ```
291
+
292
+ ---
293
+
294
+ ## ๐Ÿ› ๏ธ Developer Notes
295
+
296
+ - Uses CH343 USB Serial
297
+ - Auto-connects to correct port or fallback
298
+ - Supports baud rate switching to 4M
299
+ - Automatically enables `km.buttons(1)` monitoring if `send_init=True`
300
+ - Supports raw button state polling
301
+
302
+ ---
303
+
304
+ ## ๐Ÿ“œ License
305
+
306
+ GPL License ยฉ SleepyTotem
307
+
308
+ ---
309
+
310
+ ## Support
311
+ Please open an issue on the project repository and I will get to it asap
312
+
313
+ ## ๐ŸŒ Links
314
+
315
+ - ๐Ÿ”— [Project Homepage](https://github.com/SleepyTotem/makcu-py-lib)
@@ -0,0 +1,13 @@
1
+ makcu/__init__.py,sha256=gBIXKg-TXZg3fTrWeUi97z1ezWF_pleFDbw9f6NpjKs,418
2
+ makcu/__main__.py,sha256=tptSrqmMTrkfe23JsJT_znNXUX2orseCigEnVCeB-B0,2346
3
+ makcu/connection.py,sha256=-lHPzMifqOOhG0ZfYGrM7SNmifBppbWYbdrm1IY5ZBY,10635
4
+ makcu/controller.py,sha256=oFp1qrUW4xqr5FYT3SXTvHIQJxxGF2v5ysqIpZk2Dsk,6542
5
+ makcu/enums.py,sha256=VmvCLmpghVHuTAkvCGMfA14MgWTtFVMfsGQQNnJ58Ts,126
6
+ makcu/errors.py,sha256=4CkQ4gKa7GL5-BO3yOAJMMsy3QlUDDL42S1P1clqV4A,562
7
+ makcu/mouse.py,sha256=KYse0Bm6rEyF8v7ujtRWDXGeUZQU5VAzKO9SxXY_O9g,5284
8
+ makcu/utils.py,sha256=-xr6mkYITpWyAIFxHeTsZQO1V__91Sm0aFho5iWHegc,191
9
+ makcu-0.1.1.dist-info/licenses/LICENSE,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
10
+ makcu-0.1.1.dist-info/METADATA,sha256=Z08RUlzyhGdKSoMUrMHpvgfZy0yc_nO7u-_j1meazpU,5563
11
+ makcu-0.1.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ makcu-0.1.1.dist-info/top_level.txt,sha256=IRO1UVb5LK_ovjau0g4oObyXQqy00tVEE-yF5lPgw1w,6
13
+ makcu-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+