Skip to content

Commit

Permalink
Use atomic mouse states
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Mar 10, 2024
1 parent e54bed2 commit e76390a
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 79 deletions.
84 changes: 25 additions & 59 deletions pkg/worker/caged/libretro/nanoarch/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ const (
// It consists of:
// - uint16 button values
// - int16 analog stick values
type InputState [maxPort]RetroPadState

type (
InputState [maxPort]RetroPadState
RetroPadState struct {
keys uint32
axes [dpadAxes]int32
Expand All @@ -30,15 +31,13 @@ type (
mu sync.Mutex
}
MouseState struct {
x, y int16
mp sync.Mutex
l bool
r bool
m bool
mb sync.Mutex
dx, dy atomic.Int32
buttons atomic.Int32
}
)

type MouseBtnState int32

type Device byte

const (
Expand All @@ -52,6 +51,12 @@ const (
MouseButton
)

const (
MouseLeft MouseBtnState = 1 << iota
MouseRight
MouseMiddle
)

const (
maxPort = 8
dpadAxes = 4
Expand Down Expand Up @@ -87,8 +92,6 @@ func NewKeyboardState() KeyboardState {

// SetKey sets keyboard state.
//
// data format
//
// 0 1 2 3 4 5 6
// [ KEY ] P MOD
//
Expand Down Expand Up @@ -128,67 +131,30 @@ func (ks *KeyboardState) Pressed(key uint) C.int16_t {

// ShiftPos sets mouse relative position state.
//
// data format
// 0 1 2 3
// [dx] [dy]
//
// 0 1 2 3
// [x] [y]
//
// x and y contain relative (to the previous values)
// X, Y positions as signed int.
// dx and dy are relative mouse coordinates
func (ms *MouseState) ShiftPos(data []byte) {
if len(data) != 4 {
return
}
dx := int16(data[0])<<8 + int16(data[1])
dy := int16(data[2])<<8 + int16(data[3])
ms.mp.Lock()
ms.x += dx
ms.y += dy
ms.mp.Unlock()
}

func (ms *MouseState) PopX() C.int16_t {
var x int16
ms.mp.Lock()
x = ms.x
ms.x = 0
ms.mp.Unlock()
return C.int16_t(x)
ms.dx.Add(int32(dx))
ms.dy.Add(int32(dy))
}

func (ms *MouseState) PopY() C.int16_t {
var y int16
ms.mp.Lock()
y = ms.y
ms.y = 0
ms.mp.Unlock()
return C.int16_t(y)
}
func (ms *MouseState) PopX() C.int16_t { return C.int16_t(ms.dx.Swap(0)) }
func (ms *MouseState) PopY() C.int16_t { return C.int16_t(ms.dy.Swap(0)) }

// SetButtons sets the state of mouse buttons.
//
// data format
//
// 0 1 2
// L R M
//
// L is the left button, R is right, and M is the middle button.
func (ms *MouseState) SetButtons(data []byte) {
if len(data) != 3 {
return
}
ms.mb.Lock()
ms.l = data[0] == 1
ms.r = data[1] == 1
ms.m = data[2] == 1
ms.mb.Unlock()
}
// SetButtons sets the state MouseBtnState of mouse buttons.
func (ms *MouseState) SetButtons(data byte) { ms.buttons.Store(int32(data)) }

func (ms *MouseState) Buttons() (l, r, m bool) {
ms.mb.Lock()
l = ms.l
r = ms.r
m = ms.m
ms.mb.Unlock()
mbs := MouseBtnState(ms.buttons.Load())
l = mbs&MouseLeft != 0
r = mbs&MouseRight != 0
m = mbs&MouseMiddle != 0
return
}
52 changes: 52 additions & 0 deletions pkg/worker/caged/libretro/nanoarch/input_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package nanoarch

import (
"encoding/binary"
"math/rand"
"sync"
"testing"
Expand All @@ -19,3 +20,54 @@ func TestConcurrentInput(t *testing.T) {
}
wg.Wait()
}

func TestMousePos(t *testing.T) {
data := []byte{0, 0, 0, 0}

dx := 1111
dy := 2222

binary.BigEndian.PutUint16(data, uint16(dx))
binary.BigEndian.PutUint16(data[2:], uint16(dy))

ms := MouseState{}
ms.ShiftPos(data)

x := int(ms.PopX())
y := int(ms.PopY())

if x != dx || y != dy {
t.Errorf("invalid state, %v = %v, %v = %v", dx, x, dy, y)
}

if ms.dx.Load() != 0 || ms.dy.Load() != 0 {
t.Errorf("coordinates weren't cleared")
}
}

func TestMouseButtons(t *testing.T) {
tests := []struct {
name string
data byte
l bool
r bool
m bool
}{
{name: "l+r+m+", data: 1 + 2 + 4, l: true, r: true, m: true},
{name: "l-r-m-", data: 0},
{name: "l-r+m-", data: 2, r: true},
{name: "l+r-m+", data: 1 + 4, l: true, m: true},
}

ms := MouseState{}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
ms.SetButtons(test.data)
l, r, m := ms.Buttons()
if l != test.l || r != test.r || m != test.m {
t.Errorf("wrong button state: %v -> %v, %v, %v", test.data, l, r, m)
}
})
}
}
2 changes: 1 addition & 1 deletion pkg/worker/caged/libretro/nanoarch/nanoarch.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func (n *Nanoarch) InputMouse(_ int, data []byte) {
case MouseMove:
n.mouse.ShiftPos(state)
case MouseButton:
n.mouse.SetButtons(state)
n.mouse.SetButtons(state[0])
}
}

Expand Down
25 changes: 6 additions & 19 deletions web/js/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,36 +80,23 @@ const api = (() => {
})();

const mousePress = (() => {
// 0 1 2 3
// T L R M
const buffer = new ArrayBuffer(4);
// 0 1
// T B
const buffer = new ArrayBuffer(2);
const dv = new DataView(buffer);

// #define RETRO_DEVICE_ID_MOUSE_LEFT 2
// #define RETRO_DEVICE_ID_MOUSE_RIGHT 3
// #define RETRO_DEVICE_ID_MOUSE_WHEELUP 4
// #define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5
// #define RETRO_DEVICE_ID_MOUSE_MIDDLE 6
// #define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP 7
// #define RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN 8
// #define RETRO_DEVICE_ID_MOUSE_BUTTON_4 9
// #define RETRO_DEVICE_ID_MOUSE_BUTTON_5 10

// 0: Main button pressed, usually the left button or the un-initialized state
// 1: Auxiliary button pressed, usually the wheel button or the middle button (if present)
// 2: Secondary button pressed, usually the right button
// 3: Fourth button, typically the Browser Back button
// 4: Fifth button, typically the Browser Forward button

const b2r = [1, 3, 2, 9, 10] // browser mouse button to retro button
const b2r = [1, 4, 2, 0, 0] // browser mouse button to retro button
// assumed that only one button pressed / released

/* @param buttons contains pressed state of mouse buttons according to
* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
*/
return (button = 0, pressed = false) => {
dv.setUint32(0, 0);
dv.setUint8(0, mouse.BUTTONS);
dv.setUint8(b2r[button], +pressed);
dv.setUint8(1, pressed ? b2r[button] : 0);
webrtc.mouse(buffer);
}
})();
Expand Down

0 comments on commit e76390a

Please sign in to comment.