diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 07c477a..0000000 --- a/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Binaries -remote-touchpad - -# Systemd service state -.remote-touchpad.service.state - -# Logs and run files -.rts-log - -# Environment files -.env \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e59454c..8df847c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,5 @@ # Changelog -## 1.5.4 (2026-08-02) - -* Improve X11 keyboard input -* Update dependencies - -## 1.5.3 (2025-12-24) - -* Update dependencies - ## 1.5.2 (2025-10-12) * Update dependencies diff --git a/README.md b/README.md index e039950..fd05b7a 100644 --- a/README.md +++ b/README.md @@ -23,35 +23,6 @@ Supports Flatpak's RemoteDesktop portal (for Wayland), Windows and X11. go install github.com/unrud/remote-touchpad@latest ``` -## Linux User Service Installation - -To install remote-touchpad as a user-specific systemd service (no root access required): - -1. Clone the repository and navigate to the project directory: - - ```sh - git clone https://github.com/Unrud/remote-touchpad.git - cd remote-touchpad - ``` - -2. Install the service using the provided wrapper script (no sudo required): - - ```sh - ./rts install - ``` - -3. Access the service: - - * View service status: `./rts status` - * Get URL: `./rts url` - * View logs: `./rts log` - * Stop service: `./rts stop` - * Start service: `./rts start` - * Restart service: `./rts restart` - * Uninstall: `./rts uninstall` - -The service will run in the background and maintain a persistent connection with URL and QR code accessible via the `url` command. - ## Screenshots ![screenshot 1](https://raw.githubusercontent.com/Unrud/remote-touchpad/master/screenshots/1.png) diff --git a/desktop/com.github.unrud.RemoteTouchpad.metainfo.xml b/desktop/com.github.unrud.RemoteTouchpad.metainfo.xml index 113ef4d..9c85e89 100644 --- a/desktop/com.github.unrud.RemoteTouchpad.metainfo.xml +++ b/desktop/com.github.unrud.RemoteTouchpad.metainfo.xml @@ -23,21 +23,6 @@ Unrud - - -
    -
  • Improve X11 keyboard input
  • -
  • Update dependencies
  • -
-
-
- - -
    -
  • Update dependencies
  • -
-
-
    @@ -373,16 +358,16 @@ - https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.4/screenshots/1.png + https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.2/screenshots/1.png - https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.4/screenshots/2.png + https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.2/screenshots/2.png - https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.4/screenshots/3.png + https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.2/screenshots/3.png - https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.4/screenshots/4.png + https://raw.githubusercontent.com/Unrud/remote-touchpad/v1.5.2/screenshots/4.png diff --git a/flatpak/com.github.unrud.RemoteTouchpad.yaml b/flatpak/com.github.unrud.RemoteTouchpad.yaml index 239160e..54e8e97 100644 --- a/flatpak/com.github.unrud.RemoteTouchpad.yaml +++ b/flatpak/com.github.unrud.RemoteTouchpad.yaml @@ -17,8 +17,8 @@ modules: path: .. - type: git url: https://github.com/godbus/dbus - tag: v5.2.2 - commit: a8ac15ba63645f02ffd57f4b443203279ab40b30 + tag: v5.1.0 + commit: e523abc905595cf17fb0001a7d77eaaddfaa216d dest: vendor/github.com/godbus/dbus/v5 - type: git url: https://github.com/skip2/go-qrcode @@ -26,14 +26,14 @@ modules: dest: vendor/github.com/skip2/go-qrcode - type: git url: https://github.com/golang/net - tag: v0.57.0 - commit: b8f09f6f062ceb4531b7af4bd17a5c8fe9c4b2b5 + tag: v0.46.0 + commit: 2002a064a49010d8b881673c73f04e0b741e7c32 dest: vendor/golang.org/x/net - type: git - url: https://github.com/golang/sys - tag: v0.47.0 - commit: 9e7e939dcafac07e8ab4cffa6e5fc74908413f00 - dest: vendor/golang.org/x/sys + url: https://github.com/golang/crypto + tag: v0.43.0 + commit: 627cb894b6b2021e34c4ad4af4c0a963127491e4 + dest: vendor/golang.org/x/crypto - type: file path: modules.txt dest: vendor diff --git a/flatpak/modules.txt b/flatpak/modules.txt index 6092904..cb7ea3f 100644 --- a/flatpak/modules.txt +++ b/flatpak/modules.txt @@ -1,17 +1,17 @@ # github.com/bendahl/uinput v1.7.0 ## explicit; go 1.13 github.com/bendahl/uinput -# github.com/godbus/dbus/v5 v5.2.2 -## explicit; go 1.20 +# github.com/godbus/dbus/v5 v5.1.0 +## explicit; go 1.12 github.com/godbus/dbus/v5 # github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e ## explicit; go 1.13 github.com/skip2/go-qrcode github.com/skip2/go-qrcode/bitset github.com/skip2/go-qrcode/reedsolomon -# golang.org/x/net v0.57.0 -## explicit; go 1.25.0 +# golang.org/x/crypto v0.43.0 +## explicit; go 1.24.0 +golang.org/x/crypto/hkdf +# golang.org/x/net v0.46.0 +## explicit; go 1.24.0 golang.org/x/net/websocket -# golang.org/x/sys v0.47.0 -## explicit; go 1.25.0 -golang.org/x/sys/unix diff --git a/go.mod b/go.mod index 5afd19d..75e1e34 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,13 @@ module github.com/unrud/remote-touchpad -go 1.25.5 +go 1.24.0 + +toolchain go1.24.8 require ( github.com/bendahl/uinput v1.7.0 - github.com/godbus/dbus/v5 v5.2.2 + github.com/godbus/dbus/v5 v5.1.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e - golang.org/x/net v0.57.0 + golang.org/x/crypto v0.43.0 + golang.org/x/net v0.46.0 ) - -require golang.org/x/sys v0.47.0 // indirect diff --git a/go.sum b/go.sum index 783b4df..736cffa 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,10 @@ github.com/bendahl/uinput v1.7.0 h1:nA4fm8Wu8UYNOPykIZm66nkWEyvxzfmJ8YC02PM40jg= github.com/bendahl/uinput v1.7.0/go.mod h1:Np7w3DINc9wB83p12fTAM3DPPhFnAKP0WTXRqCQJ6Z8= -github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= -github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= -golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= +golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= +golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= +golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= diff --git a/host.go b/host.go index 622b3bf..54874e5 100644 --- a/host.go +++ b/host.go @@ -74,8 +74,7 @@ func findDefaultHost() string { continue } for _, linkLocalPrefix := range []string{ - "169.254.", "fe8", "fe9", "fea", "feb", - } { + "169.254.", "fe8", "fe9", "fea", "feb"} { if strings.HasPrefix(ip.String(), linkLocalPrefix) { addIP(20, ip) continue addrs diff --git a/inputcontrol/controller.go b/inputcontrol/controller.go index 111e937..06ed8e4 100644 --- a/inputcontrol/controller.go +++ b/inputcontrol/controller.go @@ -21,10 +21,8 @@ package inputcontrol import "sort" -type ( - PointerButton int - Key int -) +type PointerButton int +type Key int const ( PointerButtonLeft PointerButton = iota diff --git a/inputcontrol/controller_portal.go b/inputcontrol/controller_portal.go index 99ecf8b..7ee2f81 100644 --- a/inputcontrol/controller_portal.go +++ b/inputcontrol/controller_portal.go @@ -24,7 +24,6 @@ package inputcontrol import ( "crypto/aes" "crypto/cipher" - "crypto/hkdf" "crypto/rand" "crypto/sha256" "errors" @@ -36,6 +35,7 @@ import ( "slices" "github.com/godbus/dbus/v5" + "golang.org/x/crypto/hkdf" ) const ( @@ -88,14 +88,12 @@ func InitPortalController() (Controller, error) { "org.freedesktop.portal.RemoteDesktop.version") if err != nil { return nil, &UnsupportedPlatformError{ - fmt.Errorf("getting 'version' failed: %w", err), - } + fmt.Errorf("getting 'version' failed: %w", err)} } remoteDesktopVersion, ok := remoteDesktopVersionV.Value().(uint32) if !ok { return nil, &UnsupportedPlatformError{ - errors.New("unexpected 'version' type"), - } + errors.New("unexpected 'version' type")} } restoreTokenStore, err := func() (*secretStore, error) { if remoteDesktopVersion < 2 { @@ -105,7 +103,7 @@ func InitPortalController() (Controller, error) { if err != nil { return nil, err } - if err := os.MkdirAll(cacheDirectory, 0o700); err != nil { + if err := os.MkdirAll(cacheDirectory, 0700); err != nil { return nil, err } secret, err := retrieveSecret(bus) @@ -122,20 +120,17 @@ func InitPortalController() (Controller, error) { "org.freedesktop.portal.RemoteDesktop.AvailableDeviceTypes") if err != nil { return nil, &UnsupportedPlatformError{ - fmt.Errorf("getting 'AvailableDeviceTypes' failed: %w", err), - } + fmt.Errorf("getting 'AvailableDeviceTypes' failed: %w", err)} } availableDeviceTypes, ok := availableDeviceTypesV.Value().(uint32) if !ok { return nil, &UnsupportedPlatformError{ - errors.New("unexpected 'AvailableDeviceTypes' return type"), - } + errors.New("unexpected 'AvailableDeviceTypes' return type")} } if availableDeviceTypes&deviceKeyboard == 0 || availableDeviceTypes&devicePointer == 0 { return nil, &UnsupportedPlatformError{ - errors.New("keyboard or pointer source type not supported"), - } + errors.New("keyboard or pointer source type not supported")} } createSessionResults, err := checkResponse(getResponse(bus, portalDesktop, "org.freedesktop.portal.RemoteDesktop.CreateSession", 0, @@ -143,14 +138,12 @@ func InitPortalController() (Controller, error) { )) if err != nil { return nil, &UnsupportedPlatformError{ - fmt.Errorf("calling 'CreateSession' failed: %w", err), - } + fmt.Errorf("calling 'CreateSession' failed: %w", err)} } sessionHandleString, ok := createSessionResults["session_handle"].Value().(string) if !ok { return nil, &UnsupportedPlatformError{ - errors.New("unexpected 'session_handle' type in 'CreateSession' return value"), - } + errors.New("unexpected 'session_handle' type in 'CreateSession' return value")} } sessionHandle := dbus.ObjectPath(sessionHandleString) selectDevicesOptions := map[string]dbus.Variant{ @@ -172,8 +165,7 @@ func InitPortalController() (Controller, error) { )) if err != nil { return nil, &UnsupportedPlatformError{ - fmt.Errorf("calling 'SelectDevices' failed: %w", err), - } + fmt.Errorf("calling 'SelectDevices' failed: %w", err)} } startResponseStatus, startResults, err := getResponse(bus, portalDesktop, "org.freedesktop.portal.RemoteDesktop.Start", 0, @@ -181,8 +173,7 @@ func InitPortalController() (Controller, error) { ) if err != nil { return nil, &UnsupportedPlatformError{ - fmt.Errorf("calling 'Start' failed: %w", err), - } + fmt.Errorf("calling 'Start' failed: %w", err)} } if startResponseStatus != 0 { return nil, errors.New("keyboard or pointer access denied") @@ -195,17 +186,14 @@ func InitPortalController() (Controller, error) { devices, ok := startResults["devices"].Value().(uint32) if !ok { return nil, &UnsupportedPlatformError{ - errors.New("unexpected 'devices' type in 'Start' return value"), - } + errors.New("unexpected 'devices' type in 'Start' return value")} } if devices&deviceKeyboard == 0 || devices&devicePointer == 0 { return nil, errors.New("keyboard or pointer access denied") } cleanupBus = false - return &portalController{ - bus: bus, portalDesktop: portalDesktop, - sessionHandle: sessionHandle, - }, nil + return &portalController{bus: bus, portalDesktop: portalDesktop, + sessionHandle: sessionHandle}, nil } func retrieveSecret(bus *dbus.Conn) ([]byte, error) { @@ -242,8 +230,9 @@ type secretStore struct { } func newSecretStore(key []byte, filename string) (*secretStore, error) { - derivedKey, err := hkdf.Key(sha256.New, key, nil, "", 32) - if err != nil { + hkdf := hkdf.New(sha256.New, key, nil, nil) + derivedKey := make([]byte, 32) + if _, err := io.ReadFull(hkdf, derivedKey); err != nil { return nil, err } block, err := aes.NewCipher(derivedKey) @@ -279,12 +268,11 @@ func (s *secretStore) Store(data []byte) error { return err } ciphertext := s.aesgcm.Seal(nil, nonce, data, nil) - return os.WriteFile(s.filename, slices.Concat(nonce, ciphertext), 0o600) + return os.WriteFile(s.filename, slices.Concat(nonce, ciphertext), 0600) } func getResponse(bus *dbus.Conn, object dbus.BusObject, method string, - flags dbus.Flags, args ...interface{}, -) (uint32, map[string]dbus.Variant, error) { + flags dbus.Flags, args ...interface{}) (uint32, map[string]dbus.Variant, error) { ch := make(chan *dbus.Signal, 512) bus.Signal(ch) defer bus.RemoveSignal(ch) diff --git a/inputcontrol/controller_uinput.go b/inputcontrol/controller_uinput.go index 2dd9bab..df51e65 100644 --- a/inputcontrol/controller_uinput.go +++ b/inputcontrol/controller_uinput.go @@ -25,11 +25,10 @@ package inputcontrol import ( "errors" "fmt" + "github.com/bendahl/uinput" "log" "os" "time" - - "github.com/bendahl/uinput" ) const shiftKeysDelay time.Duration = 50 * time.Millisecond diff --git a/inputcontrol/controller_x11.go b/inputcontrol/controller_x11.go index f45b75b..bb37d37 100644 --- a/inputcontrol/controller_x11.go +++ b/inputcontrol/controller_x11.go @@ -32,12 +32,9 @@ package inputcontrol // return DefaultRootWindow(dpy); // } import "C" - import ( "errors" "fmt" - "maps" - "slices" "strings" "sync" "time" @@ -45,18 +42,12 @@ import ( ) const ( - keyboardMappingDelay time.Duration = 200 * time.Millisecond + keyboardMappingDelay time.Duration = 500 * time.Millisecond scrollDiv int = 20 ) -var modifierIndexes = [...]int{ - C.ShiftMapIndex, - C.Mod1MapIndex, - C.Mod2MapIndex, - C.Mod3MapIndex, - C.Mod4MapIndex, - C.Mod5MapIndex, -} +var modifierIndices [6]uint = [...]uint{C.ShiftMapIndex, C.Mod1MapIndex, + C.Mod2MapIndex, C.Mod3MapIndex, C.Mod4MapIndex, C.Mod5MapIndex} type x11Controller struct { display *C.Display @@ -72,15 +63,13 @@ func InitX11Controller() (Controller, error) { display := C.XOpenDisplay(nil) if display == nil { return nil, &UnsupportedPlatformError{ - errors.New("failed to connect to X server"), - } + errors.New("failed to connect to X server")} } p := &x11Controller{display: display} if p.xIsXwayland() { p.Close() return nil, &UnsupportedPlatformError{ - errors.New("X server is Xwayland"), - } + errors.New("X server is Xwayland")} } return p, nil } @@ -124,68 +113,53 @@ func (p *x11Controller) Close() error { return nil } -func (p *x11Controller) findEmptyKeycodeLocked() (keycode C.KeyCode, keysymsPerKeycode int, err error) { +func (p *x11Controller) findEmptyKeycodeLocked() (C.KeyCode, C.int, error) { var minKeycodes, maxKeycodes C.int C.XDisplayKeycodes(p.display, &minKeycodes, &maxKeycodes) - var keysymsPerKeycodeC C.int - keysyms := C.XGetKeyboardMapping( - p.display, - C.KeyCode(minKeycodes), - maxKeycodes-minKeycodes+1, - &keysymsPerKeycodeC, - ) + var keysymsPerKeycode C.int + keysyms := C.XGetKeyboardMapping(p.display, C.KeyCode(minKeycodes), + maxKeycodes-minKeycodes+1, &keysymsPerKeycode) if keysyms == nil { return 0, 0, errors.New("failed to get keyboard mapping") } defer C.XFree(unsafe.Pointer(keysyms)) - keysymsPerKeycode = int(keysymsPerKeycodeC) keycodes: - for keycode := int(minKeycodes); keycode <= int(maxKeycodes); keycode++ { - for i := range keysymsPerKeycode { - keysymsIndex := (keycode-int(minKeycodes))*keysymsPerKeycode + i - keysym := *(*C.KeySym)(unsafe.Pointer( - uintptr(unsafe.Pointer(keysyms)) + - uintptr(keysymsIndex)*unsafe.Sizeof(*keysyms), - )) + for keycode := C.KeyCode(minKeycodes); keycode <= C.KeyCode(maxKeycodes); keycode++ { + for i := 0; i < int(keysymsPerKeycode); i++ { + keysymsIndex := int(keycode- + C.KeyCode(minKeycodes))*int(keysymsPerKeycode) + i + keysym := *(*C.KeySym)(unsafe.Pointer(uintptr(unsafe.Pointer(keysyms)) + + uintptr(keysymsIndex)*unsafe.Sizeof(*keysyms))) if keysym != 0 { continue keycodes } } - return C.KeyCode(keycode), keysymsPerKeycode, nil + return keycode, keysymsPerKeycode, nil } return 0, 0, errors.New("no empty keycode found") } -func (p *x11Controller) changeKeyMappingLocked( - keycode C.KeyCode, keysymsPerKeycode int, keysym Keysym, -) { +func (p *x11Controller) changeKeyMappingLocked(keysymsPerKeycode C.int, + keycode C.KeyCode, keysym Keysym) { keycodeMapping := make([]C.KeySym, keysymsPerKeycode) for i := range keycodeMapping { keycodeMapping[i] = C.KeySym(keysym) } - C.XChangeKeyboardMapping( - p.display, - C.int(keycode), - C.int(keysymsPerKeycode), - (*C.KeySym)(unsafe.Pointer(&keycodeMapping[0])), - 1, - ) - C.XSync(p.display, C.False) + C.XChangeKeyboardMapping(p.display, C.int(keycode), keysymsPerKeycode, + (*C.KeySym)(unsafe.Pointer(&keycodeMapping[0])), 1) + C.XFlush(p.display) } func (p *x11Controller) getModKeycodesLocked() map[uint]C.KeyCode { modKeymap := C.XGetModifierMapping(p.display) defer C.XFreeModifiermap(modKeymap) modKeycodes := make(map[uint]C.KeyCode) - for _, modIndex := range modifierIndexes { - for i := range int(modKeymap.max_keypermod) { - keycodeIndex := modIndex*int(modKeymap.max_keypermod) + i - keycode := *(*C.KeyCode)(unsafe.Pointer( - uintptr(unsafe.Pointer(modKeymap.modifiermap)) + - uintptr(keycodeIndex)*unsafe.Sizeof(*modKeymap.modifiermap), - )) + for _, modIndex := range modifierIndices { + for i := 0; i < int(modKeymap.max_keypermod); i++ { + keycode := *(*C.KeyCode)(unsafe.Pointer(uintptr(unsafe.Pointer(modKeymap.modifiermap)) + + uintptr(uint(modIndex)*uint(modKeymap.max_keypermod)+uint(i)))) if keycode != 0 { - modKeycodes[1< /dev/null; then - echo "Error: Go is not installed. Please install Go first." - return 1 - fi - - echo "Building remote-touchpad binary..." - go build -tags portal,uinput,x11 -o remote-touchpad - - if [ ! -f "remote-touchpad" ]; then - echo "Error: Failed to build remote-touchpad binary" - return 1 - fi - - # Setup directories - mkdir -p ~/.local/bin ~/.config/systemd/user - - echo "Installing service files..." - cp remote-touchpad ~/.local/bin/ || echo "Error: cp to ~/.local/bin failed" - cp remote-touchpad.service ~/.config/systemd/user/ || echo "Error: cp to ~/.config/systemd/user failed" - - echo "Enabling and starting service..." - systemctl --user daemon-reload - systemctl --user enable --now ${SERVICE_NAME}.service - - echo "✓ remote-touchpad user service installed and started" - echo "" - echo "Use './rts status' to check the service" - echo "Use './rts url' to get the connection URL" -} - -start() { - systemctl --user start ${SERVICE_NAME}.service - echo "Started remote-touchpad service" -} - -stop() { - systemctl --user stop ${SERVICE_NAME}.service - echo "Stopped remote-touchpad service" -} - -status() { - systemctl --user status ${SERVICE_NAME}.service --no-pager -} - -restart() { - systemctl --user restart ${SERVICE_NAME}.service - echo "Restarted remote-touchpad service" -} - -url() { - # Extract URL from service logs - echo "Fetching remote-touchpad URL..." - local url=$(journalctl --user -u ${SERVICE_NAME}.service -n 100 --no-pager 2>/dev/null | grep -oE "http://[^ ]+|https://[^ ]+" | tail -1) - if [ -n "$url" ]; then - echo "Remote Touchpad URL: $url" - # Generate QR code if qrencode is available - if command -v qrencode &> /dev/null; then - echo "Generating QR code..." - echo "$url" | qrencode -t ansiutf8 - else - echo "QR code generation requires qrencode. Install it with:" - echo " sudo apt-get install qrencode # Debian/Ubuntu" - echo " sudo dnf install qrencode # Fedora" - echo " brew install qrencode # macOS" - fi - else - echo "Could not find URL in service logs. Is the service running?" - fi -} - -log() { - echo "Viewing remote-touchpad service logs..." - journalctl --user -u ${SERVICE_NAME}.service --no-pager -} - -uninstall() { - echo "Uninstalling remote-touchpad..." - systemctl --user stop ${SERVICE_NAME}.service - systemctl --user disable ${SERVICE_NAME}.service - rm -f ~/.config/systemd/user/${SERVICE_NAME}.service - rm -f ~/.local/bin/remote-touchpad - systemctl --user daemon-reload - echo "✓ remote-touchpad uninstalled" -} - -help() { - echo "Remote Touchpad CLI Wrapper" - echo "" - echo "Usage: rts [command]" - echo "" - echo "Commands:" - echo " install - Install remote-touchpad as a systemd user service" - echo " start - Start the remote-touchpad service" - echo " stop - Stop the remote-touchpad service" - echo " status - Check service status" - echo " restart - Restart the service" - echo " url - Show the remote-touchpad URL" - echo " log - View service logs" - echo " uninstall - Uninstall the service" - echo " help - Show this help message" -} - -# Main command handler -case "$1" in - install) - install - ;; - start) - start - ;; - stop) - stop - ;; - status) - status - ;; - restart) - restart - ;; - url) - url - ;; - log) - log - ;; - uninstall) - uninstall - ;; - help|--help|-h|"") - help - ;; - *) - echo "Unknown command: $1" - help - exit 1 - ;; -esac diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 6d23326..677f302 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,21 +1,17 @@ -# Build by running `snapcraft`. +# Build by running "snapcraft". # WARNING: # Snapcraft uses caching for already build steps but it's buggy and can cause strange problems. -# Clean the cache by running `snapcraft clean`. +# Clean the cache by running "snapcraft clean". name: remote-touchpad license: GPL-3.0+ grade: stable adopt-info: remote-touchpad -base: core24 +base: core22 confinement: strict -platforms: - amd64: - arm64: - apps: remote-touchpad: command: bin/remote-touchpad @@ -52,6 +48,10 @@ parts: - libxt6 - libxrandr2 - libxtst6 + override-pull: | + craftctl default + # WORKAROUND: Point icon directly to SVG otherwise snapcraft can't find it + sed -e 's|Icon=com.github.unrud.RemoteTouchpad|Icon=/usr/share/icons/hicolor/scalable/apps/com.github.unrud.RemoteTouchpad.svg|' -i desktop/com.github.unrud.RemoteTouchpad.desktop override-build: | craftctl default install -Dm0755 -t "${CRAFT_PART_INSTALL}/bin" desktop/remote-touchpad-wait-on-error