chromedp/input.go
Daniel Martí 3d3bf22ccc start the chromedp v2 refactor
First, we want all of the functionality in a single package; this means
collapsing whatever is useful into the root chromedp package.

The runner package is being replaced by the Allocator interface, with a
default implementation which starts browser processes.

The client package doesn't really have a place in the new design. The
context, allocator, and browser types will handle the connection with
each browser.

Finally, the new API is context-based, hence the addition of context.go.
The tests have been modified to build and run against the new API.
2019-04-01 12:17:28 +01:00

195 lines
5.2 KiB
Go

package chromedp
import (
"context"
"fmt"
"time"
"github.com/chromedp/cdproto/cdp"
"github.com/chromedp/cdproto/dom"
"github.com/chromedp/cdproto/input"
"github.com/chromedp/chromedp/kb"
)
// MouseAction is a mouse action.
func MouseAction(typ input.MouseType, x, y int64, opts ...MouseOption) Action {
me := input.DispatchMouseEvent(typ, float64(x), float64(y))
// apply opts
for _, o := range opts {
me = o(me)
}
return me
}
// MouseClickXY sends a left mouse button click (ie, mousePressed and
// mouseReleased event) at the X, Y location.
func MouseClickXY(x, y int64, opts ...MouseOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error {
me := &input.DispatchMouseEventParams{
Type: input.MousePressed,
X: float64(x),
Y: float64(y),
Button: input.ButtonLeft,
ClickCount: 1,
}
// apply opts
for _, o := range opts {
me = o(me)
}
err := me.Do(ctxt, h)
if err != nil {
return err
}
me.Type = input.MouseReleased
return me.Do(ctxt, h)
})
}
// MouseClickNode dispatches a mouse left button click event at the center of a
// specified node.
//
// Note that the window will be scrolled if the node is not within the window's
// viewport.
func MouseClickNode(n *cdp.Node, opts ...MouseOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error {
var pos []int
err := EvaluateAsDevTools(fmt.Sprintf(scrollIntoViewJS, n.FullXPath()), &pos).Do(ctxt, h)
if err != nil {
return err
}
box, err := dom.GetBoxModel().WithNodeID(n.NodeID).Do(ctxt, h)
if err != nil {
return err
}
c := len(box.Content)
if c%2 != 0 || c < 1 {
return ErrInvalidDimensions
}
var x, y int64
for i := 0; i < c; i += 2 {
x += int64(box.Content[i])
y += int64(box.Content[i+1])
}
x /= int64(c / 2)
y /= int64(c / 2)
return MouseClickXY(x, y, opts...).Do(ctxt, h)
})
}
// MouseOption is a mouse action option.
type MouseOption func(*input.DispatchMouseEventParams) *input.DispatchMouseEventParams
// Button is a mouse action option to set the button to click from a string.
func Button(btn string) MouseOption {
return ButtonType(input.ButtonType(btn))
}
// ButtonType is a mouse action option to set the button to click.
func ButtonType(button input.ButtonType) MouseOption {
return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithButton(button)
}
}
// ButtonLeft is a mouse action option to set the button clicked as the left
// mouse button.
func ButtonLeft(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithButton(input.ButtonLeft)
}
// ButtonMiddle is a mouse action option to set the button clicked as the middle
// mouse button.
func ButtonMiddle(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithButton(input.ButtonMiddle)
}
// ButtonRight is a mouse action option to set the button clicked as the right
// mouse button.
func ButtonRight(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithButton(input.ButtonRight)
}
// ButtonNone is a mouse action option to set the button clicked as none (used
// for mouse movements).
func ButtonNone(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithButton(input.ButtonNone)
}
// ButtonModifiers is a mouse action option to add additional input modifiers
// for a button click.
func ButtonModifiers(modifiers ...input.Modifier) MouseOption {
return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
for _, m := range modifiers {
p.Modifiers |= m
}
return p
}
}
// ClickCount is a mouse action option to set the click count.
func ClickCount(n int) MouseOption {
return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithClickCount(int64(n))
}
}
// KeyAction will synthesize a keyDown, char, and keyUp event for each rune
// contained in keys along with any supplied key options.
//
// Only well-known, "printable" characters will have char events synthesized.
//
// Please see the chromedp/kb package for implementation details and the list
// of well-known keys.
func KeyAction(keys string, opts ...KeyOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error {
for _, r := range keys {
for _, k := range kb.Encode(r) {
if err := k.Do(ctxt, h); err != nil {
return err
}
}
// TODO: move to context
time.Sleep(5 * time.Millisecond)
}
return nil
})
}
// KeyActionNode dispatches a key event on a node.
func KeyActionNode(n *cdp.Node, keys string, opts ...KeyOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.Executor) error {
err := dom.Focus().WithNodeID(n.NodeID).Do(ctxt, h)
if err != nil {
return err
}
return KeyAction(keys, opts...).Do(ctxt, h)
})
}
// KeyOption is a key action option.
type KeyOption func(*input.DispatchKeyEventParams) *input.DispatchKeyEventParams
// KeyModifiers is a key action option to add additional modifiers on the key
// press.
func KeyModifiers(modifiers ...input.Modifier) KeyOption {
return func(p *input.DispatchKeyEventParams) *input.DispatchKeyEventParams {
for _, m := range modifiers {
p.Modifiers |= m
}
return p
}
}