自动热键:将超宽21:9纵横比更改为16:9

  • 本文关键字: autohotkey aspect-ratio
  • 更新时间 :
  • 英文 :


我有一台38英寸的超宽显示器。我有一个正在工作的AHK脚本,它可以在3840x1600和1920x1080分辨率之间切换,但它不会更改为16:9的纵横比,这应该会在显示器两侧留下黑条(当保持21:9的比例时,所有内容都会按比例水平缩放(

当你在Windows显示设置中将分辨率从3840更改为1920时,它也会将比例更改为16:9,这正是我所需要的。

这是我的决议工作脚本:请告诉我需要更改\添加什么才能将比例更改为16:9。

x := A_ScreenWidth
;# y := A_ScreenHeight
;# MsgBox, Your screen resolution is : %x%x%y%

if (x = 1920)
{
ChangeResolution(3840, 1600)
Sleep, 500
Run, J:PRESETSAUTOHOTKEY SCRIPTSPRODUCTIVITYResizeDefaultWindows.ahk
}
else
ChangeResolution(1920, 1080)
Return
ChangeResolution(Screen_Width := 1920, Screen_Height := 1080, Color_Depth := 32)
{
VarSetCapacity(Device_Mode,156,0)
NumPut(156,Device_Mode,36) 
DllCall( "EnumDisplaySettingsA", UInt,0, UInt,-1, UInt,&Device_Mode )
NumPut(0x5c0000,Device_Mode,40) 
NumPut(Color_Depth,Device_Mode,104)
NumPut(Screen_Width,Device_Mode,108)
NumPut(Screen_Height,Device_Mode,112)
Return DllCall( "ChangeDisplaySettingsA", UInt,&Device_Mode, UInt,0 )
}
ExitApp
Return

dmDisplayFixedOutput设置为DMDFO_CENTER(docs(可能会奏效
但你也可能在四个侧面都有黑条
这也可能没有任何区别。当我尝试这个时,在不同的显示器上得到了非常不一致的结果。你的显示器设置肯定也会在这里发挥作用
但无论如何,我想值得一试。


让我们从_devicemodeA(docs(结构开始
我添加了每个成员的大小(以字节为单位(及其偏移量:

typedef struct _devicemodeA {                   //  size    |   offset
BYTE   dmDeviceName[CCHDEVICENAME];         //  32          0
WORD dmSpecVersion;                         //  2           32
WORD dmDriverVersion;                       //  2           34
WORD dmSize;                                //  2           36
WORD dmDriverExtra;                         //  2           38
DWORD dmFields;                             //  4           40
union {
/* printer only fields */
struct {
short dmOrientation;                    //  2           44
short dmPaperSize;                      //  2           46
short dmPaperLength;                    //  2           48
short dmPaperWidth;                     //  2           50
short dmScale;                          //  2           52
short dmCopies;                         //  2           54
short dmDefaultSource;                  //  2           56
short dmPrintQuality;                   //  2           58
} DUMMYSTRUCTNAME;
/* display only fields */
struct {
POINTL dmPosition;                      //  8           44
DWORD  dmDisplayOrientation;            //  4           52
DWORD  dmDisplayFixedOutput;            //  4           56
} DUMMYSTRUCTNAME2;
} DUMMYUNIONNAME;
short dmColor;                              //  2           60
short dmDuplex;                             //  2           62
short dmYResolution;                        //  2           64
short dmTTOption;                           //  2           66
short dmCollate;                            //  2           68
BYTE   dmFormName[CCHFORMNAME];             //  32          70
WORD   dmLogPixels;                         //  2           102
DWORD  dmBitsPerPel;                        //  4           104
DWORD  dmPelsWidth;                         //  4           108
DWORD  dmPelsHeight;                        //  4           112
union {
DWORD  dmDisplayFlags;                  //  4           116
DWORD  dmNup;                           //  4           116
} DUMMYUNIONNAME2;
DWORD  dmDisplayFrequency;                  //  4           120
#if(WINVER >= 0x0400)
DWORD  dmICMMethod;                         //  4           124
DWORD  dmICMIntent;                         //  4           128
DWORD  dmMediaType;                         //  4           132
DWORD  dmDitherType;                        //  4           136
DWORD  dmReserved1;                         //  4           140
DWORD  dmReserved2;                         //  4           144
#if (WINVER >= 0x0500) || (_WIN32_WINNT >= _WIN32_WINNT_NT4)
DWORD  dmPanningWidth;                      //  4           148
DWORD  dmPanningHeight;                     //  4           152
#endif                                          //-----
#endif /* WINVER >= 0x0400 */                   //  156 (total)
} DEVMODEA, *PDEVMODEA, *NPDEVMODEA, *LPDEVMODEA;

我们对dmSizedmFieldsdmDisplayFixedOutputdmPelsWidthdmPelsHeight成员感兴趣
在其他实现中,例如dmDeviceNamedmPositiondmDisplayOrientationdmDisplayFrequency成员也可能非常有趣。


所以我们首先创建一个DEVMODE结构,并用我们的显示设备的当前信息填充它。这样,我们只能改变我们想要的,而不是在其中设置每一条所需的信息。

因此,我们创建了一个变量_DEVMODE,并为其保留156个字节。
156来自我们上面为其计算的大小
预订只是AHK DllCalling的一件事,没有什么特别的了。

VarSetCapacity(_DEVMODE, 156)

然后我们可以使用EnumDisplaySettingsA(docs(函数来填充结构
但首先我们注意到文档状态:

在调用EnumDisplaySettings之前,将dmSize成员设置为sizeof(DEVMODE)

因此,我们知道大小为156字节,dmSize成员的偏移量为36字节
NumPut()(docs(用于操作特定内存地址的内存:

NumPut(156, _DEVMODE, 36)

然后我们准备呼叫EnumDisplaySettingsA:

DllCall("EnumDisplaySettingsA", Ptr, 0, UInt, ENUM_CURRENT_SETTINGS := -1, UInt, &_DEVMODE)

参数:

  • lpszDeviceName:传入的Ptr0表示NULL(docs(,表示使用当前显示设备。一个更高级的解决方案可以在这里选择使用哪种显示器
  • iModeNum:UIntENUM_CURRENT_SETTINGS(其值为-1(传入以指示使用当前使用的设置,而不是存储在注册表中的设置
  • *lpDevMode:UInt&_DEVMODE传入,表示我们的_DEVMODE结构的指针
    &(docs(用于获取指针

现在该结构应该已成功填充
测试它可能很好,所以让我们试着用NumGet()(docs(获得刷新率作为测试:

MsgBox, % NumGet(_DEVMODE, 120) " Hz"

现在我们可以开始更改分辨率并设置DMDFO_CENTER标志,以获得所需的黑条。

首先,我们将标志设置为dmFields成员,以指示我们正在使用一些成员
我们需要设置DM_PELSHEIGHTDM_PELSWIDTHDM_DISPLAYFIXEDOUTPUT标志,因为我们正在更改高度、宽度和";固定输出";地位

DM_PELSHEIGHT := 0x00100000
DM_PELSWIDTH := 0x00080000
DM_DISPLAYFIXEDOUTPUT := 0x20000000
; technically + instead of | (bitwise or) would work the same
flags := DM_PELSHEIGHT | DM_PELSWIDTH | DM_DISPLAYFIXEDOUTPUT

然后我们可以NumPut。我们知道CCD_ 34处于偏移40处。

NumPut(flags, _DEVMODE, 40)

然后我们可以将NumPut我们想要的分辨率dmPelsWidth(偏移量108(和dmPelsHeight(偏移量112(:

NumPut(1920, _DEVMODE, 108)
NumPut(1080, _DEVMODE, 112)

然后NumPutDMDFO_CENTER标志设置为dmDisplayFixedOutput(偏移56(:

NumPut(DMDFO_CENTER := 2, _DEVMODE, 56)

现在,我们的结构应该充满我们想要的东西。

注意:如果要更改回监视器的本机分辨率,请不要尝试使用DMDFO_CENTERDMDFO_STRETCH标志。使用DMDFO_DEFAULT,或者根本不使用dmDisplayFixedOutput成员


现在只剩下使用ChangeDisplaySettingsA(docs(函数来设置我们的更改:

DllCall("ChangeDisplaySettingsA", UInt, &_DEVMODE, UInt, 0)

再次,传入我们结构的指针,然后传入UInt 0标志,指示立即更改显示设置。


完整示例脚本

#NoEnv
ENUM_CURRENT_SETTINGS := -1
DM_PELSHEIGHT := 0x00100000
DM_PELSWIDTH := 0x00080000
DM_DISPLAYFIXEDOUTPUT := 0x20000000
DMDFO_DEFAULT := 0
DMDFO_STRETCH := 1
DMDFO_CENTER := 2
VarSetCapacity(_DEVMODE, 156)
NumPut(156, _DEVMODE, 36)           ;dmSize
DllCall("EnumDisplaySettingsA", Ptr, 0, UInt, ENUM_CURRENT_SETTINGS, UInt, &_DEVMODE)
MsgBox, % NumGet(_DEVMODE, 120) " Hz"
; technically + instead of | (bitwise or) would work the same
flags := DM_PELSHEIGHT | DM_PELSWIDTH | DM_DISPLAYFIXEDOUTPUT
NumPut(flags, _DEVMODE, 40)         ;dmFields
NumPut(1920, _DEVMODE, 108)         ;dmPelsWidth
NumPut(1080, _DEVMODE, 112)         ;dmPelsHeight
NumPut(DMDFO_CENTER, _DEVMODE, 56)  ;dmDisplayFixedOutput
DllCall("ChangeDisplaySettingsA", UInt, &_DEVMODE, UInt, 0)

作为函数的完整示例脚本

#NoEnv
DMDFO_DEFAULT := 0
DMDFO_STRETCH := 1
DMDFO_CENTER := 2
F1::ChangeDisplaySettings(1920, 1080, DMDFO_CENTER)
F2::ChangeDisplaySettings(3840, 1600, DMDFO_DEFAULT)
ChangeDisplaySettings(width, height, DMDFO)
{
static ENUM_CURRENT_SETTINGS := -1
, DM_PELSHEIGHT := 0x00100000
, DM_PELSWIDTH := 0x00080000
, DM_DISPLAYFIXEDOUTPUT := 0x20000000

VarSetCapacity(_DEVMODE, 156)
NumPut(156, _DEVMODE, 36)       ;dmSize

DllCall("EnumDisplaySettingsA", Ptr, 0, UInt, ENUM_CURRENT_SETTINGS, UInt, &_DEVMODE)

; technically + instead of | (bitwise or) would work the same
flags := DM_PELSHEIGHT | DM_PELSWIDTH | DM_DISPLAYFIXEDOUTPUT
NumPut(flags, _DEVMODE, 40)     ;dmFields
NumPut(width, _DEVMODE, 108)    ;dmPelsWidth
NumPut(height, _DEVMODE, 112)   ;dmPelsHeight
NumPut(DMDFO, _DEVMODE, 56)     ;dmDisplayFixedOutput
return DllCall("ChangeDisplaySettingsA", UInt, &_DEVMODE, UInt, 0)
}

对于一些你最终可能不会使用的东西,这篇文章很长,可能过于详细,但我避免了学校作业
写作很有趣,也许至少有人能从中学到一些东西。

相关内容

  • 没有找到相关文章

最新更新