chromedp/input.go
2017-01-26 14:28:34 +07:00

172 lines
4.0 KiB
Go

package chromedp
import (
"context"
"errors"
"time"
"github.com/knq/chromedp/cdp"
"github.com/knq/chromedp/cdp/dom"
"github.com/knq/chromedp/cdp/input"
)
// Error types.
var (
ErrInvalidDimensions = errors.New("invalid box dimensions")
)
// MouseAction is a mouse action.
func MouseAction(typ input.MouseType, x, y int64, opts ...MouseOption) Action {
f := input.DispatchMouseEvent(typ, x, y)
for _, o := range opts {
f = o(f)
}
return f
}
// MouseClickXY sends a left mouse button click at the X, Y location.
func MouseClickXY(x, y int64, opts ...MouseOption) Action {
return Tasks{
MouseAction(input.MousePressed, x, y, append(opts, Button(input.ButtonLeft), ClickCount(1))...),
MouseAction(input.MouseReleased, x, y, append(opts, Button(input.ButtonLeft), ClickCount(1))...),
}
}
// MouseActionNode dispatches a mouse event at the center of a specified node.
func MouseActionNode(n *cdp.Node, opts ...MouseOption) Action {
return ActionFunc(func(ctxt context.Context, h cdp.FrameHandler) error {
box, err := dom.GetBoxModel(n.NodeID).Do(ctxt, h)
if err != nil {
return err
}
c := len(box.Content)
if c%2 != 0 {
return ErrInvalidDimensions
}
var x, y int64
for i := 0; i < c; i += 2 {
x += int64(box.Content[i])
y += int64(box.Content[i+1])
}
return MouseClickXY(x/int64(c/2), y/int64(c/2), 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.
func Button(button input.ButtonType) MouseOption {
return func(p *input.DispatchMouseEventParams) *input.DispatchMouseEventParams {
return p.WithButton(button)
}
}
// ButtonString is a mouse action option to set the button to click as a
// string.
func ButtonString(btn string) MouseOption {
return Button(input.ButtonType(btn))
}
// ButtonModifiers is a mouse action option to add additional modifiers for the
// button.
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 contains information about a key action.
type KeyAction struct {
v string
opts []KeyOption
}
var keyNames = map[rune]string{
'\b': "Backspace",
'\t': "Tab",
'\r': "Enter",
'\n': "Enter",
}
// Do satisfies Action interface.
func (ka *KeyAction) Do(ctxt context.Context, h cdp.FrameHandler) error {
var err error
// apply opts
sysP := input.DispatchKeyEvent(input.KeyRawDown)
keyP := input.DispatchKeyEvent(input.KeyChar)
for _, o := range ka.opts {
sysP = o(sysP)
keyP = o(keyP)
}
for _, r := range ka.v {
s := string(r)
if n, ok := keyNames[r]; ok {
kc := int64(r)
if r == '\n' {
s = string('\r')
kc = int64('\r')
}
err = sysP.WithKey(n).
WithNativeVirtualKeyCode(kc).
WithWindowsVirtualKeyCode(kc).
WithUnmodifiedText(s).
WithText(s).
Do(ctxt, h)
if err != nil {
return err
}
}
err = keyP.WithText(s).Do(ctxt, h)
if err != nil {
return err
}
// FIXME
time.Sleep(5 * time.Millisecond)
}
return nil
}
// KeyActionNode dispatches a key event on a node.
func KeyActionNode(n *cdp.Node, v string, opts ...KeyOption) Action {
return Tasks{
dom.Focus(n.NodeID),
MouseActionNode(n),
&KeyAction{v, opts},
}
}
// 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
}
}