Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Advanced desktop automation with mouse, keyboard, and screen control
.claude/skills/desktop-control-skill/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 174% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 230% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 139% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 154% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 64% | 0% |
The most advanced desktop automation skill for OpenClaw. Provides pixel-perfect mouse control, lightning-fast keyboard input, screen capture, window management, and clipboard operations.
First, install required dependencies:
bashpip install pyautogui pillow opencv-python pygetwindow
pythonfrom skills.desktop_control import DesktopController # Initialize controller dc = DesktopController(failsafe=True) # Mouse operations dc.move_mouse(500, 300) # Move to coordinates dc.click() # Left click at current position dc.click(100, 200, button="right") # Right click at position # Keyboard operations dc.type_text("Hello from OpenClaw!") dc.hotkey("ctrl", "c") # Copy dc.press("enter") # Screen operations screenshot = dc.screenshot() position = dc.get_mouse_position()
move_mouse(x, y, duration=0, smooth=True)Move mouse to absolute screen coordinates.
Parameters:
x (int): X coordinate (pixels from left)y (int): Y coordinate (pixels from top)duration (float): Movement time in seconds (0 = instant, 0.5 = smooth)smooth (bool): Use bezier curve for natural movementExample:
python# Instant movement dc.move_mouse(1000, 500) # Smooth 1-second movement dc.move_mouse(1000, 500, duration=1.0)
move_relative(x_offset, y_offset, duration=0)Move mouse relative to current position.
Parameters:
x_offset (int): Pixels to move horizontally (positive = right)y_offset (int): Pixels to move vertically (positive = down)duration (float): Movement time in secondsExample:
python# Move 100px right, 50px down dc.move_relative(100, 50, duration=0.3)
click(x=None, y=None, button='left', clicks=1, interval=0.1)Perform mouse click.
Parameters:
x, y (int, optional): Coordinates to click (None = current position)button (str): 'left', 'right', 'middle'clicks (int): Number of clicks (1 = single, 2 = double)interval (float): Delay between multiple clicksExample:
python# Simple left click dc.click() # Double-click at specific position dc.click(500, 300, clicks=2) # Right-click dc.click(button='right')
drag(start_x, start_y, end_x, end_y, duration=0.5, button='left')Drag and drop operation.
Parameters:
start_x, start_y (int): Starting coordinatesend_x, end_y (int): Ending coordinatesduration (float): Drag durationbutton (str): Mouse button to useExample:
python# Drag file from desktop to folder dc.drag(100, 100, 500, 500, duration=1.0)
scroll(clicks, direction='vertical', x=None, y=None)Scroll mouse wheel.
Parameters:
clicks (int): Scroll amount (positive = up/left, negative = down/right)direction (str): 'vertical' or 'horizontal'x, y (int, optional): Position to scroll atExample:
python# Scroll down 5 clicks dc.scroll(-5) # Scroll up 10 clicks dc.scroll(10) # Horizontal scroll dc.scroll(5, direction='horizontal')
get_mouse_position()Get current mouse coordinates.
Returns: (x, y) tuple
Example:
pythonx, y = dc.get_mouse_position() print(f"Mouse is at: {x}, {y}")
type_text(text, interval=0, wpm=None)Type text with configurable speed.
Parameters:
text (str): Text to typeinterval (float): Delay between keystrokes (0 = instant)wpm (int, optional): Words per minute (overrides interval)Example:
python# Instant typing dc.type_text("Hello World") # Human-like typing at 60 WPM dc.type_text("Hello World", wpm=60) # Slow typing with 0.1s between keys dc.type_text("Hello World", interval=0.1)
press(key, presses=1, interval=0.1)Press and release a key.
Parameters:
key (str): Key name (see Key Names section)presses (int): Number of times to pressinterval (float): Delay between pressesExample:
python# Press Enter dc.press('enter') # Press Space 3 times dc.press('space', presses=3) # Press Down arrow dc.press('down')
hotkey(*keys, interval=0.05)Execute keyboard shortcut.
Parameters:
*keys (str): Keys to press togetherinterval (float): Delay between key pressesExample:
python# Copy (Ctrl+C) dc.hotkey('ctrl', 'c') # Paste (Ctrl+V) dc.hotkey('ctrl', 'v') # Open Run dialog (Win+R) dc.hotkey('win', 'r') # Save (Ctrl+S) dc.hotkey('ctrl', 's') # Select All (Ctrl+A) dc.hotkey('ctrl', 'a')
key_down(key) / key_up(key)Manually control key state.
Example:
python# Hold Shift dc.key_down('shift') dc.type_text("hello") # Types "HELLO" dc.key_up('shift') # Hold Ctrl and click (for multi-select) dc.key_down('ctrl') dc.click(100, 100) dc.click(200, 100) dc.key_up('ctrl')
screenshot(region=None, filename=None)Capture screen or region.
Parameters:
region (tuple, optional): (left, top, width, height) for partial capturefilename (str, optional): Path to save imageReturns: PIL Image object
Example:
python# Full screen img = dc.screenshot() # Save to file dc.screenshot(filename="screenshot.png") # Capture specific region img = dc.screenshot(region=(100, 100, 500, 300))
get_pixel_color(x, y)Get color of pixel at coordinates.
Returns: RGB tuple (r, g, b)
Example:
pythonr, g, b = dc.get_pixel_color(500, 300) print(f"Color at (500, 300): RGB({r}, {g}, {b})")
find_on_screen(image_path, confidence=0.8)Find image on screen (requires OpenCV).
Parameters:
image_path (str): Path to template imageconfidence (float): Match threshold (0-1)Returns: (x, y, width, height) or None
Example:
python# Find button on screen location = dc.find_on_screen("button.png") if location: x, y, w, h = location # Click center of found image dc.click(x + w//2, y + h//2)
get_screen_size()Get screen resolution.
Returns: (width, height) tuple
Example:
pythonwidth, height = dc.get_screen_size() print(f"Screen: {width}x{height}")
get_all_windows()List all open windows.
Returns: List of window titles
Example:
pythonwindows = dc.get_all_windows() for title in windows: print(f"Window: {title}")
activate_window(title_substring)Bring window to front by title.
Parameters:
title_substring (str): Part of window title to matchExample:
python# Activate Chrome dc.activate_window("Chrome") # Activate VS Code dc.activate_window("Visual Studio Code")
get_active_window()Get currently focused window.
Returns: Window title (str)
Example:
pythonactive = dc.get_active_window() print(f"Active window: {active}")
copy_to_clipboard(text)Copy text to clipboard.
Example:
pythondc.copy_to_clipboard("Hello from OpenClaw!")
get_from_clipboard()Get text from clipboard.
Returns: str
Example:
pythontext = dc.get_from_clipboard() print(f"Clipboard: {text}")
'a' through 'z'
'0' through '9'
'f1' through 'f24'
'enter' / 'return''esc' / 'escape''space' / 'spacebar''tab''backspace''delete' / 'del''insert''home''end''pageup' / 'pgup''pagedown' / 'pgdn''up' / 'down' / 'left' / 'right''ctrl' / 'control''shift''alt''win' / 'winleft' / 'winright''cmd' / 'command' (Mac)'capslock''numlock''scrolllock''.' / ',' / '?' / '!' / ';' / ':''[' / ']' / '{' / '}''(' / ')''+' / '-' / '*' / '/' / '='Move mouse to any corner of the screen to abort all automation.
python# Enable failsafe (enabled by default) dc = DesktopController(failsafe=True)
python# Pause all automation for 2 seconds dc.pause(2.0) # Check if automation is safe to proceed if dc.is_safe(): dc.click(500, 500)
Require user confirmation before actions:
pythondc = DesktopController(require_approval=True) # This will ask for confirmation dc.click(500, 500) # Prompt: "Allow click at (500, 500)? [y/n]"
pythondc = DesktopController() # Click name field dc.click(300, 200) dc.type_text("John Doe", wpm=80) # Tab to next field dc.press('tab') dc.type_text("john@example.com", wpm=80) # Tab to password dc.press('tab') dc.type_text("SecurePassword123", wpm=60) # Submit form dc.press('enter')
python# Capture specific area region = (100, 100, 800, 600) # left, top, width, height img = dc.screenshot(region=region) # Save with timestamp import datetime timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") img.save(f"capture_{timestamp}.png")
python# Hold Ctrl and click multiple files dc.key_down('ctrl') dc.click(100, 200) # First file dc.click(100, 250) # Second file dc.click(100, 300) # Third file dc.key_up('ctrl') # Copy selected files dc.hotkey('ctrl', 'c')
python# Activate Calculator dc.activate_window("Calculator") time.sleep(0.5) # Type calculation dc.type_text("5+3=", interval=0.2) time.sleep(0.5) # Take screenshot of result dc.screenshot(filename="calculation_result.png")
python# Drag file from source to destination dc.drag( start_x=200, start_y=300, # File location end_x=800, end_y=500, # Folder location duration=1.0 # Smooth 1-second drag )
duration=0get_screen_size() to confirm dimensionsinterval for reliabilityDesktopController(failsafe=False)Install all:
bashpip install pyautogui pillow opencv-python pygetwindow
Built for OpenClaw - The ultimate desktop automation companion 🦞
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 11,669 | 6,997 | -40% | 1 | 1 | 0% | 2,057 | 5,637 | +174% | 0 | 0 | — |
case-06 | fail→pass | 6,851 | 2,050 | -70% | 1 | 1 | 0% | 1,369 | 4,524 | +230% | 0 | 0 | — |
case-02 | fail→pass | 10,495 | 5,421 | -48% | 1 | 1 | 0% | 2,267 | 5,418 | +139% | 0 | 0 | — |
case-03 | fail→pass | 10,581 | 6,456 | -39% | 1 | 1 | 0% | 2,163 | 5,487 | +154% | 0 | 0 | — |
case-04 | fail→pass | 14,231 | 3,930 | -72% | 1 | 1 | 0% | 2,969 | 4,867 | +64% | 0 | 0 | — |
case-05 | fail→pass | 10,352 | 2,524 | -76% | 1 | 1 | 0% | 1,934 | 4,660 | +141% | 0 | 0 | — |
case-07 | fail→pass | 8,988 | 2,511 | -72% | 1 | 1 | 0% | 1,251 | 4,625 | +270% | 0 | 0 | — |
case-08 | pass→pass | 6,951 | 2,632 | -62% | 1 | 1 | 0% | 1,347 | 4,724 | +251% | 0 | 0 | — |
case-09 | pass→pass | 7,178 | 2,274 | -68% | 1 | 1 | 0% | 1,137 | 4,509 | +297% | 0 | 0 | — |
case-10 | fail→pass | 4,815 | 2,257 | -53% | 1 | 1 | 0% | 815 | 4,479 | +450% | 0 | 0 | — |
case-11 | fail→pass | 9,485 | 3,069 | -68% | 1 | 1 | 0% | 1,896 | 4,624 | +144% | 0 | 0 | — |
case-12 | fail→pass | 7,420 | 2,226 | -70% | 1 | 1 | 0% | 1,262 | 4,562 | +261% | 0 | 0 | — |
case-13 | pass→pass | 11,348 | 3,049 | -73% | 1 | 1 | 0% | 2,274 | 4,712 | +107% | 0 | 0 | — |
case-14 | pass→pass | 10,119 | 2,892 | -71% | 1 | 1 | 0% | 1,885 | 4,725 | +151% | 0 | 0 | — |
case-15 | fail→pass | 6,624 | 4,487 | -32% | 1 | 1 | 0% | 1,263 | 5,045 | +299% | 0 | 0 | — |
case-16 | fail→pass | 9,033 | 3,350 | -63% | 1 | 1 | 0% | 1,571 | 4,682 | +198% | 0 | 0 | — |
case-17 | fail→pass | 9,812 | 2,443 | -75% | 1 | 1 | 0% | 1,684 | 4,467 | +165% | 0 | 0 | — |
case-18 | pass→pass | 7,928 | 2,371 | -70% | 1 | 1 | 0% | 1,402 | 4,533 | +223% | 0 | 0 | — |
case-19 | pass→pass | 9,368 | 2,230 | -76% | 1 | 1 | 0% | 1,708 | 4,452 | +161% | 0 | 0 | — |
case-20 | pass→pass | 6,263 | 4,574 | -27% | 1 | 1 | 0% | 979 | 5,056 | +416% | 0 | 0 | — |
case-21 | pass→pass | 6,748 | 4,574 | -32% | 1 | 1 | 0% | 1,262 | 5,016 | +297% | 0 | 0 | — |
case-22 | pass→pass | 8,357 | 7,445 | -11% | 1 | 1 | 0% | 1,648 | 5,718 | +247% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +59 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/28/2026 | +55% |
Other measured skills in the registry, with their headline benchmark lift.