DPI缩放可以在每个会话的基础上以编程方式启用/禁用吗? [英] Can DPI scaling be enabled/disabled programmatically on a per-session basis?

查看:777
本文介绍了DPI缩放可以在每个会话的基础上以编程方式启用/禁用吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序恰好是用pygame编写的,它使用了封装了SDL的pygame,但我想这可能是使用Windows API的一个更普遍的问题。



在我的一些Python应用程序中,即使在高分辨率下,我也希望在Windows 10下进行像素对像素的控制。例如,我希望能够确保如果我的Surface Pro 3具有2160x1440的原始分辨率,那么我可以使用这些尺寸进入全屏模式,并呈现完全符合这些尺寸的全屏图像。



屏障是DPI缩放。默认情况下,在Windows的设置 - >显示下,更改文本,应用和其他项的大小的值为150%(推荐),结果是我只看到2/3的图像。我已经发现了如何解决这个问题......通过将该滑块向下移动到100%(但是这是对大多数其他应用程序而言不合要求)

  • 仅用于 python.exe pythonw.exe ,转到这些可执行文件的属性对话框,兼容性选项卡,然后单击禁用显示缩放比例高DPI设置。我可以为我单独或为所有用户做到这一点。我也可以通过以编程方式在注册表中设置适当的键来自动执行此过程。或者通过 .exe.manifest 文件(这似乎也需要全局设置更改,以选择外部清单,并可能对其他应用程序产生副作用)。

  • 我的问题是:我可以在每次启动的基础上从我的程序中的执行此操作,然后打开我的图形窗口?我或任何使用我的软件的人不一定希望为所有的 Python应用程序启用此设置 - 我们可能只需要在运行特定的Python程序时使用它。我在想象可能会有一个 winapi 调用(或者在SDL中包含的东西失败,可以实现这个功能),但到目前为止,我的研究还是空白。

    解决方案

    这是我寻找的答案,基于IInspectable和andlabs的评论(非常感谢):

    import ctypes

    #Query DPI Awareness(Windows 10 and 8)
    意识= ctypes.c_int()
    errorCode = ctypes.windll.shcore.GetProcessDpiAwareness(0,ctypes.addressof(意识))
    print(awareness.value)

    #Set DPI感知(Windows 10和8)
    errorCode = ctypes.windll.shcore.SetProcessDpiAwareness(2)
    #参数是感知等级,可以是0,1或2:
    #对于1对1像素控制,我似乎需要它是非零(我使用2级)

    #设置DPI感知(Windows 7和Vista)
    成功= ctypes.windll.use r32.SetProcessDPIAware()
    #在后面的操作系统上的行为是未定义的,但是当我在Windows 10机器上运行它时,它似乎与SetProcessDpiAwareness(1)

    知晓程度定义如下:
    $ b

      typedef enum _PROCESS_DPI_AWARENESS {
    PROCESS_DPI_UNAWARE = 0,
    / * DPI不知道。此应用程序不针对DPI更改进行缩放,并且
    始终假定具有100%的比例因子(96 DPI)。系统会根据任何其他DPI
    设置自动缩放
    。 * /

    PROCESS_SYSTEM_DPI_AWARE = 1,
    / *系统DPI可识别。此应用程序不会针对DPI更改进行缩放。
    它将查询一次DPI并将该值用于应用程序的
    生命周期。如果DPI更改,则应用程序不会
    调整为新的DPI值。当DPI从系统
    值变化时,系统会自动按比例增加或减少
    。 * /

    PROCESS_PER_MONITOR_DPI_AWARE = 2
    / *每台显示器支持DPI。这个应用程序在创建
    时检查DPI,并在DPI更改时调整比例因子。
    这些应用程序不会被系统自动缩放。 * /
    } PROCESS_DPI_AWARENESS;

    2级听起来最适合我的目标,但1也可以工作,前提是系统分辨率/ DPI缩放。

    SetProcessDpiAwareness 将失败,并且 errorCode = -2147024891 = 0x80070005 = E_ACCESSDENIED ,如果它之前已被调用当前进程(并且包括在启动进程时由系统调用,由于注册表项或 .manifest 文件)


    My application happens to be written in Python using pygame, which wraps SDL, but I'm imagining that this is probably a more-general question to do with the Windows API.

    In some of my Python applications, I want pixel-for-pixel control under Windows 10 even at high resolutions. I want to be able to ensure, for example, that if my Surface Pro 3 has a native resolution of 2160x1440, then I can enter full-screen mode with those dimensions and present a full-screen image of exactly those dimensions.

    The barrier to this is "DPI scaling". By default, under Windows' Settings -> Display, the value of "Change the size of text, apps, and other items" is "150% (Recommended)" and the result is that I only see 2/3 of my image. I have discovered how to fix this behaviour...

    1. systemwide, by moving that slider down to 100% (but that's undesirable for most other applications)
    2. just for python.exe and pythonw.exe, by going to those executables' "Properties" dialogs, Compatibility tab, and clicking "Disable display scaling on high DPI settings". I can do this for me alone, or for all users. I can also automate this process by setting the appropriate keys in the registry programmatically. Or via .exe.manifest files (which also seems to require a global setting change, to prefer external manifests, with possible side-effects on other applications).

    My question is: can I do this from inside my program on a per-launch basis, before I open my graphics window? I, or anyone using my software, won't necessarily want this setting enabled for all Python applications ever—we might want it just when running particular Python programs. I'm imagining there might be a winapi call (or failing that something inside SDL, wrapped by pygame) that could achieve this, but so far my research is drawing a blank.

    解决方案

    Here's the answer I was looking for, based on comments by IInspectable and andlabs (many thanks):

      import ctypes
    
      # Query DPI Awareness (Windows 10 and 8)
      awareness = ctypes.c_int()
      errorCode = ctypes.windll.shcore.GetProcessDpiAwareness(0, ctypes.addressof(awareness))
      print(awareness.value)
    
      # Set DPI Awareness  (Windows 10 and 8)
      errorCode = ctypes.windll.shcore.SetProcessDpiAwareness(2)
      # the argument is the awareness level, which can be 0, 1 or 2:
      # for 1-to-1 pixel control I seem to need it to be non-zero (I'm using level 2)
    
      # Set DPI Awareness  (Windows 7 and Vista)
      success = ctypes.windll.user32.SetProcessDPIAware()
      # behaviour on later OSes is undefined, although when I run it on my Windows 10 machine, it seems to work with effects identical to SetProcessDpiAwareness(1)
    

    The awareness levels are defined as follows:

    typedef enum _PROCESS_DPI_AWARENESS { 
        PROCESS_DPI_UNAWARE = 0,
        /*  DPI unaware. This app does not scale for DPI changes and is
            always assumed to have a scale factor of 100% (96 DPI). It
            will be automatically scaled by the system on any other DPI
            setting. */
    
        PROCESS_SYSTEM_DPI_AWARE = 1,
        /*  System DPI aware. This app does not scale for DPI changes.
            It will query for the DPI once and use that value for the
            lifetime of the app. If the DPI changes, the app will not
            adjust to the new DPI value. It will be automatically scaled
            up or down by the system when the DPI changes from the system
            value. */
    
        PROCESS_PER_MONITOR_DPI_AWARE = 2
        /*  Per monitor DPI aware. This app checks for the DPI when it is
            created and adjusts the scale factor whenever the DPI changes.
            These applications are not automatically scaled by the system. */
    } PROCESS_DPI_AWARENESS;
    

    Level 2 sounds most appropriate for my goal although 1 will also work provided there's no change in system resolution / DPI scaling.

    SetProcessDpiAwareness will fail with errorCode = -2147024891 = 0x80070005 = E_ACCESSDENIED if it has previously been called for the current process (and that includes being called by the system when the process is launched, due to a registry key or .manifest file)

    这篇关于DPI缩放可以在每个会话的基础上以编程方式启用/禁用吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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