以编程方式旋转监视器 [英] Programmatically rotate monitor

查看:35
本文介绍了以编程方式旋转监视器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个可以做很多事情的实用程序脚本.我想做的一件事是旋转显示器;我有多个显示器,我希望主显示器旋转.我知道这种事情通常通过 win32api 起作用,我发现其中的一些功能似乎很有帮助,但我正在努力实现.

此行和下一行之间的所有内容都已过时,请参阅下面的第二行以获取对解决方案尝试的最新描述

<小时>

在将我的脸埋在文档中之后,恐怕我仍然没有太多关于如何前进的想法,除了它可能涉及 win32api.ChangeDisplaySettingsEx().我知道我需要给那个函数一个指向 DEVMODE 对象的指针(甚至不确定如何在 python 中做 C 指针),我想我可以从 win32api.EnumDisplaySettingsEx().所以如果我尝试,

<预><代码>>>>将 win32api 导入为 win32>>>a = win32.EnumDisplayDevices()>>>类型(一)

我应该得到一些涉及 DEVMODE 指针或其他什么的东西,但我得到了

<预><代码>>>>类型(一)<输入'PyDISPLAY_DEVICE'>

我不知道该怎么做,但我认为 这是结构

那么,我如何获得可以提供给 ChangeDisplaySettingsEx()DEVMODE 对象,以便我可以旋转我的一个显示器?提前致谢.

我在 Windows 7 上运行 Python 2.7

如果我使用正确的功能,它仍然不起作用.这可能是 Python 模块不完整吗?

<预><代码>>>>a = win32.EnumDisplaySettings()>>>类型(一)<输入'PyDEVMODEA'>>>>尺寸回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中AttributeError: 'PyDEVMODEA' 对象没有属性 'dmSize'>>>a.dmScale回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中AttributeError: 'PyDEVMODEA' 对象没有属性 'dmScale'>>>a.dmDisplayOrientation回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中AttributeError: 'PyDEVMODEA' 对象没有属性 'dmDisplayOrientation'

现在,我注意到这给了我一个 DEVMODEA 对象而不是 DEVMODE,但是 这个页面 说它们是一样的.这可能是什么问题?

现在我使用了正确的属性名称,我可以获得一个有效的 DEVMODEA 对象:

<预><代码>>>>a = win32.EnumDisplaySettings()>>>a.尺寸124L>>>a.显示方向0升

并改变对象的方向:

<预><代码>>>>a.DisplayOrientation = 90L>>>a.显示方向90L

然后我可以通过将这个 DEVMODEA 对象提供给 ChangeDisplaySettingsEx()

来尝试应用"这些更改<预><代码>>>>win32.ChangeDisplaySettingsEx(a.DeviceName, a, 0)-5L

这没有任何作用.不幸的是,文档在帮助我解释返回方面不是很有用价值.我假设 -5L 是某种错误代码,因为它不起作用,但我无法知道是哪一个.这个返回值是什么意思,我如何让我的新 DEVMODEA 对象应用"

我发现 -5L 返回值表示一个错误的参数.具体来说,它对第一个字段感到愤怒.如果我用 DISPLAY_DEVICE.DeviceName 替换它,我会得到 -2L 结果.这对应于坏模式(无论是什么).即使我给 ChangeDisplaySettingsEx() 提供了 EnumDisplaySettings() 输出的内容,也会发生这种情况.

<小时>

到目前为止我的进展:

<预><代码>>>>将 win32api 导入为 win32>>>导入 win32con>>>a = win32.EnumDisplaySettings()>>>a.显示方向0升>>>a.DisplayOrientation = win32con.DMDO_90>>>a.显示方向1L>>>a.PelsWidth, a.PelsHeight = a.PelsHeight, a.PelsWidth>>>a.Fields = a.Fields &win32con.DM_DISPLAYORIENTATION>>>name = win32.EnumDisplayDevices().DeviceName>>>姓名'\\\\.\\DISPLAY1'>>>win32.ChangeDisplaySettingsEx(name, a)-2L

<小时>

最近的尝试(美国东部时间 6 月 4 日上午 10:50)

Python 2.7.6(默认,2013 年 11 月 10 日,19:24:18)[MSC v.1500 32 位(英特尔)] on win32输入帮助"、版权"、信用"或许可"以获取更多信息.>>>将 win32api 导入为 win32>>>导入 win32con>>>>>>device = win32.EnumDisplayDevices(None, 1)>>>打印旋转设备 {} ({})".format(device.DeviceString, device.DeviceName)旋转设备 Intel(R) HD Graphics 4000 (\\.\DISPLAY2)>>>>>>dm = win32.EnumDisplaySettings(device.DeviceName, win32con.ENUM_CURRENT_SETTINGS)回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中pywintypes.error: (0, 'EnumDisplaySettings', '没有可用的错误信息')>>>>>>dm = win32.EnumDisplaySettings(device.DeviceName)回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中pywintypes.error: (123, 'EnumDisplaySettings', '文件名、目录名或卷标语法不正确.')>>>>>>dm = win32.EnumDisplaySettings(device.DeviceName, win32con.ENUM_CURRENT_SETTINGS)回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中pywintypes.error: (123, 'EnumDisplaySettings', '文件名、目录名或卷标语法不正确.')>>>

注意创建 dm 的第一次和第三次尝试如何失败尽管代码相同,但出现不同的错误.

解决方案

您正在调用返回 PDISPLAY_DEVICE 的 EnumDisplayDevices API.(请参阅 http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx)

您可以通过两种方式获取对象:

1) 来自 EnumDisplayDevicesEx

<预><代码>>>>导入 win32api>>>win32api.EnumDisplaySettingsEx()<0x00512E78处的PyDEVMODEA对象>

2) 或创建它(它将是空的)

<预><代码>>>>导入pywintypes;>>>dmode = pywintypes.DEVMODEType()>>>类型(dmode)<输入'PyDEVMODEA'>

对象公开的属性命名为win32"版本:例如dmSize变成Size完整列表可以在 PyDEVMODEA 对象上使用 dir(dmode) 命令可以看到.

可以使用 PyDEVMODEA 对象上的 help(dmode) 命令读取字段的描述.

完整的详细映射参考pywin32源代码分发内的PyDEVMODE.cpp

旋转显示器的步骤是:

  1. 获取开发模式

  2. 获取显示名称

  3. 设置旋转

  4. 使用 a.Fields = a.Fields & 配置标志win32con.DM_DISPLAYORIENTATION

  5. 调用 ChangeDisplaySettingsEx

在您的脚本中,您缺少 3-5 步.(字段也用作二进制掩码,因此必须相应处理).

您可以在 msdn 站点上看到有关 api 使用(C 语言)的完整示例:http://msdn.microsoft.com/en-us/library/ms812499.aspx

编辑 3在设置旋转"期间,您还必须交换宽度和高度,否则您要求的屏幕模式是不可能的:

(dmode.PelsWidth,dmode.PelsHeight) = (dmode.PelsHeight,dmode.PelsWidth)

EDIT4一个完整的例子(没有错误检查):

导入win32api为win32导入 win32condef printAllScreen():我 = 0为真:尝试:device = win32.EnumDisplayDevices(None,i);print("[%d] %s (%s)"%(i,device.DeviceString,device.DeviceName));i = i+1;除了:休息;返回我screen_count=printAllScreen()x = int(input("\n请输入一个显示数字 [0-%d]: "%screen_count-1))device = win32.EnumDisplayDevices(None,x);print("旋转设备 %s (%s)"%(device.DeviceString,device.DeviceName));dm = win32.EnumDisplaySettings(device.DeviceName,win32con.ENUM_CURRENT_SETTINGS)dm.DisplayOrientation = win32con.DMDO_90dm.PelsWidth, dm.PelsHeight = dm.PelsHeight, dm.PelsWidthdm.Fields = dm.Fields &win32con.DM_DISPLAYORIENTATIONwin32.ChangeDisplaySettingsEx(device.DeviceName,dm)

I'm working on making a utility script that does a whole bunch of things. One of the things I want to do is to rotate a display; I have multiple monitors, and I want the main one to rotate. I know this sort of thing usually works through win32api and I found a few functions there that seem helpful, but I'm struggling with the implementation.

Everything between this line and the next is out of date, see below second line for up to date description of solution attempts


After burying my face in the docs, I'm afraid I still don't have much of an idea on how to move forward aside from that it will likely involve win32api.ChangeDisplaySettingsEx(). I know I need to give that function a pointer to a DEVMODE object (not even sure how to do C pointers in python), which I think I can get from win32api.EnumDisplaySettingsEx(). So if I try,

>>> import win32api as win32
>>> a = win32.EnumDisplayDevices()
>>> type(a)

I should get something that involves DEVMODE pointer or whatever, but instead I get

>>> type(a)
<type 'PyDISPLAY_DEVICE'>

And I have no idea what to do with that, but I think this is the structure

So, how do I get a DEVMODE ojbect I can give to ChangeDisplaySettingsEx() so that I can rotate one of my displays? Thanks in advance.

I'm running Python 2.7 on Windows 7

EDIT: If I acutally use the correct function, it still doesn't work. Could this be the Python module be not complete?

>>> a = win32.EnumDisplaySettings()
>>> type(a)
<type 'PyDEVMODEA'>
>>> a.dmSize
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'PyDEVMODEA' object has no attribute 'dmSize'
>>> a.dmScale
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'PyDEVMODEA' object has no attribute 'dmScale'
>>> a.dmDisplayOrientation
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'PyDEVMODEA' object has no attribute 'dmDisplayOrientation'

Now, I noticed that this is giving me a DEVMODEA object instead of DEVMODE, but this page says they're the same. What could be the issue here?

EDIT: Now that I'm using the correct attribute names, I can get a valid DEVMODEA object:

>>> a = win32.EnumDisplaySettings()
>>> a.Size
124L
>>> a.DisplayOrientation
0L

And change the orientation in the object:

>>> a.DisplayOrientation = 90L
>>> a.DisplayOrientation
90L

I can then attempt to "apply" these changes by giving this DEVMODEA object to ChangeDisplaySettingsEx()

>>> win32.ChangeDisplaySettingsEx(a.DeviceName, a, 0)
-5L

This does nothing. Unfortnately, the docs aren't very useful in helping me interpret the return value. I'm assuming -5L is some sort of error code since it didn't work, but I have no way of knowing which one. What does this return value mean and how do I get my new DEVMODEA object to "apply"

I've worked out that -5L return value indicates a bad parameter. Specifically, its angry at the first field. If I replace that with DISPLAY_DEVICE.DeviceName, I get a -2L result. This corresponds to a bad mode (whatever that is). This happens even if I give ChangeDisplaySettingsEx() exactly what EnumDisplaySettings() puts out.


So my progress so far:

>>> import win32api as win32
>>> import win32con
>>> a = win32.EnumDisplaySettings()
>>> a.DisplayOrientation
0L
>>> a.DisplayOrientation = win32con.DMDO_90
>>> a.DisplayOrientation
1L
>>> a.PelsWidth, a.PelsHeight = a.PelsHeight, a.PelsWidth
>>> a.Fields = a.Fields & win32con.DM_DISPLAYORIENTATION
>>> name = win32.EnumDisplayDevices().DeviceName
>>> name
'\\\\.\\DISPLAY1'
>>> win32.ChangeDisplaySettingsEx(name, a)
-2L


Most recent attempt (6/4, 10:50am EST)

Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import win32api as win32
>>> import win32con
>>>
>>> device = win32.EnumDisplayDevices(None, 1)
>>> print "Rotate device {} ({})".format(device.DeviceString, device.DeviceName)
Rotate device Intel(R) HD Graphics 4000 (\\.\DISPLAY2)
>>>
>>> dm = win32.EnumDisplaySettings(device.DeviceName, win32con.ENUM_CURRENT_SETTINGS)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pywintypes.error: (0, 'EnumDisplaySettings', 'No error message is available')
>>>
>>> dm = win32.EnumDisplaySettings(device.DeviceName)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pywintypes.error: (123, 'EnumDisplaySettings', 'The filename, directory name, or volume label syntax is incorrect.')
>>>
>>> dm = win32.EnumDisplaySettings(device.DeviceName, win32con.ENUM_CURRENT_SETTINGS)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pywintypes.error: (123, 'EnumDisplaySettings', 'The filename, directory name, or volume label syntax is incorrect.')
>>>

Notice how the first and third attempt to create dm fail with different errors despite being the same code.

解决方案

You are calling the EnumDisplayDevices API that returns a PDISPLAY_DEVICE. (see http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx)

You can obtain the object in two way:

1) From EnumDisplayDevicesEx

>>> import win32api
>>> win32api.EnumDisplaySettingsEx()
<PyDEVMODEA object at 0x00512E78>

2) or creating it (it will be empty)

>>> import pywintypes;
>>> dmode = pywintypes.DEVMODEType()
>>> type(dmode)
<type 'PyDEVMODEA'>

EDIT:

the property exposed by the object are not named like the "win32" version: for example dmSize becomes Size the full list can be seen with dir(dmode) command on PyDEVMODEA object.

The description of the fields can be read with the help(dmode) command on a PyDEVMODEA object.

For a full detailed mapping refer to PyDEVMODE.cpp inside the pywin32 source distribution

EDIT2: The procedure to rotate the monitor is:

  1. Get Devmode

  2. Get DisplayName

  3. Set Rotation

  4. Configure the flags with a.Fields = a.Fields & win32con.DM_DISPLAYORIENTATION

  5. Invoke ChangeDisplaySettingsEx

In your script you are missing steps from 3-5. (also Fields is used as a binary mask so must handled corrispondly).

You can see a complete example about the api usage (in C) on the msdn site: http://msdn.microsoft.com/en-us/library/ms812499.aspx

Edit3 During "Set Rotation" you must also need to swap width and height, otherwise you are asking an screen mode that is not possible:

(dmode.PelsWidth,dmode.PelsHeight) = (dmode.PelsHeight,dmode.PelsWidth)

EDIT4 A complete example (with no error checking):

import win32api as win32
import win32con

def printAllScreen():
    i = 0
    while True:
        try:
            device = win32.EnumDisplayDevices(None,i);
            print("[%d] %s (%s)"%(i,device.DeviceString,device.DeviceName));
            i = i+1;
        except:
            break;
    return i

screen_count=printAllScreen()
x = int(input("\nEnter a display number [0-%d]: "%screen_count-1))


device = win32.EnumDisplayDevices(None,x);
print("Rotate device %s (%s)"%(device.DeviceString,device.DeviceName));

dm = win32.EnumDisplaySettings(device.DeviceName,win32con.ENUM_CURRENT_SETTINGS)
dm.DisplayOrientation = win32con.DMDO_90
dm.PelsWidth, dm.PelsHeight = dm.PelsHeight, dm.PelsWidth
dm.Fields = dm.Fields & win32con.DM_DISPLAYORIENTATION
win32.ChangeDisplaySettingsEx(device.DeviceName,dm)

这篇关于以编程方式旋转监视器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆