1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #include "IrrCompileConfig.h"
6 
7 #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_
8 
9 #include "CIrrDeviceSDL.h"
10 #include "IEventReceiver.h"
11 #include "irrList.h"
12 #include "os.h"
13 #include "CTimer.h"
14 #include "irrString.h"
15 #include "Keycodes.h"
16 #include "COSOperator.h"
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include "SIrrCreationParameters.h"
20 #include "COpenGLExtensionHandler.h"
21 
22 #include "guiengine/engine.hpp"
23 
24 extern bool GLContextDebugBit;
25 
26 namespace irr
27 {
28 	namespace video
29 	{
30 		extern bool useCoreContext;
31 		IVideoDriver* createOpenGLDriver(const SIrrlichtCreationParameters& params,
32 			io::IFileSystem* io, CIrrDeviceSDL* device);
33 		IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params,
34 			io::IFileSystem* io, CIrrDeviceSDL* device, u32 default_fb);
35 
36 	} // end namespace video
37 
38 } // end namespace irr
39 
40 extern "C" void init_objc(SDL_SysWMinfo* info, float* top, float* bottom, float* left, float* right);
41 extern "C" int handle_app_event(void* userdata, SDL_Event* event);
42 
43 namespace irr
44 {
45 
46 float g_native_scale_x = 1.0f;
47 float g_native_scale_y = 1.0f;
48 
49 //! constructor
CIrrDeviceSDL(const SIrrlichtCreationParameters & param)50 CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param)
51 	: CIrrDeviceStub(param),
52 	Window(0), Context(0),
53 	MouseX(0), MouseY(0), MouseButtonStates(0),
54 	Width(param.WindowSize.Width), Height(param.WindowSize.Height),
55 	TopPadding(0), BottomPadding(0), LeftPadding(0), RightPadding(0),
56 	WindowHasFocus(false), WindowMinimized(false), Resizable(false),
57 	AccelerometerIndex(-1), AccelerometerInstance(-1),
58 	GyroscopeIndex(-1), GyroscopeInstance(-1)
59 {
60 	#ifdef _DEBUG
61 	setDebugName("CIrrDeviceSDL");
62 	#endif
63 
64 	Operator = 0;
65 	// Initialize SDL... Timer for sleep, video for the obvious, and
66 	// noparachute prevents SDL from catching fatal errors.
67 	SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
68 	SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
69 	u32 init_flags = SDL_INIT_TIMER | SDL_INIT_VIDEO;
70 	if (SDL_Init(init_flags) < 0)
71 	{
72 		os::Printer::log("Unable to initialize SDL!", SDL_GetError());
73 		Close = true;
74 	}
75 
76 #if SDL_VERSION_ATLEAST(2, 0, 9)
77 	// Don't exit if failed to init sensor (doesn't work in wine)
78 	if (SDL_InitSubSystem(SDL_INIT_SENSOR) < 0)
79 	{
80 		os::Printer::log("Failed to init SDL sensor!", SDL_GetError());
81 	}
82 #endif
83 
84 	// create keymap
85 	createKeyMap();
86 
87 	// create window
88 	if (CreationParams.DriverType != video::EDT_NULL)
89 	{
90 		// create the window, only if we do not use the null device
91 		if (!Close && createWindow())
92 		{
93 			SDL_VERSION(&Info.version);
94 
95 			if (!SDL_GetWindowWMInfo(Window, &Info))
96 				return;
97 #ifdef IOS_STK
98 			init_objc(&Info, &TopPadding, &BottomPadding, &LeftPadding, &RightPadding);
99 #endif
100 			core::stringc sdlversion = "SDL Version ";
101 			sdlversion += Info.version.major;
102 			sdlversion += ".";
103 			sdlversion += Info.version.minor;
104 			sdlversion += ".";
105 			sdlversion += Info.version.patch;
106 
107 			Operator = new COSOperator(sdlversion);
108 			os::Printer::log(sdlversion.c_str(), ELL_INFORMATION);
109 #if SDL_VERSION_ATLEAST(2, 0, 9)
110 			for (int i = 0; i < SDL_NumSensors(); i++)
111 			{
112 				if (SDL_SensorGetDeviceType(i) == SDL_SENSOR_ACCEL)
113 					AccelerometerIndex = i;
114 				else if (SDL_SensorGetDeviceType(i) == SDL_SENSOR_GYRO)
115 					GyroscopeIndex = i;
116 			}
117 #endif
118 		}
119 		else
120 			return;
121 	}
122 #ifndef ANDROID
123 	else if (!GUIEngine::isNoGraphics())
124 	{
125 		// Get highdpi native scale using renderer so it will work with any
126 		// backend later (opengl or vulkan)
127 		// Android doesn't use high dpi
128 		SDL_Window* window = NULL;
129 		SDL_Renderer* renderer = NULL;
130 		if (SDL_CreateWindowAndRenderer(640, 480,
131 			SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN,
132 			&window, &renderer) == 0)
133 		{
134 			int w, h, rw, rh;
135 			w = h = rw = rh = 0;
136 			SDL_GetWindowSize(window, &w, &h);
137 			SDL_GetRendererOutputSize(renderer, &rw, &rh);
138 			if (w != 0 && h != 0 && rw != 0 && rh != 0)
139 			{
140 				g_native_scale_x = (float)rw / (float)w;
141 				g_native_scale_y = (float)rh / (float)h;
142 			}
143 			SDL_DestroyRenderer(renderer);
144 			SDL_DestroyWindow(window);
145 		}
146 	}
147 #endif
148 
149 	// create cursor control
150 	CursorControl = new CCursorControl(this);
151 
152 	// create driver
153 	createDriver();
154 
155 	if (VideoDriver)
156 		createGUIAndScene();
157 #ifdef IOS_STK
158 	SDL_SetEventFilter(handle_app_event, NULL);
159 #endif
160 }
161 
162 
163 //! destructor
~CIrrDeviceSDL()164 CIrrDeviceSDL::~CIrrDeviceSDL()
165 {
166 	if (VideoDriver)
167 	{
168 		VideoDriver->drop();
169 		VideoDriver = NULL;
170 	}
171 	if (Context)
172 		SDL_GL_DeleteContext(Context);
173 	if (Window)
174 		SDL_DestroyWindow(Window);
175 	SDL_Quit();
176 }
177 
178 
activateAccelerometer(float updateInterval)179 bool CIrrDeviceSDL::activateAccelerometer(float updateInterval)
180 {
181 #if SDL_VERSION_ATLEAST(2, 0, 9)
182 	if (AccelerometerInstance == -1 && AccelerometerIndex != -1)
183 	{
184 		SDL_Sensor* accel = SDL_SensorOpen(AccelerometerIndex);
185 		if (accel)
186 			AccelerometerInstance = SDL_SensorGetInstanceID(accel);
187 	}
188 #endif
189 	return AccelerometerInstance != -1;
190 }
191 
192 
deactivateAccelerometer()193 bool CIrrDeviceSDL::deactivateAccelerometer()
194 {
195 #if SDL_VERSION_ATLEAST(2, 0, 9)
196 	if (AccelerometerInstance == -1)
197 		return false;
198 	SDL_Sensor* accel = SDL_SensorFromInstanceID(AccelerometerInstance);
199 	if (!accel)
200 		return false;
201 	SDL_SensorClose(accel);
202 	AccelerometerInstance = -1;
203 #endif
204 	return true;
205 }
206 
207 
isAccelerometerActive()208 bool CIrrDeviceSDL::isAccelerometerActive()
209 {
210 	return AccelerometerInstance != -1;
211 }
212 
213 
isAccelerometerAvailable()214 bool CIrrDeviceSDL::isAccelerometerAvailable()
215 {
216 	return AccelerometerIndex != -1;
217 }
218 
219 
activateGyroscope(float updateInterval)220 bool CIrrDeviceSDL::activateGyroscope(float updateInterval)
221 {
222 #if SDL_VERSION_ATLEAST(2, 0, 9)
223 	if (GyroscopeInstance == -1 && GyroscopeIndex != -1)
224 	{
225 		SDL_Sensor* gyro = SDL_SensorOpen(GyroscopeIndex);
226 		if (gyro)
227 			GyroscopeInstance = SDL_SensorGetInstanceID(gyro);
228 	}
229 #endif
230 	return GyroscopeInstance != -1;
231 }
232 
233 
deactivateGyroscope()234 bool CIrrDeviceSDL::deactivateGyroscope()
235 {
236 #if SDL_VERSION_ATLEAST(2, 0, 9)
237 	if (GyroscopeInstance == -1)
238 		return false;
239 	SDL_Sensor* gyro = SDL_SensorFromInstanceID(GyroscopeInstance);
240 	if (!gyro)
241 		return false;
242 	SDL_SensorClose(gyro);
243 	GyroscopeInstance = -1;
244 #endif
245 	return true;
246 }
247 
248 
isGyroscopeActive()249 bool CIrrDeviceSDL::isGyroscopeActive()
250 {
251 	return GyroscopeInstance != -1;
252 }
253 
254 
isGyroscopeAvailable()255 bool CIrrDeviceSDL::isGyroscopeAvailable()
256 {
257 	return GyroscopeIndex != -1;
258 }
259 
260 
versionCorrect(int major,int minor)261 bool versionCorrect(int major, int minor)
262 {
263 #ifdef _IRR_COMPILE_WITH_OGLES2_
264 	return true;
265 #else
266 	int created_major = 2;
267 	int created_minor = 0;
268 	glGetIntegerv(GL_MAJOR_VERSION, &created_major);
269 	glGetIntegerv(GL_MINOR_VERSION, &created_minor);
270 	if (created_major > major ||
271 		(created_major == major && created_minor >= minor))
272 		return true;
273 	return false;
274 #endif
275 }
276 
277 
278 // Used in OptionsScreenVideo for live updating vertical sync config
update_swap_interval(int swap_interval)279 extern "C" void update_swap_interval(int swap_interval)
280 {
281 #ifndef IOS_STK
282 	// iOS always use vertical sync
283 	if (swap_interval > 1)
284 		swap_interval = 1;
285 
286 	// Try adaptive vsync first if support
287 	if (swap_interval > 0)
288 	{
289 		int ret = SDL_GL_SetSwapInterval(-1);
290 		if (ret == 0)
291 			return;
292 	}
293 	SDL_GL_SetSwapInterval(swap_interval);
294 #endif
295 }
296 
297 
createWindow()298 bool CIrrDeviceSDL::createWindow()
299 {
300 	// Ignore alpha size here, this follow irr_driver.cpp:450
301 	// Try 32 and, upon failure, 24 then 16 bit per pixels
302 	if (CreationParams.Bits == 32)
303 	{
304 		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
305 		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
306 		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
307 		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
308 	}
309 	else if (CreationParams.Bits == 24)
310 	{
311 		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
312 		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
313 		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
314 		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
315 	}
316 	else
317 	{
318 		SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 3);
319 		SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 3);
320 		SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 2);
321 		SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
322 	}
323 
324 	u32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
325 	if (CreationParams.Fullscreen)
326 		flags |= SDL_WINDOW_FULLSCREEN;
327 
328 	if (CreationParams.DriverType == video::EDT_OPENGL ||
329 		CreationParams.DriverType == video::EDT_OGLES2)
330 		flags |= SDL_WINDOW_OPENGL;
331 
332 #ifdef MOBILE_STK
333 	flags |= SDL_WINDOW_BORDERLESS | SDL_WINDOW_MAXIMIZED;
334 #endif
335 
336 	tryCreateOpenGLContext(flags);
337 	if (!Window || !Context)
338 	{
339 		os::Printer::log( "Could not initialize display!" );
340 		return false;
341 	}
342 
343 	update_swap_interval(CreationParams.SwapInterval);
344 	return true;
345 }
346 
347 
tryCreateOpenGLContext(u32 flags)348 void CIrrDeviceSDL::tryCreateOpenGLContext(u32 flags)
349 {
350 start:
351 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, CreationParams.Doublebuffer);
352 	irr::video::useCoreContext = true;
353 
354 	if (GLContextDebugBit)
355 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
356 
357 	if (CreationParams.DriverType == video::EDT_OGLES2)
358 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
359 	else
360 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
361 
362 	if (CreationParams.ForceLegacyDevice)
363 		goto legacy;
364 
365 #ifdef _IRR_COMPILE_WITH_OGLES2_
366 	if (Context)
367 	{
368 		SDL_GL_DeleteContext(Context);
369 		Context = NULL;
370 	}
371 	if (Window)
372 	{
373 		SDL_DestroyWindow(Window);
374 		Window = NULL;
375 	}
376 
377 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
378 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
379 	Window = SDL_CreateWindow("",
380 		(float)CreationParams.WindowPosition.X / g_native_scale_x,
381 		(float)CreationParams.WindowPosition.Y / g_native_scale_y,
382 		(float)CreationParams.WindowSize.Width / g_native_scale_x,
383 		(float)CreationParams.WindowSize.Height / g_native_scale_y, flags);
384 	if (Window)
385 	{
386 		Context = SDL_GL_CreateContext(Window);
387 		if (Context && versionCorrect(3, 0)) return;
388 	}
389 
390 #else
391 	if (Context)
392 	{
393 		SDL_GL_DeleteContext(Context);
394 		Context = NULL;
395 	}
396 	if (Window)
397 	{
398 		SDL_DestroyWindow(Window);
399 		Window = NULL;
400 	}
401 
402 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
403 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
404 	Window = SDL_CreateWindow("",
405 		(float)CreationParams.WindowPosition.X / g_native_scale_x,
406 		(float)CreationParams.WindowPosition.Y / g_native_scale_y,
407 		(float)CreationParams.WindowSize.Width / g_native_scale_x,
408 		(float)CreationParams.WindowSize.Height / g_native_scale_y, flags);
409 	if (Window)
410 	{
411 		Context = SDL_GL_CreateContext(Window);
412 		if (Context && versionCorrect(4, 3)) return;
413 	}
414 
415 	if (Context)
416 	{
417 		SDL_GL_DeleteContext(Context);
418 		Context = NULL;
419 	}
420 	if (Window)
421 	{
422 		SDL_DestroyWindow(Window);
423 		Window = NULL;
424 	}
425 
426 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
427 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
428 	Window = SDL_CreateWindow("",
429 		(float)CreationParams.WindowPosition.X / g_native_scale_x,
430 		(float)CreationParams.WindowPosition.Y / g_native_scale_y,
431 		(float)CreationParams.WindowSize.Width / g_native_scale_x,
432 		(float)CreationParams.WindowSize.Height / g_native_scale_y, flags);
433 	if (Window)
434 	{
435 		Context = SDL_GL_CreateContext(Window);
436 		if (Context && versionCorrect(3, 3)) return;
437 	}
438 
439 	if (Context)
440 	{
441 		SDL_GL_DeleteContext(Context);
442 		Context = NULL;
443 	}
444 	if (Window)
445 	{
446 		SDL_DestroyWindow(Window);
447 		Window = NULL;
448 	}
449 
450 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
451 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
452 	Window = SDL_CreateWindow("",
453 		(float)CreationParams.WindowPosition.X / g_native_scale_x,
454 		(float)CreationParams.WindowPosition.Y / g_native_scale_y,
455 		(float)CreationParams.WindowSize.Width / g_native_scale_x,
456 		(float)CreationParams.WindowSize.Height / g_native_scale_y, flags);
457 	if (Window)
458 	{
459 		Context = SDL_GL_CreateContext(Window);
460 		if (Context && versionCorrect(3, 1)) return;
461 	}
462 #endif
463 
464 legacy:
465 	irr::video::useCoreContext = false;
466 	if (Context)
467 	{
468 		SDL_GL_DeleteContext(Context);
469 		Context = NULL;
470 	}
471 	if (Window)
472 	{
473 		SDL_DestroyWindow(Window);
474 		Window = NULL;
475 	}
476 
477 #ifdef _IRR_COMPILE_WITH_OGLES2_
478 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
479 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
480 #else
481 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
482 	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
483 #endif
484 	if (CreationParams.DriverType == video::EDT_OGLES2)
485 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
486 	else
487 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
488 	Window = SDL_CreateWindow("",
489 		(float)CreationParams.WindowPosition.X / g_native_scale_x,
490 		(float)CreationParams.WindowPosition.Y / g_native_scale_y,
491 		(float)CreationParams.WindowSize.Width / g_native_scale_x,
492 		(float)CreationParams.WindowSize.Height / g_native_scale_y, flags);
493 	if (Window)
494 	{
495 		Context = SDL_GL_CreateContext(Window);
496 		if (Context) return;
497 	}
498 
499 	if (CreationParams.Doublebuffer)
500 	{
501 		CreationParams.Doublebuffer = false;
502 		goto start;
503 	}
504 }
505 
506 //! create the driver
createDriver()507 void CIrrDeviceSDL::createDriver()
508 {
509 	switch(CreationParams.DriverType)
510 	{
511 	case video::EDT_OPENGL:
512 		#ifdef _IRR_COMPILE_WITH_OPENGL_
513 		VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this);
514 		#else
515 		os::Printer::log("No OpenGL support compiled in.", ELL_ERROR);
516 		#endif
517 		break;
518 
519 	case video::EDT_OGLES2:
520 	{
521 		#ifdef _IRR_COMPILE_WITH_OGLES2_
522 		u32 default_fb = 0;
523 		#ifdef IOS_STK
524 		default_fb = Info.info.uikit.framebuffer;
525 		#endif
526 		VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, this, default_fb);
527 		#else
528 		os::Printer::log("No OpenGL ES 2.0 support compiled in.", ELL_ERROR);
529 		#endif
530 		break;
531 	}
532 
533 	case video::EDT_NULL:
534 		VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
535 		break;
536 
537 	default:
538 		os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
539 		break;
540 	}
541 }
542 
543 // In input_manager.cpp
544 extern "C" void handle_joystick(SDL_Event& event);
545 // In main_loop.cpp
546 extern "C" void pause_mainloop();
547 extern "C" void resume_mainloop();
548 //! runs the device. Returns false if device wants to be deleted
run()549 bool CIrrDeviceSDL::run()
550 {
551 	os::Timer::tick();
552 
553 	SEvent irrevent;
554 	SDL_Event SDL_event;
555 
556 	while ( !Close && SDL_PollEvent( &SDL_event ) )
557 	{
558 		switch ( SDL_event.type )
559 		{
560 #if defined(MOBILE_STK) && !defined(IOS_STK)
561 		case SDL_APP_WILLENTERBACKGROUND:
562 			pause_mainloop();
563 			break;
564 		case SDL_APP_DIDENTERFOREGROUND:
565 			resume_mainloop();
566 			break;
567 #endif
568 #if SDL_VERSION_ATLEAST(2, 0, 9)
569 		case SDL_SENSORUPDATE:
570 			if (SDL_event.sensor.which == AccelerometerInstance)
571 			{
572 				SDL_DisplayOrientation o = SDL_GetDisplayOrientation(0);
573 				irrevent.EventType = irr::EET_ACCELEROMETER_EVENT;
574 				if (o == SDL_ORIENTATION_LANDSCAPE ||
575 					o == SDL_ORIENTATION_LANDSCAPE_FLIPPED)
576 				{
577 					irrevent.AccelerometerEvent.X = SDL_event.sensor.data[0];
578 					irrevent.AccelerometerEvent.Y = SDL_event.sensor.data[1];
579 				}
580 				else
581 				{
582 					// For android multi-window mode vertically
583 					irrevent.AccelerometerEvent.X = -SDL_event.sensor.data[1];
584 					irrevent.AccelerometerEvent.Y = -SDL_event.sensor.data[0];
585 				}
586 				irrevent.AccelerometerEvent.Z = SDL_event.sensor.data[2];
587 				// Mobile STK specific
588 				if (irrevent.AccelerometerEvent.X < 0.0)
589 					irrevent.AccelerometerEvent.X *= -1.0;
590 #ifdef IOS_STK
591 				if (o == SDL_ORIENTATION_LANDSCAPE)
592 					irrevent.AccelerometerEvent.Y *= -1.0;
593 #else
594 				if (o == SDL_ORIENTATION_LANDSCAPE_FLIPPED ||
595 					o == SDL_ORIENTATION_PORTRAIT_FLIPPED)
596 					irrevent.AccelerometerEvent.Y *= -1.0;
597 #endif
598 				postEventFromUser(irrevent);
599 			}
600 			else if (SDL_event.sensor.which == GyroscopeInstance)
601 			{
602 				irrevent.EventType = irr::EET_GYROSCOPE_EVENT;
603 				irrevent.GyroscopeEvent.X = SDL_event.sensor.data[0];
604 				irrevent.GyroscopeEvent.Y = SDL_event.sensor.data[1];
605 				irrevent.GyroscopeEvent.Z = SDL_event.sensor.data[2];
606 				postEventFromUser(irrevent);
607 			}
608 			break;
609 #endif
610 		case SDL_FINGERMOTION:
611 		case SDL_FINGERDOWN:
612 		case SDL_FINGERUP:
613 			irrevent.EventType = irr::EET_TOUCH_INPUT_EVENT;
614 			irrevent.TouchInput.Event = SDL_event.type == SDL_FINGERMOTION ? irr::ETIE_MOVED :
615 				SDL_event.type == SDL_FINGERDOWN ? irr::ETIE_PRESSED_DOWN : irr::ETIE_LEFT_UP;
616 			irrevent.TouchInput.ID = getTouchId(SDL_event.tfinger.fingerId);
617 			if (SDL_event.type == SDL_FINGERUP)
618 				removeTouchId(SDL_event.tfinger.fingerId);
619 			irrevent.TouchInput.X = SDL_event.tfinger.x * Width;
620 			irrevent.TouchInput.Y = SDL_event.tfinger.y * Height;
621 			postEventFromUser(irrevent);
622 			break;
623 
624 		case SDL_MOUSEWHEEL:
625 			if (SDL_event.wheel.x > 0 || SDL_event.wheel.x < 0)
626 				break;
627 			irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
628 			irrevent.MouseInput.Event = irr::EMIE_MOUSE_WHEEL;
629 			irrevent.MouseInput.X = MouseX;
630 			irrevent.MouseInput.Y = MouseY;
631 			irrevent.MouseInput.ButtonStates = MouseButtonStates;
632 			irrevent.MouseInput.Wheel = SDL_event.wheel.y > 0 ? 1.0f : -1.0f;
633 			postEventFromUser(irrevent);
634 			break;
635 
636 		case SDL_MOUSEMOTION:
637 			irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
638 			irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
639 			MouseX = irrevent.MouseInput.X = SDL_event.motion.x * g_native_scale_x;
640 			MouseY = irrevent.MouseInput.Y = SDL_event.motion.y * g_native_scale_y;
641 			irrevent.MouseInput.ButtonStates = MouseButtonStates;
642 
643 			postEventFromUser(irrevent);
644 			break;
645 
646 		case SDL_MOUSEBUTTONDOWN:
647 		case SDL_MOUSEBUTTONUP:
648 
649 			irrevent.EventType = irr::EET_MOUSE_INPUT_EVENT;
650 			irrevent.MouseInput.X = SDL_event.button.x * g_native_scale_x;
651 			irrevent.MouseInput.Y = SDL_event.button.y * g_native_scale_y;
652 
653 			irrevent.MouseInput.Event = irr::EMIE_MOUSE_MOVED;
654 
655 			switch(SDL_event.button.button)
656 			{
657 			case SDL_BUTTON_LEFT:
658 				if (SDL_event.type == SDL_MOUSEBUTTONDOWN)
659 				{
660 					irrevent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN;
661 					MouseButtonStates |= irr::EMBSM_LEFT;
662 				}
663 				else
664 				{
665 					irrevent.MouseInput.Event = irr::EMIE_LMOUSE_LEFT_UP;
666 					MouseButtonStates &= ~irr::EMBSM_LEFT;
667 				}
668 				break;
669 
670 			case SDL_BUTTON_RIGHT:
671 				if (SDL_event.type == SDL_MOUSEBUTTONDOWN)
672 				{
673 					irrevent.MouseInput.Event = irr::EMIE_RMOUSE_PRESSED_DOWN;
674 					MouseButtonStates |= irr::EMBSM_RIGHT;
675 				}
676 				else
677 				{
678 					irrevent.MouseInput.Event = irr::EMIE_RMOUSE_LEFT_UP;
679 					MouseButtonStates &= ~irr::EMBSM_RIGHT;
680 				}
681 				break;
682 
683 			case SDL_BUTTON_MIDDLE:
684 				if (SDL_event.type == SDL_MOUSEBUTTONDOWN)
685 				{
686 					irrevent.MouseInput.Event = irr::EMIE_MMOUSE_PRESSED_DOWN;
687 					MouseButtonStates |= irr::EMBSM_MIDDLE;
688 				}
689 				else
690 				{
691 					irrevent.MouseInput.Event = irr::EMIE_MMOUSE_LEFT_UP;
692 					MouseButtonStates &= ~irr::EMBSM_MIDDLE;
693 				}
694 				break;
695 			}
696 
697 			irrevent.MouseInput.ButtonStates = MouseButtonStates;
698 
699 			if (irrevent.MouseInput.Event != irr::EMIE_MOUSE_MOVED)
700 			{
701 				postEventFromUser(irrevent);
702 
703 				if ( irrevent.MouseInput.Event >= EMIE_LMOUSE_PRESSED_DOWN && irrevent.MouseInput.Event <= EMIE_MMOUSE_PRESSED_DOWN )
704 				{
705 					u32 clicks = checkSuccessiveClicks(irrevent.MouseInput.X, irrevent.MouseInput.Y, irrevent.MouseInput.Event);
706 					if ( clicks == 2 )
707 					{
708 						irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_DOUBLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);
709 						postEventFromUser(irrevent);
710 					}
711 					else if ( clicks == 3 )
712 					{
713 						irrevent.MouseInput.Event = (EMOUSE_INPUT_EVENT)(EMIE_LMOUSE_TRIPLE_CLICK + irrevent.MouseInput.Event-EMIE_LMOUSE_PRESSED_DOWN);
714 						postEventFromUser(irrevent);
715 					}
716 				}
717 			}
718 			break;
719 
720 		case SDL_KEYDOWN:
721 		case SDL_KEYUP:
722 			{
723 				SKeyMap mp;
724 				mp.SDLKey = SDL_event.key.keysym.sym;
725 				s32 idx = KeyMap.binary_search(mp);
726 
727 				EKEY_CODE key;
728 				if (idx == -1)
729 				{
730 					// Fallback to use scancode directly if not found, happens in
731 					// belarusian keyboard layout for example
732 					auto it = ScanCodeMap.find(SDL_event.key.keysym.scancode);
733 					if (it != ScanCodeMap.end())
734 						key = it->second;
735 					else
736 						key = (EKEY_CODE)0;
737 				}
738 				else
739 					key = (EKEY_CODE)KeyMap[idx].Win32Key;
740 
741 				irrevent.EventType = irr::EET_KEY_INPUT_EVENT;
742 				irrevent.KeyInput.Char = 0;
743 				irrevent.KeyInput.Key = key;
744 				irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
745 				irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
746 				irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL ) != 0;
747 				postEventFromUser(irrevent);
748 			}
749 			break;
750 
751 		case SDL_QUIT:
752 			Close = true;
753 			break;
754 
755 		case SDL_WINDOWEVENT:
756 			{
757 				u32 new_width = SDL_event.window.data1 * g_native_scale_x;
758 				u32 new_height = SDL_event.window.data2 * g_native_scale_y;
759 				if (SDL_event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED &&
760 					((new_width != Width) || (new_height != Height)))
761 				{
762 					Width = new_width;
763 					Height = new_height;
764 					if (VideoDriver)
765 						VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));
766 				}
767 				else if (SDL_event.window.event == SDL_WINDOWEVENT_MINIMIZED)
768 				{
769 					WindowMinimized = true;
770 				}
771 				else if (SDL_event.window.event == SDL_WINDOWEVENT_MAXIMIZED)
772 				{
773 					WindowMinimized = false;
774 				}
775 				else if (SDL_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
776 				{
777 					WindowHasFocus = true;
778 				}
779 				else if (SDL_event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
780 				{
781 					WindowHasFocus = false;
782 				}
783 			}
784 			break;
785 		case SDL_TEXTEDITING:
786 			{
787 				irrevent.EventType = irr::EET_SDL_TEXT_EVENT;
788 				irrevent.SDLTextEvent.Type = SDL_event.type;
789 				const size_t size = sizeof(irrevent.SDLTextEvent.Text);
790 				const size_t other_size = sizeof(SDL_event.edit.text);
791 				static_assert(sizeof(size) == sizeof(other_size), "Wrong size");
792 				memcpy(irrevent.SDLTextEvent.Text, SDL_event.edit.text, size);
793 				irrevent.SDLTextEvent.Start = SDL_event.edit.start;
794 				irrevent.SDLTextEvent.Length = SDL_event.edit.length;
795 				postEventFromUser(irrevent);
796 			}
797 			break;
798 		case SDL_TEXTINPUT:
799 			{
800 				irrevent.EventType = irr::EET_SDL_TEXT_EVENT;
801 				irrevent.SDLTextEvent.Type = SDL_event.type;
802 				const size_t size = sizeof(irrevent.SDLTextEvent.Text);
803 				const size_t other_size = sizeof(SDL_event.text.text);
804 				static_assert(sizeof(size) == sizeof(other_size), "Wrong size");
805 				memcpy(irrevent.SDLTextEvent.Text, SDL_event.text.text, size);
806 				irrevent.SDLTextEvent.Start = 0;
807 				irrevent.SDLTextEvent.Length = 0;
808 				postEventFromUser(irrevent);
809 			}
810 			break;
811 		default:
812 			handle_joystick(SDL_event);
813 			break;
814 		} // end switch
815 
816 	} // end while
817 
818 	return !Close;
819 }
820 
821 //! Activate any joysticks, and generate events for them.
activateJoysticks(core::array<SJoystickInfo> & joystickInfo)822 bool CIrrDeviceSDL::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
823 {
824 	return false;
825 }
826 
827 
828 
829 //! pause execution temporarily
yield()830 void CIrrDeviceSDL::yield()
831 {
832 	SDL_Delay(0);
833 }
834 
835 
836 //! pause execution for a specified time
sleep(u32 timeMs,bool pauseTimer)837 void CIrrDeviceSDL::sleep(u32 timeMs, bool pauseTimer)
838 {
839 	const bool wasStopped = Timer ? Timer->isStopped() : true;
840 	if (pauseTimer && !wasStopped)
841 		Timer->stop();
842 
843 	SDL_Delay(timeMs);
844 
845 	if (pauseTimer && !wasStopped)
846 		Timer->start();
847 }
848 
849 
850 //! sets the caption of the window
setWindowCaption(const wchar_t * text)851 void CIrrDeviceSDL::setWindowCaption(const wchar_t* text)
852 {
853 	core::stringc textc = text;
854 	SDL_SetWindowTitle(Window, textc.c_str());
855 }
856 
857 
858 //! presents a surface in the client area
present(video::IImage * surface,void * windowId,core::rect<s32> * srcClip)859 bool CIrrDeviceSDL::present(video::IImage* surface, void* windowId, core::rect<s32>* srcClip)
860 {
861 	return false;
862 }
863 
864 
865 //! notifies the device that it should close itself
closeDevice()866 void CIrrDeviceSDL::closeDevice()
867 {
868 	Close = true;
869 }
870 
871 
872 //! \return Pointer to a list with all video modes supported
getVideoModeList()873 video::IVideoModeList* CIrrDeviceSDL::getVideoModeList()
874 {
875 	if (!VideoModeList.getVideoModeCount())
876 	{
877 		// enumerate video modes.
878 		int display_count = 0;
879 		if ((display_count = SDL_GetNumVideoDisplays()) < 1)
880 		{
881 			os::Printer::log("No display created: ", SDL_GetError(), ELL_ERROR);
882 			return &VideoModeList;
883 		}
884 
885 		int mode_count = 0;
886 		if ((mode_count = SDL_GetNumDisplayModes(0)) < 1)
887 		{
888 			os::Printer::log("No display modes available: ", SDL_GetError(), ELL_ERROR);
889 			return &VideoModeList;
890 		}
891 
892 		SDL_DisplayMode mode = { SDL_PIXELFORMAT_UNKNOWN, 0, 0, 0, 0 };
893 		if (SDL_GetDesktopDisplayMode(0, &mode) == 0)
894 		{
895 			VideoModeList.setDesktop(SDL_BITSPERPIXEL(mode.format),
896 				core::dimension2d<u32>(mode.w * g_native_scale_x, mode.h * g_native_scale_y));
897 		}
898 
899 #ifdef MOBILE_STK
900 	// SDL2 will return w,h and h,w for mobile STK, as we only use landscape
901 	// so we just use desktop resolution for now
902 	VideoModeList.addMode(core::dimension2d<u32>(mode.w * g_native_scale_x, mode.h * g_native_scale_y),
903 		SDL_BITSPERPIXEL(mode.format));
904 #else
905 		for (int i = 0; i < mode_count; i++)
906 		{
907 			if (SDL_GetDisplayMode(0, i, &mode) == 0)
908 			{
909 				VideoModeList.addMode(core::dimension2d<u32>(mode.w * g_native_scale_x, mode.h * g_native_scale_y),
910 					SDL_BITSPERPIXEL(mode.format));
911 			}
912 		}
913 #endif
914 	}
915 
916 	return &VideoModeList;
917 }
918 
919 
920 //! Sets if the window should be resizable in windowed mode.
setResizable(bool resize)921 void CIrrDeviceSDL::setResizable(bool resize)
922 {
923 #if SDL_VERSION_ATLEAST(2, 0, 5)
924 	if (CreationParams.Fullscreen)
925 		return;
926 	SDL_SetWindowResizable(Window, resize ? SDL_TRUE : SDL_FALSE);
927 	Resizable = resize;
928 #endif
929 }
930 
931 
isResizable() const932 bool CIrrDeviceSDL::isResizable() const
933 {
934 	if (CreationParams.Fullscreen)
935 		return false;
936 	return Resizable;
937 }
938 
939 
940 //! Minimizes window if possible
minimizeWindow()941 void CIrrDeviceSDL::minimizeWindow()
942 {
943 	// do nothing
944 }
945 
946 
947 //! Maximize window
maximizeWindow()948 void CIrrDeviceSDL::maximizeWindow()
949 {
950 	// do nothing
951 }
952 
953 
954 //! Restore original window size
restoreWindow()955 void CIrrDeviceSDL::restoreWindow()
956 {
957 	// do nothing
958 }
959 
960 
961 //! Move window to requested position
moveWindow(int x,int y)962 bool CIrrDeviceSDL::moveWindow(int x, int y)
963 {
964 	if (Window)
965 	{
966 		SDL_SetWindowPosition(Window, x, y);
967 		return true;
968 	}
969 	return false;
970 }
971 
972 
973 //! Get current window position.
getWindowPosition(int * x,int * y)974 bool CIrrDeviceSDL::getWindowPosition(int* x, int* y)
975 {
976 	if (Window)
977 	{
978 		SDL_GetWindowPosition(Window, x, y);
979 		return true;
980 	}
981 	return false;
982 }
983 
984 
985 //! returns if window is active. if not, nothing need to be drawn
isWindowActive() const986 bool CIrrDeviceSDL::isWindowActive() const
987 {
988 	return (WindowHasFocus && !WindowMinimized);
989 }
990 
991 
992 //! returns if window has focus.
isWindowFocused() const993 bool CIrrDeviceSDL::isWindowFocused() const
994 {
995 	return WindowHasFocus;
996 }
997 
998 
999 //! returns if window is minimized.
isWindowMinimized() const1000 bool CIrrDeviceSDL::isWindowMinimized() const
1001 {
1002 	return WindowMinimized;
1003 }
1004 
1005 
1006 //! Set the current Gamma Value for the Display
setGammaRamp(f32 red,f32 green,f32 blue,f32 brightness,f32 contrast)1007 bool CIrrDeviceSDL::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )
1008 {
1009 	/*
1010 	// todo: Gamma in SDL takes ints, what does Irrlicht use?
1011 	return (SDL_SetGamma(red, green, blue) != -1);
1012 	*/
1013 	return false;
1014 }
1015 
1016 //! Get the current Gamma Value for the Display
getGammaRamp(f32 & red,f32 & green,f32 & blue,f32 & brightness,f32 & contrast)1017 bool CIrrDeviceSDL::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )
1018 {
1019 /*	brightness = 0.f;
1020 	contrast = 0.f;
1021 	return (SDL_GetGamma(&red, &green, &blue) != -1);*/
1022 	return false;
1023 }
1024 
setWindowMinimumSize(u32 width,u32 height)1025 void CIrrDeviceSDL::setWindowMinimumSize(u32 width, u32 height)
1026 {
1027 	if (Window)
1028 		SDL_SetWindowMinimumSize(Window, width, height);
1029 }
1030 
1031 //! returns color format of the window.
getColorFormat() const1032 video::ECOLOR_FORMAT CIrrDeviceSDL::getColorFormat() const
1033 {
1034 	if (Window)
1035 	{
1036 		u32 pixel_format = SDL_GetWindowPixelFormat(Window);
1037 		if (SDL_BITSPERPIXEL(pixel_format) == 16)
1038 		{
1039 			if (SDL_ISPIXELFORMAT_ALPHA(pixel_format))
1040 				return video::ECF_A1R5G5B5;
1041 			else
1042 				return video::ECF_R5G6B5;
1043 		}
1044 		else
1045 		{
1046 			if (SDL_ISPIXELFORMAT_ALPHA(pixel_format))
1047 				return video::ECF_A8R8G8B8;
1048 			else
1049 				return video::ECF_R8G8B8;
1050 		}
1051 	}
1052 	else
1053 		return CIrrDeviceStub::getColorFormat();
1054 }
1055 
1056 
createKeyMap()1057 void CIrrDeviceSDL::createKeyMap()
1058 {
1059 	// I don't know if this is the best method  to create
1060 	// the lookuptable, but I'll leave it like that until
1061 	// I find a better version.
1062 
1063 	KeyMap.reallocate(105);
1064 
1065 	// buttons missing
1066 
1067 	KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, IRR_KEY_BACK));
1068 	KeyMap.push_back(SKeyMap(SDLK_TAB, IRR_KEY_TAB));
1069 	KeyMap.push_back(SKeyMap(SDLK_CLEAR, IRR_KEY_CLEAR));
1070 	KeyMap.push_back(SKeyMap(SDLK_RETURN, IRR_KEY_RETURN));
1071 
1072 	// combined modifiers missing
1073 
1074 	KeyMap.push_back(SKeyMap(SDLK_PAUSE, IRR_KEY_PAUSE));
1075 	KeyMap.push_back(SKeyMap(SDLK_CAPSLOCK, IRR_KEY_CAPITAL));
1076 
1077 	// asian letter keys missing
1078 
1079 	KeyMap.push_back(SKeyMap(SDLK_ESCAPE, IRR_KEY_ESCAPE));
1080 
1081 	// asian letter keys missing
1082 
1083 	KeyMap.push_back(SKeyMap(SDLK_SPACE, IRR_KEY_SPACE));
1084 	KeyMap.push_back(SKeyMap(SDLK_PAGEUP, IRR_KEY_PRIOR));
1085 	KeyMap.push_back(SKeyMap(SDLK_PAGEDOWN, IRR_KEY_NEXT));
1086 	KeyMap.push_back(SKeyMap(SDLK_END, IRR_KEY_END));
1087 	KeyMap.push_back(SKeyMap(SDLK_HOME, IRR_KEY_HOME));
1088 	KeyMap.push_back(SKeyMap(SDLK_LEFT, IRR_KEY_LEFT));
1089 	KeyMap.push_back(SKeyMap(SDLK_UP, IRR_KEY_UP));
1090 	KeyMap.push_back(SKeyMap(SDLK_RIGHT, IRR_KEY_RIGHT));
1091 	KeyMap.push_back(SKeyMap(SDLK_DOWN, IRR_KEY_DOWN));
1092 
1093 	// select missing
1094 	KeyMap.push_back(SKeyMap(SDLK_PRINTSCREEN, IRR_KEY_PRINT));
1095 	// execute missing
1096 	KeyMap.push_back(SKeyMap(SDLK_PRINTSCREEN, IRR_KEY_SNAPSHOT));
1097 
1098 	KeyMap.push_back(SKeyMap(SDLK_INSERT, IRR_KEY_INSERT));
1099 	KeyMap.push_back(SKeyMap(SDLK_DELETE, IRR_KEY_DELETE));
1100 	KeyMap.push_back(SKeyMap(SDLK_HELP, IRR_KEY_HELP));
1101 
1102 	KeyMap.push_back(SKeyMap(SDLK_0, IRR_KEY_0));
1103 	KeyMap.push_back(SKeyMap(SDLK_1, IRR_KEY_1));
1104 	KeyMap.push_back(SKeyMap(SDLK_2, IRR_KEY_2));
1105 	KeyMap.push_back(SKeyMap(SDLK_3, IRR_KEY_3));
1106 	KeyMap.push_back(SKeyMap(SDLK_4, IRR_KEY_4));
1107 	KeyMap.push_back(SKeyMap(SDLK_5, IRR_KEY_5));
1108 	KeyMap.push_back(SKeyMap(SDLK_6, IRR_KEY_6));
1109 	KeyMap.push_back(SKeyMap(SDLK_7, IRR_KEY_7));
1110 	KeyMap.push_back(SKeyMap(SDLK_8, IRR_KEY_8));
1111 	KeyMap.push_back(SKeyMap(SDLK_9, IRR_KEY_9));
1112 
1113 	KeyMap.push_back(SKeyMap(SDLK_a, IRR_KEY_A));
1114 	KeyMap.push_back(SKeyMap(SDLK_b, IRR_KEY_B));
1115 	KeyMap.push_back(SKeyMap(SDLK_c, IRR_KEY_C));
1116 	KeyMap.push_back(SKeyMap(SDLK_d, IRR_KEY_D));
1117 	KeyMap.push_back(SKeyMap(SDLK_e, IRR_KEY_E));
1118 	KeyMap.push_back(SKeyMap(SDLK_f, IRR_KEY_F));
1119 	KeyMap.push_back(SKeyMap(SDLK_g, IRR_KEY_G));
1120 	KeyMap.push_back(SKeyMap(SDLK_h, IRR_KEY_H));
1121 	KeyMap.push_back(SKeyMap(SDLK_i, IRR_KEY_I));
1122 	KeyMap.push_back(SKeyMap(SDLK_j, IRR_KEY_J));
1123 	KeyMap.push_back(SKeyMap(SDLK_k, IRR_KEY_K));
1124 	KeyMap.push_back(SKeyMap(SDLK_l, IRR_KEY_L));
1125 	KeyMap.push_back(SKeyMap(SDLK_m, IRR_KEY_M));
1126 	KeyMap.push_back(SKeyMap(SDLK_n, IRR_KEY_N));
1127 	KeyMap.push_back(SKeyMap(SDLK_o, IRR_KEY_O));
1128 	KeyMap.push_back(SKeyMap(SDLK_p, IRR_KEY_P));
1129 	KeyMap.push_back(SKeyMap(SDLK_q, IRR_KEY_Q));
1130 	KeyMap.push_back(SKeyMap(SDLK_r, IRR_KEY_R));
1131 	KeyMap.push_back(SKeyMap(SDLK_s, IRR_KEY_S));
1132 	KeyMap.push_back(SKeyMap(SDLK_t, IRR_KEY_T));
1133 	KeyMap.push_back(SKeyMap(SDLK_u, IRR_KEY_U));
1134 	KeyMap.push_back(SKeyMap(SDLK_v, IRR_KEY_V));
1135 	KeyMap.push_back(SKeyMap(SDLK_w, IRR_KEY_W));
1136 	KeyMap.push_back(SKeyMap(SDLK_x, IRR_KEY_X));
1137 	KeyMap.push_back(SKeyMap(SDLK_y, IRR_KEY_Y));
1138 	KeyMap.push_back(SKeyMap(SDLK_z, IRR_KEY_Z));
1139 
1140 	KeyMap.push_back(SKeyMap(SDLK_LGUI, IRR_KEY_LWIN));
1141 	KeyMap.push_back(SKeyMap(SDLK_RGUI, IRR_KEY_RWIN));
1142 	KeyMap.push_back(SKeyMap(SDLK_APPLICATION, IRR_KEY_APPS));
1143 	KeyMap.push_back(SKeyMap(SDLK_POWER, IRR_KEY_SLEEP)); //??
1144 
1145 	KeyMap.push_back(SKeyMap(SDLK_KP_0, IRR_KEY_NUMPAD0));
1146 	KeyMap.push_back(SKeyMap(SDLK_KP_1, IRR_KEY_NUMPAD1));
1147 	KeyMap.push_back(SKeyMap(SDLK_KP_2, IRR_KEY_NUMPAD2));
1148 	KeyMap.push_back(SKeyMap(SDLK_KP_3, IRR_KEY_NUMPAD3));
1149 	KeyMap.push_back(SKeyMap(SDLK_KP_4, IRR_KEY_NUMPAD4));
1150 	KeyMap.push_back(SKeyMap(SDLK_KP_5, IRR_KEY_NUMPAD5));
1151 	KeyMap.push_back(SKeyMap(SDLK_KP_6, IRR_KEY_NUMPAD6));
1152 	KeyMap.push_back(SKeyMap(SDLK_KP_7, IRR_KEY_NUMPAD7));
1153 	KeyMap.push_back(SKeyMap(SDLK_KP_8, IRR_KEY_NUMPAD8));
1154 	KeyMap.push_back(SKeyMap(SDLK_KP_9, IRR_KEY_NUMPAD9));
1155 	KeyMap.push_back(SKeyMap(SDLK_KP_MULTIPLY, IRR_KEY_MULTIPLY));
1156 	KeyMap.push_back(SKeyMap(SDLK_KP_PLUS, IRR_KEY_ADD));
1157 	KeyMap.push_back(SKeyMap(SDLK_SEPARATOR, IRR_KEY_SEPARATOR));
1158 	KeyMap.push_back(SKeyMap(SDLK_KP_MINUS, IRR_KEY_SUBTRACT));
1159 	KeyMap.push_back(SKeyMap(SDLK_KP_PERIOD, IRR_KEY_DECIMAL));
1160 	KeyMap.push_back(SKeyMap(SDLK_KP_DIVIDE, IRR_KEY_DIVIDE));
1161 
1162 	KeyMap.push_back(SKeyMap(SDLK_F1,  IRR_KEY_F1));
1163 	KeyMap.push_back(SKeyMap(SDLK_F2,  IRR_KEY_F2));
1164 	KeyMap.push_back(SKeyMap(SDLK_F3,  IRR_KEY_F3));
1165 	KeyMap.push_back(SKeyMap(SDLK_F4,  IRR_KEY_F4));
1166 	KeyMap.push_back(SKeyMap(SDLK_F5,  IRR_KEY_F5));
1167 	KeyMap.push_back(SKeyMap(SDLK_F6,  IRR_KEY_F6));
1168 	KeyMap.push_back(SKeyMap(SDLK_F7,  IRR_KEY_F7));
1169 	KeyMap.push_back(SKeyMap(SDLK_F8,  IRR_KEY_F8));
1170 	KeyMap.push_back(SKeyMap(SDLK_F9,  IRR_KEY_F9));
1171 	KeyMap.push_back(SKeyMap(SDLK_F10, IRR_KEY_F10));
1172 	KeyMap.push_back(SKeyMap(SDLK_F11, IRR_KEY_F11));
1173 	KeyMap.push_back(SKeyMap(SDLK_F12, IRR_KEY_F12));
1174 	KeyMap.push_back(SKeyMap(SDLK_F13, IRR_KEY_F13));
1175 	KeyMap.push_back(SKeyMap(SDLK_F14, IRR_KEY_F14));
1176 	KeyMap.push_back(SKeyMap(SDLK_F15, IRR_KEY_F15));
1177 	// no higher F-keys
1178 
1179 	KeyMap.push_back(SKeyMap(SDLK_NUMLOCKCLEAR, IRR_KEY_NUMLOCK));
1180 	KeyMap.push_back(SKeyMap(SDLK_SCROLLLOCK, IRR_KEY_SCROLL));
1181 	KeyMap.push_back(SKeyMap(SDLK_LSHIFT, IRR_KEY_LSHIFT));
1182 	KeyMap.push_back(SKeyMap(SDLK_RSHIFT, IRR_KEY_RSHIFT));
1183 	KeyMap.push_back(SKeyMap(SDLK_LCTRL,  IRR_KEY_LCONTROL));
1184 	KeyMap.push_back(SKeyMap(SDLK_RCTRL,  IRR_KEY_RCONTROL));
1185 	KeyMap.push_back(SKeyMap(SDLK_LALT,  IRR_KEY_LMENU));
1186 	KeyMap.push_back(SKeyMap(SDLK_RALT,  IRR_KEY_RMENU));
1187 	KeyMap.push_back(SKeyMap(SDLK_MENU,  IRR_KEY_MENU));
1188 
1189 	KeyMap.push_back(SKeyMap(SDLK_PLUS,   IRR_KEY_PLUS));
1190 	KeyMap.push_back(SKeyMap(SDLK_COMMA,  IRR_KEY_COMMA));
1191 	KeyMap.push_back(SKeyMap(SDLK_MINUS,  IRR_KEY_MINUS));
1192 	KeyMap.push_back(SKeyMap(SDLK_PERIOD, IRR_KEY_PERIOD));
1193 	KeyMap.push_back(SKeyMap(SDLK_AC_BACK, IRR_KEY_ESCAPE));
1194 
1195 	KeyMap.push_back(SKeyMap(SDLK_EQUALS, IRR_KEY_PLUS));
1196 	KeyMap.push_back(SKeyMap(SDLK_LEFTBRACKET, IRR_KEY_OEM_4));
1197 	KeyMap.push_back(SKeyMap(SDLK_RIGHTBRACKET, IRR_KEY_OEM_6));
1198 	KeyMap.push_back(SKeyMap(SDLK_BACKSLASH, IRR_KEY_OEM_5));
1199 	KeyMap.push_back(SKeyMap(SDLK_SEMICOLON, IRR_KEY_OEM_1));
1200 	KeyMap.push_back(SKeyMap(SDLK_SLASH, IRR_KEY_OEM_2));
1201 	KeyMap.push_back(SKeyMap(SDLK_MODE, IRR_KEY_BUTTON_MODE));
1202 
1203 	// some special keys missing
1204 
1205 	KeyMap.sort();
1206 
1207 	ScanCodeMap[SDL_SCANCODE_A] = IRR_KEY_A;
1208 	ScanCodeMap[SDL_SCANCODE_B] = IRR_KEY_B;
1209 	ScanCodeMap[SDL_SCANCODE_C] = IRR_KEY_C;
1210 	ScanCodeMap[SDL_SCANCODE_D] = IRR_KEY_D;
1211 	ScanCodeMap[SDL_SCANCODE_E] = IRR_KEY_E;
1212 	ScanCodeMap[SDL_SCANCODE_F] = IRR_KEY_F;
1213 	ScanCodeMap[SDL_SCANCODE_G] = IRR_KEY_G;
1214 	ScanCodeMap[SDL_SCANCODE_H] = IRR_KEY_H;
1215 	ScanCodeMap[SDL_SCANCODE_I] = IRR_KEY_I;
1216 	ScanCodeMap[SDL_SCANCODE_J] = IRR_KEY_J;
1217 	ScanCodeMap[SDL_SCANCODE_K] = IRR_KEY_K;
1218 	ScanCodeMap[SDL_SCANCODE_L] = IRR_KEY_L;
1219 	ScanCodeMap[SDL_SCANCODE_M] = IRR_KEY_M;
1220 	ScanCodeMap[SDL_SCANCODE_N] = IRR_KEY_N;
1221 	ScanCodeMap[SDL_SCANCODE_O] = IRR_KEY_O;
1222 	ScanCodeMap[SDL_SCANCODE_P] = IRR_KEY_P;
1223 	ScanCodeMap[SDL_SCANCODE_Q] = IRR_KEY_Q;
1224 	ScanCodeMap[SDL_SCANCODE_R] = IRR_KEY_R;
1225 	ScanCodeMap[SDL_SCANCODE_S] = IRR_KEY_S;
1226 	ScanCodeMap[SDL_SCANCODE_T] = IRR_KEY_T;
1227 	ScanCodeMap[SDL_SCANCODE_U] = IRR_KEY_U;
1228 	ScanCodeMap[SDL_SCANCODE_V] = IRR_KEY_V;
1229 	ScanCodeMap[SDL_SCANCODE_W] = IRR_KEY_W;
1230 	ScanCodeMap[SDL_SCANCODE_X] = IRR_KEY_X;
1231 	ScanCodeMap[SDL_SCANCODE_Y] = IRR_KEY_Y;
1232 	ScanCodeMap[SDL_SCANCODE_Z] = IRR_KEY_Z;
1233 	ScanCodeMap[SDL_SCANCODE_1] = IRR_KEY_1;
1234 	ScanCodeMap[SDL_SCANCODE_2] = IRR_KEY_2;
1235 	ScanCodeMap[SDL_SCANCODE_3] = IRR_KEY_3;
1236 	ScanCodeMap[SDL_SCANCODE_4] = IRR_KEY_4;
1237 	ScanCodeMap[SDL_SCANCODE_5] = IRR_KEY_5;
1238 	ScanCodeMap[SDL_SCANCODE_6] = IRR_KEY_6;
1239 	ScanCodeMap[SDL_SCANCODE_7] = IRR_KEY_7;
1240 	ScanCodeMap[SDL_SCANCODE_8] = IRR_KEY_8;
1241 	ScanCodeMap[SDL_SCANCODE_9] = IRR_KEY_9;
1242 	ScanCodeMap[SDL_SCANCODE_0] = IRR_KEY_0;
1243 	ScanCodeMap[SDL_SCANCODE_RETURN] = IRR_KEY_RETURN;
1244 	ScanCodeMap[SDL_SCANCODE_ESCAPE] = IRR_KEY_ESCAPE;
1245 	ScanCodeMap[SDL_SCANCODE_BACKSPACE] = IRR_KEY_BACK;
1246 	ScanCodeMap[SDL_SCANCODE_TAB] = IRR_KEY_TAB;
1247 	ScanCodeMap[SDL_SCANCODE_SPACE] = IRR_KEY_SPACE;
1248 	ScanCodeMap[SDL_SCANCODE_MINUS] = IRR_KEY_MINUS;
1249 	ScanCodeMap[SDL_SCANCODE_EQUALS] = IRR_KEY_PLUS;
1250 	ScanCodeMap[SDL_SCANCODE_LEFTBRACKET] = IRR_KEY_OEM_4;
1251 	ScanCodeMap[SDL_SCANCODE_RIGHTBRACKET] = IRR_KEY_OEM_6;
1252 	ScanCodeMap[SDL_SCANCODE_BACKSLASH] = IRR_KEY_OEM_5;
1253 	ScanCodeMap[SDL_SCANCODE_SEMICOLON] = IRR_KEY_OEM_1;
1254 	ScanCodeMap[SDL_SCANCODE_APOSTROPHE] = IRR_KEY_OEM_7;
1255 	ScanCodeMap[SDL_SCANCODE_GRAVE] = IRR_KEY_OEM_3;
1256 	ScanCodeMap[SDL_SCANCODE_COMMA] = IRR_KEY_COMMA;
1257 	ScanCodeMap[SDL_SCANCODE_PERIOD] = IRR_KEY_PERIOD;
1258 	ScanCodeMap[SDL_SCANCODE_SLASH] = IRR_KEY_OEM_2;
1259 	ScanCodeMap[SDL_SCANCODE_CAPSLOCK] = IRR_KEY_CAPITAL;
1260 	ScanCodeMap[SDL_SCANCODE_F1] = IRR_KEY_F1;
1261 	ScanCodeMap[SDL_SCANCODE_F2] = IRR_KEY_F2;
1262 	ScanCodeMap[SDL_SCANCODE_F3] = IRR_KEY_F3;
1263 	ScanCodeMap[SDL_SCANCODE_F4] = IRR_KEY_F4;
1264 	ScanCodeMap[SDL_SCANCODE_F5] = IRR_KEY_F5;
1265 	ScanCodeMap[SDL_SCANCODE_F6] = IRR_KEY_F6;
1266 	ScanCodeMap[SDL_SCANCODE_F7] = IRR_KEY_F7;
1267 	ScanCodeMap[SDL_SCANCODE_F8] = IRR_KEY_F8;
1268 	ScanCodeMap[SDL_SCANCODE_F9] = IRR_KEY_F9;
1269 	ScanCodeMap[SDL_SCANCODE_F10] = IRR_KEY_F10;
1270 	ScanCodeMap[SDL_SCANCODE_F11] = IRR_KEY_F11;
1271 	ScanCodeMap[SDL_SCANCODE_F12] = IRR_KEY_F12;
1272 	ScanCodeMap[SDL_SCANCODE_PRINTSCREEN] = IRR_KEY_PRINT;
1273 	ScanCodeMap[SDL_SCANCODE_SCROLLLOCK] = IRR_KEY_SCROLL;
1274 	ScanCodeMap[SDL_SCANCODE_PAUSE] = IRR_KEY_PAUSE;
1275 	ScanCodeMap[SDL_SCANCODE_INSERT] = IRR_KEY_INSERT;
1276 	ScanCodeMap[SDL_SCANCODE_HOME] = IRR_KEY_HOME;
1277 	ScanCodeMap[SDL_SCANCODE_PAGEUP] = IRR_KEY_PRIOR;
1278 	ScanCodeMap[SDL_SCANCODE_DELETE] = IRR_KEY_DELETE;
1279 	ScanCodeMap[SDL_SCANCODE_END] = IRR_KEY_END;
1280 	ScanCodeMap[SDL_SCANCODE_PAGEDOWN] = IRR_KEY_NEXT;
1281 	ScanCodeMap[SDL_SCANCODE_RIGHT] = IRR_KEY_RIGHT;
1282 	ScanCodeMap[SDL_SCANCODE_LEFT] = IRR_KEY_LEFT;
1283 	ScanCodeMap[SDL_SCANCODE_DOWN] = IRR_KEY_DOWN;
1284 	ScanCodeMap[SDL_SCANCODE_UP] = IRR_KEY_UP;
1285 	ScanCodeMap[SDL_SCANCODE_NUMLOCKCLEAR] = IRR_KEY_NUMLOCK;
1286 	ScanCodeMap[SDL_SCANCODE_KP_DIVIDE] = IRR_KEY_DIVIDE;
1287 	ScanCodeMap[SDL_SCANCODE_KP_MULTIPLY] = IRR_KEY_MULTIPLY;
1288 	ScanCodeMap[SDL_SCANCODE_KP_MINUS] = IRR_KEY_MINUS;
1289 	ScanCodeMap[SDL_SCANCODE_KP_PLUS] = IRR_KEY_PLUS;
1290 	ScanCodeMap[SDL_SCANCODE_SEPARATOR] = IRR_KEY_SEPARATOR;
1291 	ScanCodeMap[SDL_SCANCODE_KP_ENTER] = IRR_KEY_RETURN;
1292 	ScanCodeMap[SDL_SCANCODE_KP_1] = IRR_KEY_NUMPAD1;
1293 	ScanCodeMap[SDL_SCANCODE_KP_2] = IRR_KEY_NUMPAD2;
1294 	ScanCodeMap[SDL_SCANCODE_KP_3] = IRR_KEY_NUMPAD3;
1295 	ScanCodeMap[SDL_SCANCODE_KP_4] = IRR_KEY_NUMPAD4;
1296 	ScanCodeMap[SDL_SCANCODE_KP_5] = IRR_KEY_NUMPAD5;
1297 	ScanCodeMap[SDL_SCANCODE_KP_6] = IRR_KEY_NUMPAD6;
1298 	ScanCodeMap[SDL_SCANCODE_KP_7] = IRR_KEY_NUMPAD7;
1299 	ScanCodeMap[SDL_SCANCODE_KP_8] = IRR_KEY_NUMPAD8;
1300 	ScanCodeMap[SDL_SCANCODE_KP_9] = IRR_KEY_NUMPAD9;
1301 	ScanCodeMap[SDL_SCANCODE_KP_0] = IRR_KEY_NUMPAD0;
1302 	ScanCodeMap[SDL_SCANCODE_LCTRL] = IRR_KEY_LCONTROL;
1303 	ScanCodeMap[SDL_SCANCODE_LSHIFT] = IRR_KEY_LSHIFT;
1304 	ScanCodeMap[SDL_SCANCODE_LALT] = IRR_KEY_LMENU;
1305 	ScanCodeMap[SDL_SCANCODE_LGUI] = IRR_KEY_LWIN;
1306 	ScanCodeMap[SDL_SCANCODE_RCTRL] = IRR_KEY_RCONTROL;
1307 	ScanCodeMap[SDL_SCANCODE_RSHIFT] = IRR_KEY_RSHIFT;
1308 	ScanCodeMap[SDL_SCANCODE_RALT] = IRR_KEY_RMENU;
1309 	ScanCodeMap[SDL_SCANCODE_RGUI] = IRR_KEY_RWIN;
1310 	ScanCodeMap[SDL_SCANCODE_APPLICATION] = IRR_KEY_APPS;
1311 	ScanCodeMap[SDL_SCANCODE_MODE] = IRR_KEY_BUTTON_MODE;
1312 	ScanCodeMap[SDL_SCANCODE_MENU] = IRR_KEY_MENU;
1313 }
1314 
1315 
supportsTouchDevice() const1316 bool CIrrDeviceSDL::supportsTouchDevice() const
1317 {
1318 	return SDL_GetNumTouchDevices() > 0;
1319 }
1320 
1321 
hasOnScreenKeyboard() const1322 bool CIrrDeviceSDL::hasOnScreenKeyboard() const
1323 {
1324 	return SDL_HasScreenKeyboardSupport() == SDL_TRUE;
1325 }
1326 
1327 
1328 extern "C" int Android_getMovedHeight();
getMovedHeight() const1329 s32 CIrrDeviceSDL::getMovedHeight() const
1330 {
1331 #if defined(IOS_STK)
1332 	return SDL_GetMovedHeightByScreenKeyboard() * g_native_scale_y;
1333 #elif defined(ANDROID)
1334 	return Android_getMovedHeight();
1335 #else
1336 	return 0;
1337 #endif
1338 }
1339 
1340 
1341 extern "C" int Android_getKeyboardHeight();
getOnScreenKeyboardHeight() const1342 u32 CIrrDeviceSDL::getOnScreenKeyboardHeight() const
1343 {
1344 #if defined(IOS_STK)
1345 	return SDL_GetScreenKeyboardHeight() * g_native_scale_y;
1346 #elif defined(ANDROID)
1347 	return Android_getKeyboardHeight();
1348 #else
1349 	return 0;
1350 #endif
1351 }
1352 
1353 
getNativeScaleX() const1354 f32 CIrrDeviceSDL::getNativeScaleX() const
1355 {
1356 	return g_native_scale_x;
1357 }
1358 
1359 
getNativeScaleY() const1360 f32 CIrrDeviceSDL::getNativeScaleY() const
1361 {
1362 	return g_native_scale_y;
1363 }
1364 
1365 } // end namespace irr
1366 
1367 #endif // _IRR_COMPILE_WITH_SDL_DEVICE_
1368 
1369