从 C 绑定传递的 Ada SDL Unchecked Union

Ada SDL Unchecked Union passed from C binding

我正在使用 AdaSDL2,这是一个绑定到 C 库的第三方。 SDL 中的事件是通过联合处理的,如参考文献所示:

http://www.willusher.io/sdl2%20tutorials/2013/08/20/lesson-4-handling-events/

问题在于绑定将 SDL_Event 类型定义为未检查联合,因此您无法检查判别式以查看它是什么类型。这是类型的定义:

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);

所以当上面参考中的示例代码说要检查 e.type 时,我在 Ada 类型中没有相关值。当我尝试这个时:

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 说“无法引用 Unchecked_Union 的判别式。我尝试了几个不同的想法来弄清楚它是什么类型的事件,但到目前为止 none 似乎既可行又有效。对此有通用的解决方案吗,或者有人有任何想法吗?谢谢。

在我看来,所有在区分组件中使用的记录类型都以(例如)

开头
type SDL_CommonEventRecord is record
   typ       : aliased Uint32;
   timestamp : aliased Uint32;
end record;

并且这些将被覆盖,所以 typSDL_Event 的前 4 个字节;也就是说,typcommon.typwindow.typ 都引用存储中的相同数据。

我猜你应该写一个 case 语句来处理这个:

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;