今天在抖音冲浪,突然刷到了某佬用鸡胸肉当键盘。
OK,这东西熟悉呀,好酷。 我在家疯狂寻找。
OK,鸡胸肉和开发板都有。我直接开做。 ** 本文源码会上传于交流群: 656210280 **
感兴趣的小伙伴可以加群一起探讨🤪🤪
原理阐述 由于人体在接触ESP32的IO时会导致电容值发生变化,ESP32总共有 十个可以直接读取电容的IO
,我们可以利用电容量变化来判断我们是否按下。
在Arduino IDE中利用以下函数读取触摸传感器
for(;;) { Serial.print("A:"); Serial.println(touchRead(4)); delay(10); }
用上述代码,我们进行测试。
可以发现,在空置的时候,触摸传感器的值在80作用,当我们触摸IO(我拉了根杜邦线)的时候,电容的值会降到10+。变化非常明显。
知道这个原理,我们加点判断逻辑,即可实现触摸的检测。 接下来写一个上位机程序
using System.Management; using System.Runtime.InteropServices; [DllImport("user32.dll", SetLastError = true)] static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
struct INPUT { public int type; public InputUnion u; }
[StructLayout(LayoutKind.Explicit)] struct InputUnion { [FieldOffset(0)] public MOUSEINPUT mi; [FieldOffset(0)] public KEYBDINPUT ki; [FieldOffset(0)] public HARDWAREINPUT hi; }
struct MOUSEINPUT { public int dx; public int dy; public uint mouseData; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; }
struct KEYBDINPUT { public ushort wVk; public ushort wScan; public uint dwFlags; public uint time; public IntPtr dwExtraInfo; }
struct HARDWAREINPUT { public uint uMsg; public ushort wParamL; public ushort wParamH; }
const int INPUT_KEYBOARD = 1; const uint KEYEVENTF_KEYUP = 0x0002;
public static void SendKey(ushort key, bool keyUp) { INPUT[] inputs = new INPUT[] { new INPUT { type = INPUT_KEYBOARD, u = new InputUnion { ki = new KEYBDINPUT { wVk = key, wScan = 0, dwFlags = keyUp ? KEYEVENTF_KEYUP : 0, time = 0, dwExtraInfo = IntPtr.Zero } } } };
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))); } char boolc; private void SendKeysToApplication(string input) { foreach (char c in input) { if(c!='T') { SendKey(c, true); boolc = c; } else { SendKey(boolc, false); } } }
我们调用系统API将我们接收到的文本转化为键盘硬件输出(有些游戏会把模拟键盘视作外挂(英雄联盟我试了不行))并且在串口接收的部分调用这个函数。
System.Management 用于管理和操作Windows管理信息。 System.Runtime.InteropServices
用于在托管代码和非托管代码之间进行工作,特别是用于调用Windows API。
[DllImport("user32.dll", SetLastError = true)]static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
这是 SendInput 函数的声明,它来自user32.dll(一个Windows系统库),用于插入键盘或鼠标输入事件到Windows的消息队列。
SetLastError = true 表示如果函数调用失败,可以使用 Marshal.GetLastWin32Error() 来获取错误代码。 **
结构体定义 ** 代码中定义了几个结构体,它们对应于 SendInput 函数所需的参数。
struct INPUT{ public int type; public InputUnion u;}
type 表示输入类型,例如键盘输入(INPUT_KEYBOARD)。 u 是一个联合体,可以表示鼠标、键盘或硬件输入。
[StructLayout(LayoutKind.Explicit)]struct InputUnion{ [FieldOffset(0)] public MOUSEINPUT mi; [FieldOffset(0)] public KEYBDINPUT ki; [FieldOffset(0)] public HARDWAREINPUT hi;}
一个具有显式布局的结构体,其成员共享相同的内存位置(所有成员的 FieldOffset 都是0)。这意味着 mi、ki 和 hi
实际上是互相重叠的,这个结构体在任何时候只能表示其中一种输入。MOUSEINPUT, KEYBDINPUT, HARDWAREINPUT
结构体这些结构体包含了模拟鼠标、键盘和硬件输入所需 的具体信息。
- 最后 SendKey 中,第一个参数是字符,第二个参数是模拟按下还是释放
在之前的串口助手中将模拟键盘功能加上。 我们测试一遍发现没有问题。 直接上幻兽帕鲁测试