Adding hotkeys to switch to N-th screen on Windows

Keyboard shortcuts for switching between desktops on Windows

For quite a while, the multi-screen setup on my desktop was powered by Synergy.
Which, I should say, is pretty neat, aside of it's complete unwillingness to send non-English keystrokes to additional devices.

Slightly more recently I've switched to using a more conventional dual-screen setup.
Which, of course, is more convenient (being able to drag a window to the second screen without having to sync the related media first), one thing would seem to be missing — the "hotkeys".

Moving the mouse over an entire monitor (or two) only to click something and move it back is not all that exciting, and Synergy's keyboard shortcuts for moving the mouse to N-th screen (while remembering the old position for returning) were a welcome feature.

Windows, unfortunately, does not seem to have any "built-in" keyboard shortcuts for swithing to a given screen, but that can be easily fixed with help of an AutoIt script:

Const $Mons = 2 ; How many monitors have you got?
Global $MouseX[$Mons], $MouseY[$Mons]
Global $MonX[$Mons], $MonY[$Mons], $MonW[$Mons], $MonH[$Mons]
; Monitor setup
Func SetupMon($index, $x, $y, $width, $height)
	$MonX[$index] = $x
	$MonY[$index] = $y
	$MonW[$index] = $width
	$MonH[$index] = $height
	$MouseX[$index] = $x + $width / 2
	$MouseY[$index] = $y + $height / 2
EndFunc
; Setup your monitors here:
SetupMon(0, 0, 0, 1920, 1080)
SetupMon(1, 1920, 0, 1920, 1080)
;
Func SwitchToMon($index)
	$mx = MouseGetPos(0)
	$my = MouseGetPos(1)
	; Find, on which monitor the mouse currently is:
	$mm = -1
	For $i = 0 To $Mons - 1
		If ($mx > $MonX[$i]) And ($mx < $MonX[$i] + $MonW[$i]) And ($my > $MonY[$i]) And ($my < $MonY[$i] + $MonH[$i]) Then
			$mm = $i
		EndIf
	Next
	; Store the current monitor' mouse coordinates:
	If ($mm >= 0) Then
		$MouseX[$mm] = $mx
		$MouseY[$mm] = $my
	EndIf
	; Switch to the target monitor:
	MouseMove($MouseX[$index], $MouseY[$index], 0)
EndFunc
; Bindings:
Func SwitchToMon0()
	SwitchToMon(0)
EndFunc
HotKeySet("^#{LEFT}", "SwitchToMon0")
Func SwitchToMon1()
	SwitchToMon(1)
EndFunc
HotKeySet("^#{RIGHT}", "SwitchToMon1")
;
While (True)
	Sleep(1000)
WEnd

The process of adjusting the script for your setup is as following:

  • Change "2" on the first line to match the number of available screens.
  • Edit the "Setup your monitors here" section to match with your screen sizes and positions.
    If the screens are arranged horizontally, the X for each will be X+Width of the previous one.
    As an example, this part is configured for two 1920x1080 screens.
  • Edit the "Bindings" section to use the preferred key combinations.
    See documentation for Send() function for the format.
    If you have more than two monitors, you'll need to add additional pairs of functions and HotKeySet calls (calling SwitchToMon(2), SwitchToMon(3), and so on).
    As an example, this part is configured to have Control+Windows+Left to switch to the first monitor and Control+Windows+Right to switch to the second monitor.

Upon being ran, the program will listen for defined hotkeys until closed (via the icon in the Windows tray). As can be observed in the GIF in the beginning of this post, the mouse instantly changes the screen upon pressing the key combination, and will jump back to the original position upon switching back to the previous screen. All lightweight and tweakable.

Update (December 2016)

After evaluating things that I liked in Synergy (which is great if you have a multi-station rather than a multi-monitor setup), I made some modernizations to the macros - it now allows to use "+"/"-" arguments for switching to next/previous monitor, and will preserve and restore previously active window per that monitor, which is pretty rad of a function.

Const $Mons = 2 ; How many monitors have you got?
Global $MouseX[$Mons], $MouseY[$Mons], $CurMon
Global $MonX[$Mons], $MonY[$Mons], $MonW[$Mons], $MonH[$Mons], $HWnd[$Mons]
; Monitor setup
Func SetupMon($index, $x, $y, $width, $height)
	$MonX[$index] = $x
	$MonY[$index] = $y
	$MonW[$index] = $width
	$MonH[$index] = $height
	$MouseX[$index] = $x + $width / 2
	$MouseY[$index] = $y + $height / 2
	$HWnd[$index] = 0;
EndFunc
; Setup your monitors here:
SetupMon(0, 1920*0, 0, 1920, 1080)
SetupMon(1, 1920*1, 0, 1920, 1080)
;
Func SwitchToMon($index)
	$mx = MouseGetPos(0)
	$my = MouseGetPos(1)
	; Find, on which monitor the mouse currently is:
	$mm = -1
	For $i = 0 To $Mons - 1
		If ($mx >= $MonX[$i]) And ($mx < $MonX[$i] + $MonW[$i]) And ($my >= $MonY[$i]) And ($my < $MonY[$i] + $MonH[$i]) Then
			$mm = $i
		EndIf
	Next
	; Handle
	If ($index == "-") Then
		$index = $mm - 1
		If ($index < 0) Then
			$index = $index + $Mons
		EndIf
	EndIf
	If ($index == "+") Then
		$index = Mod($mm + 1, $Mons)
	EndIf
	; Store the current monitor' mouse coordinates:
	If ($mm >= 0) Then
		$MouseX[$mm] = $mx
		$MouseY[$mm] = $my
		$HWnd[$mm] = WinGetHandle("[ACTIVE]")
	EndIf
	; Switch to the target monitor:
	If ($mm <> $index) Then
		MouseMove($MouseX[$index], $MouseY[$index], 0)
		$hdl = $HWnd[$index]
		If ($hdl <> 0 And WinExists($hdl)) Then
			WinActivate($hdl)
		EndIf
	EndIf
EndFunc
; Bindings:
Func SwitchToMon0()
	SwitchToMon(0)
EndFunc
HotKeySet("^#{LEFT}", "SwitchToMon0")
Func SwitchToMon1()
	SwitchToMon(1)
EndFunc
HotKeySet("^#{RIGHT}", "SwitchToMon1")
; Loop:
While (True)
	Sleep(1000)
WEnd

Have fun!

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.