This commit is contained in:
Josh at WLTechBlog
2025-09-30 14:11:27 -05:00
parent 86d1db55cd
commit a3c782eb24
11 changed files with 4904 additions and 6 deletions

View File

@@ -2621,3 +2621,635 @@ func (c *Client) ClearStorage(tabID string, timeout int) error {
return nil
}
// DragAndDrop performs a drag and drop operation from source to target element
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) DragAndDrop(tabID, sourceSelector, targetSelector string, timeout int) error {
params := map[string]string{
"source": sourceSelector,
"target": targetSelector,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("drag-and-drop", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform drag and drop: %s", resp.Error)
}
return nil
}
// DragAndDropToCoordinates performs a drag and drop operation from source element to specific coordinates
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) DragAndDropToCoordinates(tabID, sourceSelector string, targetX, targetY int, timeout int) error {
params := map[string]string{
"source": sourceSelector,
"target-x": strconv.Itoa(targetX),
"target-y": strconv.Itoa(targetY),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("drag-and-drop-coordinates", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform drag and drop to coordinates: %s", resp.Error)
}
return nil
}
// DragAndDropByOffset performs a drag and drop operation from source element by a relative offset
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) DragAndDropByOffset(tabID, sourceSelector string, offsetX, offsetY int, timeout int) error {
params := map[string]string{
"source": sourceSelector,
"offset-x": strconv.Itoa(offsetX),
"offset-y": strconv.Itoa(offsetY),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("drag-and-drop-offset", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform drag and drop by offset: %s", resp.Error)
}
return nil
}
// RightClick performs a right-click on an element
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) RightClick(tabID, selector string, timeout int) error {
params := map[string]string{
"selector": selector,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("right-click", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to right-click element: %s", resp.Error)
}
return nil
}
// DoubleClick performs a double-click on an element
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) DoubleClick(tabID, selector string, timeout int) error {
params := map[string]string{
"selector": selector,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("double-click", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to double-click element: %s", resp.Error)
}
return nil
}
// MiddleClick performs a middle-click on an element
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) MiddleClick(tabID, selector string, timeout int) error {
params := map[string]string{
"selector": selector,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("middle-click", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to middle-click element: %s", resp.Error)
}
return nil
}
// Hover moves the mouse over an element without clicking
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) Hover(tabID, selector string, timeout int) error {
params := map[string]string{
"selector": selector,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("hover", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to hover over element: %s", resp.Error)
}
return nil
}
// MouseMove moves the mouse to specific coordinates without clicking
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) MouseMove(tabID string, x, y int, timeout int) error {
params := map[string]string{
"x": strconv.Itoa(x),
"y": strconv.Itoa(y),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("mouse-move", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to move mouse: %s", resp.Error)
}
return nil
}
// ScrollWheel performs mouse wheel scrolling at specific coordinates
// If tabID is empty, the current tab will be used
// deltaX and deltaY specify scroll amounts (negative = up/left, positive = down/right)
// timeout is in seconds, 0 means no timeout
func (c *Client) ScrollWheel(tabID string, x, y, deltaX, deltaY int, timeout int) error {
params := map[string]string{
"x": strconv.Itoa(x),
"y": strconv.Itoa(y),
"delta-x": strconv.Itoa(deltaX),
"delta-y": strconv.Itoa(deltaY),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("scroll-wheel", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to scroll with mouse wheel: %s", resp.Error)
}
return nil
}
// KeyCombination sends a key combination (e.g., "Ctrl+C", "Alt+Tab", "Shift+Enter")
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) KeyCombination(tabID, keys string, timeout int) error {
params := map[string]string{
"keys": keys,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("key-combination", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to send key combination: %s", resp.Error)
}
return nil
}
// SpecialKey sends a special key (e.g., "Enter", "Escape", "Tab", "F1", "ArrowUp")
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) SpecialKey(tabID, key string, timeout int) error {
params := map[string]string{
"key": key,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("special-key", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to send special key: %s", resp.Error)
}
return nil
}
// ModifierClick performs a click with modifier keys (e.g., Ctrl+click, Shift+click)
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) ModifierClick(tabID, selector, modifiers string, timeout int) error {
params := map[string]string{
"selector": selector,
"modifiers": modifiers,
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("modifier-click", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform modifier click: %s", resp.Error)
}
return nil
}
// TouchTap performs a single finger tap at specific coordinates
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) TouchTap(tabID string, x, y int, timeout int) error {
params := map[string]string{
"x": strconv.Itoa(x),
"y": strconv.Itoa(y),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("touch-tap", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform touch tap: %s", resp.Error)
}
return nil
}
// TouchLongPress performs a long press at specific coordinates
// If tabID is empty, the current tab will be used
// duration is in milliseconds (default: 1000ms)
// timeout is in seconds, 0 means no timeout
func (c *Client) TouchLongPress(tabID string, x, y, duration int, timeout int) error {
params := map[string]string{
"x": strconv.Itoa(x),
"y": strconv.Itoa(y),
}
if duration > 0 {
params["duration"] = strconv.Itoa(duration)
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("touch-long-press", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform touch long press: %s", resp.Error)
}
return nil
}
// TouchSwipe performs a swipe gesture from start to end coordinates
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) TouchSwipe(tabID string, startX, startY, endX, endY int, timeout int) error {
params := map[string]string{
"start-x": strconv.Itoa(startX),
"start-y": strconv.Itoa(startY),
"end-x": strconv.Itoa(endX),
"end-y": strconv.Itoa(endY),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("touch-swipe", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform touch swipe: %s", resp.Error)
}
return nil
}
// PinchZoom performs a pinch-to-zoom gesture
// If tabID is empty, the current tab will be used
// scale > 1.0 zooms in, scale < 1.0 zooms out
// timeout is in seconds, 0 means no timeout
func (c *Client) PinchZoom(tabID string, centerX, centerY int, scale float64, timeout int) error {
params := map[string]string{
"center-x": strconv.Itoa(centerX),
"center-y": strconv.Itoa(centerY),
"scale": fmt.Sprintf("%.2f", scale),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("pinch-zoom", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to perform pinch zoom: %s", resp.Error)
}
return nil
}
// ScrollElement scrolls a specific element by a given amount
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) ScrollElement(tabID, selector string, deltaX, deltaY int, timeout int) error {
params := map[string]string{
"selector": selector,
"delta-x": strconv.Itoa(deltaX),
"delta-y": strconv.Itoa(deltaY),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("scroll-element", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to scroll element: %s", resp.Error)
}
return nil
}
// ScrollToCoordinates scrolls the page to specific coordinates
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) ScrollToCoordinates(tabID string, x, y int, timeout int) error {
params := map[string]string{
"x": strconv.Itoa(x),
"y": strconv.Itoa(y),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("scroll-to-coordinates", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to scroll to coordinates: %s", resp.Error)
}
return nil
}
// SelectText selects text within an element by character range
// If tabID is empty, the current tab will be used
// timeout is in seconds, 0 means no timeout
func (c *Client) SelectText(tabID, selector string, startIndex, endIndex int, timeout int) error {
params := map[string]string{
"selector": selector,
"start": strconv.Itoa(startIndex),
"end": strconv.Itoa(endIndex),
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("select-text", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to select text: %s", resp.Error)
}
return nil
}
// SelectAllText selects all text within an element or the entire page
// If tabID is empty, the current tab will be used
// If selector is empty, selects all text on the page
// timeout is in seconds, 0 means no timeout
func (c *Client) SelectAllText(tabID, selector string, timeout int) error {
params := map[string]string{}
if selector != "" {
params["selector"] = selector
}
// Only include tab ID if it's provided
if tabID != "" {
params["tab"] = tabID
}
// Add timeout if specified
if timeout > 0 {
params["timeout"] = strconv.Itoa(timeout)
}
resp, err := c.SendCommand("select-all-text", params)
if err != nil {
return err
}
if !resp.Success {
return fmt.Errorf("failed to select all text: %s", resp.Error)
}
return nil
}