AutoHotkey - MS Windows 10 - Open Apps on Multiple Monitors and Desktops

Applies to:
  • Microsoft Windows 10
  • AutoHotkey 1.1.30
Yay for Microsoft Windows 10 in joining the rest of the Operating Systems in implementing multiple desktops. So if you have a Mac or Linux system, you will know of a feature where you can have another virtual desktop on your device.

For those that don't know it, the feature is similar to mobile phones where you swipe left/right to reveal another screen of app icons. The same can be done to the desktop versions with open applications instead of just their icons.

MS Windows 10 has made a major step but when you close down your PC and log back in, all the applications are grouped into the one desktop. If you have a multiple monitor setup (ie. more than 1 monitor), then MS Windows will almost remember which apps were open on which screen but always on Desktop 1.

In addition, there are some developments on AutoHotkey forums where people are having difficulties opening an app on their second monitor. So I thought I'd jot down some notes here on how I've achieved this across multiple monitors... and now multiple desktops.

The following example is assuming you have 3 monitors and 3 desktops. I'm going to cover the basic code to: 1) get all monitors, 2) open an app on a specified monitor, 3) switch to another desktop.

Count Monitors and Check it can see left-most, central, and right-most monitors:
; init
    DetectHiddenWindows, Off
    v_LeftMost := 0
    v_Center := 0
    v_RightMost := 0
    a_MyArray := Array()

    ; get all monitors (excl. hidden/virtual)
    SysGet, v_MonitorCount, 80
    Loop %v_MonitorCount%
        ; monitor boundaries
        SysGet, v_Monitor%A_Index%, Monitor, %A_Index%
        v_x1 := v_Monitor%A_Index%Left
        v_y1 := v_Monitor%A_Index%Top
        v_x2 := v_Monitor%A_Index%Right
        v_y2 := v_Monitor%A_Index%Bottom

        ; determine if leftest
        if(v_x1 < v_LeftMost)
            v_LeftMost:= v_x1
            a_MyArray[0,0] := v_x1
            a_MyArray[0,1] := v_y1
            a_MyArray[0,2] := v_x2
            a_MyArray[0,3] := v_y2
        else if(v_x1 > v_RightMost)
            v_RightMost:= v_x1
            a_MyArray[2,0] := v_x1
            a_MyArray[2,1] := v_y1
            a_MyArray[2,2] := v_x2
            a_MyArray[2,3] := v_y2
            v_Center:= v_x1
            a_MyArray[1,0] := v_x1
            a_MyArray[1,1] := v_y1
            a_MyArray[1,2] := v_x2
            a_MyArray[1,3] := v_y2

    ; output test
    v_Leftest := a_MyArray[0,0]
    v_Central := a_MyArray[1,0]
    v_Rightest := a_MyArray[2,0]
    MsgBox 1: %v_Leftest% 2: %v_Central% 3: %v_Rightest%
  1.  ; init 
  2.      DetectHiddenWindows, Off 
  3.      v_LeftMost :0 
  4.      v_Center :0 
  5.      v_RightMost :0 
  6.      a_MyArray :Array() 
  8.      ; get all monitors (excl. hidden/virtual) 
  9.      SysGet, v_MonitorCount, 80 
  10.      Loop %v_MonitorCount% 
  11.      { 
  12.          ; monitor boundaries 
  13.          SysGet, v_Monitor%A_Index%, Monitor, %A_Index% 
  14.          v_x1 := v_Monitor%A_Index%Left 
  15.          v_y1 := v_Monitor%A_Index%Top 
  16.          v_x2 := v_Monitor%A_Index%Right 
  17.          v_y2 := v_Monitor%A_Index%Bottom 
  19.          ; determine if leftest 
  20.          if(v_x1 < v_LeftMost) 
  21.          { 
  22.              v_LeftMost:= v_x1 
  23.              a_MyArray[0,0] := v_x1 
  24.              a_MyArray[0,1] := v_y1 
  25.              a_MyArray[0,2] := v_x2 
  26.              a_MyArray[0,3] := v_y2 
  27.          } 
  28.          else if(v_x1 > v_RightMost) 
  29.          { 
  30.              v_RightMost:= v_x1 
  31.              a_MyArray[2,0] := v_x1 
  32.              a_MyArray[2,1] := v_y1 
  33.              a_MyArray[2,2] := v_x2 
  34.              a_MyArray[2,3] := v_y2 
  35.          } 
  36.          else 
  37.          { 
  38.              v_Center:= v_x1 
  39.              a_MyArray[1,0] := v_x1 
  40.              a_MyArray[1,1] := v_y1 
  41.              a_MyArray[1,2] := v_x2 
  42.              a_MyArray[1,3] := v_y2 
  43.          } 
  44.      } 
  46.      ; output test 
  47.      v_Leftest := a_MyArray[0,0] 
  48.      v_Central := a_MyArray[1,0] 
  49.      v_Rightest := a_MyArray[2,0] 
  50.      MsgBox 1: %v_Leftest% 2: %v_Central% 3: %v_Rightest% 

Now there is an issue in that Monitor 1,2, and 3 might not be in the order placed on the desk and not in the order of left to right. So the above code tries to determine the leftmost monitor and rightmost with the last being in the centre.

First of all here's the code to open a windows application on a non-default monitor:
; Get full screen coordinates for the right-most (3rd) monitor
    v_XCoord := a_MyArray[2,0]
    v_YCoord := a_MyArray[2,1]
    v_ThisWidth := a_MyArray[2, 2] - a_MyArray[2, 0]
    v_ThisHeight := a_MyArray[2, 3] - a_MyArray[2, 1]

    ; Open Notepad on right-most (3rd) Screen
    RunWait, Notepad.exe
    v_LastID := WinExist("A")
    WinMove, ahk_id %v_LastID%,, %v_XCoord%, %v_YCoord%, %v_ThisWidth%, %v_ThisHeight%
  1.  ; Get full screen coordinates for the right-most (3rd) monitor 
  2.      v_XCoord := a_MyArray[2,0] 
  3.      v_YCoord := a_MyArray[2,1] 
  4.      v_ThisWidth := a_MyArray[2, 2] - a_MyArray[2, 0] 
  5.      v_ThisHeight := a_MyArray[2, 3] - a_MyArray[2, 1] 
  7.      ; Open Notepad on right-most (3rd) Screen 
  8.      RunWait, Notepad.exe 
  9.      v_LastID :WinExist("A") 
  10.      WinMove, ahk_id %v_LastID%,, %v_XCoord%, %v_YCoord%, %v_ThisWidth%, %v_ThisHeight% 

And switching desktop? Well considering you cycle (can't jump to) to the previous or next desktop by holding down the Control (CTRL) and Windows Key then the left or right arrow keys as appropriate... the code in AutoHotkey being:
; next desktop
    Send, ^#{Right}

    ; previous desktop
    Send, ^#{Left}
  1.  ; next desktop 
  2.      Send, ^#{Right} 
  4.      ; previous desktop 
  5.      Send, ^#{Left} 

The above example, is if you have 3 monitors. If you only have 2 monitors, then note that right-most will not exist and only left and centre should with the central screen starting at coordinates 0,0 (might be different on your setup)...

Note that removing the width and height parameters should simply load the app without resizing it to the maximum width/height of the screen.

Windows 10 Mail
Lastly: Want to start a built-in app in Windows 10 (not found in your program files etc) like Windows Mail? Open a run command and type:
  1.  shell:appsfolder 
This will open your applications in explorer (much like MacOS). You can then create shortcuts from these and more importantly see the command to open them. Note that the MS Windows 10 Mail shortcut will be something like target: microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail. The easiest way to do this is to right-click and drag to the desktop (or wherever you want to store shortcuts) then run the shortcut:
RunWait, "C:\Users\Joel\Documents\_shortcuts\Mail - Shortcut.lnk"
  1.  RunWait, "C:\Users\Joel\Documents\_shortcuts\Mail - Shortcut.lnk" 
Without a shortcut, the command to run is:
RunWait, "C:\Windows\explorer.exe" "shell:AppsFolder\microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail"
  1.  RunWait, "C:\Windows\explorer.exe" "shell:AppsFolder\microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.mail" 

Google Chrome Profiles
Even more final than lastly: Suppose you didn't opt to create a desktop shortcut when creating a specific user profile in Google Chrome or you've deleted it and don't know what the profile number is: To create another desktop shortcut, open Google Chrome browser with the profile you want to create a desktop shortcut for. Then browse to chrome://settings/manageProfile and click on the profile, this will create another shortcut on your desktop. Then right-click the shortcut and view the properties, the target will have the profile number:
RunWait, "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 11" ""

; load further tabs
RunWait, "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 11" ""
RunWait, "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 11" ""
  1.  RunWait, "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 11" "" 
  3.  ; load further tabs 
  4.  RunWait, "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 11" "" 
  5.  RunWait, "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --profile-directory="Profile 11" "" 

Category: AutoHotkey :: Article: 688

Credit where Credit is Due:

Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: Please note that the information provided on this website is intended for informational purposes only and does not represent a warranty. The opinions expressed are those of the author only. We recommend testing any solutions in a development environment before implementing them in production. The articles are based on our good faith efforts and were current at the time of writing, reflecting our practical experience in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman

Related Articles

Joes Revolver Map


Badge - Certified Zoho Creator Associate
Badge - Certified Zoho Creator Associate

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Donate to Joel Lipman via PayPal

Donate to Joel Lipman with Bitcoin bc1qf6elrdxc968h0k673l2djc9wrpazhqtxw8qqp4

Donate to Joel Lipman with Ethereum 0xb038962F3809b425D661EF5D22294Cf45E02FebF
© 2023 Joel Lipman .com. All Rights Reserved.