ChangeDisplayOrientation(Orientation [, Display, Flags])
Description: Changes the orientation of the display.

(orientation=rotation)
Note: This feature is most likely chipset-specific. It is known to work on (some?) nVidia cards.
Code:
; Orientation
; 0 - DMDO_DEFAULT
; 1 - DMDO_90
; 2 - DMDO_180
; 3 - DMDO_270
; Display:
; The name of the display device. Usually something like: \\.\DISPLAY1
; If omitted, uses the default display device.
; dwflags:
; 0 - change dynamically (use ResetDisplay() to reset to settings in registry)
; 1 - change dynamically and update registry (CDS_UPDATEREGISTRY)
; 2 - test if the requested mode could be set (CDS_TEST)
ChangeDisplayOrientation(Orientation, Display="", dwflags=0)
{
; DEVMODE is 156 bytes on Windows XP and later.
; It is smaller on earlier versions of Windows, but that's okay.
VarSetCapacity(devmode, 156, 0)
NumPut(156, devmode, 36) ; devmode.dmSize := sizeof(devmode)
; Get the current resolution and orientation.
if ! DllCall("EnumDisplaySettings"
, "uint", Display ? &Display : 0 ; device name or NULL
, "int", -1 ; ENUM_CURRENT_SETTINGS
, "uint", &devmode
, "uint", 0)
return ; FAILED
; Get current resolution.
dmPelsWidth := NumGet(devmode, 108)
dmPelsHeight := NumGet(devmode, 112)
if (mod(NumGet(devmode, 52),2) != mod(Orientation,2))
{ ; Swap height and width.
NumPut(dmPelsHeight, devmode, 108) ; width
NumPut(dmPelsWidth, devmode, 112) ; height
}
; Set orientation.
NumPut(Orientation, devmode, 52)
; Update display settings.
return DllCall("ChangeDisplaySettingsEx"
, "uint", Display ? &Display : 0
, "uint", &devmode
, "uint", 0
, "uint", dwflags
, "uint", 0)
/* Return values for ChangeDisplaySettings
#define DISP_CHANGE_SUCCESSFUL 0
#define DISP_CHANGE_RESTART 1
#define DISP_CHANGE_FAILED -1
#define DISP_CHANGE_BADMODE -2
#define DISP_CHANGE_NOTUPDATED -3
#define DISP_CHANGE_BADFLAGS -4
#define DISP_CHANGE_BADPARAM -5
#define DISP_CHANGE_BADDUALVIEW -6
*/
}
ResetDisplay(Display="")
{
return DllCall("ChangeDisplaySettingsEx"
, "uint", Display ? &Display : 0 ; device name or NULL
, "uint", 0, "uint", 0, "uint", 0, "uint", 0)
}
Example usage - rotates the default display device 180 degrees, waits 10 seconds, then resets it.
Code:
ChangeDisplayOrientation(2) ; temporary by default (not saved to registry)
Sleep, 10000
ResetDisplay() ; reset to the values currently in the registry
It also supports multiple monitors, with the help of GetDisplayDeviceList():
Code:
; Creates a global array using ArrayName as the base.
; %ArrayName% Number of display devices.
; %ArrayName%Primary The index of the primary display device.
; %ArrayName%%N% Name of display device (used by ChangeDisplaySettingsEx.)
; %ArrayName%%N%ID {GUID} value required for some registry operations.
; Only set if DesktopOnly=false:
; %ArrayName%%N%Attached =1 if "Extend the desktop onto this monitor" is enabled.
GetDisplayDeviceList(ArrayName, DesktopOnly=true)
{
local DisplayDevice, Count, DeviceName, StateFlags, DeviceKey
; DISPLAY_DEVICE DisplayDevice
VarSetCapacity(DisplayDevice, 424)
; lpDisplayDevice.cb := sizeof(DISPLAY_DEVICE)
NumPut(424, DisplayDevice, 0)
if %ArrayName%Primary
%ArrayName%Primary =
VarSetCapacity(DeviceName, 32, 0)
VarSetCapacity(DeviceKey , 128, 0)
Loop
{
if ! DllCall("EnumDisplayDevices"
, "UInt", 0 ; lpDevice (NULL: use iDevNum to identify devices)
, "UInt", A_Index-1 ; iDevNum
, "UInt", &DisplayDevice ; lpDisplayDevice
, "UInt", 0) ; dwFlags
break
StateFlags := NumGet(DisplayDevice, 164)
; Useful DISPLAY_DEVICE.StateFlags:
; #define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001
; #define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004
; #define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008
if (StateFlags & 8) ; always exclude pseudo-devices
continue
if (DesktopOnly && !(StateFlags & 1))
continue
Count += 1
DllCall("lstrcpynA", "Str", DeviceName , "UInt", &DisplayDevice+4 , "int", 32)
DllCall("lstrcpynA", "Str", DeviceKey , "UInt", &DisplayDevice+296, "int", 128)
%ArrayName%%Count% := DeviceName
; DeviceKey is something like:
; \Registry\Machine\System\CurrentControlSet\Control\Video\{device-specific-value}\0000
; We want the:
; {device-specific-value}
SplitPath, DeviceKey,, DeviceKey ; "up one level"
SplitPath, DeviceKey, %ArrayName%%Count%ID
if (StateFlags & 4)
%ArrayName%Primary := Count
if (!DesktopOnly)
%ArrayName%%Count%Attached := (StateFlags&1)
; else: function only returns attached monitors, no need for %..%Attached.
}
%ArrayName% := Count
}
Example (same as example above, but for the second monitor):
Code:
GetDisplayDeviceList("Display", false)
if Display2 ; second monitor
{
ChangeDisplayOrientation(2, Display2)
Sleep, 10000
ResetDisplay(Display2)
}