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

Electron小工具开发:检测全屏应用以控制唤出逻辑(PowerShell失效)

检测系统全屏应用,控制Electron工具唤出逻辑

我正在开发一款Electron小工具,按下Ctrl+Space组合键即可唤出显示。需求是仅当系统中没有应用处于全屏运行状态时,该工具才能被唤出。我曾尝试用PowerShell实现检测逻辑,但方案无法正常工作,原代码如下:

const { exec } = require('child_process')
function isFullscreenAppRunning() {
    return new Promise((resolve, reject) => {
        const script = `
        function Is-AppFullScreen {
                param(
                [Parameter(Mandatory = $true)]
                [string] $ProcessName
                )
            
                # Get main screen resolution
                $screenWidth = (Get-Screen).WorkingArea.Width
                $screenHeight = (Get-Screen).WorkingArea.Height
            
                # Get window of the process
                $window = Get-Process -Name $ProcessName | Where-Object {$_.MainWindowTitle -ne $null} | Select-Object -ExpandProperty MainWindowHandle
            
                if ($window) {
                # Get window dimensions (accounting for borders)
                $windowRect = [System.Drawing.Rectangle]::FromLTRB((Get-Window -Handle $window).Left, (Get-Window -Handle $window).Top, (Get-Window -Handle $window).Right, (Get-Window -Handle $window).Bottom)
                $windowWidth = $windowRect.Width - (Get-Window -Handle $window).BorderWidth
                $windowHeight = $windowRect.Height - (Get-Window -Handle $window).BorderHeight
            
                # Check if window dimensions match screen resolution (considering potential rounding errors)
                return ($windowWidth -eq $screenWidth -and $windowHeight -eq $screenHeight)
                } else {
                # Process not found or no main window
                return $false
                }
            }
            
            # Check all processes with a main window title
            $isAnyAppFullScreen = $false
            Get-Process | Where-Object {$_.MainWindowTitle -ne $null} | ForEach-Object {
                $processName = $_.Name
                if (Is-AppFullScreen -ProcessName $processName) {
                $isAnyAppFullScreen = $true
                # Exit loop once a fullscreen app is found (optional for performance)
                break
                }
            }
            
            # Return true if any app is fullscreen, false otherwise
            return $isAnyAppFullScreen
            `
        
        exec(`powershell -command "${script}"`, (err, stdout, stderr) => {
            if (err) {
            reject(err)
            return
            }
            resolve(stdout.trim() === 'True')
        })
    })
}

原方案问题分析

  1. 依赖非原生命令:Get-Screen和Get-Window属于第三方PowerShell模块(如PSScriptTools),未安装时会直接报错。
  2. 全屏判断逻辑错误:使用WorkingArea(排除任务栏的屏幕区域)作为判断基准,而真正的全屏应用会覆盖整个显示器(包括任务栏),导致误判。
  3. 进程名匹配风险:通过进程名获取窗口句柄,若存在同名进程,可能获取错误的窗口信息。

修复后的解决方案

方案1:基于原生Windows API的PowerShell脚本

改用Windows原生API获取窗口和显示器信息,无需额外安装模块,判断逻辑更准确:

const { exec } = require('child_process');

function isFullscreenAppRunning() {
    return new Promise((resolve, reject) => {
        const script = `
        Add-Type @"
        using System;
        using System.Runtime.InteropServices;

        public class WindowInfo {
            [DllImport("user32.dll")]
            public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
            
            [DllImport("user32.dll")]
            public static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
            
            [DllImport("user32.dll")]
            public static extern IntPtr MonitorFromWindow(IntPtr hWnd, uint dwFlags);
            
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT {
                public int Left;
                public int Top;
                public int Right;
                public int Bottom;
            }
            
            [StructLayout(LayoutKind.Sequential)]
            public struct MONITORINFO {
                public uint cbSize;
                public RECT rcMonitor;
                public RECT rcWork;
                public uint dwFlags;
            }
            
            [DllImport("user32.dll")]
            public static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
            
            public const int GWL_STYLE = -16;
            public const uint WS_MAXIMIZE = 0x01000000;
        }
        "@

        function Test-WindowIsFullScreen {
            param([IntPtr]$hWnd)
            
            # 先判断窗口是否处于最大化状态
            $style = [WindowInfo]::GetWindowLong($hWnd, [WindowInfo]::GWL_STYLE)
            if (-not ($style -band [WindowInfo]::WS_MAXIMIZE)) {
                return $false
            }
            
            # 获取窗口所在显示器的完整区域(包括任务栏)
            $monitor = [WindowInfo]::MonitorFromWindow($hWnd, 0)
            $monitorInfo = New-Object WindowInfo+MONITORINFO
            $monitorInfo.cbSize = [System.Runtime.InteropServices.Marshal]::SizeOf($monitorInfo)
            [WindowInfo]::GetMonitorInfo($monitor, [ref]$monitorInfo)
            
            # 获取窗口的实际位置和大小
            $windowRect = New-Object WindowInfo+RECT
            [WindowInfo]::GetWindowRect($hWnd, [ref]$windowRect)
            
            # 判断窗口是否完全覆盖显示器的整个区域
            return ($windowRect.Left -eq $monitorInfo.rcMonitor.Left -and
                    $windowRect.Top -eq $monitorInfo.rcMonitor.Top -and
                    $windowRect.Right -eq $monitorInfo.rcMonitor.Right -and
                    $windowRect.Bottom -eq $monitorInfo.rcMonitor.Bottom)
        }

        $isFullscreen = $false
        # 遍历所有拥有有效窗口句柄的进程
        Get-Process | Where-Object { $_.MainWindowHandle -ne 0 } | ForEach-Object {
            if (Test-WindowIsFullScreen $_.MainWindowHandle) {
                $isFullscreen = $true
                break
            }
        }

        $isFullscreen
        `;

        exec(`powershell -command "${script}"`, (err, stdout, stderr) => {
            if (err) {
                reject(err);
                return;
            }
            resolve(stdout.trim() === 'True');
        });
    });
}

// 快捷键唤出逻辑示例
async function toggleToolWindow() {
    const hasFullscreenApp = await isFullscreenAppRunning();
    if (!hasFullscreenApp) {
        // 这里替换为你的Electron窗口显示逻辑
        console.log('唤出工具窗口');
    } else {
        console.log('检测到全屏应用,不唤出工具');
    }
}

// 注册Ctrl+Space快捷键
const { globalShortcut } = require('electron');
globalShortcut.register('Ctrl+Space', toggleToolWindow);

方案2:使用Node.js原生库(跨平台可选)

如果需要跨平台支持,可以使用windows-management(Windows)或Electron内置screen模块结合窗口检测库:

  • 安装依赖:npm install windows-management
  • 简化检测逻辑:
const { getAllWindows } = require('windows-management');
const { screen } = require('electron');

function isFullscreenAppRunning() {
    const displays = screen.getAllDisplays();
    for (const window of getAllWindows()) {
        if (window.isFullscreen) {
            return true;
        }
        // 额外判断最大化窗口是否覆盖整个显示器
        for (const display of displays) {
            if (window.x === display.bounds.x && 
                window.y === display.bounds.y && 
                window.width === display.bounds.width && 
                window.height === display.bounds.height) {
                return true;
            }
        }
    }
    return false;
}

// 快捷键逻辑同方案1

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 13:55:02