Keyboard shortcuts (hotkeys) to move mouse to monitors in a multi-monitor configuration - AutoHotkey Script

Published on
7,726 Points
3 Endorsements
Last Modified:
Joe Winograd
50+ years in computer industry
CIO•Document Imaging
EE — FELLOW 2017
MVE 2015,2016,2018
RENOWNED 2018,2019
GOLD 2020
In a question here at Experts Exchange, a member has users with a large number of monitors connected to their W10 computers. The member wants an AutoHotkey script that defines hotkeys — Alt+Ctrl+1, Alt+Ctrl+2, etc. — to move the mouse pointer to the monitors. This article presents such a solution.


In an interesting question here at Experts Exchange, a member requested this:

Code for using Windows AutoHotkey to immediately move mouse pointer to particular monitor

The member has "...several users who have 8 or more monitors connected to their Windows 10 computers." The requirement is to write an AutoHotkey script that defines a series of keyboard shortcuts (aka "hotkeys") to move the mouse pointer to each monitor. In particular:

Alt+Ctrl+1 ==> move mouse to monitor 1
Alt+Ctrl+2 ==> move mouse to monitor 2
Alt+Ctrl+3 ==> move mouse to monitor 3
Alt+Ctrl+4 ==> move mouse to monitor 4
Alt+Ctrl+5 ==> move mouse to monitor 5
Alt+Ctrl+6 ==> move mouse to monitor 6
Alt+Ctrl+7 ==> move mouse to monitor 7
Alt+Ctrl+8 ==> move mouse to monitor 8
Alt+Ctrl+9 ==> move mouse to monitor 9

I wrote a no-frills script (Version 1) and posted it at the EE thread. After that, however, I decided to write this EE article with an enhanced script (Version 2).

Version 1 Features

The following features are in V1:

• Defines the nine hotkeys shown above.

• Defines Alt+Ctrl+0 (zero) as a hotkey to exit the script.

• Allows other "modifier" keys to be used for the hotkeys rather than hard-coding Alt+Ctrl ("!^"), as follows:

! (exclamation mark) ==> Alt
^ (caret, circumflex, hat) ==> Ctrl
+ (plus sign) ==> Shift
# (hash mark, pound sign, octothorpe) ==> Win (Windows logo key)

You may use any number of those modifiers, and they may be in any order, that is, "!^" (Alt+Ctrl) behaves the same as "^!" (Ctrl+Alt).

• Allows horizontal (X) and vertical (Y) offsets to be specified. That is, the mouse pointer will be moved to the specified number of pixels (OffsetX) from the left edge of the monitor and the specified number of pixels (OffsetY) from the top edge of the monitor.

• The script does not have a system tray (notification area) icon. I did this intentionally, as the default AutoHotkey context menu (exposed via a right-click on the system tray icon, and containing Exit) is likely to be confusing for many users.

Article Update 31-Dec-2019: In private correspondence, an EE member asked me to enhance the script with an option to start it automatically when Windows starts. I did this and replaced the attached V2 script with the V3 one. Note that V3 is backward compatible with V2, as the V3 default is not to start with Windows (same as V2). Also, I modified all the article sections below to contain V3 content rather than V2.

Version 3 Features

V3 has all the features documented above in V1, except for two modifications. First, it displays an icon in the system tray (V1 does not). The default is a monitor icon, but it can be changed to a mouse icon (see below). The icons look like this (may vary depending on the version of Windows, as it uses icons from a built-in Windows file):

Second, V3 changes the meaning of the Alt+Ctrl+0 hotkey (of course, you may use modifiers other than Alt+Ctrl). In V1, it exits the script, which is a necessary feature because there is no tray icon with a context menu containing an Exit choice. In V3, Alt+Ctrl+0 moves the mouse to the Primary monitor, regardless of what monitor number the Primary monitor is (exiting the script is done differently in V3, discussed below).

In addition to those two changes, V3 has the following new features:

• If OffsetX is set to -1, it moves the mouse to the horizontal center of the monitor. Otherwise, it acts the same as in V1, i.e., it is the pixel offset from the left edge of the monitor.

• If OffsetY is set to -1, it moves the mouse to the vertical center of the monitor. Otherwise, it acts the same as in V1, i.e., it is the pixel offset from the top edge of the monitor.

• Displays a tooltip when hovering on the system tray icon. The tooltip gives brief usage instructions, like this:

• Displays this context menu when right-clicking on the system tray icon:

• Selecting the Show Primary Monitor Number menu item displays this dialog:

• Selecting the Show Monitor Names menu item displays this dialog:

• Selecting the Change Tray Icon menu item changes the icon to a mouse if it is currently a monitor; to a monitor if it is currently a mouse. The default icon is the monitor (but the default can be easily changed to the mouse in the AutoHotkey source code).

• Selecting the Start with Windows (On/Off toggle) menu item toggles that setting, i.e., if it is Off (the default), it turns On; if it is On, it turns Off. When it is On, a checkmark appears next to it in the context menu:

The method used to start the script with Windows is to create a shortcut (a .LNK file) and put it in the Startup folder (the one for the logged in user, not the Public one). The icon for it in the Startup folder looks like this:

Turning this off deletes the shortcut; turning it on creates the shortcut.

• Selecting the Exit menu item exits (terminates/quits) the script, thereby removing the icon from the system tray and undefining all the hotkeys. To make sure that this wasn't selected by accident, it displays this dialog, with No as the default button (so that an accidental Enter key won't cause an unwanted exit):

Version 3 Script

As noted at the top of this article, the EE member specifically asked for an AutoHotkey solution. If other readers of this article are not familiar with AutoHotkey, my EE article will get you going on it:

AutoHotkey - Getting Started

Here is the script in a code block (it is also attached as a file at the end of the article for easy downloading):

; Joe Winograd 31-Dec-2019 Version 3
#Warn,UseUnsetLocal ; warning on uninitialized variables
#NoEnv ; avoid checking empty variables to see if they are environment variables
#SingleInstance Force ; replace old instance immediately
SetBatchLines,-1 ; run at maximum speed

Gosub,InitializeVars ; initialize all variables
Gosub,ConfigureInitialTray ; configure initial system tray (notification area)

CoordMode,Mouse,Screen ; coordinates relative to entire desktop
SysGet,NumMons,MonitorCount ; get number of monitors
Hotkey,%HotkeyModifiers%0,MoveMousePrimary,On ; define Modifiers+0 hotkey to move mouse to Primary monitor regardless of its monitor number
Loop,%NumMons% ; process all monitors
  SysGet,Coordinates%MonNum%,Monitor,%MonNum% ; get coordinates for this monitor
  If (OffsetX=-1)
    MoveX:=Floor(0.5*(Right-Left)) ; center
  If (OffsetY=-1)
    MoveY:=Floor(0.5*(Bottom-Top)) ; center
  MoveToX[MonNum]:=Left+MoveX ; store mouse-move X coordinate for this monitor
  MoveToY[MonNum]:=Top+MoveY ; store mouse-move Y coordinate for this monitor
  Hotkey,%HotkeyModifiers%%MonNum%,MoveMouseMon,On ; define Modifiers+N hotkey

TrayIconFile:=A_WinDir . "\System32\setupapi.dll" ; get icons from setupapi.dll file
TrayIconNumMon:="-35" ; monitor icon
TrayIconNumMou:="-2" ; mouse icon

; *** begin variables to change ***
TrayIconNum:=TrayIconNumMon ; default icon - TrayIconNumMon=monitor or TrayIconNumMou=mouse
OffsetX:=-1 ; move mouse to this number of pixels from left edge of monitor (-1 means center)
OffsetY:=-1 ; move mouse to this number of pixels from top edge of monitor (-1 means center)
; modifier keys:  ! is Alt   ^ is Ctrl   + is Shift   # is Win (the Windows logo key)
HotkeyModifiers:="!^" ; Alt+Ctrl - these are the modifier keys for the number keys (0-9)
; *** end variables to change ***

SplitPath,A_ScriptName,,,,ProgramName ; get name of script without path or extension
NumModifiers:=StrLen(HotkeyModifiers) ; get number of modifier keys
MoveToX:={} ; declare array for mouse-move X coordinates
MoveToY:={} ; declare array for mouse-move Y coordinates

Menu,Tray,NoStandard ; do not use standard AutoHotkey context menu
Menu,Tray,Add,Show &Primary Monitor Number,ContextMenu
Menu,Tray,Add,Show Monitor &Names,ContextMenu
Menu,Tray,Add,Change Tray &Icon,ContextMenu
Menu,Tray,Add,Start with &Windows (On/Off toggle),ContextMenu
StartupLink:=A_Startup . "\" . ProgramName . ".lnk"
If (FileExist(StartupLink))
  Menu,Tray,Check,Start with &Windows (On/Off toggle)
  Menu,Tray,Uncheck,Start with &Windows (On/Off toggle)
Menu,Tray,Default,Show &Primary Monitor Number
HotkeyModifiersTip:=StrReplace(HotkeyModifiers,"+","Shift+") ; do this first so we don't catch the other plus signs
TrayTip:=HotkeyModifiersTip . "N to move mouse to monitor N (1-9)`n" . HotkeyModifiersTip . "0 to move mouse to Primary monitor`nRight-click for context menu"

If (A_ThisMenuItem="Show &Primary Monitor Number")
  SysGet,PrimaryMonNum,MonitorPrimary ; get number of Primary monitor
  MsgBox,4160,%ProgramName%,Primary monitor number is %PrimaryMonNum%
If (A_ThisMenuItem="Show Monitor &Names")
  Loop,%NumMons% ; process all monitors
    SysGet,MonName,MonitorName,%MonNum% ; get name of this monitor
    MonNames:=MonNames . MonNum . "=" . MonName . "`n"
  MsgBox,4160,%ProgramName%,Monitor names are:`n%MonNames%
If (A_ThisMenuItem="Change Tray &Icon")
  If (TrayIconNum=TrayIconNumMou)
If (A_ThisMenuItem="Start with &Windows (On/Off toggle)")
  If (FileExist(StartupLink))
    ; it's on, so this click turns it off
    Menu,Tray,Uncheck,Start with &Windows (On/Off toggle)
    ; it's off, so this click turns it on
    Menu,Tray,Check,Start with &Windows (On/Off toggle)
    FileCreateShortcut,%A_ScriptFullPath%,%StartupLink%,%A_ScriptDir%,,%ProgramName%,%TrayIconFile% ; in a DLL, only first icon is valid (in this case, it's a monitor)
      If (ErrorLevel!=0)
        MsgBox,4112,Fatal Error,Error Level=%ErrorLevel% trying to create Startup shortcut:`n%StartupLink%
If (A_ThisMenuItem="E&xit")
  MsgBox,4388,%ProgramName% - Terminate?,Are you sure you want to quit and deactivate all hotkeys?

MonNum:=SubStr(A_ThisHotkey,NumModifiers+1,1) ; monitor number is after the modifiers
X:=MoveToX[MonNum] ; retrieve horizontal mouse-move coordinate
Y:=MoveToY[MonNum] ; retrieve vertical mouse-move coordinate
MouseMove,%X%,%Y% ; move it!

SysGet,PrimaryMonNum,MonitorPrimary ; get number of Primary monitor
X:=MoveToX[PrimaryMonNum] ; retrieve horizontal mouse-move coordinate
Y:=MoveToY[PrimaryMonNum] ; retrieve vertical mouse-move coordinate
MouseMove,%X%,%Y% ; move it!

My hope is that the descriptive variable names along with the extensive comments in the script provide enough documentation for readers to modify it, but if you have any questions, post them here, and I'll try to assist.

The script should work in all versions of Windows from XP through W10, both 32-bit and 64-bit, with up to nine monitors. I tested it on W7/64-bit with three monitors and W10/64-bit with two monitors — worked perfectly! If you use it on other configurations — a different version of Windows and/or a different number of monitors — I'll really appreciate it if you post your results as a comment under the article.

If you find this article to be helpful, please click the thumbs-up icon below. This lets me know what is valuable for EE members and provides direction for future articles. Thanks very much! Regards, Joe


Ask questions about what you read
If you have a question about something within an article, you can receive help directly from the article author. Experts Exchange article authors are available to answer questions and further the discussion.
Get 7 days free