input
输入查询 + keybind formatter + 剪贴板 + 硬件设备输出。
input.is_active(path) → bool
参数:path : string —— 控件 full_path(hotkey 控件)
返回该 hotkey 当前是否处于 active 状态(按 mode 不同:Toggle = 已切到 on / Hold = 正按住 / Always = 永远 true)。
input.format(path, fn)
给 keybind 控件挂动态文字 + 颜色提示,formatter 只在该 hotkey 处于 active 状态(出现在 "active keybinds" 浮窗中)时调用。
参数:
path : string—— 菜单元素 full_path 或 Pattern B hotkey ID(两种都接受)fn : function(id : string) → string | { text = string, color = {r,g,b,a} }
path 自动解析
传 menu element full_path(自然语义)即可 —— 如果该元素是 KeybindControl 且内部把 keybind 重映射到稳定 ID,会自动跟随到那个稳定 ID。
| 调用形式 | 解析过程 |
|---|---|
input.format("settings.display.menu", fn) | → 解析到 hotkey.menu_open |
input.format("hotkey.menu_open", fn) | → 直接用 |
input.format("KbHints.g.alarm", fn) | → 用户自建 KeybindControl 无重映射,用 full_path |
fn 返回类型
| 返回 | 行为 |
|---|---|
string | 用主题色显示该文本 |
table {text, color={r,g,b,a}} | 自定义文本 + 颜色 |
| 其他 | LOG_ERR + 走默认显示 |
Owner-scoped:脚本卸载时自动 unregister。
input.unformat(path)
path 解析逻辑与 input.format 相同。
input.clipboard_get() → string
读系统剪贴板。空时返空 string。
input.clipboard_set(text)
写系统剪贴板。
local key = input.clipboard_get()
if key ~= "" then gui.notify:info("已读取: " .. key) end
input.clipboard_set("hello")不提供
input.is_down(vk)—— 双机架构下 OS 按键 API 读的是程序所在机器而非游戏玩家。查玩家按键走game.localplayer.*字段(如is_zooming、is_grenade)。详见 入门指南。
formatter 示例
-- formatter #1:纯 string
input.format("KbHints.g.alarm", function(id)
return alarm_armed and "ARMED" or "OFF"
end)
-- formatter #2:返 {text, color} table
input.format("KbHints.g.stopwatch", function(id)
local sec = os.clock() - start_t
return {
text = string.format("%.1fs", sec),
color = { 0.55, 0.85, 1.0, 1.0 },
}
end)
-- formatter #3:按阈值动态变色
input.format("KbHints.g.counter", function(id)
local label = string.format("× %d", counter)
if counter == 0 then return { text = label, color = { 0.6, 0.6, 0.6, 1.0 } } end
if counter < 10 then return { text = label, color = { 0.3, 1.0, 0.3, 1.0 } } end
return { text = label, color = { 1.0, 0.45, 0.25, 1.0 } }
end)硬件设备输出
经外接输入设备(KMBOX Net / KMBOX B+ / MAKCU)向游戏机发送真实的鼠标键盘输入。
没连设备时全部 no-op 返回 false —— 不会报错,也不会走别的路径。写脚本前先用 input.device_connected() 判一下。
只有相对移动
input.move 是相对位移,没有 input.move_to(x, y)。
MAKCU 固件确实有一条 moveto(x, y)(KMBOX Net / B+ 都没有),但按官方 API 的说法它是"内部算出到达目标位置所需的 x/y 位移"再发出去 —— 底层仍是相对报文,需要一个可信的"当前光标位置"当参照。
在 FPS 里那个参照不存在:游戏走 raw input 吃 delta、把系统光标锁在窗口中心,屏幕坐标跟游戏内视角没有对应关系;加上双机架构下本程序也读不到游戏机的光标位置。所以 moveto 对瞄准没有意义,facade 没有接。
要"瞄向某个世界坐标"用 game.aimbot.set_predictor,让瞄准管线读 view_angle 反解出需要的 delta。
input.backend() → string
当前输入设备后端名。脚本据此做能力分支(各后端支持的动作不同,见下表)。
| 返回值 | 含义 |
|---|---|
"disable" | 未选择设备 |
"write_view" | 内存接管(不经硬件,本节的函数全部无效) |
"kmboxnet" | KMBOX Net(网口) |
"kmboxb+" | KMBOX B+(串口) |
"makcu" | MAKCU(串口) |
input.device_connected() → bool
设备是否已连接可用。
后端能力对照
| 动作 | kmboxnet | kmboxb+ | makcu |
|---|---|---|---|
move / click / button(左键) | ✅ | ✅ | ✅ |
button 右键 / 中键 / 侧键 | ✅ | ⚠️ | ✅ |
wheel | ✅ | ⚠️ | ✅ |
move_curve(固件侧插值) | ✅ | ↩︎ 退化成 move | ✅ |
key_down / key_up / key_press | ✅ | ✅ | ❌ |
mask 鼠标左键 | ✅ | ✅ | ✅ |
mask 其它鼠标键 / "x" / "y" | ✅ | ❌ | ✅ |
mask "wheel" | ✅ | ❌ | ❌ |
mask 键盘键 | ✅ | ❌ | ❌ |
- ⚠️ = KMBOX B+ 的这几条命令名是按已实证命令的规律外推的,未实机验证。固件不认时串口写入照样成功,所以返回
true也可能实际没动作。 - ❌ = 后端没有该能力,返回
false。别把false一律当成"设备没连" —— 先看这张表。 - MAKCU 固件没有键盘 HID 通道,键盘三件套在它上面恒
false。
input.move(dx, dy) → bool
参数:dx : int, dy : int —— 相对位移(mickey 单位,正 = 右 / 下)
input.move_curve(dx, dy, ms?) → bool
参数:dx : int, dy : int, ms : int(可选,默认 20,上限 2000)
把一次大位移交给固件分段推送,轨迹比逐帧小步 move 更接近人手。
阻塞式推送
固件侧在整个 ms 期间占住设备,排在后面的瞄准 move 全被拖住。别放进每帧循环。
input.button(name, down) → bool
参数:name : string,down : bool
name | 别名 |
|---|---|
"left" | "lmb" |
"right" | "rmb" |
"middle" | "mmb" / "wheel_click" |
"side1" | "mouse4" / "x1" |
"side2" | "mouse5" / "x2" |
input.click(name?) → bool
按下 + 松开一次。name 省略 = 左键。
input.wheel(delta) → bool
参数:delta : int —— 格数(正 = 前滚)
input.key_down(key) / input.key_up(key) / input.key_press(key) → bool
参数:key : string —— 单字符("r")或键名("shift" / "enter" / "f1" / "space" / "lctrl" / 方向键 "up" 等)
key_press = 按下 + 松开一次。
MAKCU 后端无键盘通道,这三个恒
false。
input.mask(what, enable) → bool
屏蔽玩家的物理输入,让它不再传给游戏。用于"接管某个键"的场景 —— 盒子拦掉玩家自己的按键,再由脚本决定什么时候真发出去。
参数:
what : string—— 鼠标键名(同input.button)/"x"/"y"/"wheel"/ 键盘键名enable : bool
键盘屏蔽的前提
只有物理键盘插在盒子上时键盘 mask 才真生效。键盘直连游戏机的话盒子拦不到,函数返回 true 也没有实际效果。
脚本卸载时所有 mask 自动解除,见下方「自动清理」。
自动清理
设备输出里有状态的操作按脚本 owner 记账,脚本卸载(热重载 / 切配置 / 手动卸载)时自动还原:
| 操作 | 卸载时 |
|---|---|
input.button(name, true) 按下未松 | 自动松开 |
input.key_down(key) 按下未松 | 自动松开 |
input.mask(what, true) | 自动解除 |
没有这层的话,脚本在按住左键时被卸载,按键会永久卡在盒子固件里 —— 游戏里表现为一直开火,且用户自己点鼠标也停不下来。
click / move / wheel / key_press 是瞬时操作,不需要清理。
与扳机的配合
扳机靠"本机是否在开火"判断要不要让位,而脚本经盒子点的左键同样会让它以为玩家在手动开火。input.click("left") 和 input.button("left", false) 会自动通知扳机这一发是脚本点的,不需要脚本自己处理。
脚本持按左键期间扳机会让位不扣发 —— 这是正确行为:已经在持续开火了,扳机再点没有意义。
设备输出示例
-- 能力分支:不同后端能做的事不一样
local backend = input.backend()
if not input.device_connected() then
gui.notify:warn("未连接输入设备")
return
end
-- 缓慢画一个方块(固件侧插值,比逐帧 move 自然)
for _, d in ipairs({ {200,0}, {0,200}, {-200,0}, {0,-200} }) do
input.move_curve(d[1], d[2], 150)
end
-- 侧键点射:按下 → 60ms → 松开
input.button("side1", true)
Delay(0.06, function() input.button("side1", false) end)
-- 接管 R 键:拦掉玩家的物理 R,自己决定何时真按
-- (仅 kmboxnet + 键盘插在盒子上时有效)
if backend == "kmboxnet" then
input.mask("r", true)
event.on("frame_update", function()
if should_reload_now() then
input.mask("r", false)
input.key_press("r")
input.mask("r", true)
end
end)
end