Last active
January 12, 2018 19:18
-
-
Save shoover/1fab3e21017854923b8d52fd1056b7e4 to your computer and use it in GitHub Desktop.
AutoHotKey NextWindow function using window class and IVirtualDesktopManager
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Activate the next window in the same window class and virtual desktop. | |
; This works by searching windows by ahk_cls. | |
NextWindow() | |
{ | |
; Get the active window class | |
WinGetClass cls, A | |
; Sometimes the active window class is blank when a Chrome tab is loading. | |
if !RegExMatch(cls, "[^\s]") | |
return | |
; Get the active virtual desktop | |
deskMgr := new VirtualDesktopManager() | |
activeDesktop := deskMgr.GetWindowDesktopId(WinExist("A")) | |
; Loop over windows in the class and activate the last one. | |
WinGet, id, list, ahk_class %cls% | |
Loop, %id% | |
{ | |
i := id - A_Index + 1 | |
desktopId := deskMgr.GetWindowDesktopId(id%i%) | |
if (desktopId = activeDesktop) { | |
WinActivate % "ahk_id" id%i% | |
return | |
} | |
} | |
} | |
; Wrapper for COM interface IVirtualDesktopManager. | |
; c:/Program Files (x86)/Windows Kits/10/Include/10.0.15063.0/um/ShObjIdl.h | |
; Usage: | |
; deskMgr := new VirtualDesktopManager() | |
; desktopId := deskMgr.GetWindowDesktopId(WinExist("A")) | |
; MsgBox % _guidToStr(desktopId) | |
; if (desktopId = deskMgr.GetWindowDesktopId(otherHwnd)) | |
; ... | |
class VirtualDesktopManager | |
{ | |
static CLSID := "{aa509086-5ca9-4c25-8f95-589d3c07b48a}" ; VirtualDesktopManager clsid | |
static IID := "{a5cd92ff-29be-454c-8d04-d82879fb3f1b}" ; IID_IVirtualDesktopManager | |
__New() | |
{ | |
this.ptr := ComObjCreate(this.CLSID, this.IID) | |
} | |
__Delete() | |
{ | |
ObjRelease(this.ptr) | |
} | |
; Returns the virtual desktop ID of the window as a binary GUID. | |
GetWindowDesktopId(hwnd) | |
{ | |
; Initialize a GUID. By some quirk of VarSetCapacity, initializing to 0 yields buggy results. | |
VarSetCapacity(desktopId, 16, 0xEE) | |
res := DllCall(vtable(this.ptr, 4), "Ptr", this.ptr, "Ptr", hwnd, "Ptr", &desktopId, "Int") | |
; A_LastError is also of interest, but it doesn't seem to clear between calls | |
if res or ErrorLevel | |
throw Exception("Virtual call failure", -1 | |
,Format("HWND: {1:d}, Result: {:d}, ErrorLevel: {:d}, A_LastError: {:d}, GUID: {:s}" | |
,hwnd, res, ErrorLevel, A_LastError, _guidToStr(desktopId))) | |
return desktopId | |
} | |
} | |
; Get the address of function #n in an interface pointer's vtable. | |
vtable(ptr, n) | |
{ | |
return NumGet(NumGet(ptr+0), n*A_PtrSize) | |
} | |
; https://github.com/cocobelgica/AutoHotkey-Util/blob/master/Guid.ahk#L36 | |
_guidToStr(ByRef VarOrAddress) | |
{ | |
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") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment