Skip to content

Commit

Permalink
Merge pull request #9 from kevinconway/osx-drag
Browse files Browse the repository at this point in the history
Add support for OSX drag events
  • Loading branch information
kevinconway authored Mar 9, 2021
2 parents 7cc48c9 + 86ebcbd commit 7890f70
Show file tree
Hide file tree
Showing 15 changed files with 1,326 additions and 154 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ generate: $(BINDIR)
GO111MODULE=on \
GOFLAGS="$(GOFLAGS)" \
PATH="${PATH}:$(BINDIR)" \
go generate github.com/kevinconway/remouse/pkg github.com/kevinconway/remouse/pkg/internal
go generate github.com/kevinconway/remouseable/pkg github.com/kevinconway/remouseable/pkg/internal
$(MAKE) fmt

coverage: $(BINDIR) $(COVERDIR) $(COVERCOMBINED) $(COVERINTERCHANGE) $(COVERHTML) $(COVERXML)
Expand Down
112 changes: 60 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ the project. To view the code API documentation check out the

Most settings default to the correct values. The only value you should need to
set in the common case is the SSH password for the tablet. This password value
is found in the `About` tab of the tablet menu at the bottom of the `General
is found in the settings menu under `Help` and then `Copyrights and licenses`.
Your password will be near the bottom of the page. If you have an older tablet
that has not been updated to the latest software then your password may be
found in the `About` tab of the tablet menu at the bottom of the `General
Information` section. You may either give the password as text with

```bash
Expand All @@ -44,7 +47,39 @@ tablet surface with the stylus the computer mouse will click and hold down the
left mouse button while you write or draw and then release the button when you
lift the stylus.

### Easier SSH Setup
### OSX Privacy Settings

If you are using this on an Apple or OSX device then you will need to give the
terminal or shell you are using permissions to control your mouse. Mouse
permissions are treated as an accessibility feature. If you are not prompted by
the operating system to update your permissions the first time you run the
application then you can navigate to
`System Preferences -> Security & Privacy -> Privacy -> Accessibility`. You will
see your terminal or shell in the list of applications that have requested
accessibility permissions.

### reMarkable 2 Tablets

The application should work with both reMarkable and reMarkable 2 tablets.
However, the reMarkable 2 requires that you add
`--event-file /dev/input/event1` when executing because of a slight change in
where the stylus events are written in the new tablets. The full command should
look like
`remousable --ssh-password="MYPASSWORD" --event-file="/dev/input/event1"`.

### Wireless Tablet

The default expectation is that you will have your tablet connected over USB
which makes the default `10.11.99.1` address available. However, it is also
possible to access your device over wifi. If you attempt this method then you
will need to arrange for a static, or at least consistent, IP address for the
tablet. This is something you can usually do through configuring your router to
assign a fixed IP address to the device based on the hardware MAC address.

If you cannot assign the same `10.11.99.1` address in your setup then you may
override the default IP address when running the application:

### Advanced SSH Setup

By default, the tablet only accepts the root password for authentication. It is
possible, though, to install a custom public key on the device so that you can
Expand All @@ -55,9 +90,9 @@ If you'd like to create a key pair especially for accessing the reMarkable
tablet then start with a guide like
<https://help.github.com/en/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent>
that walks through creating a new key pair and registering it with your SSH
agent. For advanced SSH users, such as those using the gpg-agent as the SSH
agent, the reMouse application will talk to any valid SSH agent implementation
so long as the `SSH_AUTH_SOCK` value is set correctly.
agent. For even more advanced SSH users, such as those using the gpg-agent as
the SSH agent, the remouseable application will talk to any valid SSH agent
implementation so long as the `SSH_AUTH_SOCK` value is set correctly.

Once you have a key pair ready, copy the public key value from `ssh-add -L` for
the key you want to use. Then copy the key over to your tablet with:
Expand All @@ -74,68 +109,41 @@ the usual password flag when running the application.
Note that windows builds cannot use this option due to incompatibilities with
the current version of the windows ssh-agent.

Note that if you encounter the `Invalid MIT-MAGIC-COOKIE-1 key` error
it means that most likely the ssh fingerprint of the device might have
changed, most likely due to an update of the OS.
Follow the ssh suggestion of removing the outdated fingerprint then
if you are satisfied that your device is indeed the right one try connecting again.

### Wireless Tablet

The default expectation is that you will have your tablet connected over USB
which makes the default `10.11.99.1` address available. However, it is also
possible to access your device over wifi. If you attempt this method then you
will need to arrange for a static, or at least consistent, IP address for the
tablet. This is something you can usually do through configuring your router to
assign a fixed IP address to the device based on the hardware MAC address.

If you cannot assign the same `10.11.99.1` address in your setup then you may
override the default IP address when running the application:
Note that if you encounter the `Invalid MIT-MAGIC-COOKIE-1 key` error it means
that most likely the ssh fingerprint of the device might have changed to an
update of the tablet OS. Follow the ssh suggestion of removing the outdated
fingerprint then if you are satisfied that your device is indeed the right one
try connecting again.

```bash
remouseable --ssh-ip="192.168.1.110" # or other IP
```

### OSX Privacy Settings

If you are using this on an Apple or OSX device then you will need to give the
terminal or shell you are using permissions to control your mouse. Mouse
permissions are treated as an accessibility feature. If you are not prompted by
the operating system to update your permissions the first time you run the
application then you can navigate to
`System Preferences -> Security & Privacy -> Privacy -> Accessibility`. You will
see your terminal or shell in the list of applications that have requested
accessibility permissions.

### reMarkable 2 Tablets

The application should work with both reMarkable and reMarkable 2 tablets.
However, the reMarkable 2 requires that you add
`--event-file /dev/input/event1` when executing because of a slight change in
where the stylus events are written in the new tablets.

### All Options

```
$ remouseable -h
Usage of remouseable:
--event-file string The path on the tablet from which to read evdev events. Probably don't change this. (default "/dev/input/event0")
--orientation string Orientation of the tablet. Choices are vertical, right, and left (default "right")
--screen-height int The max units per millimeter of the host screen height. Probably don't change this. (default 1080)
--screen-width int The max units per millimeter of the host screen width. Probably don't change this. (default 1920)
--ssh-ip string The host and port of a tablet. (default "10.11.99.1:22")
--ssh-password string An optional password to use when ssh-ing into the tablet. Use - for a prompt rather than entering a value. If not given then public/private keypair authentication is used.
--ssh-socket string Path to the SSH auth socket. This must not be empty if using public/private keypair authentication. (default "/run/user/1000/gnupg/S.gpg-agent.ssh")
--ssh-user string The ssh username to use when logging into the tablet. (default "root")
--tablet-height int The max units per millimeter for the hight of the tablet. Probably don't change this. (default 15725)
--tablet-width int The max units per millimeter for the width of the tablet. Probably don't change this. (default 20967)
--debug-events Stream hardware events from the tablet instead of acting as a mouse. This is for debugging.
--disable-drag-event Disable use of the custom OSX drag event. Only use this drawing on an Apple device is not working as expected.
--event-file string The path on the tablet from which to read evdev events. Probably don't change this. (default "/dev/input/event0")
--orientation string Orientation of the tablet. Choices are vertical, right, and left (default "right")
--pressure-threshold int Change the click detection sensitivity. 1000 is when the pen makes contact with the tablet. Set higher to require more pen pressure for a click. (default 1000)
--screen-height int The max units per millimeter of the host screen height. Probably don't change this. (default 1080)
--screen-width int The max units per millimeter of the host screen width. Probably don't change this. (default 1920)
--ssh-ip string The host and port of a tablet. (default "10.11.99.1:22")
--ssh-password string An optional password to use when ssh-ing into the tablet. Use - for a prompt rather than entering a value. If not given then public/private keypair authentication is used.
--ssh-socket string Path to the SSH auth socket. This must not be empty if using public/private keypair authentication.
--ssh-user string The ssh username to use when logging into the tablet. (default "root")
--tablet-height int The max units per millimeter for the hight of the tablet. Probably don't change this. (default 15725)
--tablet-width int The max units per millimeter for the width of the tablet. Probably don't change this. (default 20967)
pflag: help requested
exit status 2
```

## Building

There are pre-build binaries attached to each release that should work for all
There are pre-built binaries attached to each release that should work for all
64bit versions of linux, osx, and windows. However, if you prefer to generate
your own build then the following sections detail building a binary on
different platforms.
Expand Down Expand Up @@ -247,7 +255,7 @@ creating a portable binary build difficult.
## Developing
This project is go1.13+ compatible. A Makefile is included to make some things
This project is go1.16+ compatible. A Makefile is included to make some things
easier. Some make targets of note:
- make generate
Expand Down
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
module github.com/kevinconway/remouseable

go 1.13
go 1.16

require (
github.com/dave/jennifer v1.3.0
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/mock v1.3.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550
golang.org/x/sys v0.0.0-20191018095205-727590c5006e
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
)
14 changes: 9 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,19 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191018095205-727590c5006e h1:ZtoklVMHQy6BFRHkbG6JzK+S6rX82//Yeok1vMlizfQ=
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
Expand Down
41 changes: 38 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ func main() {
sshPassword := fs.String("ssh-password", "", "An optional password to use when ssh-ing into the tablet. Use - for a prompt rather than entering a value. If not given then public/private keypair authentication is used.")
sshSocket := fs.String("ssh-socket", os.Getenv("SSH_AUTH_SOCK"), "Path to the SSH auth socket. This must not be empty if using public/private keypair authentication.")
evtFile := fs.String("event-file", "/dev/input/event0", "The path on the tablet from which to read evdev events. Probably don't change this.")
debugEvents := fs.Bool("debug-events", false, "Stream hardware events from the tablet instead of acting as a mouse. This is for debugging.")
disableDrag := fs.Bool("disable-drag-event", false, "Disable use of the custom OSX drag event. Only use this drawing on an Apple device is not working as expected.")
pressureThreshold := fs.Int("pressure-threshold", 1000, "Change the click detection sensitivity. 1000 is when the pen makes contact with the tablet. Set higher to require more pen pressure for a click.")
_ = fs.Parse(os.Args[1:])

if *sshPassword == "-" {
Expand Down Expand Up @@ -98,6 +101,30 @@ func main() {
if err = sesh.Start(fmt.Sprintf("cat %s", *evtFile)); err != nil {
panic(err)
}
if *debugEvents {
it := &remouseable.SelectingEvdevIterator{
Wrapped: &remouseable.FileEvdevIterator{
Source: ioutil.NopCloser(pipe),
},
Selection: []uint16{remouseable.EV_ABS},
}
defer it.Close()
fmt.Println("remouseable connected and running.")
for it.Next() {
evt := it.Current()
evtype := remouseable.EVMap[evt.Type]
evcode := remouseable.CodeString(evt.Type, evt.Code)
fmt.Printf(
`{"eventType": %d, "eventTypeName": "%s", "eventCode": %d, "eventCodeName": "%s", "eventValue": %d}`,
evt.Type, evtype, evt.Code, evcode, evt.Value,
)
fmt.Print("\n")
}
if err = it.Close(); err != nil {
panic(err.Error())
}
return
}

it := &remouseable.SelectingEvdevIterator{
Wrapped: &remouseable.FileEvdevIterator{
Expand All @@ -107,9 +134,17 @@ func main() {
}
defer it.Close()

sm := &remouseable.EvdevStateMachine{
Iterator: it,
PressureThreshold: 1000,
var sm remouseable.StateMachine = &remouseable.DraggingEvdevStateMachine{
EvdevStateMachine: &remouseable.EvdevStateMachine{
Iterator: it,
PressureThreshold: *pressureThreshold,
},
}
if *disableDrag {
sm = &remouseable.EvdevStateMachine{
Iterator: it,
PressureThreshold: *pressureThreshold,
}
}
defer sm.Close()

Expand Down
14 changes: 14 additions & 0 deletions pkg/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ type EvdevIterator interface {
const (
// StateChangeMove represents a move of the x and y for the mouse.
ChangeTypeMove = "MOVE"
// StateChangeDrag represents a move of the x and y for the mouse when clicked.
ChangeTypeDrag = "DRAG"
// ChangeTypeClick indicates that the stylus is touching the tablet.
ChangeTypeClick = "CLICK"
// ChangeTypeUnclick indicates the stylus is no longer touching the tablet.
Expand All @@ -69,6 +71,17 @@ func (*StateChangeMove) Type() string {
return ChangeTypeMove
}

// StateChangeDrag contains mouse movement data when clicked.
type StateChangeDrag struct {
X int
Y int
}

// Type returns the specific change type.
func (*StateChangeDrag) Type() string {
return ChangeTypeDrag
}

// StateChangeClick contains mouse click data.
type StateChangeClick struct{}

Expand Down Expand Up @@ -116,6 +129,7 @@ type PositionScaler interface {
// Driver is used to control a host system.
type Driver interface {
MoveMouse(x int, y int) error
DragMouse(x int, y int) error
Click() error
Unclick() error
GetSize() (width int, height int, err error)
Expand Down
8 changes: 8 additions & 0 deletions pkg/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,11 @@ func (*RobotgoDriver) MoveMouse(x int, y int) error {
robotgo.MoveMouse(x, y)
return nil
}

// DragMouse sets the mouse to a specified location while dragging a screen element.
func (*RobotgoDriver) DragMouse(x int, y int) error {
// Reversing the x/y due to robotgo seemingly having an opposite
// x/y concept as the typical event source of evdev, etc.
robotgo.DragMouse(x, y)
return nil
}
1 change: 0 additions & 1 deletion pkg/internal/robotgo/mouse/goMouse.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ int drag_mouse(int32_t x, int32_t y, MMMouseButton button)
MMPointInt32 point;
point = MMPointInt32Make(x, y);
dragMouse(point, button);
microsleep(mouseDelay);

return 0;
}
Expand Down
Loading

0 comments on commit 7890f70

Please sign in to comment.