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

基于WPF开发网吧类应用:实现自定义登录并限制系统导航快捷键

实现自定义锁定界面并拦截系统导航快捷键(WPF/WinForms)

核心思路

要替代系统LockWorkStation的锁定效果,需要完成三个核心任务:

  • 显示全屏置顶的自定义登录窗口,覆盖整个屏幕
  • 全局拦截Alt+Tab、Win+D等系统导航快捷键
  • 在超时或指定事件触发时激活锁定逻辑,验证通过后解除限制

1. 自定义全屏登录窗口(WPF示例)

创建无边框、全屏、置顶的窗口,禁用关闭按钮,避免用户通过任务管理器强制关闭:

XAML代码

<Window x:Class="CyberCafeLock.LoginWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStyle="None"
        WindowState="Maximized"
        Topmost="True"
        ShowInTaskbar="False"
        Closing="LoginWindow_Closing">
    <Grid Background="#1a1a1a">
        <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Width="300">
            <TextBox x:Name="txtUser" PlaceholderText="请输入用户名" Margin="0 0 0 15" Padding="10"/>
            <PasswordBox x:Name="txtPwd" PlaceholderText="请输入密码" Margin="0 0 0 15" Padding="10"/>
            <Button Content="登录" Click="Login_Click" Padding="10 5" HorizontalAlignment="Center"/>
        </StackPanel>
    </Grid>
</Window>

后台逻辑

private bool _isAuthenticated = false;

private void LoginWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
    // 未验证通过时禁止关闭窗口
    if (!_isAuthenticated) e.Cancel = true;
}

private void Login_Click(object sender, RoutedEventArgs e)
{
    // 替换为你的验证逻辑
    if (txtUser.Text == "admin" && txtPwd.Password == "cyber123")
    {
        _isAuthenticated = true;
        GlobalKeyHook.UnregisterHook();
        this.Close();
    }
}

2. 全局键盘钩子拦截系统快捷键

通过user32.dll设置全局低级键盘钩子,拦截指定按键组合:

using System;
using System.Runtime.InteropServices;
using System.Windows.Input;

public static class GlobalKeyHook
{
    private const int WH_KEYBOARD_LL = 13;
    private const int WM_KEYDOWN = 0x0100;
    private const int WM_SYSKEYDOWN = 0x0104;

    private static LowLevelKeyboardProc _hookProc = HookCallback;
    private static IntPtr _hookId = IntPtr.Zero;

    public static void RegisterHook()
    {
        _hookId = SetHook(_hookProc);
    }

    public static void UnregisterHook()
    {
        UnhookWindowsHookEx(_hookId);
    }

    private static IntPtr SetHook(LowLevelKeyboardProc proc)
    {
        using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
        using (var curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

    private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
        {
            int vkCode = Marshal.ReadInt32(lParam);
            var key = KeyInterop.KeyFromVirtualKey(vkCode);

            // 拦截目标快捷键
            bool isAltPressed = Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt);
            bool isWinPressed = Keyboard.IsKeyDown(Key.LWin) || Keyboard.IsKeyDown(Key.RWin);

            if ((isAltPressed && key == Key.Tab) || 
                (isWinPressed && key == Key.D) || 
                key == Key.LWin || key == Key.RWin)
            {
                // 返回1表示拦截该按键消息
                return (IntPtr)1;
            }
        }
        return CallNextHookEx(_hookId, nCode, wParam, lParam);
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);
}

3. 触发锁定逻辑(示例:超时锁定)

在主程序中设置定时器,监听用户操作,超时后激活锁定:

private System.Timers.Timer _lockTimer;

public MainWindow()
{
    InitializeComponent();
    // 设置30分钟超时
    _lockTimer = new System.Timers.Timer(30 * 60 * 1000);
    _lockTimer.Elapsed += OnLockTimeout;
    _lockTimer.Start();
}

private void OnLockTimeout(object sender, System.Timers.ElapsedEventArgs e)
{
    Dispatcher.Invoke(() =>
    {
        GlobalKeyHook.RegisterHook();
        var loginWin = new LoginWindow();
        loginWin.ShowDialog();
        // 验证通过后重置定时器
        _lockTimer.Reset();
    });
}

// 监听鼠标/键盘操作,重置超时定时器
protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);
    _lockTimer.Reset();
}

protected override void OnKeyDown(KeyEventArgs e)
{
    base.OnKeyDown(e);
    _lockTimer.Reset();
}

注意事项

  • WinForms实现逻辑类似:设置FormBorderStyle.None、WindowState.Maximized、TopMost=true即可
  • Ctrl+Alt+Del属于系统级快捷键,常规钩子无法拦截,可通过提示用户避免使用,或通过组策略临时禁用(不推荐,会影响系统功能)
  • 程序需要管理员权限运行,否则全局钩子可能无法正常工作
  • 测试时可添加隐藏紧急退出逻辑(比如特定按键组合),避免被锁在系统外

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:50:13