mirror of https://github.com/mgba-emu/mgba.git
Scripting: Add base input, supports key events
This commit is contained in:
parent
fcfab847fc
commit
e5ed2b4119
|
@ -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 <mgba-util/common.h>
|
||||
|
||||
#include <mgba/script/context.h>
|
||||
#include <mgba/script/macros.h>
|
||||
|
||||
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
|
|
@ -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()
|
||||
|
|
|
@ -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 <mgba/script/input.h>
|
||||
|
||||
#include <mgba-util/string.h>
|
||||
#include <mgba-util/table.h>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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 <mgba/internal/script/lua.h>
|
||||
#include <mgba/script/context.h>
|
||||
#include <mgba/script/input.h>
|
||||
#include <mgba/script/types.h>
|
||||
|
||||
#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),
|
||||
)
|
Loading…
Reference in New Issue