From 8223e4004911be70621ca73424bb98832dc4e779 Mon Sep 17 00:00:00 2001 From: xingluo Date: Thu, 22 Jan 2026 17:22:59 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=96=87=E4=BB=B6=E8=87=B3?= =?UTF-8?q?=20/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Keyboard_client.lua | 274 ++++++++++++++++++++++++++++++++++++++++++++ Keyboard_server.lua | 78 +++++++++++++ 2 files changed, 352 insertions(+) create mode 100644 Keyboard_client.lua create mode 100644 Keyboard_server.lua diff --git a/Keyboard_client.lua b/Keyboard_client.lua new file mode 100644 index 0000000..18be01e --- /dev/null +++ b/Keyboard_client.lua @@ -0,0 +1,274 @@ +local config = {} + +function log(text) + --print(text) +end + + +-- 保存配置文件 +local function saveConfig() + local file = fs.open(".key_config", "w") + file. write(textutils.serialize(config)) + file.close() +end + +-- 加载或创建配置文件 +local function loadOrCreateConfig() + if fs.exists(".key_config") then + local file = fs.open(".key_config", "r") + local content = file.readAll() + file.close() + config = textutils.unserialize(content) + log("Config loaded") + else + log("Creating default config...") + config = { + + events = { + "key", "key_up", + "mouse_click", "mouse_drag", "mouse_scroll", "mouse_up", + "char", "paste", + }, + + fn_key = "rightAlt", + target_channels = {["q"] = "nil", ["w"] = "nil", ["e"] = "nil", ["r"] = "nil"}, + special_keys = { + ["one"] = "f1", ["two"] = "f2", ["three"] = "f3", ["four"] = "f4", + ["five"] = "f5", ["six"] = "f6", ["seven"] = "f7", ["eight"] = "f8", + ["nine"] = "f9", ["zero"] = "f10", ["minus"] = "f11", ["equals"] = "f12", + + ["1"] = "f1", ["2"] = "f2", ["3"] = "f3", ["4"] = "f4", + ["5"] = "f5", ["6"] = "f6", ["7"] = "f7", ["8"] = "f8", + ["9"] = "f9", ["0"] = "f10", ["-"] = "f11", ["="] = "f12" + }, + target = "q", -- 默认目标频道 + + protocol = "wireless_keyboard" -- 通信协议 + } + + saveConfig() + log("Default config created") + end +end + + + +-- 初始化 rednet +local function initRednet() + peripheral.find("modem", rednet.open) +end + +-- 在表中查找值的索引 +local function findIndex(tbl, value) + for i, v in ipairs(tbl) do + if v == value then + return i + end + end + return false +end + +-- 显示状态信息 +local function updateDisplay() + term.setCursorPos(1, 1) + term.setTextColor(colors.white) + term.setBackgroundColor(colors.gray) + term.clearLine() + + local id = config.target_channels[config.target] + + term.write("Target: " .. config.target.." | ID: " .. id) + + term.setBackgroundColor(colors.lightGray) +end + + + +-- 发送事件到服务器 +local function sendEvent(eventType, ...) + log("Sending event: " .. eventType) + local args = {...} + local payload = { + type = eventType, + args = args, + timestamp = os.clock() + } + + local id = config.target_channels[config.target] + + if id ~= "nil" then + rednet.send(id, payload, config.protocol) + end +end + +-- ID输入对话框 +local function showIdInputDialog(keyName) + term.clear() + term.setCursorPos(1, 1) + term.setTextColor(colors.yellow) + print("=== ID Pairing Mode ===") + term.setTextColor(colors.white) + print("") + print("Enter target computer ID:") + print("") + + + while true do + local input = read() + local id = tonumber(input) + if not id then + term.setTextColor(colors.red) + print("Invalid ID! Please enter a numeric ID:") + term.setTextColor(colors.white) + end + + config.target_channels[keyName] = id + break + end + + term.setCursorPos(1, 1) + term.setTextColor(colors.white) + term.setBackgroundColor(colors.lightGray) + term.clear() + + updateDisplay() + saveConfig() +end + + +function key_Handle(event, ...) + arg = {...} + + -- 处理key事件 + if event == "key" then + local keyName = keys.getName(arg[1]) + + if keyName == config.fn_key then + return + end + + if fnPressed then + + if config.special_keys[keyName] then + -- 特殊键映射(Fn + 1-0-= -> F1-F12) + log(keyName.." to "..config.special_keys[keyName]) + local specialKey = config.special_keys[keyName] + arg[1] = keys[specialKey] + sendEvent("key", arg) + + elseif config.target_channels[keyName] then + if arg[2] then + -- Fn + 长按 Q/W/E/R -> 进入配对模式 + showIdInputDialog(keyName) + + else + -- Fn + 短按 Q/W/E/R -> 切换频率 + config.target = keyName + updateDisplay() + end + else + -- 其他按键与 Fn 一起按下,直接发送原始按键 + log("Sending key for key: " .. keyName) + sendEvent("key", arg) + end + + else + -- 正常按键 + sendEvent("key", arg) + end + + --处理key_up事件 + elseif event == "key_up" then + local keyName = keys.getName(arg[1]) + + if keyName == config.fn_key then + return + end + + if fnPressed then + if config.special_keys[keyName] then + log(keyName.." to "..config.special_keys[keyName]) + -- 特殊键映射(Fn + 1-0-= -> F1-F12) + local specialKey = config.special_keys[keyName] + arg[1] = keys[specialKey] + sendEvent("key_up", arg) + + + elseif config.target_channels[keyName] then + -- 忽略 Fn + Q/W/E/R 的 key_up 事件 + return + else + -- 其他按键与 Fn 一起按下,直接发送原始按键 + log("Sending key_up for key: " .. keyName) + sendEvent("key_up", arg) + end + else + sendEvent("key_up", arg) + end + + elseif event == 'char' then + local keyName = arg[1] + + if fnPressed then + if config.special_keys[keyName] then + return + elseif config.target_channels[keyName] then + -- 忽略 Fn + Q/W/E/R 的 char 事件 + return + else + -- 其他按键与 Fn 一起按下,直接发送原始按键 + log("Sending char for key: " .. keyName) + sendEvent("char", arg) + end + else + sendEvent("char", arg) + end + + -- 检查事件是否在events列表中 + elseif findIndex(config.events, event) then + sendEvent(event, arg) + end +end + + +function fn_Thread() + fnPressed = false + while true do + local event, key, is_held = os.pullEvent("key") + + if keys.getName(key) == config.fn_key then + fnPressed = true + + while true do + + local event, key = os.pullEvent("key_up") + if keys.getName(key) == config.fn_key then + fnPressed = false + + break + end + + end + end + end +end + +function key_Thread() + + while true do + + key_Handle(os.pullEvent()) + + end +end +term.clear() + +loadOrCreateConfig() + +initRednet() +updateDisplay() + +parallel.waitForAny( + fn_Thread, + key_Thread +) \ No newline at end of file diff --git a/Keyboard_server.lua b/Keyboard_server.lua new file mode 100644 index 0000000..a35d08f --- /dev/null +++ b/Keyboard_server.lua @@ -0,0 +1,78 @@ +local config = {} + +function log(text) + --print("[" .. os.date("%H:%M:%S") .. "] " .. text) +end + + +-- 保存配置文件 +local function saveConfig() + local file = fs.open(".key_config", "w") + file.write(textutils.serialize(config)) + file.close() +end + +-- 加载或创建配置文件 +local function loadOrCreateConfig() + if fs.exists(".key_config") then + local file = fs.open(".key_config", "r") + local content = file.readAll() + file.close() + config = textutils.unserialize(content) + log("Config loaded") + else + log("Creating default config...") + config = { + protocol = "wireless_keyboard", + external_program = "shell", -- 默认外部程序 + } + saveConfig() + log("Default config created") + end +end + + + +-- 初始化 rednet +local function initRednet() + peripheral.find("modem", rednet.open) +end + +-- 网络监听函数 +local function networkListener() + while true do + local senderId, message, protocol = rednet.receive() + + if protocol == config.protocol and message.type then + -- 注入事件到本机事件队列 + + os.queueEvent(message.type, table.unpack(message.args[1])) + + log("Event from ID " .. senderId .. ": " .. message.type) + end + end +end + +-- 外部程序运行函数 +local function runExternalProgram() + shell.run(config.external_program) +end + +-- 主函数 +local function main() + loadOrCreateConfig() + initRednet() + + log("=== Wireless Keyboard Server ===") + log("Protocol: " .. config.protocol) + log("External program: " .. config.external_program) + log("") + + -- 并行执行网络监听和外部程序 + parallel.waitForAny(networkListener, runExternalProgram) + + log("Server stopped") + rednet.close() +end + +main() \ No newline at end of file