(WinApi) ChangeDisplaySettingsEx 不起作用
(WinApi) ChangeDisplaySettingsEx does not work
我正在尝试编写 python 脚本来切换主监视器。
我有 3 个显示器(一个插入我的 i5 图形芯片,2 个插入 ATI HD7870)
我写了以下脚本:
import win32api as w
import win32con as c
i = 0
workingDevices = []
def setPrimary(id):
global workingDevices
return w.ChangeDisplaySettingsEx(
workingDevices[id].DeviceName,
w.EnumDisplaySettings(
workingDevices[id].DeviceName,
c.ENUM_CURRENT_SETTINGS
),
c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_RESET) \
== c.DISP_CHANGE_SUCCESSFUL
while True:
try:
Device = w.EnumDisplayDevices(None, i, 1)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
break
print("Num Devices: ", len(workingDevices))
for dev in workingDevices:
print("Name: ", dev.DeviceName)
调用它会导致:
In [192]: %run test.py
Num Devices: 3
Name: \.\DISPLAY1
Name: \.\DISPLAY2
Name: \.\DISPLAY7
In [193]: setPrimary(0)
Out[193]: True
In [194]: setPrimary(1)
Out[194]: True
In [195]: setPrimary(2)
Out[195]: True
到目前为止看起来不错,但问题是:什么都没有改变。由于 CDS_RESET,我的显示器会短暂闪烁,但主屏幕不会改变,尽管 ChangeDisplaySettingsEx returns DISP_CHANGE_SUCCESSFUL
有人知道为什么吗?
(我使用 Python 3.5.1 和 PyWin32 build 220)
PS 我使用 1 作为 EnumDisplayDevices 的第三个参数,因为 msdn 指出它应该设置为 1,尽管 PyWin 帮助说它应该设置为 0。
但是脚本的行为不会独立于这个值为一或零的值而改变
好的,我找到了解决方案。
显然,主监视器必须始终位于 (0, 0) 位置。
因此,当我尝试将另一台显示器设置为主要显示器时,其位置被设置为 (0, 0),这导致它与旧的主要显示器相交。
似乎要走的路是更新所有监视器的位置,并将这些更改写入注册表,然后一旦完成,通过使用默认参数调用 ChangeDisplaySettingsEx() 来应用更改。
这是我的新(现在可用)代码:
import win32api as w
import win32con as c
def load_device_list():
"""loads all Monitor which are plugged into the pc
The list is needed to use setPrimary
"""
workingDevices = []
i = 0
while True:
try:
Device = w.EnumDisplayDevices(None, i, 0)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
return workingDevices
def setPrimary(id, workingDevices, MonitorPositions):
"""
param id: index in the workingDevices list.
Designates which display should be the new primary one
param workingDevices: List of Monitors returned by load_device_list()
param MonitorPositions: dictionary of form {id: (x_position, y_position)}
specifies the monitor positions
"""
FlagForPrimary = c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_NORESET
FlagForSec = c.CDS_UPDATEREGISTRY | c.CDS_NORESET
offset_X = - MonitorPositions[id][0]
offset_Y = - MonitorPositions[id][1]
numDevs = len(workingDevices)
#get devmodes, correct positions, and update registry
for i in range(numDevs):
devmode = w.EnumDisplaySettings(workingDevices[i].DeviceName, c.ENUM_CURRENT_SETTINGS)
devmode.Position_x = MonitorPositions[i][0] + offset_X
devmode.Position_y = MonitorPositions[i][1] + offset_Y
if(w.ChangeDisplaySettingsEx(workingDevices[i].DeviceName, devmode,
FlagForSec if i != id else FlagForPrimary) \
!= c.DISP_CHANGE_SUCCESSFUL): return False
#apply Registry updates once all settings are complete
return w.ChangeDisplaySettingsEx() == c.DISP_CHANGE_SUCCESSFUL;
if(__name__ == "__main__"):
devices = load_device_list()
for dev in devices:
print("Name: ", dev.DeviceName)
MonitorPositions = {
0: (0, -1080),
1: (0, 0),
2: (1920, 0)
}
setPrimary(0, devices, MonitorPositions)
我正在尝试编写 python 脚本来切换主监视器。 我有 3 个显示器(一个插入我的 i5 图形芯片,2 个插入 ATI HD7870)
我写了以下脚本:
import win32api as w
import win32con as c
i = 0
workingDevices = []
def setPrimary(id):
global workingDevices
return w.ChangeDisplaySettingsEx(
workingDevices[id].DeviceName,
w.EnumDisplaySettings(
workingDevices[id].DeviceName,
c.ENUM_CURRENT_SETTINGS
),
c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_RESET) \
== c.DISP_CHANGE_SUCCESSFUL
while True:
try:
Device = w.EnumDisplayDevices(None, i, 1)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
break
print("Num Devices: ", len(workingDevices))
for dev in workingDevices:
print("Name: ", dev.DeviceName)
调用它会导致:
In [192]: %run test.py
Num Devices: 3
Name: \.\DISPLAY1
Name: \.\DISPLAY2
Name: \.\DISPLAY7
In [193]: setPrimary(0)
Out[193]: True
In [194]: setPrimary(1)
Out[194]: True
In [195]: setPrimary(2)
Out[195]: True
到目前为止看起来不错,但问题是:什么都没有改变。由于 CDS_RESET,我的显示器会短暂闪烁,但主屏幕不会改变,尽管 ChangeDisplaySettingsEx returns DISP_CHANGE_SUCCESSFUL
有人知道为什么吗? (我使用 Python 3.5.1 和 PyWin32 build 220)
PS 我使用 1 作为 EnumDisplayDevices 的第三个参数,因为 msdn 指出它应该设置为 1,尽管 PyWin 帮助说它应该设置为 0。 但是脚本的行为不会独立于这个值为一或零的值而改变
好的,我找到了解决方案。 显然,主监视器必须始终位于 (0, 0) 位置。 因此,当我尝试将另一台显示器设置为主要显示器时,其位置被设置为 (0, 0),这导致它与旧的主要显示器相交。 似乎要走的路是更新所有监视器的位置,并将这些更改写入注册表,然后一旦完成,通过使用默认参数调用 ChangeDisplaySettingsEx() 来应用更改。 这是我的新(现在可用)代码:
import win32api as w
import win32con as c
def load_device_list():
"""loads all Monitor which are plugged into the pc
The list is needed to use setPrimary
"""
workingDevices = []
i = 0
while True:
try:
Device = w.EnumDisplayDevices(None, i, 0)
if Device.StateFlags & c.DISPLAY_DEVICE_ATTACHED_TO_DESKTOP: #Attached to desktop
workingDevices.append(Device)
i += 1
except:
return workingDevices
def setPrimary(id, workingDevices, MonitorPositions):
"""
param id: index in the workingDevices list.
Designates which display should be the new primary one
param workingDevices: List of Monitors returned by load_device_list()
param MonitorPositions: dictionary of form {id: (x_position, y_position)}
specifies the monitor positions
"""
FlagForPrimary = c.CDS_SET_PRIMARY | c.CDS_UPDATEREGISTRY | c.CDS_NORESET
FlagForSec = c.CDS_UPDATEREGISTRY | c.CDS_NORESET
offset_X = - MonitorPositions[id][0]
offset_Y = - MonitorPositions[id][1]
numDevs = len(workingDevices)
#get devmodes, correct positions, and update registry
for i in range(numDevs):
devmode = w.EnumDisplaySettings(workingDevices[i].DeviceName, c.ENUM_CURRENT_SETTINGS)
devmode.Position_x = MonitorPositions[i][0] + offset_X
devmode.Position_y = MonitorPositions[i][1] + offset_Y
if(w.ChangeDisplaySettingsEx(workingDevices[i].DeviceName, devmode,
FlagForSec if i != id else FlagForPrimary) \
!= c.DISP_CHANGE_SUCCESSFUL): return False
#apply Registry updates once all settings are complete
return w.ChangeDisplaySettingsEx() == c.DISP_CHANGE_SUCCESSFUL;
if(__name__ == "__main__"):
devices = load_device_list()
for dev in devices:
print("Name: ", dev.DeviceName)
MonitorPositions = {
0: (0, -1080),
1: (0, 0),
2: (1920, 0)
}
setPrimary(0, devices, MonitorPositions)