From 4c439be11f9d775ec9e6e590324e55e6b4270bc1 Mon Sep 17 00:00:00 2001 From: vcaesar Date: Sun, 18 Jan 2026 05:45:38 -0800 Subject: [PATCH] Add: add toogle error check and MultiClikck, optimize the code and api --- mouse/mouse_c.h | 49 ++++++++---------------------- robotgo.go | 81 ++++++++++++++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 67 deletions(-) diff --git a/mouse/mouse_c.h b/mouse/mouse_c.h index fc8bdb4..b252623 100644 --- a/mouse/mouse_c.h +++ b/mouse/mouse_c.h @@ -54,7 +54,6 @@ } #elif defined(IS_WINDOWS) - DWORD MMMouseUpToMEventF(MMMouseButton button) { if (button == LEFT_BUTTON) { return MOUSEEVENTF_LEFTUP; } if (button == RIGHT_BUTTON) { return MOUSEEVENTF_RIGHTUP; } @@ -99,7 +98,6 @@ void moveMouse(MMPointInt32 point){ CGPointFromMMPointInt32(point), kCGMouseButtonLeft); calculateDeltas(&move, point); - CGEventPost(kCGHIDEventTap, move); CFRelease(move); CFRelease(source); @@ -156,7 +154,7 @@ MMPointInt32 location() { } /* Press down a button, or release it. */ -int toggleMouseErr(bool down, MMMouseButton button) { +int toggleMouse(bool down, MMMouseButton button) { #if defined(IS_MACOSX) const CGPoint currentPos = CGPointFromMMPointInt32(location()); const CGEventType mouseType = MMMouseToCGEventType(down, button); @@ -167,20 +165,17 @@ int toggleMouseErr(bool down, MMMouseButton button) { CFRelease(source); return (int)kCGErrorCannotComplete; } - + CGEventPost(kCGHIDEventTap, event); CFRelease(event); CFRelease(source); - return 0; #elif defined(USE_X11) Display *display = XGetMainDisplay(); Status status = XTestFakeButtonEvent(display, button, down ? True : False, CurrentTime); XSync(display, false); - return status ? 0 : 1; #elif defined(IS_WINDOWS) - // mouse_event(MMMouseToMEventF(down, button), 0, 0, 0, 0); INPUT mouseInput; mouseInput.type = INPUT_MOUSE; @@ -195,26 +190,18 @@ int toggleMouseErr(bool down, MMMouseButton button) { #endif } -void toggleMouse(bool down, MMMouseButton button) { - toggleMouseErr(down, button); -} - -int clickMouseErr(MMMouseButton button){ - int err = toggleMouseErr(true, button); +int clickMouse(MMMouseButton button){ + int err = toggleMouse(true, button); if (err != 0) { return err; } microsleep(5.0); - - return toggleMouseErr(false, button); + return toggleMouse(false, button); } -void clickMouse(MMMouseButton button){ - clickMouseErr(button); -} - -int doubleClickErr(MMMouseButton button){ +/* Special function for sending double clicks, needed for MacOS. */ +int doubleClick(MMMouseButton button){ #if defined(IS_MACOSX) /* Double click for Mac. */ const CGPoint currentPos = CGPointFromMMPointInt32(location()); @@ -223,7 +210,6 @@ int doubleClickErr(MMMouseButton button){ CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); CGEventRef event = CGEventCreateMouseEvent(source, mouseTypeDown, currentPos, kCGMouseButtonLeft); - if (event == NULL) { CFRelease(source); return (int)kCGErrorCannotComplete; @@ -238,26 +224,18 @@ int doubleClickErr(MMMouseButton button){ CFRelease(event); CFRelease(source); - return 0; #else /* Double click for everything else. */ - int err = clickMouseErr(button); + int err = clickMouse(button); if (err != 0) { return err; } - microsleep(200); - - return clickMouseErr(button); + return clickMouse(button); #endif } -/* Special function for sending double clicks, needed for MacOS. */ -void doubleClick(MMMouseButton button){ - doubleClickErr(button); -} - /* Function used to scroll the screen in the required direction. */ void scrollMouseXY(int x, int y) { #if defined(IS_WINDOWS) @@ -268,7 +246,7 @@ void scrollMouseXY(int x, int y) { #if defined(IS_MACOSX) CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState); - CGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x); + CGEventRef event = CGEventCreateScrollWheelEvent(source, kCGScrollEventUnitPixel, 2, y, x); CGEventPost(kCGHIDEventTap, event); CFRelease(event); @@ -351,10 +329,10 @@ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed) velo_y /= veloDistance; pos.x += floor(velo_x + 0.5); - pos.y += floor(velo_y + 0.5); + pos.y += floor(velo_y + 0.5); - /* Make sure we are in the screen boundaries! (Strange things will happen if we are not.) */ - // if (pos.x >= screenSize.w || pos.y >= screenSize.h) { + /* Make sure we are in the screen boundaries! */ + // if (pos.x >= screenSize.w || pos.y >= screenSize.h) { // return false; // } moveMouse(pos); @@ -363,6 +341,5 @@ bool smoothlyMoveMouse(MMPointInt32 endPoint, double lowSpeed, double highSpeed) microsleep(DEADBEEF_UNIFORM(lowSpeed, highSpeed)); // microsleep(DEADBEEF_UNIFORM(1.0, 3.0)); } - return true; } diff --git a/robotgo.go b/robotgo.go index a875790..aebd38c 100644 --- a/robotgo.go +++ b/robotgo.go @@ -659,7 +659,7 @@ func Location() (int, int) { return x, y } -// Click click the mouse button +// ClickV1 click the mouse button // // robotgo.Click(button string, double bool) // @@ -668,7 +668,7 @@ func Location() (int, int) { // robotgo.Click() // default is left button // robotgo.Click("right") // robotgo.Click("wheelLeft") -func Click(args ...interface{}) { +func ClickV1(args ...interface{}) { var ( button C.MMMouseButton = C.LEFT_BUTTON double bool @@ -691,18 +691,19 @@ func Click(args ...interface{}) { MilliSleep(MouseSleep) } -// ClickE click the mouse button and return error +// Click click the mouse button and return error // -// robotgo.ClickE(button string, double bool) +// robotgo.Click(button string, double bool) // // Examples: // -// err := robotgo.ClickE() // default is left button -// err := robotgo.ClickE("right") -func ClickE(args ...interface{}) error { +// err := robotgo.Click() // default is left button +// err := robotgo.Click("right") +func Click(args ...interface{}) error { var ( button C.MMMouseButton = C.LEFT_BUTTON double bool + count int ) if len(args) > 0 { @@ -720,30 +721,46 @@ func ClickE(args ...interface{}) error { } double = dbl } - - defer MilliSleep(MouseSleep) - - if !double { - if code := C.toggleMouseErr(true, button); code != 0 { - return formatClickError(int(code), button, "down", false) - } - - // match clickMouse timing - C.microsleep(C.double(5.0)) - - if code := C.toggleMouseErr(false, button); code != 0 { - return formatClickError(int(code), button, "up", false) - } - } else { - if code := C.doubleClickErr(button); code != 0 { - return formatClickError(int(code), button, "double", true) - } + if len(args) > 3 { + count = args[3].(int) } + defer MilliSleep(MouseSleep) + if !double { + if code := C.toggleMouse(true, button); code != 0 { + return formatClickError(int(code), button, "down", count) + } + MilliSleep(5) + if code := C.toggleMouse(false, button); code != 0 { + return formatClickError(int(code), button, "up", count) + } + } else { + if code := C.doubleClick(button); code != 0 { + return formatClickError(int(code), button, "double", 2) + } + } return nil } -func formatClickError(code int, button C.MMMouseButton, stage string, double bool) error { +// MultiClick performs multiple clicks and returns error +// +// robotgo.MultiClick(button string, count int) +func MultiClick(button string, count int) error { + if count < 1 { + return nil + } + btn := CheckMouse(button) + defer MilliSleep(MouseSleep) + + for i := 0; i < count; i++ { + if err := Click(btn, false, count); err != nil { + return err + } + } + return nil +} + +func formatClickError(code int, button C.MMMouseButton, stage string, count int) error { btnName := MouseButtonString(button) detail := "" @@ -776,10 +793,9 @@ func formatClickError(code int, button C.MMMouseButton, stage string, double boo } if detail != "" { - return fmt.Errorf("click %s failed (%s, double=%v): %s (code=%d)", stage, btnName, double, detail, code) + return fmt.Errorf("click %s failed (%s, count=%d): %s (code=%d)", stage, btnName, count, detail, code) } - - return fmt.Errorf("click %s failed (%s, double=%v), code=%d", stage, btnName, double, code) + return fmt.Errorf("click %s failed (%s, count=%d), code=%d", stage, btnName, count, code) } // MoveClick move and click the mouse @@ -824,11 +840,14 @@ func Toggle(key ...interface{}) error { if len(key) > 1 && key[1].(string) == "up" { down = false } - C.toggleMouse(C.bool(down), button) + code := C.toggleMouse(C.bool(down), button) + if code != 0 { + return formatClickError(int(code), button, "down", 1) + } + if len(key) > 2 { MilliSleep(MouseSleep) } - return nil }