root/trunk/luigi/adapters/sdl.d

Revision 48, 14.6 kB (checked in by baxissimo, 2 years ago)

Finally fixed it so that the GUI can steal mouse clicks and the user can listen for everything else.

Line 
1 //---------------------------------------------------------------------
2 /*
3  Copyright:
4
5   luigi/adapter/glfw.d
6      -- GLFW input adapter for the 'Luigi' user interface library.
7
8   Copyright (C) 2006 William V. Baxter III
9
10   This software is provided 'as-is', without any express or implied
11   warranty.  In no event will the authors be held liable for any
12   damages arising from the use of this software.
13
14   Permission is granted to anyone to use this software for any
15   purpose, including commercial applications, and to alter it and
16   redistribute it freely, subject to the following restrictions:
17
18   1. The origin of this software must not be misrepresented; you must
19      not claim that you wrote the original software. If you use this
20      software in a product, an acknowledgment in the product
21      documentation would be appreciated but is not required.
22   2. Altered source versions must be plainly marked as such, and must
23      not be misrepresented as being the original software.
24   3. This notice may not be removed or altered from any source distribution.
25
26   William Baxter wbaxter@gmail.com
27 */
28 module luigi.adapters.sdl;
29
30 import luigi.base;
31 import luigi.event;
32 import luigi.adapter;
33 import derelict.sdl.sdl;
34 import luigi.signalobj;
35
36 import std.ctype;
37
38 import std.stdio : writefln;
39
40 int translate_key(int sdlkey)
41 {
42     if (sdlkey<256) {
43         switch(sdlkey) {
44         case SDLK_BACKSPACE: return Key.Backspace;
45         case SDLK_TAB: return Key.Tab;
46         case SDLK_RETURN: return Key.Enter;
47         case SDLK_ESCAPE: return Key.Escape;
48         case SDLK_SPACE: return Key.Space;
49         case SDLK_DELETE: return Key.Delete;
50 /*
51   // these are all just regular ASCII
52         case SDLK_CLEAR: return Key.Clear;
53         case SDLK_PAUSE: return Key.Pause;
54         case SDLK_EXCLAIM: return Key.;
55         case SDLK_QUOTEDBL: return Key.;
56         case SDLK_HASH: return Key.;
57         case SDLK_DOLLAR: return Key.;
58         case SDLK_AMPERSAND: return Key.;
59         case SDLK_QUOTE: return Key.;
60         case SDLK_LEFTPAREN: return Key.;
61         case SDLK_RIGHTPAREN: return Key.;
62         case SDLK_ASTERISK: return Key.;
63         case SDLK_PLUS: return Key.;
64         case SDLK_COMMA: return Key.;
65         case SDLK_MINUS: return Key.;
66         case SDLK_PERIOD: return Key.;
67         case SDLK_SLASH: return Key.;
68         case SDLK_0: return Key.;
69         case SDLK_1: return Key.;
70         case SDLK_2: return Key.;
71         case SDLK_3: return Key.;
72         case SDLK_4: return Key.;
73         case SDLK_5: return Key.;
74         case SDLK_6: return Key.;
75         case SDLK_7: return Key.;
76         case SDLK_8: return Key.;
77         case SDLK_9: return Key.;
78         case SDLK_COLON: return Key.;
79         case SDLK_SEMICOLON: return Key.;
80         case SDLK_LESS: return Key.;
81         case SDLK_EQUALS: return Key.;
82         case SDLK_GREATER: return Key.;
83         case SDLK_QUESTION: return Key.;
84         case SDLK_AT: return Key.;
85         case SDLK_LEFTBRACKET: return Key.;
86         case SDLK_BACKSLASH: return Key.;
87         case SDLK_RIGHTBRACKET: return Key.;
88         case SDLK_CARET: return Key.;
89         case SDLK_UNDERSCORE: return Key.;
90         case SDLK_BACKQUOTE: return Key.;
91 */
92         default:
93             return sdlkey; // must be ascii?
94         }
95     }
96
97     switch(sdlkey) {
98     case SDLK_KP0: return Key.KP0;
99     case SDLK_KP1: return Key.KP1;
100     case SDLK_KP2: return Key.KP2;
101     case SDLK_KP3: return Key.KP3;
102     case SDLK_KP4: return Key.KP4;
103     case SDLK_KP5: return Key.KP5;
104     case SDLK_KP6: return Key.KP6;
105     case SDLK_KP7: return Key.KP7;
106     case SDLK_KP8: return Key.KP8;
107     case SDLK_KP9: return Key.KP9;
108     case SDLK_KP_PERIOD: return Key.KP_Decimal;
109     case SDLK_KP_DIVIDE: return Key.KP_Divide;
110     case SDLK_KP_MULTIPLY: return Key.KP_Multiply;
111     case SDLK_KP_MINUS: return Key.KP_Subtract;
112     case SDLK_KP_PLUS: return Key.KP_Add;
113     case SDLK_KP_ENTER: return Key.KP_Enter;
114     case SDLK_KP_EQUALS: return Key.KP_Equals;
115
116     /* Arrows + Home/End pad */
117     case SDLK_UP: return Key.Up;
118     case SDLK_DOWN: return Key.Down;
119     case SDLK_RIGHT: return Key.Right;
120     case SDLK_LEFT: return Key.Left;
121     case SDLK_INSERT: return Key.Insert;
122     case SDLK_HOME: return Key.Home;
123     case SDLK_END: return Key.End;
124     case SDLK_PAGEUP: return Key.PageUp;
125     case SDLK_PAGEDOWN: return Key.PageDown;
126
127     /* Function keys */
128     case SDLK_F1: return Key.F1;
129     case SDLK_F2: return Key.F2;
130     case SDLK_F3: return Key.F3;
131     case SDLK_F4: return Key.F4;
132     case SDLK_F5: return Key.F5;
133     case SDLK_F6: return Key.F6;
134     case SDLK_F7: return Key.F7;
135     case SDLK_F8: return Key.F8;
136     case SDLK_F9: return Key.F9;
137     case SDLK_F10: return Key.F10;
138     case SDLK_F11: return Key.F11;
139     case SDLK_F12: return Key.F12;
140     case SDLK_F13: return Key.F13;
141     case SDLK_F14: return Key.F14;
142     case SDLK_F15: return Key.F15;
143
144     /* Key state modifier keys */
145     case SDLK_NUMLOCK: return Key.NumLock;
146     case SDLK_CAPSLOCK: return Key.CapsLock;
147     case SDLK_SCROLLOCK: return Key.ScrollLock;
148     case SDLK_RSHIFT: return Key.RShift;
149     case SDLK_LSHIFT: return Key.LShift;
150     case SDLK_RCTRL: return Key.RCtrl;
151     case SDLK_LCTRL: return Key.LCtrl;
152     case SDLK_RALT: return Key.RAlt;
153     case SDLK_LALT: return Key.LAlt;
154     case SDLK_RMETA: return Key.RMeta;
155     case SDLK_LMETA: return Key.LMeta;
156     case SDLK_RSUPER: return Key.RSuper;
157     case SDLK_LSUPER: return Key.LSuper;
158     case SDLK_MODE: return Key.Mode;
159     case SDLK_COMPOSE: return Key.Compose;
160
161     /* Miscellaneous function keys */
162     case SDLK_HELP: return Key.Help;
163     case SDLK_PRINT: return Key.Print;
164     case SDLK_SYSREQ: return Key.SysReq;
165     case SDLK_BREAK: return Key.Break;
166     case SDLK_MENU: return Key.Menu;
167     case SDLK_POWER: return Key.Power;
168     case SDLK_EURO: return Key.Euro;
169     case SDLK_UNDO: return Key.Undo;
170
171     default:
172         return Key.Unknown;
173     }
174 }
175 dchar translate_char(int sdlkey, KeyMods mods)
176 {
177     if (mods & (KeyMods.Alt|KeyMods.Ctrl)) return 0;
178
179     // Space tends to print as space regardless of shift key status
180     if (isspace(sdlkey)) return sdlkey;
181
182     if (mods & KeyMods.Shift) {
183         if (islower(sdlkey)) {
184             return toupper(sdlkey);
185         }
186         // this part is keyboard specific.  This is only correct for a US keyboard.
187         switch(sdlkey) {
188         case '1': return '!';
189         case '2': return '@';
190         case '3': return '#';
191         case '4': return '$';
192         case '5': return '%';
193         case '6': return '^';
194         case '7': return '&';
195         case '8': return '*';
196         case '9': return '(';
197         case '0': return ')';
198         case '-': return '_';
199         case '=': return '+';
200         case '\\': return '|';
201         case '[': return '{';
202         case ']': return '}';
203         case '`': return '~';
204         case ',': return '<';
205         case '.': return '>';
206         case '/': return '?';
207         case '\'': return '"';
208         case ';': return ':';
209         default:
210             // shift+something that we don't understand
211             if (isprint(sdlkey)) return sdlkey;
212             else return 0;
213         }
214     }
215     else {
216         // non-shift key
217         switch(sdlkey) {
218         case SDLK_KP0: return '0';
219         case SDLK_KP1: return '1';
220         case SDLK_KP2: return '2';
221         case SDLK_KP3: return '3';
222         case SDLK_KP4: return '4';
223         case SDLK_KP5: return '5';
224         case SDLK_KP6: return '6';
225         case SDLK_KP7: return '7';
226         case SDLK_KP8: return '8';
227         case SDLK_KP9: return '9';
228         case SDLK_KP_PERIOD: return '.';
229         case SDLK_KP_DIVIDE: return '/';
230         case SDLK_KP_MULTIPLY: return '*';
231         case SDLK_KP_MINUS: return '-';
232         case SDLK_KP_PLUS: return '+';
233         case SDLK_KP_EQUALS: return '=';
234         default:
235             if (isprint(sdlkey)) return sdlkey;
236         }
237     }       
238     // must not be a printable char
239     return 0;
240 }
241
242
243 class SDLAdapter : InputAdapter
244 {
245     /// Singleton access via static opCall SDLAdapter()
246     static SDLAdapter opCall() {
247         static SDLAdapter myinstance = null;
248         if (!myinstance) {
249             myinstance = new SDLAdapter;
250             myinstance.init();
251         }
252         return myinstance;
253     }
254     /// Singleton access via 'inst' property
255     static SDLAdapter inst() {
256         return SDLAdapter();
257     }
258
259     /** Return the size of the SDL window.
260      *  Params: an SDL_Surface* cast to a WindowHandle
261      */
262     Size get_window_size(WindowHandle win) {
263         // only one window in SDL to query the size of
264         SDL_Surface *surf = cast(SDL_Surface*)win;
265         if (surf is null) {
266             throw new GUIException(
267                 "Null is not a valid WindowHandle for SDLAdapter.  \n"
268                 "Overlay needs the window's SDL_Surface pointer: \n"
269                 "  e.g. gui = new Overlay( cast(WindowHandle)main_surface );");
270         }
271         return Size(surf.w,surf.h);
272     }
273
274     /** Call this to give Luigi access to SDL events coming into your app's
275      *  main event loop. Returns whether the event was sucessfully dispatched
276      *  or not.
277      *  So the pattern is:
278      *  ---------------
279      *  while ( SDL_PollEvent(&event) ) {
280      *      if(dispatchEvent(event))
281      *          continue;
282      *      // otherwise handle the event
283      *      switch(event.type) {
284      *          ...
285      *      }
286      *  ---------------
287      */
288     bool dispatchEvent(inout SDL_Event event)
289     {
290         const bool EVENT_CONSUMED = true;
291         const bool EVENT_ALIVE = false;
292
293         switch(event.type) {
294         case SDL_KEYDOWN:
295         case SDL_KEYUP:
296             return !keyCallback(event.key);
297         case SDL_MOUSEMOTION:
298             mouseMotionCallback(event.motion);
299             return EVENT_CONSUMED;
300
301         case SDL_MOUSEBUTTONDOWN:
302         case SDL_MOUSEBUTTONUP:
303             return !mouseButtonCallback(event.button);
304
305         case SDL_VIDEORESIZE:
306             windowSizeCallback(event.resize);
307             return EVENT_ALIVE;
308
309         case SDL_QUIT:
310             windowCloseCallback(event.quit);
311             return EVENT_ALIVE;
312
313         // We don't do anything with these events currently
314         case SDL_VIDEOEXPOSE:
315         case SDL_SYSWMEVENT:
316         case SDL_USEREVENT:
317         case SDL_ACTIVEEVENT:
318         case SDL_JOYAXISMOTION:
319         case SDL_JOYHATMOTION:
320         case SDL_JOYBALLMOTION:
321         case SDL_JOYBUTTONDOWN:
322         case SDL_JOYBUTTONUP:
323         default:
324             return EVENT_ALIVE;
325         }
326         return EVENT_ALIVE;
327     }
328
329 private:
330
331     MouseButtons _getButtons(Uint8 sdlbtn) {
332         alias MouseButtons M;
333         MouseButtons m = M.None;
334         if (sdlbtn & (1<<0)) m|=M.Left;
335         if (sdlbtn & (1<<1)) m|=M.Middle;
336         if (sdlbtn & (1<<2)) m|=M.Right;
337         return m;
338     }
339     MouseButtons _getButtons() {
340         return _getButtons(SDL_GetMouseState(null,null));
341     }
342     KeyMods _getMods(SDLMod sdlmod) {
343         alias KeyMods M;
344         KeyMods m = M.None;
345         if (sdlmod & KMOD_CTRL)  m|= M.Ctrl;
346         if (sdlmod & KMOD_SHIFT) m|= M.Shift;
347         if (sdlmod & KMOD_ALT)   m|= M.Alt;
348         return m;
349     }
350     KeyMods _getMods() {
351         return _getMods(SDL_GetModState());
352     }
353
354     // SDL Event Handlers
355     bool keyCallback(inout SDL_KeyboardEvent sdl)
356     {
357         _KeyEvent ev;
358         int k = translate_key(sdl.keysym.sym);
359         dchar ch;
360         if (SDL_EnableUNICODE(-1)) {
361             ch = sdl.keysym.unicode;
362         }
363         else {
364             ch = translate_char(sdl.keysym.sym, ev.mods);
365         }
366         void _initEvent() {
367             ev.key = k;
368             ev.ch = ch;
369             ev.mods = inst._getMods();
370             ev.is_press  = (sdl.type==SDL_KEYDOWN);
371             ev.is_key = true;
372             ev.is_char = (ev.ch != 0);
373         }
374         _initEvent();
375         inst.sig.sysKey.emit(&ev);
376         if (ev.alive) {
377             _initEvent();
378             inst.sig.key.emit(&ev);
379         }
380         return ev.alive;
381     }
382     bool mouseButtonCallback(inout SDL_MouseButtonEvent sdl)
383     {
384         if (sdl.button == SDL_BUTTON_WHEELUP || sdl.button == SDL_BUTTON_WHEELDOWN)
385         {
386             return mouseWheelCallback(sdl);
387         }
388         _MouseButtonEvent ev;
389         void _initEvent() {
390             ev.x = ev.winx = sdl.x;
391             ev.y = ev.winy = sdl.y;
392             ev.is_press  = (sdl.type==SDL_MOUSEBUTTONDOWN);
393             ev.mods = inst._getMods();
394             ev.pressed = inst._getButtons();
395             if      (sdl.button == SDL_BUTTON_LEFT) ev.button = MouseButtons.Left;
396             else if (sdl.button == SDL_BUTTON_RIGHT) ev.button = MouseButtons.Right;
397             else if (sdl.button == SDL_BUTTON_MIDDLE) ev.button = MouseButtons.Middle;
398         }
399         _initEvent();
400         inst.sig.sysMouseButton.emit(&ev);
401         if (ev.alive) {
402             _initEvent();
403             inst.sig.mouseButton.emit(&ev);
404         }
405         return ev.alive;
406     }
407     bool mouseWheelCallback(inout SDL_MouseButtonEvent sdl)
408     {
409         if (sdl.type == SDL_MOUSEBUTTONUP) return true; // ignore up of down/up pair
410         _MouseWheelEvent ev;
411         ev.x = ev.winx = sdl.x;
412         ev.y = ev.winy = sdl.y;
413         const int inc = 1; // is this right?
414         if (sdl.button == SDL_BUTTON_WHEELUP)
415             ev.delta = inc;
416         else
417             ev.delta = -inc;
418         ev.pressed = inst._getButtons();
419         ev.mods = inst._getMods();
420
421         inst.sig.mouseWheel.emit(&ev);
422         return ev.alive;
423     }
424     bool mouseMotionCallback(inout SDL_MouseMotionEvent sdl)
425     {
426         _MouseMoveEvent ev;
427         ev.x = ev.winx = sdl.x;
428         ev.y = ev.winy = sdl.y;
429         ev.pressed = inst._getButtons(sdl.state);
430         ev.mods = inst._getMods();
431
432         inst.sig.mouseMove.emit(&ev);
433         return ev.alive;
434     }
435     void windowSizeCallback(inout SDL_ResizeEvent sdl)
436     {
437         writefln("Resize!");
438         _WindowSizeEvent ev;
439         ev.w = sdl.w;
440         ev.h = sdl.h;
441         inst.sig.windowSize.emit(&ev);
442     }
443     bool  windowCloseCallback(inout SDL_QuitEvent sdl)
444     {
445         _WindowCloseEvent ev;
446         inst.sig.windowClose.emit(&ev);
447         return ev.alive;
448     }
449     void windowRefreshCallback()
450     {
451         //_WindowRefreshEvent ev;
452     }
453
454     // Singleton, so constructor is private
455     this() {
456         initInputAdapter(); // from mixin
457     }
458
459     void init() {
460     }
461
462     ~this() {
463     }
464
465 public:
466     mixin InputAdapterMix;
467
468 }
469
470
471 alias SDLAdapter DefaultAdapter;
Note: See TracBrowser for help on using the browser.