2012/08/17

SDLイベントキューの実装を解析

SDLではOSが送ってくるウィンドウメッセージをいったんSDL側で全て吸収してSDL独自形式に変換した上で、SDL_PollEventを使用してユーザー側に渡して処理をさせます。
ここではそのウィンドウメッセージをどう処理しているのかコードを辿っていきたいと思う。

まず、SDLにおけるウィンドウプロシージャの実装はSDL_sysevents.cに定義されているWinMessage関数内で行われている。
ここから様々なサブシステムにメッセージを投げて処理をしていると思われるがウィンドウプロシージャ側から辿るのが難しそうなので逆方向からアプローチを行う。

ユーザーがイベントを取得するSDL_PollEvent側から辿ってみる。
SDL_PollEvent(正確にはSDL_PeepEvent)で使用するSDL_EventQ(イベントキュー)はグローバルメンバ変数で、SDL_events.cに次のように定義されている

[cpp]
/* SDL_events.c */
/* Private data -- event queue */
#define MAXEVENTS 128
static struct {
SDL_mutex *lock;
int active;
int head;
int tail;
SDL_Event event[MAXEVENTS];
int wmmsg_next;
struct SDL_SysWMmsg wmmsg[MAXEVENTS];
} SDL_EventQ;
[/cpp]

構造体の仕様から、SDLの内部処理でeventメンバに対して随時ウィンドウメッセージを処理したイベントを追加されることが予想される。では、実際にどこでイベントが追加されるかというとSDL_AddEvent内で処理される。

簡単に流れを整理するとWinMessage>(SDL入力処理?)>SDL_AddEvent>SDL_PollEventの順に処理されることでメッセージをやり取りするのではないかと推測できる。

次はSDL_AddEventをだれが呼び出しているかについて調べていきたい。
以降から多少複雑になるが、SDL_AddEventを呼び出している処理はSDL_PollEvent内でも呼び出しているSDL_PeepEventsによって追加処理も行われる。
これはSDL_PeepEventsと引数であるSDL_eventactionが次のような定義になっているためである。
定義を見るとSDL_ADDEVNETを渡せばイベントを登録するし、それ以外であればイベントを取得する処理になるのがわかる。

[cpp]
int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
Uint32 mask)

/* SDL_eventactionの定義 * /
typedef enum {
SDL_ADDEVENT,
SDL_PEEKEVENT,
SDL_GETEVENT
} SDL_eventaction;
[/cpp]

ではさらに辿ってSDL_PeepEventに対してSDL_ADDEVENTを渡している処理を追ってみる。
SDL_PeepEventをさらにラップしているSDL_PushEventを経由して多岐にわたるソースコードからイベントが登録されている。
SDL_PushEventを使用してイベントを登録しているサブシステムは以下の通り。

  • sdl_mouse.c

  • sdl_keyboard.c

  • sdl_joystick.c

  • sdl_events.c

  • sdl_resize.c

  • sdl_quit.c

  • sdl_expose.c

  • sdl_active.c

説明は省くがsdl_mouse、sdl_keyboardやsdl_joystick等入力処理からの登録がほとんどである。
これを集約してさらに元をたどるとWinMessageに行き当たる。

以上でSDLがウィンドウプロシージャからのメッセージをどの様にユーザーに提供しているのか大まかに把握できた。

0 件のコメント:

コメントを投稿