delphi 键盘按键替换工具

设计界面:

image

 功能设计:

1.按下窗体右上角的关闭按钮时,程序隐藏

2.按下ctrl+~组合键时,程序隐藏或者显示

3.程序最多支持三组按键更替,PressCom指定的按键会被替换为TargetCom按键,当某一组任意值为空是,该组不执行更替任务

4.当scGPCheckBox1勾选时,程序才执行更替任务,否则不执行

5.点击ExitBtn按钮时,程序才真正退出

6.所有的TscGPComboBox都要添加所有键盘的按键

7.这三组控件不能重复替换相同的按键

以下代码通过AI生成,功能已实测通过.

unit ButtonReplacementTool;

interface

uses
    winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
    System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
    scGPControls, scGPExtControls, scControls, System.Win.Registry;

type
    // ============================================================
    // KBDLLHOOKSTRUCT - 低级键盘钩子结构体
    // 用于接收系统级键盘事件的信息
    // ============================================================
    KBDLLHOOKSTRUCT = record
        vkCode: DWORD;          // 虚拟键码(Virtual Key Code)
        scanCode: DWORD;        // 扫描码(硬件扫描码)
        flags: DWORD;           // 标志位(扩展键、ALT键等)
        time: DWORD;            // 事件的时间戳
        dwExtraInfo: ULONG_PTR; // 附加信息
    end;

    PKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;  // 指向结构体的指针类型

    TMain = class(TForm)
        // ============================================================
        // 界面组件声明
        // ============================================================
        scGPCheckBox1: TscGPCheckBox;      // 启用/禁用按键映射的复选框
        PressCom1: TscGPComboBox;          // 第一组:被替换的按键(按下此键触发替换)
        TargetCom1: TscGPComboBox;         // 第一组:目标按键(替换为按此键)
        scGPLabel1: TscGPLabel;            // 第一组的标签
        SaveBtn: TscGPButton;              // 保存设置按钮
        ExitBtn: TscGPButton;              // 退出程序按钮
        PressCom2: TscGPComboBox;          // 第二组:被替换的按键
        TargetCom2: TscGPComboBox;         // 第二组:目标按键
        scGPLabel2: TscGPLabel;            // 第二组的标签
        PressCom3: TscGPComboBox;          // 第三组:被替换的按键
        TargetCom3: TscGPComboBox;         // 第三组:目标按键
        scGPLabel3: TscGPLabel;            // 第三组的标签

        // ============================================================
        // 事件处理方法
        // ============================================================
        procedure FormCreate(Sender: TObject);                    // 窗体创建时
        procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); // 窗体关闭询问
        procedure ExitBtnClick(Sender: TObject);                 // 退出按钮点击
        procedure SaveBtnClick(Sender: TObject);                 // 保存按钮点击
        procedure FormShow(Sender: TObject);                     // 窗体显示时
        procedure scGPCheckBox1Click(Sender: TObject);           // 复选框点击
        procedure FormDestroy(Sender: TObject);                  // 窗体销毁时

    private
        { Private declarations }
        FHotKeyId: Integer;          // 全局热键的ID
        FIsHidden: Boolean;          // 窗体是否处于隐藏状态
        FKeyboardHook: HHOOK;        // 键盘钩子句柄

        // ============================================================
        // 按键映射数组:存储三组按键映射配置
        // 每组包含:被替换的按键、目标按键、是否激活
        // ============================================================
        FKeyMapping: array[1..3] of record
            PressKey: DWORD;         // 被替换的按键(按下此键)
            TargetKey: DWORD;        // 目标按键(替换为按此键)
            Active: Boolean;         // 该组映射是否激活
        end;

        // ============================================================
        // 私有方法声明
        // ============================================================
        procedure InitializeComboBoxes;   // 初始化下拉组合框,填充所有按键选项
        procedure LoadSettings;           // 从注册表加载保存的设置
        procedure SaveSettings;           // 保存设置到注册表
        procedure UpdateKeyMapping;       // 更新按键映射配置
        procedure ApplyKeyMapping;        // 应用按键映射(安装键盘钩子)
        procedure RemoveKeyMapping;       // 移除按键映射(卸载键盘钩子)
        procedure HandleHotKey(var MSG: TMessage);  // 处理全局热键消息

    public
        { Public declarations }
        procedure WndProc(var MSG: TMessage); override;  // 重写窗口过程以接收热键消息
    end;

var
    Main: TMain;
    HookInstance: HHOOK = 0;  // 全局键盘钩子句柄(用于低级键盘钩子回调)
    IsProcessingSimulatedKey: Boolean = False;  // 防止递归的标志 (防止同一个按键即时当前按键又是目标按键)
implementation

{$R *.dfm}

uses
    winapi.ShellAPI;

// ============================================================
// KeyboardProc - 低级键盘钩子回调函数
// 当系统检测到键盘事件时,此函数被调用
// 参数:
//   nCode  - 钩子代码(HC_ACTION 表示有键盘事件)
//   wParam - 消息类型(WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, WM_SYSKEYUP)
//   lParam - 指向 KBDLLHOOKSTRUCT 结构体的指针
// 返回值:
//   0 - 允许按键事件继续传递
//   1 - 阻止按键事件(吃掉该按键)
// ============================================================
function KeyboardProc(nCode: Integer; wParam: wParam; lParam: lParam): LRESULT; stdcall;
var
    p: PKBDLLHOOKSTRUCT;
    i: Integer;
    KeyDown: Boolean;
begin
    // 先调用下一个钩子
    Result := CallNextHookEx(HookInstance, nCode, wParam, lParam);

    // ============================================================
    // 防止递归:如果正在处理模拟按键,直接退出
    // 这样可以避免 PageUp → Home → Delete 的连锁反应
    // ============================================================
    if IsProcessingSimulatedKey then
        Exit;

    if nCode = HC_ACTION then
    begin
        p := PKBDLLHOOKSTRUCT(lParam);
        if Assigned(p) then
        begin
            KeyDown := (wParam = WM_KEYDOWN) or (wParam = WM_SYSKEYDOWN);

            if KeyDown then
            begin
                for i := 1 to 3 do
                begin
                    if Main.FKeyMapping[i].Active and
                        (Main.FKeyMapping[i].PressKey = p.vkCode) then
                    begin
                        // 设置标志,防止模拟按键再次触发钩子
                        IsProcessingSimulatedKey := True;
                        try
                            // 模拟按下目标按键
                            keybd_event(Main.FKeyMapping[i].TargetKey, 0, 0, 0);
                            // 模拟释放目标按键
                            keybd_event(Main.FKeyMapping[i].TargetKey, 0, KEYEVENTF_KEYUP, 0);
                        finally
                            // 重置标志
                            IsProcessingSimulatedKey := False;
                        end;

                        // 阻止原始按键
                        Result := 1;
                        Exit;
                    end;
                end;
            end;
        end;
    end;
end;

// ============================================================
// GetKeyName - 将虚拟键码转换为可读的按键名称
// 参数:KeyCode - 虚拟键码(0-255)
// 返回:按键的字符串描述
// ============================================================
function GetKeyName(KeyCode: Integer): string;
begin
    Result := '';

    // ============================================================
    // 1. 字母键 A-Z (65-90)
    // ============================================================
    if (KeyCode >= 65) and (KeyCode <= 90) then
    begin
        Result := Chr(KeyCode);
        Exit;
    end;

    // ============================================================
    // 2. 数字键 0-9 (48-57)
    // ============================================================
    if (KeyCode >= 48) and (KeyCode <= 57) then
    begin
        Result := Chr(KeyCode);
        Exit;
    end;

    // ============================================================
    // 3. 功能键 F1-F12 (F13-F24 不常用,去掉)
    // ============================================================
    if (KeyCode >= VK_F1) and (KeyCode <= VK_F12) then
    begin
        Result := 'F' + IntToStr(KeyCode - VK_F1 + 1);
        Exit;
    end;

    // ============================================================
    // 4. 小键盘数字键 Num0-Num9
    // ============================================================
    if (KeyCode >= VK_NUMPAD0) and (KeyCode <= VK_NUMPAD9) then
    begin
        Result := 'Num' + IntToStr(KeyCode - VK_NUMPAD0);
        Exit;
    end;

    // ============================================================
    // 5. 常用特殊键(只保留最常用的)
    // ============================================================
    case KeyCode of
        // ---------- 编辑键 ----------
        VK_BACK:         Result := 'Backspace';   // 退格键
        VK_TAB:          Result := 'Tab';          // Tab键
        VK_RETURN:       Result := 'Enter';        // 回车键
        VK_ESCAPE:       Result := 'Esc';          // Escape键
        VK_SPACE:        Result := 'Space';        // 空格键
        VK_DELETE:       Result := 'Delete';       // Delete键
        VK_INSERT:       Result := 'Insert';       // Insert键

        // ---------- 光标控制键 ----------
        VK_HOME:         Result := 'Home';         // Home键
        VK_END:          Result := 'End';          // End键
        VK_PRIOR:        Result := 'PageUp';       // PageUp键
        VK_NEXT:         Result := 'PageDown';     // PageDown键
        VK_LEFT:         Result := 'Left';         // 左箭头
        VK_UP:           Result := 'Up';           // 上箭头
        VK_RIGHT:        Result := 'Right';        // 右箭头
        VK_DOWN:         Result := 'Down';         // 下箭头

        // ---------- 修饰键 ----------
        VK_SHIFT:        Result := 'Shift';        // Shift键
        VK_CONTROL:      Result := 'Ctrl';         // Ctrl键
        VK_MENU:         Result := 'Alt';          // Alt键
        VK_CAPITAL:      Result := 'CapsLock';     // CapsLock键
        VK_NUMLOCK:      Result := 'NumLock';      // NumLock键
        VK_SCROLL:       Result := 'ScrollLock';   // ScrollLock键

        // ---------- Windows键 ----------
        VK_LWIN:         Result := 'LeftWin';      // 左Windows键
        VK_RWIN:         Result := 'RightWin';     // 右Windows键
        VK_APPS:         Result := 'Apps';         // 应用程序键(右键菜单)

        // ---------- 符号键 ----------
        VK_OEM_1:        Result := '; :';          // 分号键
        VK_OEM_PLUS:     Result := '+ =';          // 加号/等号键
        VK_OEM_COMMA:    Result := ', <';          // 逗号键
        VK_OEM_MINUS:    Result := '- _';          // 减号/下划线键
        VK_OEM_PERIOD:   Result := '. >';          // 句号键
        VK_OEM_2:        Result := '/ ?';          // 斜杠键
        VK_OEM_3:        Result := '` ~';          // 反引号键
        VK_OEM_4:        Result := '[ {';          // 左方括号
        VK_OEM_5:        Result := '\ |';          // 反斜杠
        VK_OEM_6:        Result := '] }';          // 右方括号
        VK_OEM_7:        Result := ''' "';         // 单引号键

        // ---------- 截图键 ----------
        VK_SNAPSHOT:     Result := 'PrintScreen';  // 截屏键

        // ---------- 暂停/中断 ----------
        VK_PAUSE:        Result := 'Pause';        // Pause键
    else
        // 未识别的按键返回空字符串(不显示)
        Result := '';
    end;
end;
// ============================================================
// TMain.FormCreate - 窗体创建事件
// 在程序启动时执行初始化操作
// ============================================================
procedure TMain.FormCreate(Sender: TObject);
begin
    // 设置程序主窗体在任务栏显示
    Application.MainFormOnTaskBar := True;

    // 初始化窗体可见状态
    FIsHidden := False;

    // 初始化键盘钩子句柄为0(表示未安装)
    FKeyboardHook := 0;

    // ============================================================
    // 注册全局热键 Ctrl+~ (用于显示/隐藏程序主窗口)
    // GlobalAddAtom - 创建全局原子,确保热键ID唯一
    // RegisterHotKey - 注册热键
    //   参数1: 窗口句柄(接收热键消息的窗口)
    //   参数2: 热键ID
    //   参数3: 修饰键(MOD_CONTROL = Ctrl键)
    //   参数4: 虚拟键码(VK_OEM_3 = ~ 键)
    // ============================================================
    FHotKeyId := GlobalAddAtom('MyHotKey') - $C000;
    if not RegisterHotKey(Handle, FHotKeyId, MOD_CONTROL, VK_OEM_3) then
    begin
        ShowMessage('无法注册热键 Ctrl+~');
    end;

    // 初始化下拉组合框(填充所有按键选项)
    InitializeComboBoxes;

    // 从注册表加载保存的设置
    LoadSettings;

    // 更新按键映射(根据加载的设置)
    UpdateKeyMapping;
end;

// ============================================================
// TMain.FormDestroy - 窗体销毁事件
// 在程序退出时清理资源
// ============================================================
procedure TMain.FormDestroy(Sender: TObject);
begin
    // 移除键盘钩子(如果已安装)
    RemoveKeyMapping;

    // 注销全局热键(如果已注册)
    if FHotKeyId <> 0 then
        UnregisterHotKey(Handle, FHotKeyId);
end;

// ============================================================
// TMain.FormCloseQuery - 窗体关闭询问事件
// 当用户点击窗口右上角的 X 按钮时触发
// 阻止直接关闭,改为隐藏到系统托盘(实际是隐藏到任务栏)
// ============================================================
procedure TMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
    CanClose := False;   // 阻止关闭
    Hide;                // 隐藏窗体
    FIsHidden := True;   // 标记为隐藏状态
end;

// ============================================================
// TMain.ExitBtnClick - 退出按钮点击事件
// 真正退出程序,释放所有资源
// ============================================================
procedure TMain.ExitBtnClick(Sender: TObject);
begin
    // 移除键盘钩子
    RemoveKeyMapping;

    // 注销热键
    if FHotKeyId <> 0 then
        UnregisterHotKey(Handle, FHotKeyId);

    // 终止应用程序
    Application.Terminate;
end;

// ============================================================
// TMain.SaveBtnClick - 保存按钮点击事件
// 保存当前设置到注册表并应用
// ============================================================
procedure TMain.SaveBtnClick(Sender: TObject);
begin
    SaveSettings;        // 保存设置到注册表
    UpdateKeyMapping;    // 更新并应用按键映射
    ShowMessage('设置已保存并应用');
end;

// ============================================================
// TMain.FormShow - 窗体显示事件
// 当窗体从隐藏状态变为显示时触发
// ============================================================
procedure TMain.FormShow(Sender: TObject);
begin
    FIsHidden := False;  // 标记为可见状态
end;

// ============================================================
// TMain.scGPCheckBox1Click - 复选框点击事件
// 启用或禁用按键映射功能
// ============================================================
procedure TMain.scGPCheckBox1Click(Sender: TObject);
begin
    if scGPCheckBox1.Checked then
        ApplyKeyMapping    // 勾选:应用按键映射(安装钩子)
    else
        RemoveKeyMapping;  // 取消勾选:移除按键映射(卸载钩子)
end;

// ============================================================
// TMain.InitializeComboBoxes - 初始化下拉组合框
// 向所有组合框添加按键选项列表
// ============================================================
procedure TMain.InitializeComboBoxes;
var
    i: Integer;          // 循环计数器(遍历按键码)
    KeyName: string;     // 按键名称
    ComboBoxes: array[1..6] of TscGPComboBox;  // 所有组合框数组
begin
    // 将6个组合框赋值到数组中,方便统一处理
    ComboBoxes[1] := PressCom1;
    ComboBoxes[2] := TargetCom1;
    ComboBoxes[3] := PressCom2;
    ComboBoxes[4] := TargetCom2;
    ComboBoxes[5] := PressCom3;
    ComboBoxes[6] := TargetCom3;

    // ---------- 首先为所有组合框添加一个空选项(None) ----------
    for var j := 1 to 6 do
    begin
        ComboBoxes[j].Items.Clear;           // 清空原有项目
        var temp := ComboBoxes[j].Items.Add; // 添加新项目
        temp.Caption := 'None';              // 显示为 "None"
    end;

    // ---------- 遍历所有虚拟键码(0-255)添加按键选项 ----------
    for i := 0 to 255 do
    begin
        // 跳过鼠标按键(左键、右键、中键等)
        if (i >= VK_LBUTTON) and (i <= VK_RBUTTON) then
            Continue;
        // 跳过 Cancel 键
        if i = VK_CANCEL then
            Continue;

        // 获取按键的可读名称
        KeyName := GetKeyName(i);
        if KeyName='' then
             Continue;

        // 将按键添加到所有6个组合框中
        // 格式:按键名称|键码(例如 "A|65")
        // 这样既显示可读名称,又保留了键码值
        for var j := 1 to 6 do
        begin
            var temp := ComboBoxes[j].Items.Add;
            temp.Caption := KeyName + '|' + IntToStr(i);
        end;
    end;

    // ---------- 设置默认选中 "None" ----------
    for var j := 1 to 6 do
        ComboBoxes[j].ItemIndex := 0;
end;

// ============================================================
// TMain.LoadSettings - 从注册表加载设置
// 读取之前保存的按键映射配置
// ============================================================
procedure TMain.LoadSettings;
var
    Reg: TRegistry;  // 注册表对象
begin
    Reg := TRegistry.Create;
    try
        Reg.RootKey := HKEY_CURRENT_USER;  // 使用当前用户注册表根键

        // 打开注册表键 "Software\KeyMapper"
        if Reg.OpenKey('Software\KeyMapper', False) then
        begin
            // 加载三组按键的索引值
            PressCom1.ItemIndex := Reg.ReadInteger('Press1');
            TargetCom1.ItemIndex := Reg.ReadInteger('Target1');
            PressCom2.ItemIndex := Reg.ReadInteger('Press2');
            TargetCom2.ItemIndex := Reg.ReadInteger('Target2');
            PressCom3.ItemIndex := Reg.ReadInteger('Press3');
            TargetCom3.ItemIndex := Reg.ReadInteger('Target3');

            // 加载启用状态
            scGPCheckBox1.Checked := Reg.ReadBool('Enabled');
        end;
    finally
        Reg.Free;  // 释放注册表对象
    end;
end;

// ============================================================
// TMain.SaveSettings - 保存设置到注册表
// 保存当前按键映射配置以便下次启动时加载
// ============================================================
procedure TMain.SaveSettings;
var
    Reg: TRegistry;  // 注册表对象
begin
    Reg := TRegistry.Create;
    try
        Reg.RootKey := HKEY_CURRENT_USER;  // 使用当前用户注册表根键

        // 打开(或创建)注册表键 "Software\KeyMapper"
        if Reg.OpenKey('Software\KeyMapper', True) then
        begin
            // 保存三组按键的索引值
            Reg.WriteInteger('Press1', PressCom1.ItemIndex);
            Reg.WriteInteger('Target1', TargetCom1.ItemIndex);
            Reg.WriteInteger('Press2', PressCom2.ItemIndex);
            Reg.WriteInteger('Target2', TargetCom2.ItemIndex);
            Reg.WriteInteger('Press3', PressCom3.ItemIndex);
            Reg.WriteInteger('Target3', TargetCom3.ItemIndex);

            // 保存启用状态
            Reg.WriteBool('Enabled', scGPCheckBox1.Checked);
        end;
    finally
        Reg.Free;  // 释放注册表对象
    end;
end;

// ============================================================
// TMain.UpdateKeyMapping - 更新按键映射配置
// 从组合框读取用户选择的按键,更新内存中的映射数组
// 并检查是否有重复的按键映射
// ============================================================
procedure TMain.UpdateKeyMapping;

    // ----------------------------------------------------------
    // 辅助函数:从组合框中获取按键值
    // 参数:ComboBox - 组合框对象
    // 返回:选中的按键的虚拟键码(如果没有选中则返回0)
    // ----------------------------------------------------------
    function GetKeyValue(ComboBox: TscGPComboBox): DWORD;
    var
        ItemText: string;  // 项目的显示文本
        P: Integer;        // 分隔符位置
    begin
        Result := 0;  // 默认返回0(表示未选择)

        // 如果选中的不是第一个(None)项目
        if ComboBox.ItemIndex > 0 then
        begin
            ItemText := ComboBox.Items[ComboBox.ItemIndex].Caption;
            P := Pos('|', ItemText);  // 查找分隔符 "|"
            if P > 0 then
                // 提取分隔符后面的数字(键码)
                Result := StrToIntDef(Copy(ItemText, P + 1, MaxInt), 0);
        end;
    end;

begin
    // ---------- 先移除现有的按键映射(卸载钩子) ----------
    RemoveKeyMapping;

    // ---------- 从组合框读取三组按键映射 ----------
    // 第一组
    FKeyMapping[1].PressKey := GetKeyValue(PressCom1);
    FKeyMapping[1].TargetKey := GetKeyValue(TargetCom1);
    FKeyMapping[1].Active := (PressCom1.ItemIndex > 0) and (TargetCom1.ItemIndex > 0);

    // 第二组
    FKeyMapping[2].PressKey := GetKeyValue(PressCom2);
    FKeyMapping[2].TargetKey := GetKeyValue(TargetCom2);
    FKeyMapping[2].Active := (PressCom2.ItemIndex > 0) and (TargetCom2.ItemIndex > 0);

    // 第三组
    FKeyMapping[3].PressKey := GetKeyValue(PressCom3);
    FKeyMapping[3].TargetKey := GetKeyValue(TargetCom3);
    FKeyMapping[3].Active := (PressCom3.ItemIndex > 0) and (TargetCom3.ItemIndex > 0);

    // ---------- 检查是否有重复的被替换按键 ----------
    // 组1 和 组2 不能相同
    if FKeyMapping[1].Active and FKeyMapping[2].Active and
       (FKeyMapping[1].PressKey = FKeyMapping[2].PressKey) then
    begin
        ShowMessage('组1和组2的按键不能相同');
        Exit;
    end;

    // 组1 和 组3 不能相同
    if FKeyMapping[1].Active and FKeyMapping[3].Active and
       (FKeyMapping[1].PressKey = FKeyMapping[3].PressKey) then
    begin
        ShowMessage('组1和组3的按键不能相同');
        Exit;
    end;

    // 组2 和 组3 不能相同
    if FKeyMapping[2].Active and FKeyMapping[3].Active and
       (FKeyMapping[2].PressKey = FKeyMapping[3].PressKey) then
    begin
        ShowMessage('组2和组3的按键不能相同');
        Exit;
    end;

    // ---------- 如果启用状态为真,则应用按键映射 ----------
    if scGPCheckBox1.Checked then
        ApplyKeyMapping;
end;

// ============================================================
// TMain.ApplyKeyMapping - 应用按键映射
// 安装低级键盘钩子,开始拦截并替换按键
// ============================================================
procedure TMain.ApplyKeyMapping;
begin
    // 如果钩子已经存在,先移除(避免重复安装)
    if HookInstance <> 0 then
        RemoveKeyMapping;

    // ============================================================
    // 安装低级键盘钩子
    // SetWindowsHookEx 参数说明:
    //   参数1: WH_KEYBOARD_LL - 低级键盘钩子类型
    //   参数2: @KeyboardProc - 钩子回调函数地址
    //   参数3: HInstance - 当前应用程序实例句柄
    //   参数4: 0 - 全局钩子(监控所有线程)
    // ============================================================
    HookInstance := SetWindowsHookEx(WH_KEYBOARD_LL, @KeyboardProc, HInstance, 0);

    // 检查钩子是否安装成功
    if HookInstance = 0 then
        ShowMessage('安装键盘钩子失败!错误代码:' + IntToStr(GetLastError))
    else
        FKeyboardHook := HookInstance;  // 保存钩子句柄
end;

// ============================================================
// TMain.RemoveKeyMapping - 移除按键映射
// 卸载键盘钩子,停止拦截按键
// ============================================================
procedure TMain.RemoveKeyMapping;
begin
    // 如果钩子已安装(句柄不为0)
    if HookInstance <> 0 then
    begin
        UnhookWindowsHookEx(HookInstance);  // 卸载钩子
        HookInstance := 0;                  // 重置句柄
        FKeyboardHook := 0;                // 重置保存的句柄
    end;
end;

// ============================================================
// TMain.WndProc - 重写的窗口过程
// 用于接收和处理 Windows 消息
// 特别用于接收全局热键消息(WM_HOTKEY)
// ============================================================
procedure TMain.WndProc(var Msg: TMessage);
begin
    // 如果收到热键消息,交给 HandleHotKey 处理
    if Msg.Msg = WM_HOTKEY then
        HandleHotKey(Msg);

    // 调用父类的窗口过程,确保其他消息正常处理
    inherited WndProc(Msg);
end;

// ============================================================
// TMain.HandleHotKey - 处理全局热键消息
// 当用户按下 Ctrl+~ 时,切换窗体的显示/隐藏状态
// ============================================================
procedure TMain.HandleHotKey(var Msg: TMessage);
begin
    // 检查热键ID是否匹配
    if Msg.WParam = FHotKeyId then
    begin
        if FIsHidden then
        begin
            // 如果窗体当前隐藏,则显示并置前
            Show;                    // 显示窗体
            Application.BringToFront; // 将窗体置于最前
            FIsHidden := False;      // 更新状态为可见
        end
        else
        begin
            // 如果窗体当前可见,则隐藏
            Hide;                    // 隐藏窗体
            FIsHidden := True;       // 更新状态为隐藏
        end;
    end;
end;

end.

 

posted @ 2026-06-25 03:17  一曲轻扬  阅读(4)  评论(0)    收藏  举报