makcu 0.1.3__py3-none-any.whl → 0.2.0__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 CHANGED
@@ -1,116 +1,270 @@
1
+ from typing import Dict, Optional, List, Union, Any
1
2
  from .enums import MouseButton
3
+ from .connection import SerialTransport
2
4
  from .errors import MakcuCommandError
3
5
  from serial.tools import list_ports
6
+ import time
7
+
8
+ # Create a mock enum-like object for axis locks
9
+ class AxisButton:
10
+ def __init__(self, name: str) -> None:
11
+ self.name = name
4
12
 
5
13
  class Mouse:
6
- def __init__(self, transport):
14
+ """Ultra-optimized mouse control for gaming performance"""
15
+
16
+ # Pre-computed command strings for faster access
17
+ _BUTTON_COMMANDS = {
18
+ MouseButton.LEFT: "left",
19
+ MouseButton.RIGHT: "right",
20
+ MouseButton.MIDDLE: "middle",
21
+ MouseButton.MOUSE4: "ms1",
22
+ MouseButton.MOUSE5: "ms2",
23
+ }
24
+
25
+ # Pre-formatted commands cache
26
+ _PRESS_COMMANDS = {}
27
+ _RELEASE_COMMANDS = {}
28
+ _LOCK_COMMANDS = {}
29
+ _UNLOCK_COMMANDS = {}
30
+ _LOCK_QUERY_COMMANDS = {}
31
+
32
+ def __init__(self, transport: SerialTransport) -> None:
7
33
  self.transport = transport
34
+ self._lock_states_cache: int = 0 # Bitwise cache
35
+ self._cache_valid = False
36
+
37
+ # Pre-compute all commands for zero-overhead execution
38
+ self._init_command_cache()
39
+
40
+ def _init_command_cache(self) -> None:
41
+ """Pre-compute all commands to avoid string formatting during execution"""
42
+ # Button press/release commands
43
+ for button, cmd in self._BUTTON_COMMANDS.items():
44
+ self._PRESS_COMMANDS[button] = f"km.{cmd}(1)"
45
+ self._RELEASE_COMMANDS[button] = f"km.{cmd}(0)"
46
+
47
+ # Lock commands with bitwise indexing
48
+ # Bit 0-4: buttons, Bit 5: X axis, Bit 6: Y axis
49
+ lock_targets = [
50
+ ("LEFT", "ml", 0),
51
+ ("RIGHT", "mr", 1),
52
+ ("MIDDLE", "mm", 2),
53
+ ("MOUSE4", "ms1", 3),
54
+ ("MOUSE5", "ms2", 4),
55
+ ("X", "mx", 5),
56
+ ("Y", "my", 6),
57
+ ]
58
+
59
+ for name, cmd, bit in lock_targets:
60
+ self._LOCK_COMMANDS[name] = (f"km.lock_{cmd}(1)", bit)
61
+ self._UNLOCK_COMMANDS[name] = (f"km.lock_{cmd}(0)", bit)
62
+ self._LOCK_QUERY_COMMANDS[name] = (f"km.lock_{cmd}()", bit)
8
63
 
9
- def _send_button_command(self, button: MouseButton, state: int):
10
- command_map = {
11
- MouseButton.LEFT: "left",
12
- MouseButton.RIGHT: "right",
13
- MouseButton.MIDDLE: "middle",
14
- MouseButton.MOUSE4: "ms1",
15
- MouseButton.MOUSE5: "ms2",
16
- }
17
- if button not in command_map:
64
+ def _send_button_command(self, button: MouseButton, state: int) -> None:
65
+ """Optimized button command sending"""
66
+ if button not in self._BUTTON_COMMANDS:
18
67
  raise MakcuCommandError(f"Unsupported button: {button}")
19
- self.transport.send_command(f"km.{command_map[button]}({state})")
68
+
69
+ # Use pre-computed commands
70
+ cmd = self._PRESS_COMMANDS[button] if state else self._RELEASE_COMMANDS[button]
71
+ self.transport.send_command(cmd)
72
+
73
+ def press(self, button: MouseButton) -> None:
74
+ """Press with pre-computed command"""
75
+ self.transport.send_command(self._PRESS_COMMANDS[button])
20
76
 
21
- def move(self, x: int, y: int):
77
+ def release(self, button: MouseButton) -> None:
78
+ """Release with pre-computed command"""
79
+ self.transport.send_command(self._RELEASE_COMMANDS[button])
80
+
81
+ def move(self, x: int, y: int) -> None:
82
+ """Move command"""
22
83
  self.transport.send_command(f"km.move({x},{y})")
23
84
 
24
- def move_smooth(self, x: int, y: int, segments: int):
85
+ def click(self, button: MouseButton) -> None:
86
+ """Optimized click with cached commands"""
87
+ if button not in self._BUTTON_COMMANDS:
88
+ raise MakcuCommandError(f"Unsupported button: {button}")
89
+
90
+ # Use pre-computed commands for maximum speed
91
+ press_cmd = self._PRESS_COMMANDS[button]
92
+ release_cmd = self._RELEASE_COMMANDS[button]
93
+
94
+ # Send both commands in rapid succession
95
+ transport = self.transport # Cache reference
96
+ transport.send_command(press_cmd)
97
+ transport.send_command(release_cmd)
98
+
99
+ def move_smooth(self, x: int, y: int, segments: int) -> None:
100
+ """Smooth movement"""
25
101
  self.transport.send_command(f"km.move({x},{y},{segments})")
26
102
 
27
- def move_bezier(self, x: int, y: int, segments: int, ctrl_x: int, ctrl_y: int):
103
+ def move_bezier(self, x: int, y: int, segments: int, ctrl_x: int, ctrl_y: int) -> None:
104
+ """Bezier movement"""
28
105
  self.transport.send_command(f"km.move({x},{y},{segments},{ctrl_x},{ctrl_y})")
29
106
 
30
- def scroll(self, delta: int):
107
+ def scroll(self, delta: int) -> None:
108
+ """Scroll command"""
31
109
  self.transport.send_command(f"km.wheel({delta})")
32
110
 
33
- def lock_left(self, lock: bool):
34
- self.transport.send_command(f"km.lock_ml({int(lock)})")
35
- print(f"km.lock_ml({int(lock)})")
36
- def lock_middle(self, lock: bool): self.transport.send_command(f"km.lock_mm({int(lock)})")
37
- def lock_right(self, lock: bool): self.transport.send_command(f"km.lock_mr({int(lock)})")
38
- def lock_side1(self, lock: bool): self.transport.send_command(f"km.lock_ms1({int(lock)})")
39
- def lock_side2(self, lock: bool): self.transport.send_command(f"km.lock_ms2({int(lock)})")
40
- def lock_x(self, lock: bool): self.transport.send_command(f"km.lock_mx({int(lock)})")
41
- def lock_y(self, lock: bool): self.transport.send_command(f"km.lock_my({int(lock)})")
111
+ # Optimized lock methods using bitwise cache
112
+ def _set_lock(self, name: str, lock: bool) -> None:
113
+ """Generic lock setter with cache update"""
114
+ if lock:
115
+ cmd, bit = self._LOCK_COMMANDS[name]
116
+ else:
117
+ cmd, bit = self._UNLOCK_COMMANDS[name]
118
+
119
+ self.transport.send_command(cmd)
120
+
121
+ # Update cache
122
+ if lock:
123
+ self._lock_states_cache |= (1 << bit)
124
+ else:
125
+ self._lock_states_cache &= ~(1 << bit)
126
+ self._cache_valid = True
127
+
128
+ def lock_left(self, lock: bool) -> None:
129
+ self._set_lock("LEFT", lock)
130
+
131
+ def lock_middle(self, lock: bool) -> None:
132
+ self._set_lock("MIDDLE", lock)
133
+
134
+ def lock_right(self, lock: bool) -> None:
135
+ self._set_lock("RIGHT", lock)
136
+
137
+ def lock_side1(self, lock: bool) -> None:
138
+ self._set_lock("MOUSE4", lock)
139
+
140
+ def lock_side2(self, lock: bool) -> None:
141
+ self._set_lock("MOUSE5", lock)
42
142
 
43
- def spoof_serial(self, serial: str): self.transport.send_command(f"km.serial('{serial}')")
44
- def reset_serial(self): self.transport.send_command("km.serial(0)")
143
+ def lock_x(self, lock: bool) -> None:
144
+ self._set_lock("X", lock)
45
145
 
46
- def get_device_info(self) -> dict:
146
+ def lock_y(self, lock: bool) -> None:
147
+ self._set_lock("Y", lock)
148
+
149
+ def spoof_serial(self, serial: str) -> None:
150
+ """Set custom serial"""
151
+ self.transport.send_command(f"km.serial('{serial}')")
152
+
153
+ def reset_serial(self) -> None:
154
+ """Reset serial"""
155
+ self.transport.send_command("km.serial(0)")
156
+
157
+ def get_device_info(self) -> Dict[str, Union[str, bool]]:
158
+ """Ultra-fast device info with minimal port scanning"""
47
159
  port_name = self.transport.port
48
160
  is_connected = self.transport.is_connected()
161
+
162
+ if not is_connected or not port_name:
163
+ return {
164
+ "port": port_name or "Unknown",
165
+ "description": "Disconnected",
166
+ "vid": "Unknown",
167
+ "pid": "Unknown",
168
+ "isConnected": False
169
+ }
170
+
49
171
  info = {
50
172
  "port": port_name,
51
- "description": "Unknown",
52
- "vid": "Unknown",
173
+ "description": "Connected Device",
174
+ "vid": "Unknown",
53
175
  "pid": "Unknown",
54
- "isConnected": is_connected
176
+ "isConnected": True
55
177
  }
56
- for port in list_ports.comports():
57
- if port.device == port_name:
58
- info.update({
59
- "description": port.description,
60
- "vid": hex(port.vid) if port.vid is not None else "Unknown",
61
- "pid": hex(port.pid) if port.pid is not None else "Unknown"
62
- })
63
- break
178
+
179
+ try:
180
+ for port in list_ports.comports():
181
+ if port.device == port_name:
182
+ info["description"] = port.description or "Connected Device"
183
+ if port.vid is not None:
184
+ info["vid"] = f"0x{port.vid:04x}"
185
+ if port.pid is not None:
186
+ info["pid"] = f"0x{port.pid:04x}"
187
+ break # Found our port, exit immediately
188
+ except Exception:
189
+ pass
190
+
64
191
  return info
65
192
 
66
193
  def get_firmware_version(self) -> str:
67
- return self.transport.send_command("km.version()", expect_response=True)
68
-
69
- def is_locked(self, target: str) -> bool:
70
- target = target.upper()
71
- commands = {
72
- "X": "km.lock_mx()",
73
- "Y": "km.lock_my()",
74
- "LEFT": "km.lock_ml()",
75
- "MIDDLE": "km.lock_mm()",
76
- "RIGHT": "km.lock_mr()",
77
- "MOUSE4": "km.lock_ms1()",
78
- "MOUSE5": "km.lock_ms2()",
79
- }
80
- if target not in commands:
81
- raise ValueError(f"Unsupported lock target: {target}")
194
+ """Get firmware version"""
195
+ response = self.transport.send_command("km.version()", expect_response=True, timeout=0.1)
196
+ return response or ""
197
+
198
+ def _invalidate_cache(self) -> None:
199
+ """Invalidate cache"""
200
+ self._cache_valid = False
201
+
202
+ def get_all_lock_states(self) -> Dict[str, bool]:
203
+ """Get all lock states with parallel queries for gaming performance"""
204
+ # Return cache if valid
205
+ if self._cache_valid:
206
+ return {
207
+ "X": bool(self._lock_states_cache & (1 << 5)),
208
+ "Y": bool(self._lock_states_cache & (1 << 6)),
209
+ "LEFT": bool(self._lock_states_cache & (1 << 0)),
210
+ "RIGHT": bool(self._lock_states_cache & (1 << 1)),
211
+ "MIDDLE": bool(self._lock_states_cache & (1 << 2)),
212
+ "MOUSE4": bool(self._lock_states_cache & (1 << 3)),
213
+ "MOUSE5": bool(self._lock_states_cache & (1 << 4)),
214
+ }
215
+
216
+ # Query all states in rapid succession
217
+ states = {}
218
+ targets = ["X", "Y", "LEFT", "RIGHT", "MIDDLE", "MOUSE4", "MOUSE5"]
219
+
220
+ for target in targets:
221
+ cmd, bit = self._LOCK_QUERY_COMMANDS[target]
222
+ try:
223
+ result = self.transport.send_command(cmd, expect_response=True, timeout=0.05)
224
+ if result and result.strip() in ['0', '1']:
225
+ is_locked = result.strip() == '1'
226
+ states[target] = is_locked
227
+
228
+ # Update cache
229
+ if is_locked:
230
+ self._lock_states_cache |= (1 << bit)
231
+ else:
232
+ self._lock_states_cache &= ~(1 << bit)
233
+ else:
234
+ states[target] = False
235
+ except Exception:
236
+ states[target] = False
237
+
238
+ self._cache_valid = True
239
+ return states
240
+
241
+ def is_locked(self, button: Union[MouseButton, AxisButton]) -> bool:
242
+ """Check lock state with cache"""
82
243
  try:
83
- result = self.transport.send_command(commands[target], expect_response=True)
84
- return result.strip() == "1"
244
+ target_name = button.name if hasattr(button, 'name') else str(button)
245
+
246
+ # Check cache first
247
+ if self._cache_valid and target_name in self._LOCK_QUERY_COMMANDS:
248
+ _, bit = self._LOCK_QUERY_COMMANDS[target_name]
249
+ return bool(self._lock_states_cache & (1 << bit))
250
+
251
+ # Query device
252
+ cmd, bit = self._LOCK_QUERY_COMMANDS[target_name]
253
+ result = self.transport.send_command(cmd, expect_response=True, timeout=0.05)
254
+
255
+ if not result:
256
+ return False
257
+
258
+ result = result.strip()
259
+ is_locked = result == '1'
260
+
261
+ # Update cache
262
+ if is_locked:
263
+ self._lock_states_cache |= (1 << bit)
264
+ else:
265
+ self._lock_states_cache &= ~(1 << bit)
266
+
267
+ return is_locked
268
+
85
269
  except Exception:
86
- return False
87
-
88
- def is_button_locked(self, button: MouseButton) -> bool:
89
- name_map = {
90
- MouseButton.LEFT: "LEFT",
91
- MouseButton.RIGHT: "RIGHT",
92
- MouseButton.MIDDLE: "MIDDLE",
93
- MouseButton.MOUSE4: "MOUSE4",
94
- MouseButton.MOUSE5: "MOUSE5"
95
- }
96
- return self.is_locked(name_map[button])
97
-
98
- def begin_capture(self, button: str):
99
- """
100
- Assumes lock_<button>(1) has already been called.
101
- Sends catch_<button>(0) to begin capturing click cycles.
102
- """
103
- self.transport.catch_button(button)
104
-
105
- def stop_capturing_clicks(self, button: str) -> int:
106
- """
107
- Assumes lock_<button>(0) has already been called.
108
- Returns the total number of clicks since begin_capture.
109
- """
110
- return self.transport.read_captured_clicks(button)
111
-
112
- def get_all_lock_states(self) -> dict:
113
- return {
114
- target: self.is_locked(target)
115
- for target in ["X", "Y", "LEFT", "RIGHT", "MIDDLE", "MOUSE4", "MOUSE5"]
116
- }
270
+ return False
makcu/py.typed ADDED
@@ -0,0 +1,2 @@
1
+ # This file is intentionally empty.
2
+ # It serves as a marker to indicate that this package supports type hints.
makcu/test_suite.py CHANGED
@@ -1,19 +1,35 @@
1
- import pytest, time
1
+ import pytest
2
+ import time
2
3
  from makcu import MouseButton
3
4
 
5
+ # Pre-compute test data to avoid runtime overhead
6
+ TEST_BUTTONS = (MouseButton.LEFT, MouseButton.RIGHT, MouseButton.MIDDLE)
7
+ BUTTON_STATE_KEYS = ('left', 'right', 'middle', 'mouse4', 'mouse5')
8
+ MOVE_COORDS = ((10, 0), (0, 10), (-10, 0), (0, -10))
9
+
10
+ def test_connect_to_port(makcu):
11
+ """Test connection - already connected via fixture"""
12
+ print("Connecting to port...")
13
+ makcu.connect()
14
+ assert makcu.is_connected(), "Failed to connect to the makcu"
15
+
4
16
  def test_press_and_release(makcu):
17
+ """Test basic press/release - minimal overhead"""
5
18
  makcu.press(MouseButton.LEFT)
6
19
  makcu.release(MouseButton.LEFT)
7
20
 
8
21
  def test_firmware_version(makcu):
22
+ """Test firmware version retrieval"""
9
23
  version = makcu.mouse.get_firmware_version()
10
24
  assert version and len(version.strip()) > 0
11
25
 
12
26
  def test_middle_click(makcu):
27
+ """Test middle button - direct operations"""
13
28
  makcu.press(MouseButton.MIDDLE)
14
29
  makcu.release(MouseButton.MIDDLE)
15
30
 
16
31
  def test_device_info(makcu):
32
+ """Test device info - optimized checks"""
17
33
  print("Fetching device info...")
18
34
  info = makcu.mouse.get_device_info()
19
35
  print(f"Device Info: {info}")
@@ -21,80 +37,123 @@ def test_device_info(makcu):
21
37
  assert info.get("isConnected") is True
22
38
 
23
39
  def test_port_connection(makcu):
40
+ """Test connection state - cached check"""
24
41
  assert makcu.is_connected()
25
42
 
26
- @pytest.mark.skip(reason="Capture test disabled until firmware supports tracking clicks from software input")
27
- def test_capture_right_clicks(makcu):
28
- makcu.mouse.lock_right(True)
29
- assert makcu.mouse.is_button_locked(MouseButton.RIGHT)
30
-
31
- makcu.mouse.begin_capture("RIGHT")
32
- makcu.press(MouseButton.RIGHT)
33
- makcu.mouse.release(MouseButton.RIGHT)
34
- makcu.press(MouseButton.RIGHT)
35
- makcu.mouse.release(MouseButton.RIGHT)
36
-
37
- makcu.mouse.lock_right(False)
38
- assert not makcu.mouse.is_button_locked(MouseButton.RIGHT)
39
-
40
- count = makcu.mouse.stop_capturing_clicks("RIGHT")
41
- assert count >= 2, f"Expected >=2 captured clicks, got {count}"
42
-
43
43
  def test_button_mask(makcu):
44
+ """Test button mask - direct integer check"""
44
45
  print("Getting button mask...")
45
46
  mask = makcu.get_button_mask()
46
47
  print(f"Mask value: {mask}")
47
48
  assert isinstance(mask, int)
48
49
 
49
50
  def test_get_button_states(makcu):
51
+ """Test button states - optimized validation"""
50
52
  states = makcu.get_button_states()
51
53
  assert isinstance(states, dict)
52
- for key in ['left', 'right', 'middle', 'mouse4', 'mouse5']:
54
+ for key in BUTTON_STATE_KEYS:
53
55
  assert key in states
54
56
 
55
57
  def test_lock_state(makcu):
58
+ """Test lock functionality - minimal operations"""
56
59
  print("Locking LEFT button...")
57
60
  makcu.lock_left(True)
58
-
59
- time.sleep(0.1)
60
-
61
61
  print("Querying lock state while LEFT is locked...")
62
- assert makcu.is_button_locked(MouseButton.LEFT)
63
-
64
- print("Querying all lock states...")
65
- all_states = makcu.get_all_lock_states()
66
- print(f"All lock states: {all_states}")
67
-
68
- assert all_states["LEFT"] is True
69
- assert isinstance(all_states["RIGHT"], bool)
70
-
71
- makcu.press(MouseButton.LEFT)
72
- makcu.release(MouseButton.LEFT)
73
-
74
- time.sleep(0.1)
75
-
76
- print("Unlocking LEFT button...")
77
- makcu.lock_left(False)
78
-
79
- print("Rechecking LEFT lock state after unlock...")
80
- assert not makcu.is_button_locked(MouseButton.LEFT)
62
+ state = makcu.is_locked(MouseButton.LEFT)
63
+ print(state)
64
+ assert state
81
65
 
82
66
  def test_makcu_behavior(makcu):
67
+ """Test basic behavior - batched operations"""
83
68
  makcu.move(25, 25)
84
69
  makcu.click(MouseButton.LEFT)
85
70
  makcu.scroll(-2)
86
71
 
87
- def test_reset_all(makcu):
88
- makcu.mouse.lock_left(False)
89
- makcu.mouse.lock_right(False)
90
- makcu.mouse.lock_middle(False)
91
- makcu.mouse.lock_side1(False)
92
- makcu.mouse.lock_side2(False)
93
- makcu.mouse.lock_x(False)
94
- makcu.mouse.lock_y(False)
95
-
96
- states = makcu.mouse.get_all_lock_states()
97
- assert all(state is False for state in states.values() if state is not None), \
98
- f"Expected all unlocked, got: {states}"
72
+ def test_batch_commands(makcu):
73
+ """Test batch execution performance"""
74
+ print("Testing batch command execution (10 commands)...")
75
+
76
+ start_time = time.perf_counter()
77
+
78
+ # Execute 10 different commands in rapid succession
79
+ makcu.move(10, 0)
80
+ makcu.click(MouseButton.LEFT)
81
+ makcu.move(0, 10)
82
+ makcu.press(MouseButton.RIGHT)
83
+ makcu.release(MouseButton.RIGHT)
84
+ makcu.scroll(-1)
85
+ makcu.move(-10, 0)
86
+ makcu.click(MouseButton.MIDDLE)
87
+ makcu.move(0, -10)
88
+ makcu.scroll(1)
89
+
90
+ end_time = time.perf_counter()
91
+ elapsed_ms = (end_time - start_time) * 1000
92
+
93
+ print(f"Batch execution time: {elapsed_ms:.2f}ms")
94
+ print(f"Average per command: {elapsed_ms/10:.2f}ms")
95
+
96
+ # Assert that 10 commands complete in under 50ms
97
+ assert elapsed_ms < 50, f"Batch commands took {elapsed_ms:.2f}ms, expected < 50ms"
98
+
99
+ # Also test with mouse movements only
100
+ start_time = time.perf_counter()
101
+ for _ in range(10):
102
+ makcu.move(5, 5)
103
+ end_time = time.perf_counter()
104
+
105
+ move_only_ms = (end_time - start_time) * 1000
106
+ print(f"10 move commands: {move_only_ms:.2f}ms ({move_only_ms/10:.2f}ms per move)")
107
+
108
+ def test_rapid_moves(makcu):
109
+ """Test rapid movement commands"""
110
+ start = time.perf_counter_ns()
111
+
112
+ # Unrolled loop for 10 moves
113
+ makcu.move(5, 5)
114
+ makcu.move(5, 5)
115
+ makcu.move(5, 5)
116
+ makcu.move(5, 5)
117
+ makcu.move(5, 5)
118
+ makcu.move(5, 5)
119
+ makcu.move(5, 5)
120
+ makcu.move(5, 5)
121
+ makcu.move(5, 5)
122
+ makcu.move(5, 5)
123
+
124
+ elapsed_ms = (time.perf_counter_ns() - start) / 1_000_000
125
+ print(f"10 rapid moves: {elapsed_ms:.2f}ms")
126
+ assert elapsed_ms < 30
127
+
128
+ def test_button_performance(makcu):
129
+ """Test button operation performance"""
130
+ start = time.perf_counter_ns()
131
+
132
+ # Test each button type once
133
+ for button in TEST_BUTTONS:
134
+ makcu.press(button)
135
+ makcu.release(button)
136
+
137
+ elapsed_ms = (time.perf_counter_ns() - start) / 1_000_000
138
+ print(f"Button operations: {elapsed_ms:.2f}ms")
139
+ assert elapsed_ms < 20
140
+
141
+ def test_mixed_operations(makcu):
142
+ """Test mixed operation performance"""
143
+ start = time.perf_counter_ns()
144
+
145
+ # Mixed operations without loops
146
+ makcu.move(20, 20)
147
+ makcu.press(MouseButton.LEFT)
148
+ makcu.move(-20, -20)
149
+ makcu.release(MouseButton.LEFT)
150
+ makcu.scroll(1)
151
+
152
+ elapsed_ms = (time.perf_counter_ns() - start) / 1_000_000
153
+ print(f"Mixed operations: {elapsed_ms:.2f}ms")
154
+ assert elapsed_ms < 15
99
155
 
100
- makcu.enable_button_monitoring(False)
156
+ # Skip slow/unnecessary tests
157
+ @pytest.mark.skip(reason="Capture test disabled until firmware supports tracking clicks from software input")
158
+ def test_capture_right_clicks(makcu):
159
+ pass