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;
|
||||
};
|
||||
|
||||
struct mScriptGamepad {
|
||||
unsigned pad;
|
||||
|
||||
struct mScriptList axes;
|
||||
struct mScriptList buttons;
|
||||
struct mScriptList hats;
|
||||
};
|
||||
|
||||
mSCRIPT_DECLARE_STRUCT(mScriptEvent);
|
||||
mSCRIPT_DECLARE_STRUCT(mScriptKeyEvent);
|
||||
mSCRIPT_DECLARE_STRUCT(mScriptMouseButtonEvent);
|
||||
|
@ -227,10 +235,28 @@ mSCRIPT_DECLARE_STRUCT(mScriptGamepadHatEvent);
|
|||
mSCRIPT_DECLARE_STRUCT(mScriptSensorEvent);
|
||||
mSCRIPT_DECLARE_STRUCT(mScriptTriggerEvent);
|
||||
|
||||
mSCRIPT_DECLARE_STRUCT(mScriptGamepad);
|
||||
|
||||
void mScriptContextAttachInput(struct mScriptContext* context);
|
||||
|
||||
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
|
||||
|
||||
#endif
|
||||
|
|
|
@ -30,6 +30,7 @@ static const struct mScriptType* eventTypes[mSCRIPT_EV_TYPE_MAX] = {
|
|||
struct mScriptInputContext {
|
||||
uint64_t seq;
|
||||
struct Table activeKeys;
|
||||
struct mScriptGamepad* activeGamepad;
|
||||
};
|
||||
|
||||
static void _mScriptInputDeinit(struct mScriptInputContext*);
|
||||
|
@ -43,6 +44,7 @@ mSCRIPT_DEFINE_STRUCT(mScriptInputContext)
|
|||
mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext)
|
||||
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, U64, seq)
|
||||
mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive)
|
||||
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptInputContext, PCS(mScriptGamepad), activeGamepad)
|
||||
mSCRIPT_DEFINE_END;
|
||||
|
||||
mSCRIPT_DEFINE_STRUCT(mScriptEvent)
|
||||
|
@ -92,6 +94,12 @@ mSCRIPT_DEFINE_STRUCT(mScriptGamepadHatEvent)
|
|||
mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, direction)
|
||||
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) {
|
||||
struct mScriptInputContext* inputContext = calloc(1, sizeof(*inputContext));
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
cmocka_unit_test(members),
|
||||
cmocka_unit_test(seq),
|
||||
cmocka_unit_test(fireKey),
|
||||
cmocka_unit_test(gamepadExport),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue