1 /*
2 *******************************************************************************************
3 * Dgame (a D game framework) - Copyright (c) Randy Schütt
4 * 
5 * This software is provided 'as-is', without any express or implied warranty.
6 * In no event will the authors be held liable for any damages arising from
7 * the use of this software.
8 * 
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, subject to the following restrictions:
12 * 
13 * 1. The origin of this software must not be misrepresented; you must not claim
14 *    that you wrote the original software. If you use this software in a product,
15 *    an acknowledgment in the product documentation would be appreciated but is
16 *    not required.
17 * 
18 * 2. Altered source versions must be plainly marked as such, and must not be
19 *    misrepresented as being the original software.
20 * 
21 * 3. This notice may not be removed or altered from any source distribution.
22 *******************************************************************************************
23 */
24 module Dgame.Window.EventHandler;
25 
26 private {
27 	import derelict.sdl2.types;
28 	import derelict.sdl2.functions;
29 
30 	import Dgame.Internal.Log;
31 }
32 
33 public import Dgame.Window.Event;
34 
35 /**
36  * These class handles incomming events and returns outcomming events.
37  *
38  * Author: rschuett
39  */
40 final abstract class EventHandler {
41 	enum State {
42 		Query   = SDL_QUERY,
43 		Ignore  = SDL_IGNORE,
44 		Disable = SDL_DISABLE,
45 		Enable  = SDL_ENABLE
46 	}
47 	
48 private:
49 	static bool _process(Event* event, ref const SDL_Event sdl_event) in {
50 		assert(event !is null, "Null Event");
51 	} body {
52 		switch (sdl_event.type) {
53 			case Event.Type.KeyDown:
54 			case Event.Type.KeyUp:
55 				event.type = sdl_event.type == Event.Type.KeyDown ? Event.Type.KeyDown : Event.Type.KeyUp;
56 				
57 				event.timestamp = sdl_event.key.timestamp;
58 				event.windowId = sdl_event.key.windowID;
59 				
60 				event.keyboard.code = cast(Keyboard.Code) sdl_event.key.keysym.sym;
61 				event.keyboard.scancode = cast(Keyboard.ScanCode) sdl_event.key.keysym.scancode;
62 				
63 				event.keyboard.repeat = sdl_event.key.repeat != 0;
64 				event.keyboard.state = cast(Keyboard.State) sdl_event.key.state;
65 				
66 				event.keyboard.mod = Keyboard.getModifier();
67 				
68 				return true;
69 			case Event.Type.Window:
70 				event.type = Event.Type.Window;
71 				
72 				event.windowId = sdl_event.window.windowID;
73 				event.timestamp = sdl_event.window.timestamp;
74 				
75 				event.window.eventId = cast(WindowEventId) sdl_event.window.event;
76 				
77 				return true;
78 			case Event.Type.Quit:
79 				event.type = Event.Type.Quit;
80 				
81 				return true;
82 			case Event.Type.MouseButtonDown:
83 			case Event.Type.MouseButtonUp:
84 				if (sdl_event.type == Event.Type.MouseButtonUp)
85 					event.type = Event.Type.MouseButtonUp;
86 				else
87 					event.type = Event.Type.MouseButtonDown;
88 				
89 				event.timestamp = sdl_event.button.timestamp;
90 				event.windowId  = sdl_event.button.windowID;
91 				
92 				event.mouseButton.button = cast(Mouse.Button) sdl_event.button.button;
93 				
94 				event.mouseButton.x = cast(short) sdl_event.button.x;
95 				event.mouseButton.y = cast(short) sdl_event.button.y;
96 				
97 				return true;
98 			case Event.Type.MouseMotion:
99 				event.type = Event.Type.MouseMotion;
100 				
101 				event.timestamp = sdl_event.motion.timestamp;
102 				event.windowId  = sdl_event.motion.windowID;
103 				
104 				if (sdl_event.button.state == SDL_PRESSED)
105 					event.mouseMotion.state = Mouse.State.Pressed;
106 				else
107 					event.mouseMotion.state = Mouse.State.Released;
108 				
109 				event.mouseMotion.x = cast(short) sdl_event.motion.x;
110 				event.mouseMotion.y = cast(short) sdl_event.motion.y;
111 				
112 				event.mouseMotion.rel_x = cast(short) sdl_event.motion.xrel;
113 				event.mouseMotion.rel_y = cast(short) sdl_event.motion.yrel;
114 				
115 				return true;
116 			case Event.Type.MouseWheel:
117 				event.type = Event.Type.MouseWheel;
118 				
119 				event.timestamp = sdl_event.wheel.timestamp;
120 				event.windowId  = sdl_event.wheel.windowID;
121 				
122 				event.mouseWheel.x = cast(short) sdl_event.wheel.x;
123 				event.mouseWheel.y = cast(short) sdl_event.wheel.y;
124 				
125 				event.mouseWheel.delta_x = cast(short) sdl_event.wheel.x;
126 				event.mouseWheel.delta_y = cast(short) sdl_event.wheel.y;
127 				
128 				return true;
129 			case Event.Type.TextEdit:
130 				event.type = Event.Type.TextEdit;
131 				
132 				event.timestamp = sdl_event.edit.timestamp;
133 				event.windowId  = sdl_event.edit.windowID;
134 				
135 				event.textEdit.text = sdl_event.edit.text;
136 				event.textEdit.start = cast(short) sdl_event.edit.start;
137 				event.textEdit.length = cast(ushort) sdl_event.edit.length;
138 				
139 				return true;
140 			case Event.Type.TextInput:
141 				event.type = Event.Type.TextInput;
142 				
143 				event.timestamp = sdl_event.text.timestamp;
144 				event.windowId  = sdl_event.text.windowID;
145 				
146 				event.textInput.text = sdl_event.text.text;
147 				
148 				return true;
149 			default:
150 				return false;
151 		}
152 	}
153 	
154 public:
155 	/**
156 	 * Update the parameter event and set the data of the current event in it.
157 	 * 
158 	 * Returns: true, if there was a valid event and false if not.
159 	 */
160 	static bool poll(Event* event) in {
161 		assert(event !is null, "Null Event");
162 	} body {
163 		SDL_Event sdl_event;
164 		SDL_PollEvent(&sdl_event);
165 		
166 		return EventHandler._process(event, sdl_event);
167 	}
168 	
169 	/**
170 	 * Push an event of the given type inside the Event queue.
171 	 * 
172 	 * Returns: if the push was successfull or not.
173 	 */
174 	static bool push(Event.Type type) {
175 		SDL_Event sdl_event;
176 		sdl_event.type = type;
177 		
178 		return SDL_PushEvent(&sdl_event) == 1;
179 	}
180 	
181 	/**
182 	 * Clear the Event queue.
183 	 */
184 	static void clear(Event.Type type) {
185 		SDL_FlushEvent(type);
186 	}
187 	
188 	/**
189 	 * Set a state for a Event.Type.
190 	 * 
191 	 * Returns: the previous type.
192 	 *
193 	 * See: State enum
194 	 */
195 	static State setState(Event.Type type, State state) {
196 		return cast(State) SDL_EventState(type, state);
197 	}
198 	
199 	/**
200 	 * Returns: if inside of the Event Queue is an Event of the given type.
201 	 */
202 	static bool hasEvent(Event.Type type) {
203 		return SDL_HasEvent(type) == SDL_TRUE;
204 	}
205 	
206 	/**
207 	 * Returns: if the current Event queue has the Quit Event.
208 	 */
209 	static bool hasQuitEvent() {
210 		return SDL_QuitRequested();
211 	}
212 	
213 	/**
214 	 * Waits for the given Event.
215 	 * If the seconds parameter is greater then -1, it waits maximal timeout seconds.
216 	 */
217 	static bool wait(Event* event, int timeout = -1) {
218 		int result = 0;
219 		SDL_Event sdl_event;
220 		
221 		if (timeout < 0)
222 			result = SDL_WaitEvent(&sdl_event);
223 		else
224 			result = SDL_WaitEventTimeout(&sdl_event, timeout);
225 		
226 		EventHandler._process(event, sdl_event);
227 		
228 		return result > 0;
229 	}
230 }