uinput-controller: Map runes/keys directly and handle errors

This commit is contained in:
Unrud 2023-02-23 01:09:30 +01:00
parent 809d3a0064
commit d254ae5b0d
4 changed files with 150 additions and 129 deletions

View file

@ -2,6 +2,7 @@
/* /*
* Copyright (c) 2023 De_Coder github.com/ps100000 * Copyright (c) 2023 De_Coder github.com/ps100000
* Copyright (c) 2023 Unrud <unrud@outlook.com>
* *
* This file is part of Remote-Touchpad. * This file is part of Remote-Touchpad.
* *
@ -22,83 +23,66 @@
package inputcontrol package inputcontrol
import ( import (
"errors" "fmt"
"github.com/bendahl/uinput" "github.com/bendahl/uinput"
"unicode"
) )
var ukeysMap = map[Keysym]int{ var ukeysMap = map[rune]int{
0x0061: uinput.KeyA, 'a': uinput.KeyA,
0x0062: uinput.KeyB, 'b': uinput.KeyB,
0x0063: uinput.KeyC, 'c': uinput.KeyC,
0x0064: uinput.KeyD, 'd': uinput.KeyD,
0x0065: uinput.KeyE, 'e': uinput.KeyE,
0x0066: uinput.KeyF, 'f': uinput.KeyF,
0x0067: uinput.KeyG, 'g': uinput.KeyG,
0x0068: uinput.KeyH, 'h': uinput.KeyH,
0x0069: uinput.KeyI, 'i': uinput.KeyI,
0x006a: uinput.KeyJ, 'j': uinput.KeyJ,
0x006b: uinput.KeyK, 'k': uinput.KeyK,
0x006c: uinput.KeyL, 'l': uinput.KeyL,
0x006d: uinput.KeyM, 'm': uinput.KeyM,
0x006e: uinput.KeyN, 'n': uinput.KeyN,
0x006f: uinput.KeyO, 'o': uinput.KeyO,
0x0070: uinput.KeyP, 'p': uinput.KeyP,
0x0071: uinput.KeyQ, 'q': uinput.KeyQ,
0x0072: uinput.KeyR, 'r': uinput.KeyR,
0x0073: uinput.KeyS, 's': uinput.KeyS,
0x0074: uinput.KeyT, 't': uinput.KeyT,
0x0075: uinput.KeyU, 'u': uinput.KeyU,
0x0076: uinput.KeyV, 'v': uinput.KeyV,
0x0077: uinput.KeyW, 'w': uinput.KeyW,
0x0078: uinput.KeyX, 'x': uinput.KeyX,
0x0079: uinput.KeyY, 'y': uinput.KeyY,
0x007a: uinput.KeyZ, 'z': uinput.KeyZ,
'0': uinput.Key0,
0x0030: uinput.Key0, '1': uinput.Key1,
0x0031: uinput.Key1, '2': uinput.Key2,
0x0032: uinput.Key2, '3': uinput.Key3,
0x0033: uinput.Key3, '4': uinput.Key4,
0x0034: uinput.Key4, '5': uinput.Key5,
0x0035: uinput.Key5, '6': uinput.Key6,
0x0036: uinput.Key6, '7': uinput.Key7,
0x0037: uinput.Key7, '8': uinput.Key8,
0x0038: uinput.Key8, '9': uinput.Key9,
0x0039: uinput.Key9, 0x1b: uinput.KeyEsc,
'-': uinput.KeyMinus,
0xff1b: uinput.KeyEsc, '+': uinput.KeyKpplus,
0x002d: uinput.KeyMinus, '*': uinput.KeyKpasterisk,
0x002b: uinput.KeyKpplus, '=': uinput.KeyEqual,
0x002a: uinput.KeyKpasterisk, 0x08: uinput.KeyBackspace,
0x003d: uinput.KeyEqual, '\t': uinput.KeyTab,
0xff08: uinput.KeyBackspace, '(': uinput.KeyLeftbrace,
0xff09: uinput.KeyTab, ')': uinput.KeyRightbrace,
0x0028: uinput.KeyLeftbrace, '\n': uinput.KeyEnter,
0x0029: uinput.KeyRightbrace, ';': uinput.KeySemicolon,
0xff0d: uinput.KeyEnter, '\'': uinput.KeyApostrophe,
0x003b: uinput.KeySemicolon, '`': uinput.KeyGrave,
0x0027: uinput.KeyApostrophe, '\\': uinput.KeyBackslash,
0x0060: uinput.KeyGrave, ',': uinput.KeyComma,
0x005c: uinput.KeyBackslash, '.': uinput.KeyDot,
0x002c: uinput.KeyComma, '/': uinput.KeySlash,
0x0abd: uinput.KeyDot, ' ': uinput.KeySpace,
0x002f: uinput.KeySlash,
0x0020: uinput.KeySpace,
0xff50: uinput.KeyHome,
0xff52: uinput.KeyUp,
0xff51: uinput.KeyLeft,
0xff53: uinput.KeyRight,
0xff57: uinput.KeyEnd,
0xff54: uinput.KeyDown,
0xffff: uinput.KeyDelete,
0x1008FF12: uinput.KeyMute,
0x1008FF11: uinput.KeyVolumedown,
0x1008FF13: uinput.KeyVolumeup,
0xffeb: uinput.KeyLeftmeta,
0x1008ff26: uinput.KeyBack,
0x1008ff27: uinput.KeyForward,
0x1008ff17: uinput.KeyNextsong,
0x1008ff14: uinput.KeyPlaypause,
0x1008ff16: uinput.KeyPrevioussong,
} }
type uinputController struct { type uinputController struct {
@ -107,93 +91,130 @@ type uinputController struct {
} }
func init() { func init() {
RegisterController("Uinput", InitUinputController, 0) RegisterController("uinput", InitUinputController, 0)
} }
func InitUinputController() (Controller, error) { func InitUinputController() (Controller, error) {
keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("remote-tp-keyboard")) keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("remote-touchpad-keyboard"))
if err != nil { if err != nil {
return nil, err return nil, err
} }
mouse, err := uinput.CreateMouse("/dev/uinput", []byte("remote-tp-mouse")) mouse, err := uinput.CreateMouse("/dev/uinput", []byte("remote-touchpad-mouse"))
if err != nil { if err != nil {
keyboard.Close() keyboard.Close()
return nil, err return nil, err
} }
p := &uinputController{keyboard, mouse} return &uinputController{keyboard, mouse}, nil
return p, nil
} }
func (p *uinputController) Close() error { func (p *uinputController) Close() error {
p.keyboard.Close() if err := p.keyboard.Close(); err != nil {
p.mouse.Close() p.mouse.Close()
return nil
}
func (p *uinputController) sendKeysym(sym Keysym) error {
if sym >= 0x0041 && sym <= 0x005a { // capital letters
p.keyboard.KeyDown(uinput.KeyLeftshift)
p.keyboard.KeyPress(ukeysMap[sym+0x20])
p.keyboard.KeyUp(uinput.KeyLeftshift)
} else if key, ok := ukeysMap[sym]; ok {
p.keyboard.KeyPress(key)
}
return nil
}
func (p *uinputController) KeyboardText(text string) error {
for _, runeValue := range text {
keysym, err := RuneToKeysym(runeValue)
if err != nil {
return err return err
} }
err = p.sendKeysym(keysym) return p.mouse.Close()
}
// No support for keyboard layouts, only works with QWERTY
func (p *uinputController) KeyboardText(text string) error {
for _, runeValue := range text {
modifierShift := false
if unicode.IsUpper(runeValue) {
modifierShift = true
runeValue = unicode.ToLower(runeValue)
}
uinputKey, found := ukeysMap[runeValue]
if !found {
return fmt.Errorf("unsupported rune: %q", runeValue)
}
if modifierShift {
if err := p.keyboard.KeyDown(uinput.KeyLeftshift); err != nil {
return err
}
}
if err := p.keyboard.KeyPress(uinputKey); err != nil {
return err
}
if modifierShift {
if err := p.keyboard.KeyUp(uinput.KeyLeftshift); err != nil {
return err
}
}
} }
return nil return nil
} }
func (p *uinputController) KeyboardKey(key Key) error { func (p *uinputController) KeyboardKey(key Key) error {
keysym, err := KeyToKeysym(key) var uinputKey int
if err != nil { switch key {
return err case KeyBackSpace:
uinputKey = uinput.KeyBackspace
case KeyReturn:
uinputKey = uinput.KeyEnter
case KeyDelete:
uinputKey = uinput.KeyDelete
case KeyHome:
uinputKey = uinput.KeyHome
case KeyLeft:
uinputKey = uinput.KeyLeft
case KeyUp:
uinputKey = uinput.KeyUp
case KeyRight:
uinputKey = uinput.KeyRight
case KeyDown:
uinputKey = uinput.KeyDown
case KeyEnd:
uinputKey = uinput.KeyEnd
case KeySuper:
uinputKey = uinput.KeyLeftmeta
case KeyVolumeMute:
uinputKey = uinput.KeyMute
case KeyVolumeDown:
uinputKey = uinput.KeyVolumedown
case KeyVolumeUp:
uinputKey = uinput.KeyVolumeup
case KeyMediaPlayPause:
uinputKey = uinput.KeyPlaypause
case KeyMediaPrevTrack:
uinputKey = uinput.KeyPrevioussong
case KeyMediaNextTrack:
uinputKey = uinput.KeyNextsong
case KeyBrowserBack:
uinputKey = uinput.KeyBack
case KeyBrowserForward:
uinputKey = uinput.KeyForward
default:
return fmt.Errorf("unsupported key: %#v", key)
} }
return p.sendKeysym(keysym) return p.keyboard.KeyPress(uinputKey)
} }
func (p *uinputController) PointerButton(button PointerButton, press bool) error { func (p *uinputController) PointerButton(button PointerButton, press bool) error {
switch button { switch {
case PointerButtonLeft: case button == PointerButtonLeft && press:
if press { return p.mouse.LeftPress()
p.mouse.LeftPress() case button == PointerButtonLeft && !press:
} else { return p.mouse.LeftRelease()
p.mouse.LeftRelease() case button == PointerButtonRight && press:
} return p.mouse.RightPress()
case PointerButtonRight: case button == PointerButtonRight && !press:
if press { return p.mouse.RightRelease()
p.mouse.RightPress() case button == PointerButtonMiddle && press:
} else { return p.mouse.MiddlePress()
p.mouse.RightRelease() case button == PointerButtonMiddle && !press:
} return p.mouse.MiddleRelease()
case PointerButtonMiddle:
if press {
p.mouse.MiddlePress()
} else {
p.mouse.MiddleRelease()
}
default: default:
return errors.New("unsupported pointer button") return fmt.Errorf("unsupported pointer button: %#v", button)
} }
return nil
} }
func (p *uinputController) PointerMove(deltaX, deltaY int) error { func (p *uinputController) PointerMove(deltaX, deltaY int) error {
p.mouse.Move(int32(deltaX), int32(deltaY)) return p.mouse.Move(int32(deltaX), int32(deltaY))
return nil
} }
func (p *uinputController) PointerScroll(deltaHorizontal, deltaVertical int, finish bool) error { func (p *uinputController) PointerScroll(deltaHorizontal, deltaVertical int, finish bool) error {
p.mouse.Wheel(false, int32(deltaVertical)) if err := p.mouse.Wheel(false, int32(deltaVertical)); err != nil {
p.mouse.Wheel(true, int32(deltaHorizontal)) return err
return nil }
return p.mouse.Wheel(true, int32(deltaHorizontal))
} }

View file

@ -1,5 +1,5 @@
// Code generated by keysyms.generator.go. DO NOT EDIT. // Code generated by keysyms.generator.go. DO NOT EDIT.
//go:build portal || x11 || uinput //go:build portal || x11
package inputcontrol package inputcontrol

View file

@ -102,7 +102,7 @@ func main() {
keysymsMap[unicode] = keysym keysymsMap[unicode] = keysym
} }
content := "// Code generated by keysyms.generator.go. DO NOT EDIT.\n" + content := "// Code generated by keysyms.generator.go. DO NOT EDIT.\n" +
"//go:build portal || x11 || uinput\n\n" + "//go:build portal || x11\n\n" +
"package inputcontrol\n\n" + "package inputcontrol\n\n" +
"var keysymsMap = map[rune]Keysym{\n" "var keysymsMap = map[rune]Keysym{\n"
keys := make([]rune, 0) keys := make([]rune, 0)

View file

@ -1,4 +1,4 @@
//go:build portal || x11 || uinput //go:build portal || x11
/* /*
* Copyright (c) 2018 Unrud <unrud@outlook.com> * Copyright (c) 2018 Unrud <unrud@outlook.com>