Keyboard event-based input is working for keydown and keyup

This commit is contained in:
2022-11-05 17:54:45 +01:00
parent 0c145b4e5b
commit 2439c3d7b9
9 changed files with 266 additions and 54 deletions

View File

@@ -1,20 +1,27 @@
import engine; import engine;
//import input; import input;
/*
//input settings, mapping SDL2's virtual keys to event names //input settings, mapping SDL2's virtual keys to event names
mapInputEventToKey("character_up", "w", 0); //event, keysym, keymod mapInputEventToKeyDown("character_up", "w"); //event, keysym
mapInputEventToKey("character_left", "a", 0); //event, keysym, keymod mapInputEventToKeyDown("character_left", "a"); //event, keysym
mapInputEventToKey("character_down", "s", 0); //event, keysym, keymod mapInputEventToKeyDown("character_down", "s"); //event, keysym
mapInputEventToKey("character_right", "d", 0); //event, keysym, keymod mapInputEventToKeyDown("character_right", "d"); //event, keysym
mapInputEventToSpecial("character_up", "arrow_up"); //event, special mapInputEventToKeyUp("character_up", "w"); //event, keysym
mapInputEventToSpecial("character_left", "arrow_left"); //event, special mapInputEventToKeyUp("character_left", "a"); //event, keysym
mapInputEventToSpecial("character_down", "arrow_down"); //event, special mapInputEventToKeyUp("character_down", "s"); //event, keysym
mapInputEventToSpecial("character_right", "arrow_right"); //event, special mapInputEventToKeyUp("character_right", "d"); //event, keysym
mapInputEventToKey("character_jump", " ", 0); //event, keysym, keymod mapInputEventToKeyDown("character_up", "up"); //event, keysym
*/ mapInputEventToKeyDown("character_left", "left"); //event, keysym
mapInputEventToKeyDown("character_down", "down"); //event, keysym
mapInputEventToKeyDown("character_right", "right"); //event, keysym
mapInputEventToKeyUp("character_up", "up"); //event, keysym
mapInputEventToKeyUp("character_left", "left"); //event, keysym
mapInputEventToKeyUp("character_down", "down"); //event, keysym
mapInputEventToKeyUp("character_right", "right"); //event, keysym
//this function must always be called, or the engine won't run //this function must always be called, or the engine won't run
initWindow("Airport Game", 800, 600, false); initWindow("Airport Game", 800, 600, false);

View File

@@ -1,13 +1,18 @@
import node; import node;
//constants
var SPEED: int const = 10;
//variables //variables
var parent: opaque = null; var parent: opaque = null;
var x: int = 50; var x: int = 50;
var y: int = 50; var y: int = 50;
var xspeed: int = 0;
var yspeed: int = 0;
//accessors //accessors
fn getX(node: opaque) { fn getX(node: opaque) {
print "Called getX";
return x; return x;
} }
@@ -26,8 +31,53 @@ fn onInit(node: opaque) {
print "accessed parent"; print "accessed parent";
} }
fn onKeyDown(node: opaque, event: string) {
if (event == "character_up") {
yspeed -= SPEED;
return;
}
if (event == "character_down") {
yspeed += SPEED;
return;
}
if (event == "character_left") {
xspeed -= SPEED;
return;
}
if (event == "character_right") {
xspeed += SPEED;
return;
}
}
fn onKeyUp(node: opaque, event: string) {
if (event == "character_up" && yspeed < 0) {
yspeed = 0;
return;
}
if (event == "character_down" && yspeed > 0) {
yspeed = 0;
return;
}
if (event == "character_left" && xspeed < 0) {
xspeed = 0;
return;
}
if (event == "character_right" && xspeed > 0) {
xspeed = 0;
return;
}
}
fn onStep(node: opaque) { fn onStep(node: opaque) {
print "render.toy:onStep()"; x += xspeed;
y += yspeed;
} }
fn onFree(node: opaque) { fn onFree(node: opaque) {
@@ -37,7 +87,7 @@ fn onFree(node: opaque) {
} }
fn onDraw(node: opaque) { fn onDraw(node: opaque) {
print "render.toy:onDraw() called"; // print "render.toy:onDraw() called";
var px = parent.callNode("getX"); var px = parent.callNode("getX");
var py = parent.callNode("getY"); var py = parent.callNode("getY");

View File

@@ -11,6 +11,8 @@
#include "parser.h" #include "parser.h"
#include "compiler.h" #include "compiler.h"
#include "interpreter.h" #include "interpreter.h"
#include "literal_array.h"
#include "literal_dictionary.h"
#include "console_colors.h" #include "console_colors.h"
@@ -40,6 +42,12 @@ void initEngine() {
fatalError("Failed to initialize SDL2"); fatalError("Failed to initialize SDL2");
} }
//init events
initLiteralArray(&engine.keyDownEvents);
initLiteralDictionary(&engine.symKeyDownEvents);
initLiteralArray(&engine.keyUpEvents);
initLiteralDictionary(&engine.symKeyUpEvents);
//init Toy //init Toy
initInterpreter(&engine.interpreter); initInterpreter(&engine.interpreter);
injectNativeHook(&engine.interpreter, "engine", hookEngine); injectNativeHook(&engine.interpreter, "engine", hookEngine);
@@ -56,13 +64,9 @@ void initEngine() {
} }
void freeEngine() { void freeEngine() {
SDL_DestroyRenderer(engine.renderer);
SDL_DestroyWindow(engine.window);
SDL_Quit();
//clear existing root node //clear existing root node
if (engine.rootNode != NULL) { if (engine.rootNode != NULL) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree"); callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(engine.rootNode); freeEngineNode(engine.rootNode);
@@ -71,14 +75,31 @@ void freeEngine() {
freeInterpreter(&engine.interpreter); freeInterpreter(&engine.interpreter);
//free events
freeLiteralArray(&engine.keyDownEvents);
freeLiteralDictionary(&engine.symKeyDownEvents);
freeLiteralArray(&engine.keyUpEvents);
freeLiteralDictionary(&engine.symKeyUpEvents);
//free SDL
SDL_DestroyRenderer(engine.renderer);
SDL_DestroyWindow(engine.window);
SDL_Quit();
engine.renderer = NULL; engine.renderer = NULL;
engine.window = NULL; engine.window = NULL;
} }
static void execStep() { static void execEvents() {
//call onStep //clear event lists
if (engine.rootNode != NULL) { if (engine.keyDownEvents.count > 0) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onStep"); freeLiteralArray(&engine.keyDownEvents);
//NOTE: this is likely memory intensive - a more bespoke linked list designed for this task would be better
//NOTE: alternatively - manual memory-wipes, skipping the free step could be better
}
if (engine.keyUpEvents.count > 0) {
freeLiteralArray(&engine.keyUpEvents);
} }
//poll events //poll events
@@ -103,8 +124,65 @@ static void execStep() {
} }
break; break;
//TODO: input //input
case SDL_KEYDOWN: {
//determine the given keycode
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!existsLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral)) {
break;
} }
//get the event name
Literal eventLiteral = getLiteralDictionary(&engine.symKeyDownEvents, keycodeLiteral);
//push to the event list
pushLiteralArray(&engine.keyDownEvents, eventLiteral);
}
break;
case SDL_KEYUP: {
//determine the given keycode
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)(event.key.keysym.sym) );
if (!existsLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral)) {
break;
}
//get the event name
Literal eventLiteral = getLiteralDictionary(&engine.symKeyUpEvents, keycodeLiteral);
//push to the event list
pushLiteralArray(&engine.keyUpEvents, eventLiteral);
}
break;
}
}
//callbacks
if (engine.rootNode != NULL) {
//key down events
for (int i = 0; i < engine.keyDownEvents.count; i++) {
LiteralArray args;
initLiteralArray(&args);
pushLiteralArray(&args, engine.keyDownEvents.literals[i]);
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyDown", &args);
freeLiteralArray(&args);
}
//key up events
for (int i = 0; i < engine.keyUpEvents.count; i++) {
LiteralArray args;
initLiteralArray(&args);
pushLiteralArray(&args, engine.keyUpEvents.literals[i]);
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onKeyUp", &args);
freeLiteralArray(&args);
}
}
}
void execStep() {
if (engine.rootNode != NULL) {
//steps
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onStep", NULL);
} }
} }
@@ -120,18 +198,11 @@ void execEngine() {
struct timeval delta = { .tv_sec = 0, .tv_usec = 1000 * 1000 / 60 }; //60 frames per second struct timeval delta = { .tv_sec = 0, .tv_usec = 1000 * 1000 / 60 }; //60 frames per second
while (engine.running) { while (engine.running) {
execEvents();
//calc the time passed //calc the time passed
gettimeofday(&engine.realTime, NULL); gettimeofday(&engine.realTime, NULL);
// printf("real time: %ld.%ld sim time: %ld.%ld + (delta: %ld.%ld)\n",
// engine.realTime.tv_sec,
// engine.realTime.tv_usec,
// engine.simTime.tv_sec,
// engine.simTime.tv_usec,
// delta.tv_sec,
// delta.tv_usec
// );
//if not enough time has passed //if not enough time has passed
if (timercmp(&engine.simTime, &engine.realTime, <)) { if (timercmp(&engine.simTime, &engine.realTime, <)) {
//while not enough time has passed //while not enough time has passed
@@ -151,7 +222,7 @@ void execEngine() {
SDL_SetRenderDrawColor(engine.renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later SDL_SetRenderDrawColor(engine.renderer, 0, 0, 0, 255); //NOTE: This line can be disabled later
SDL_RenderClear(engine.renderer); //NOTE: This line can be disabled later SDL_RenderClear(engine.renderer); //NOTE: This line can be disabled later
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onDraw"); callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onDraw", NULL);
SDL_RenderPresent(engine.renderer); SDL_RenderPresent(engine.renderer);
} }

View File

@@ -4,6 +4,9 @@
#include "engine_node.h" #include "engine_node.h"
#include "interpreter.h" #include "interpreter.h"
#include "literal_array.h"
#include "literal_dictionary.h"
#include <SDL2/SDL.h> #include <SDL2/SDL.h>
#include <sys/time.h> #include <sys/time.h>
@@ -24,6 +27,13 @@ typedef struct _engine {
SDL_Renderer* renderer; SDL_Renderer* renderer;
int screenWidth; int screenWidth;
int screenHeight; int screenHeight;
//input syms mapped to events
LiteralArray keyDownEvents; //list of events that occurred this frame
LiteralDictionary symKeyDownEvents; //keysym -> event names
LiteralArray keyUpEvents; //list of events that occurred this frame
LiteralDictionary symKeyUpEvents; //keysym -> event names
} Engine; } Engine;
//extern singleton //extern singleton

View File

@@ -101,7 +101,7 @@ void freeEngineNode(EngineNode* node) {
node->freeMemory(node); node->freeMemory(node);
} }
Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key) { Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args) {
Literal ret = TO_NULL_LITERAL; Literal ret = TO_NULL_LITERAL;
//if this fn exists //if this fn exists
@@ -116,6 +116,12 @@ Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Litera
pushLiteralArray(&arguments, n); pushLiteralArray(&arguments, n);
if (args) {
for (int i = 0; i < args->count; i++) {
pushLiteralArray(&arguments, args->literals[i]);
}
}
callLiteralFn(interpreter, fn, &arguments, &returns); callLiteralFn(interpreter, fn, &arguments, &returns);
ret = popLiteralArray(&returns); ret = popLiteralArray(&returns);
@@ -130,18 +136,18 @@ Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Litera
return ret; return ret;
} }
Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName) { Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args) {
//call "fnName" on this node, and all children, if it exists //call "fnName" on this node, and all children, if it exists
Literal key = TO_IDENTIFIER_LITERAL(copyString(fnName, strlen(fnName)), strlen(fnName)); Literal key = TO_IDENTIFIER_LITERAL(copyString(fnName, strlen(fnName)), strlen(fnName));
Literal ret = callEngineNodeLiteral(node, interpreter, key); Literal ret = callEngineNodeLiteral(node, interpreter, key, args);
freeLiteral(key); freeLiteral(key);
return ret; return ret;
} }
void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key) { void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args) {
//if this fn exists //if this fn exists
if (existsLiteralDictionary(node->functions, key)) { if (existsLiteralDictionary(node->functions, key)) {
Literal fn = getLiteralDictionary(node->functions, key); Literal fn = getLiteralDictionary(node->functions, key);
@@ -152,6 +158,13 @@ void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter,
initLiteralArray(&arguments); initLiteralArray(&arguments);
initLiteralArray(&returns); initLiteralArray(&returns);
//feed the arguments in backwards!
if (args) {
for (int i = args->count -1; i >= 0; i--) {
pushLiteralArray(&arguments, args->literals[i]);
}
}
pushLiteralArray(&arguments, n); pushLiteralArray(&arguments, n);
callLiteralFn(interpreter, fn, &arguments, &returns); callLiteralFn(interpreter, fn, &arguments, &returns);
@@ -166,16 +179,16 @@ void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter,
//recurse to the (non-tombstone) children //recurse to the (non-tombstone) children
for (int i = 0; i < node->count; i++) { for (int i = 0; i < node->count; i++) {
if (node->children[i] != NULL) { if (node->children[i] != NULL) {
callRecursiveEngineNodeLiteral(node->children[i], interpreter, key); callRecursiveEngineNodeLiteral(node->children[i], interpreter, key, args);
} }
} }
} }
void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName) { void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args) {
//call "fnName" on this node, and all children, if it exists //call "fnName" on this node, and all children, if it exists
Literal key = TO_IDENTIFIER_LITERAL(copyString(fnName, strlen(fnName)), strlen(fnName)); Literal key = TO_IDENTIFIER_LITERAL(copyString(fnName, strlen(fnName)), strlen(fnName));
callRecursiveEngineNodeLiteral(node, interpreter, key); callRecursiveEngineNodeLiteral(node, interpreter, key, args);
freeLiteral(key); freeLiteral(key);
} }

View File

@@ -44,11 +44,11 @@ CORE_API void initEngineNode(EngineNode* node, Interpreter* interpreter, void* t
CORE_API void pushEngineNode(EngineNode* node, EngineNode* child); //push to the array (prune tombstones when expanding/copying) CORE_API void pushEngineNode(EngineNode* node, EngineNode* child); //push to the array (prune tombstones when expanding/copying)
CORE_API void freeEngineNode(EngineNode* node); //free and tombstone this node CORE_API void freeEngineNode(EngineNode* node); //free and tombstone this node
CORE_API Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key); CORE_API Literal callEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args);
CORE_API Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName); //call "fnName" on this node, and only this node, if it exists CORE_API Literal callEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args); //call "fnName" on this node, and only this node, if it exists
CORE_API void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key); CORE_API void callRecursiveEngineNodeLiteral(EngineNode* node, Interpreter* interpreter, Literal key, LiteralArray* args);
CORE_API void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName); //call "fnName" on this node, and all children, if it exists CORE_API void callRecursiveEngineNode(EngineNode* node, Interpreter* interpreter, char* fnName, LiteralArray* args); //call "fnName" on this node, and all children, if it exists
CORE_API int loadTextureEngineNode(EngineNode* node, char* fname); CORE_API int loadTextureEngineNode(EngineNode* node, char* fname);
CORE_API void freeTextureEngineNode(EngineNode* node); CORE_API void freeTextureEngineNode(EngineNode* node);

View File

@@ -98,7 +98,7 @@ static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments)
//clear existing root node //clear existing root node
if (engine.rootNode != NULL) { if (engine.rootNode != NULL) {
callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree"); callRecursiveEngineNode(engine.rootNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(engine.rootNode); freeEngineNode(engine.rootNode);
FREE(EngineNode, engine.rootNode); FREE(EngineNode, engine.rootNode);
@@ -137,7 +137,7 @@ static int nativeLoadRootNode(Interpreter* interpreter, LiteralArray* arguments)
initEngineNode(engine.rootNode, &inner, tb, size); initEngineNode(engine.rootNode, &inner, tb, size);
//init the new node (and ONLY this node) //init the new node (and ONLY this node)
callEngineNode(engine.rootNode, &engine.interpreter, "onInit"); callEngineNode(engine.rootNode, &engine.interpreter, "onInit", NULL);
//cleanup //cleanup
freeLiteralArray(&inner.stack); freeLiteralArray(&inner.stack);

View File

@@ -2,7 +2,68 @@
#include "memory.h" #include "memory.h"
//TODO: native input calls #include "engine.h"
#include <SDL2/SDL.h>
static int nativeMapInputEventToKey(Interpreter* interpreter, LiteralArray* arguments, LiteralDictionary* symKeyEventsPtr, char* fnName) {
//checks
if (arguments->count != 2) {
interpreter->errorOutput("Incorrect number of arguments passed to ");
interpreter->errorOutput(fnName);
interpreter->errorOutput("\n");
return -1;
}
Literal symLiteral = popLiteralArray(arguments);
Literal evtLiteral = popLiteralArray(arguments);
Literal evtLiteralIdn = evtLiteral;
if (IS_IDENTIFIER(evtLiteral) && parseIdentifierToValue(interpreter, &evtLiteral)) {
freeLiteral(evtLiteralIdn);
}
Literal symLiteralIdn = symLiteral;
if (IS_IDENTIFIER(symLiteral) && parseIdentifierToValue(interpreter, &symLiteral)) {
freeLiteral(symLiteralIdn);
}
if (!IS_STRING(symLiteral) || !IS_STRING(evtLiteral)) {
interpreter->errorOutput("Incorrect type of arguments passed to mapInputEventToKey\n");
return -1;
}
//use the keycode for faster lookups
SDL_Keycode keycode = SDL_GetKeyFromName( AS_STRING(symLiteral) );
if (keycode == SDLK_UNKNOWN) {
interpreter->errorOutput("Unknown key found: ");
interpreter->errorOutput(SDL_GetError());
interpreter->errorOutput("\n");
return -1;
}
Literal keycodeLiteral = TO_INTEGER_LITERAL( (int)keycode );
//save the sym-event pair
setLiteralDictionary(symKeyEventsPtr, keycodeLiteral, evtLiteral); //I could possibly map multiple events to one sym
//cleanup
freeLiteral(symLiteral);
freeLiteral(evtLiteral);
freeLiteral(keycodeLiteral);
return 0;
}
//dry wrappers
static int nativeMapInputEventToKeyDown(Interpreter* interpreter, LiteralArray* arguments) {
return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyDownEvents, "mapInputEventToKeyDown");
}
static int nativeMapInputEventToKeyUp(Interpreter* interpreter, LiteralArray* arguments) {
return nativeMapInputEventToKey(interpreter, arguments, &engine.symKeyUpEvents, "mapInputEventToKeyUp");
}
//call the hook //call the hook
typedef struct Natives { typedef struct Natives {
@@ -13,9 +74,9 @@ typedef struct Natives {
int hookInput(Interpreter* interpreter, Literal identifier, Literal alias) { int hookInput(Interpreter* interpreter, Literal identifier, Literal alias) {
//build the natives list //build the natives list
Natives natives[] = { Natives natives[] = {
// {"mapInputEventToKey", nativeMapInputEventToKey}, {"mapInputEventToKeyDown", nativeMapInputEventToKeyDown},
{"mapInputEventToKeyUp", nativeMapInputEventToKeyUp},
// {"mapInputEventToMouse", nativeMapInputEventToMouse}, // {"mapInputEventToMouse", nativeMapInputEventToMouse},
// {"mapInputEventToSpecial", nativeMapInputEventToSpecial},
{NULL, NULL} {NULL, NULL}
}; };

View File

@@ -96,7 +96,7 @@ static int nativeInitNode(Interpreter* interpreter, LiteralArray* arguments) {
EngineNode* engineNode = AS_OPAQUE(node); EngineNode* engineNode = AS_OPAQUE(node);
//init the new node (and ONLY this node) //init the new node (and ONLY this node)
callEngineNode(engineNode, &engine.interpreter, "onInit"); callEngineNode(engineNode, &engine.interpreter, "onInit", NULL);
//cleanup //cleanup
freeLiteral(node); freeLiteral(node);
@@ -140,7 +140,7 @@ static int nativeFreeChildNode(Interpreter* interpreter, LiteralArray* arguments
//free the node //free the node
if (childNode != NULL) { if (childNode != NULL) {
callRecursiveEngineNode(childNode, &engine.interpreter, "onFree"); callRecursiveEngineNode(childNode, &engine.interpreter, "onFree", NULL);
freeEngineNode(childNode); freeEngineNode(childNode);
} }
@@ -563,7 +563,7 @@ static int nativeCallNode(Interpreter* interpreter, LiteralArray* arguments) {
Literal fnNameIdentifier = TO_IDENTIFIER_LITERAL(copyString(strptr, strlen(strptr)), strlen(strptr)); Literal fnNameIdentifier = TO_IDENTIFIER_LITERAL(copyString(strptr, strlen(strptr)), strlen(strptr));
//call the function //call the function
Literal result = callEngineNodeLiteral(AS_OPAQUE(nodeLiteral), interpreter, fnNameIdentifier); Literal result = callEngineNodeLiteral(AS_OPAQUE(nodeLiteral), interpreter, fnNameIdentifier, NULL);
pushLiteralArray(&interpreter->stack, result); pushLiteralArray(&interpreter->stack, result);