root/trunk/luigi/adapters/glfw.d

Revision 48, 10.9 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      This was originally written for DerelictGLFW, but the Derelict
8      project has since decided to abandon the project.
9      There are supposedly D bindings distributed with GLFW, so you can
10      link to it directly without Derelict's help.
11
12      This is made to work with Derelict's former GLFW.  Should be
13      easy to get it working with the D bindings that come with GLFW, or
14      just use GLD, the all-D native port of GLFW for D.
15      The Luigi GLD bindings are better tested than these.
16
17   Copyright (C) 2006 William V. Baxter III
18
19   This software is provided 'as-is', without any express or implied
20   warranty.  In no event will the authors be held liable for any
21   damages arising from the use of this software.
22
23   Permission is granted to anyone to use this software for any
24   purpose, including commercial applications, and to alter it and
25   redistribute it freely, subject to the following restrictions:
26
27   1. The origin of this software must not be misrepresented; you must
28      not claim that you wrote the original software. If you use this
29      software in a product, an acknowledgment in the product
30      documentation would be appreciated but is not required.
31   2. Altered source versions must be plainly marked as such, and must
32      not be misrepresented as being the original software.
33   3. This notice may not be removed or altered from any source distribution.
34
35   William Baxter wbaxter@gmail.com
36 */
37 module luigi.adapters.glfw;
38
39 import luigi.base;
40 import luigi.event;
41 import luigi.adapter;
42 import derelict.glfw.glfw;
43 import luigi.signalobj;
44
45 import std.stdio : writefln;
46
47 int translate_key(int glfwkey)
48 {
49     if (glfwkey<Key.Special) { return glfwkey; }
50     switch(glfwkey) {
51     case GLFW_KEY_SPACE: return Key.Space;
52     case GLFW_KEY_ESC: return Key.Escape;
53     case GLFW_KEY_F1: return Key.F1;
54     case GLFW_KEY_F2: return Key.F2;
55     case GLFW_KEY_F3: return Key.F3;
56     case GLFW_KEY_F4: return Key.F4;
57     case GLFW_KEY_F5: return Key.F5;
58     case GLFW_KEY_F6: return Key.F6;
59     case GLFW_KEY_F7: return Key.F7;
60     case GLFW_KEY_F8: return Key.F8;
61     case GLFW_KEY_F9: return Key.F9;
62     case GLFW_KEY_F10: return Key.F10;
63     case GLFW_KEY_F11: return Key.F11;
64     case GLFW_KEY_F12: return Key.F12;
65     case GLFW_KEY_F13: return Key.F13;
66     case GLFW_KEY_F14: return Key.F14;
67     case GLFW_KEY_F15: return Key.F15;
68     case GLFW_KEY_F16: return Key.F16;
69     case GLFW_KEY_F17: return Key.F17;
70     case GLFW_KEY_F18: return Key.F18;
71     case GLFW_KEY_F19: return Key.F19;
72     case GLFW_KEY_F20: return Key.F20;
73     case GLFW_KEY_F21: return Key.F21;
74     case GLFW_KEY_F22: return Key.F22;
75     case GLFW_KEY_F23: return Key.F23;
76     case GLFW_KEY_F24: return Key.F24;
77     case GLFW_KEY_F25: return Key.F25;
78     case GLFW_KEY_UP: return Key.Up;
79     case GLFW_KEY_DOWN: return Key.Down;
80     case GLFW_KEY_LEFT: return Key.Left;
81     case GLFW_KEY_RIGHT: return Key.Right;
82     case GLFW_KEY_LSHIFT: return Key.LShift;
83     case GLFW_KEY_RSHIFT: return Key.RShift;
84     case GLFW_KEY_LCTRL: return Key.LCtrl;
85     case GLFW_KEY_RCTRL: return Key.        RCtrl;
86     case GLFW_KEY_LALT: return Key.LAlt;
87     case GLFW_KEY_RALT: return Key.RAlt;
88     case GLFW_KEY_TAB: return Key.Tab;
89     case GLFW_KEY_ENTER: return Key.Enter;
90     case GLFW_KEY_BACKSPACE: return Key.Backspace;
91     case GLFW_KEY_INSERT: return Key.Insert;
92     case GLFW_KEY_DEL: return Key.Delete;
93     case GLFW_KEY_PAGEUP: return Key.PageUp;
94     case GLFW_KEY_PAGEDOWN: return Key.PageDown;
95     case GLFW_KEY_HOME: return Key.Home;
96     case GLFW_KEY_END: return Key.End;
97     case GLFW_KEY_KP_0: return Key.KP0;
98     case GLFW_KEY_KP_1: return Key.KP1;
99     case GLFW_KEY_KP_2: return Key.KP2;
100     case GLFW_KEY_KP_3: return Key.KP3;
101     case GLFW_KEY_KP_4: return Key.KP4;
102     case GLFW_KEY_KP_5: return Key.KP5;
103     case GLFW_KEY_KP_6: return Key.KP6;
104     case GLFW_KEY_KP_7: return Key.KP7;
105     case GLFW_KEY_KP_8: return Key.KP8;
106     case GLFW_KEY_KP_9: return Key.KP9;
107     case GLFW_KEY_KP_DIVIDE: return Key.KP_Divide;
108     case GLFW_KEY_KP_MULTIPLY: return Key.KP_Multiply;
109     case GLFW_KEY_KP_SUBTRACT: return Key.KP_Subtract;
110     case GLFW_KEY_KP_ADD: return Key.KP_Add;
111     case GLFW_KEY_KP_DECIMAL: return Key.KP_Decimal;
112     case GLFW_KEY_KP_EQUAL: return Key.KP_Equals;
113     case GLFW_KEY_KP_ENTER: return Key.KP_Enter;
114     default:
115         return Key.Unknown;
116     }
117 }
118
119
120 class GLFWAdapter : InputAdapter
121 {
122     // Singleton access via static opCall GLFWAdapter()
123     static GLFWAdapter opCall() {
124         static GLFWAdapter myinstance = null;
125         if (!myinstance) {
126             myinstance = new GLFWAdapter;
127             myinstance.init();
128         }
129         return myinstance;
130     }
131     // Singleton access via 'inst' property
132     static GLFWAdapter inst() {
133         return GLFWAdapter();
134     }
135
136     Size get_window_size(WindowHandle win) {
137         // only one window in GLFW to query the size of
138         int w,h;
139         glfwGetWindowSize(&w, &h);
140         return Size(w,h);
141     }
142
143
144 private:
145     int m_lastWheelPos = 0;
146     static int m_lastKey = Key.Unknown;
147
148     MouseButtons _getButtons() {
149         alias MouseButtons M;
150         MouseButtons m = M.None;
151         if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_LEFT)) m|=M.Left;
152         if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_RIGHT)) m|=M.Right;
153         if (glfwGetMouseButton(GLFW_MOUSE_BUTTON_MIDDLE)) m|=M.Middle;
154         return m;
155     }
156     KeyMods _getMods() {
157         alias KeyMods M;
158         KeyMods m = M.None;
159         if (glfwGetKey(GLFW_KEY_LCTRL) || glfwGetKey(GLFW_KEY_RCTRL))   m|= M.Ctrl;
160         if (glfwGetKey(GLFW_KEY_LSHIFT) || glfwGetKey(GLFW_KEY_RSHIFT)) m|= M.Shift;
161         if (glfwGetKey(GLFW_KEY_LALT) || glfwGetKey(GLFW_KEY_RALT))     m|= M.Alt;
162         return m;
163     }
164
165     extern(C) {
166         // All of our GLFW callbacks
167     static void keyCallbackC(int k, int action)
168     {
169         _KeyEvent ev;
170         void _initEvent() {
171             ev.key = translate_key(k);
172             m_lastKey = ev.key;
173             ev.ch = 0;
174             ev.is_press  = (action==GLFW_PRESS);
175             ev.mods = inst._getMods();
176             ev.is_key = true;
177             ev.is_char = false;
178         }
179         _initEvent();
180         inst.sig.sysKey.emit(&ev);
181         if (ev.alive) {
182             _initEvent();
183             inst.sig.key.emit(&ev);
184         }
185     }
186     static void charCallbackC(int ch, int action)
187     {
188         _KeyEvent ev;
189         // In practice it seems that char callbacks always come _after_
190         // key callbacks. (That's probably the case for any sane operating system).
191         // Also, you only get one char for one key.  This isn't
192         // necessarily the case in general with fancy input methods
193         // (e.g. european and asian) but it seems to be the case with GLFW.
194         // Not every key has a char, but every char has a key in GLFW
195         void _initEvent() {
196             ev.key = m_lastKey;
197             ev.ch = ch;
198             ev.is_press  = (action==GLFW_PRESS);
199             ev.mods = inst._getMods();
200             ev.is_key = false;
201             ev.is_char = true;
202         }
203         _initEvent();
204         inst.sig.sysKey.emit(&ev);
205         if (ev.alive) {
206             _initEvent();
207             inst.sig.key.emit(&ev);
208         }
209     }
210     static void mouseButtonCallbackC(int button, int action)
211     {
212         _MouseButtonEvent ev;
213         int x,y;
214         glfwGetMousePos(&x, &y);
215         void _initEvent() {
216             ev.x = ev.winx = x;
217             ev.y = ev.winy = y;
218             ev.is_press  = (action==GLFW_PRESS);
219             ev.mods = inst._getMods();
220             ev.pressed = inst._getButtons();
221             if      (button == GLFW_MOUSE_BUTTON_LEFT) ev.button = MouseButtons.Left;
222             else if (button == GLFW_MOUSE_BUTTON_RIGHT) ev.button = MouseButtons.Right;
223             else if (button == GLFW_MOUSE_BUTTON_MIDDLE) ev.button = MouseButtons.Middle;
224         }       
225         _initEvent();
226         inst.sig.sysMouseButton.emit(&ev);
227         if (ev.alive) {
228             // reinit because GUI might much with it
229             _initEvent();
230             inst.sig.mouseButton.emit(&ev);
231         }
232     }
233     static void mousePosCallbackC(int x, int y)
234     {
235         _MouseMoveEvent ev;
236         ev.x = ev.winx = x;
237         ev.y = ev.winy = y;
238         ev.pressed = inst._getButtons();
239         ev.mods = inst._getMods();
240
241         inst.sig.mouseMove.emit(&ev);
242     }
243     static void mouseWheelCallbackC(int pos)
244     {
245         _MouseWheelEvent ev;
246         int x,y;
247         glfwGetMousePos(&x, &y);
248         ev.x = ev.winx = x;
249         ev.y = ev.winy = y;
250         ev.delta = pos - inst.m_lastWheelPos;
251         ev.pressed = inst._getButtons();
252         ev.mods = inst._getMods();
253         inst.m_lastWheelPos = pos;
254
255         inst.sig.mouseWheel.emit(&ev);
256     }
257     static void windowSizeCallbackC(int width, int height)
258     {
259         _WindowSizeEvent ev;
260         ev.w = width;
261         ev.h = height;
262         inst.sig.windowSize.emit(&ev);
263     }
264     static int  windowCloseCallbackC()
265     {
266         _WindowCloseEvent ev;
267         inst.sig.windowClose.emit(&ev);
268         return true;
269     }
270     static void windowRefreshCallbackC()
271     {
272         //WindowRefreshEvent ev;
273     }
274
275     } // end extern(C)
276
277     void setCallbacks() {
278         // Note: a window has to be open for these to work!
279         glfwSetKeyCallback(cast(GLFWkeyfun) &keyCallbackC);
280         glfwSetCharCallback(cast(GLFWcharfun) &charCallbackC);
281         glfwSetMouseButtonCallback(cast(GLFWmousebuttonfun) &mouseButtonCallbackC);
282         glfwSetMousePosCallback(cast(GLFWmouseposfun) &mousePosCallbackC);
283         glfwSetMouseWheelCallback(cast(GLFWmousewheelfun) &mouseWheelCallbackC);
284         glfwSetWindowSizeCallback(cast(GLFWwindowsizefun) &windowSizeCallbackC);
285         glfwSetWindowCloseCallback(cast(GLFWwindowclosefun) &windowCloseCallbackC);
286         glfwSetWindowRefreshCallback(cast(GLFWwindowrefreshfun) &windowRefreshCallbackC);
287     }
288     void clearCallbacks() {
289         glfwSetKeyCallback(null);
290         glfwSetCharCallback(null);
291         glfwSetMouseButtonCallback(null);
292         glfwSetMousePosCallback(null);
293         glfwSetMouseWheelCallback(null);
294         glfwSetWindowSizeCallback(null);
295         glfwSetWindowCloseCallback(null);
296         glfwSetWindowRefreshCallback(null);
297     }
298
299     // Singleton, so constructor is private
300     this() {
301         initInputAdapter();
302     }
303     void init() {
304         // These can't be in the constructor because they trigger callbacks
305         // and the callbacks want to call inst().
306         // glfwInit();
307         setCallbacks();
308     }
309     ~this() {
310         clearCallbacks();
311     }
312
313 public:
314     mixin InputAdapterMix;
315
316 }
317
318
319 alias GLFWAdapter DefaultAdapter;
Note: See TracBrowser for help on using the browser.