mirror of
https://github.com/giongto35/cloud-game.git
synced 2026-08-03 23:34:01 +00:00
Add input cache for retropad, keyboard and mouse
This commit is contained in:
parent
f708fce112
commit
671e875f12
3 changed files with 163 additions and 63 deletions
|
|
@ -6,8 +6,16 @@ import (
|
|||
"sync/atomic"
|
||||
)
|
||||
|
||||
//#include <stdint.h>
|
||||
//#include "libretro.h"
|
||||
/*
|
||||
#include <stdint.h>
|
||||
#include "libretro.h"
|
||||
|
||||
void input_cache_set_port(unsigned port, uint32_t buttons,
|
||||
int16_t axis0, int16_t axis1, int16_t axis2, int16_t axis3);
|
||||
void input_cache_set_keyboard_key(unsigned id, uint8_t pressed);
|
||||
void input_cache_set_mouse(int16_t dx, int16_t dy, uint8_t buttons);
|
||||
void input_cache_clear(void);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
const (
|
||||
|
|
@ -84,6 +92,19 @@ func (s *InputState) IsDpadTouched(port uint, axis uint) (shift C.int16_t) {
|
|||
return C.int16_t(atomic.LoadInt32(&s[port].axes[axis]))
|
||||
}
|
||||
|
||||
// SyncToCache syncs the entire input state to the C-side cache.
|
||||
// Call this once before each Run() instead of having C call back into Go.
|
||||
func (s *InputState) SyncToCache() {
|
||||
for port := uint(0); port < maxPort; port++ {
|
||||
buttons := atomic.LoadUint32(&s[port].keys)
|
||||
axis0 := C.int16_t(atomic.LoadInt32(&s[port].axes[0]))
|
||||
axis1 := C.int16_t(atomic.LoadInt32(&s[port].axes[1]))
|
||||
axis2 := C.int16_t(atomic.LoadInt32(&s[port].axes[2]))
|
||||
axis3 := C.int16_t(atomic.LoadInt32(&s[port].axes[3]))
|
||||
C.input_cache_set_port(C.uint(port), C.uint32_t(buttons), axis0, axis1, axis2, axis3)
|
||||
}
|
||||
}
|
||||
|
||||
// SetKey sets keyboard state.
|
||||
//
|
||||
// 0 1 2 3 4 5 6
|
||||
|
|
@ -120,6 +141,15 @@ func (ks *KeyboardState) Pressed(key uint) C.int16_t {
|
|||
return Released
|
||||
}
|
||||
|
||||
// SyncToCache syncs keyboard state to the C-side cache.
|
||||
func (ks *KeyboardState) SyncToCache() {
|
||||
ks.mu.Lock()
|
||||
defer ks.mu.Unlock()
|
||||
for id, pressed := range ks.keys {
|
||||
C.input_cache_set_keyboard_key(C.uint(id), C.uint8_t(pressed))
|
||||
}
|
||||
}
|
||||
|
||||
// ShiftPos sets mouse relative position state.
|
||||
//
|
||||
// 0 1 2 3
|
||||
|
|
@ -148,3 +178,12 @@ func (ms *MouseState) Buttons() (l, r, m bool) {
|
|||
m = mbs&MouseMiddle != 0
|
||||
return
|
||||
}
|
||||
|
||||
// SyncToCache syncs mouse state to the C-side cache.
|
||||
// This consumes the delta values (swaps to 0).
|
||||
func (ms *MouseState) SyncToCache() {
|
||||
dx := C.int16_t(ms.dx.Swap(0))
|
||||
dy := C.int16_t(ms.dy.Swap(0))
|
||||
buttons := C.uint8_t(ms.buttons.Load())
|
||||
C.input_cache_set_mouse(dx, dy, buttons)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,17 +3,18 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define RETRO_ENVIRONMENT_GET_CLEAR_ALL_THREAD_WAITS_CB (3 | 0x800000)
|
||||
|
||||
int initialized = 0;
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
void* fn;
|
||||
void* arg1;
|
||||
void* arg2;
|
||||
void* result;
|
||||
int type;
|
||||
void* fn;
|
||||
void* arg1;
|
||||
void* arg2;
|
||||
void* result;
|
||||
} call_def_t;
|
||||
|
||||
call_def_t call;
|
||||
|
|
@ -26,6 +27,57 @@ enum call_type {
|
|||
|
||||
void *same_thread_with_args(void *f, int type, ...);
|
||||
|
||||
// Input State Cache
|
||||
|
||||
#define INPUT_MAX_PORTS 4
|
||||
#define INPUT_MAX_KEYS 512
|
||||
|
||||
typedef struct {
|
||||
// Retropad: store raw button bitmask and analog axes per port
|
||||
uint32_t buttons[INPUT_MAX_PORTS];
|
||||
int16_t analog[INPUT_MAX_PORTS][4]; // 4 axes per port
|
||||
|
||||
// Keyboard
|
||||
uint8_t keyboard[INPUT_MAX_KEYS];
|
||||
|
||||
// Mouse
|
||||
int16_t mouse_x;
|
||||
int16_t mouse_y;
|
||||
uint8_t mouse_buttons; // bit 0=left, bit 1=right, bit 2=middle
|
||||
} input_cache_t;
|
||||
|
||||
static input_cache_t input_cache = {0};
|
||||
|
||||
// Update entire port state at once
|
||||
void input_cache_set_port(unsigned port, uint32_t buttons,
|
||||
int16_t axis0, int16_t axis1, int16_t axis2, int16_t axis3) {
|
||||
if (port < INPUT_MAX_PORTS) {
|
||||
input_cache.buttons[port] = buttons;
|
||||
input_cache.analog[port][0] = axis0;
|
||||
input_cache.analog[port][1] = axis1;
|
||||
input_cache.analog[port][2] = axis2;
|
||||
input_cache.analog[port][3] = axis3;
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard update
|
||||
void input_cache_set_keyboard_key(unsigned id, uint8_t pressed) {
|
||||
if (id < INPUT_MAX_KEYS) {
|
||||
input_cache.keyboard[id] = pressed;
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse update
|
||||
void input_cache_set_mouse(int16_t dx, int16_t dy, uint8_t buttons) {
|
||||
input_cache.mouse_x = dx;
|
||||
input_cache.mouse_y = dy;
|
||||
input_cache.mouse_buttons = buttons;
|
||||
}
|
||||
|
||||
void input_cache_clear(void) {
|
||||
memset(&input_cache, 0, sizeof(input_cache));
|
||||
}
|
||||
|
||||
void core_log_cgo(enum retro_log_level level, const char *fmt, ...) {
|
||||
char msg[2048] = {0};
|
||||
va_list va;
|
||||
|
|
@ -144,8 +196,61 @@ void core_input_poll_cgo() {
|
|||
}
|
||||
|
||||
int16_t core_input_state_cgo(unsigned port, unsigned device, unsigned index, unsigned id) {
|
||||
int16_t coreInputState(unsigned, unsigned, unsigned, unsigned);
|
||||
return coreInputState(port, device, index, id);
|
||||
if (port >= INPUT_MAX_PORTS) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (device) {
|
||||
case RETRO_DEVICE_JOYPAD:
|
||||
// Extract button bit from cached bitmask
|
||||
return (int16_t)((input_cache.buttons[port] >> id) & 1);
|
||||
|
||||
case RETRO_DEVICE_ANALOG:
|
||||
switch (index) {
|
||||
case RETRO_DEVICE_INDEX_ANALOG_LEFT:
|
||||
// id: 0=X, 1=Y
|
||||
if (id < 2) {
|
||||
return input_cache.analog[port][id];
|
||||
}
|
||||
break;
|
||||
case RETRO_DEVICE_INDEX_ANALOG_RIGHT:
|
||||
// id: 0=X, 1=Y -> stored in axes[2], axes[3]
|
||||
if (id < 2) {
|
||||
return input_cache.analog[port][2 + id];
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RETRO_DEVICE_KEYBOARD:
|
||||
if (id < INPUT_MAX_KEYS) {
|
||||
return input_cache.keyboard[id] ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case RETRO_DEVICE_MOUSE:
|
||||
switch (id) {
|
||||
case RETRO_DEVICE_ID_MOUSE_X: {
|
||||
int16_t x = input_cache.mouse_x;
|
||||
input_cache.mouse_x = 0; // Consume delta
|
||||
return x;
|
||||
}
|
||||
case RETRO_DEVICE_ID_MOUSE_Y: {
|
||||
int16_t y = input_cache.mouse_y;
|
||||
input_cache.mouse_y = 0; // Consume delta
|
||||
return y;
|
||||
}
|
||||
case RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
return (input_cache.mouse_buttons & 0x01) ? 1 : 0;
|
||||
case RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
return (input_cache.mouse_buttons & 0x02) ? 1 : 0;
|
||||
case RETRO_DEVICE_ID_MOUSE_MIDDLE:
|
||||
return (input_cache.mouse_buttons & 0x04) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t core_audio_sample_batch_cgo(const int16_t *data, size_t frames) {
|
||||
|
|
|
|||
|
|
@ -396,12 +396,21 @@ func (n *Nanoarch) Reset() {
|
|||
C.bridge_call(retroReset)
|
||||
}
|
||||
|
||||
func (n *Nanoarch) syncInputToCache() {
|
||||
n.retropad.SyncToCache()
|
||||
if n.keyboardCb != nil {
|
||||
n.keyboard.SyncToCache()
|
||||
}
|
||||
n.mouse.SyncToCache()
|
||||
}
|
||||
|
||||
func (n *Nanoarch) Run() {
|
||||
n.syncInputToCache()
|
||||
|
||||
if n.LibCo {
|
||||
C.same_thread(retroRun)
|
||||
} else {
|
||||
if n.Video.gl.enabled {
|
||||
// running inside a go routine, lock the thread to make sure the OpenGL context stays current
|
||||
runtime.LockOSThread()
|
||||
if err := n.sdlCtx.BindContext(); err != nil {
|
||||
n.log.Error().Err(err).Msg("ctx bind fail")
|
||||
|
|
@ -672,59 +681,6 @@ func coreVideoRefresh(data unsafe.Pointer, width, height uint, packed uint) {
|
|||
Nan0.Handlers.OnVideo(data_, int32(dt), FrameInfo{W: width, H: height, Stride: packed})
|
||||
}
|
||||
|
||||
//export coreInputState
|
||||
func coreInputState(port C.unsigned, device C.unsigned, index C.unsigned, id C.unsigned) C.int16_t {
|
||||
//Nan0.log.Debug().Msgf("%v %v %v %v", port, device, index, id)
|
||||
|
||||
// something like PCSX-ReArmed has 8 ports
|
||||
if port >= maxPort {
|
||||
return Released
|
||||
}
|
||||
|
||||
switch device {
|
||||
case C.RETRO_DEVICE_JOYPAD:
|
||||
return Nan0.retropad.IsKeyPressed(uint(port), int(id))
|
||||
case C.RETRO_DEVICE_ANALOG:
|
||||
switch index {
|
||||
case C.RETRO_DEVICE_INDEX_ANALOG_LEFT:
|
||||
return Nan0.retropad.IsDpadTouched(uint(port), uint(index*2+id))
|
||||
case C.RETRO_DEVICE_INDEX_ANALOG_RIGHT:
|
||||
case C.RETRO_DEVICE_INDEX_ANALOG_BUTTON:
|
||||
}
|
||||
case C.RETRO_DEVICE_KEYBOARD:
|
||||
return Nan0.keyboard.Pressed(uint(id))
|
||||
case C.RETRO_DEVICE_MOUSE:
|
||||
switch id {
|
||||
case C.RETRO_DEVICE_ID_MOUSE_X:
|
||||
x := Nan0.mouse.PopX()
|
||||
return x
|
||||
case C.RETRO_DEVICE_ID_MOUSE_Y:
|
||||
y := Nan0.mouse.PopY()
|
||||
return y
|
||||
case C.RETRO_DEVICE_ID_MOUSE_LEFT:
|
||||
if l, _, _ := Nan0.mouse.Buttons(); l {
|
||||
return Pressed
|
||||
}
|
||||
case C.RETRO_DEVICE_ID_MOUSE_RIGHT:
|
||||
if _, r, _ := Nan0.mouse.Buttons(); r {
|
||||
return Pressed
|
||||
}
|
||||
case C.RETRO_DEVICE_ID_MOUSE_WHEELUP:
|
||||
case C.RETRO_DEVICE_ID_MOUSE_WHEELDOWN:
|
||||
case C.RETRO_DEVICE_ID_MOUSE_MIDDLE:
|
||||
if _, _, m := Nan0.mouse.Buttons(); m {
|
||||
return Pressed
|
||||
}
|
||||
case C.RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELUP:
|
||||
case C.RETRO_DEVICE_ID_MOUSE_HORIZ_WHEELDOWN:
|
||||
case C.RETRO_DEVICE_ID_MOUSE_BUTTON_4:
|
||||
case C.RETRO_DEVICE_ID_MOUSE_BUTTON_5:
|
||||
}
|
||||
}
|
||||
|
||||
return Released
|
||||
}
|
||||
|
||||
//export coreAudioSampleBatch
|
||||
func coreAudioSampleBatch(data unsafe.Pointer, frames C.size_t) C.size_t {
|
||||
if Nan0.Stopped.Load() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue