Python+Arduino模拟鼠标左键异常:按住触发自动连点而非持续按住
问题描述
需要实现鼠标左键持续按压功能:按住摇杆按钮时保持左键按下状态,但当前程序按住按钮时每秒触发约35次点击,而非持续按住。
Python通过串口读取Arduino发送的三个数值,其中Z代表左键按下/释放状态,先后使用pyautogui.click()和mouseDown/mouseUp逻辑均未解决问题。
Python代码
import serial import pydirectinput import time import pyautogui try: arduino = serial.Serial('COM4', 115200, timeout=.1) except serial.SerialException as e: print(f"Error opening serial port: {e}") exit() pydirectinput.PAUSE=0 pyautogui.PAUSE=0 pyautogui.FAILSAFE=False keys_down = {} # list of currently pressed keys def key_down(key): keys_down[key] = True pydirectinput.keyDown(key) def key_up(key): if key in keys_down: del keys_down[key] pydirectinput.keyUp(key) def handle_joystick_as_arrow_keys(x, y, z): if x == 0: pyautogui.moveRel(0, -10)#drag 10 pixels up elif x == 2: pyautogui.moveRel(0, 10)#drag 10 pixels down if y == 2: pyautogui.moveRel(-10, 0) elif y == 0: pyautogui.moveRel(10, 0) if z == 1: pyautogui.mouseDown(button='left') else: pyautogui.mouseUp(button='left') try: while True: raw_data = arduino.readline() data = str(raw_data.decode('utf-8')) if data.startswith("S"): x_direction = int(data[1]) y_direction = int(data[3]) joystick_button = int(data[5]) handle_joystick_as_arrow_keys(x_direction, y_direction, joystick_button) except KeyboardInterrupt: print("Script terminated by user.") finally: arduino.close()
Arduino代码
const int JoyStick_pin = 8; //plug Joystick 'Button' into pin 8 const int X_pin = A0; //plug joystick X direction into pin A0 const int Y_pin = A1; //plug joystick Y direction into pin A1 int xc; int yc; int JSButton; int prevButtonState = HIGH; // void setup() { pinMode(JoyStick_pin, INPUT_PULLUP); Serial.begin(115200); } void loop() { int x = analogRead(X_pin) - 517; //read x direction value and -517 to bring back to around 0 int y = analogRead(Y_pin) - 512; //read y direction value and -512 to bring back to around 0 if (x < -10) { //joystick has off set of +/-8 so this negates that xc = 0; //turn analogue value into integer. 0, 1 or 2 depending on state } else if (x > 10) { xc = 2; } else { xc = 1; } if (y < -10) { yc = 0; } else if (y > 10) { yc = 2; } else { yc = 1; } int buttonStates = 0; //set starting value of Joystick button buttonStates |= ((digitalRead(JoyStick_pin) == LOW) ? 1 : 0) << 0; Serial.print("S"); //start printing the data, format is Sxc,yc,buttonStates > S1,1,0 Serial.print(xc); Serial.print(","); Serial.print(yc); Serial.print(","); Serial.println((buttonStates)); delay(40); }
解决方案
问题核心是Arduino持续发送相同的按钮按下状态,Python每次收到都会重复调用pyautogui.mouseDown(),导致系统误判为多次点击。只需在Python中维护左键状态,仅当状态变化时执行操作即可解决。
修改Python代码
添加状态变量并更新处理函数:
import serial import pydirectinput import time import pyautogui try: arduino = serial.Serial('COM4', 115200, timeout=.1) except serial.SerialException as e: print(f"Error opening serial port: {e}") exit() pydirectinput.PAUSE=0 pyautogui.PAUSE=0 pyautogui.FAILSAFE=False keys_down = {} # list of currently pressed keys left_mouse_down = False # 记录当前左键状态 def key_down(key): keys_down[key] = True pydirectinput.keyDown(key) def key_up(key): if key in keys_down: del keys_down[key] pydirectinput.keyUp(key) def handle_joystick_as_arrow_keys(x, y, z): global left_mouse_down if x == 0: pyautogui.moveRel(0, -10)#drag 10 pixels up elif x == 2: pyautogui.moveRel(0, 10)#drag 10 pixels down if y == 2: pyautogui.moveRel(-10, 0) elif y == 0: pyautogui.moveRel(10, 0) # 仅当状态变化时执行按压/释放 if z == 1 and not left_mouse_down: pyautogui.mouseDown(button='left') left_mouse_down = True elif z == 0 and left_mouse_down: pyautogui.mouseUp(button='left') left_mouse_down = False try: while True: raw_data = arduino.readline() data = str(raw_data.decode('utf-8')) if data.startswith("S"): x_direction = int(data[1]) y_direction = int(data[3]) joystick_button = int(data[5]) handle_joystick_as_arrow_keys(x_direction, y_direction, joystick_button) except KeyboardInterrupt: print("Script terminated by user.") finally: arduino.close()
可选优化:减少Arduino串口发送量
让Arduino仅在状态变化时发送数据,降低串口负载:
const int JoyStick_pin = 8; //plug Joystick 'Button' into pin 8 const int X_pin = A0; //plug joystick X direction into pin A0 const int Y_pin = A1; //plug joystick Y direction into pin A1 int xc; int yc; int prevXc = -1; int prevYc = -1; int prevButtonState = HIGH; void setup() { pinMode(JoyStick_pin, INPUT_PULLUP); Serial.begin(115200); } void loop() { int x = analogRead(X_pin) - 517; //read x direction value and -517 to bring back to around 0 int y = analogRead(Y_pin) - 512; //read y direction value and -512 to bring back to around 0 if (x < -10) { //joystick has off set of +/-8 so this negates that xc = 0; //turn analogue value into integer. 0, 1 or 2 depending on state } else if (x > 10) { xc = 2; } else { xc = 1; } if (y < -10) { yc = 0; } else if (y > 10) { yc = 2; } else { yc = 1; } int buttonState = (digitalRead(JoyStick_pin) == LOW) ? 1 : 0; // 仅当状态变化时发送数据 if (xc != prevXc || yc != prevYc || buttonState != prevButtonState) { Serial.print("S"); Serial.print(xc); Serial.print(","); Serial.print(yc); Serial.print(","); Serial.println(buttonState); prevXc = xc; prevYc = yc; prevButtonState = buttonState; } delay(40); }
内容的提问来源于stack exchange,提问作者Justin Li
相关产品推荐
相关产品推荐

