Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ set(SOURCES
# Platform-specific sources
if(WIN32)
list(APPEND SOURCES src/NativeInput_Windows.cpp)
set(PLATFORM_LIBS winmm)
set(PLATFORM_LIBS winmm hid setupapi)
elseif(APPLE)
list(APPEND SOURCES src/NativeInput_Mac.mm)
find_library(APPKIT_FRAMEWORK AppKit REQUIRED)
Expand Down
106 changes: 81 additions & 25 deletions src/NativeInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,26 @@ typedef enum {
VPE_INPUT_MAX = 64 // Reserve space for future actions
} VpeInputAction;

// Input binding type
typedef enum {
VPE_BINDING_KEYBOARD = 0,
VPE_BINDING_GAMEPAD = 1,
VPE_BINDING_MOUSE = 2
} VpeBindingType;
// ABI protocol version. Increment when struct layouts change.
#define VPE_INPUT_PROTOCOL_VERSION 2

// Input binding type
typedef enum {
VPE_BINDING_KEYBOARD = 0,
VPE_BINDING_GAMEPAD = 1,
VPE_BINDING_MOUSE = 2
} VpeBindingType;

typedef enum {
VPE_INPUT_EVENT_ACTION = 0,
VPE_INPUT_EVENT_AXIS = 1
} VpeInputEventType;

typedef enum {
VPE_AXIS_KIND_POSITION = 0,
VPE_AXIS_KIND_VELOCITY = 1,
VPE_AXIS_KIND_ACCELERATION = 2
} VpeAxisKind;

// Key codes (Windows virtual key codes, mapped on other platforms)
typedef enum {
Expand Down Expand Up @@ -117,24 +131,55 @@ typedef enum {
VPE_KEY_P = 0x50,
VPE_KEY_T = 0x54,
VPE_KEY_Y = 0x59,
VPE_KEY_Z = 0x5A,
VPE_KEY_NUMPAD1 = 0x61,
VPE_KEY_A = 0x41,
VPE_KEY_B = 0x42,
VPE_KEY_S = 0x53,
VPE_KEY_D = 0x44,
VPE_KEY_W = 0x57,
VPE_KEY_MINUS = 0xBD, // VK_OEM_MINUS
VPE_KEY_SLASH = 0xBF, // VK_OEM_2
VPE_KEY_QUOTE = 0xDE, // VK_OEM_7
VPE_KEY_CARET = 0xC0, // VK_OEM_3 (layout dependent)
} VpeKeyCode;

// Input event structure (matches C# struct layout)
typedef struct {
int64_t timestampUsec; // Microsecond timestamp
int32_t action; // VpeInputAction
float value; // 0.0 (released) or 1.0 (pressed), or analog value
int32_t _padding; // Ensure 16-byte alignment
} VpeInputEvent;

#define VPE_INPUT_DEVICE_ID_SIZE 260
#define VPE_INPUT_DEVICE_NAME_SIZE 128
#define VPE_INPUT_AXIS_NAME_SIZE 32

// Input device descriptor (matches C# struct layout)
typedef struct {
int32_t deviceIndex;
int32_t axisCount;
int32_t isConnected;
int32_t _padding;
char stableId[VPE_INPUT_DEVICE_ID_SIZE];
char displayName[VPE_INPUT_DEVICE_NAME_SIZE];
} VpeInputDeviceInfo;

// Input axis descriptor (matches C# struct layout)
typedef struct {
int32_t axisId;
int32_t usagePage;
int32_t usage;
int32_t kind;
float rawValue;
int32_t _padding;
int64_t timestampUsec;
char name[VPE_INPUT_AXIS_NAME_SIZE];
} VpeInputAxisInfo;

// Input event structure (matches C# struct layout)
typedef struct {
int64_t timestampUsec; // Microsecond timestamp
int32_t eventType; // VpeInputEventType
int32_t action; // VpeInputAction for action events
int32_t deviceIndex; // device index for axis events
int32_t axisId; // axis id for axis events
float value; // 0.0/1.0 for buttons, -1.0..1.0 for axes
int32_t _padding;
} VpeInputEvent;
Comment thread
freezy marked this conversation as resolved.

// Input binding structure
typedef struct {
Expand All @@ -147,12 +192,15 @@ typedef struct {
// Callback for input events
typedef void (*VpeInputEventCallback)(const VpeInputEvent* event, void* userData);

// Initialize input system
// Returns 1 on success, 0 on failure
VPE_API int VpeInputInit(void);

// Shutdown input system
VPE_API void VpeInputShutdown(void);
// Initialize input system
// Returns 1 on success, 0 on failure
VPE_API int VpeInputInit(void);

// Native ABI protocol version
VPE_API int VpeInputGetProtocolVersion(void);

// Shutdown input system
VPE_API void VpeInputShutdown(void);

// Set input bindings
// bindings: Array of VpeInputBinding
Expand All @@ -165,11 +213,19 @@ VPE_API void VpeInputSetBindings(const VpeInputBinding* bindings, int count);
// pollIntervalUs: Polling interval in microseconds (default 500)
VPE_API int VpeInputStartPolling(VpeInputEventCallback callback, void* userData, int pollIntervalUs);

// Stop polling thread
VPE_API void VpeInputStopPolling(void);

// Get high-resolution timestamp in microseconds
VPE_API int64_t VpeGetTimestampUsec(void);
// Stop polling thread
VPE_API void VpeInputStopPolling(void);

// List HID joystick/gamepad-style devices with analog axes.
// Returns the total available device count. Copies up to maxDevices entries when devices is non-null.
VPE_API int VpeInputListDevices(VpeInputDeviceInfo* devices, int maxDevices);

// List axes for a device index returned by VpeInputListDevices.
// Returns the total available axis count. Copies up to maxAxes entries when axes is non-null.
VPE_API int VpeInputListDeviceAxes(int deviceIndex, VpeInputAxisInfo* axes, int maxAxes);

// Get high-resolution timestamp in microseconds
VPE_API int64_t VpeGetTimestampUsec(void);

// Set thread priority to time-critical (best effort)
VPE_API void VpeSetThreadPriority(void);
Expand Down
23 changes: 23 additions & 0 deletions src/NativeInput_Linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,12 @@ namespace {
return XK_w;
case VPE_KEY_Y:
return XK_y;
case VPE_KEY_Z:
return XK_z;
case VPE_KEY_MINUS:
return XK_minus;
case VPE_KEY_SLASH:
return XK_slash;
case VPE_KEY_QUOTE:
return XK_apostrophe;
case VPE_KEY_CARET:
Expand Down Expand Up @@ -261,6 +265,7 @@ namespace {

VpeInputEvent event{};
event.timestampUsec = timestampUsec;
event.eventType = VPE_INPUT_EVENT_ACTION;
event.action = static_cast<int32_t>(binding.action);
event.value = 0.0f;
g_callback(&event, g_userData);
Expand Down Expand Up @@ -298,6 +303,7 @@ namespace {

VpeInputEvent event{};
event.timestampUsec = timestampUsec;
event.eventType = VPE_INPUT_EVENT_ACTION;
event.action = static_cast<int32_t>(binding.action);
event.value = currentValue;
g_callback(&event, g_userData);
Expand Down Expand Up @@ -328,6 +334,10 @@ VPE_API int VpeInputInit(void) {
return 1;
}

VPE_API int VpeInputGetProtocolVersion(void) {
return VPE_INPUT_PROTOCOL_VERSION;
}

VPE_API void VpeInputShutdown(void) {
VpeInputStopPolling();
g_bindings.clear();
Expand Down Expand Up @@ -402,6 +412,19 @@ VPE_API void VpeInputStopPolling(void) {
}
}

VPE_API int VpeInputListDevices(VpeInputDeviceInfo* devices, int maxDevices) {
(void)devices;
(void)maxDevices;
return 0;
}

VPE_API int VpeInputListDeviceAxes(int deviceIndex, VpeInputAxisInfo* axes, int maxAxes) {
(void)deviceIndex;
(void)axes;
(void)maxAxes;
return 0;
}

VPE_API int64_t VpeGetTimestampUsec(void) {
return GetTimestampUsecInternal();
}
Expand Down
25 changes: 25 additions & 0 deletions src/NativeInput_Mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,15 @@ bool MapKeyCode(int keyCode, CGKeyCode* nativeKeyCode) {
case VPE_KEY_Y:
*nativeKeyCode = 16;
return true;
case VPE_KEY_Z:
*nativeKeyCode = 6;
return true;
case VPE_KEY_MINUS:
*nativeKeyCode = 27;
return true;
case VPE_KEY_SLASH:
*nativeKeyCode = 44;
return true;
case VPE_KEY_QUOTE:
*nativeKeyCode = 39;
return true;
Expand Down Expand Up @@ -225,6 +231,7 @@ void EmitReleaseForPressedKeys(int64_t timestampUsec) {

VpeInputEvent event{};
event.timestampUsec = timestampUsec;
event.eventType = VPE_INPUT_EVENT_ACTION;
event.action = static_cast<int32_t>(binding.action);
event.value = 0.0f;
g_callback(&event, g_userData);
Expand Down Expand Up @@ -260,6 +267,7 @@ void PollingThreadFunc() {

VpeInputEvent event{};
event.timestampUsec = timestampUsec;
event.eventType = VPE_INPUT_EVENT_ACTION;
event.action = static_cast<int32_t>(binding.action);
event.value = currentValue;
g_callback(&event, g_userData);
Expand All @@ -284,6 +292,10 @@ VPE_API int VpeInputInit(void) {
return 1;
}

VPE_API int VpeInputGetProtocolVersion(void) {
return VPE_INPUT_PROTOCOL_VERSION;
}

VPE_API void VpeInputShutdown(void) {
VpeInputStopPolling();
g_bindings.clear();
Expand Down Expand Up @@ -348,6 +360,19 @@ VPE_API void VpeInputStopPolling(void) {
}
}

VPE_API int VpeInputListDevices(VpeInputDeviceInfo* devices, int maxDevices) {
(void)devices;
(void)maxDevices;
return 0;
}

VPE_API int VpeInputListDeviceAxes(int deviceIndex, VpeInputAxisInfo* axes, int maxAxes) {
(void)deviceIndex;
(void)axes;
(void)maxAxes;
return 0;
}

VPE_API int64_t VpeGetTimestampUsec(void) {
return GetTimestampUsecInternal();
}
Expand Down
39 changes: 28 additions & 11 deletions src/NativeInput_Stub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@

extern "C" {

VPE_API int VpeInputInit(void) {
// TODO: Implement for Linux (evdev) and macOS (IOKit)
return 0; // Not implemented
}

VPE_API void VpeInputShutdown(void) {
VPE_API int VpeInputInit(void) {
// TODO: Implement for Linux (evdev) and macOS (IOKit)
return 0; // Not implemented
}

VPE_API int VpeInputGetProtocolVersion(void) {
return VPE_INPUT_PROTOCOL_VERSION;
}

VPE_API void VpeInputShutdown(void) {
// TODO
}

Expand All @@ -27,11 +31,24 @@ VPE_API int VpeInputStartPolling(VpeInputEventCallback callback, void* userData,
return 0;
}

VPE_API void VpeInputStopPolling(void) {
// TODO
}

VPE_API int64_t VpeGetTimestampUsec(void) {
VPE_API void VpeInputStopPolling(void) {
// TODO
}

VPE_API int VpeInputListDevices(VpeInputDeviceInfo* devices, int maxDevices) {
(void)devices;
(void)maxDevices;
return 0;
}

VPE_API int VpeInputListDeviceAxes(int deviceIndex, VpeInputAxisInfo* axes, int maxAxes) {
(void)deviceIndex;
(void)axes;
(void)maxAxes;
return 0;
}

VPE_API int64_t VpeGetTimestampUsec(void) {
auto now = std::chrono::high_resolution_clock::now();
auto duration = now.time_since_epoch();
return std::chrono::duration_cast<std::chrono::microseconds>(duration).count();
Expand Down
Loading
Loading