xoreos  0.0.5
events.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cstdlib>
26 
27 #include "src/common/fallthrough.h"
29 #include <SDL_timer.h>
31 
32 #include "src/common/util.h"
33 #include "src/common/error.h"
34 #include "src/common/threads.h"
35 #include "src/common/configman.h"
36 
37 #include "src/events/events.h"
38 #include "src/events/requests.h"
40 #include "src/events/timerman.h"
41 #include "src/events/joystick.h"
42 
43 #include "src/graphics/types.h"
44 #include "src/graphics/graphics.h"
46 #include "src/graphics/windowman.h"
47 
49 
50 namespace Events {
51 
52 const EventsManager::RequestHandler EventsManager::_requestHandler[kITCEventMAX] = {
53  0,
54  &EventsManager::requestCallInMainThread,
55  &EventsManager::requestRebuildGLContainer,
56  &EventsManager::requestDestroyGLContainer
57 };
58 
59 
60 EventsManager::EventsManager() : _ready(false), _quitRequested(false), _doQuit(false),
61  _fatalError(false), _queueSize(0), _fullQueue(false), _repeat(false), _repeatCounter(0),
62  _textInputCounter(0) {
63 
64 }
65 
67  if (!GfxMan.ready())
68  throw Common::Exception("The GraphicsManager needs to be initialized first");
69 
70  RequestMan.init();
71  NotificationMan.init();
72  TimerMan.init();
73 
74  _fullQueue = false;
75  _queueSize = 0;
76 
77  _ready = true;
78 
79  initJoysticks();
80 
81  SDL_RegisterEvents(1);
82 
83  std::srand(getTimestamp());
84 
85  // Forcing enableTextInput to be disabled requires _textInputCounter = 1 to not underrun the counter.
87  enableTextInput(false);
88 
89  _repeatCounter = 0;
90 }
91 
93  if (!_ready)
94  return;
95 
97 
98  RequestMan.deinit();
99 
100  _ready = false;
101 }
102 
104  if (!_ready)
105  return;
106 
108 
109  // Clear the SDL event queue
110  while (SDL_PollEvent(0));
111 
112  // Clear our event queue
113  _eventQueue.clear();
114 
115  deinitJoysticks();
116  initJoysticks();
117 
118  _repeatCounter = 0;
119 
120  _textInputCounter = 0;
121 }
122 
123 bool EventsManager::ready() const {
124  return _ready;
125 }
126 
128  return _fullQueue;
129 }
130 
132  if (!_quitRequested)
133  SDL_Delay(ms);
134 }
135 
137  return SDL_GetTicks();
138 }
139 
141  if ((event.type == kEventQuit) ||
142  ((event.type == kEventKeyDown) &&
143  (event.key.keysym.mod & (KMOD_CTRL | KMOD_GUI)) &&
144  (event.key.keysym.sym == SDLK_q))) {
145 
146  requestQuit();
147  return true;
148  }
149 
150 #ifdef WIN32
151  if ((event.type == kEventKeyDown) && (event.key.keysym.mod & KMOD_ALT) &&
152  (event.key.keysym.sym == SDLK_F4)) {
153  requestQuit();
154  return true;
155  }
156 #endif
157 
158  return false;
159 }
160 
162  if (event.type == kEventKeyDown) {
163  if ((event.key.keysym.mod & KMOD_ALT) && event.key.keysym.sym == SDLK_RETURN) {
164  WindowMan.toggleFullScreen();
165  return true;
166  } else if ((event.key.keysym.mod & KMOD_ALT) && event.key.keysym.sym == SDLK_m) {
167  WindowMan.toggleMouseGrab();
168  return true;
169  } else if ((event.key.keysym.mod & KMOD_ALT) && event.key.keysym.sym == SDLK_s) {
170  GfxMan.takeScreenshot();
171  return true;
172  }
173  }
174 
175  if (event.type == kEventWindow) {
176  // If the window was restored, reassert the window size
177  if (event.window.event == kEventWindowRestored)
178  WindowMan.setWindowSize(WindowMan.getWindowWidth(), WindowMan.getWindowHeight());
179 
180  return true;
181  }
182 
183  return false;
184 }
185 
186 bool EventsManager::parseITC(const Event &event) {
187  if (event.type != kEventITC)
188  return false;
189 
190  // Get the specific ITC type
191  ITCEvent itcEvent = (ITCEvent) event.user.code;
192 
193  Request &request = *static_cast<Request *>(event.user.data1);
194 
195  if (request._type != itcEvent)
196  throw Common::Exception("Request type does not match the ITC type");
197 
198  // Call its request handler
199  if ((itcEvent >= 0) && (itcEvent < kITCEventMAX)) {
200  RequestHandler handler = _requestHandler[itcEvent];
201 
202  if (handler)
203  (this->*handler)(request);
204  }
205 
206  request.signalReply();
207  return true;
208 }
209 
212 
214 
215  Event event;
216  while (SDL_PollEvent(&event)) {
217  // Check repeated event.
218  if (((event.type == kEventKeyDown) || (event.type == kEventKeyUp)) &&
219  event.key.repeat && !_repeat)
220  continue;
221 
222  // Check for quit events
223  if (parseEventQuit(event))
224  continue;
225 
226  // Check for graphics events
227  if (parseEventGraphics(event))
228  continue;
229 
230  if (parseITC(event))
231  continue;
232 
233  // Push the event to the back of the list
234  _eventQueue.push_back(event);
235  }
236 
237  _queueSize = 0;
238  _fullQueue = false;
239 }
240 
243 
244  _eventQueue.clear();
245 }
246 
249 
250  if (_eventQueue.empty())
251  return false;
252 
253  // Return an event from the front of the list
254  event = _eventQueue.front();
255  _eventQueue.pop_front();
256 
257  return true;
258 }
259 
261  if (_queueSize >= 50)
262  if (!Common::isMainThread())
263  _queueProcessed.wait(100);
264 
266 
267  int result = SDL_PushEvent(&event);
268  _queueSize++;
269 
270  return result == 1;
271 }
272 
274  if (!repeat && _repeatCounter == 0)
275  throw Common::Exception("EventsManager::enableKeyRepeat(): Counter underrun");
276 
277  if (repeat)
278  _repeatCounter++;
279  else
280  _repeatCounter--;
281 
282  _repeat = _repeatCounter > 0;
283 }
284 
285 void EventsManager::enableTextInput(bool textInput) {
286  if (!textInput && _textInputCounter == 0)
287  throw Common::Exception("EventsManager::enableTextInput(): Counter underrun");
288 
289  if (textInput) {
290  if (_textInputCounter == 0)
291  SDL_StartTextInput();
293  } else {
294  if (_textInputCounter == 1)
295  SDL_StopTextInput();
297  }
298 }
299 
301  // TextInput events already contain UTF-8 encoded text
302  if (event.type == kEventTextInput)
303  return event.text.text;
304 
305  if (event.type == kEventKeyDown) {
306  uint32 sym = event.key.keysym.sym;
307 
308  // Mask out control characters
309  if ((sym & SDLK_SCANCODE_MASK) || Common::UString::isCntrl(sym))
310  return "";
311 
312  // Interpret this KeySym as an Unicode codepoint
313  return Common::UString(sym, 1);
314  }
315 
316  return "";
317 }
318 
320  return _quitRequested;
321 }
322 
324  _quitRequested = true;
325 }
326 
328  _doQuit = true;
329 }
330 
332  return _fatalError;
333 }
334 
336  _fatalError = true;
337  _quitRequested = true;
338  _doQuit = true;
339 }
340 
342  while (!_doQuit) {
343  // (Pre)Process all events
344  processEvents();
345 
347 
348  // Render a frame
349  GfxMan.renderScene();
350  }
351 }
352 
354  deinitJoysticks();
355 
356  const int joyCount = SDL_NumJoysticks();
357  if (joyCount <= 0)
358  return;
359 
360  _joysticks.reserve(joyCount);
361  for (int i = 0; i < joyCount; i++)
362  _joysticks.push_back(new Joystick(i));
363 
364  SDL_JoystickEventState(SDL_ENABLE);
365 }
366 
368  SDL_JoystickEventState(SDL_DISABLE);
369 
370  _joysticks.clear();
371 }
372 
374  return _joysticks.size();
375 }
376 
378  if (index >= _joysticks.size())
379  return 0;
380 
381  return _joysticks[index];
382 }
383 
385  for (Joysticks::const_iterator j = _joysticks.begin(); j != _joysticks.end(); ++j)
386  if ((*j)->getName() == name)
387  return *j;
388 
389  return 0;
390 }
391 
393  (*request._callInMainThread.caller)();
394 }
395 
397  request._glContainer.glContainer->rebuild();
398 }
399 
401  request._glContainer.glContainer->destroy();
402 }
403 
404 } // End of namespace Events
bool pushEvent(Event &event)
Push an event onto the events queue.
Definition: events.cpp:260
Inter-thread request events.
bool parseITC(const Event &event)
Look for inter-thread communication.
Definition: events.cpp:186
bool ready() const
Was the events subsystem successfully initialized?
Definition: events.cpp:123
The global graphics manager.
void runMainLoop()
Run the main loop.
Definition: events.cpp:341
#define START_IGNORE_IMPLICIT_FALLTHROUGH
Definition: fallthrough.h:79
A class holding an UTF-8 string.
Definition: ustring.h:48
void requestRebuildGLContainer(Request &request)
Definition: events.cpp:396
The global config manager.
Joystick/Gamepad handling.
void init()
Initialize the events subsystem.
Definition: events.cpp:66
bool isMainThread()
Returns true if called from the main thread, false otherwise.
Definition: threads.cpp:54
RequestDataGLContainer _glContainer
Definition: requesttypes.h:72
Inter-thread communication.
Definition: types.h:56
#define NotificationMan
Shortcut for accessing the notification manager.
Definition: notifications.h:75
Graphics::GLContainer * glContainer
Definition: requesttypes.h:48
The global window manager.
Text was written.
Definition: types.h:52
void enableTextInput(bool textInput=true)
Enable/Disable the text input.
Definition: events.cpp:285
#define TimerMan
Shortcut for accessing the timer manager.
Definition: timerman.h:112
Basic graphics types.
bool quitRequested() const
Was an engine quit requested?
Definition: events.cpp:319
void requestDestroyGLContainer(Request &request)
Definition: events.cpp:400
bool isQueueFull() const
Is the event queue full?
Definition: events.cpp:127
Common::Mutex _eventQueueMutex
Definition: events.h:172
EventQueue _eventQueue
Definition: events.h:171
Exception that provides a stack of explanations.
Definition: error.h:36
bool _ready
Was the events subsystem successfully initialized?
Definition: events.h:162
Common::UString getTextInput(const Event &event)
Return the text that was input with keyboard, in UTF-8 encoding.
Definition: events.cpp:300
SDL_Event Event
Definition: types.h:42
A container of OpenGL elements.
Joysticks _joysticks
Definition: events.h:169
bool wait(uint32 timeout=0)
Definition: mutex.cpp:121
Keyboard key was pressed.
Definition: types.h:46
The notification manager, handling all notifications.
uint32 getTimestamp() const
Return the number of milliseconds the application is running.
Definition: events.cpp:136
const MainThreadCallerFunctor * caller
Definition: requesttypes.h:44
Basic exceptions to throw.
Threading system helpers.
void raiseFatalError()
Raise a fatal engine error.
Definition: events.cpp:335
Utility templates and functions.
Common::Condition _queueProcessed
Definition: events.h:177
#define DECLARE_SINGLETON(T)
Note that you need to use this macro from the global namespace.
Definition: singleton.h:122
The global events manager.
void(EventsManager::* RequestHandler)(Request &)
Definition: events.h:157
ITCEvent
Specific type of the inter-thread communication.
Definition: types.h:70
Joystick * getJoystickByIndex(size_t index) const
Return the joystick with that index.
Definition: events.cpp:377
void requestQuit()
Request an engine quit.
Definition: events.cpp:323
void requestCallInMainThread(Request &request)
Definition: events.cpp:392
void reset()
Completely reset the events manager.
Definition: events.cpp:103
For range checks.
Definition: types.h:75
static const RequestHandler _requestHandler[kITCEventMAX]
Pointer to the request handler.
Definition: events.h:160
void deinitJoysticks()
Deinitialize the available joysticks/gamepads.
Definition: events.cpp:367
StackException Exception
Definition: error.h:59
The events manager.
Definition: events.h:48
Application quit was requested.
Definition: types.h:53
void doQuit()
Initiate the actual quitting process.
Definition: events.cpp:327
Convenience class that locks a mutex on creation and unlocks it on destruction.
Definition: mutex.h:71
#define STOP_IGNORE_IMPLICIT_FALLTHROUGH
Definition: fallthrough.h:80
#define WindowMan
Shortcut for accessing the window manager.
Definition: windowman.h:137
bool pollEvent(Event &event)
Get an event from the events queue.
Definition: events.cpp:247
void delay(uint32 ms)
Sleep that number of milliseconds.
Definition: events.cpp:131
void initJoysticks()
Initialize the available joysticks/gamepads.
Definition: events.cpp:353
void enforceMainThread()
Throws an Exception if called from a non-main thread.
Definition: threads.cpp:60
void deinit()
Deinitialize the events subsystem.
Definition: events.cpp:92
Joystick * getJoystickByName(const Common::UString &name) const
Return the first joystick with that name.
Definition: events.cpp:384
uint32_t uint32
Definition: types.h:204
bool parseEventGraphics(const Event &event)
Look for graphics events.
Definition: events.cpp:161
The global timer manager.
#define RequestMan
Shortcut for accessing the request manager.
Definition: requests.h:127
bool parseEventQuit(const Event &event)
Look for quit events.
Definition: events.cpp:140
size_t getJoystickCount() const
Return the number of available joysticks.
Definition: events.cpp:373
Compiler-specific defines to mark an implicit switch-case fallthrough.
A request, carrying inter-thread communication.
Definition: requesttypes.h:52
bool _quitRequested
Was an engine quit requested?
Definition: events.h:164
bool fatalErrorRaised() const
Was a fatal engine error raised?
Definition: events.cpp:331
bool _doQuit
Are we currently in the process of quitting?
Definition: events.h:165
void enableKeyRepeat(bool repeat=true)
Enable/Disable repeated key events.
Definition: events.cpp:273
void flushEvents()
Clear the event queue, ignore all unhandled events.
Definition: events.cpp:241
RequestCallInMainThread _callInMainThread
Definition: requesttypes.h:71
static bool isCntrl(uint32 c)
Is the character an ASCII control character?
Definition: ustring.cpp:805
Window was restored.
Definition: types.h:66
Keyboard key was released.
Definition: types.h:47
#define GfxMan
Shortcut for accessing the graphics manager.
Definition: graphics.h:299
Resize the window.
Definition: types.h:54