You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下能否为双显示器布局切换设置快捷键?

双屏布局快速切换的PowerShell实现

核心思路

借助Windows系统user32.dll提供的显示配置API,通过PowerShell脚本修改屏幕位置参数,再将脚本绑定到快捷键,实现一键切换两种布局。

步骤1:获取显示器设备信息

先运行以下命令,获取你的飞利浦显示器和Huion Kamvas的设备ID(后续脚本需要用到):

Get-CimInstance Win32_DesktopMonitor | Select-Object DeviceID, ScreenWidth, ScreenHeight

记录下格式类似DISPLAY\PHL****\****的设备ID。

步骤2:编写布局切换脚本

脚本1:垂直堆叠布局(Kamvas在主显示器下方)

新建文件VerticalStack.ps1,填入以下内容(替换<主显示器DeviceID>和<Kamvas DeviceID>为你获取的实际值):

Add-Type @"
using System;
using System.Runtime.InteropServices;

public class DisplayConfig {
    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_INFO {
        public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo;
        public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo;
        public uint flags;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_SOURCE_INFO {
        public uint adapterIdLow;
        public uint adapterIdHigh;
        public uint id;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_PATH_TARGET_INFO {
        public uint adapterIdLow;
        public uint adapterIdHigh;
        public uint id;
        public uint modeInfoIdx;
        public DISPLAYCONFIG_VIDEO_OUTPUT_TYPE outputType;
        public DISPLAYCONFIG_ROTATION rotation;
        public DISPLAYCONFIG_SCALING scaling;
        public DISPLAYCONFIG_RATIONAL refreshRate;
        public DISPLAYCONFIG_SCANLINE_ORDERING scanlineOrdering;
        public bool targetAvailable;
        public uint statusFlags;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_MODE_INFO {
        public DISPLAYCONFIG_MODE_INFO_TYPE infoType;
        public uint id;
        public uint adapterIdLow;
        public uint adapterIdHigh;
        public DISPLAYCONFIG_TARGET_MODE targetMode;
        public DISPLAYCONFIG_SOURCE_MODE sourceMode;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_TARGET_MODE {
        public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_SOURCE_MODE {
        public uint width;
        public uint height;
        public DISPLAYCONFIG_PIXELFORMAT pixelFormat;
        public POINTL position;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct POINTL {
        public int x;
        public int y;
    }

    public enum DISPLAYCONFIG_MODE_INFO_TYPE {
        DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1,
        DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2
    }

    public enum DISPLAYCONFIG_ROTATION {
        DISPLAYCONFIG_ROTATION_IDENTITY = 1,
        DISPLAYCONFIG_ROTATION_ROTATE90 = 2,
        DISPLAYCONFIG_ROTATION_ROTATE180 = 3,
        DISPLAYCONFIG_ROTATION_ROTATE270 = 4
    }

    public enum DISPLAYCONFIG_PIXELFORMAT {
        DISPLAYCONFIG_PIXELFORMAT_8BPP = 1,
        DISPLAYCONFIG_PIXELFORMAT_16BPP = 2,
        DISPLAYCONFIG_PIXELFORMAT_24BPP = 3,
        DISPLAYCONFIG_PIXELFORMAT_32BPP = 4,
        DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5
    }

    public enum DISPLAYCONFIG_VIDEO_OUTPUT_TYPE {
        DISPLAYCONFIG_OUTPUT_TYPE_OTHER = 0,
        DISPLAYCONFIG_OUTPUT_TYPE_HD15 = 1,
        DISPLAYCONFIG_OUTPUT_TYPE_SVIDEO = 2,
        DISPLAYCONFIG_OUTPUT_TYPE_COMPOSITE_VIDEO = 3,
        DISPLAYCONFIG_OUTPUT_TYPE_COMPONENT_VIDEO = 4,
        DISPLAYCONFIG_OUTPUT_TYPE_DVI = 5,
        DISPLAYCONFIG_OUTPUT_TYPE_HDMI = 6,
        DISPLAYCONFIG_OUTPUT_TYPE_LVDS = 7,
        DISPLAYCONFIG_OUTPUT_TYPE_D_JPN = 8,
        DISPLAYCONFIG_OUTPUT_TYPE_SDI = 9,
        DISPLAYCONFIG_OUTPUT_TYPE_DISPLAYPORT_EXTERNAL = 10,
        DISPLAYCONFIG_OUTPUT_TYPE_DISPLAYPORT_EMBEDDED = 11,
        DISPLAYCONFIG_OUTPUT_TYPE_UDI_EXTERNAL = 12,
        DISPLAYCONFIG_OUTPUT_TYPE_UDI_EMBEDDED = 13,
        DISPLAYCONFIG_OUTPUT_TYPE_SDTVDONGLE = 14,
        DISPLAYCONFIG_OUTPUT_TYPE_MIRACAST = 15
    }

    public enum DISPLAYCONFIG_SCALING {
        DISPLAYCONFIG_SCALING_IDENTITY = 1,
        DISPLAYCONFIG_SCALING_CENTERED = 2,
        DISPLAYCONFIG_SCALING_STRETCHED = 3,
        DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4,
        DISPLAYCONFIG_SCALING_CUSTOM = 5,
        DISPLAYCONFIG_SCALING_PREFERRED = 128
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_RATIONAL {
        public uint Numerator;
        public uint Denominator;
    }

    public enum DISPLAYCONFIG_SCANLINE_ORDERING {
        DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0,
        DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1,
        DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2,
        DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = 2,
        DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO {
        public ulong pixelRate;
        public DISPLAYCONFIG_RATIONAL hSyncFreq;
        public DISPLAYCONFIG_RATIONAL vSyncFreq;
        public DISPLAYCONFIG_2DREGION activeSize;
        public DISPLAYCONFIG_2DREGION totalSize;
        public uint videoStandard;
        public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct DISPLAYCONFIG_2DREGION {
        public uint cx;
        public uint cy;
    }

    [DllImport("user32.dll")]
    public static extern long GetDisplayConfigBufferSizes(uint flags, out uint numPathArrayElements, out uint numModeInfoArrayElements);

    [DllImport("user32.dll")]
    public static extern long QueryDisplayConfig(uint flags, ref uint numPathArrayElements, DISPLAYCONFIG_PATH_INFO[] pathArray, ref uint numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO[] modeInfoArray, IntPtr currentTopologyId);

    [DllImport("user32.dll")]
    public static extern long SetDisplayConfig(uint numPathArrayElements, DISPLAYCONFIG_PATH_INFO[] pathArray, uint numModeInfoArrayElements, DISPLAYCONFIG_MODE_INFO[] modeInfoArray, uint flags);
}
"@

# 替换为你的两个显示器设备ID
$mainMonitorId = "<主显示器DeviceID>"
$kamvasId = "<Kamvas DeviceID>"

# 获取当前显示配置
$numPaths = 0
$numModes = 0
[DisplayConfig]::GetDisplayConfigBufferSizes(0x00000001, [ref]$numPaths, [ref]$numModes) | Out-Null

$paths = New-Object DisplayConfig+DISPLAYCONFIG_PATH_INFO[] $numPaths
$modes = New-Object DisplayConfig+DISPLAYCONFIG_MODE_INFO[] $numModes

[DisplayConfig]::QueryDisplayConfig(0x00000001, [ref]$numPaths, $paths, [ref]$numModes, $modes, [IntPtr]::Zero) | Out-Null

# 修改Kamvas位置为垂直堆叠(主显示器下方)
foreach ($mode in $modes) {
    if ($mode.infoType -eq [DisplayConfig+DISPLAYCONFIG_MODE_INFO_TYPE]::DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE) {
        $deviceId = "DISPLAY\$($mode.adapterIdLow.ToString('X8'))\$($mode.id.ToString('X8'))"
        if ($deviceId -eq $kamvasId) {
            # 主显示器高度1080,Kamvas Y坐标设为1080
            $mode.sourceMode.position.y = 1080
            $mode.sourceMode.position.x = 0
        } elseif ($deviceId -eq $mainMonitorId) {
            $mode.sourceMode.position.x = 0
            $mode.sourceMode.position.y = 0
        }
    }
}

# 应用新配置
[DisplayConfig]::SetDisplayConfig($numPaths, $paths, $numModes, $modes, 0x00000001) | Out-Null

脚本2:水平排列布局(Kamvas在主显示器右侧)

新建文件HorizontalLayout.ps1,内容与垂直脚本基本一致,仅修改Kamvas的位置参数:

# ... 省略前面的Add-Type部分(与垂直脚本完全相同) ...

# 修改Kamvas位置为水平排列(主显示器右侧)
foreach ($mode in $modes) {
    if ($mode.infoType -eq [DisplayConfig+DISPLAYCONFIG_MODE_INFO_TYPE]::DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE) {
        $deviceId = "DISPLAY\$($mode.adapterIdLow.ToString('X8'))\$($mode.id.ToString('X8'))"
        if ($deviceId -eq $kamvasId) {
            # 主显示器宽度1920,Kamvas X坐标设为1920
            $mode.sourceMode.position.x = 1920
            $mode.sourceMode.position.y = 0
        } elseif ($deviceId -eq $mainMonitorId) {
            $mode.sourceMode.position.x = 0
            $mode.sourceMode.position.y = 0
        }
    }
}

# 应用新配置
[DisplayConfig]::SetDisplayConfig($numPaths, $paths, $numModes, $modes, 0x00000001) | Out-Null

步骤3:绑定快捷键

  1. 右键点击每个.ps1文件,选择创建快捷方式。
  2. 右键点击快捷方式,选择属性。
  3. 在快捷方式选项卡的目标字段中,在脚本路径前添加powershell.exe -ExecutionPolicy Bypass -File ,示例:
    powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\VerticalStack.ps1"
    
  4. 在快捷键字段设置组合键(比如Ctrl+Alt+V对应垂直堆叠,Ctrl+Alt+H对应水平排列)。
  5. 点击确定保存设置。

注意事项

  • 若脚本报错,检查设备ID是否正确,以及屏幕分辨率是否与脚本中1920/1080的坐标匹配(如果你的1920p是垂直分辨率,需调整对应坐标值)。
  • 首次运行可能弹出PowerShell执行策略提示,选择允许即可。

内容的提问来源于stack exchange,提问作者Ian Mendes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 18:35:05