Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions server/internal/desktop/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type DesktopManagerCtx struct {
func New(config *config.Desktop) *DesktopManagerCtx {
var input xinput.Driver
if config.UseInputDriver {
log.Info().Str("socket", config.InputSocket).Msg("using xinput driver for scroll")
input = xinput.NewDriver(config.InputSocket)
} else {
input = xinput.NewDummy()
Expand Down
16 changes: 15 additions & 1 deletion server/internal/desktop/xorg.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,21 @@ func (manager *DesktopManagerCtx) GetCursorPosition() (int, int) {
}

func (manager *DesktopManagerCtx) Scroll(deltaX, deltaY int, controlKey bool) {
xorg.Scroll(deltaX, deltaY, controlKey)
if manager.config.UseInputDriver {
// XI2.1 smooth scrolling via xf86-input-neko: set modifier before the
// driver posts the motion event so the X server sees Ctrl held.
if controlKey {
xorg.SetKeyboardModifier(xorg.KbdModControl, true)
defer xorg.SetKeyboardModifier(xorg.KbdModControl, false)
}
if err := manager.input.Scroll(int32(deltaX), int32(deltaY)); err != nil {
manager.logger.Warn().Err(err).Msg("xinput scroll failed, falling back to XTest")
xorg.Scroll(deltaX, deltaY, false)
}
} else {
// XTest fallback — handles controlKey atomically under a single X11 lock
xorg.Scroll(deltaX, deltaY, controlKey)
}
}

func (manager *DesktopManagerCtx) ButtonDown(code uint32) error {
Expand Down
42 changes: 31 additions & 11 deletions server/internal/webrtc/legacyhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package webrtc
import (
"bytes"
"encoding/binary"
"strconv"

"github.com/m1k1o/neko/server/pkg/types"

Expand Down Expand Up @@ -35,6 +34,13 @@ type PayloadScroll struct {
Y int16
}

type PayloadScrollWithCtrl struct {
PayloadHeader
DeltaX int16
DeltaY int16
ControlKey uint8
}

type PayloadKey struct {
PayloadHeader
Key uint64 // TODO: uint32
Expand Down Expand Up @@ -72,18 +78,32 @@ func (manager *WebRTCManagerCtx) handleLegacy(

manager.desktop.Move(int(payload.X), int(payload.Y))
case OP_SCROLL:
payload := &PayloadScroll{}
if err := binary.Read(buffer, binary.LittleEndian, payload); err != nil {
return err
}
if header.Length == 5 {
payload := &PayloadScrollWithCtrl{}
if err := binary.Read(buffer, binary.LittleEndian, payload); err != nil {
return err
}

logger.Trace().
Int16("deltaX", payload.DeltaX).
Int16("deltaY", payload.DeltaY).
Bool("controlKey", payload.ControlKey != 0).
Msg("scroll")

manager.desktop.Scroll(int(payload.DeltaX), int(payload.DeltaY), payload.ControlKey != 0)
} else {
payload := &PayloadScroll{}
if err := binary.Read(buffer, binary.LittleEndian, payload); err != nil {
return err
}

logger.
Trace().
Str("x", strconv.Itoa(int(payload.X))).
Str("y", strconv.Itoa(int(payload.Y))).
Msg("scroll")
logger.Trace().
Int16("x", payload.X).
Int16("y", payload.Y).
Msg("scroll")

manager.desktop.Scroll(int(payload.X), int(payload.Y), false)
manager.desktop.Scroll(int(payload.X), int(payload.Y), false)
}
case OP_KEY_DOWN:
payload := &PayloadKey{}
if err := binary.Read(buffer, binary.LittleEndian, payload); err != nil {
Expand Down
1 change: 0 additions & 1 deletion server/internal/webrtc/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,6 @@ func (manager *WebRTCManagerCtx) CreatePeer(session types.Session) (*webrtc.Sess
//

if viper.GetBool("legacy") {
// handle legacy data channel
dc.OnMessage(func(message webrtc.DataChannelMessage) {
if err := manager.handleLegacy(logger, message.Data, session); err != nil {
logger.Err(err).Msg("data handle failed")
Expand Down
11 changes: 10 additions & 1 deletion server/pkg/xinput/dummy.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package xinput

import "time"
import (
"errors"
"time"
)

var errNotConnected = errors.New("xinput driver not connected")

type dummy struct{}

Expand Down Expand Up @@ -29,3 +34,7 @@ func (d *dummy) TouchUpdate(touchId uint32, x, y int, pressure uint8) error {
func (d *dummy) TouchEnd(touchId uint32, x, y int, pressure uint8) error {
return nil
}

func (d *dummy) Scroll(deltaX, deltaY int32) error {
return errNotConnected
}
4 changes: 4 additions & 0 deletions server/pkg/xinput/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const (
XI_TouchBegin = 18
XI_TouchUpdate = 19
XI_TouchEnd = 20
NEKO_SCROLL = 0x80
)

type Message struct {
Expand Down Expand Up @@ -58,4 +59,7 @@ type Driver interface {
TouchBegin(touchId uint32, x, y int, pressure uint8) error
TouchUpdate(touchId uint32, x, y int, pressure uint8) error
TouchEnd(touchId uint32, x, y int, pressure uint8) error
// scroll via XI2 scroll valuators in the xf86-input-neko driver.
// deltaX/deltaY are in scroll units (120 = one notch).
Scroll(deltaX, deltaY int32) error
}
13 changes: 13 additions & 0 deletions server/pkg/xinput/xinput.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,16 @@ func (d *driver) TouchEnd(touchId uint32, x, y int, pressure uint8) error {
_, err := d.conn.Write(msg.Pack())
return err
}

func (d *driver) Scroll(deltaX, deltaY int32) error {
d.mu.Lock()
defer d.mu.Unlock()

msg := Message{
_type: NEKO_SCROLL,
x: deltaX,
y: deltaY,
}
_, err := d.conn.Write(msg.Pack())
return err
}
8 changes: 4 additions & 4 deletions server/pkg/xorg/xorg.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,16 @@ void XScroll(int deltaX, int deltaY) {

int ydir;
if (deltaY > 0) {
ydir = 4; // button 4 is up
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is needed for scrolling direction

ydir = 5; // positive = scroll down = button 5
} else {
ydir = 5; // button 5 is down
ydir = 4; // negative = scroll up = button 4
}

int xdir;
if (deltaX > 0) {
xdir = 6; // button 6 is right
xdir = 7; // positive = scroll right = button 7
} else {
xdir = 7; // button 7 is left
xdir = 6; // negative = scroll left = button 6
}

for (int i = 0; i < abs(deltaY); i++) {
Expand Down
Loading