背景信息
我最近在新房子里完成了一套新的“家庭影院”设置。客厅里有一台电视和条形音箱,办公室墙的另一边有我的电脑(运行 Plex)、PS3、Xbox 360 和路由器。我安装了一些新面板,并在房间之间铺设了 HDMI 电缆、USB 电缆和 cat6 电缆。在我的办公室,我将 PC、PS3 和 x360 连接到 3 合 1 HDMI 分配器,然后将其连接到客厅电视。
我的问题是,我可以设置好一切,以便在 PC 上使用多台显示器,将 Plex 设置为在电视启动时自动运行,等等。但是,如果我将 HDMI 开关切换到 PS3,它实际上会将电视作为显示器从我的 PC 上“拔下”,当我切换回来时,就像连接了一台新显示器,并且不会保留任何以前的设置。对于 Plex/XBMC 和 Steam Big Picture 来说,这尤其令人沮丧,因为它们不记得在该显示器上启动。
我的问题
有没有办法在电视拔掉电源插头后仍保留电视的所有多显示器设置?我唯一的其他选择是购买另一根 HDMI 电缆并将其穿过墙壁,专用于 PC,然后使用另一根电缆在 PS3/X360 之间切换。这样效果很好,但如果没有必要,我宁愿不花钱。
谢谢!
答案1
不,至少在没有第三方实用程序的情况下;您看到的是 Windows 的预期行为。
看看这个 SU 问题:保存应用程序的窗口位置和/或谷歌 寻找一个可以根据命令保存和恢复窗口/图标的实用程序。有很多实用程序可以做到这一点,包括(可能)显示驱动程序的实用程序。
答案2
我有开源一个小程序(事实上是两个)来解决这个问题。
第一个保存位置所有窗口:
SaveWinPositions [NumMonitors]
NumMonitors: (1 default) integer (positive) specifying the number of physical screens on the computer. The program will exit is at least this number of screens is not available. Zero (0) to ignore and save anyway.
第二个恢复它们:
RestoreWinPositions [NumMonitors]
NumMonitors: (1 default) integer (positive) specifying the number of physical screens on the computer. The program will wait for this number of screens available to start restoring. Zero (0) to ignore and restore anyway.
您可以通过任务计划程序对它们进行编程,使其按间隔执行,也可以通过热键手动执行,在屏幕保护程序中运行它们开始/关闭(这是我喜欢的)......等等。
这里是两个可执行文件(当然还有源代码)。
更新:我不知道为什么,但是有些人报告说 SourceForge 认为它是恶意软件,所以这里是源代码(德国工商会脚本)保存获胜位置:
; SaveWinPositions
; Version v0.22
; Obtiene el nombre, ID, posición y tamaño (x,y,w,h) de todas las ventanas.
; Incluídas las minimizadas.
; Crea un fichero "WinPos.txt" en %TEMP% conteniendo sus posiciones.
; Comprobamos que el programa no se ha activado por un disparo en falso (apagado/encendido casi simultáneo) del salvapantallas:
FileGetTime, FechaOriginal, %TEMP%\WinPos.txt
TiempoTranscurrido := A_Now-FechaOriginal
If TiempoTranscurrido<=5
{ ; Se grabaron datos de posiciones de ventanas hace 5 segundos o menos.
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Se grabaron datos de posiciones de ventanas hace " . TiempoTranscurrido . " segundos. Disparo en falso del salvapantallas. No se almacenarán posiciones de ventanas. Saliendo de SaveWinPositions. `n", %TEMP%\WinPositions-Log.txt
TrayTip, SaveWinPositions, Se grabaron datos de posiciones de ventanas hace %TiempoTranscurrido% segundos. Disparo en falso del salvapantallas. Abortando., ,1
sleep 10000
Exit ; Disparo en falso del salvapantallas. Cancelando la ejecución del programa.
}
NumParametros = %0%
Parametro1 = %1%
NumeroDePantallasEsperado:=1 ; El sistema dispone de este número de pantallas en total. No se deben mover ventanas ni grabar sus posiciones si no están encendidas todas.
;Nótese que este será el valor por defecto de no ser especificado mediante parámetro en la línea de comandos ni existir %A_WorkingDir%\screens.cfg.
If ( NumParametros<1 ) ; Comprobamos el número de parámetros.
{ ; Si no hay parámetros, capturamos el número de pantallas del fichero de configuración (por defecto en el directorio de ejecución del programa), si existe:
IfExist, screens.cfg ; Si existe el fichero de configuración...
{ ; ... leemos de él el número de pantallas esperado.
FileReadLine,NumeroDePantallasEsperado,%A_WorkingDir%\screens.cfg,1
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> No se introdujeron parámetros, se utilizará el extraído del fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
} else
{ ; No existe el fichero de configuración: informamos en el log.
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> No existe el fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
}
} else
{ ; Si hay parámetros...
If ( Parametro1 = 0 ) ; si el parámetro es un 0...
{ ; Ignorar número de monitores
IgnoreNumPantallas = 1
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Ignorando número de monitores: se ejecutará el programa sin esperarlos.`n", %TEMP%\WinPositions-Log.txt
} else
{ ; si el parámetro es distinto de 0...
; ... el parámetro contiene el número de pantallas esperado:
NumeroDePantallasEsperado = %1%
}
}
If ( Parametro1 != 0 ) ; a menos que se ignore el número de monitores...
{ ; ... añadimos una entrada al log con el número de pantallas necesarias.
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Numero de monitores esperado: " . NumeroDePantallasEsperado ".`n", %TEMP%\WinPositions-Log.txt
}
; Comprobamos que estén todos los monitores conectados:
SysGet, m, MonitorCount
If ( not IgnoreNumPantallas and m < NumeroDePantallasEsperado )
{
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Número de pantallas actual: " . m . "; se esperaba al menos " . NumeroDePantallasEsperado . ". Saliendo de SaveWinPositions. `n", %TEMP%\WinPositions-Log.txt
TrayTip, SaveWinPositions, Número de pantallas actual: %m% (se esperaba al menos %NumeroDePantallasEsperado%). Abortando., ,2
sleep 10000
Exit ; No están todas las pantallas. Cancelamos la ejecución del programa.
}
; Comprobamos si el salvapantallas está activo:
SalvaPantallas := WinExist("Protector de pantalla")
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Grabando posiciones de las ventanas del Escritorio `n", %TEMP%\WinPositions-Log.txt
FileDelete, %TEMP%\WindowsPositions.txt
WinGet windows, List
Loop %windows%
{
ContainsSpecialCharacter:=0
id := windows%A_Index%
WinGetTitle wt, ahk_id %id%
WinGet, WinStatus, MinMax, ahk_id %id%
if (WinStatus=-1)
{ ; Esta ventana está minimizada.
WinGetNormalPos(id, x, y, w, h)
If (x+y+w+h=0)
{ ; Todas sus coordenadas parecen valer 0. Necesitamos restaurarla para capturarlas corréctamente.
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Posible problema en ventana : " . wt . ". Es necesario restaurarla para detectar sus coordenadas."
WinRestore, ahk_id %ID%
WinGetPos, x,y,w,h,ahk_id %ID%
WinMinimize, ahk_id %ID%
WindowRestored:=1
}
} else
{ ; Esta ventana no está minimizada. Recurrimos a captura normal de coordenadas.
WinGetPos,x,y,w,h,ahk_id %id%
}
If (wt and wt!="Inicio") ; Ignore Windos Title null and "Inicio".
{ ; Añadir al fichero de datos: Coordenadas, dimensiones y título de la ventana.
r .= ID . "," . x . "," . y . "," . w . "," . h . "," . wt . "`n"
}
FileAppend , %r%, %TEMP%\WindowsPositions.txt
}
; Ordenamos por ID de ventana el fichero resultante:
FileRead, OutputVar, %TEMP%\WindowsPositions.txt
Sort, OutputVar, u ; Se producen duplicados de líneas, no sabemos aún porqué. :-P
; Duplicamos el fichero anteriormente existente de las posiciones de las ventanas, por si las moscas.
FileDelete, %TEMP%\WinPos-.txt
FileCopy, %TEMP%\WinPos--.txt, %TEMP%\WinPos---.txt
FileCopy, %TEMP%\WinPos-.txt, %TEMP%\WinPos--.txt
FileCopy, %TEMP%\WinPos.txt, %TEMP%\WinPos-.txt
FileDelete, %TEMP%\WinPos.txt
FileAppend, %OutputVar%,%TEMP%\WinPos.txt
If (SalvaPantallas and WindowRestored)
{ ; El programa necesitó desactivar el salvapantallas. Procedemos a reactivarlo:
FileAppend, % "* " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "SaveWinPositions:-> Estaba en funcionamiento el salvapantallas y hubo de ser desactivado. Reactivándolo..."
; Método alternativo para activación del salvapantallas (requiere NirSoft NirCmd en el path del sistema).
Run, nircmdc screensaver
}
TrayTip, SaveWinPositions, Posiciones de ventanas grabadas para %NumeroDePantallasEsperado% pantalla(s)., ,1
; Beeps report: correctly finished.
SoundBeep 1500,100
SoundBeep 1000,100
SoundBeep 3500,100
sleep 10000
; Funciones del programa
WinGetNormalPos(hwnd, ByRef x, ByRef y, ByRef w="", ByRef h="")
; Devuelve la posición que tendría la ventana si no estuviera minimizada (posición restaurada).
{
VarSetCapacity(wp, 44), NumPut(44, wp)
DllCall("GetWindowPlacement", "uint", hwnd, "uint", &wp)
x := NumGet(wp, 28, "int")
y := NumGet(wp, 32, "int")
w := NumGet(wp, 36, "int") - x
h := NumGet(wp, 40, "int") - y
}
这是代码恢复获胜位置:
FileDelete, %TEMP%\WinPosWorking.txt
FileCopy, %TEMP%\WinPos.txt, %TEMP%\WinPosWorking.txt
FileGetTime, FechaOriginal, %TEMP%\WinPos.txt
TiempoTranscurrido := A_Now-FechaOriginal
ArrayCount = 0
if TiempoTranscurrido>5 ; Disparo correcto del salvapantallas: activado/apagado no a la misma vez.
{
Loop, Read, %TEMP%\WinPosWorking.txt ; This loop retrieves each line from the file, one at a time.
{
ArrayCount += 1 ; Keep track of how many items are in the array.
Array%ArrayCount% := A_LoopReadLine ; Store this line in the next array element.
}
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Fichero de posiciones creado hace " . TiempoTranscurrido . " segundos (Correcto). Restaurando ventanas...." . " `n", %TEMP%\WinPositions-Log.txt
TrayTip, RestoreWinPositions, Restaurando ventanas..., ,1
}
if TiempoTranscurrido<=5 ; Disparo en falso del salvapantallas: activado/apagado (casi) a la misma vez.
{
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Fichero de posiciones creado hace " . TiempoTranscurrido . " segundos (demasiado reciente): Salvapantallas activado en falso. Abortando..." . " `n", %TEMP%\WinPositions-Log.txt
TrayTip, RestoreWinPositions, Fichero de posiciones crado hace %TiempoTranscurrido% segundos (demasiado reciente): Salvapantallas activado en falso. Abortando., ,2
sleep 10000
Exit 1
}
NumParametros = %0%
If ( NumParametros>0 )
{
Parametro1 = %1%
}
NumeroDePantallasEsperado:=1 ; El sistema dispone de este número de pantallas en total. No se deben mover ventanas ni grabar sus posiciones si no están encendidas todas.
;Nótese que este será el valor por defecto de no ser especificado mediante parámetro en la línea de comandos ni existir %A_WorkingDir%\screens.cfg.
If ( NumParametros<1 ) ; Comprobamos el número de parámetros.
{ ; Si no hay parámetros, capturamos el número de pantallas del fichero de configuración (por defecto en el directorio de ejecución del programa), si existe:
IfExist, screens.cfg ; Si existe el fichero de configuración...
{ ; ... leemos de él el número de pantallas esperado.
FileReadLine,NumeroDePantallasEsperado,%A_WorkingDir%\screens.cfg,1
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> No se introdujeron parámetros, se utilizará el extraído del fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
} else
{
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> No existe el fichero de configuración.`n", %TEMP%\WinPositions-Log.txt
}
} else
{ ; Si hay parámetros...
If ( Parametro1 = 0 ) ; si el parámetro es un 0...
{ ; Ignorar número de monitores
IgnoreNumPantallas = 1
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-> Ignorando número de monitores: se ejecutará el programa sin esperarlos.`n", %TEMP%\WinPositions-Log.txt
} else
{ ; si el parámetro es distinto de 0...
; ... el parámetro contiene el número de pantallas esperado:
NumeroDePantallasEsperado = %1%
}
}
If ( not IgnoreNumPantallas ) ; a menos que se ignore el número de monitores...
{ ; ... añadimos una entrada al log con el número de pantallas necesarias.
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> El sistema debe tener al menos " . NumeroDePantallasEsperado " pantalla(s).`n", %TEMP%\WinPositions-Log.txt
}
; Comprobamos que estén todos los monitores conectados:
SysGet, m, MonitorCount
If ( m < NumeroDePantallasEsperado ) ; Si no están todas las pantallas todavía activas...
{ ; ... esperamos a que se enciendan.
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-> Esperando a que el sistema tenga al menos " . NumeroDePantallasEsperado " pantalla(s).`n", %TEMP%\WinPositions-Log.txt
InicioEspera := A_Now
TrayTip, RestoreWinPositions, Esperando que estén encendidas %NumeroDePantallasEsperado% pantallas., ,1
}
While ( not IgnoreNumPantallas and m < NumeroDePantallasEsperado )
{
SysGet, m, MonitorCount
Ahora := A_Now
TiempoLimite := 180 ; Tiempo límite en segundos para esperar a que se enciendan todas las pantallas.
If ( Ahora>InicioEspera+TiempoLimite )
{ ; Superado tiempo de espera por pantallas.
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:-> No están listas las " . NumeroDePantallasEsperado . " pantallas transcurrido el tiempo límite. Cancelando la ejecución del programa.`n", %TEMP%\WinPositions-Log.txt
TrayTip, RestoreWinPositions, Transcurrido tiempo límite (%TiempoLimite% segundos) esperando que estén encendidas %NumeroDePantallasEsperado% pantallas. Abortando., ,2
sleep 10000
Exit ,3 ; No están todas las pantallas transcurridos 3 minutos. Cancelamos la ejecución del programa.
}
}
; Variable para comprobación de que todas las ventanas han sido corréctamente movidas:
Checking := 0
IncorrectPositionWindows := 65536 ; Just to enter the While loop.
; Repetir hasta que ninguna ventana haya tenido que ser movida.
While IncorrectPositionWindows>0
{
If Checking>0
{
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Alguna(s) ventana(s) no estaban en su posición correcta. Revisando; pasada número " . Checking+1 . " ...." . " `n", %TEMP%\WinPositions-Log.txt
}
; Inicializaciones de variables
CorrectPositionWindows := 0
IncorrectPositionWindows := 0
; Read from the array:
Loop %ArrayCount%
{ ; Extraemos línea a línea los datos de cada ventana individual
Ventana := Array%A_Index% ; Todos los datos de la ventana serán almacenados en esta variable.
coma = ,
; Extraemos el ID de la ventana.
Position := InStr(Ventana, coma)
StringMid, ID, Ventana, 0, Position-1
StringTrimLeft, Ventana, Ventana, Position
; Extraemos la coordenada X de la ventana.
Position := InStr(Ventana, coma)
StringMid, x, Ventana, 0, Position-1
StringTrimLeft, Ventana, Ventana, Position
; Extraemos la coordenada Y de la ventana.
Position := InStr(Ventana, coma)
StringMid, y, Ventana, 0, Position-1
StringTrimLeft, Ventana, Ventana, Position
; Extraemos el ancho W de la ventana.
Position := InStr(Ventana, coma)
StringMid, w, Ventana, 0, Position-1
StringTrimLeft, Ventana, Ventana, Position
; Extraemos el alto H de la ventana.
Position := InStr(Ventana, coma)
StringMid, h, Ventana, 0, Position-1
StringTrimLeft, Ventana, Ventana, Position
; Extraemos el título (lo que quede en el string) de la ventana.
Titulo := Ventana
WinGetPos,actualx,actualy,actualw,actualh,ahk_id %ID%
WinGet, WinStatus, MinMax, ahk_id %ID%
if WinStatus = -1 ; Si la ventana está minimizada...
{ ; Tratamos de obtener sus coordenadas restauradas sin tener que restaurarla.
WinGetNormalPos(ID, actualx, actualy, actualw, actualh)
}
If (x=actualx and y=actualy and w=actualw and h=actualh) ; Si la ventana ya tiene sus coordenadas finales...
{ ; Incrementamos el contador de ventanas que ya estaban en su posición correcta (no ha sido necesario moverla).
CorrectPositionWindows := ++CorrectPositionWindows
} else
{ IfWinExist, ahk_id %ID% ; Actuaremos sobre la ventana tan solo si la ventana existe.
{ ; Incrementamos el contador de ventanas que no están en su posición correcta (es necesario moverla).
IncorrectPositionWindows := ++IncorrectPositionWindows
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Moviendo ventana " . Titulo . " de coordenadas (X,Y,W,H): " . actualx . "," . actualy . "," . actualw . "," . actualh . " a coordenadas (X,Y,W,H): " . x . "," . y . "," . w . "," . h . "." . " `n", %TEMP%\WinPositions-Log.txt
If WinStatus = -1 ; Si la ventana está minimizada...
{ ; No hay más remedio que restaurarla, moverla, y minimizarla de nuevo (No disponemos de métodos para cambiar las coordenadas de restauración para una ventana minimizada).
WinRestore, ahk_id %ID%
WinMove, ahk_id %ID%, , x, y, w, h
WinMinimize, ahk_id %ID%
} else
{ ; Si la ventana no está minimizada, nos basta con moverla.
WinMove, ahk_id %ID%, , x, y, w, h
}
} else ; Si la ventana no existe...
{ ; prescindimos de actuar sobre esta ventana.
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Omitiendo ventana inexistente: " . Titulo . ". `n", %TEMP%\WinPositions-Log.txt
}
}
}
If Checking>=10 ; ¿Llevamos más de 10 pasadas intentando poner las ventanas en su sitio?
{ ; Cancelamos
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Demasiados intentos de ubicar ventanas. Abortando. :-( `n", %TEMP%\WinPositions-Log.txt
TrayTip, RestoreWinPositions, Demasiados intentos de ubicar ventanas. Abortando. :-( , ,1
sleep 10000
Exit 2
}
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Ventanas que ya estaban en su posición correcta: " . CorrectPositionWindows . ". `n", %TEMP%\WinPositions-Log.txt
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Ventanas reubicadas: " . IncorrectPositionWindows . ". `n", %TEMP%\WinPositions-Log.txt
Checking := ++Checking
}
FileAppend, % "# " . A_YYYY . "-" . A_MM . "-" . A_DD . " " . A_Hour . ":" . A_Min . ":" . A_Sec . " --> " . "RestoreWinPositions:--> Ventanas reubicadas corréctamente. Saliendo del programa. :-) `n", %TEMP%\WinPositions-Log.txt
TrayTip, RestoreWinPositions, Ventanas reubicadas corréctamente. Saliendo del programa. :-), ,1
; Beeps report: correctly finished.
SoundBeep 1500,100
SoundBeep 1000,100
SoundBeep 3500,100
sleep 10000
; Funciones utilizadas por el programa.
WinGetNormalPos(hwnd, ByRef x, ByRef y, ByRef w="", ByRef h="")
; Devuelve la posición que tendría la ventana si no estuviera minimizada (posición restaurada).
{
VarSetCapacity(wp, 44), NumPut(44, wp)
DllCall("GetWindowPlacement", "uint", hwnd, "uint", &wp)
x := NumGet(wp, 28, "int")
y := NumGet(wp, 32, "int")
w := NumGet(wp, 36, "int") - x
h := NumGet(wp, 40, "int") - y
}
答案3
下载布局工具
要在多个监视器上保存当前窗口位置,请运行:
winLayout save
要恢复窗口位置:
winLayout restore
它没有任何多余的装饰,只是一个 .exe 文件。为了便于运行,请为其创建一个任务栏快捷方式。
免责声明:我是作者。