diff --git a/include/mgba/script/input.h b/include/mgba/script/input.h new file mode 100644 index 000000000..f81ecda45 --- /dev/null +++ b/include/mgba/script/input.h @@ -0,0 +1,217 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef M_SCRIPT_INPUT_H +#define M_SCRIPT_INPUT_H + +#include + +#include +#include + +CXX_GUARD_START + +enum mScriptEventType { + mSCRIPT_EV_TYPE_NONE = 0, + mSCRIPT_EV_TYPE_KEY, + mSCRIPT_EV_TYPE_MOUSE_BUTTON, + mSCRIPT_EV_TYPE_MOUSE_MOVE, + mSCRIPT_EV_TYPE_MOUSE_WHEEL, + mSCRIPT_EV_TYPE_GAMEPAD_BUTTON, + mSCRIPT_EV_TYPE_GAMEPAD_HAT, + mSCRIPT_EV_TYPE_TRIGGER, + mSCRIPT_EV_TYPE_MAX +}; + +enum mScriptInputState { + mSCRIPT_INPUT_STATE_UP = 0, + mSCRIPT_INPUT_STATE_DOWN = 1, + mSCRIPT_INPUT_STATE_HELD = 2, +}; + +enum mScriptInputDirection { + mSCRIPT_INPUT_DIR_NONE = 0, + + mSCRIPT_INPUT_DIR_NORTH = 1, + mSCRIPT_INPUT_DIR_EAST = 2, + mSCRIPT_INPUT_DIR_SOUTH = 4, + mSCRIPT_INPUT_DIR_WEST = 8, + + mSCRIPT_INPUT_DIR_UP = mSCRIPT_INPUT_DIR_NORTH, + mSCRIPT_INPUT_DIR_RIGHT = mSCRIPT_INPUT_DIR_EAST, + mSCRIPT_INPUT_DIR_DOWN = mSCRIPT_INPUT_DIR_SOUTH, + mSCRIPT_INPUT_DIR_LEFT = mSCRIPT_INPUT_DIR_WEST, + + mSCRIPT_INPUT_DIR_NORTHEAST = mSCRIPT_INPUT_DIR_NORTH | mSCRIPT_INPUT_DIR_EAST, + mSCRIPT_INPUT_DIR_NORTHWEST = mSCRIPT_INPUT_DIR_NORTH | mSCRIPT_INPUT_DIR_WEST, + mSCRIPT_INPUT_DIR_SOUTHEAST = mSCRIPT_INPUT_DIR_SOUTH | mSCRIPT_INPUT_DIR_EAST, + mSCRIPT_INPUT_DIR_SOUTHWEST = mSCRIPT_INPUT_DIR_SOUTH | mSCRIPT_INPUT_DIR_WEST, +}; + +enum mScriptKeyModifier { + mSCRIPT_KMOD_NONE = 0, + + mSCRIPT_KMOD_LSHIFT = 0x1, + mSCRIPT_KMOD_RSHIFT = 0x2, + mSCRIPT_KMOD_SHIFT = 0x3, + + mSCRIPT_KMOD_LCONTROL = 0x4, + mSCRIPT_KMOD_RCONTROL = 0x8, + mSCRIPT_KMOD_CONTROL = 0xC, + + mSCRIPT_KMOD_LALT = 0x10, + mSCRIPT_KMOD_RALT = 0x20, + mSCRIPT_KMOD_ALT = 0x30, + + mSCRIPT_KMOD_LSUPER = 0x40, + mSCRIPT_KMOD_RSUPER = 0x80, + mSCRIPT_KMOD_SUPER = 0xC0, + + mSCRIPT_KMOD_CAPS_LOCK = 0x100, + mSCRIPT_KMOD_NUM_LOCK = 0x200, + mSCRIPT_KMOD_SCROLL_LOCK = 0x400, +}; + +#define mSCRIPT_KEYBASE 0x200000 + +enum mScriptKey { + mSCRIPT_KEY_NONE = 0, + + mSCRIPT_KEY_BACKSPACE = 0x000008, + mSCRIPT_KEY_TAB = 0x000009, + mSCRIPT_KEY_LINE_FEED = 0x00000A, + mSCRIPT_KEY_ESCAPE = 0x00001B, + mSCRIPT_KEY_DELETE = 0x00007F, + + mSCRIPT_KEY_F1 = mSCRIPT_KEYBASE | 1, + mSCRIPT_KEY_F2, + mSCRIPT_KEY_F3, + mSCRIPT_KEY_F4, + mSCRIPT_KEY_F5, + mSCRIPT_KEY_F6, + mSCRIPT_KEY_F7, + mSCRIPT_KEY_F8, + mSCRIPT_KEY_F9, + mSCRIPT_KEY_F10, + mSCRIPT_KEY_F11, + mSCRIPT_KEY_F12, + mSCRIPT_KEY_F13, + mSCRIPT_KEY_F14, + mSCRIPT_KEY_F15, + mSCRIPT_KEY_F16, + mSCRIPT_KEY_F17, + mSCRIPT_KEY_F18, + mSCRIPT_KEY_F19, + mSCRIPT_KEY_F20, + mSCRIPT_KEY_F21, + mSCRIPT_KEY_F22, + mSCRIPT_KEY_F23, + mSCRIPT_KEY_F24, + + mSCRIPT_KEY_UP = mSCRIPT_KEYBASE | 0x20, + mSCRIPT_KEY_RIGHT, + mSCRIPT_KEY_DOWN, + mSCRIPT_KEY_LEFT, + mSCRIPT_KEY_PAGE_UP, + mSCRIPT_KEY_PAGE_DOWN, + mSCRIPT_KEY_HOME, + mSCRIPT_KEY_END, + mSCRIPT_KEY_INSERT, + mSCRIPT_KEY_BREAK, + mSCRIPT_KEY_CLEAR, + mSCRIPT_KEY_PRNTSCR, + mSCRIPT_KEY_SYSRQ, + mSCRIPT_KEY_MENU, + + mSCRIPT_KEY_LSHIFT = mSCRIPT_KEYBASE | 0x30, + mSCRIPT_KEY_RSHIFT, + mSCRIPT_KEY_SHIFT, + mSCRIPT_KEY_LCONTROL, + mSCRIPT_KEY_RCONTROL, + mSCRIPT_KEY_CONTROL, + mSCRIPT_KEY_LALT, + mSCRIPT_KEY_RALT, + mSCRIPT_KEY_ALT, + mSCRIPT_KEY_LSUPER, + mSCRIPT_KEY_RSUPER, + mSCRIPT_KEY_SUPER, + mSCRIPT_KEY_CAPS_LOCK, + mSCRIPT_KEY_NUM_LOCK, + mSCRIPT_KEY_SCROLL_LOCK, +}; + +struct mScriptEvent { + int32_t type; + int32_t reserved; + uint64_t seq; +}; + +struct mScriptKeyEvent { + struct mScriptEvent d; + uint8_t state; + uint8_t reserved; + uint16_t modifiers; + uint32_t key; +}; + +struct mScriptMouseButtonEvent { + struct mScriptEvent d; + uint8_t state; + uint8_t mouse; + uint8_t button; +}; + +struct mScriptMouseMoveEvent { + struct mScriptEvent d; + bool relative; + uint8_t mouse; + int32_t x; + int32_t y; +}; + +struct mScriptMouseWheelEvent { + struct mScriptEvent d; + uint8_t mouse; + int32_t x; + int32_t y; +}; + +struct mScriptGamepadButtonEvent { + struct mScriptEvent d; + uint8_t state; + uint8_t pad; + uint16_t button; +}; + +struct mScriptGamepadHatEvent { + struct mScriptEvent d; + uint8_t pad; + uint8_t hat; + uint8_t direction; +}; + +struct mScriptTriggerEvent { + struct mScriptEvent d; + uint8_t trigger; + bool state; +}; + +mSCRIPT_DECLARE_STRUCT(mScriptEvent); +mSCRIPT_DECLARE_STRUCT(mScriptKeyEvent); +mSCRIPT_DECLARE_STRUCT(mScriptMouseButtonEvent); +mSCRIPT_DECLARE_STRUCT(mScriptMouseMoveEvent); +mSCRIPT_DECLARE_STRUCT(mScriptMouseWheelEvent); +mSCRIPT_DECLARE_STRUCT(mScriptGamepadButtonEvent); +mSCRIPT_DECLARE_STRUCT(mScriptGamepadHatEvent); +mSCRIPT_DECLARE_STRUCT(mScriptSensorEvent); +mSCRIPT_DECLARE_STRUCT(mScriptTriggerEvent); + +void mScriptContextAttachInput(struct mScriptContext* context); + +void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*); + +CXX_GUARD_END + +#endif diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt index 504736f2f..d84659453 100644 --- a/src/script/CMakeLists.txt +++ b/src/script/CMakeLists.txt @@ -1,6 +1,7 @@ include(ExportDirectory) set(SOURCE_FILES context.c + input.c socket.c stdlib.c types.c) @@ -13,6 +14,7 @@ if(USE_LUA) list(APPEND SOURCE_FILES engines/lua.c) list(APPEND TEST_FILES test/context.c + test/input.c test/lua.c test/stdlib.c) endif() diff --git a/src/script/input.c b/src/script/input.c new file mode 100644 index 000000000..9436cd78c --- /dev/null +++ b/src/script/input.c @@ -0,0 +1,249 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include + +#include +#include + +static const char* eventNames[mSCRIPT_EV_TYPE_MAX] = { + [mSCRIPT_EV_TYPE_KEY] = "key", + [mSCRIPT_EV_TYPE_MOUSE_BUTTON] = "mouseButton", + [mSCRIPT_EV_TYPE_MOUSE_MOVE] = "mouseMove", + [mSCRIPT_EV_TYPE_MOUSE_WHEEL] = "mouseWheel", + [mSCRIPT_EV_TYPE_GAMEPAD_BUTTON] = "gamepadButton", + [mSCRIPT_EV_TYPE_GAMEPAD_HAT] = "gamepadHat", + [mSCRIPT_EV_TYPE_TRIGGER] = "trigger", +}; + +static const struct mScriptType* eventTypes[mSCRIPT_EV_TYPE_MAX] = { + [mSCRIPT_EV_TYPE_KEY] = mSCRIPT_TYPE_MS_S(mScriptKeyEvent), + [mSCRIPT_EV_TYPE_MOUSE_BUTTON] = mSCRIPT_TYPE_MS_S(mScriptMouseButtonEvent), + [mSCRIPT_EV_TYPE_MOUSE_MOVE] = mSCRIPT_TYPE_MS_S(mScriptMouseMoveEvent), + [mSCRIPT_EV_TYPE_MOUSE_WHEEL] = mSCRIPT_TYPE_MS_S(mScriptMouseWheelEvent), + [mSCRIPT_EV_TYPE_GAMEPAD_BUTTON] = mSCRIPT_TYPE_MS_S(mScriptGamepadButtonEvent), + [mSCRIPT_EV_TYPE_GAMEPAD_HAT] = mSCRIPT_TYPE_MS_S(mScriptGamepadHatEvent), +}; + +struct mScriptInputContext { + struct Table activeKeys; +}; + +static void _mScriptInputDeinit(struct mScriptInputContext*); +static bool _mScriptInputIsKeyActive(const struct mScriptInputContext*, struct mScriptValue*); + +mSCRIPT_DECLARE_STRUCT(mScriptInputContext); +mSCRIPT_DECLARE_STRUCT_VOID_METHOD(mScriptInputContext, _deinit, _mScriptInputDeinit, 0); +mSCRIPT_DECLARE_STRUCT_C_METHOD(mScriptInputContext, BOOL, isKeyActive, _mScriptInputIsKeyActive, 1, WRAPPER, key); + +mSCRIPT_DEFINE_STRUCT(mScriptInputContext) + mSCRIPT_DEFINE_STRUCT_DEINIT(mScriptInputContext) + mSCRIPT_DEFINE_STRUCT_METHOD(mScriptInputContext, isKeyActive) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptEvent, S32, type) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptEvent, U64, seq) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptKeyEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, U8, state) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, S16, modifiers) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptKeyEvent, S32, key) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptMouseButtonEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, mouse) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, state) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseButtonEvent, U8, button) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptMouseMoveEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, U8, mouse) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, S32, x) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseMoveEvent, S32, y) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptMouseWheelEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, U8, mouse) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, S32, x) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptMouseWheelEvent, S32, y) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptGamepadButtonEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U8, state) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U8, pad) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadButtonEvent, U16, button) +mSCRIPT_DEFINE_END; + +mSCRIPT_DEFINE_STRUCT(mScriptGamepadHatEvent) + mSCRIPT_DEFINE_INHERIT(mScriptEvent) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, pad) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, hat) + mSCRIPT_DEFINE_STRUCT_MEMBER(mScriptGamepadHatEvent, U8, direction) +mSCRIPT_DEFINE_END; + +void mScriptContextAttachInput(struct mScriptContext* context) { + struct mScriptInputContext* inputContext = calloc(1, sizeof(*inputContext)); + struct mScriptValue* value = mScriptValueAlloc(mSCRIPT_TYPE_MS_S(mScriptInputContext)); + value->flags = mSCRIPT_VALUE_FLAG_FREE_BUFFER; + value->value.opaque = inputContext; + + TableInit(&inputContext->activeKeys, 0, NULL); + + mScriptContextSetGlobal(context, "input", value); + mScriptContextSetDocstring(context, "input", "Singleton instance of struct::mScriptInputContext"); + + mScriptContextExportConstants(context, "EV_TYPE", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, KEY), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_BUTTON), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_MOVE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, MOUSE_WHEEL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, GAMEPAD_BUTTON), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_EV_TYPE, TRIGGER), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "INPUT_STATE", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, UP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, DOWN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_STATE, HELD), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "INPUT_DIR", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTH), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, EAST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTH), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, WEST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, UP), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, RIGHT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, DOWN), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, LEFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTHEAST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, NORTHWEST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTHEAST), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_INPUT_DIR, SOUTHWEST), + mSCRIPT_KV_SENTINEL + }); + + mScriptContextExportConstants(context, "KMOD", (struct mScriptKVPair[]) { + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, NONE), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LSHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RSHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SHIFT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LCONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RCONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, CONTROL), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, ALT), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, LSUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, RSUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SUPER), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, CAPS_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, NUM_LOCK), + mSCRIPT_CONSTANT_PAIR(mSCRIPT_KMOD, SCROLL_LOCK), + mSCRIPT_KV_SENTINEL + }); +} + +void _mScriptInputDeinit(struct mScriptInputContext* context) { + TableDeinit(&context->activeKeys); +} + +bool _mScriptInputIsKeyActive(const struct mScriptInputContext* context, struct mScriptValue* value) { + uint32_t key; + struct mScriptValue intValue; + size_t length; + const char* strbuf; + + switch (value->type->base) { + case mSCRIPT_TYPE_SINT: + case mSCRIPT_TYPE_UINT: + case mSCRIPT_TYPE_FLOAT: + if (!mScriptCast(mSCRIPT_TYPE_MS_U32, value, &intValue)) { + return false; + } + key = intValue.value.u32; + break; + case mSCRIPT_TYPE_STRING: + if (value->value.string->length > 1) { + return false; + } + strbuf = value->value.string->buffer; + length = value->value.string->size; + key = utf8Char(&strbuf, &length); + break; + default: + return false; + } + + void* down = TableLookup(&context->activeKeys, key); + return down != NULL; +} + +static bool _updateKeys(struct mScriptContext* context, struct mScriptKeyEvent* event) { + int offset = 0; + switch (event->state) { + case mSCRIPT_INPUT_STATE_UP: + offset = -1; + break; + case mSCRIPT_INPUT_STATE_DOWN: + offset = 1; + break; + default: + return true; + } + + struct mScriptValue* input = mScriptContextGetGlobal(context, "input"); + if (!input) { + return false; + } + struct mScriptInputContext* inputContext = input->value.opaque; + intptr_t value = (intptr_t) TableLookup(&inputContext->activeKeys, event->key); + value += offset; + if (value < 1) { + TableRemove(&inputContext->activeKeys, event->key); + } else { + TableInsert(&inputContext->activeKeys, event->key, (void*) value); + } + if (offset < 0 && value > 0) { + return false; + } + if (offset > 0 && value != 1) { + event->state = mSCRIPT_INPUT_STATE_HELD; + } + return true; +} + +void mScriptContextFireEvent(struct mScriptContext* context, struct mScriptEvent* event) { + switch (event->type) { + case mSCRIPT_EV_TYPE_KEY: + if (!_updateKeys(context, (struct mScriptKeyEvent*) event)) { + return; + } + break; + case mSCRIPT_EV_TYPE_NONE: + return; + } + + struct mScriptList args; + mScriptListInit(&args, 1); + struct mScriptValue* value = mScriptListAppend(&args); + value->type = eventTypes[event->type]; + value->refs = mSCRIPT_VALUE_UNREF; + value->flags = 0; + value->value.opaque = event; + mScriptContextTriggerCallback(context, eventNames[event->type], &args); + mScriptListDeinit(&args); +} diff --git a/src/script/test/input.c b/src/script/test/input.c new file mode 100644 index 000000000..1d4c85662 --- /dev/null +++ b/src/script/test/input.c @@ -0,0 +1,86 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "util/test/suite.h" + +#include +#include +#include +#include + +#include "script/test.h" + +#define SETUP_LUA \ + struct mScriptContext context; \ + mScriptContextInit(&context); \ + struct mScriptEngineContext* lua = mScriptContextRegisterEngine(&context, mSCRIPT_ENGINE_LUA); \ + mScriptContextAttachStdlib(&context); \ + mScriptContextAttachInput(&context) + +M_TEST_SUITE_SETUP(mScriptInput) { + if (mSCRIPT_ENGINE_LUA->init) { + mSCRIPT_ENGINE_LUA->init(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_SUITE_TEARDOWN(mScriptInput) { + if (mSCRIPT_ENGINE_LUA->deinit) { + mSCRIPT_ENGINE_LUA->deinit(mSCRIPT_ENGINE_LUA); + } + return 0; +} + +M_TEST_DEFINE(members) { + SETUP_LUA; + + TEST_PROGRAM("assert(input)"); + TEST_PROGRAM("assert(input.isKeyActive)"); + + mScriptContextDeinit(&context); +} + +M_TEST_DEFINE(fireKey) { + SETUP_LUA; + + TEST_PROGRAM("assert(not input:isKeyActive('a'))"); + + TEST_PROGRAM( + "activeKey = false\n" + "state = nil\n" + "function cb(ev)\n" + " assert(ev.type == C.EV_TYPE.KEY)\n" + " activeKey = string.char(ev.key)\n" + " state = ev.state\n" + "end\n" + "id = callbacks:add('key', cb)\n" + "assert(id)\n" + "assert(not activeKey)\n" + ); + + struct mScriptKeyEvent keyEvent = { + .d = { .type = mSCRIPT_EV_TYPE_KEY }, + .state = mSCRIPT_INPUT_STATE_DOWN, + .key = 'a' + }; + mScriptContextFireEvent(&context, &keyEvent.d); + + TEST_PROGRAM("assert(input:isKeyActive('a'))"); + TEST_PROGRAM("assert(activeKey == 'a')"); + TEST_PROGRAM("assert(state == C.INPUT_STATE.DOWN)"); + + keyEvent.state = mSCRIPT_INPUT_STATE_UP; + mScriptContextFireEvent(&context, &keyEvent.d); + + TEST_PROGRAM("assert(not input:isKeyActive('a'))"); + TEST_PROGRAM("assert(state == C.INPUT_STATE.UP)"); + + mScriptContextDeinit(&context); +} + +M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput, + cmocka_unit_test(members), + cmocka_unit_test(fireKey), +)