实现一个BLE HID鼠标

ops/2024/11/17 8:24:16/
  • 这个程序将 ESP32 或类似设备变成了一个简单的蓝牙鼠标,通过 4 个 GPIO 引脚来控制鼠标的上下左右移动。
  • 连接到蓝牙后,按下相应的按键会发送 HID 鼠标移动事件。
  • 包含了一个简单的测试函数,用于验证鼠标的移动和点击功能。
# MicroPython Human Interface Device library
# Copyright (C) 2021 H. Groefsema
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
import time
from machine import SoftSPI, Pin
from hid_services import Mouseclass Device:def __init__(self):# 定义初始坐标self.x = 0 # 用于存储鼠标的 X 轴和 Y 轴移动量。self.y = 0self.prev_x = 0self.prev_y = 0# 定义按键引脚(GPIO)# 对应于鼠标的上、下、右、左移动,分别连接到 GPIO 引脚 5、23、19 和 18self.pin_forward = Pin(5, Pin.IN)self.pin_reverse = Pin(23, Pin.IN)self.pin_right = Pin(19, Pin.IN)self.pin_left = Pin(18, Pin.IN)# 创建鼠标设备实例self.mouse = Mouse("Mouse")# 设置状态变化回调函数 mouse_state_callbackself.mouse.set_state_change_callback(self.mouse_state_callback)# 启动鼠标设备self.mouse.start()# Function that catches device status events# 鼠标状态回调函数,用于处理鼠标设备状态变化。可能会根据设备状态执行不同的操作。def mouse_state_callback(self):if self.mouse.get_state() is Mouse.DEVICE_IDLE: # 设备处于空闲状态returnelif self.mouse.get_state() is Mouse.DEVICE_ADVERTISING: # 设备正在广播蓝牙信号,等待连接return elif self.mouse.get_state() is Mouse.DEVICE_CONNECTED: # 设备已连接returnelse:returndef advertise(self): #启动蓝牙广播,使设备可以被发现和连接self.mouse.start_advertising()def stop_advertise(self): #停止蓝牙广播self.mouse.stop_advertising()# Main loopdef start(self):while True:# 根据按键状态计算 x 和 y 的变化量# 右键按下 (pin_right.value() == 1) 时,x = 127,表示向右移动最大速度self.x = self.pin_right.value() * 127 - self.pin_left.value() * 127self.y = self.pin_forward.value() * 127 - self.pin_reverse.value() * 127# 如果检测到坐标发生变化且鼠标设备已连接,则发送 HID 报告,通知移动更新。# 检查是否发生变化if (self.x != self.prev_x) or (self.y != self.prev_y):# 更新上一次的坐标值self.prev_x = self.xself.prev_y = self.y# 如果鼠标已连接,更新坐标并通知# If idle start advertising for 30s or until connectedif self.mouse.get_state() is Mouse.DEVICE_CONNECTED:self.mouse.set_axes(self.x, self.y)self.mouse.notify_hid_report()# 如果设备处于空闲状态,则开始广播elif self.mouse.get_state() is Mouse.DEVICE_IDLE:self.mouse.start_advertising()i = 10while i > 0 and self.mouse.get_state() is Mouse.DEVICE_ADVERTISING:time.sleep(3)i -= 1if self.mouse.get_state() is Mouse.DEVICE_ADVERTISING:self.mouse.stop_advertising()# 如果鼠标已连接,休眠 20ms 后退出循环,进行测试if self.mouse.get_state() is Mouse.DEVICE_CONNECTED:time.sleep_ms(20)breakelse:time.sleep(2)self.test()# 停止设备def stop(self):self.mouse.stop()# Test routinedef test(self):self.mouse.set_battery_level(50)self.mouse.notify_battery_level()for i in range(30):self.mouse.set_axes(100,100) # 向右上移动 (100, 100) 并按下左键self.mouse.set_buttons(1)self.mouse.notify_hid_report()time.sleep_ms(500)self.mouse.set_axes(100,-100) # 向右下移动 (100, -100) 释放按键self.mouse.set_buttons()self.mouse.notify_hid_report()time.sleep_ms(500)self.mouse.set_axes(-100,-100) # 向左下移动 (-100, -100) 并按下右键self.mouse.set_buttons(b2=1)self.mouse.notify_hid_report()time.sleep_ms(500)self.mouse.set_axes(-100,100) # 向左上移动 (-100, 100) 释放按键self.mouse.set_buttons()self.mouse.notify_hid_report()time.sleep_ms(500)self.mouse.set_axes(0,0) # 最后将鼠标位置重置为 (0, 0),并模拟将电池电量更新为 100%self.mouse.set_buttons()self.mouse.notify_hid_report()self.mouse.set_battery_level(100) # 设置电池电量(模拟电池状态self.mouse.notify_battery_level()if __name__ == "__main__":# 创建 Device 实例并启动主循环,等待蓝牙连接和处理按键输入。d = Device()d.start()

你可以通过修改 pin_forwardpin_reversepin_rightpin_left 引脚编号,来匹配你的硬件设置,并根据需要调整鼠标移动的速度(例如更改 127 的值)。


http://www.ppmy.cn/ops/134373.html

相关文章

【数据结构】10.线索二叉树

一、线索二叉树的产生 采用先序、中序、后序三种方法遍历二叉树后都可以得到一个线性序列&#xff0c;序列上的每一个结点&#xff08;除了第一个和最后一个&#xff09;都有一个前驱和一个后继&#xff0c;但是&#xff0c;这个线性序列只是逻辑的概念&#xff0c;不是物理结…

MySQL的编程语言

一、MySQL基础 使用系统的全局变量@@VERSION查看当前使用的MySQL的版本信息,SQL语句如下: select @@version; 将局部变量varl声明为char的类型,长度值为10,并为其赋值为“程菲” begin declare var1 char(10); set @var1="程菲"; end 通过局部变量查看d_eams数…

Flink_DataStreamAPI_源算子Source

Flink_DataStreamAPI_源算子Source 1从集合中读取数据2从文件读取数据3从Socket读取数据4从Kafka读取数据5从数据生成器读取数据Flink支持的数据类型1&#xff09;Flink的类型系统2&#xff09;Flink支持的数据类型3&#xff09;类型提示&#xff08;Type Hints&#xff09; 1从…

springboot整合security5.7.16实现用户登录及超时自动登录

1、问题概述? 提供源码下载,springSecurity关键技术,仔细阅读。 解决如下问题: 1、使用springboot2.7.16整合springSecurity5.7.16实现用户登录 2、解决新版本的Security的配置文件-提供完整配置。 3、当用户登录信息失效后,在界面发送的ajax,如何重定向到login.htm…

Android Framework与JNI

本文以 android-12.0.0_r34 的代码进行分析。 framework中的JNI 通常来说&#xff0c;Android framework 中使用到的 native 函数都是动态注册的&#xff0c;而且注册过程有固定的套路。我们以Parcel类为例来解析套路。 首先&#xff0c;我们在Parcel.java中会看到很多标记为…

Java-02 深入浅出 MyBatis - MyBatis 快速入门(无 Spring) POM Mapper 核心文件 增删改查

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

freemarker 读取template.xml ,通过response 输出文件,解决中文乱码问题

采用 try (Writer writer new OutputStreamWriter(os, “UTF-8”)) UTF-8 内容转换 public static void setResponseHeader(HttpServletResponse response, String fileName) {try {// fileName "中文.xls";try {fileName new String(fileName.getBytes(),"…

PostgreSQL中的COPY命令:高效数据导入与导出

在PostgreSQL数据库中&#xff0c;数据导入和导出是日常工作中常见的操作。传统的插入&#xff08;INSERT&#xff09;方法虽然可以实现数据的导入&#xff0c;但在处理大量数据时效率较低。而COPY命令则提供了一个快速、高效的方式来完成这一任务。COPY命令不仅可以用于将数据…