eventHandler not called for buttons

,

I am trying out the C-API SDK.
For this I used the Hello World example as a start and can compile it just fine.
Then I changed it a little to change the text if a button is pressed but it seems like the eventHandler() function is not called for buttons in the simulator.
I added a logging function to it to test my theory and i get log output on startup, pause, resume but not for buttons.

I am on Fedora 35 and use the SDK 1.9
Another suggestion/question: Why is clang used for the final linking and not gcc on linux? Everything else uses the gcc toolchain.

Greetings Stefan

Hi there, I'd like to look into your question about gcc and clang. Can you post your build log please?

I've been working with the Hello World C example, but haven't modified it yet. Can you post the code you're using to deal with the button clicks and I'll take a look at it?

@james Here is the output while compiling:

mkdir -p build
mkdir -p build/dep
/usr/bin/arm-none-eabi-gcc -g -c -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1 -O2 -falign-functions=16 -fomit-frame-pointer -gdwarf-2 -Wall -Wno-unused -Wstrict-prototypes -Wno-unknown-pragmas -fverbose-asm -ffunction-sections -fdata-sections -Wa,-ahlms=build/main.lst -DTARGET_PLAYDATE=1 -DTARGET_EXTENSION=1  -MD -MP -MF build/dep/main.o.d -I . -I . -I /home/user/Downloads/PlaydateSDK-1.9.0/C_API src/main.c -o build/main.o
/usr/bin/arm-none-eabi-gcc -g -c -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1 -O2 -falign-functions=16 -fomit-frame-pointer -gdwarf-2 -Wall -Wno-unused -Wstrict-prototypes -Wno-unknown-pragmas -fverbose-asm -ffunction-sections -fdata-sections -Wa,-ahlms=build/setup.lst -DTARGET_PLAYDATE=1 -DTARGET_EXTENSION=1  -MD -MP -MF build/dep/setup.o.d -I . -I . -I /home/user/Downloads/PlaydateSDK-1.9.0/C_API /home/user/Downloads/PlaydateSDK-1.9.0/C_API/buildsupport/setup.c -o build/setup.o
/usr/bin/arm-none-eabi-gcc -g build/main.o build/setup.o -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-sp-d16 -D__FPU_USED=1 -T/home/user/Downloads/PlaydateSDK-1.9.0/C_API/buildsupport/link_map.ld -Wl,-Map=build/pdex.map,--cref,--gc-sections,--no-warn-mismatch    -o build/pdex.elf
/usr/bin/arm-none-eabi-objcopy -O binary build/pdex.elf build/pdex.bin
cp build/pdex.bin Source
clang -shared -fPIC -lm -g -DTARGET_SIMULATOR=1 -DTARGET_EXTENSION=1 -I . -I /home/user/Downloads/PlaydateSDK-1.9.0/C_API -o build/pdex.so src/main.c /home/user/Downloads/PlaydateSDK-1.9.0/C_API/buildsupport/setup.c
touch Source/pdex.bin
cp build/pdex.so Source
/home/user/Downloads/PlaydateSDK-1.9.0/bin/pdc -sdkpath /home/user/Downloads/PlaydateSDK-1.9.0 Source HelloWorld.pdx
rm build/main.o build/setup.o

There you see clang being called. By digging deeper since my last post I think this is done for the simulator build. Which is fine, don't get me wrong. I just thought on linux many distributions have gcc available per default while clang needs to be installed.
I actually tried to just replace clang line 144 in SDK/C_API/buildsupport/common.mk with gcc which works just fine. Maybe it is possible to expose this as variable? Default would be $(CC) but that is already used so maybe $(CC-SIMULATOR)? It could still default to clang.

@Robert123
Sure thing, here is my changed eventHandler in main.c of the Hello World C_API example:

int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t arg)
{
	(void)arg; // arg is currently only used for event = kEventKeyPressed
    pd->system->logToConsole("Hi\n");

	if ( event == kEventInit )
	{
		const char* err;
		font = pd->graphics->loadFont(fontpath, &err);
		
		if ( font == NULL )
			pd->system->error("%s:%i Couldn't load font %s: %s", __FILE__, __LINE__, fontpath, err);

		// Note: If you set an update callback in the kEventInit handler, the system assumes the game is pure C and doesn't run any Lua code in the game
		pd->system->setUpdateCallback(update, pd);
	}
    if (event == kEventKeyPressed) {
        pd->system->logToConsole("%li\n", arg);
    }

	
	return 0;
}

As mentioned in my previous post, the logging of "Hi" happens if I for example press the Menu Button or lock the screen but not for the Buttons A,B and directions.
I first assumed I must enable the buttons but the Documentation only specifies activation of the accelerometer so I assume that is not it.

Greetings
Stefan

P.S.: In case it is easier here is the diff of the main:

--- /src/main.c	2022-02-28 23:15:18.000000000 +0100
+++ src/main.c	2022-03-03 09:52:31.975150720 +0100
@@ -21,6 +21,7 @@
 int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t arg)
 {
 	(void)arg; // arg is currently only used for event = kEventKeyPressed
+    pd->system->logToConsole("Hi\n");
 
 	if ( event == kEventInit )
 	{
@@ -33,6 +34,10 @@
 		// Note: If you set an update callback in the kEventInit handler, the system assumes the game is pure C and doesn't run any Lua code in the game
 		pd->system->setUpdateCallback(update, pd);
 	}
+    if (event == kEventKeyPressed) {
+        pd->system->logToConsole("%li\n", arg);
+    }
+
 	
 	return 0;
 }

There's a variety of things which could be going on. In a situation like this I old-school it and just put a bunch of print/log statements in order. I.e. logToConsole("one"), logToConsole("two'), etc. Then when you run it the log shows you the actual rather than anticipated thread of control. From there you can zero in on why bodies of code aren't being entered, etc. If we could debug a game in the simulator while running it from visual studio, then you could use breakpoints but I don't know if we can do that.

In the above case the you need these traces, in addition to your "Hi" one, inside the ktEventInit block, immediately after that block, inside the kEventKeyPressed block, and immediately after it. Maybe also see if there is a print method that works on the enum PDSystemEvent itself.

Also one or more in the update() function.

Damn it's 2am but now I'm really curious, I'm going to hack your changes into my running Hello World program to see what I should have done an hour ago :slight_smile:

Ok I sprinkled comments in...and as you say, none of the buttons are registereding. I'm thinking we have to register handlers for each button, as is done in Lua? I'll try that tomorrow, time to get a few hours sleep.

P.S. also had some really bizarre problems in visual studio after inserting some of the comments. Compile failures. Exited, replaced file, cleaned it all up, tried again,still a problem. After a 3rd try it seemed to be fixed. I'm wondering if when some type of error happens it breaks a file somewhere and it has to be remake'd before recompiling.

So, the odd thing here is that we don't call eventHandler() for button presses. Instead, you use

playdate->system->getButtonState(PDButtons* current, PDButtons* pushed, PDButtons* released);

to return the current state of the buttons, which buttons were pushed in the last frame, and/or which buttons were released in the last frame. Any of the arguments can be NULL. I was going to replace that with calls to eventHandler() but all of the game devs that were using the C API said they preferred this polling function. Obviously this is a point of confusion, so I'll add kEventButtonPressed after all (and leave getButtonState()).

Yeah we use the same makefile on both macos and linux. I'll file a bug to make that a little smarter.

@dave Alright, that explains it. I just assumed as there is a kEventKeyPressed that this event would be triggered.
I actually saw the getButtonState() but coming from an embedded background I somewhat preferred interrupt over polling but that is just my personal background.
I can actually live with both very well, I would just suggest to either remove kEventKeyPressed and it's siblings or at least document it. Implementing it is fine of course too. This could also enable more energy efficient implementations in the future if you would expose some kind of sleep which only wakes up on button interrupt etc. for games that do not need to update their screen very often (e.g. Sudoku, chess etc.)

Have you considered making the source of the documentation open source so the Community can propose patches?

@james Sounds great, thank you!

This is an instant poll I assume, rather than the option of a timed libc poll(2)?

I'm another one surprised that bottons don't interrupt the callback. This means that we have to call the poll for almost every frame?

Yes, the function returns immediately: We read the button states on the systick interrupt, at 1kHz. We debounce there, requiring the button to read as pressed or released for 20 cycles before setting the corresponding flag that gets picked up at the start of the run loop. Then getButtonState() returns those flags.

1 Like

I just created an account for the only purpose to report this bug. Please call the event handler as suggested in the documentation and examples (e.g. C_API game of life example) or update the documentation.

As a new developer it's not easy to know what is a "silly simulator behavior" or intended functionality.

Can you please explain what bug it is you're reporting here? It's not clear at all from context what you're referring to. What is the expected behavior and what are you seeing that's different from that?

Well, basically the title - eventHandler not called for buttons is the bug.

The documentation for version 1.12.3 does say regarding the eventHandler:

When an arbitrary key is pressed or released in the simulator this function is called with event set to kEventKeyPressed or kEventKeyReleased and the keycode of the key in the arg argument.

and in PlaydateSDK\C_API\Examples\Hello World\src\main.c in int eventHandler(...) it says

int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t arg)
{
	(void)arg; // arg is currently only used for event = kEventKeyPressed
    ...

both of which are incorrect, kEventKeyPressed is never sent as far as I can tell - at least I have not been able to trigger it via the simulator.

So expected behavior: evenHandler should be called or documentation should be updated to indicate that the event is never triggered.

This works as expected for me:

#include <stdio.h>
#include <stdlib.h>

#include "pd_api.h"

static int update(void* userdata) {	return 1; }

#ifdef _WINDLL
__declspec(dllexport)
#endif
int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t arg)
{
	if ( event == kEventInit )
		pd->system->setUpdateCallback(update, pd);
	else if ( event == kEventKeyPressed )
		pd->system->logToConsole("key pressed: %x", arg);
	
	return 0;
}

When I press a key that's not mapped to a control input (by default, arrow keys and A for the B button and S for the A Button) I get a message on the console telling me which key was pressed.

I'm on macOS, but I don't see anything suspicious in the WX code. Can you give this demo a try and see if you get the same result?

Ah! Ok, it's me misunderstanding - I expected the callback to be for the device input, not host keyboard presses. So the callback is only used for simulator builds to respond to keyboard input.

Thanks for clearing this up and sorry for wasting your time.