Functions for retrieving screen resolution and multi-monitor info. Click on a function name for details. The Keysharp-specific Monitor object below adds display identity, metadata, brightness control and change notifications.
| Function | Description |
|---|---|
| MonitorGet | Checks if the specified monitor exists and optionally retrieves its bounding coordinates. |
| MonitorGetCount | Returns the total number of monitors. |
| MonitorGetName | Returns the operating system's name of the specified monitor. |
| MonitorGetPrimary | Returns the number of the primary monitor. |
| MonitorGetWorkArea | Checks if the specified monitor exists and optionally retrieves the bounding coordinates of its working area. |
class Monitor extends Object
Represents one display. This class is exported by the KS module:
#Import "Ks" { Monitor }
Note: This class is experimental: it and its nested types may change or be removed without deprecation. See #Warn Experimental.
Identity and geometry are read when a Monitor is created; call Refresh to re-read them. Other metadata, such as Model or RefreshRate, is read when first used and then kept. Brightness and the VCP methods query the device on every call. A property the display does not report is the empty string.
M := Monitor(N) M := Monitor.Primary M := Monitor.FromPoint(X, Y) M := Monitor.FromMouse() M := Monitor.FromWindow(WinTitle, WinText, ExcludeTitle, ExcludeText) M := Monitor.FromId(Id) Monitors := Monitor.All Count := Monitor.Count
| Member | Description |
|---|---|
Monitor(N) | The monitor with 1-based number N, the same numbering MonitorGet uses. If N is omitted, the primary monitor. A number outside the current monitor count throws a ValueError. |
Monitor.Primary | The primary monitor. |
Monitor.All | An Array of every monitor, in number order, built from one enumeration. Prefer this to a loop over Monitor(A_Index), whose numbering can change between calls. |
Monitor.Count | The number of monitors; the same value as MonitorGetCount. |
Monitor.VirtualScreen | The whole desktop — the union of every monitor — as an object with X, Y, Width and Height, in native screen coordinates. X and Y are negative when a display sits left of or above the primary. |
Monitor.FromPoint(X, Y) | The monitor containing a point in native screen coordinates, or the nearest monitor when the point lies in a gap between displays. |
Monitor.FromMouse() | The monitor the mouse cursor is on. On Linux, cursor queries require a supported keysharp-desktop backend and do not request an interactive grant. |
Monitor.FromWindow(WinTitle, ...) | The monitor a window overlaps most, matching how the platform decides which monitor owns a window. Criteria use ordinary WinTitle matching. |
Monitor.FromId(Id) | The monitor whose Id matches, or the empty string when that monitor is not currently attached. Matching is case-insensitive. It reads the metadata of every attached display. |
| Property | Description |
|---|---|
Index | This monitor's 1-based number, matching MonitorGet. |
Name | The operating system's name for the monitor; the same value as MonitorGetName. |
Model | The panel's model name, for example "U2720Q". |
Manufacturer | The three-letter PNP manufacturer code, for example "DEL". |
Serial | The panel's serial number. |
Id | An identifier for this physical monitor that survives reboots and replugging, suitable for saving in a settings file — for example to restore a window layout per monitor. Pass it back to Monitor.FromId to find the display again. |
Adapter | The graphics adapter driving the monitor. |
Connection | How the monitor is attached: "HDMI", "DisplayPort", "eDP", "DVI", "VGA", "Internal", or the empty string. |
IsPrimary | Whether this is the primary monitor. |
IsInternal | Whether this is a built-in panel, such as a laptop or all-in-one screen, rather than an external monitor. |
Note: For a monitor which reports no serial number, Id identifies the port it is plugged into, not the panel; on macOS, it identifies the model, so identical displays share one Id. Id is the empty string when the display exposes no usable identity.
| Property | Description |
|---|---|
X, Y, Width, Height | Position and size in native screen coordinates, the same space MonitorGet reports. |
Bounds | The full monitor rectangle as an object with X, Y, Width and Height. |
WorkArea | The work area — the desktop minus taskbars, docks and panels — in the same shape. |
Scale | The monitor's authored-size scale; 1.0 is 100% and 1.5 is 150%. It maps deliberately authored UI sizes into native screen units. |
Dpi | Dots per inch, computed from the panel's physical size. Expressed in the same units as Width and Height. |
PhysicalWidth, PhysicalHeight | The panel's physical size in millimetres. |
RefreshRate | Vertical refresh in Hz as a floating-point value — 59.94, not 59. |
Orientation | Clockwise rotation of the desktop content in degrees: 0, 90, 180 or 270. |
Refresh() | Re-reads this monitor's layout and metadata in place and returns the same object, so it can be chained. The monitor is matched by name, then by number. Returns an empty string when the monitor is no longer attached, leaving the object's values unchanged. |
Note: Scale is not a screen-coordinate conversion factor and must never be applied to absolute positions.
Percent := M.Brightness M.Brightness := Percent Supported := M.IsBrightnessSupported Feature := M.GetVCP(Code) M.SetVCP(Code, Value)
| Member | Description |
|---|---|
Brightness | Gets or sets the monitor's brightness as a percentage from 0 to 100. Assigning another value throws a ValueError before the device is contacted. |
IsBrightnessSupported | Whether Brightness works for this monitor. |
GetVCP(Code) | Reads one raw DDC/CI VCP feature, returning an object with Current and Maximum. Throws a ValueError for a Code outside 0 to 255, and an OSError when the monitor does not answer. |
SetVCP(Code, Value) | Writes one raw DDC/CI VCP feature. Throws a ValueError for a Code outside 0 to 255 or a Value outside 0 to 65535, and an OSError when the monitor does not implement the code. |
Over DDC/CI, each read or assignment of Brightness takes tens of milliseconds. On a monitor or platform which does not support it, Brightness throws an OSError naming the reason; reading IsBrightnessSupported performs one brightness read to test this without an exception.
VCP codes are defined by the MCCS standard, for example 0x10 brightness, 0x12 contrast, 0x60 input source, 0x62 speaker volume and 0xD6 power mode.
SetVCP reads the feature before writing it, so each call performs two device transactions.
Warning: SetVCP drives the monitor's firmware directly. Setting an input-source or power code will switch the monitor away from this computer, and some displays react badly to codes they document but mishandle. Verify a code against the monitor's own MCCS documentation first.
Hook := Monitor.OnChange(Callback) Hooks := Monitor.Hooks
Calls Callback whenever the display configuration changes, and returns a running MonitorHook controlling the subscription.
Callback is a function object which receives (Hook, Change):
| Change | Meaning |
|---|---|
"Topology" | The set of attached monitors changed: one was plugged in or unplugged, or the machine docked or undocked. |
"Settings" | The same monitors are attached, but something about them changed: resolution, position, scale, or which one is primary. |
To inspect the new layout, read Monitor.Count or Monitor.All in the callback, or call Refresh on a Monitor obtained earlier.
The callback is not called for a notification which changed nothing observable.
The returned hook is an EventHook. Monitor.Hooks is an Array of the running hooks. A MonitorHook does not keep the script running, so a script which only waits for display changes calls Persistent.
The built-in variables A_ScreenWidth and A_ScreenHeight contain the dimensions of the primary monitor, in pixels.
SysGet can be used to retrieve the bounding rectangle of all display monitors. For example, this retrieves the width and height of the virtual screen:
MsgBox SysGet(78) " x " SysGet(79)
Geometry, Name, Index and the factories work on every platform. What varies is metadata and device control.
Brightness works on the built-in panel and on external monitors which support DDC/CI.
New queries refresh display geometry and scale after display changes; existing Monitor objects retain their snapshot semantics. Work-area queries account for panels and docks independently of display-layout changes.
On X11, geometry, refresh rate and orientation are read through keysharp-desktop. On Wayland, RefreshRate and Orientation are the empty string and 0 if the native compositor connection is unavailable. Adapter is the DRM driver name, such as amdgpu or i915.
For external monitors, Brightness and the VCP methods need the i2c-dev kernel module and access to the i2c bus. A root install adds a udev rule granting the local-seat user access to display-controller i2c buses, and ddcutil's own rule also works; without either, they throw an OSError naming the requirement. OnChange works on X11 and every Wayland compositor.
Model and Adapter are always the empty string, and Connection distinguishes only built-in from external. RefreshRate is the empty string on some built-in panels.
Brightness works on the built-in panel, Apple displays and other external monitors which support DDC/CI. The VCP methods work only on external DDC/CI monitors.
Note: DDC/CI on Intel Macs is unverified. Some USB-C hubs and docks do not carry the DDC channel through to the monitor, in which case Brightness and the VCP methods throw an OSError for a display that would otherwise support them.
DllCall, Win functions, SysGet, EventHook
Displays info about each monitor.
MonitorCount := MonitorGetCount()
MonitorPrimary := MonitorGetPrimary()
MsgBox "Monitor Count:`t" MonitorCount "`nPrimary Monitor:`t" MonitorPrimary
Loop MonitorCount
{
MonitorGet A_Index, &L, &T, &R, &B
MonitorGetWorkArea A_Index, &WL, &WT, &WR, &WB
MsgBox
(
"Monitor:`t#" A_Index "
Name:`t" MonitorGetName(A_Index) "
Left:`t" L " (" WL " work)
Top:`t" T " (" WT " work)
Right:`t" R " (" WR " work)
Bottom:`t" B " (" WB " work)"
)
}
Lists every monitor using the Monitor object, showing which facts the displays actually report.
#Import "Ks" { Monitor }
for M in Monitor.All
{
Info := "Monitor:`t#" M.Index (M.IsPrimary ? " (primary)" : "") "`n"
Info .= "Name:`t" M.Name "`n"
Info .= "Model:`t" M.Manufacturer " " M.Model "`n"
Info .= "Size:`t" M.Width "x" M.Height " at " (M.Scale * 100) "%`n"
Info .= "Refresh:`t" M.RefreshRate "`n"
Info .= "Id:`t" M.Id
MsgBox Info
}
Dims every monitor that supports it. IsBrightnessSupported is tested first so an unsupported display is skipped instead of throwing.
#Import "Ks" { Monitor }
for M in Monitor.All
if (M.IsBrightnessSupported)
M.Brightness := Max(0, M.Brightness - 20)
Reacts to the display configuration changing — for example to re-place windows after docking. The hook does not keep the script running, so Persistent does.
#Import "Ks" { Monitor }
Hook := Monitor.OnChange(DisplaysChanged)
Persistent
DisplaysChanged(Hook, Change)
{
if (Change = "Topology")
ToolTip "Monitors attached or removed: now " Monitor.Count
else
ToolTip "Display settings changed"
SetTimer () => ToolTip(), -3000
}
Saves the monitor a window is on, and finds that same physical display again on a later run.
#Import "Ks" { Monitor }
Id := Monitor.FromWindow("A").Id
IniWrite Id, "layout.ini", "Editor", "Monitor"
; ... on a later run:
Saved := IniRead("layout.ini", "Editor", "Monitor", "")
M := Monitor.FromId(Saved)
if (M)
MsgBox "That display is attached, as monitor #" M.Index
else
MsgBox "That display is not currently attached."