I'm using AdaSDL2, a third-party binding to a C library. Events in SDL are handled via a union, as seen at this reference:
http://www.willusher.io/sdl2%20tutorials/2013/08/20/lesson-4-handling-events/
Problem is that the binding defines the SDL_Event type as an Unchecked Union and as such you can't check a discriminant to see what type it is. Here is the definition of the type:
type SDL_Event (discr : C.unsigned := 0) is record
case discr is
when 0 =>
typ : aliased Uint32;
when 1 =>
common : aliased SDL_CommonEventRecord;
when 2 =>
window : aliased SDL_WindowEventRecord;
when 3 =>
key : aliased SDL_KeyboardEventRecord;
when 4 =>
edit : aliased SDL_TextEditingEventRecord;
when 5 =>
text : aliased SDL_TextInputEventRecord;
when 6 =>
motion : aliased SDL_MouseMotionEventRecord;
when 7 =>
button : aliased SDL_MouseButtonEventRecord;
when 8 =>
wheel : aliased SDL_MouseWheelEventRecord;
when 9 =>
jaxis : aliased SDL_JoyAxisEventRecord;
when 10 =>
jball : aliased SDL_JoyBallEventRecord;
when 11 =>
jhat : aliased SDL_JoyHatEventRecord;
when 12 =>
jbutton : aliased SDL_JoyButtonEventRecord;
when 13 =>
jdevice : aliased SDL_JoyDeviceEventRecord;
when 14 =>
caxis : aliased SDL_ControllerAxisEventRecord;
when 15 =>
cbutton : aliased SDL_ControllerButtonEventRecord;
when 16 =>
cdevice : aliased SDL_ControllerDeviceEventRecord;
when 17 =>
quit : aliased SDL_QuitEventRecord;
when 18 =>
user : aliased SDL_UserEventRecord;
when 19 =>
syswm : aliased SDL_SysWMEventRecord;
when 20 =>
tfinger : aliased SDL_TouchFingerEventRecord;
when 21 =>
mgesture : aliased SDL_MultiGestureEventRecord;
when 22 =>
dgesture : aliased SDL_DollarGestureEventRecord;
when 23 =>
drop : aliased SDL_DropEventRecord;
when others =>
padding : aliased SDL_Event_padding_array;
end case;
end record;
pragma Convention (C_Pass_By_Copy, SDL_Event);
pragma Unchecked_Union (SDL_Event);
So when the example code in the above reference says to check e.type, I don't have a related value in the Ada type. When I try this:
procedure Process_Events is
E : access SDL_Event;
begin
while SDL_PollEvent(E) = 1 loop
if E.discr = SDL_SHUTDOWN then
Ada.Text_IO.Put("Shutdown requested.");
Ada.Task_Identification.Abort_Task(Ada.Task_Identification.Current_Task);
end if;
end loop;
end Process_Events;
GNAT says "cannot reference discriminant of Unchecked_Union. I've tried a couple of different ideas to figure out what type of Event it is but so far none seem both feasible and efficient. Is there a common solution to this, or does anybody have any ideas? Thanks.
Looks to me as though all the record types that are used in the discriminated components start with (e.g.)
type SDL_CommonEventRecord is record
typ : aliased Uint32;
timestamp : aliased Uint32;
end record;
and these are going to be overlaid, so the typ
is the first 4 bytes of the SDL_Event
; that is, typ
, common.typ
, window.typ
all refer to the same data in store.
I guess you’re supposed to write a case statement to handle this:
case E.typ is
when SDL_WINDOWEVENT =>
-- use E.window components
when SDL_KEYDOWN =>
-- use E.key components for key-down
when SDL_KEYUP =>
-- use E.key components for key-up
...
end case;