Scripting: Clear down keys when the window is deactivated

This commit is contained in:
Vicki Pfau 2023-02-02 21:34:14 -08:00
parent f27ce8d82e
commit e95bd06321
4 changed files with 88 additions and 0 deletions

View File

@ -249,6 +249,7 @@ mSCRIPT_DECLARE_STRUCT(mScriptGamepad);
void mScriptContextAttachInput(struct mScriptContext* context);
void mScriptContextFireEvent(struct mScriptContext*, struct mScriptEvent*);
void mScriptContextClearKeys(struct mScriptContext*);
int mScriptContextGamepadAttach(struct mScriptContext*, struct mScriptGamepad*);
bool mScriptContextGamepadDetach(struct mScriptContext*, int pad);

View File

@ -155,6 +155,10 @@ void ScriptingController::event(QObject* obj, QEvent* event) {
}
switch (event->type()) {
case QEvent::FocusOut:
case QEvent::WindowDeactivate:
mScriptContextClearKeys(&m_scriptContext);
return;
case QEvent::KeyPress:
case QEvent::KeyRelease: {
struct mScriptKeyEvent ev{mSCRIPT_EV_TYPE_KEY};

View File

@ -427,6 +427,44 @@ void mScriptContextFireEvent(struct mScriptContext* context, struct mScriptEvent
mScriptListDeinit(&args);
}
void mScriptContextClearKeys(struct mScriptContext* context) {
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {
return;
}
struct mScriptInputContext* inputContext = input->value.opaque;
size_t keyCount = TableSize(&inputContext->activeKeys);
uint32_t* keys = calloc(keyCount, sizeof(uint32_t));
struct TableIterator iter;
size_t i = 0;
if (!TableIteratorStart(&inputContext->activeKeys, &iter)) {
free(keys);
return;
}
do {
keys[i] = TableIteratorGetKey(&inputContext->activeKeys, &iter);
++i;
} while (TableIteratorNext(&inputContext->activeKeys, &iter));
struct mScriptKeyEvent event = {
.d = {
.type = mSCRIPT_EV_TYPE_KEY
},
.state = mSCRIPT_INPUT_STATE_UP,
.modifiers = 0
};
for (i = 0; i < keyCount; ++i) {
event.key = keys[i];
intptr_t value = (intptr_t) TableLookup(&inputContext->activeKeys, event.key);
if (value > 1) {
TableInsert(&inputContext->activeKeys, event.key, (void*) 1);
}
mScriptContextFireEvent(context, &event.d);
}
free(keys);
}
int mScriptContextGamepadAttach(struct mScriptContext* context, struct mScriptGamepad* pad) {
struct mScriptValue* input = mScriptContextGetGlobal(context, "input");
if (!input) {

View File

@ -131,6 +131,50 @@ M_TEST_DEFINE(activeKeys) {
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(clearKeys) {
SETUP_LUA;
TEST_PROGRAM("assert(not input:isKeyActive('a'))");
TEST_PROGRAM("assert(not input:isKeyActive('b'))");
TEST_PROGRAM("assert(#input:activeKeys() == 0)");
struct mScriptKeyEvent keyEvent = {
.d = { .type = mSCRIPT_EV_TYPE_KEY },
.state = mSCRIPT_INPUT_STATE_DOWN,
.key = 'a'
};
mScriptContextFireEvent(&context, &keyEvent.d);
// This changes it to STATE_HELD, but increments the down counter
mScriptContextFireEvent(&context, &keyEvent.d);
keyEvent.state = mSCRIPT_INPUT_STATE_DOWN;
keyEvent.key = 'b';
mScriptContextFireEvent(&context, &keyEvent.d);
TEST_PROGRAM("assert(input:isKeyActive('a'))");
TEST_PROGRAM("assert(input:isKeyActive('b'))");
TEST_PROGRAM("assert(#input:activeKeys() == 2)");
TEST_PROGRAM(
"up = {}\n"
"function cb(ev)\n"
" assert(ev.type == C.EV_TYPE.KEY)\n"
" assert(ev.state == C.INPUT_STATE.UP)\n"
" table.insert(up, ev.key)\n"
"end\n"
"id = callbacks:add('key', cb)\n"
);
mScriptContextClearKeys(&context);
TEST_PROGRAM("assert(not input:isKeyActive('a'))");
TEST_PROGRAM("assert(not input:isKeyActive('b'))");
TEST_PROGRAM("assert(#input:activeKeys() == 0)");
TEST_PROGRAM("assert(#up == 2)");
mScriptContextDeinit(&context);
}
M_TEST_DEFINE(gamepadExport) {
SETUP_LUA;
@ -176,5 +220,6 @@ M_TEST_SUITE_DEFINE_SETUP_TEARDOWN(mScriptInput,
cmocka_unit_test(seq),
cmocka_unit_test(fireKey),
cmocka_unit_test(activeKeys),
cmocka_unit_test(clearKeys),
cmocka_unit_test(gamepadExport),
)