比如
显示器A,全屏打开了软件1,软件2
显示器B,全屏打开了软件3,软件4
如何实现当鼠标在显示器A时候,一键切换软件1和2
当鼠标在显示器B时候,一键切换软件3和4
多显示器管理软件。
收费的 displayFusion
免费的 Dual Monitor Tools
下了小恐龙版的Dual Monitor Tools,没有找着相关的设置
毕竟是免费的
它只是提供快速切换窗口和光标的功能。
displayFusion 默认也没有类似的功能。
但是 displayFusion 好在支持代码脚本(C#和VB),你可以自己写, 也可以下载别人写好的。
对了,如果只是单纯这个需求,固定的软件, AHK的效果可能更好。 但是缺乏普适性。
感谢小恐龙,其实我主要是想知道win10能不能设置alt+tab 只切换当前屏幕上的窗口。
比较喜欢所有软件全屏起来用,虽说开四个软件,按住alt,再按tab最多也就切三次。
但是设置单键等于alt+tab,一键切换最近两个窗口还是要爽很多。
我试着写个ahk,我就4个窗口,应该很简单,当前活动窗口是A的话,一键切B,活动窗口是C的话,一键切D……四小段就搞定了
没有,也可能我的win10版本太低
啊不!我刚试了一下,这个也不行,这个只有虚拟桌面才有效。显示器 A 和显示器 B 会被一起当作一个桌面。
找到一个更通用的解决方案。
软件groupy,开启这个设置。
用groupy把软件1和2在显示器A组个group,把软件3和4在显示器B组个group。
这时在两个显示器上分别用ctrl + tab,切换的就只是该显示器上的软件了。
另外,组好group之后,软件1234还是可以全屏化的,不影响切换,可谓是完美啦(不过若用浏览器得把浏览器的ctrl + tab快捷键消掉)。
发现一个脚本,更加好用:
WheelSwitcher - 通过在屏幕边缘滚动鼠标滚轮来切换全屏应用程序(例如 RDP 客户端) - AutoHotkey 社区
#SingleInstance force
OutputDebug DBGVIEWCLEAR
CoordMode, Mouse, Screen
RunAsTask()
~WheelUp::
DoWheel(1)
return
~WheelDown::
DoWheel(-1)
return
DoWheel(dir){
if (!IsMouseAtEdgeOfMonitor()){
return
}
MouseGetPos, mx, my, active_hwnd
;msgbox % "x" ax " y" ay " w" aw " h" ah
;WinGet, l, list, % "ahk_exe " ProcessName " ahk_class " cls
windows := []
WinGet, l, list
;WinGet, l, list, % "ahk_exe notepad.exe"
Loop, %l%
{
w := l%A_Index%
;if (alternate_mode || !alternate_mode && IsMouseAtEdgeOfMonitor()){
windows.push(w)
;}
}
windows := FilterWindows(active_hwnd, windows)
w := GetNextWindow(active_hwnd, windows, dir)
if (w){
WinActivate, % "ahk_id " w
}
}
IsMouseAtEdgeOfMonitor(){
MouseGetPos, mx, my
mon := WhichMonitorIsMouseOn()
SysGet, monArea, Monitor, % mon
if ( (mx >= monAreaLeft && mx <= monAreaLeft + 10) || (mx <= monAreaRight && mx >= monAreaRight - 10) || (my >= monAreaTop && my <= monAreaTop + 10) || (my <= monAreaBottom && my >= monAreaBottom - 10))
return 1
}
; Which monitor is the mouse on?
WhichMonitorIsMouseOn(){
MouseGetPos, mx, my
SysGet, mc, MonitorCount
Loop % mc {
SysGet, monArea, Monitor, % A_Index
if (mx >= monAreaLeft && mx <= monAreaRight && my >= monAreaTop && my <= monAreaBottom){
return A_Index
}
}
return 0
}
FilterWindows(active_hwnd, windows){
static window_diff := 7
WinGetPos, ax, ay, aw, ah, % "ahk_id " active_hwnd
;OutputDebug % "AHK| Checking windows against ax: " ax ", ay: " ay ", ah: " ah ", aw: " aw ")"
w := []
for i, hwnd in windows {
WinGetPos, wx, wy, ww, wh, % "ahk_id " hwnd
WinGetTitle, title, % "ahk_id " hwnd
;if (wx == ax && wy == ay && ww == aw && wh == ah){
if (abs(wx-ax) <= window_diff && abs(wy-ay) <= window_diff && abs(ww - aw) <= (window_diff * 2) && abs(wh - ah) <= (window_diff * 2)){
w.push(hwnd)
;OutputDebug % "AHK| Adding window: " title
} else {
;OutputDebug % "AHK| Filtering out window: " title " ( wx: " wx ", wy:" wy ", wh: " wh ", ww: " ww
}
}
;return SortWindowsByHwnd(w)
return SortWindowsByTitle(w)
}
; Sorts a windows array by Window Title
SortWindowsByTitle(array){
for k, v in array {
WinGetTitle, title, % "ahk_id " v
str := title "|ws|" v "`n"
;OutputDebug % "AHK| SortWindowsByTitle: " str
sorted .= str
}
StringTrimRight,sorted,sorted,1
Sort,sorted, D
out := []
Loop, Parse, sorted, `n
{
hwnd := StrSplit(A_LoopField, "|ws|")
hwnd := hwnd[2]
out.push(hwnd)
}
return out
}
; Sorts a windows array by HWND
SortWindowsByHwnd(array){
for k, v in array {
sorted .= v "`n"
}
StringTrimRight,sorted,sorted,1
Sort,sorted, D
out := []
Loop, Parse, sorted, `n
{
out.push(A_LoopField)
}
return out
}
; Finds the window after the current one in a windows array
GetNextWindow(hwnd, windows, dir){
; Find the current window in the list
this_index := 0
max := windows.length()
Loop % max {
if (windows[A_Index] == hwnd){
this_index := A_Index
break
}
}
if (!this_index)
return 0
found := 0
ct := 0
new_index := this_index
while (!found && (ct <= max)){
ct++
new_index += dir
if (new_index < 1)
new_index := max
if (new_index > max)
new_index := 1
if windows[new_index] is number {
;OutputDebug % "AHK| Found Window #" windows[new_index]
found := 1
}
}
if (found)
return windows[new_index]
else
return 0
}
/*
_ _ _ __ __ _ _ _ _
| |__ | |_ | |_ _ __ _ / // /__ _ | |__ | | __ ___ ___ _ __ (_) _ __ | |_ ___ _ __ __ _
| '_ \ | __|| __|| '_ \(_) / // // _` || '_ \ | |/ // __| / __|| '__|| || '_ \ | __| / _ \ | '__|/ _` |
| | | || |_ | |_ | |_) |_ / // /| (_| || | | || < \__ \| (__ | | | || |_) || |_ _| (_) || | | (_| |
|_| |_| \__| \__|| .__/(_)_//_/ \__,_||_| |_||_|\_\|___/ \___||_| |_|| .__/ \__|(_)\___/ |_| \__, |
|_| |_| |___/
RunAsTask() - Auto-elevates script without UAC prompt | http://ahkscript.org/boards/viewtopic.php?t=4334
_________________________________________________________________________________________________________
*/
RunAsTask() { ; By SKAN, http://goo.gl/yG6A1F, CD:19/Aug/2014 | MD:22/Aug/2014
Local CmdLine, TaskName, TaskExists, XML, TaskSchd, TaskRoot, RunAsTask
Local TASK_CREATE := 0x2, TASK_LOGON_INTERACTIVE_TOKEN := 3
Try TaskSchd := ComObjCreate( "Schedule.Service" ), TaskSchd.Connect()
, TaskRoot := TaskSchd.GetFolder( "\" )
Catch
Return "", ErrorLevel := 1
CmdLine := ( A_IsCompiled ? "" : """" A_AhkPath """" ) A_Space ( """" A_ScriptFullpath """" )
TaskName := "[RunAsTask] " A_ScriptName " @" SubStr( "000000000" DllCall( "NTDLL\RtlComputeCrc32"
, "Int",0, "WStr",CmdLine, "UInt",StrLen( CmdLine ) * 2, "UInt" ), -9 )
Try RunAsTask := TaskRoot.GetTask( TaskName )
TaskExists := ! A_LastError
If ( not A_IsAdmin and TaskExists ) {
RunAsTask.Run( "" )
ExitApp
}
If ( not A_IsAdmin and not TaskExists ) {
Run *RunAs %CmdLine%, %A_ScriptDir%, UseErrorLevel
ExitApp
}
If ( A_IsAdmin and not TaskExists ) {
XML := "
( LTrim Join
<?xml version=""1.0"" ?><Task xmlns=""http://schemas.microsoft.com/windows/2004/02/mit/task""><Regi
strationInfo /><Triggers /><Principals><Principal id=""Author""><LogonType>InteractiveToken</LogonT
ype><RunLevel>HighestAvailable</RunLevel></Principal></Principals><Settings><MultipleInstancesPolic
y>Parallel</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><
StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAva
ilable><IdleSettings><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleS
ettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><
RunOnlyIfIdle>false</RunOnlyIfIdle><DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteApp
Session><UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine><WakeToRun>false</WakeToRun><
ExecutionTimeLimit>PT0S</ExecutionTimeLimit></Settings><Actions Context=""Author""><Exec>
<Command>" ( A_IsCompiled ? A_ScriptFullpath : A_AhkPath ) "</Command>
<Arguments>" ( !A_IsCompiled ? """" A_ScriptFullpath """" : "" ) "</Arguments>
<WorkingDirectory>" A_ScriptDir "</WorkingDirectory></Exec></Actions></Task>
)"
TaskRoot.RegisterTask( TaskName, XML, TASK_CREATE, "", "", TASK_LOGON_INTERACTIVE_TOKEN )
}
Return TaskName, ErrorLevel := 0
} ; _____________________________________________________________________________________________________
如果是在打游戏, 会影响全屏的游戏吗
实测不会,到全屏游戏里就失效了,不知道为啥
ps 浏览器无边框化的全屏也会失效
应该是只针对最大化窗口,不针对全屏
发现不支持 wps 的识别
应坛友需求,这里发一下非全屏版,
分为两个版本:
alt + tab、alt + shift + tab切换当前激活窗口所在显示器窗口的代码。
alt + tab、alt + shift + tab切换当前鼠标所在显示器窗口的代码。
版本一
;alttab切换当前激活窗口所在显示器窗口
#SingleInstance force
OutputDebug DBGVIEWCLEAR
CoordMode, Mouse, Screen
RunAsTask()
!Tab::
DoWheel(+1)
return
!+TAB::
DoWheel(-1)
return
DoWheel(dir){
MouseGetPos, mx, my
active_hwnd := WinExist("A")
;msgbox % "x" ax " y" ay " w" aw " h" ah
;WinGet, l, list, % "ahk_exe " ProcessName " ahk_class " cls
windows := []
DetectHiddenWindows On
arr := EnumerateAltTabWindows()
for k, v in arr
{
WinGetClass, winClass, ahk_id %v%
WinGetTitle, title, ahk_id %v%
windows.push(v)
;altTabWindows .= A_Index "`nTitle: " title "`nClass: " winClass "`nhWnd: " v "`nLastActivePopup: " format("0x{:x}", GetLastActivePopup(v)) "`n`n"
}
windows := FilterWindows(active_hwnd, windows)
w := GetNextWindow(active_hwnd, windows, dir)
WinActivate, % "ahk_id " w
}
; Which monitor is the mouse on?
WhichMonitorIsMouseOn(){
MouseGetPos, mx, my
SysGet, mc, MonitorCount
Loop % mc {
SysGet, monArea, Monitor, % A_Index
if (mx >= monAreaLeft && mx <= monAreaRight && my >= monAreaTop && my <= monAreaBottom){
return A_Index
}
}
return 0
}
FilterWindows(active_hwnd, windows){
static window_diff := 7
WinGetPos, ax, ay, aw, ah, % "ahk_id " active_hwnd
ax_:=ax+aw/2,ay_:=ay+ah/2
monA:=MWAGetMonitor(ax_, ay_)
;OutputDebug % "AHK| Checking windows against ax: " ax ", ay: " ay ", ah: " ah ", aw: " aw ")"
w := []
for i, hwnd in windows {
WinGetPos, wx, wy, ww, wh, % "ahk_id " hwnd
WinGetTitle, title, % "ahk_id " hwnd
wx_:=wx+ww/2,wy_:=wy+wh/2
monW:=MWAGetMonitor(wx_, wy_)
if ((monA=monW) and title!=""){
w.push(hwnd)
;MsgBox,% monA monW title hwnd
;OutputDebug % "AHK| Adding window: " title
} else {
;OutputDebug % "AHK| Filtering out window: " title " ( wx: " wx ", wy:" wy ", wh: " wh ", ww: " ww
}
}
;return SortWindowsByHwnd(w)
return SortWindowsByTitle(w)
}
; Sorts a windows array by Window Title
SortWindowsByTitle(array){
for k, v in array {
WinGetTitle, title, % "ahk_id " v
str := title "|ws|" v "`n"
;OutputDebug % "AHK| SortWindowsByTitle: " str
sorted .= str
}
StringTrimRight,sorted,sorted,1
Sort,sorted, D
out := []
Loop, Parse, sorted, `n
{
hwnd := StrSplit(A_LoopField, "|ws|")
hwnd := hwnd[2]
out.push(hwnd)
}
return out
}
; Sorts a windows array by HWND
SortWindowsByHwnd(array){
for k, v in array {
sorted .= v "`n"
}
StringTrimRight,sorted,sorted,1
Sort,sorted, D
out := []
Loop, Parse, sorted, `n
{
out.push(A_LoopField)
}
return out
}
; Finds the window after the current one in a windows array
GetNextWindow(hwnd, windows, dir){
; Find the current window in the list
this_index := 0
max := windows.length()
Loop % max {
if (windows[A_Index] == hwnd){
this_index := A_Index
WinGetTitle, title, % "ahk_id " hwnd
break
}
}
if (!this_index)
return 0
new_index := this_index+dir
if (new_index < 1)
new_index := max
if (new_index > max)
new_index := 1
;MsgBox,% title " " this_index " " new_index
return windows[new_index]
}
/*
_ _ _ __ __ _ _ _ _
| |__ | |_ | |_ _ __ _ / // /__ _ | |__ | | __ ___ ___ _ __ (_) _ __ | |_ ___ _ __ __ _
| '_ \ | __|| __|| '_ \(_) / // // _` || '_ \ | |/ // __| / __|| '__|| || '_ \ | __| / _ \ | '__|/ _` |
| | | || |_ | |_ | |_) |_ / // /| (_| || | | || < \__ \| (__ | | | || |_) || |_ _| (_) || | | (_| |
|_| |_| \__| \__|| .__/(_)_//_/ \__,_||_| |_||_|\_\|___/ \___||_| |_|| .__/ \__|(_)\___/ |_| \__, |
|_| |_| |___/
RunAsTask() - Auto-elevates script without UAC prompt | http://ahkscript.org/boards/viewtopic.php?t=4334
_________________________________________________________________________________________________________
*/
RunAsTask() { ; By SKAN, http://goo.gl/yG6A1F, CD:19/Aug/2014 | MD:22/Aug/2014
Local CmdLine, TaskName, TaskExists, XML, TaskSchd, TaskRoot, RunAsTask
Local TASK_CREATE := 0x2, TASK_LOGON_INTERACTIVE_TOKEN := 3
Try TaskSchd := ComObjCreate( "Schedule.Service" ), TaskSchd.Connect()
, TaskRoot := TaskSchd.GetFolder( "\" )
Catch
Return "", ErrorLevel := 1
CmdLine := ( A_IsCompiled ? "" : """" A_AhkPath """" ) A_Space ( """" A_ScriptFullpath """" )
TaskName := "[RunAsTask] " A_ScriptName " @" SubStr( "000000000" DllCall( "NTDLL\RtlComputeCrc32"
, "Int",0, "WStr",CmdLine, "UInt",StrLen( CmdLine ) * 2, "UInt" ), -9 )
Try RunAsTask := TaskRoot.GetTask( TaskName )
TaskExists := ! A_LastError
If ( not A_IsAdmin and TaskExists ) {
RunAsTask.Run( "" )
ExitApp
}
If ( not A_IsAdmin and not TaskExists ) {
Run *RunAs %CmdLine%, %A_ScriptDir%, UseErrorLevel
ExitApp
}
If ( A_IsAdmin and not TaskExists ) {
XML := "
( LTrim Join
<?xml version=""1.0"" ?><Task xmlns=""http://schemas.microsoft.com/windows/2004/02/mit/task""><Regi
strationInfo /><Triggers /><Principals><Principal id=""Author""><LogonType>InteractiveToken</LogonT
ype><RunLevel>HighestAvailable</RunLevel></Principal></Principals><Settings><MultipleInstancesPolic
y>Parallel</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><
StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAva
ilable><IdleSettings><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleS
ettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><
RunOnlyIfIdle>false</RunOnlyIfIdle><DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteApp
Session><UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine><WakeToRun>false</WakeToRun><
ExecutionTimeLimit>PT0S</ExecutionTimeLimit></Settings><Actions Context=""Author""><Exec>
<Command>" ( A_IsCompiled ? A_ScriptFullpath : A_AhkPath ) "</Command>
<Arguments>" ( !A_IsCompiled ? """" A_ScriptFullpath """" : "" ) "</Arguments>
<WorkingDirectory>" A_ScriptDir "</WorkingDirectory></Exec></Actions></Task>
)"
TaskRoot.RegisterTask( TaskName, XML, TASK_CREATE, "", "", TASK_LOGON_INTERACTIVE_TOKEN )
}
Return TaskName, ErrorLevel := 0
} ; _____________________________________________________________________________________________________
MWAGetMonitor(Mx := "", My := "")
{
if (!Mx or !My)
{
; if Mx or My is empty, revert to the mouse cursor placement
Coordmode, Mouse, Screen ; use Screen, so we can compare the coords with the sysget information`
MouseGetPos, Mx, My
}
SysGet, MonitorCount, 80 ; monitorcount, so we know how many monitors there are, and the number of loops we need to do
Loop, %MonitorCount%
{
SysGet, mon%A_Index%, Monitor, %A_Index% ; "Monitor" will get the total desktop space of the monitor, including taskbars
if ( Mx >= mon%A_Index%left ) && ( Mx < mon%A_Index%right ) && ( My >= mon%A_Index%top ) && ( My < mon%A_Index%bottom )
{
ActiveMon := A_Index
break
}
}
return ActiveMon
}
EnumerateAltTabWindows()
{
AltTabList := []
WinGet, list, List
Loop % list
{
if IsAltTabWindow(list%A_Index%)
AltTabList.Push(list%A_Index%)
}
Return AltTabList
}
IsAltTabWindow(hwnd)
{
static ImmersiveShell, IApplicationViewCollection, MONITOR_DEFAULTTONULL := 0, VirtualDesktopAltTabFilter := "null", PropEnumProcEx := RegisterCallback("PropEnumProcEx", "Fast", 4)
if (VirtualDesktopAltTabFilter = "null")
{
RegRead, VirtualDesktopAltTabFilter, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, VirtualDesktopAltTabFilter
OSbuildNumber := StrSplit(A_OSVersion, ".")[3]
if (OSbuildNumber < 14393)
{
msgbox Your %A_OSVersion% can not handle virtual desktops
exitapp
}
else if (OSbuildNumber <= 17134) ; Windows 10 1607 to 1803 and Windows Server 2016
IID_IApplicationViewCollection := "{2C08ADF0-A386-4B35-9250-0FE183476FCC}"
else
IID_IApplicationViewCollection := "{1841C6D7-4F9D-42C0-AF41-8747538F10E5}"
if !(ImmersiveShell := ComObjCreate(CLSID_ImmersiveShell := "{C2F03A33-21F5-47FA-B4BB-156362A2F239}", IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"))
{
MsgBox ImmersiveShell not supported.
ExitApp
}
if !(IApplicationViewCollection := ComObjQuery(ImmersiveShell, IID_IApplicationViewCollection, IID_IApplicationViewCollection))
{
MsgBox IApplicationViewCollection interface not supported.
ExitApp
}
}
WinGetClass, winClass, ahk_id %hWnd%
if (winClass = "Windows.UI.Core.CoreWindow")
return
if (winClass = "ApplicationFrameWindow")
{
varsetcapacity(ApplicationViewCloakType, 4, 0)
DllCall("EnumPropsEx", "uptr", hWnd, "ptr", PropEnumProcEx, "ptr", &ApplicationViewCloakType)
if (numget(ApplicationViewCloakType, 0, "int") = 1) ; https://github.com/kvakulo/Switcheroo/commit/fa526606d52d5ba066ba0b2b5aa83ed04741390f
return
}
; if !DllCall("MonitorFromWindow", "uptr", hwnd, "uint", MONITOR_DEFAULTTONULL, "ptr") ; test if window is shown on any monitor. alt-tab shows any window even if window is out of monitor.
; return
DllCall(NumGet(NumGet(IApplicationViewCollection+0)+6*A_PtrSize), "ptr", IApplicationViewCollection, "uptr", hwnd, "ptr*", pView) ; GetViewForHwnd
if pView
{
DllCall(NumGet(NumGet(pView+0)+27*A_PtrSize), "ptr", pView, "int*", ShowInSwitchers) ; GetShowInSwitchers
ObjRelease(pView)
}
if ShowInSwitchers and ((VirtualDesktopAltTabFilter = 0) or IsWindowOnCurrentVirtualDesktop(hwnd))
return true
return
}
GetLastActivePopup(hwnd)
{
static GA_ROOTOWNER := 3
hwnd := DllCall("GetAncestor", "uptr", hwnd, "uint", GA_ROOTOWNER, "ptr")
hwnd := DllCall("GetLastActivePopup", "uptr", hwnd, "ptr")
return hwnd
}
IsWindowOnCurrentVirtualDesktop(hwnd)
{
static IVirtualDesktopManager
if !IVirtualDesktopManager
IVirtualDesktopManager := ComObjCreate(CLSID_VirtualDesktopManager := "{AA509086-5CA9-4C25-8F95-589D3C07B48A}", IID_IVirtualDesktopManager := "{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}")
DllCall(NumGet(NumGet(IVirtualDesktopManager+0), 3*A_PtrSize), "ptr", IVirtualDesktopManager, "uptr", hwnd, "int*", onCurrentDesktop) ; IsWindowOnCurrentVirtualDesktop
return onCurrentDesktop
}
PropEnumProcEx(hWnd, lpszString, hData, dwData)
{
if (strget(lpszString, "UTF-16") = "ApplicationViewCloakType")
{
numput(hData, dwData+0, 0, "int")
return false
}
return true
}
版本二
;alttab切换当前鼠标所在显示器窗口
#SingleInstance force
OutputDebug DBGVIEWCLEAR
CoordMode, Mouse, Screen
RunAsTask()
!Tab::
DoWheel(+1)
return
!+TAB::
DoWheel(-1)
return
DoWheel(dir){
MouseGetPos, mx, my
active_hwnd := WinExist("A")
;msgbox % "x" ax " y" ay " w" aw " h" ah
;WinGet, l, list, % "ahk_exe " ProcessName " ahk_class " cls
windows := []
DetectHiddenWindows On
arr := EnumerateAltTabWindows()
for k, v in arr
{
WinGetClass, winClass, ahk_id %v%
WinGetTitle, title, ahk_id %v%
windows.push(v)
;altTabWindows .= A_Index "`nTitle: " title "`nClass: " winClass "`nhWnd: " v "`nLastActivePopup: " format("0x{:x}", GetLastActivePopup(v)) "`n`n"
}
windows := FilterWindows(active_hwnd, windows)
w := GetNextWindow(active_hwnd, windows, dir)
WinActivate, % "ahk_id " w
}
; Which monitor is the mouse on?
WhichMonitorIsMouseOn(){
MouseGetPos, mx, my
SysGet, mc, MonitorCount
Loop % mc {
SysGet, monArea, Monitor, % A_Index
if (mx >= monAreaLeft && mx <= monAreaRight && my >= monAreaTop && my <= monAreaBottom){
return A_Index
}
}
return 0
}
FilterWindows(active_hwnd, windows){
static window_diff := 7
WinGetPos, ax, ay, aw, ah, % "ahk_id " active_hwnd
ax_:=ax+aw/2,ay_:=ay+ah/2
MouseGetPos,ax_,ay_
monA:=MWAGetMonitor(ax_, ay_)
;OutputDebug % "AHK| Checking windows against ax: " ax ", ay: " ay ", ah: " ah ", aw: " aw ")"
w := []
for i, hwnd in windows {
WinGetPos, wx, wy, ww, wh, % "ahk_id " hwnd
WinGetTitle, title, % "ahk_id " hwnd
wx_:=wx+ww/2,wy_:=wy+wh/2
monW:=MWAGetMonitor(wx_, wy_)
if ((monA=monW) and title!=""){
w.push(hwnd)
;MsgBox,% monA monW title hwnd
;OutputDebug % "AHK| Adding window: " title
} else {
;OutputDebug % "AHK| Filtering out window: " title " ( wx: " wx ", wy:" wy ", wh: " wh ", ww: " ww
}
}
;return SortWindowsByHwnd(w)
return SortWindowsByTitle(w)
}
; Sorts a windows array by Window Title
SortWindowsByTitle(array){
for k, v in array {
WinGetTitle, title, % "ahk_id " v
str := title "|ws|" v "`n"
;OutputDebug % "AHK| SortWindowsByTitle: " str
sorted .= str
}
StringTrimRight,sorted,sorted,1
Sort,sorted, D
out := []
Loop, Parse, sorted, `n
{
hwnd := StrSplit(A_LoopField, "|ws|")
hwnd := hwnd[2]
out.push(hwnd)
}
return out
}
; Sorts a windows array by HWND
SortWindowsByHwnd(array){
for k, v in array {
sorted .= v "`n"
}
StringTrimRight,sorted,sorted,1
Sort,sorted, D
out := []
Loop, Parse, sorted, `n
{
out.push(A_LoopField)
}
return out
}
; Finds the window after the current one in a windows array
GetNextWindow(hwnd, windows, dir){
; Find the current window in the list
this_index := 0
max := windows.length()
Loop % max {
if (windows[A_Index] == hwnd){
this_index := A_Index
WinGetTitle, title, % "ahk_id " hwnd
break
}
}
if (!this_index)
new_index:=1
else
{
new_index := this_index+dir
if (new_index < 1)
new_index := max
if (new_index > max)
new_index := 1
}
;MsgBox,% title " " this_index " " new_index
return windows[new_index]
}
/*
_ _ _ __ __ _ _ _ _
| |__ | |_ | |_ _ __ _ / // /__ _ | |__ | | __ ___ ___ _ __ (_) _ __ | |_ ___ _ __ __ _
| '_ \ | __|| __|| '_ \(_) / // // _` || '_ \ | |/ // __| / __|| '__|| || '_ \ | __| / _ \ | '__|/ _` |
| | | || |_ | |_ | |_) |_ / // /| (_| || | | || < \__ \| (__ | | | || |_) || |_ _| (_) || | | (_| |
|_| |_| \__| \__|| .__/(_)_//_/ \__,_||_| |_||_|\_\|___/ \___||_| |_|| .__/ \__|(_)\___/ |_| \__, |
|_| |_| |___/
RunAsTask() - Auto-elevates script without UAC prompt | http://ahkscript.org/boards/viewtopic.php?t=4334
_________________________________________________________________________________________________________
*/
RunAsTask() { ; By SKAN, http://goo.gl/yG6A1F, CD:19/Aug/2014 | MD:22/Aug/2014
Local CmdLine, TaskName, TaskExists, XML, TaskSchd, TaskRoot, RunAsTask
Local TASK_CREATE := 0x2, TASK_LOGON_INTERACTIVE_TOKEN := 3
Try TaskSchd := ComObjCreate( "Schedule.Service" ), TaskSchd.Connect()
, TaskRoot := TaskSchd.GetFolder( "\" )
Catch
Return "", ErrorLevel := 1
CmdLine := ( A_IsCompiled ? "" : """" A_AhkPath """" ) A_Space ( """" A_ScriptFullpath """" )
TaskName := "[RunAsTask] " A_ScriptName " @" SubStr( "000000000" DllCall( "NTDLL\RtlComputeCrc32"
, "Int",0, "WStr",CmdLine, "UInt",StrLen( CmdLine ) * 2, "UInt" ), -9 )
Try RunAsTask := TaskRoot.GetTask( TaskName )
TaskExists := ! A_LastError
If ( not A_IsAdmin and TaskExists ) {
RunAsTask.Run( "" )
ExitApp
}
If ( not A_IsAdmin and not TaskExists ) {
Run *RunAs %CmdLine%, %A_ScriptDir%, UseErrorLevel
ExitApp
}
If ( A_IsAdmin and not TaskExists ) {
XML := "
( LTrim Join
<?xml version=""1.0"" ?><Task xmlns=""http://schemas.microsoft.com/windows/2004/02/mit/task""><Regi
strationInfo /><Triggers /><Principals><Principal id=""Author""><LogonType>InteractiveToken</LogonT
ype><RunLevel>HighestAvailable</RunLevel></Principal></Principals><Settings><MultipleInstancesPolic
y>Parallel</MultipleInstancesPolicy><DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries><
StopIfGoingOnBatteries>false</StopIfGoingOnBatteries><AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable><RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAva
ilable><IdleSettings><StopOnIdleEnd>true</StopOnIdleEnd><RestartOnIdle>false</RestartOnIdle></IdleS
ettings><AllowStartOnDemand>true</AllowStartOnDemand><Enabled>true</Enabled><Hidden>false</Hidden><
RunOnlyIfIdle>false</RunOnlyIfIdle><DisallowStartOnRemoteAppSession>false</DisallowStartOnRemoteApp
Session><UseUnifiedSchedulingEngine>false</UseUnifiedSchedulingEngine><WakeToRun>false</WakeToRun><
ExecutionTimeLimit>PT0S</ExecutionTimeLimit></Settings><Actions Context=""Author""><Exec>
<Command>" ( A_IsCompiled ? A_ScriptFullpath : A_AhkPath ) "</Command>
<Arguments>" ( !A_IsCompiled ? """" A_ScriptFullpath """" : "" ) "</Arguments>
<WorkingDirectory>" A_ScriptDir "</WorkingDirectory></Exec></Actions></Task>
)"
TaskRoot.RegisterTask( TaskName, XML, TASK_CREATE, "", "", TASK_LOGON_INTERACTIVE_TOKEN )
}
Return TaskName, ErrorLevel := 0
} ; _____________________________________________________________________________________________________
MWAGetMonitor(Mx := "", My := "")
{
if (!Mx or !My)
{
; if Mx or My is empty, revert to the mouse cursor placement
Coordmode, Mouse, Screen ; use Screen, so we can compare the coords with the sysget information`
MouseGetPos, Mx, My
}
SysGet, MonitorCount, 80 ; monitorcount, so we know how many monitors there are, and the number of loops we need to do
Loop, %MonitorCount%
{
SysGet, mon%A_Index%, Monitor, %A_Index% ; "Monitor" will get the total desktop space of the monitor, including taskbars
if ( Mx >= mon%A_Index%left ) && ( Mx < mon%A_Index%right ) && ( My >= mon%A_Index%top ) && ( My < mon%A_Index%bottom )
{
ActiveMon := A_Index
break
}
}
return ActiveMon
}
EnumerateAltTabWindows()
{
AltTabList := []
WinGet, list, List
Loop % list
{
if IsAltTabWindow(list%A_Index%)
AltTabList.Push(list%A_Index%)
}
Return AltTabList
}
IsAltTabWindow(hwnd)
{
static ImmersiveShell, IApplicationViewCollection, MONITOR_DEFAULTTONULL := 0, VirtualDesktopAltTabFilter := "null", PropEnumProcEx := RegisterCallback("PropEnumProcEx", "Fast", 4)
if (VirtualDesktopAltTabFilter = "null")
{
RegRead, VirtualDesktopAltTabFilter, HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced, VirtualDesktopAltTabFilter
OSbuildNumber := StrSplit(A_OSVersion, ".")[3]
if (OSbuildNumber < 14393)
{
msgbox Your %A_OSVersion% can not handle virtual desktops
exitapp
}
else if (OSbuildNumber <= 17134) ; Windows 10 1607 to 1803 and Windows Server 2016
IID_IApplicationViewCollection := "{2C08ADF0-A386-4B35-9250-0FE183476FCC}"
else
IID_IApplicationViewCollection := "{1841C6D7-4F9D-42C0-AF41-8747538F10E5}"
if !(ImmersiveShell := ComObjCreate(CLSID_ImmersiveShell := "{C2F03A33-21F5-47FA-B4BB-156362A2F239}", IID_IUnknown := "{00000000-0000-0000-C000-000000000046}"))
{
MsgBox ImmersiveShell not supported.
ExitApp
}
if !(IApplicationViewCollection := ComObjQuery(ImmersiveShell, IID_IApplicationViewCollection, IID_IApplicationViewCollection))
{
MsgBox IApplicationViewCollection interface not supported.
ExitApp
}
}
WinGetClass, winClass, ahk_id %hWnd%
if (winClass = "Windows.UI.Core.CoreWindow")
return
if (winClass = "ApplicationFrameWindow")
{
varsetcapacity(ApplicationViewCloakType, 4, 0)
DllCall("EnumPropsEx", "uptr", hWnd, "ptr", PropEnumProcEx, "ptr", &ApplicationViewCloakType)
if (numget(ApplicationViewCloakType, 0, "int") = 1) ; https://github.com/kvakulo/Switcheroo/commit/fa526606d52d5ba066ba0b2b5aa83ed04741390f
return
}
; if !DllCall("MonitorFromWindow", "uptr", hwnd, "uint", MONITOR_DEFAULTTONULL, "ptr") ; test if window is shown on any monitor. alt-tab shows any window even if window is out of monitor.
; return
DllCall(NumGet(NumGet(IApplicationViewCollection+0)+6*A_PtrSize), "ptr", IApplicationViewCollection, "uptr", hwnd, "ptr*", pView) ; GetViewForHwnd
if pView
{
DllCall(NumGet(NumGet(pView+0)+27*A_PtrSize), "ptr", pView, "int*", ShowInSwitchers) ; GetShowInSwitchers
ObjRelease(pView)
}
if ShowInSwitchers and ((VirtualDesktopAltTabFilter = 0) or IsWindowOnCurrentVirtualDesktop(hwnd))
return true
return
}
GetLastActivePopup(hwnd)
{
static GA_ROOTOWNER := 3
hwnd := DllCall("GetAncestor", "uptr", hwnd, "uint", GA_ROOTOWNER, "ptr")
hwnd := DllCall("GetLastActivePopup", "uptr", hwnd, "ptr")
return hwnd
}
IsWindowOnCurrentVirtualDesktop(hwnd)
{
static IVirtualDesktopManager
if !IVirtualDesktopManager
IVirtualDesktopManager := ComObjCreate(CLSID_VirtualDesktopManager := "{AA509086-5CA9-4C25-8F95-589D3C07B48A}", IID_IVirtualDesktopManager := "{A5CD92FF-29BE-454C-8D04-D82879FB3F1B}")
DllCall(NumGet(NumGet(IVirtualDesktopManager+0), 3*A_PtrSize), "ptr", IVirtualDesktopManager, "uptr", hwnd, "int*", onCurrentDesktop) ; IsWindowOnCurrentVirtualDesktop
return onCurrentDesktop
}
PropEnumProcEx(hWnd, lpszString, hData, dwData)
{
if (strget(lpszString, "UTF-16") = "ApplicationViewCloakType")
{
numput(hData, dwData+0, 0, "int")
return false
}
return true
}