remote-touchpad/inputcontrol/controller_uinput.go

220 lines
5.5 KiB
Go

//go:build uinput
/*
* Copyright (c) 2023 De_Coder github.com/ps100000
* Copyright (c) 2023 Unrud <unrud@outlook.com>
*
* This file is part of Remote-Touchpad.
*
* Remote-Touchpad is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Remote-Touchpad is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Remote-Touchpad. If not, see <http://www.gnu.org/licenses/>.
*/
package inputcontrol
import (
"fmt"
"github.com/bendahl/uinput"
"unicode"
)
var ukeysMap = map[rune]int{
'a': uinput.KeyA,
'b': uinput.KeyB,
'c': uinput.KeyC,
'd': uinput.KeyD,
'e': uinput.KeyE,
'f': uinput.KeyF,
'g': uinput.KeyG,
'h': uinput.KeyH,
'i': uinput.KeyI,
'j': uinput.KeyJ,
'k': uinput.KeyK,
'l': uinput.KeyL,
'm': uinput.KeyM,
'n': uinput.KeyN,
'o': uinput.KeyO,
'p': uinput.KeyP,
'q': uinput.KeyQ,
'r': uinput.KeyR,
's': uinput.KeyS,
't': uinput.KeyT,
'u': uinput.KeyU,
'v': uinput.KeyV,
'w': uinput.KeyW,
'x': uinput.KeyX,
'y': uinput.KeyY,
'z': uinput.KeyZ,
'0': uinput.Key0,
'1': uinput.Key1,
'2': uinput.Key2,
'3': uinput.Key3,
'4': uinput.Key4,
'5': uinput.Key5,
'6': uinput.Key6,
'7': uinput.Key7,
'8': uinput.Key8,
'9': uinput.Key9,
0x1b: uinput.KeyEsc,
'-': uinput.KeyMinus,
'+': uinput.KeyKpplus,
'*': uinput.KeyKpasterisk,
'=': uinput.KeyEqual,
0x08: uinput.KeyBackspace,
'\t': uinput.KeyTab,
'(': uinput.KeyLeftbrace,
')': uinput.KeyRightbrace,
'\n': uinput.KeyEnter,
';': uinput.KeySemicolon,
'\'': uinput.KeyApostrophe,
'`': uinput.KeyGrave,
'\\': uinput.KeyBackslash,
',': uinput.KeyComma,
'.': uinput.KeyDot,
'/': uinput.KeySlash,
' ': uinput.KeySpace,
}
type uinputController struct {
keyboard uinput.Keyboard
mouse uinput.Mouse
}
func init() {
RegisterController("uinput", InitUinputController, 0)
}
func InitUinputController() (Controller, error) {
keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("remote-touchpad-keyboard"))
if err != nil {
return nil, err
}
mouse, err := uinput.CreateMouse("/dev/uinput", []byte("remote-touchpad-mouse"))
if err != nil {
keyboard.Close()
return nil, err
}
return &uinputController{keyboard, mouse}, nil
}
func (p *uinputController) Close() error {
if err := p.keyboard.Close(); err != nil {
p.mouse.Close()
return err
}
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
}
func (p *uinputController) KeyboardKey(key Key) error {
var uinputKey int
switch key {
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.keyboard.KeyPress(uinputKey)
}
func (p *uinputController) PointerButton(button PointerButton, press bool) error {
switch {
case button == PointerButtonLeft && press:
return p.mouse.LeftPress()
case button == PointerButtonLeft && !press:
return p.mouse.LeftRelease()
case button == PointerButtonRight && press:
return p.mouse.RightPress()
case button == PointerButtonRight && !press:
return p.mouse.RightRelease()
case button == PointerButtonMiddle && press:
return p.mouse.MiddlePress()
case button == PointerButtonMiddle && !press:
return p.mouse.MiddleRelease()
default:
return fmt.Errorf("unsupported pointer button: %#v", button)
}
}
func (p *uinputController) PointerMove(deltaX, deltaY int) error {
return p.mouse.Move(int32(deltaX), int32(deltaY))
}
func (p *uinputController) PointerScroll(deltaHorizontal, deltaVertical int, finish bool) error {
if err := p.mouse.Wheel(false, int32(deltaVertical)); err != nil {
return err
}
return p.mouse.Wheel(true, int32(deltaHorizontal))
}