Hi,
I would like to be able to use a hotkey to switch between virtual desktop 1 to virtual desktop 2 running RDP in full screen.
I found this post https://superuser.com/questions/1046767/windows-10-switch-virtual-deskop-while-in-fullscreen-remote-desktop/1198031#1198031
Which explains how to do it manually and then user electrotype post in the notes his/her script on how to do this with autohotkey https://pastebin.com/raw/3SKkU1qt
The script does the following:
1. If in virtual desktop one, press control alt home takes you to RDP in full screen on virtual desktop two
2. If in virtual desktop two (RDP in full screen), press control alt home takes you to on virtual desktop one
I have a couple of problems and the script is much more complex than I can understand:
1. If in virtual desktop one, press control alt home takes you to RDP in full screen on virtual desktop two
100% of the times I will be taken to the remote session. Randomly (more often than not), the focus will not be on the screen. For example, frequently the RDP session will show me the PC lockscreen. This is the screen is asking me to enter my password. But I would need to click on the password field so it takes my typing
2. If in virtual desktop two (RDP in full screen), press control alt home takes you to on virtual desktop one
90% of the times it will not complete the switch. I would have to repeat ctrl-alt-home again to complete jumping to virtual desktop 1
It is still extremely helpful but would hope one of the gurus is able to comment on what may help. I have tried inserting a delay but didn't fix it. Also, unfortunately I don't have enough reputation to post a comment on superuser.com to ask the poster. Thanks
Switch Virtual screen with remote desktop
Re: Switch Virtual screen with remote desktop
Adding code here in case somebody can take a peek.
Code: Select all
#SingleInstance, force
#Persistent
#NoEnv
globalDesktopManager := new JPGIncDesktopManagerClass()
globalDesktopManager.switchRD()
return
#c::ExitApp
debugger(message)
{
;~ ToolTip, % message
;~ sleep 100
return
}
turnCapslockOff()
{
;if the capslock key is down then set the capslock state to on so that
;when the user lets go it will change the state to off
if(GetKeyState("Capslock", "P"))
{
SetCapsLockState, On
} else
{
SetCapsLockState , Off
}
return
}
/*
* If we send the keystrokes too quickly you sometimes get a flickering of the screen
*/
send(toSend)
{
oldDelay := A_KeyDelay
SetKeyDelay, 30
send, % toSend
SetKeyDelay, % oldDelay
return
}
closeMultitaskingViewFrame()
{
IfWinActive, ahk_class MultitaskingViewFrame
{
send("#{tab}")
}
return
}
openMultitaskingViewFrame()
{
IfWinNotActive, ahk_class MultitaskingViewFrame
{
send("#{tab}")
WinWaitActive, ahk_class MultitaskingViewFrame
}
return
}
callFunction(possibleFunction)
{
if(IsFunc(possibleFunction))
{
%possibleFunction%()
} else if(IsObject(possibleFunction))
{
possibleFunction.Call()
} else if(IsLabel(possibleFunction))
{
gosub, % possibleFunction
}
return
}
getDesktopNumberFromHotkey(keyCombo)
{
number := RegExReplace(keyCombo, "[^\d]", "")
return number == 0 ? 10 : number
}
getIndexFromArray(searchFor, array)
{
loop, % array.MaxIndex()
{
if(array[A_index] == searchFor)
{
return A_index
}
}
return -1
}
/*
* this function is used when a hotkey combo is pressed. It directs the program to the appropriate function in the appropriate class
*/
JPGIncDesktopManagerCallback(desktopManager, functionName, keyCombo)
{
desktopManager[functionName](getDesktopNumberFromHotkey(keyCombo))
return
}
class JPGIncHotkeyManager
{
_notAnAutohotkeyModKeyRegex := "[^#!^+<>*~$]"
__new()
{
return this
}
setupNumberedHotkey(callbackClass, callbackFunctionName, hotkeyKey)
{
if(this._doesHotkeyRequireCustomHotkeySyntax(hotkeyKey))
{
hotkeyKey .= " & "
}
Loop, 10
{
this.setupHotkey(callbackClass, callbackFunctionName, hotkeyKey (A_Index - 1))
}
return this
}
setupHotkey(callbackClass, callbackFunctionName, hotkeyKey)
{
;~ debugger("Setting up callback: " callbackFunctionName " as " hotkeyKey)
callback := Func("JPGIncDesktopManagerCallback").Bind(callbackClass, callbackFunctionName, hotkeyKey)
Hotkey, % hotkeyKey, % callback, On
return this
}
/*
* If the modifier key used is only a modifier symbol then we don't need to do anything (https://autohotkey.com/docs/Hotkeys.htm#Symbols)
* but if it contains any other characters then it means that the hotkey is a combination hotkey then we need to add " & "
*/
_doesHotkeyRequireCustomHotkeySyntax(key)
{
return RegExMatch(key, this._notAnAutohotkeyModKeyRegex)
}
}
;taken from optimist__prime https://autohotkey.com/boards/viewtopic.php?t=9224
class MonitorMapperClass
{
; This part figures out how many times we need to hit Tab to get to the
; monitor with the window we are trying to send to another desktop.
getRequiredTabCount(hwnd)
{
activemonitor := this.getWindowsMonitorNumber(hwnd)
SysGet, monitorcount, MonitorCount
SysGet, primarymonitor, MonitorPrimary
If (activemonitor > primarymonitor)
{
tabCount := activemonitor - primarymonitor
}
else If (activemonitor < primarymonitor)
{
tabCount := monitorcount - primarymonitor + activemonitor
}
else
{
tabCount := 0
}
tabCount *= 2
return tabCount
}
/*
* This function returns the monitor number of the window with the given hwnd
*/
getWindowsMonitorNumber(hwnd)
{
WinGetPos, x, y, width, height, % "Ahk_id" hwnd
debugger("Window Position/Size:`nX: " X "`nY: " Y "`nWidth: " width "`nHeight: " height)
SysGet, monitorcount, MonitorCount
SysGet, primarymonitor, MonitorPrimary
debugger("Monitor Count: " MonitorCount)
Loop %monitorcount%
{
SysGet, mon, Monitor, %a_index%
debugger("Primary Monitor: " primarymonitor "`nDistance between monitor #" a_index "'s right border and Primary monitor's left border (Left < 0, Right > 0):`n" monRight "px")
If (x < monRight - width / 2 || monitorcount = a_index)
{
return %a_index%
}
}
}
}
class VirtualDesktopManagerClass
{
__new()
{
debugger("creating th vdm")
;https msdn.microsoft.com /en-us/library/windows/desktop/mt186440(v=vs.85).aspx Broken Link for safety
CLSID := "{aa509086-5ca9-4c25-8f95-589d3c07b48a}" ;search VirtualDesktopManager clsid
IID := "{a5cd92ff-29be-454c-8d04-d82879fb3f1b}" ;search IID_IVirtualDesktopManager
this.iVirtualDesktopManager := ComObjCreate(CLSID, IID)
this.isWindowOnCurrentVirtualDesktopAddress := NumGet(NumGet(this.iVirtualDesktopManager+0), 3*A_PtrSize)
this.getWindowDesktopIdAddress := NumGet(NumGet(this.iVirtualDesktopManager+0), 4*A_PtrSize)
this.moveWindowToDesktopAddress := NumGet(NumGet(this.iVirtualDesktopManager+0), 5*A_PtrSize)
return this
}
getWindowDesktopId(hWnd, tryAgain := true)
{
desktopId := ""
VarSetCapacity(desktopID, 16, 0)
;IVirtualDesktopManager::GetWindowDesktopId method
;https msdn.microsoft.com /en-us/library/windows/desktop/mt186441(v=vs.85).aspx Broken Link for safety
Error := DllCall(this.getWindowDesktopIdAddress, "Ptr", this.iVirtualDesktopManager, "Ptr", hWnd, "Ptr", &desktopID)
if(Error != 0) {
if(tryAgain)
{
return this.getWindowDesktopId(hwnd, false)
}
msgbox % "error in getWindowDesktopId " Error
clipboard := error
}
return &desktopID
}
getDesktopGuid(hwnd)
{
debugger("getting the guid")
return this._guidToStr(this.getWindowDesktopId(hwnd))
}
; https://github.com/cocobelgica/AutoHotkey-Util/blob/master/Guid.ahk#L36
_guidToStr(ByRef VarOrAddress)
{
;~ debugger(&VarOrAddress " address")
pGuid := IsByRef(VarOrAddress) ? &VarOrAddress : VarOrAddress
VarSetCapacity(sGuid, 78) ; (38 + 1) * 2
if !DllCall("ole32\StringFromGUID2", "Ptr", pGuid, "Ptr", &sGuid, "Int", 39)
throw Exception("Invalid GUID", -1, Format("<at {1:p}>", pGuid))
return StrGet(&sGuid, "UTF-16")
}
isDesktopCurrentlyActive(hWnd)
{
;IVirtualDesktopManager::IsWindowOnCurrentVirtualDesktop method
;Indicates whether the provided window is on the currently active virtual desktop.
;https msdn.microsoft.com /en-us/library/windows/desktop/mt186442(v=vs.85).aspx Broken Link for safety
Error := DllCall(this.isWindowOnCurrentVirtualDesktopAddress, "Ptr", this.iVirtualDesktopManager, "Ptr", hWnd, "IntP", onCurrentDesktop)
if(Error != 0) {
msgbox % "error in isDesktopCurrentlyActive " Error
clipboard := error
}
return onCurrentDesktop
}
moveWindowToDesktop(hWnd, ByRef desktopId)
{
Error := DllCall(this.moveWindowToDesktopAddress, "Ptr", this.iVirtualDesktopManager, "Ptr", activeHwnd, "Ptr", &desktopId)
if(Error != 0) {
msgbox % "error in moveWindowToDesktop " Error "but no error?"
clipboard := error
}
return this
}
getCurrentDesktop(hWnd)
{
desktopId := ""
VarSetCapacity(desktopID, 16, 0)
Error := DllCall(this.getCurrentDesktopAddress, "Ptr", this.iVirtualDesktopManagerInternal, "Ptr", &desktopID)
if(Error != 0) {
msgbox % "error in getWindowDesktopId " Error
clipboard := error
}
return &desktopID
}
}
class DesktopMapperClass
{
desktopIds := []
__new(virtualDesktopManager)
{
this._setupGui()
this.virtualDesktopManager := virtualDesktopManager
return this
}
/*
* Populates the desktopIds array with the current virtual deskops according to the registry key
*/
mapVirtualDesktops()
{
regIdLength := 32
RegRead, DesktopList, HKEY_CURRENT_USER, SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\VirtualDesktops, VirtualDesktopIDs
this.desktopIds := []
while, true
{
desktopId := SubStr(DesktopList, ((A_index-1) * regIdLength) + 1, regIdLength)
if(desktopId)
{
this.desktopIds.Insert(this._idFromReg(desktopId))
} else
{
break
}
}
debugger("there are " this.desktopIds.MaxIndex() " things")
return this
}
/*
* Gets the desktop id of the current desktop
*/
getCurrentDesktopId()
{
hwnd := this.hwnd
Gui %hwnd%:show, NA ;show but don't activate
winwait, % "Ahk_id " hwnd
guid := this.virtualDesktopManager.getDesktopGuid(hwnd)
Gui %hwnd%:hide
;if you don't wait until it closes (and sleep a little) then the desktop the gui is on can get focus
WinWaitClose, % "Ahk_id " hwnd
sleep 50
return this._idFromGuid(guid)
}
getNumberOfDesktops()
{
this.mapVirtualDesktops()
return this.desktopIds.maxIndex()
}
/*
* returns the number of the current desktop
*/
getDesktopNumber()
{
this.mapVirtualDesktops()
currentDesktop := this.getCurrentDesktopId()
return this._indexOfId(currentDesktop)
}
/*
* takes an ID from the registry and extracts the last 16 characters (which matches the last 16 characters of the GUID)
*/
_idFromReg(regString)
{
return SubStr(regString, 17)
}
/*
* takes an ID from microsofts IVirtualDesktopManager and extracts the last 16 characters (which matches the last 16 characters of the ID from the registry)
*/
_idFromGuid(guidString)
{
return SubStr(RegExReplace(guidString, "[-{}]"), 17)
}
_indexOfId(guid)
{
loop, % this.desktopIds.MaxIndex()
{
debugger("looking for `n" guid "`n" this.desktopIds[A_index])
if(this.desktopIds[A_index] == guid)
{
debugger("Found it! desktop is " A_Index)
return A_Index
}
}
return -1
}
_setupGui()
{
Gui, new
Gui, show
Gui, +HwndMyGuiHwnd
this.hwnd := MyGuiHwnd
Gui, hide
return this
}
}
class JPGIncWindowMoverClass
{
moveActiveWindowToDesktopFunctionName := "moveActiveWindowToDesktop"
moveToNextFunctionName := "moveActiveWindowToNextDesktop"
moveToPreviousFunctionName := "moveActiveWindowToPreviousDesktop"
_postMoveWindowFunctionName := ""
__new()
{
this.desktopMapper := new DesktopMapperClass(new VirtualDesktopManagerClass())
this.monitorMapper := new MonitorMapperClass()
return this
}
doPostMoveWindow()
{
callFunction(this._postMoveWindowFunctionName)
return this
}
moveActiveWindowToDesktop(targetDesktop, follow := false)
{
currentDesktop := this.desktopMapper.getDesktopNumber()
if(currentDesktop == targetDesktop)
{
return this
}
numberOfTabsNeededToSelectActiveMonitor := this.monitorMapper.getRequiredTabCount(WinActive("A"))
numberOfDownsNeededToSelectDesktop := this.getNumberOfDownsNeededToSelectDesktop(targetDesktop, currentDesktop)
openMultitaskingViewFrame()
send("{tab " numberOfTabsNeededToSelectActiveMonitor "}")
send("{Appskey}m{Down " numberOfDownsNeededToSelectDesktop "}{Enter}")
closeMultitaskingViewFrame()
this.doPostMoveWindow()
return this
}
moveActiveWindowToNextDesktop(follow := false)
{
currentDesktop := this.desktopMapper.getDesktopNumber()
return this.moveActiveWindowToDesktop(currentDesktop + 1, follow)
}
moveActiveWindowToPreviousDesktop(follow := false)
{
currentDesktop := this.desktopMapper.getDesktopNumber()
if(currentDesktop == 1)
{
return this
}
return this.moveActiveWindowToDesktop(currentDesktop - 1, follow)
}
getNumberOfDownsNeededToSelectDesktop(targetDesktop, currentDesktop)
{
; This part figures out how many times we need to push down within the context menu to get the desktop we want.
if (targetDesktop > currentDesktop)
{
targetDesktop -= 2
}
else
{
targetdesktop--
}
return targetDesktop
}
}
class JPGIncDesktopChangerClass
{
goToDesktopCallbackFunctionName := "goToDesktop"
nextDesktopFunctionName := "goToNextDesktop"
PreviousDesktopFunctionName := "goToPreviousDesktop"
_postGoToDesktopFunctionName := ""
__new()
{
this.desktopMapper := new DesktopMapperClass(new VirtualDesktopManagerClass())
return this
}
goToNextDesktop(keyCombo := "")
{
send("^#{right}")
return this.doPostGoToDesktop()
}
goToPreviousDesktop(keyCombo := "")
{
send("^#{left}")
return this.doPostGoToDesktop()
}
switchRD(keyCombo := "")
{
desktopNbr := this.desktopMapper.getDesktopNumber()
if desktopNbr = 2
{
Send {Ctrl down}{LWin down}{Left}{LWin up}{Ctrl up}
} else {
Send {Ctrl down}{LWin down}{Right}{LWin up}{Ctrl up}
}
return this.doPostGoToDesktop()
}
/*
* swap to the given virtual desktop number
*/
goToDesktop(newDesktopNumber)
{
debugger("in go to desktop changing to " newDesktopNumber)
this._makeDesktopsIfRequired(newDesktopNumber)
._goToDesktop(newDesktopNumber)
closeMultitaskingViewFrame()
this.doPostGoToDesktop()
return this
}
_makeDesktopsIfRequired(minimumNumberOfDesktops)
{
currentNumberOfDesktops := this.desktopMapper.getNumberOfDesktops()
loop, % minimumNumberOfDesktops - currentNumberOfDesktops
{
send("#^d")
}
return this
}
_goToDesktop(newDesktopNumber)
{
currentDesktop := this.desktopMapper.getDesktopNumber()
direction := currentDesktop - newDesktopNumber
distance := Abs(direction)
debugger("distance to move is " distance "`ndirectin" direction)
if(direction < 0)
{
debugger("Sending right! " distance "times")
send("^#{right " distance "}")
} else
{
send("^#{left " distance "}")
}
return this
}
doPostGoToDesktop()
{
this._activateTopMostWindow()
callFunction(this.postGoToDesktopFunctionName)
return this
}
_activateTopMostWindow()
{
If(WinActive("ahk_exe explorer.exe"))
{
send !{tab}
}
return this
}
}
class JPGIncDesktopManagerClass
{
__new()
{
this._desktopChanger := new JPGIncDesktopChangerClass()
this._windowMover := new JPGIncWindowMoverClass()
this.hotkeyManager := new JPGIncHotkeyManager()
this._setupDefaultHotkeys()
return this
}
/*
*
*/
switchRD()
{
this.hotkeyManager.setupHotkey(this._desktopChanger, "switchRD", "^!Home")
return this
}
/*
* Public API to setup virtual desktop hotkeys and callbacks
*/
setGoToDesktop(hotkeyKey)
{
this.hotkeyManager.setupNumberedHotkey(this._desktopChanger, this._desktopChanger.goToDesktopCallbackFunctionName, hotkeyKey)
return this
}
setMoveWindowToDesktop(hotkeyKey)
{
this.hotkeyManager.setupNumberedHotkey(this._windowMover, this._windowMover.moveActiveWindowToDesktopFunctionName, hotkeyKey)
return this
}
setGoToNextDesktop(hotkeyKey)
{
this.hotkeyManager.setupHotkey(this._desktopChanger, this._desktopChanger.nextDesktopFunctionName, hotkeyKey)
return this
}
setGoToPreviousDesktop(hotkeyKey)
{
this.hotkeyManager.setupHotkey(this._desktopChanger, this._desktopChanger.PreviousDesktopFunctionName, hotkeyKey)
return this
}
setMoveWindowToNextDesktop(hotkeyKey)
{
this.hotkeyManager.setupHotkey(this._windowMover, this._windowMover.moveToNextFunctionName, hotkeyKey)
return this
}
setMoveWindowToPreviousDesktop(hotkeyKey)
{
this.hotkeyManager.setupHotkey(this._windowMover, this._windowMover.moveToPreviousFunctionName, hotkeyKey)
return this
}
setCloseDesktop(hotkeyKey)
{
this.hotkeyManager.setupHotkey(this, "closeDesktop", hotkeyKey)
return this
}
setNewDesktop(hotkeyKey)
{
this.hotkeyManager.setupHotkey(this, "newDesktop", hotkeyKey)
return this
}
afterGoToDesktop(functionLabelOrClassWithCallMethodName)
{
this._desktopChanger.postGoToDesktopFunctionName := functionLabelOrClassWithCallMethodName
return this
}
afterMoveWindowToDesktop(functionLabelOrClassWithCallMethodName)
{
this._windowMover.postMoveWindowFunctionName := functionLabelOrClassWithCallMethodName
return this
}
/*
* end public api
*/
newDesktop(hotkeyCombo := "")
{
send("^#d")
return this
}
closeDesktop(hotkeyCombo := "")
{
send("^#{f4}")
return this
}
_setupDefaultHotkeys()
{
Hotkey, IfWinActive, ahk_class MultitaskingViewFrame
this.hotkeyManager.setupNumberedHotkey(this._desktopChanger, this._desktopChanger.goToDesktopCallbackFunctionName, "")
Hotkey, If
return this
}
}