In my last post I showed how to get a circle bouncing back and forth on the screen. Next, I’d need to figure out how Nim handles SDL_Event, which normally uses a union structure along with a type field to determine how the data for an event gets used.
Nim doesn’t have a union type as far as I can tell. It has a pragma for telling the compiler that a Nim structure should be translated to a C union, but that’s not what I"m looking for.
Digging into the SDL2 wrapper a little, I think this is the piece of code I need to understand:
template EvConv(name, name2, ptype: expr; valid: set[TEventType]): stmt {.immediate.}=
proc `name`* (event: var TEvent): ptype =
assert event.kind in valid
return cast[ptype](addr event)
proc `name2`* (event: var TEvent): ptype =
assert event.kind in valid
return cast[ptype](addr event)
which is used like:
EvConv(EvWindow, window, PWindowEvent, {WindowEvent})
What is a template
in Nim’s parlance? As it turns out, it’s a way of creating a simple substitution macro at compile time, and is called like a normal procedure.
Therefore the EvConv
template being defined above is creating 2 procedures that are identical, except for the name. If you direct your gaze to the usage example, the first two parameters are EvWindow
and window
– which means that the example will result in two procedures called EvWindow
and window
, which do precisly the same thing, which is to make certain the kind of event is a valid kind, and then to cast (reinterpret the type without altering the bit structure) the event data into the Nim type pointed to by the ptype pointer.
The result of this is that in my program I can check for a keydown event thusly:
if evt.kind == KeyDown:
if evt.key.keysym.sym == K_ESCAPE:
runGame = false
break
There’s a few things that initially tripped me up with even that, so allow me to explain a few more things:
- the
TEvent
type (in the SDL2 wrapper) is an unsafe/untraced pointer – but it get’s dereferenced implicitely by the “.
” - the
EvConv
template produces theEvKeyboard
andkey
procedures that each can be used in the method call syntax style on TEvent values - The actual key value is retrieved from the
TEvent
propertykeysym
, which in turn is aTKeySym
type. TheTKeySym
type has properties that get values for a scancode, a keycode, or the unicode value. The difference between the scancode and keycode is that the scancode tries to represent the location on the actual keyboard, whereas the keycode is just the value returned by the device, regardless of whether or not it’s in the expected physical position. I chose keycode (the.sym
call) because the scancode seems like it’s rife with potential hardware compatibility issues, and, eventually, I should allow for custom remapping of keys anyway.
Whew!
That still wasn’t much code, but I did learn a lot about the SDL2 wrapper, Nim, and even a little about SDL2 itself!