今天在抖音冲浪,突然刷到了某佬用鸡胸肉当键盘。
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 中,第一个参数是字符,第二个参数是模拟按下还是释放
在之前的串口助手中将模拟键盘功能加上。 我们测试一遍发现没有问题。 直接上幻兽帕鲁测试
