这次来完成一个好玩的项目,实现一个完整的跨设备输入监控系统,将 PC 物理键盘的按键实时同步到 Arduino UNO Q 的 12×8 LED 矩阵显示。
层级位置技术功能
| 输入捕获层 | PC 电脑 | pynput 库 | 监听全局键盘事件 |
| 传输层 | 局域网 | Socket.IO (WebSocket) | 实时双向通信 |
| 执行层 | UNO Q | Arduino Bridge RPC | 接收按键,驱动 LED 矩阵 |
PC → MPU 协议:
# PC 发送的 JSON 数据包
{
"key": "A", # 显示文本(字符串)
"type": 1 # 类型编码(整数)
}类型编码定义:
类型码含义示例LED 颜色
| 1 | 字母数字 | A-Z, 0-9 | 黄色 (#f0883e) |
| 2 | 功能键 | ↑↓←→, Esc, Enter, Tab, Del, BS, Space | 绿色 (#3fb950) |
| 3 | 控制键 | Ctrl, Alt, Shift, Caps | 青色 (#58a6ff) |
| 0 | 清除 | CLEAR | 灰色 (#484f58) |
MPU → PC 反馈协议:
# MPU 推送的 LED 状态反馈
{
"text": "A", # 显示字符
"color": "yellow", # 颜色名称
"colorClass": "", # CSS 类名
"type": 1, # 类型码
"sendCount": 5, # 累计发送次数
"warning": "" # 警告信息(如 "duplicate")
}PC 端(keyboard_capture.py)
核心模块:
# 1. 键盘监听模块
from pynput import keyboard as kb
listener = kb.Listener(on_press=on_press, on_release=on_release)
# 2. 网络通信模块
import socketio
sio = socketio.Client()
sio.connect("ws://192.168.10.187:7000")
# 3. 事件处理
def on_press(key):
key_info = get_key_info(key) # 获取按键映射
sio.emit('key_press', {'key': display_text, 'type': key_type})
def on_display(data):
# 接收 MPU 反馈,显示 LED 状态
text = data.get('text', '')
color = data.get('color', '')关键功能:
全局键盘监听(需要管理员权限,POWERSHELL使用管理员权限打开)
防重复发送(同一按键连续按下不重复发送)
实时统计(发送次数、最常按键)
错误处理(连接断开自动重连)

MPU 端(main.py)
核心流程:
# 1. 初始化 WebUI
ui = WebUI() # 自动服务 /app/assets/index.html
# 2. 注册 Socket.IO 事件处理
ui.on_message("key_press", on_key_press)
ui.on_connect(lambda sid: print(...))
ui.on_disconnect(lambda sid: print(...))
# 3. 按键处理
def on_key_press(sid, message):
# 解析消息 → 发送到 MCU → 推送状态到客户端
result = Bridge.call("key_event", key_type, key_text)
ui.send_message("display", {...}, room=sid)WebUI 自动启动:
端口:7000
静态文件:index.html
WebSocket 支持:Socket.IO 4.x

MCU 端(sketch/sketch.ino)
硬件驱动:
#include "ArduinoGraphics.h"
#include "Arduino_LED_Matrix.h"
Arduino_LED_Matrix matrix;
// 初始化
void setup() {
matrix.begin();
Bridge.begin();
Bridge.provide_safe("key_event", key_event);
}
// 按键事件处理
void key_event(int code, String key) {
display_text(key, code);
}
// LED 显示
void display_text(String text, int type) {
matrix.beginDraw();
matrix.clear();
// 根据类型选择颜色
switch (type) {
case KEY_ALPHA: color = 0xFFFF00; break; // 黄色
case KEY_SPECIAL: color = 0x00FF00; break; // 绿色
default: color = 0x000000; break; // 灰/黑
}
matrix.textFont(Font_5x7);
matrix.beginText(0, 1, color);
matrix.print(text);
matrix.endText();
matrix.endDraw();
}完整数据流
物理键盘按下
│
▼
pynput.on_press() 回调
│
▼
get_key_info(key) → (type, display_text)
│
▼
防重复检查 (last_sent_key)
│
▼
sio.emit('key_press', {'key': display_text, 'type': key_type})
│
▼ WebSocket 传输
│
▼
MPU.on_key_press(sid, message)
│
▼
Bridge.call("key_event", key_type, key_text)
│
▼ USB/UART 通信
│
▼
MCU.key_event(int code, String key)
│
▼
display_text(String text, int type)
│
▼
LED 矩阵绘制 (颜色根据类型选择)
│
▼
同步推送
│
▼
ui.send_message("display", {...}, room=sid)
│
▼ WebSocket 传输
│
▼
sio.on('display', on_display) ← 更新 PC 端显示状态最终效果
1、HTML上点击相应按钮,可以在LED矩阵显示对应字母

2,物理键盘按下按键,可在LED矩阵上显示对应的字母

完整项目:
我要赚赏金
