Mouse Helper Class

The Mouse class is an internal helper that handles the low-level mouse operations for the MakcuController. While you typically won’t use this class directly, understanding it can help with advanced usage and troubleshooting.

Class Overview

The Mouse class provides:

  • Raw Command Generation: Creates the actual device commands

  • State Management: Tracks button states and lock status

  • Protocol Handling: Formats commands for the Makcu device

  • Response Parsing: Interprets device responses

Note: You typically don’t create Mouse instances directly. The MakcuController creates and manages one for you.

Internal Architecture

The Mouse class works as a bridge between your Python code and the Makcu device’s protocol:

Your Code β†’ MakcuController β†’ Mouse β†’ SerialTransport β†’ Device

makcu.click() β†’ mouse.click() β†’ "km.click(1)" β†’ Device

This layered approach provides: - Clean separation of concerns - Easy testing and debugging - Protocol abstraction - State management

Core Operations

Click Operations

The click method generates commands like:

# Internal command generation:
mouse.click(MouseButton.LEFT)    # β†’ "km.click(1)"
mouse.click(MouseButton.RIGHT)   # β†’ "km.click(2)"
mouse.click(MouseButton.MIDDLE)  # β†’ "km.click(4)"
# Press/release generate separate commands:
mouse.press(MouseButton.LEFT)    # β†’ "km.press(1)"
mouse.release(MouseButton.LEFT)  # β†’ "km.release(1)"

Movement Operations

# Movement commands:
mouse.move(100, 50)  # β†’ "km.move(100,50)"
mouse.move(-25, 0)   # β†’ "km.move(-25,0)"
# Scroll commands:
mouse.scroll(-3)  # β†’ "km.scroll(-3)"
mouse.scroll(2)   # β†’ "km.scroll(2)"

State Management

Button State Tracking

The Mouse class maintains an internal representation of button states:

# Internal state format (bitwise):
# Bit 0 (1): LEFT button
# Bit 1 (2): RIGHT button
# Bit 2 (4): MIDDLE button
# Bit 3 (8): MOUSE4 button
# Bit 4 (16): MOUSE5 button

states = mouse.get_button_states()
# Returns: {"LEFT": False, "RIGHT": True, "MIDDLE": False, ...}
# Check individual button state:
if mouse.is_pressed(MouseButton.LEFT):
    print("Left button is pressed")

Lock State Management

The locking system prevents buttons/axes from functioning:

# Lock commands:
mouse.lock(MouseButton.LEFT)  # β†’ "km.lock.button(1)"
mouse.lock("X")               # β†’ "km.lock.axis(1)"
mouse.lock("Y")               # β†’ "km.lock.axis(2)"
# Query lock state:
mouse.is_locked(MouseButton.LEFT)  # β†’ "km.lock.query(1)"
mouse.is_locked("X")               # β†’ "km.lock.query.axis(1)"
# Batch query for performance:
locks = mouse.get_all_lock_states()
# β†’ "km.lock.query.all()" β†’ parsing response

Protocol Details

Command Format

The Mouse class generates commands in the Makcu protocol format:

Basic Commands: .. code-block:: text

km.click(button) # Click button (1=LEFT, 2=RIGHT, 4=MIDDLE, etc.) km.press(button) # Press and hold button km.release(button) # Release button km.move(x,y) # Move mouse relatively km.scroll(delta) # Scroll wheel

State Commands: .. code-block:: text

km.button.state() # Get button states (returns bitmask) km.button.query(btn) # Check if button is pressed

Lock Commands: .. code-block:: text

km.lock.button(btn) # Lock button km.unlock.button(btn) # Unlock button km.lock.axis(axis) # Lock movement axis (1=X, 2=Y) km.lock.query.all() # Get all lock states

Response Parsing

The Mouse class parses device responses:

# Example response parsing:
raw_response = ">>> button_state:7"  # Bitmask: 7 = LEFT+RIGHT+MIDDLE

# Parsed into:
parsed_states = {
    "LEFT": True,    # Bit 0 set
    "RIGHT": True,   # Bit 1 set
    "MIDDLE": True,  # Bit 2 set
    "MOUSE4": False, # Bit 3 not set
    "MOUSE5": False  # Bit 4 not set
}

Button Mapping

The Mouse class uses internal button mapping:

# MouseButton enum to device values:
BUTTON_MAPPING = {
    MouseButton.LEFT: 1,    # Binary: 00001
    MouseButton.RIGHT: 2,   # Binary: 00010
    MouseButton.MIDDLE: 4,  # Binary: 00100
    MouseButton.MOUSE4: 8,  # Binary: 01000
    MouseButton.MOUSE5: 16  # Binary: 10000
}

# Multiple buttons can be combined:
# LEFT + RIGHT = 3 (binary: 00011)

Advanced Features

Batch Operations

# Execute multiple operations efficiently:
mouse.batch_execute([
    lambda: mouse.move(50, 0),
    lambda: mouse.click(MouseButton.LEFT),
    lambda: mouse.scroll(-1)
])

Human-Like Timing

The Mouse class includes timing profiles for realistic behavior:

# Timing profiles (internal delays):
PROFILES = {
    "gaming": (0.001, 0.003),    # 1-3ms between clicks
    "fast": (0.02, 0.08),        # 20-80ms
    "normal": (0.1, 0.3),        # 100-300ms
    "slow": (0.3, 0.8),          # 300-800ms
    "variable": (0.05, 0.5)      # 50-500ms (random)
}

Error Handling

The Mouse class handles various error conditions:

# Common error scenarios:
try:
    mouse.click(MouseButton.LEFT)
except Exception as e:
    # Device communication errors
    # Invalid button parameters
    # Timeout errors
    # Connection lost errors
    pass

Internal State Properties

The Mouse class maintains several internal properties:

# Button states (cached for performance)
mouse._button_states = 0  # Bitmask of pressed buttons

# Lock states (cached)
mouse._lock_states = {
    "LEFT": False, "RIGHT": False, "MIDDLE": False,
    "MOUSE4": False, "MOUSE5": False,
    "X": False, "Y": False
}

# Transport reference
mouse.transport = serial_transport_instance

Performance Optimizations

The Mouse class includes several performance optimizations:

Pre-computed Commands: .. code-block:: python

# Commands are pre-formatted for speed: CLICK_COMMANDS = {

MouseButton.LEFT: β€œkm.click(1)”, MouseButton.RIGHT: β€œkm.click(2)”, # … etc

}

State Caching: .. code-block:: python

# Button states cached to avoid repeated queries: if not self._state_cache_expired():

return self._cached_button_states

Bitwise Operations: .. code-block:: python

# Fast button state checking: def is_pressed(self, button):

mask = BUTTON_MAPPING[button] return bool(self._button_states & mask)

Usage Examples

Direct Usage (Advanced):

# You typically don't do this - use MakcuController instead
from makcu.mouse import Mouse
from makcu.connection import SerialTransport

transport = SerialTransport("COM3")
mouse = Mouse(transport)

# Direct mouse operations:
mouse.click(MouseButton.LEFT)
mouse.move(100, 50)

Accessing via MakcuController:

from makcu import create_controller, MouseButton

makcu = create_controller()

# Access the internal mouse instance:
internal_mouse = makcu.mouse

# Now you can call mouse methods directly if needed:
internal_mouse.click(MouseButton.LEFT)

Debugging

The Mouse class supports debug output:

# Debug output shows command generation:
mouse.debug = True
mouse.click(MouseButton.LEFT)

# Output:
# [DEBUG] Generated command: km.click(1)
# [DEBUG] Sending to transport...
# [DEBUG] Response received: >>> clicked

Thread Safety

The Mouse class is not thread-safe. It maintains internal state that can be corrupted by concurrent access. Always use proper synchronization if accessing from multiple threads.

Integration with Transport Layer

The Mouse class works closely with the SerialTransport:

# Command flow:
mouse.click(MouseButton.LEFT)
↓
command = "km.click(1)"  # Generated by Mouse
↓
transport.send_command(command)  # Sent via SerialTransport
↓
response = ">>> clicked"  # Received from device
↓
mouse.parse_response(response)  # Processed by Mouse

Limitations

Synchronous Only: The Mouse class is designed for synchronous operations. For async usage, see the AsyncMouse class.

Single Device: Each Mouse instance works with one device connection.

State Timing: Button state queries may have slight delays (~1ms) due to device communication.

See Also