跳到主要内容

全局快捷键 Shortcut

快捷键是效率的牙齿。HiEasyX 的全局快捷键系统不跟控件抢饭碗——它只在所有控件都处理完消息之后本帧结束前执行,因此 Ctrl+C 在文本框里是复制,在蓝图里也是复制,互不冲突。

核心设计

快捷键系统遵循后处理原则:

  1. 控件先消费消息(如 TextInput 吃掉 Ctrl+A 做全选)。
  2. HX::End() 内部检查剩余未处理的 KeyPressed 消息。
  3. 如果按键组合匹配已注册的快捷键,触发回调。

这意味着:只要某个控件把消息标记为 Processed,快捷键就不会误触发。


数据结构

HXShortcut

struct HXShortcut {
bool Ctrl = false; // 是否需要按住 Ctrl
bool Shift = false; // 是否需要按住 Shift
bool Alt = false; // 是否需要按住 Alt
int Key = 0; // 虚拟键码,如 'S', VK_F5, VK_DELETE
};
虚拟键码
  • 字母数字直接用字符字面量:'S', '1'
  • 功能键用 Windows 虚拟键码:VK_F5, VK_DELETE, VK_RETURN, VK_ESCAPE`。
  • 方向键:VK_LEFT, VK_RIGHT, VK_UP, VK_DOWN

API 详解

RegisterShortcut

void RegisterShortcut(const HXShortcut &shortcut, std::function<void()> callback);

参数

参数类型说明
shortcutHXShortcut按键组合。
callbackstd::function<void()>触发时执行的回调。
注册时机

建议在程序初始化时一次性注册,不要在每帧的 Window 里重复注册(虽然内部会去重,但没必要浪费 CPU)。

UnregisterShortcut

void UnregisterShortcut(int key, bool ctrl, bool shift, bool alt);

参数

参数类型说明
keyint虚拟键码。
ctrlbool是否匹配 Ctrl。
shiftbool是否匹配 Shift。
altbool是否匹配 Alt。
精确匹配

注销时必须提供完全一致的修饰键组合。只传 key 而忽略修饰符是注销不掉的。


完整示例:编辑器快捷键

#include <include/hex.h>
#include <include/impl/EasyX/hex_impl_easyx.h>

void SetupShortcuts() {
// Ctrl+S:保存
HX::RegisterShortcut({true, false, false, 'S'}, []() {
SaveProject();
});

// Ctrl+Shift+S:另存为
HX::RegisterShortcut({true, true, false, 'S'}, []() {
SaveProjectAs();
});

// Ctrl+Z:撤销
HX::RegisterShortcut({true, false, false, 'Z'}, []() {
Undo();
});

// Ctrl+Y / Ctrl+Shift+Z:重做
HX::RegisterShortcut({true, false, false, 'Y'}, []() {
Redo();
});
HX::RegisterShortcut({true, true, false, 'Z'}, []() {
Redo();
});

// Delete:删除选中对象(蓝图/树/表通用)
HX::RegisterShortcut({false, false, false, VK_DELETE}, []() {
DeleteSelection();
});

// F5:运行
HX::RegisterShortcut({false, false, false, VK_F5}, []() {
PlayGame();
});
}

int main() {
initgraph(1280, 720);

HX::HXInitForEasyX();
HX::SetBuffer(GetWorkingImage());

BeginBatchDraw();
SetupShortcuts();

while (true) {
HX::HXBegin();
ExMessage msg;
while (peekmessage(&msg)) {
HX::PushMessage(HX::GetHXMessage(&msg));
}

HX::WindowProfile wp;
wp.Title = HXStr("My Editor");
HX::Window(HXStr("main"), wp);

HX::Text(HXStr("Press Ctrl+S to save, F5 to play."));
// ... 其他控件 ...

HX::End();
HX::Render();
FlushBatchDraw();
Sleep(16);
}

return 0;
}

与控件焦点的关系

为什么不冲突?

TextInput 在收到 Ctrl+A 时会把它标记为 ProcessedHX::End() 里的快捷键匹配只扫未处理KeyPressed 消息,所以文本框里的 Ctrl+A 不会触发全局“全选”动作。

但如果你注册了一个文本框不会消费的组合,比如 Ctrl+Shift+P(打开命令面板),即使在 TextInput 里也能触发。

不要滥用全局快捷键

如果某个操作必须在特定控件激活时才有效(如 Ctrl+B 加粗只有选中文字时才该出现),请把它做成控件的内部逻辑,而不是全局快捷键。全局快捷键适合与当前焦点无关的操作:保存、运行、切换面板、撤销/重做、删除选中项。


总结

需求做法
注册全局快捷键RegisterShortcut({ctrl, shift, alt, key}, callback)
注销UnregisterShortcut(key, ctrl, shift, alt)
避免与 TextInput 冲突框架自动处理,只匹配未 Processed 的消息
支持组合键同时注册 Ctrl+ZCtrl+Shift+Z 即可
功能键使用 VK_F1 ~ VK_F12VK_DELETE

快捷键注册一次,受益整个生命周期。把最常用的命令绑上去,你的用户会感谢你的 ⚡