4

I'm using a Windows10 system.

I have a Tkinter canvas which has an image drawn on it. Is there any way to slow down mouse pointer speed when it is hovering over the canvas? I've checked out this link and this link but the answer seems unstable..

To be more specific, is it possible to slow down mouse pointer speed in plain Python/Tkinter?

Anjali
  • 508
  • 6
  • 17

2 Answers2

6

On windows system you can use native SystemParametersInfo to change speed of the mouse pointer. It's possible to implement via ctype, which is part of Python's standard library (is it counts as a "plain" solution?).

Take a look at this snippet:

import ctypes

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk


def change_speed(speed=10):
    #   1 - slow
    #   10 - standard
    #   20 - fast
    set_mouse_speed = 113   # 0x0071 for SPI_SETMOUSESPEED
    ctypes.windll.user32.SystemParametersInfoA(set_mouse_speed, 0, speed, 0)


def proper_close():
    change_speed()
    root.destroy()

root = tk.Tk()
root.protocol('WM_DELETE_WINDOW', proper_close)
tk.Button(root, text='Slow', command=lambda: change_speed(1)).pack(expand=True, fill='x')
tk.Button(root, text='Standard', command=change_speed).pack(expand=True, fill='x')
tk.Button(root, text='Fast', command=lambda: change_speed(20)).pack(expand=True, fill='x')
root.mainloop()

But what if that our "standard" speed isn't equal 10? No problem! Take a look at this snippet:

import ctypes

try:
    import tkinter as tk
except ImportError:
    import Tkinter as tk


def change_speed(speed):
    #   1 - slow
    #   10 - standard
    #   20 - fast
    set_mouse_speed = 113   # 0x0071 for SPI_SETMOUSESPEED
    ctypes.windll.user32.SystemParametersInfoA(set_mouse_speed, 0, speed, 0)


def get_current_speed():
    get_mouse_speed = 112   # 0x0070 for SPI_GETMOUSESPEED
    speed = ctypes.c_int()
    ctypes.windll.user32.SystemParametersInfoA(get_mouse_speed, 0, ctypes.byref(speed), 0)

    return speed.value


def proper_close():
    change_speed(standard_speed)
    root.destroy()


root = tk.Tk()
root.protocol('WM_DELETE_WINDOW', proper_close)
root.minsize(width=640, height=480)

standard_speed = get_current_speed()

safe_zone = tk.LabelFrame(root, text='Safe Zone', bg='green')
slow_zone = tk.LabelFrame(root, text='Slow Zone', bg='red')

safe_zone.pack(side='left', expand=True, fill='both')
slow_zone.pack(side='left', expand=True, fill='both')

slow_zone.bind('<Enter>', lambda event: change_speed(1))
slow_zone.bind('<Leave>', lambda event: change_speed(standard_speed))

root.mainloop()

In other words - it's not a hard task at all. We are free at getting/setting mouse speed without crawling at registry and without rocket science computations!

More about SystemParametersInfo you can find on MSDN.

CommonSense
  • 4,232
  • 2
  • 14
  • 38
  • That is true. This indeed does work. But as @Ron Norris pointed out there is a greater risk on changing mouse speed without good error handling. But nevertheless, thanks a lot! – Anjali Jul 17 '17 at 03:16
  • So this doesn't touch registry? – Luk Aron Apr 25 '21 at 16:28
  • seems 20 is the maximum? Setting it 50 seems the same as 20. – Luk Aron Apr 25 '21 at 16:34
  • @LukAron [Exactly](https://stackoverflow.com/a/16835431/6634373)! And this does not affect the registry. – CommonSense Apr 27 '21 at 15:16
  • @CommonSense but there is a registry variable called sensitivity , which is exactly a value with 20 as maximum – Luk Aron May 05 '21 at 05:55
  • @LukAron Correct, but check the parameter of the `SystemParametersInfo` (fWinIni) function again. It gives you the ability to determine if changes are temporary or written to the registry. – CommonSense May 11 '21 at 09:54
2

The answer is "yes", but there's risk. You could slow down or speed up the mouse by writing an algorithm to control position. This approach would be a kluge and prone to error most likely. This method would leverage the event_generate function of tkinter.

root.event_generate('<Motion>', warp=True, x=xptr, y=yptr)

where root is the root (or any tk) window, and xptr, yptr are screen coordinates that force the mouse cursor to a specific screen location.

The second option is also a kluge and prone to error, but it comes at greater risk. This method has to do with editing the Windows registry. The registry entries are easy enough to find: HKEY_CURRENT_USER\Control Panel\Mouse. But be warned: ANY CHANGES TO THESE REGISTRY ENTRIES EFFECT ALL PROGRAMS. You can read this MSDN article for some recommended settings. Use the python registry module to change registry entries. But be sure to apply good error handling and exit control for your program, because you need to restore anything you change in the registry back to what it was. And if your program crashes before it can reset the registry entries, well you have to reset them manually unless you write a program that will set them to some default values.

Good luck!

Ron Norris
  • 2,642
  • 1
  • 9
  • 13