mirror of https://github.com/mgba-emu/mgba.git
Scripting: Basic gamepad support
This commit is contained in:
parent
a154690694
commit
dfe2f62f16
|
@ -217,6 +217,14 @@ struct mScriptTriggerEvent {
|
||||||
bool state;
|
bool state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mScriptGamepad {
|
||||||
|
unsigned pad;
|
||||||
|
|
||||||
|
struct mScriptList axes;
|
||||||
|
struct mScriptList buttons;
|
||||||
|
struct mScriptList hats;
|
||||||
|
};
|
||||||
|
|
||||||
mSCRIPT_DECLARE_STRUCT(mScriptEvent);
|
mSCRIPT_DECLARE_STRUCT(mScriptEvent);
|
||||||
mSCRIPT_DECLARE_STRUCT(mScriptKeyEvent);
|
mSCRIPT_DECLARE_STRUCT(mScriptKeyEvent);
|
||||||
mSCRIPT_DECLARE_STRUCT(mScriptMouseButtonEvent);
|
mSCRIPT_DECLARE_STRUCT(mScriptMouseButtonEvent);
|
||||||
|
@ -227,10 +235,28 @@ mSCRIPT_DECLARE_STRUCT(mScriptGamepadHatEvent);
|
||||||
mSCRIPT_DECLARE_STRUCT(mScriptSensorEvent);
|
mSCRIPT_DECLARE_STRUCT(mScriptSensorEvent);
|
||||||
mSCRIPT_DECLARE_STRUCT(mScriptTriggerEvent);
|
mSCRIPT_DECLARE_STRUCT(mScriptTriggerEvent);
|
||||||
|
|
||||||
|
mSCRIPT_DECLARE_STRUCT(mScriptGamepad);
|
||||||
|
|
||||||
void mScriptContextAttachInput(struct mScriptContext* context);
|
void mScriptContextAttachInput(struct mScriptContext* context);
|
||||||
|
|
||||||
void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*);
|
void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*);
|
||||||
|
|
||||||
|
int mScriptContextGamepadAttach(struct mScriptContext*, struct mScriptGamepad*);
|
||||||
|
bool mScriptContextGamepadDetach(struct mScriptContext*, int pad);
|
||||||
|
struct mScriptGamepad* mScriptContextGamepadLookup(struct mScriptContext*, int pad);
|
||||||
|
|
||||||
|
void mScriptGamepadInit(struct mScriptGamepad*);
|
||||||
|
void mScriptGamepadDeinit(struct mScriptGamepad*);
|
||||||
|
void mScriptGamepadSetAxisCount(struct mScriptGamepad*, unsigned);
|
||||||
|
void mScriptGamepadSetButtonCount(struct mScriptGamepad*, unsigned);
|
||||||
|
void mScriptGamepadSetHatCount(struct mScriptGamepad*, unsigned);
|
||||||
|
void mScriptGamepadSetAxis(struct mScriptGamepad*, unsigned, int16_t value);
|
||||||
|
void mScriptGamepadSetButton(struct mScriptGamepad*, unsigned, bool down);
|
||||||
|
void mScriptGamepadSetHat(struct mScriptGamepad*, unsigned, int direction);
|
||||||
|
int16_t mScriptGamepadGetAxis(struct mScriptGamepad*, unsigned);
|
||||||
|
bool mScriptGamepadGetButton(struct mScriptGamepad*, unsigned);
|
||||||
|
int mScriptGamepadGetHat(struct mScriptGamepad*, unsigned);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,6 +30,7 @@ static const struct mScriptType* eventTypes[mSCRIPT_EV_TYPE_MAX] = {
|
||||||
struct mScriptInputContext {
|
struct mScriptInputContext {
|
||||||
uint64_t seq;
|
uint64_t seq;
|
||||||
struct Table activeKeys;
|
struct Table activeKeys;
|
||||||
|
struct mScriptGamepad* activeGamepad;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void _mScriptInputDeinit(struct mScriptInputContext*);
|
static void _mScriptInputDeinit(struct mScriptInputContext*);
|
||||||
|
@ -43,6 +44,7 @@ mSCRIPT_DEFINE_STRUCT(mScriptInputContext)
|
||||||
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext)
|
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, U64, seq)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, U64, seq)
|
||||||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive)
|
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, PCS(mScriptGamepad), activeGamepad)
|
||||||
mSCRIPT_DEFINE_END;
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
mSCRIPT_DEFINE_STRUCT(mScriptEvent)
|
mSCRIPT_DEFINE_STRUCT(mScriptEvent)
|
||||||
|
@ -92,6 +94,12 @@ mSCRIPT_DEFINE_STRUCT(mScriptGamepadHatEvent)
|
||||||
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, direction)
|
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, direction)
|
||||||
mSCRIPT_DEFINE_END;
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
|
mSCRIPT_DEFINE_STRUCT(mScriptGamepad)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, axes)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, buttons)
|
||||||
|
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepad, LIST, hats)
|
||||||
|
mSCRIPT_DEFINE_END;
|
||||||
|
|
||||||
void mScriptContextAttachInput(struct mScriptContext* context) {
|
void mScriptContextAttachInput(struct mScriptContext* context) {
|
||||||
struct mScriptInputContext* inputContext = calloc(1, sizeof(*inputContext));
|
struct mScriptInputContext* inputContext = calloc(1, sizeof(*inputContext));
|
||||||
struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptInputContext));
|
struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptInputContext));
|
||||||
|
@ -258,3 +266,147 @@ void mScriptContextFireEvent(struct mScriptContext* context, struct mScriptEvent
|
||||||
mScriptContextTriggerCallback(context, eventNames[event->type], &args);
|
mScriptContextTriggerCallback(context, eventNames[event->type], &args);
|
||||||
mScriptListDeinit(&args);
|
mScriptListDeinit(&args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mScriptContextGamepadAttach(struct mScriptContext* context, struct mScriptGamepad* pad) {
|
||||||
|
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
|
||||||
|
if (!input) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mScriptInputContext* inputContext = input->value.opaque;
|
||||||
|
if (inputContext->activeGamepad) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
inputContext->activeGamepad = pad;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mScriptContextGamepadDetach(struct mScriptContext* context, int pad) {
|
||||||
|
if (pad != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
|
||||||
|
if (!input) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mScriptInputContext* inputContext = input->value.opaque;
|
||||||
|
if (!inputContext->activeGamepad) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
inputContext->activeGamepad = NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mScriptGamepad* mScriptContextGamepadLookup(struct mScriptContext* context, int pad) {
|
||||||
|
if (pad != 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
|
||||||
|
if (!input) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct mScriptInputContext* inputContext = input->value.opaque;
|
||||||
|
return inputContext->activeGamepad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadInit(struct mScriptGamepad* gamepad) {
|
||||||
|
memset(gamepad, 0, sizeof(*gamepad));
|
||||||
|
|
||||||
|
mScriptListInit(&gamepad->axes, 8);
|
||||||
|
mScriptListInit(&gamepad->buttons, 1);
|
||||||
|
mScriptListInit(&gamepad->hats, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadDeinit(struct mScriptGamepad* gamepad) {
|
||||||
|
mScriptListDeinit(&gamepad->axes);
|
||||||
|
mScriptListDeinit(&gamepad->buttons);
|
||||||
|
mScriptListDeinit(&gamepad->hats);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadSetAxisCount(struct mScriptGamepad* gamepad, unsigned count) {
|
||||||
|
if (count > UINT8_MAX) {
|
||||||
|
count = UINT8_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned oldSize = mScriptListSize(&gamepad->axes);
|
||||||
|
mScriptListResize(&gamepad->axes, (ssize_t) count - oldSize);
|
||||||
|
unsigned i;
|
||||||
|
for (i = oldSize; i < count; ++i) {
|
||||||
|
*mScriptListGetPointer(&gamepad->axes, i) = mSCRIPT_MAKE_S16(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadSetButtonCount(struct mScriptGamepad* gamepad, unsigned count) {
|
||||||
|
if (count > UINT16_MAX) {
|
||||||
|
count = UINT16_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned oldSize = mScriptListSize(&gamepad->buttons);
|
||||||
|
mScriptListResize(&gamepad->buttons, (ssize_t) count - oldSize);
|
||||||
|
unsigned i;
|
||||||
|
for (i = oldSize; i < count; ++i) {
|
||||||
|
*mScriptListGetPointer(&gamepad->buttons, i) = mSCRIPT_MAKE_BOOL(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadSetHatCount(struct mScriptGamepad* gamepad, unsigned count) {
|
||||||
|
if (count > UINT8_MAX) {
|
||||||
|
count = UINT8_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned oldSize = mScriptListSize(&gamepad->hats);
|
||||||
|
mScriptListResize(&gamepad->hats, (ssize_t) count - oldSize);
|
||||||
|
unsigned i;
|
||||||
|
for (i = oldSize; i < count; ++i) {
|
||||||
|
*mScriptListGetPointer(&gamepad->hats, i) = mSCRIPT_MAKE_U8(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadSetAxis(struct mScriptGamepad* gamepad, unsigned id, int16_t value) {
|
||||||
|
if (id >= mScriptListSize(&gamepad->axes)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScriptListGetPointer(&gamepad->axes, id)->value.s32 = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadSetButton(struct mScriptGamepad* gamepad, unsigned id, bool down) {
|
||||||
|
if (id >= mScriptListSize(&gamepad->buttons)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScriptListGetPointer(&gamepad->buttons, id)->value.u32 = down;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mScriptGamepadSetHat(struct mScriptGamepad* gamepad, unsigned id, int direction) {
|
||||||
|
if (id >= mScriptListSize(&gamepad->hats)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mScriptListGetPointer(&gamepad->hats, id)->value.u32 = direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t mScriptGamepadGetAxis(struct mScriptGamepad* gamepad, unsigned id) {
|
||||||
|
if (id >= mScriptListSize(&gamepad->axes)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mScriptListGetPointer(&gamepad->axes, id)->value.s32;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mScriptGamepadGetButton(struct mScriptGamepad* gamepad, unsigned id) {
|
||||||
|
if (id >= mScriptListSize(&gamepad->buttons)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mScriptListGetPointer(&gamepad->buttons, id)->value.u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mScriptGamepadGetHat(struct mScriptGamepad* gamepad, unsigned id) {
|
||||||
|
if (id >= mScriptListSize(&gamepad->hats)) {
|
||||||
|
return mSCRIPT_INPUT_DIR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mScriptListGetPointer(&gamepad->hats, id)->value.u32;
|
||||||
|
}
|
||||||
|
|
|
@ -109,8 +109,49 @@ M_TEST_DEFINE(fireKey) {
|
||||||
mScriptContextDeinit(&context);
|
mScriptContextDeinit(&context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
M_TEST_DEFINE(gamepadExport) {
|
||||||
|
SETUP_LUA;
|
||||||
|
|
||||||
|
struct mScriptGamepad m_gamepad;
|
||||||
|
mScriptGamepadInit(&m_gamepad);
|
||||||
|
|
||||||
|
TEST_PROGRAM("assert(not input.activeGamepad)");
|
||||||
|
assert_int_equal(mScriptContextGamepadAttach(&context, &m_gamepad), 0);
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad)");
|
||||||
|
|
||||||
|
TEST_PROGRAM("assert(#input.activeGamepad.axes == 0)");
|
||||||
|
TEST_PROGRAM("assert(#input.activeGamepad.buttons == 0)");
|
||||||
|
TEST_PROGRAM("assert(#input.activeGamepad.hats == 0)");
|
||||||
|
|
||||||
|
mScriptGamepadSetAxisCount(&m_gamepad, 1);
|
||||||
|
TEST_PROGRAM("assert(#input.activeGamepad.axes == 1)");
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad.axes[1] == 0)");
|
||||||
|
mScriptGamepadSetAxis(&m_gamepad, 0, 123);
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad.axes[1] == 123)");
|
||||||
|
|
||||||
|
mScriptGamepadSetButtonCount(&m_gamepad, 1);
|
||||||
|
TEST_PROGRAM("assert(#input.activeGamepad.buttons == 1)");
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad.buttons[1] == false)");
|
||||||
|
mScriptGamepadSetButton(&m_gamepad, 0, true);
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad.buttons[1] == true)");
|
||||||
|
|
||||||
|
mScriptGamepadSetHatCount(&m_gamepad, 1);
|
||||||
|
TEST_PROGRAM("assert(#input.activeGamepad.hats == 1)");
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad.hats[1] == C.INPUT_DIR.NONE)");
|
||||||
|
mScriptGamepadSetHat(&m_gamepad, 0, mSCRIPT_INPUT_DIR_NORTHWEST);
|
||||||
|
TEST_PROGRAM("assert(input.activeGamepad.hats[1] == C.INPUT_DIR.NORTHWEST)");
|
||||||
|
|
||||||
|
mScriptContextGamepadDetach(&context, 0);
|
||||||
|
TEST_PROGRAM("assert(not input.activeGamepad)");
|
||||||
|
|
||||||
|
mScriptGamepadDeinit(&m_gamepad);
|
||||||
|
|
||||||
|
mScriptContextDeinit(&context);
|
||||||
|
}
|
||||||
|
|
||||||
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput,
|
M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput,
|
||||||
cmocka_unit_test(members),
|
cmocka_unit_test(members),
|
||||||
cmocka_unit_test(seq),
|
cmocka_unit_test(seq),
|
||||||
cmocka_unit_test(fireKey),
|
cmocka_unit_test(fireKey),
|
||||||
|
cmocka_unit_test(gamepadExport),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue