1 /*
2     Copyright © 2020, Luna Nielsen
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module engine.input.keyboard;
8 import engine.input;
9 import bindbc.glfw;
10 import events;
11 
12 /**
13     Keys
14 */
15 enum Key {
16     KeyUnknown = GLFW_KEY_UNKNOWN,
17     KeySpace = GLFW_KEY_SPACE,
18     KeyApostrophe = GLFW_KEY_APOSTROPHE,
19     KeyComma = GLFW_KEY_COMMA,
20     KeyMinus = GLFW_KEY_MINUS,
21     KeyPeriod = GLFW_KEY_PERIOD,
22     KeySlash = GLFW_KEY_SLASH,
23     Key0 = GLFW_KEY_0,
24     Key1 = GLFW_KEY_1,
25     Key2 = GLFW_KEY_2,
26     Key3 = GLFW_KEY_3,
27     Key4 = GLFW_KEY_4,
28     Key5 = GLFW_KEY_5,
29     Key6 = GLFW_KEY_6,
30     Key7 = GLFW_KEY_7,
31     Key8 = GLFW_KEY_8,
32     Key9 = GLFW_KEY_9,
33     KeySemicolon = GLFW_KEY_SEMICOLON,
34     KeyEqual = GLFW_KEY_EQUAL,
35     KeyA = GLFW_KEY_A,
36     KeyB = GLFW_KEY_B,
37     KeyC = GLFW_KEY_C,
38     KeyD = GLFW_KEY_D,
39     KeyE = GLFW_KEY_E,
40     KeyF = GLFW_KEY_F,
41     KeyG = GLFW_KEY_G,
42     KeyH = GLFW_KEY_H,
43     KeyI = GLFW_KEY_I,
44     KeyJ = GLFW_KEY_J,
45     KeyK = GLFW_KEY_K,
46     KeyL = GLFW_KEY_L,
47     KeyM = GLFW_KEY_M,
48     KeyN = GLFW_KEY_N,
49     KeyO = GLFW_KEY_O,
50     KeyP = GLFW_KEY_P,
51     KeyQ = GLFW_KEY_Q,
52     KeyR = GLFW_KEY_R,
53     KeyS = GLFW_KEY_S,
54     KeyT = GLFW_KEY_T,
55     KeyU = GLFW_KEY_U,
56     KeyV = GLFW_KEY_V,
57     KeyW = GLFW_KEY_W,
58     KeyX = GLFW_KEY_X,
59     KeyY = GLFW_KEY_Y,
60     KeyZ = GLFW_KEY_Z,
61     KeyBracket = GLFW_KEY_LEFT_BRACKET,
62     KeyBackslash = GLFW_KEY_BACKSLASH,
63     KeyRightBracket = GLFW_KEY_RIGHT_BRACKET,
64     KeyAccent = GLFW_KEY_GRAVE_ACCENT,
65     KeyWorld1 = GLFW_KEY_WORLD_1,
66     KeyWorld2 = GLFW_KEY_WORLD_2,
67 
68     KeyEscape = GLFW_KEY_ESCAPE,
69     KeyEnter = GLFW_KEY_ENTER,
70     KeyTab = GLFW_KEY_TAB,
71     KeyBackspace = GLFW_KEY_BACKSPACE,
72     KeyInsert = GLFW_KEY_INSERT,
73     KeyDelete = GLFW_KEY_DELETE,
74     KeyRight = GLFW_KEY_RIGHT,
75     KeyLeft = GLFW_KEY_LEFT,
76     KeyDown = GLFW_KEY_DOWN,
77     KeyUp = GLFW_KEY_UP,
78     KeyPageUp = GLFW_KEY_PAGE_UP,
79     KeyPageDown = GLFW_KEY_PAGE_DOWN,
80     KeyHome = GLFW_KEY_HOME,
81     KeyEnd = GLFW_KEY_END,
82     KeyCapsLock = GLFW_KEY_CAPS_LOCK,
83     KeyScrollLock = GLFW_KEY_SCROLL_LOCK,
84     KeyNumLock = GLFW_KEY_NUM_LOCK,
85     KeyPrintScreen = GLFW_KEY_PRINT_SCREEN,
86     KeyPause = GLFW_KEY_PAUSE,
87     KeyF1 = GLFW_KEY_F1,
88     KeyF2 = GLFW_KEY_F2,
89     KeyF3 = GLFW_KEY_F3,
90     KeyF4 = GLFW_KEY_F4,
91     KeyF5 = GLFW_KEY_F5,
92     KeyF6 = GLFW_KEY_F6,
93     KeyF7 = GLFW_KEY_F7,
94     KeyF8 = GLFW_KEY_F8,
95     KeyF9 = GLFW_KEY_F9,
96     KeyF10 = GLFW_KEY_F10,
97     KeyF11 = GLFW_KEY_F11,
98     KeyF12 = GLFW_KEY_F12,
99     KeyF13 = GLFW_KEY_F13,
100     KeyF14 = GLFW_KEY_F14,
101     KeyF15 = GLFW_KEY_F15,
102     KeyF16 = GLFW_KEY_F16,
103     KeyF17 = GLFW_KEY_F17,
104     KeyF18 = GLFW_KEY_F18,
105     KeyF19 = GLFW_KEY_F19,
106     KeyF20 = GLFW_KEY_F20,
107     KeyF21 = GLFW_KEY_F21,
108     KeyF22 = GLFW_KEY_F22,
109     KeyF23 = GLFW_KEY_F23,
110     KeyF24 = GLFW_KEY_F24,
111     KeyF25 = GLFW_KEY_F25,
112     Keypad0 = GLFW_KEY_KP_0,
113     Keypad1 = GLFW_KEY_KP_1,
114     Keypad2 = GLFW_KEY_KP_2,
115     Keypad3 = GLFW_KEY_KP_3,
116     Keypad4 = GLFW_KEY_KP_4,
117     Keypad5 = GLFW_KEY_KP_5,
118     Keypad6 = GLFW_KEY_KP_6,
119     Keypad7 = GLFW_KEY_KP_7,
120     Keypad8 = GLFW_KEY_KP_8,
121     Keypad9 = GLFW_KEY_KP_9,
122     KeypadDecimal = GLFW_KEY_KP_DECIMAL,
123     KeypadDivide = GLFW_KEY_KP_DIVIDE,
124     KeypadMultiply = GLFW_KEY_KP_MULTIPLY,
125     KeypadSubtract = GLFW_KEY_KP_SUBTRACT,
126     KeypadAdd = GLFW_KEY_KP_ADD,
127     KeypadEnter = GLFW_KEY_KP_ENTER,
128     KeypadEqual = GLFW_KEY_KP_EQUAL,
129     KeyLeftShift = GLFW_KEY_LEFT_SHIFT,
130     KeyLeftControl = GLFW_KEY_LEFT_CONTROL,
131     KeyLeftAlt = GLFW_KEY_LEFT_ALT,
132     KeyLeftSuper = GLFW_KEY_LEFT_SUPER,
133     KeyRightShift = GLFW_KEY_RIGHT_SHIFT,
134     KeyRightControl = GLFW_KEY_RIGHT_CONTROL,
135     KeyRightAlt = GLFW_KEY_RIGHT_ALT,
136     KeyRightSuper = GLFW_KEY_RIGHT_SUPER,
137     KeyMenu = GLFW_KEY_MENU,
138     KeyLast = GLFW_KEY_LAST,
139 
140     KeyEsc = GLFW_KEY_ESC,
141     KeyDel = GLFW_KEY_DEL,
142     KeyPgUp = GLFW_KEY_PAGEUP,
143     KeyPgDown = GLFW_KEY_PAGEDOWN,
144     KeypadNumLock = GLFW_KEY_KP_NUM_LOCK,
145     KeyLCtrl = GLFW_KEY_LCTRL,
146     KeyLShift = GLFW_KEY_LSHIFT,
147     KeyLAlt = GLFW_KEY_LALT,
148     KeyLSuper = GLFW_KEY_LSUPER,
149     KeyRCtrl = GLFW_KEY_RCTRL,
150     KeyRShift = GLFW_KEY_RSHIFT,
151     KeyRAlt = GLFW_KEY_RALT,
152     KeyRSuper = GLFW_KEY_RSUPER,
153 }
154 
155 /**
156     Keyboard
157 */
158 class Keyboard {
159 private static:
160     GLFWwindow* window;
161     dchar curChar;
162 
163     bool capsLock;
164     bool numLock;
165 
166 public static:
167 
168     /**
169         Event that is called every time a new text character is typed
170     */
171     Event!dchar onKeyboardType;
172 
173     /**
174         Event that is called every time a new ket event is emitted
175     */
176     Event!Key onKeyEvent;
177 
178     /**
179         Constructs the underlying data needed
180     */
181     void initialize(GLFWwindow* window) {
182         this.window = window;
183 
184         // Create events
185         onKeyboardType = new Event!dchar();
186         onKeyEvent = new Event!Key();
187 
188         // Do GLFW stuff
189         glfwSetInputMode(window, GLFW_LOCK_KEY_MODS, GLFW_TRUE);
190         glfwSetCharCallback(window, &onCharCallback);
191         glfwSetKeyCallback(window, &onKeyCallback);
192     }
193 
194     /**
195         Gets the current typed text character for text input
196     */
197     dchar getCurrentCharacter() {
198         return curChar;
199     }
200 
201     /**
202         Gets whether a key is pressed
203     */
204     bool isKeyPressed(Key key) {
205         return glfwGetKey(window, key) == GLFW_PRESS;
206     }
207 
208     /**
209         Gets whether a key is pressed
210     */
211     bool isKeyReleased(Key key) {
212         return glfwGetKey(window, key) == GLFW_RELEASE;
213     }
214 
215     /**
216         Gets whether CapsLock is on
217     */
218     bool isCapsLockOn() {
219         return capsLock;
220     }
221 
222     /**
223         Gets whether NumLock is on
224     */
225     bool isNumLockOn() {
226         return numLock;
227     }
228 }
229 
230 private:
231 void onKeyEventHandler(Key key) {
232     Keyboard.onKeyEvent(null, key);
233 }
234 
235 void onCharEventHandler(dchar key) {
236     Keyboard.onKeyboardType(null, key);
237 }
238 
239 nothrow extern(C):
240 void onKeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
241     Keyboard.numLock = (mods & GLFW_MOD_NUM_LOCK) > 0;
242     Keyboard.capsLock = (mods & GLFW_MOD_CAPS_LOCK) > 0;
243 
244     // Cursed magic to make our exception throwing D event handler be callable from this C function
245     (cast(void function(Key) nothrow)&onKeyEventHandler)(cast(Key)key);
246 }
247 
248 void onCharCallback(GLFWwindow* window, uint codepoint) {
249     Keyboard.curChar = cast(dchar)codepoint;
250 
251     // Cursed magic to make our exception throwing D event handler be callable from this C function
252     (cast(void function(dchar) nothrow)&onCharEventHandler)(cast(dchar)codepoint);
253 }