Add support for session restore on the linux portals backend, fixing #77
This commit is contained in:
parent
7a806f7b00
commit
05259f6db5
8 changed files with 70 additions and 13 deletions
12
README.md
12
README.md
|
|
@ -12,8 +12,16 @@ Supports Flatpak's RemoteDesktop portal (for Wayland), Windows and X11.
|
||||||
* [Snap](https://snapcraft.io/remote-touchpad)
|
* [Snap](https://snapcraft.io/remote-touchpad)
|
||||||
* [Windows](https://github.com/Unrud/remote-touchpad/releases/latest)
|
* [Windows](https://github.com/Unrud/remote-touchpad/releases/latest)
|
||||||
* Golang:
|
* Golang:
|
||||||
* Portal & uinput & X11: `go install -tags portal,uinput,x11 github.com/unrud/remote-touchpad@latest`
|
* Portal & uinput & X11:
|
||||||
* Windows: `go install github.com/unrud/remote-touchpad@latest`
|
|
||||||
|
```sh
|
||||||
|
go install -tags portal,uinput,x11 github.com/unrud/remote-touchpad@latest
|
||||||
|
```
|
||||||
|
* Windows:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go install github.com/unrud/remote-touchpad@latest
|
||||||
|
```
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,14 +55,14 @@ const (
|
||||||
|
|
||||||
type ControllerInfo struct {
|
type ControllerInfo struct {
|
||||||
Name string
|
Name string
|
||||||
Init func() (Controller, error)
|
Init func(bool) (Controller, error)
|
||||||
|
|
||||||
priority int
|
priority int
|
||||||
}
|
}
|
||||||
|
|
||||||
var Controllers []ControllerInfo
|
var Controllers []ControllerInfo
|
||||||
|
|
||||||
func RegisterController(name string, init func() (Controller, error), priority int) {
|
func RegisterController(name string, init func(bool) (Controller, error), priority int) {
|
||||||
Controllers = append(Controllers, ControllerInfo{name, init, priority})
|
Controllers = append(Controllers, ControllerInfo{name, init, priority})
|
||||||
sort.SliceStable(Controllers, func(i, j int) bool {
|
sort.SliceStable(Controllers, func(i, j int) bool {
|
||||||
return Controllers[i].priority < Controllers[j].priority
|
return Controllers[i].priority < Controllers[j].priority
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ func init() {
|
||||||
RegisterController("null", InitNullController, 1000)
|
RegisterController("null", InitNullController, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitNullController() (Controller, error) {
|
func InitNullController(saveRestoreToken bool) (Controller, error) {
|
||||||
return &nullController{}, nil
|
return &nullController{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -34,6 +36,8 @@ const (
|
||||||
btnReleased uint32 = 0
|
btnReleased uint32 = 0
|
||||||
btnPressed uint32 = 1
|
btnPressed uint32 = 1
|
||||||
|
|
||||||
|
untilRevoked uint32 = 2
|
||||||
|
|
||||||
// linux/input-event-codes.h
|
// linux/input-event-codes.h
|
||||||
btnLeft int32 = 0x110
|
btnLeft int32 = 0x110
|
||||||
btnRight int32 = 0x111
|
btnRight int32 = 0x111
|
||||||
|
|
@ -50,7 +54,26 @@ func init() {
|
||||||
RegisterController("RemoteDesktop portal", InitPortalController, 1)
|
RegisterController("RemoteDesktop portal", InitPortalController, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitPortalController() (Controller, error) {
|
func InitPortalController(saveRestoreToken bool) (Controller, error) {
|
||||||
|
cacheDirectory, err := os.UserCacheDir()
|
||||||
|
var restoreTokenFilePath string
|
||||||
|
var restoreToken string
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Join(errors.New("Cannot get user cache directory, therefore cannot get restore token file path in order to read or save the restore token. "), err)
|
||||||
|
if saveRestoreToken == true {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
restoreTokenFilePath = filepath.Join(cacheDirectory, "remote_touchpad_portals_restore_token")
|
||||||
|
restoreTokenBytes, err := os.ReadFile(restoreTokenFilePath)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to read restore token file: %s\n", err)
|
||||||
|
} else {
|
||||||
|
restoreToken = string(restoreTokenBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
bus, err := dbus.SessionBusPrivate()
|
bus, err := dbus.SessionBusPrivate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, &UnsupportedPlatformError{err}
|
return nil, &UnsupportedPlatformError{err}
|
||||||
|
|
@ -81,10 +104,18 @@ func InitPortalController() (Controller, error) {
|
||||||
return nil, &UnsupportedPlatformError{
|
return nil, &UnsupportedPlatformError{
|
||||||
errors.New("unexpected 'AvailableDeviceTypes' return type")}
|
errors.New("unexpected 'AvailableDeviceTypes' return type")}
|
||||||
}
|
}
|
||||||
if availableDeviceTypes&deviceKeyboard == 0 ||
|
if availableDeviceTypes&deviceKeyboard == 0 &&
|
||||||
availableDeviceTypes&devicePointer == 0 {
|
availableDeviceTypes&devicePointer == 0 {
|
||||||
return nil, &UnsupportedPlatformError{
|
return nil, &UnsupportedPlatformError{
|
||||||
errors.New("keyboard or pointer source type not supported")}
|
errors.New("keyboard and pointer source type not supported")}
|
||||||
|
}
|
||||||
|
if availableDeviceTypes&deviceKeyboard == 0 {
|
||||||
|
return nil, &UnsupportedPlatformError{
|
||||||
|
errors.New("keyboard source type not supported")}
|
||||||
|
}
|
||||||
|
if availableDeviceTypes&devicePointer == 0 {
|
||||||
|
return nil, &UnsupportedPlatformError{
|
||||||
|
errors.New("pointer source type not supported")}
|
||||||
}
|
}
|
||||||
inVardict := make(map[string]dbus.Variant)
|
inVardict := make(map[string]dbus.Variant)
|
||||||
inVardict["session_handle_token"] = dbus.MakeVariant("t")
|
inVardict["session_handle_token"] = dbus.MakeVariant("t")
|
||||||
|
|
@ -110,6 +141,12 @@ func InitPortalController() (Controller, error) {
|
||||||
sessionHandle := dbus.ObjectPath(sessionHandleS)
|
sessionHandle := dbus.ObjectPath(sessionHandleS)
|
||||||
inVardict = make(map[string]dbus.Variant)
|
inVardict = make(map[string]dbus.Variant)
|
||||||
inVardict["types"] = dbus.MakeVariant(deviceKeyboard | devicePointer)
|
inVardict["types"] = dbus.MakeVariant(deviceKeyboard | devicePointer)
|
||||||
|
if restoreToken != "" {
|
||||||
|
inVardict["restore_token"] = dbus.MakeVariant(restoreToken)
|
||||||
|
}
|
||||||
|
if saveRestoreToken {
|
||||||
|
inVardict["persist_mode"] = dbus.MakeVariant(untilRevoked)
|
||||||
|
}
|
||||||
result, outVardict, err = getResponse(bus, remoteDesktop,
|
result, outVardict, err = getResponse(bus, remoteDesktop,
|
||||||
"org.freedesktop.portal.RemoteDesktop.SelectDevices", 0, sessionHandle, inVardict)
|
"org.freedesktop.portal.RemoteDesktop.SelectDevices", 0, sessionHandle, inVardict)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -128,6 +165,17 @@ func InitPortalController() (Controller, error) {
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
return nil, errors.New("keyboard or pointer access denied")
|
return nil, errors.New("keyboard or pointer access denied")
|
||||||
}
|
}
|
||||||
|
if saveRestoreToken {
|
||||||
|
restoreToken, ok := outVardict["restore_token"].Value().(string)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Failed to get new restore token")
|
||||||
|
} else {
|
||||||
|
err := os.WriteFile(restoreTokenFilePath, []byte(restoreToken), 0644)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Join(errors.New("Failed to write restore token: "), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
devicesV, ok := outVardict["devices"]
|
devicesV, ok := outVardict["devices"]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, &UnsupportedPlatformError{
|
return nil, &UnsupportedPlatformError{
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func init() {
|
||||||
RegisterController("uinput", InitUinputController, 10)
|
RegisterController("uinput", InitUinputController, 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitUinputController() (Controller, error) {
|
func InitUinputController(saveRestoreToken bool) (Controller, error) {
|
||||||
keymapName, keymapSet := os.LookupEnv("REMOTE_TOUCHPAD_UINPUT_KEYMAP")
|
keymapName, keymapSet := os.LookupEnv("REMOTE_TOUCHPAD_UINPUT_KEYMAP")
|
||||||
if !keymapSet {
|
if !keymapSet {
|
||||||
keymapName = "defkeymap"
|
keymapName = "defkeymap"
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ func init() {
|
||||||
RegisterController("Windows", InitWindowsController, 0)
|
RegisterController("Windows", InitWindowsController, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitWindowsController() (Controller, error) {
|
func InitWindowsController(saveRestoreToken bool) (Controller, error) {
|
||||||
p := &windowsController{}
|
p := &windowsController{}
|
||||||
if err := sendInputProc.Find(); err != nil {
|
if err := sendInputProc.Find(); err != nil {
|
||||||
return nil, &UnsupportedPlatformError{err}
|
return nil, &UnsupportedPlatformError{err}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ func init() {
|
||||||
RegisterController("X11", InitX11Controller, 0)
|
RegisterController("X11", InitX11Controller, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitX11Controller() (Controller, error) {
|
func InitX11Controller(saveRestoreToken bool) (Controller, error) {
|
||||||
display := C.XOpenDisplay(nil)
|
display := C.XOpenDisplay(nil)
|
||||||
if display == nil {
|
if display == nil {
|
||||||
return nil, &UnsupportedPlatformError{
|
return nil, &UnsupportedPlatformError{
|
||||||
|
|
|
||||||
5
main.go
5
main.go
|
|
@ -152,7 +152,7 @@ func secureRandBase64(length int) string {
|
||||||
func main() {
|
func main() {
|
||||||
terminal.SetTitle(prettyAppName)
|
terminal.SetTitle(prettyAppName)
|
||||||
var bind, certFile, keyFile, secret string
|
var bind, certFile, keyFile, secret string
|
||||||
var showVersion bool
|
var showVersion, savePlaintextRestoreToken bool
|
||||||
var config config
|
var config config
|
||||||
flag.BoolVar(&showVersion, "version", false, "show program's version number and exit")
|
flag.BoolVar(&showVersion, "version", false, "show program's version number and exit")
|
||||||
flag.StringVar(&bind, "bind", defaultBind, "bind server to [HOSTNAME]:PORT")
|
flag.StringVar(&bind, "bind", defaultBind, "bind server to [HOSTNAME]:PORT")
|
||||||
|
|
@ -164,6 +164,7 @@ func main() {
|
||||||
flag.Float64Var(&config.ScrollSpeed, "scroll-speed", 1, "scroll speed multiplier")
|
flag.Float64Var(&config.ScrollSpeed, "scroll-speed", 1, "scroll speed multiplier")
|
||||||
flag.Float64Var(&config.MouseMoveSpeed, "mouse-move-speed", 1, "mouse move speed multiplier")
|
flag.Float64Var(&config.MouseMoveSpeed, "mouse-move-speed", 1, "mouse move speed multiplier")
|
||||||
flag.Float64Var(&config.MouseScrollSpeed, "mouse-scroll-speed", 1, "mouse scroll speed multiplier")
|
flag.Float64Var(&config.MouseScrollSpeed, "mouse-scroll-speed", 1, "mouse scroll speed multiplier")
|
||||||
|
flag.BoolVar(&savePlaintextRestoreToken, "save-plaintext-restore-token", false, "save a restore token in plaintext in order to avoid the confirmation dialogue that appears with some implementations of the portals backend on wayland on linux from appearing on the next run of remote-touchpad")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if showVersion {
|
if showVersion {
|
||||||
fmt.Println(version)
|
fmt.Println(version)
|
||||||
|
|
@ -188,7 +189,7 @@ func main() {
|
||||||
for _, controllerInfo := range inputcontrol.Controllers {
|
for _, controllerInfo := range inputcontrol.Controllers {
|
||||||
controllerName = controllerInfo.Name
|
controllerName = controllerInfo.Name
|
||||||
var err error
|
var err error
|
||||||
controller, err = controllerInfo.Init()
|
controller, err = controllerInfo.Init(savePlaintextRestoreToken)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue