多显示器下,如何只在当前显示器打开的窗口中一键切换?

找到一个更通用的解决方案。
软件groupy,开启这个设置。

image

用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
} ; _____________________________________________________________________________________________________
1 个赞