我有一台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;
我们对dmSize
、dmFields
、dmDisplayFixedOutput
、dmPelsWidth
和dmPelsHeight
成员感兴趣
在其他实现中,例如dmDeviceName
、dmPosition
、dmDisplayOrientation
和dmDisplayFrequency
成员也可能非常有趣。
所以我们首先创建一个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_PELSHEIGHT
、DM_PELSWIDTH
和DM_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)
然后NumPut
将DMDFO_CENTER
标志设置为dmDisplayFixedOutput
(偏移56(:
NumPut(DMDFO_CENTER := 2, _DEVMODE, 56)
现在,我们的结构应该充满我们想要的东西。
注意:如果要更改回监视器的本机分辨率,请不要尝试使用
DMDFO_CENTER
或DMDFO_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)
}
对于一些你最终可能不会使用的东西,这篇文章很长,可能过于详细,但我避免了学校作业
写作很有趣,也许至少有人能从中学到一些东西。