1 /**
2  * Copyright:       Copyright (C) 2018 Gabriel Gheorghe, All Rights Reserved
3  * Authors:         $(Gabriel Gheorghe)
4  * License:         $(LINK2 https://www.gnu.org/licenses/gpl-3.0.txt, GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007)
5  * Source
6  * Documentation:
7  * Coverage:
8  */
9 module liberty.core.input;
10 import derelict.sdl2.sdl;
11 import liberty.core.engine;
12 import derelict.sdl2.sdl;
13 import liberty.math.vector;
14 import liberty.core.input;
15 import liberty.core.utils : Singleton, IService;
16 pragma (inline, true):
17 ///
18 class Input : Singleton!Input, IService {
19     private bool _serviceRunning;
20 	private {
21 		bool[KeyCodeCount] _keyState;
22         bool[KeyCodeCount] _oldKeyState;
23         const _KEY_PRESSED = true;
24         const _KEY_RELEASED = false;
25         SDL_Cursor* _cursorHandle;
26         int _mouseButtonState;
27         int _mouseX = 0;
28         int _mouseY = 0;
29         int _lastMouseX = 0;
30         int _lastMouseY = 0;
31         int _mouseWheelX = 0;
32         int _mouseWheelY = 0;
33         int _mouseDeltaX = 0;
34         int _mouseDeltaY = 0;
35     }
36     package bool _isMouseMoving = false;
37     package bool _isMouseWheeling = false;
38     /// Start Input service.
39     void startService() @trusted {
40         //useSystemCursor(SystemCursor.Arrow);
41         //setCurrentCursor();
42         _serviceRunning = true;
43     }
44     /// Stop Input service.
45     void stopService() @trusted {
46         if (_cursorHandle !is null) {
47             SDL_FreeCursor(_cursorHandle);
48             _cursorHandle = null;
49         }
50         _serviceRunning = false;
51     }
52     /// Restart Input service.
53     void restartService() @trusted {
54         stopService();
55         startService();
56     }
57     /// Returns true if Input service is running.
58 	bool isServiceRunning() pure nothrow const @safe @nogc {
59 		return _serviceRunning;
60 	}
61     ///
62     bool isKeyHold(KeyCode key) {
63         SDL_Scancode scan = SDL_GetScancodeFromKey(cast(SDL_Keycode)key);
64         return _keyState[scan] == _KEY_PRESSED;
65     }
66     ///
67     bool isKeyHold(KeyModFlag key) {
68         SDL_Keymod mod = SDL_GetModState();
69         if (mod & cast(SDL_Keymod)key) {
70             //_keyState[mod] = _KEY_PRESSED; // TODO.
71             return true;
72         }
73         return false;
74     }
75     ///
76     bool isKeyDown(KeyCode key) {
77         SDL_Scancode scan = SDL_GetScancodeFromKey(cast(SDL_Keycode)key);
78         return markKeyAsJustReleased(scan);
79     }
80     ///
81     bool isKeyNone(KeyCode key) {
82         SDL_Scancode scan = SDL_GetScancodeFromKey(cast(SDL_Keycode)key);
83         return _keyState[scan] == _KEY_RELEASED;
84     }
85     ///
86     bool isKeyUp(KeyCode key) {
87         SDL_Scancode scan = SDL_GetScancodeFromKey(cast(SDL_Keycode)key);
88         bool old_state = (_oldKeyState[scan] == _KEY_PRESSED);
89         _oldKeyState[scan] = _KEY_RELEASED;
90         return (_keyState[scan] == _KEY_RELEASED) && old_state;
91     }
92     private void clearKeys() { _keyState[] = _KEY_RELEASED; }
93     /*package*/ bool markKeyAsPressed(SDL_Scancode scancode) {
94         bool old_state = _keyState[scancode];
95         _keyState[scancode] = _KEY_PRESSED;
96         return old_state;
97     }
98     /*package*/ bool markKeyAsJustReleased(SDL_Scancode scancode) {
99         bool old_state = _keyState[scancode];
100         _keyState[scancode] = _KEY_RELEASED;
101         _oldKeyState[scancode] = _KEY_PRESSED;
102         return old_state;
103     }
104     /// Returns current position of the mouse.
105     Vector2I mousePosition() nothrow {
106         return Vector2I(_mouseX, _mouseY);
107     }
108     ///
109     Vector2I lastMousePosition() nothrow {
110         return Vector2I(_lastMouseX, _lastMouseY);
111     }
112     /// Returns previous position of the mouse.
113     Vector2I previousMousePosition() nothrow {
114         return Vector2I(_mouseX - _mouseDeltaX, _mouseY - _mouseDeltaY);
115     }
116     /// Returns the relative direction of the mouse.
117     Vector2I mouseRelativeDirection() nothrow {
118         return Vector2I(_mouseDeltaX, _mouseDeltaY);
119     }
120     ///
121     Vector2I mouseDeltaWheel() nothrow {
122         Vector2I ret = Vector2I(_mouseWheelX, _mouseWheelY);
123         _mouseWheelX = _mouseWheelY = 0;
124         return ret;
125     }
126     ///
127     int mouseDeltaWheelX() nothrow {
128         int ret = _mouseWheelX;
129         _mouseWheelX = 0;
130         return ret;
131     }
132     ///
133     int mouseDeltaWheelY() nothrow {
134         int ret = _mouseWheelY;
135         _mouseWheelY = 0;
136         return ret;
137     }
138     ///
139     bool isMouseButtonPressed(MouseButton button) nothrow {
140         return (_mouseButtonState & SDL_BUTTON(button)) != 0;
141     }
142     ///
143     bool isMouseMoving() nothrow {
144         return _isMouseMoving;
145     }
146     ///
147     bool isMouseScrolling() nothrow {
148         return _isMouseWheeling;
149     }
150     //bool isMouseMoving() nothrow {
151     //    return mousePosition() != lastMousePosition();
152     //}
153     /// Capture the mouse and track input outside the MainWindow.
154     void startMouseCapture() {
155         if (SDL_CaptureMouse(SDL_TRUE) != 0) {
156             //PlatformManager.throwPlatformException("SDL_CaptureMouse");
157             // TODO: Uncomment.
158         }
159     }
160     ///
161     void stopMouseCapture() {
162         if (SDL_CaptureMouse(SDL_FALSE) != 0) {
163             //PlatformManager.throwPlatformException("SDL_CaptureMouse");
164             // TODO: Uncomment.
165         }
166     }
167     /*package*/ void updateMouse() {
168         _lastMouseX = _mouseX;
169         _lastMouseY = _mouseY;
170     }
171     /*package*/ void updateMouseMotion(const(SDL_MouseMotionEvent)* event) {
172         _mouseButtonState = SDL_GetMouseState(null, null);
173         _mouseX = event.x;
174         _mouseY = event.y;
175         _mouseDeltaX = event.xrel;
176         _mouseDeltaY = event.yrel;
177     }
178     /*package*/ void updateMouseButtons(const(SDL_MouseButtonEvent)* event) {
179         _mouseButtonState = SDL_GetMouseState(null, null);
180         _mouseX = event.x;
181         _mouseY = event.y;
182     }
183     /*package*/ void updateMouseWheel(const(SDL_MouseWheelEvent)* event) {
184         _mouseButtonState = SDL_GetMouseState(&_mouseX, &_mouseY);
185         _mouseWheelX += event.x;
186         _mouseWheelY += event.y;
187     }
188     ///
189     void useSystemCursor(SystemCursor cursor) {
190         _cursorHandle = SDL_CreateSystemCursor(cast(SDL_SystemCursor)cursor);
191         setCurrentCursor();
192     }
193     ///
194     void createColorCursor(int h_x, int h_y) {
195         //_cursorHandle = SDL_CreateColorCursor(SurfaceManager.getHandle(), h_x, h_y);
196         // TODO: Uncomment.
197         //if (_cursorHandle is null) {
198             //PlatformManager.throwPlatformException("SDL_CreateColorCursor");
199             // TODO: Uncomment.
200         //}
201     }
202     ///
203     void lockMouse(bool lock) {
204         //SDL_bool lock_ = cast(SDL_bool)lock;
205     	//SDL_ShowCursor(lock_);
206     	//SDL_SetWindowGrab(CoreEngine.get.mainWindow._window, lock_);
207     	//if ( lock ) {
208     	//	mouseLock[0] = mouseInfo.xCur;
209     	//	mouseLock[1] = mouseInfo.yCur;
210     	//}
211     }
212     ///
213     void relativeMouseMode(bool relative = true) {
214         SDL_SetRelativeMouseMode(cast(SDL_bool)relative);
215     }
216     ///
217     void windowGrab(bool grabbed = true) {
218         SDL_SetWindowGrab(CoreEngine.get.mainWindow._window, cast(SDL_bool)grabbed);
219     }
220     ///
221     void cursorVisible(bool visible = true) {
222         SDL_ShowCursor(visible);
223     }
224     ///
225     /*package*/ void setCurrentCursor() {
226         SDL_SetCursor(_cursorHandle);
227     }
228     /*package*/ SDL_Cursor* cursorHandle() {
229         return _cursorHandle;
230     }
231     /*package*/ SDL_Cursor* cursor() {
232         SDL_Cursor* cursor_handle = SDL_GetCursor();
233         if (cursor_handle is null) {
234             //PlatformManager.throwPlatformException("SDL_GetCursor");
235             // TODO: Uncomment.
236         }
237         return cursor_handle;
238     }
239     /*package*/ SDL_Cursor* defaultCursor() {
240         SDL_Cursor* cursor_handle = SDL_GetDefaultCursor();
241         if (cursor_handle is null) {
242             //PlatformManager.throwPlatformException("SDL_GetDefaultCursor");
243             // TODO: Uncomment.
244         }
245         return cursor_handle;
246     }
247 }
248 /// Number of keycodes.
249 enum KeyCodeCount = 512;
250 ///
251 enum KeyCode : int {
252 	/// Unknown keycode has value equals to 0.
253 	Unknown = SDLK_UNKNOWN,
254 	/// Return keycode has value equals to '\r' (carriage return).
255 	Return = SDLK_RETURN,
256     /// Esc keycode has value equals to '\033'.
257     Esc = SDLK_ESCAPE,
258     /// Backspace keyword has value equals to '\b'.
259     Backspace = SDLK_BACKSPACE,
260     /// Tab keyword has value equals to '\t'.
261     Tab = SDLK_TAB,
262     /// Space keyword has value equals to ' '.
263     Space = SDLK_SPACE,
264     /// Exclamation keyword has value equals to '!'.
265     Exclamation = SDLK_EXCLAIM,
266     ///
267     DoubleQuote = SDLK_QUOTEDBL,
268     ///
269     Sharp = SDLK_HASH,
270     ///
271     Percent = SDLK_PERCENT,
272     ///
273     Dollar = SDLK_DOLLAR,
274     ///
275     Ampersand = SDLK_AMPERSAND,
276     ///
277     SingleQuote = SDLK_QUOTE,
278     ///
279     LeftParenthesis = SDLK_LEFTPAREN,
280     ///
281     RightParenthesis = SDLK_RIGHTPAREN,
282     ///
283     Star = SDLK_ASTERISK,
284     ///
285     Plus = SDLK_PLUS,
286     ///
287     Comma = SDLK_COMMA,
288     ///
289     Minus = SDLK_MINUS,
290     ///
291     Dot = SDLK_PERIOD,
292     ///
293     Slash = SDLK_SLASH,
294     ///
295     Key0 = SDLK_0,
296     ///
297     Key1 = SDLK_1,
298     ///
299     Key2 = SDLK_2,
300     ///
301     Key3 = SDLK_3,
302     ///
303     Key4 = SDLK_4,
304     ///
305     Key5 = SDLK_5,
306     ///
307     Key6 = SDLK_6,
308     ///
309     Key7 = SDLK_7,
310     ///
311     Key8 = SDLK_8,
312     ///
313     Key9 = SDLK_9,
314     ///
315     Colon = SDLK_COLON,
316     ///
317     Semicolon = SDLK_SEMICOLON,
318     ///
319     Less = SDLK_LESS,
320     ///
321     Equals = SDLK_EQUALS,
322     ///
323     Greater = SDLK_GREATER,
324     ///
325     Question = SDLK_QUESTION,
326     ///
327     MonkeyTail = SDLK_AT,
328     ///
329     LeftBracket = SDLK_LEFTBRACKET,
330     ///
331     Backslash = SDLK_BACKSLASH,
332     ///
333     RightBracket = SDLK_RIGHTBRACKET,
334     ///
335     Caret = SDLK_CARET,
336     ///
337     Underscore = SDLK_UNDERSCORE,
338     ///
339     Backquote = SDLK_BACKQUOTE,
340     ///
341     A = SDLK_a,
342     ///
343     B = SDLK_b,
344     ///
345     C = SDLK_c,
346     ///
347     D = SDLK_d,
348     ///
349     E = SDLK_e,
350     ///
351     F = SDLK_f,
352     ///
353     G = SDLK_g,
354     ///
355     H = SDLK_h,
356     ///
357     I = SDLK_i,
358     ///
359     J = SDLK_j,
360     ///
361     K = SDLK_k,
362     ///
363     L = SDLK_l,
364     ///
365     M = SDLK_m,
366     ///
367     N = SDLK_n,
368     ///
369     O = SDLK_o,
370     ///
371     P = SDLK_p,
372     ///
373     Q = SDLK_q,
374     ///
375     R = SDLK_r,
376     ///
377     S = SDLK_s,
378     ///
379     T = SDLK_t,
380     ///
381     U = SDLK_u,
382     ///
383     V = SDLK_v,
384     ///
385     W = SDLK_w,
386     ///
387     X = SDLK_x,
388     ///
389     Y = SDLK_y,
390     ///
391     Z = SDLK_z,
392     ///
393     CapsLock = SDLK_CAPSLOCK,
394     ///
395     F1 = SDLK_F1,
396     ///
397     F2 = SDLK_F2,
398     ///
399     F3 = SDLK_F3,
400     ///
401     F4 = SDLK_F4,
402     ///
403     F5 = SDLK_F5,
404     ///
405     F6 = SDLK_F6,
406     ///
407     F7 = SDLK_F7,
408     ///
409     F8 = SDLK_F8,
410     ///
411     F9 = SDLK_F9,
412     ///
413     F10 = SDLK_F10,
414     ///
415     F11 = SDLK_F11,
416     ///
417     F12 = SDLK_F12,
418     ///
419     Printsceen = SDLK_PRINTSCREEN,
420     ///
421     ScrollLock = SDLK_SCROLLLOCK,
422     ///
423     Pause = SDLK_PAUSE,
424     ///
425     Insert = SDLK_INSERT,
426     ///
427     Home = SDLK_HOME,
428     ///
429     PageUp = SDLK_PAGEUP,
430     ///
431     Delete = SDLK_DELETE,
432     ///
433     End = SDLK_END,
434     ///
435     PageDown = SDLK_PAGEDOWN,
436     ///
437     Right = SDLK_RIGHT,
438     ///
439     Left = SDLK_LEFT,
440     ///
441     Down = SDLK_DOWN,
442     ///
443     Up = SDLK_UP,
444     ///
445     NumLockClear = SDLK_NUMLOCKCLEAR,
446     ///
447     Divide = SDLK_KP_DIVIDE,
448     ///
449     Multiply = SDLK_KP_MULTIPLY,
450     ///
451     Subtract = SDLK_KP_MINUS,
452     ///
453     Add = SDLK_KP_PLUS,
454     ///
455     Enter = SDLK_KP_ENTER,
456     ///
457     Num1 = SDLK_KP_1,
458     ///
459     Num2 = SDLK_KP_2,
460     ///
461     Num3 = SDLK_KP_3,
462     ///
463     Num4 = SDLK_KP_4,
464     ///
465     Num5 = SDLK_KP_5,
466     ///
467     Num6 = SDLK_KP_6,
468     ///
469     Num7 = SDLK_KP_7,
470     ///
471     Num8 = SDLK_KP_8,
472     ///
473     Num9 = SDLK_KP_9,
474     ///
475     Num0 = SDLK_KP_0,
476     ///
477     Period = SDLK_KP_PERIOD
478     // TODO: Finish.
479 }
480 ///
481 enum KeyModFlag : int { // TODO: Change name?
482 	///
483 	None = KMOD_NONE,
484 	///
485 	LeftShift = KMOD_LSHIFT,
486 	///
487 	RightShift = KMOD_RSHIFT,
488 	///
489 	LeftCtrl = KMOD_LCTRL,
490 	///
491 	RightCtrl = KMOD_RCTRL,
492 	///
493 	LeftAlt = KMOD_LALT,
494 	///
495 	RightAlt = KMOD_RALT,
496 	///
497 	LeftGUI = KMOD_LGUI,
498 	///
499 	RightGUI = KMOD_RGUI,
500 	///
501 	Num = KMOD_NUM,
502 	///
503 	Caps = KMOD_CAPS,
504 	///
505 	Mode = KMOD_MODE,
506 	///
507 	Reserved = KMOD_RESERVED,
508 	///
509 	Ctrl = KMOD_CTRL,
510 	///
511 	Shift = KMOD_SHIFT,
512 	///
513 	Alt = KMOD_ALT,
514 	///
515 	Gui = KMOD_GUI,
516 }
517 ///
518 enum MouseButton : ubyte {
519 	///
520 	Left = SDL_BUTTON_LEFT,
521 	///
522 	Middle = SDL_BUTTON_MIDDLE,
523 	///
524 	Right = SDL_BUTTON_RIGHT,
525 	///
526 	X1 = SDL_BUTTON_X1,
527 	///
528 	X2 = SDL_BUTTON_X2,
529 	///
530 	LeftMask = SDL_BUTTON_LMASK,
531 	///
532 	MiddleMask = SDL_BUTTON_MMASK,
533 	///
534 	RightMask = SDL_BUTTON_RMASK,
535 	///
536 	X1Mask = SDL_BUTTON_X1MASK,
537 	///
538 	X2Mask = SDL_BUTTON_X2MASK
539 }
540 /// All types of supported cursor found in system.
541 enum SystemCursor : int {
542 	/// Arrow cursor.
543 	Arrow = SDL_SYSTEM_CURSOR_ARROW,
544 	/// I-Beam cursor.
545 	IBeam = SDL_SYSTEM_CURSOR_IBEAM,
546 	/// Wait cursor.
547 	Wait = SDL_SYSTEM_CURSOR_WAIT,
548 	/// Crosshair cursor.
549 	CrossHair = SDL_SYSTEM_CURSOR_CROSSHAIR,
550 	/// Small wait cursor.
551 	WaitArrow = SDL_SYSTEM_CURSOR_WAITARROW,
552 	/// Double arrow pointing northwest and southeast cursor.
553 	SizeNWSE = SDL_SYSTEM_CURSOR_SIZENWSE,
554 	/// Double arrow pointing northeast and southwest cursor.
555 	SizeNESW = SDL_SYSTEM_CURSOR_SIZENESW,
556 	/// Double arrow pointing west and east cursor.
557 	SizeWE = SDL_SYSTEM_CURSOR_SIZEWE,
558 	/// Double arrow pointing north and south cursor.
559 	SizeNS = SDL_SYSTEM_CURSOR_SIZENS,
560 	/// Four pointed arrow pointing north, south, east and west cursor.
561 	SizeAll = SDL_SYSTEM_CURSOR_SIZEALL,
562 	/// Slashed circle cursor.
563 	No = SDL_SYSTEM_CURSOR_NO,
564 	/// Hand cursor.
565 	Hand = SDL_SYSTEM_CURSOR_HAND
566 }