Read and Decode Data From Your Mouse Using This PyUSB Hack

As an Amazon Associate this site may earn from qualifying purchases made through the suggested links below.

Find Your Mouse's Vendor and Product ID

If you don't already know them, use this method to find your ids. Either the decimal or hexadecimal values are fine. The hexadecimal usually start with a 0x, or at least a 0, whereas the decimal is just a regular integer number.

Code to Read Data From A Mouse

This assumes PyUSB is installed and working, and that you have your vendor and product IDs. If not, go do those things first.

This code was written for Linux (I run Ubuntu), but it should work on Mac, and even Windows, with little to no tweaking. If anything needs to be tweaked, it's likely libUSB or Python related.

  • Edit line 6 and change the 1118 with your decimal vendor ID and change the 1917 to your product ID
  • Alternatively, comment out line 6, uncomment line 8 and edit it to use your hexadecimal values
  • Copy and paste the code below to a file. I saved mine as mouse.py
  • The code must be run as the root / admin user or else you'll get [Errno 13] Access denied (insufficient permissions)
  • Run the code, sudo python mouse.py (sudo is a Linux thing, Windows users, run it as an administrator)
  • Move and/or click your mouse buttons and you should see numbers appear on the screen. It will read 50 values and the program will end
#!/usr/bin/python
import sys
import usb.core
import usb.util
# decimal vendor and product values
dev = usb.core.find(idVendor=1118, idProduct=1917)
# or, uncomment the next line to search instead by the hexidecimal equivalent
#dev = usb.core.find(idVendor=0x45e, idProduct=0x77d)
# first endpoint
interface = 0
endpoint = dev[0][(0,0)][0]
# if the OS kernel already claimed the device, which is most likely true
# thanks to http://stackoverflow.com/questions/8218683/pyusb-cannot-set-configuration
if dev.is_kernel_driver_active(interface) is True:
  # tell the kernel to detach
  dev.detach_kernel_driver(interface)
  # claim the device
  usb.util.claim_interface(dev, interface)
collected = 0
attempts = 50
while collected < attempts :
    try:
        data = dev.read(endpoint.bEndpointAddress,endpoint.wMaxPacketSize)
        collected += 1
        print data
    except usb.core.USBError as e:
        data = None
        if e.args == ('Operation timed out',):
            continue
# release the device
usb.util.release_interface(dev, interface)
# reattach the device to the OS kernel
dev.attach_kernel_driver(interface)

Decoding / Deciphering the Mouse Data Array

Here's what I figured out from a few tests. This may be particular to my Microsoft laser mouse, so results may vary. Also, when I refer to a position, I'm referring to the actual position in bold, not the array index notation.

Mouse Button Clicks

  • array('B', [16, 1, 0, 0, 0, 0, 0, 0]) - the "1" in the 2nd position indicates a standard left mouse click
  • array('B', [16, 2, 0, 0, 0, 0, 0, 0]) - the "2" in the 2nd position indicates a standard right mouse click
  • array('B', [16, 0, 0, 0, 0, 0, 0, 0]) - all zeros occurs after any mouse button is released
  • array('B', [16, 4, 0, 0, 0, 0, 0, 0]) the "4" in the 2nd position indicates a click of the mouse wheel
  • array('B', [16, 16, 0, 0, 0, 0, 0, 0]) the "16" in the 2nd position indicates a click of the button on the left side of the mouse (not the regular left click)
  • array('B', [16, 1, 0, 0, 0, 0, 1, 0]) - the "1" in the 7nd position indicates a mouse wheel forward
  • array('B', [16, 1, 0, 0, 0, 0, 255, 0]) - the "255" in the 7nd position indicates a mouse wheel backwards

Mouse Direction and Velocity

Examples of mouse direction and velocity

  • array('B', [16, 0, 255, 255, 0, 0, 0, 0]) - moving directly "left", very slowly
  • array('B', [16, 0, 1, 0, 0, 0, 0, 0]) - moving directly "right", very slowly
  • array('B', [16, 0, 0, 0, 255, 255, 0, 0]) - moving directly "up", very slowly
  • array('B', [16, 0, 0, 0, 1, 0, 0, 0]) - moving directly "down", very slowly

Moving on a diagonal, like up and to the left generates array('B', [16, 0, 255, 255, 255, 255, 0, 0])

Here's how to read the direction and velocity, positions 3 through 6.

  • 3rd position = left/right velocity
    • Left velocity range starts at 255 and decreases as the mouse moves faster to the left
    • Right velocity range starts at 1 and increases as the mouse moves faster to the right
    • 0 means the mouse is moving neither left or right
  • 4th position = left/right direction
    • 255 = left
    • 0 = right
  • 5th position = up/down velocity
    • Up velocity range starts at 255 and decreases as the mouse moves faster upward
    • Down velocity range starts at 1 and increases as the mouse moves faster downward
    • 0 means the mouse is moving neither up or down
  • 6th position = up/down direction
    • 0 = down
    • 255 = up

It Crashed, I Lost My Mouse

If the program terminates abnormally, or if you kill it with CTRL+C, your mouse will remain detached from the kernel. Fix any bugs or looping issues and re-run the program. If/when the program exits successfully it should return reattach the mouse to your operating system. Or, try unplugging and plugging the mouse back in.

Lovingly crafted by orangecoat with some rights reserved, and a promise not to spam you.

Back to top