1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "IrrCompileConfig.h"
\r
7 #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
\r
9 #if defined (__STRICT_ANSI__)
\r
10 #error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi.
\r
13 #include "CIrrDeviceWin32.h"
\r
14 #include "IEventReceiver.h"
\r
15 #include "irrList.h"
\r
19 #include "irrString.h"
\r
20 #include "COSOperator.h"
\r
21 #include "dimension2d.h"
\r
22 #include "IGUISpriteBank.h"
\r
23 #include <winuser.h>
\r
24 #include "SExposedVideoData.h"
\r
25 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
26 #include <mmsystem.h>
\r
28 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
29 #define DIRECTINPUT_VERSION 0x0800
\r
32 #pragma comment(lib, "dinput8.lib")
\r
33 #pragma comment(lib, "dxguid.lib")
\r
37 #pragma comment(lib, "winmm.lib")
\r
42 #if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
\r
43 #include "CEGLManager.h"
\r
46 #if defined(_IRR_COMPILE_WITH_OPENGL_)
\r
47 #include "CWGLManager.h"
\r
54 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
\r
55 IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, HWND window);
\r
58 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
59 IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
62 #ifdef _IRR_COMPILE_WITH_OGLES1_
\r
63 IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
66 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
67 IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
70 } // end namespace irr
\r
74 struct SJoystickWin32Control
\r
76 CIrrDeviceWin32* Device;
\r
78 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
79 IDirectInput8* DirectInputDevice;
\r
81 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
85 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
88 LPDIRECTINPUTDEVICE8 lpdijoy;
\r
95 core::array<JoystickInfo> ActiveJoysticks;
\r
98 SJoystickWin32Control(CIrrDeviceWin32* dev);
\r
99 ~SJoystickWin32Control();
\r
101 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
102 static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp);
\r
103 void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi);
\r
106 void pollJoysticks();
\r
107 bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo);
\r
108 irr::core::stringc findJoystickName(int index, const JOYCAPS &caps) const;
\r
112 SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev)
\r
114 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
115 DirectInputDevice=0;
\r
116 if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL)))
\r
118 os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING);
\r
124 SJoystickWin32Control::~SJoystickWin32Control()
\r
126 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
127 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
129 LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy;
\r
137 if (DirectInputDevice)
\r
138 DirectInputDevice->Release();
\r
142 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
143 BOOL CALLBACK SJoystickWin32Control::EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp)
\r
145 SJoystickWin32Control* p=(SJoystickWin32Control*)cp;
\r
146 p->directInputAddJoystick(lpddi);
\r
147 return DIENUM_CONTINUE;
\r
149 void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi)
\r
151 //Get the GUID of the joystuck
\r
152 const GUID guid = lpddi->guidInstance;
\r
154 JoystickInfo activeJoystick;
\r
155 activeJoystick.Index=ActiveJoysticks.size();
\r
156 activeJoystick.guid=guid;
\r
157 activeJoystick.Name=lpddi->tszProductName;
\r
158 if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL)))
\r
160 os::Printer::log("Could not create DirectInput device", ELL_WARNING);
\r
164 activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps);
\r
165 if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps)))
\r
167 os::Printer::log("Could not create DirectInput device", ELL_WARNING);
\r
171 if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))
\r
173 os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING);
\r
177 if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2)))
\r
179 os::Printer::log("Could not set DirectInput device data format", ELL_WARNING);
\r
183 if (FAILED(activeJoystick.lpdijoy->Acquire()))
\r
185 os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING);
\r
190 if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info)))
\r
192 os::Printer::log("Could not read DirectInput device state", ELL_WARNING);
\r
196 ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid));
\r
197 activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0;
\r
198 activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0;
\r
199 activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0;
\r
200 activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0;
\r
201 activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0;
\r
202 activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0;
\r
205 for (u8 i=0; i<6; i++)
\r
207 if (activeJoystick.axisValid[i])
\r
211 for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++)
\r
214 activeJoystick.axisValid[i+caxis]=1;
\r
217 ActiveJoysticks.push_back(activeJoystick);
\r
221 void SJoystickWin32Control::pollJoysticks()
\r
223 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
224 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
225 if(0 == ActiveJoysticks.size())
\r
231 for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
233 // needs to be reset for each joystick
\r
234 // request ALL values and POV as continuous if possible
\r
236 const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps;
\r
237 // if no POV is available don't ask for POV values
\r
239 if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info)))
\r
243 event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
\r
244 event.JoystickEvent.Joystick = (u8)joystick;
\r
246 event.JoystickEvent.POV = (u16)info.rgdwPOV[0];
\r
247 // set to undefined if no POV value was returned or the value
\r
249 if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900))
\r
250 event.JoystickEvent.POV = 65535;
\r
252 for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
\r
253 event.JoystickEvent.Axis[axis] = 0;
\r
258 while (dxAxis < 6 && irrAxis <caps.dwAxes)
\r
275 axisValue=info.lRx;
\r
278 axisValue=info.lRy;
\r
281 axisValue=info.lRz;
\r
284 axisValue=info.rglSlider[0];
\r
287 axisValue=info.rglSlider[1];
\r
293 if (ActiveJoysticks[joystick].axisValid[dxAxis]>0)
\r
298 s32 val=axisValue - 32768;
\r
300 if (val <-32767) val=-32767;
\r
301 if (val > 32767) val=32767;
\r
302 event.JoystickEvent.Axis[irrAxis]=(s16)(val);
\r
310 BYTE* bytebuttons=info.rgbButtons;
\r
311 for (u16 i=0; i<32; i++)
\r
313 if (bytebuttons[i] >0)
\r
315 buttons |= (1 << i);
\r
318 event.JoystickEvent.ButtonStates = buttons;
\r
320 (void)Device->postEventFromUser(event);
\r
324 if (0 == ActiveJoysticks.size())
\r
330 for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
332 // needs to be reset for each joystick
\r
333 // request ALL values and POV as continuous if possible
\r
334 info.dwSize = sizeof(info);
\r
335 info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
\r
336 const JOYCAPS & caps = ActiveJoysticks[joystick].Caps;
\r
337 // if no POV is available don't ask for POV values
\r
338 if (!(caps.wCaps & JOYCAPS_HASPOV))
\r
339 info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
\r
340 if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info))
\r
344 event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
\r
345 event.JoystickEvent.Joystick = (u8)joystick;
\r
347 event.JoystickEvent.POV = (u16)info.dwPOV;
\r
348 // set to undefined if no POV value was returned or the value
\r
350 if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900))
\r
351 event.JoystickEvent.POV = 65535;
\r
353 for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
\r
354 event.JoystickEvent.Axis[axis] = 0;
\r
356 event.JoystickEvent.ButtonStates = info.dwButtons;
\r
358 switch(caps.wNumAxes)
\r
362 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] =
\r
363 (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768);
\r
366 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] =
\r
367 (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768);
\r
370 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] =
\r
371 (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768);
\r
374 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] =
\r
375 (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768);
\r
378 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] =
\r
379 (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768);
\r
382 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =
\r
383 (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768);
\r
386 (void)Device->postEventFromUser(event);
\r
390 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
393 /** This function is ported from SDL and released under zlib-license:
\r
394 * Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> */
\r
395 irr::core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYCAPS &caps) const
\r
397 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
399 // As a default use the name given in the joystick structure.
\r
400 // It is always the same name, independent of joystick.
\r
401 irr::core::stringc result(caps.szPname);
\r
403 core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+ "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR;
\r
404 HKEY hTopKey = HKEY_LOCAL_MACHINE;
\r
406 long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);
\r
407 if (regresult != ERROR_SUCCESS)
\r
409 hTopKey = HKEY_CURRENT_USER;
\r
410 regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);
\r
412 if (regresult != ERROR_SUCCESS)
\r
415 /* find the registry key name for the joystick's properties */
\r
417 DWORD regsize = sizeof(regname);
\r
418 core::stringc regvalue = core::stringc("Joystick")+core::stringc(index+1) + REGSTR_VAL_JOYOEMNAME;
\r
419 regresult = RegQueryValueExA(hKey, regvalue.c_str(), 0, 0, (LPBYTE)regname, ®size);
\r
421 if (regresult != ERROR_SUCCESS)
\r
424 /* open that registry key */
\r
425 core::stringc regkey = core::stringc(REGSTR_PATH_JOYOEM) + "\\" + regname;
\r
426 regresult = RegOpenKeyExA(hTopKey, regkey.c_str(), 0, KEY_READ, &hKey);
\r
427 if (regresult != ERROR_SUCCESS)
\r
430 /* find the size for the OEM name text */
\r
431 regsize = sizeof(regvalue);
\r
432 regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
\r
434 if (regresult == ERROR_SUCCESS)
\r
437 /* allocate enough memory for the OEM name text ... */
\r
438 name = new char[regsize];
\r
441 /* ... and read it from the registry */
\r
442 regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
\r
443 (LPBYTE)name, ®size );
\r
455 bool SJoystickWin32Control::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
\r
457 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
458 joystickInfo.clear();
\r
459 ActiveJoysticks.clear();
\r
460 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
461 if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY )))
\r
463 os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING);
\r
467 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
469 JoystickInfo& activeJoystick = ActiveJoysticks[joystick];
\r
470 SJoystickInfo info;
\r
471 info.Axes=activeJoystick.devcaps.dwAxes;
\r
472 info.Buttons=activeJoystick.devcaps.dwButtons;
\r
473 info.Name=activeJoystick.Name;
\r
474 info.PovHat = (activeJoystick.devcaps.dwPOVs != 0)
\r
475 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
\r
476 joystickInfo.push_back(info);
\r
480 const u32 numberOfJoysticks = ::joyGetNumDevs();
\r
482 info.dwSize = sizeof(info);
\r
483 info.dwFlags = JOY_RETURNALL;
\r
485 JoystickInfo activeJoystick;
\r
486 SJoystickInfo returnInfo;
\r
488 joystickInfo.reallocate(numberOfJoysticks);
\r
489 ActiveJoysticks.reallocate(numberOfJoysticks);
\r
492 for(; joystick < numberOfJoysticks; ++joystick)
\r
494 if(JOYERR_NOERROR == joyGetPosEx(joystick, &info)
\r
496 JOYERR_NOERROR == joyGetDevCaps(joystick,
\r
497 &activeJoystick.Caps,
\r
498 sizeof(activeJoystick.Caps)))
\r
500 activeJoystick.Index = joystick;
\r
501 ActiveJoysticks.push_back(activeJoystick);
\r
503 returnInfo.Joystick = (u8)joystick;
\r
504 returnInfo.Axes = activeJoystick.Caps.wNumAxes;
\r
505 returnInfo.Buttons = activeJoystick.Caps.wNumButtons;
\r
506 returnInfo.Name = findJoystickName(joystick, activeJoystick.Caps);
\r
507 returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV)
\r
508 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
\r
510 joystickInfo.push_back(returnInfo);
\r
514 for(joystick = 0; joystick < joystickInfo.size(); ++joystick)
\r
516 char logString[256];
\r
517 (void)sprintf(logString, "Found joystick %d, %d axes, %d buttons '%s'",
\r
518 joystick, joystickInfo[joystick].Axes,
\r
519 joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());
\r
520 os::Printer::log(logString, ELL_INFORMATION);
\r
527 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
529 } // end namespace irr
\r
531 // Get the codepage from the locale language id
\r
532 // Based on the table from http://www.science.co.il/Language/Locale-Codes.asp?s=decimal
\r
533 static unsigned int LocaleIdToCodepage(unsigned int lcid)
\r
537 case 1098: // Telugu
\r
538 case 1095: // Gujarati
\r
539 case 1094: // Punjabi
\r
540 case 1103: // Sanskrit
\r
541 case 1111: // Konkani
\r
542 case 1114: // Syriac
\r
543 case 1099: // Kannada
\r
544 case 1102: // Marathi
\r
545 case 1125: // Divehi
\r
546 case 1067: // Armenian
\r
547 case 1081: // Hindi
\r
548 case 1079: // Georgian
\r
549 case 1097: // Tamil
\r
553 case 1041: // Japanese
\r
555 case 2052: // Chinese (PRC)
\r
556 case 4100: // Chinese (Singapore)
\r
558 case 1042: // Korean
\r
560 case 5124: // Chinese (Macau S.A.R.)
\r
561 case 3076: // Chinese (Hong Kong S.A.R.)
\r
562 case 1028: // Chinese (Taiwan)
\r
564 case 1048: // Romanian
\r
565 case 1060: // Slovenian
\r
566 case 1038: // Hungarian
\r
567 case 1051: // Slovak
\r
568 case 1045: // Polish
\r
569 case 1052: // Albanian
\r
570 case 2074: // Serbian (Latin)
\r
571 case 1050: // Croatian
\r
572 case 1029: // Czech
\r
574 case 1104: // Mongolian (Cyrillic)
\r
575 case 1071: // FYRO Macedonian
\r
576 case 2115: // Uzbek (Cyrillic)
\r
577 case 1058: // Ukrainian
\r
578 case 2092: // Azeri (Cyrillic)
\r
579 case 1092: // Tatar
\r
580 case 1087: // Kazakh
\r
581 case 1059: // Belarusian
\r
582 case 1088: // Kyrgyz (Cyrillic)
\r
583 case 1026: // Bulgarian
\r
584 case 3098: // Serbian (Cyrillic)
\r
585 case 1049: // Russian
\r
587 case 8201: // English (Jamaica)
\r
588 case 3084: // French (Canada)
\r
589 case 1036: // French (France)
\r
590 case 5132: // French (Luxembourg)
\r
591 case 5129: // English (New Zealand)
\r
592 case 6153: // English (Ireland)
\r
593 case 1043: // Dutch (Netherlands)
\r
594 case 9225: // English (Caribbean)
\r
595 case 4108: // French (Switzerland)
\r
596 case 4105: // English (Canada)
\r
597 case 1110: // Galician
\r
598 case 10249: // English (Belize)
\r
599 case 3079: // German (Austria)
\r
600 case 6156: // French (Monaco)
\r
601 case 12297: // English (Zimbabwe)
\r
602 case 1069: // Basque
\r
603 case 2067: // Dutch (Belgium)
\r
604 case 2060: // French (Belgium)
\r
605 case 1035: // Finnish
\r
606 case 1080: // Faroese
\r
607 case 1031: // German (Germany)
\r
608 case 3081: // English (Australia)
\r
609 case 1033: // English (United States)
\r
610 case 2057: // English (United Kingdom)
\r
611 case 1027: // Catalan
\r
612 case 11273: // English (Trinidad)
\r
613 case 7177: // English (South Africa)
\r
614 case 1030: // Danish
\r
615 case 13321: // English (Philippines)
\r
616 case 15370: // Spanish (Paraguay)
\r
617 case 9226: // Spanish (Colombia)
\r
618 case 5130: // Spanish (Costa Rica)
\r
619 case 7178: // Spanish (Dominican Republic)
\r
620 case 12298: // Spanish (Ecuador)
\r
621 case 17418: // Spanish (El Salvador)
\r
622 case 4106: // Spanish (Guatemala)
\r
623 case 18442: // Spanish (Honduras)
\r
624 case 3082: // Spanish (International Sort)
\r
625 case 13322: // Spanish (Chile)
\r
626 case 19466: // Spanish (Nicaragua)
\r
627 case 2058: // Spanish (Mexico)
\r
628 case 10250: // Spanish (Peru)
\r
629 case 20490: // Spanish (Puerto Rico)
\r
630 case 1034: // Spanish (Traditional Sort)
\r
631 case 14346: // Spanish (Uruguay)
\r
632 case 8202: // Spanish (Venezuela)
\r
633 case 1089: // Swahili
\r
634 case 1053: // Swedish
\r
635 case 2077: // Swedish (Finland)
\r
636 case 5127: // German (Liechtenstein)
\r
637 case 1078: // Afrikaans
\r
638 case 6154: // Spanish (Panama)
\r
639 case 4103: // German (Luxembourg)
\r
640 case 16394: // Spanish (Bolivia)
\r
641 case 2055: // German (Switzerland)
\r
642 case 1039: // Icelandic
\r
643 case 1057: // Indonesian
\r
644 case 1040: // Italian (Italy)
\r
645 case 2064: // Italian (Switzerland)
\r
646 case 2068: // Norwegian (Nynorsk)
\r
647 case 11274: // Spanish (Argentina)
\r
648 case 1046: // Portuguese (Brazil)
\r
649 case 1044: // Norwegian (Bokmal)
\r
650 case 1086: // Malay (Malaysia)
\r
651 case 2110: // Malay (Brunei Darussalam)
\r
652 case 2070: // Portuguese (Portugal)
\r
654 case 1032: // Greek
\r
656 case 1091: // Uzbek (Latin)
\r
657 case 1068: // Azeri (Latin)
\r
658 case 1055: // Turkish
\r
660 case 1037: // Hebrew
\r
662 case 5121: // Arabic (Algeria)
\r
663 case 15361: // Arabic (Bahrain)
\r
664 case 9217: // Arabic (Yemen)
\r
665 case 3073: // Arabic (Egypt)
\r
666 case 2049: // Arabic (Iraq)
\r
667 case 11265: // Arabic (Jordan)
\r
668 case 13313: // Arabic (Kuwait)
\r
669 case 12289: // Arabic (Lebanon)
\r
670 case 4097: // Arabic (Libya)
\r
671 case 6145: // Arabic (Morocco)
\r
672 case 8193: // Arabic (Oman)
\r
673 case 16385: // Arabic (Qatar)
\r
674 case 1025: // Arabic (Saudi Arabia)
\r
675 case 10241: // Arabic (Syria)
\r
676 case 14337: // Arabic (U.A.E.)
\r
677 case 1065: // Farsi
\r
679 case 7169: // Arabic (Tunisia)
\r
681 case 1061: // Estonian
\r
682 case 1062: // Latvian
\r
683 case 1063: // Lithuanian
\r
685 case 1066: // Vietnamese
\r
688 return 65001; // utf-8
\r
696 irr::CIrrDeviceWin32* irrDev;
\r
698 // NOTE: This is global. We can have more than one Irrlicht Device at same time.
\r
699 irr::core::array<SEnvMapper> EnvMap;
\r
701 HKL KEYBOARD_INPUT_HKL=0;
\r
702 unsigned int KEYBOARD_INPUT_CODEPAGE = 1252;
\r
705 irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
\r
707 const irr::u32 end = EnvMap.size();
\r
708 for ( irr::u32 i=0; i < end; ++i )
\r
710 const SEnvMapper& env = EnvMap[i];
\r
711 if ( env.hWnd == hWnd )
\r
719 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
721 #ifndef WM_MOUSEWHEEL
\r
722 #define WM_MOUSEWHEEL 0x020A
\r
724 #ifndef WHEEL_DELTA
\r
725 #define WHEEL_DELTA 120
\r
728 irr::CIrrDeviceWin32* dev = 0;
\r
731 static irr::s32 ClickCount=0;
\r
732 if (GetCapture() != hWnd && ClickCount > 0)
\r
740 irr::s32 irrMessage;
\r
743 static messageMap mouseMap[] =
\r
745 {0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN},
\r
746 {1, WM_LBUTTONUP, irr::EMIE_LMOUSE_LEFT_UP},
\r
747 {0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN},
\r
748 {1, WM_RBUTTONUP, irr::EMIE_RMOUSE_LEFT_UP},
\r
749 {0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN},
\r
750 {1, WM_MBUTTONUP, irr::EMIE_MMOUSE_LEFT_UP},
\r
751 {2, WM_MOUSEMOVE, irr::EMIE_MOUSE_MOVED},
\r
752 {3, WM_MOUSEWHEEL, irr::EMIE_MOUSE_WHEEL},
\r
756 // handle grouped events
\r
757 messageMap * m = mouseMap;
\r
758 while ( m->group >=0 && m->winMessage != message )
\r
761 if ( m->group >= 0 )
\r
763 if ( m->group == 0 ) // down
\r
769 if ( m->group == 1 ) // up
\r
779 event.EventType = irr::EET_MOUSE_INPUT_EVENT;
\r
780 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage;
\r
781 event.MouseInput.X = (short)LOWORD(lParam);
\r
782 event.MouseInput.Y = (short)HIWORD(lParam);
\r
783 event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0);
\r
784 event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0);
\r
785 // left and right mouse buttons
\r
786 event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON);
\r
787 // middle and extra buttons
\r
788 if (wParam & MK_MBUTTON)
\r
789 event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE;
\r
790 #if(_WIN32_WINNT >= 0x0500)
\r
791 if (wParam & MK_XBUTTON1)
\r
792 event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1;
\r
793 if (wParam & MK_XBUTTON2)
\r
794 event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2;
\r
796 event.MouseInput.Wheel = 0.f;
\r
799 if ( m->group == 3 )
\r
801 POINT p; // fixed by jox
\r
803 ClientToScreen(hWnd, &p);
\r
804 event.MouseInput.X -= p.x;
\r
805 event.MouseInput.Y -= p.y;
\r
806 event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA;
\r
809 dev = getDeviceFromHWnd(hWnd);
\r
812 dev->postEventFromUser(event);
\r
814 if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN )
\r
816 irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event);
\r
819 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
\r
820 dev->postEventFromUser(event);
\r
822 else if ( clicks == 3 )
\r
824 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
\r
825 dev->postEventFromUser(event);
\r
837 BeginPaint(hWnd, &ps);
\r
838 EndPaint(hWnd, &ps);
\r
842 case WM_ERASEBKGND:
\r
845 case WM_SYSKEYDOWN:
\r
852 event.EventType = irr::EET_KEY_INPUT_EVENT;
\r
853 event.KeyInput.Key = (irr::EKEY_CODE)wParam;
\r
854 event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN);
\r
856 const UINT MY_MAPVK_VSC_TO_VK_EX = 3; // MAPVK_VSC_TO_VK_EX should be in SDK according to MSDN, but isn't in mine.
\r
857 if ( event.KeyInput.Key == irr::KEY_SHIFT )
\r
859 // this will fail on systems before windows NT/2000/XP, not sure _what_ will return there instead.
\r
860 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
\r
862 if ( event.KeyInput.Key == irr::KEY_CONTROL )
\r
864 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
\r
865 // some keyboards will just return LEFT for both - left and right keys. So also check extend bit.
\r
866 if (lParam & 0x1000000)
\r
867 event.KeyInput.Key = irr::KEY_RCONTROL;
\r
869 if ( event.KeyInput.Key == irr::KEY_MENU )
\r
871 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX );
\r
872 if (lParam & 0x1000000)
\r
873 event.KeyInput.Key = irr::KEY_RMENU;
\r
876 GetKeyboardState(allKeys);
\r
878 event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0);
\r
879 event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0);
\r
881 // Handle unicode and deadkeys in a way that works since Windows 95 and nt4.0
\r
882 // Using ToUnicode instead would be shorter, but would to my knowledge not run on 95 and 98.
\r
884 UINT scanCode = HIWORD(lParam);
\r
885 int conversionResult = ToAsciiEx(static_cast<UINT>(wParam),scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL);
\r
886 if (conversionResult == 1)
\r
889 MultiByteToWideChar(
\r
890 KEYBOARD_INPUT_CODEPAGE,
\r
891 MB_PRECOMPOSED, // default
\r
894 (WCHAR*)&unicodeChar,
\r
896 event.KeyInput.Char = unicodeChar;
\r
899 event.KeyInput.Char = 0;
\r
901 // allow composing characters like '@' with Alt Gr on non-US keyboards
\r
902 if ((allKeys[VK_MENU] & 0x80) != 0)
\r
903 event.KeyInput.Control = 0;
\r
905 dev = getDeviceFromHWnd(hWnd);
\r
907 dev->postEventFromUser(event);
\r
909 if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
\r
910 return DefWindowProc(hWnd, message, wParam, lParam);
\r
918 dev = getDeviceFromHWnd(hWnd);
\r
925 PostQuitMessage(0);
\r
928 case WM_SYSCOMMAND:
\r
929 // prevent screensaver or monitor powersave mode from starting
\r
930 if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
\r
931 (wParam & 0xFFF0) == SC_MONITORPOWER ||
\r
932 (wParam & 0xFFF0) == SC_KEYMENU
\r
939 // we need to take care for screen changes, e.g. Alt-Tab
\r
940 dev = getDeviceFromHWnd(hWnd);
\r
941 if (dev && dev->isFullscreen())
\r
943 if ((wParam&0xFF)==WA_INACTIVE)
\r
945 // If losing focus we minimize the app to show other one
\r
946 ShowWindow(hWnd,SW_MINIMIZE);
\r
947 // and switch back to default resolution
\r
948 dev->switchToFullScreen(true);
\r
952 // Otherwise we retore the fullscreen Irrlicht app
\r
953 SetForegroundWindow(hWnd);
\r
954 ShowWindow(hWnd, SW_RESTORE);
\r
955 // and set the fullscreen resolution again
\r
956 dev->switchToFullScreen();
\r
962 event.EventType = irr::EET_USER_EVENT;
\r
963 event.UserEvent.UserData1 = static_cast<size_t>(wParam);
\r
964 event.UserEvent.UserData2 = static_cast<size_t>(lParam);
\r
965 dev = getDeviceFromHWnd(hWnd);
\r
968 dev->postEventFromUser(event);
\r
973 // because Windows forgot about that in the meantime
\r
974 dev = getDeviceFromHWnd(hWnd);
\r
977 dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );
\r
978 dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );
\r
982 case WM_INPUTLANGCHANGE:
\r
983 // get the new codepage used for keyboard input
\r
984 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
\r
985 KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
\r
988 return DefWindowProc(hWnd, message, wParam, lParam);
\r
996 CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
\r
997 : CIrrDeviceStub(params), HWnd(0), ChangedToFullScreen(false), Resized(false),
\r
998 ExternalWindow(false), Win32CursorControl(0), JoyControl(0)
\r
1001 setDebugName("CIrrDeviceWin32");
\r
1004 // get windows version and create OS operator
\r
1005 core::stringc winversion;
\r
1006 getWindowsVersion(winversion);
\r
1007 Operator = new COSOperator(winversion);
\r
1008 os::Printer::log(winversion.c_str(), ELL_INFORMATION);
\r
1010 // get handle to exe file
\r
1011 HINSTANCE hInstance = GetModuleHandle(0);
\r
1013 // Store original desktop mode.
\r
1015 memset(&DesktopMode, 0, sizeof(DesktopMode));
\r
1016 DesktopMode.dmSize = sizeof(DesktopMode);
\r
1018 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DesktopMode);
\r
1020 // create the window if we need to and we do not use the null device
\r
1021 if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)
\r
1023 const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");
\r
1027 wcex.cbSize = sizeof(WNDCLASSEX);
\r
1028 wcex.style = CS_HREDRAW | CS_VREDRAW;
\r
1029 wcex.lpfnWndProc = WndProc;
\r
1030 wcex.cbClsExtra = 0;
\r
1031 wcex.cbWndExtra = 0;
\r
1032 wcex.hInstance = hInstance;
\r
1033 wcex.hIcon = NULL;
\r
1034 wcex.hCursor = 0; // LoadCursor(NULL, IDC_ARROW);
\r
1035 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
\r
1036 wcex.lpszMenuName = 0;
\r
1037 wcex.lpszClassName = ClassName;
\r
1040 // if there is an icon, load it
\r
1041 wcex.hIcon = (HICON)LoadImage(hInstance, __TEXT("irrlicht.ico"), IMAGE_ICON, 0,0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
\r
1043 RegisterClassEx(&wcex);
\r
1045 // calculate client size
\r
1048 clientSize.top = 0;
\r
1049 clientSize.left = 0;
\r
1050 clientSize.right = CreationParams.WindowSize.Width;
\r
1051 clientSize.bottom = CreationParams.WindowSize.Height;
\r
1053 DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable);
\r
1054 AdjustWindowRect(&clientSize, style, FALSE);
\r
1056 const s32 realWidth = clientSize.right - clientSize.left;
\r
1057 const s32 realHeight = clientSize.bottom - clientSize.top;
\r
1059 s32 windowLeft = (CreationParams.WindowPosition.X == -1 ?
\r
1060 (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 :
\r
1061 CreationParams.WindowPosition.X);
\r
1062 s32 windowTop = (CreationParams.WindowPosition.Y == -1 ?
\r
1063 (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 :
\r
1064 CreationParams.WindowPosition.Y);
\r
1066 if ( windowLeft < 0 )
\r
1068 if ( windowTop < 0 )
\r
1069 windowTop = 0; // make sure window menus are in screen on creation
\r
1071 if (CreationParams.Fullscreen)
\r
1078 HWnd = CreateWindow( ClassName, __TEXT(""), style, windowLeft, windowTop,
\r
1079 realWidth, realHeight, NULL, NULL, hInstance, NULL);
\r
1082 os::Printer::log("Window could not be created.", ELL_ERROR);
\r
1085 CreationParams.WindowId = HWnd;
\r
1086 // CreationParams.WindowSize.Width = realWidth;
\r
1087 // CreationParams.WindowSize.Height = realHeight;
\r
1089 ShowWindow(HWnd, SW_SHOWNORMAL);
\r
1090 UpdateWindow(HWnd);
\r
1092 // fix ugly ATI driver bugs. Thanks to ariaci
\r
1093 MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);
\r
1095 // make sure everything gets updated to the real sizes
\r
1098 else if (CreationParams.WindowId)
\r
1100 // attach external window
\r
1101 HWnd = static_cast<HWND>(CreationParams.WindowId);
\r
1103 GetWindowRect(HWnd, &r);
\r
1104 CreationParams.WindowSize.Width = r.right - r.left;
\r
1105 CreationParams.WindowSize.Height = r.bottom - r.top;
\r
1106 CreationParams.Fullscreen = false;
\r
1107 ExternalWindow = true;
\r
1110 // create cursor control
\r
1112 Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);
\r
1113 CursorControl = Win32CursorControl;
\r
1114 JoyControl = new SJoystickWin32Control(this);
\r
1116 // initialize doubleclicks with system values
\r
1117 MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();
\r
1124 createGUIAndScene();
\r
1126 // register environment
\r
1131 EnvMap.push_back(em);
\r
1133 // set this as active window
\r
1134 if (!ExternalWindow)
\r
1136 SetActiveWindow(HWnd);
\r
1137 SetForegroundWindow(HWnd);
\r
1140 // get the codepage used for keyboard input
\r
1141 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
\r
1142 KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );
\r
1144 // inform driver about the window size etc.
\r
1145 resizeIfNecessary();
\r
1150 CIrrDeviceWin32::~CIrrDeviceWin32()
\r
1152 delete JoyControl;
\r
1154 // unregister environment
\r
1155 for (u32 i=0; i< EnvMap.size(); ++i)
\r
1157 if (EnvMap[i].hWnd == HWnd)
\r
1164 switchToFullScreen(true);
\r
1168 //! create the driver
\r
1169 void CIrrDeviceWin32::createDriver()
\r
1171 switch(CreationParams.DriverType)
\r
1173 case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
\r
1174 os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR);
\r
1176 case video::EDT_DIRECT3D9:
\r
1177 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
\r
1178 VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);
\r
1181 os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);
\r
1183 os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
\r
1186 case video::EDT_OPENGL:
\r
1187 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
1188 switchToFullScreen();
\r
1190 ContextManager = new video::CWGLManager();
\r
1191 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
\r
1193 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
\r
1196 os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
\r
1198 os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);
\r
1201 case video::EDT_OGLES1:
\r
1202 #ifdef _IRR_COMPILE_WITH_OGLES1_
\r
1203 switchToFullScreen();
\r
1205 ContextManager = new video::CEGLManager();
\r
1206 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
\r
1208 VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);
\r
1211 os::Printer::log("Could not create OpenGL-ES1 driver.", ELL_ERROR);
\r
1213 os::Printer::log("OpenGL-ES1 driver was not compiled in.", ELL_ERROR);
\r
1216 case video::EDT_OGLES2:
\r
1217 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
1218 switchToFullScreen();
\r
1220 ContextManager = new video::CEGLManager();
\r
1221 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
\r
1223 VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
\r
1226 os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR);
\r
1228 os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR);
\r
1231 case video::EDT_WEBGL1:
\r
1232 os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR);
\r
1234 case video::EDT_SOFTWARE:
\r
1235 #ifdef _IRR_COMPILE_WITH_SOFTWARE_
\r
1236 switchToFullScreen();
\r
1238 VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);
\r
1240 os::Printer::log("Software driver was not compiled in.", ELL_ERROR);
\r
1243 case video::EDT_BURNINGSVIDEO:
\r
1244 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
\r
1245 switchToFullScreen();
\r
1247 VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);
\r
1249 os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);
\r
1252 case video::EDT_NULL:
\r
1253 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
\r
1256 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
\r
1262 //! runs the device. Returns false if device wants to be deleted
\r
1263 bool CIrrDeviceWin32::run()
\r
1265 os::Timer::tick();
\r
1267 static_cast<CCursorControl*>(CursorControl)->update();
\r
1269 handleSystemMessages();
\r
1272 resizeIfNecessary();
\r
1274 if(!Close && JoyControl)
\r
1275 JoyControl->pollJoysticks();
\r
1281 //! Pause the current process for the minimum time allowed only to allow other processes to execute
\r
1282 void CIrrDeviceWin32::yield()
\r
1287 //! Pause execution and let other processes to run for a specified amount of time.
\r
1288 void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer)
\r
1290 const bool wasStopped = Timer ? Timer->isStopped() : true;
\r
1291 if (pauseTimer && !wasStopped)
\r
1296 if (pauseTimer && !wasStopped)
\r
1301 void CIrrDeviceWin32::resizeIfNecessary()
\r
1303 if (!Resized || !getVideoDriver())
\r
1307 GetClientRect(HWnd, &r);
\r
1311 if (r.right < 2 || r.bottom < 2)
\r
1313 sprintf(tmp, "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);
\r
1314 os::Printer::log(tmp);
\r
1318 sprintf(tmp, "Resizing window (%ld %ld)", r.right, r.bottom);
\r
1319 os::Printer::log(tmp);
\r
1321 getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom));
\r
1322 getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize());
\r
1329 DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const
\r
1335 return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
\r
1337 return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
\r
1340 //! sets the caption of the window
\r
1341 void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)
\r
1343 // We use SendMessage instead of SetText to ensure proper
\r
1344 // function even in cases where the HWND was created in a different thread
\r
1345 DWORD_PTR dwResult;
\r
1346 SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,
\r
1347 reinterpret_cast<LPARAM>(text),
\r
1348 SMTO_ABORTIFHUNG, 2000, &dwResult);
\r
1352 //! presents a surface in the client area
\r
1353 bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rect<s32>* src)
\r
1357 hwnd = reinterpret_cast<HWND>(windowId);
\r
1359 HDC dc = GetDC(hwnd);
\r
1364 GetClientRect(hwnd, &rect);
\r
1365 const void* memory = (const void *)image->getData();
\r
1367 BITMAPV4HEADER bi;
\r
1368 ZeroMemory (&bi, sizeof(bi));
\r
1369 bi.bV4Size = sizeof(BITMAPINFOHEADER);
\r
1370 bi.bV4BitCount = (WORD)image->getBitsPerPixel();
\r
1372 bi.bV4Width = image->getDimension().Width;
\r
1373 bi.bV4Height = -((s32)image->getDimension().Height);
\r
1374 bi.bV4V4Compression = BI_BITFIELDS;
\r
1375 bi.bV4AlphaMask = image->getAlphaMask();
\r
1376 bi.bV4RedMask = image->getRedMask();
\r
1377 bi.bV4GreenMask = image->getGreenMask();
\r
1378 bi.bV4BlueMask = image->getBlueMask();
\r
1382 StretchDIBits(dc, 0,0, rect.right, rect.bottom,
\r
1383 src->UpperLeftCorner.X, src->UpperLeftCorner.Y,
\r
1384 src->getWidth(), src->getHeight(),
\r
1385 memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);
\r
1389 StretchDIBits(dc, 0,0, rect.right, rect.bottom,
\r
1390 0, 0, image->getDimension().Width, image->getDimension().Height,
\r
1391 memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);
\r
1394 ReleaseDC(hwnd, dc);
\r
1400 //! notifies the device that it should close itself
\r
1401 void CIrrDeviceWin32::closeDevice()
\r
1403 if (!ExternalWindow)
\r
1406 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
\r
1407 PostQuitMessage(0);
\r
1408 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
\r
1409 DestroyWindow(HWnd);
\r
1410 const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");
\r
1411 HINSTANCE hInstance = GetModuleHandle(0);
\r
1412 UnregisterClass(ClassName, hInstance);
\r
1418 //! returns if window is active. if not, nothing needs to be drawn
\r
1419 bool CIrrDeviceWin32::isWindowActive() const
\r
1421 return (GetActiveWindow() == HWnd);
\r
1425 //! returns if window has focus
\r
1426 bool CIrrDeviceWin32::isWindowFocused() const
\r
1428 bool ret = (GetFocus() == HWnd);
\r
1433 //! returns if window is minimized
\r
1434 bool CIrrDeviceWin32::isWindowMinimized() const
\r
1436 WINDOWPLACEMENT plc;
\r
1437 plc.length=sizeof(WINDOWPLACEMENT);
\r
1439 if (GetWindowPlacement(HWnd,&plc))
\r
1440 ret = plc.showCmd == SW_SHOWMINIMIZED;
\r
1445 //! switches to fullscreen
\r
1446 bool CIrrDeviceWin32::switchToFullScreen(bool reset)
\r
1448 if (!CreationParams.Fullscreen)
\r
1453 if (ChangedToFullScreen)
\r
1455 return (ChangeDisplaySettings(&DesktopMode,0)==DISP_CHANGE_SUCCESSFUL);
\r
1461 // use default values from current setting
\r
1464 memset(&dm, 0, sizeof(dm));
\r
1465 dm.dmSize = sizeof(dm);
\r
1467 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm);
\r
1468 dm.dmPelsWidth = CreationParams.WindowSize.Width;
\r
1469 dm.dmPelsHeight = CreationParams.WindowSize.Height;
\r
1470 dm.dmBitsPerPel = CreationParams.Bits;
\r
1471 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
\r
1473 LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
\r
1474 if (res != DISP_CHANGE_SUCCESSFUL)
\r
1475 { // try again without forcing display frequency
\r
1476 dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
\r
1477 res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
\r
1483 case DISP_CHANGE_SUCCESSFUL:
\r
1484 ChangedToFullScreen = true;
\r
1487 case DISP_CHANGE_RESTART:
\r
1488 os::Printer::log("Switch to fullscreen: The computer must be restarted in order for the graphics mode to work.", ELL_ERROR);
\r
1490 case DISP_CHANGE_BADFLAGS:
\r
1491 os::Printer::log("Switch to fullscreen: An invalid set of flags was passed in.", ELL_ERROR);
\r
1493 case DISP_CHANGE_BADPARAM:
\r
1494 os::Printer::log("Switch to fullscreen: An invalid parameter was passed in. This can include an invalid flag or combination of flags.", ELL_ERROR);
\r
1496 case DISP_CHANGE_FAILED:
\r
1497 os::Printer::log("Switch to fullscreen: The display driver failed the specified graphics mode.", ELL_ERROR);
\r
1499 case DISP_CHANGE_BADMODE:
\r
1500 os::Printer::log("Switch to fullscreen: The graphics mode is not supported.", ELL_ERROR);
\r
1503 os::Printer::log("An unknown error occurred while changing to fullscreen.", ELL_ERROR);
\r
1510 //! returns the win32 cursor control
\r
1511 CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()
\r
1513 return Win32CursorControl;
\r
1517 //! \return Returns a pointer to a list with all video modes supported
\r
1518 //! by the gfx adapter.
\r
1519 video::IVideoModeList* CIrrDeviceWin32::getVideoModeList()
\r
1521 if (!VideoModeList->getVideoModeCount())
\r
1523 // enumerate video modes.
\r
1526 memset(&mode, 0, sizeof(mode));
\r
1527 mode.dmSize = sizeof(mode);
\r
1529 while (EnumDisplaySettings(NULL, i, &mode))
\r
1531 VideoModeList->addMode(core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight),
\r
1532 mode.dmBitsPerPel);
\r
1537 if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode))
\r
1538 VideoModeList->setDesktop(mode.dmBitsPerPel, core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight));
\r
1541 return VideoModeList;
\r
1544 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);
\r
1545 // Needed for old windows apis
\r
1546 // depending on the SDK version and compilers some defines might be available
\r
1548 #ifndef PRODUCT_ULTIMATE
\r
1549 #define PRODUCT_ULTIMATE 0x00000001
\r
1550 #define PRODUCT_HOME_BASIC 0x00000002
\r
1551 #define PRODUCT_HOME_PREMIUM 0x00000003
\r
1552 #define PRODUCT_ENTERPRISE 0x00000004
\r
1553 #define PRODUCT_HOME_BASIC_N 0x00000005
\r
1554 #define PRODUCT_BUSINESS 0x00000006
\r
1555 #define PRODUCT_STARTER 0x0000000B
\r
1557 #ifndef PRODUCT_ULTIMATE_N
\r
1558 #define PRODUCT_BUSINESS_N 0x00000010
\r
1559 #define PRODUCT_HOME_PREMIUM_N 0x0000001A
\r
1560 #define PRODUCT_ENTERPRISE_N 0x0000001B
\r
1561 #define PRODUCT_ULTIMATE_N 0x0000001C
\r
1563 #ifndef PRODUCT_STARTER_N
\r
1564 #define PRODUCT_STARTER_N 0x0000002F
\r
1566 #ifndef PRODUCT_PROFESSIONAL
\r
1567 #define PRODUCT_PROFESSIONAL 0x00000030
\r
1568 #define PRODUCT_PROFESSIONAL_N 0x00000031
\r
1570 #ifndef PRODUCT_ULTIMATE_E
\r
1571 #define PRODUCT_STARTER_E 0x00000042
\r
1572 #define PRODUCT_HOME_BASIC_E 0x00000043
\r
1573 #define PRODUCT_HOME_PREMIUM_E 0x00000044
\r
1574 #define PRODUCT_PROFESSIONAL_E 0x00000045
\r
1575 #define PRODUCT_ENTERPRISE_E 0x00000046
\r
1576 #define PRODUCT_ULTIMATE_E 0x00000047
\r
1579 void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)
\r
1581 OSVERSIONINFOEX osvi;
\r
1583 BOOL bOsVersionInfoEx;
\r
1585 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
\r
1586 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
\r
1588 bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);
\r
1589 if (!bOsVersionInfoEx)
\r
1591 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
\r
1592 if (! GetVersionEx((OSVERSIONINFO *) &osvi))
\r
1596 switch (osvi.dwPlatformId)
\r
1598 case VER_PLATFORM_WIN32_NT:
\r
1599 if (osvi.dwMajorVersion <= 4)
\r
1600 out.append("Microsoft Windows NT ");
\r
1602 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)
\r
1603 out.append("Microsoft Windows 2000 ");
\r
1605 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
\r
1606 out.append("Microsoft Windows XP ");
\r
1608 if (osvi.dwMajorVersion == 6 )
\r
1610 if (osvi.dwMinorVersion == 0)
\r
1612 if (osvi.wProductType == VER_NT_WORKSTATION)
\r
1613 out.append("Microsoft Windows Vista ");
\r
1615 out.append("Microsoft Windows Server 2008 ");
\r
1617 else if (osvi.dwMinorVersion == 1)
\r
1619 if (osvi.wProductType == VER_NT_WORKSTATION)
\r
1620 out.append("Microsoft Windows 7 ");
\r
1622 out.append("Microsoft Windows Server 2008 R2 ");
\r
1624 else if (osvi.dwMinorVersion == 2)
\r
1626 out.append("Microsoft Windows 8 or later ");
\r
1630 if (bOsVersionInfoEx)
\r
1632 if (osvi.dwMajorVersion == 6)
\r
1635 pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");
\r
1636 pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);
\r
1640 case PRODUCT_ULTIMATE:
\r
1641 case PRODUCT_ULTIMATE_E:
\r
1642 case PRODUCT_ULTIMATE_N:
\r
1643 out.append("Ultimate Edition ");
\r
1645 case PRODUCT_PROFESSIONAL:
\r
1646 case PRODUCT_PROFESSIONAL_E:
\r
1647 case PRODUCT_PROFESSIONAL_N:
\r
1648 out.append("Professional Edition ");
\r
1650 case PRODUCT_HOME_BASIC:
\r
1651 case PRODUCT_HOME_BASIC_E:
\r
1652 case PRODUCT_HOME_BASIC_N:
\r
1653 out.append("Home Basic Edition ");
\r
1655 case PRODUCT_HOME_PREMIUM:
\r
1656 case PRODUCT_HOME_PREMIUM_E:
\r
1657 case PRODUCT_HOME_PREMIUM_N:
\r
1658 out.append("Home Premium Edition ");
\r
1660 case PRODUCT_ENTERPRISE:
\r
1661 case PRODUCT_ENTERPRISE_E:
\r
1662 case PRODUCT_ENTERPRISE_N:
\r
1663 out.append("Enterprise Edition ");
\r
1665 case PRODUCT_BUSINESS:
\r
1666 case PRODUCT_BUSINESS_N:
\r
1667 out.append("Business Edition ");
\r
1669 case PRODUCT_STARTER:
\r
1670 case PRODUCT_STARTER_E:
\r
1671 case PRODUCT_STARTER_N:
\r
1672 out.append("Starter Edition ");
\r
1676 #ifdef VER_SUITE_ENTERPRISE
\r
1678 if (osvi.wProductType == VER_NT_WORKSTATION)
\r
1680 #ifndef __BORLANDC__
\r
1681 if( osvi.wSuiteMask & VER_SUITE_PERSONAL )
\r
1682 out.append("Personal ");
\r
1684 out.append("Professional ");
\r
1687 else if (osvi.wProductType == VER_NT_SERVER)
\r
1689 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )
\r
1690 out.append("DataCenter Server ");
\r
1691 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )
\r
1692 out.append("Advanced Server ");
\r
1694 out.append("Server ");
\r
1701 char szProductType[80];
\r
1704 RegOpenKeyEx( HKEY_LOCAL_MACHINE,
\r
1705 __TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),
\r
1706 0, KEY_QUERY_VALUE, &hKey );
\r
1707 RegQueryValueEx( hKey, __TEXT("ProductType"), NULL, NULL,
\r
1708 (LPBYTE) szProductType, &dwBufLen);
\r
1709 RegCloseKey( hKey );
\r
1712 if (irr::core::stringc("WINNT").equals_ignore_case(szProductType))
\r
1713 out.append("Professional ");
\r
1714 if (irr::core::stringc("LANMANNT").equals_ignore_case(szProductType))
\r
1715 out.append("Server ");
\r
1716 if (irr::core::stringc("SERVERNT").equals_ignore_case(szProductType))
\r
1717 out.append("Advanced Server ");
\r
1720 // Display version, service pack (if any), and build number.
\r
1724 if (osvi.dwMajorVersion <= 4 )
\r
1726 sprintf(tmp, "version %lu.%lu %s (Build %lu)",
\r
1727 osvi.dwMajorVersion,
\r
1728 osvi.dwMinorVersion,
\r
1729 irr::core::stringc(osvi.szCSDVersion).c_str(),
\r
1730 osvi.dwBuildNumber & 0xFFFF);
\r
1734 sprintf(tmp, "%s (Build %lu)", irr::core::stringc(osvi.szCSDVersion).c_str(),
\r
1735 osvi.dwBuildNumber & 0xFFFF);
\r
1741 case VER_PLATFORM_WIN32_WINDOWS:
\r
1743 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)
\r
1745 out.append("Microsoft Windows 95 ");
\r
1746 if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )
\r
1747 out.append("OSR2 " );
\r
1750 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
\r
1752 out.append("Microsoft Windows 98 ");
\r
1753 if ( osvi.szCSDVersion[1] == 'A' )
\r
1754 out.append( "SE " );
\r
1757 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
\r
1758 out.append("Microsoft Windows Me ");
\r
1762 case VER_PLATFORM_WIN32s:
\r
1763 out.append("Microsoft Win32s ");
\r
1768 //! Notifies the device, that it has been resized
\r
1769 void CIrrDeviceWin32::OnResized()
\r
1774 //! Resize the render window.
\r
1775 void CIrrDeviceWin32::setWindowSize(const irr::core::dimension2d<u32>& size)
\r
1777 if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
\r
1780 // get size of the window for the give size of the client area
\r
1781 DWORD style = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_STYLE));
\r
1782 DWORD exStyle = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_EXSTYLE));
\r
1784 clientSize.top = 0;
\r
1785 clientSize.left = 0;
\r
1786 clientSize.right = size.Width;
\r
1787 clientSize.bottom = size.Height;
\r
1788 AdjustWindowRectEx(&clientSize, style, false, exStyle);
\r
1789 const s32 realWidth = clientSize.right - clientSize.left;
\r
1790 const s32 realHeight = clientSize.bottom - clientSize.top;
\r
1792 UINT flags = SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
\r
1793 SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags);
\r
1796 //! Sets if the window should be resizable in windowed mode.
\r
1797 void CIrrDeviceWin32::setResizable(bool resize)
\r
1799 if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
\r
1802 LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize);
\r
1803 if (!SetWindowLongPtr(HWnd, GWL_STYLE, style))
\r
1804 os::Printer::log("Could not change window style.");
\r
1807 clientSize.top = 0;
\r
1808 clientSize.left = 0;
\r
1809 clientSize.right = getVideoDriver()->getScreenSize().Width;
\r
1810 clientSize.bottom = getVideoDriver()->getScreenSize().Height;
\r
1812 AdjustWindowRect(&clientSize, static_cast<DWORD>(style), FALSE);
\r
1814 const s32 realWidth = clientSize.right - clientSize.left;
\r
1815 const s32 realHeight = clientSize.bottom - clientSize.top;
\r
1817 const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
\r
1818 const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
\r
1820 SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,
\r
1821 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);
\r
1823 static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize);
\r
1827 //! Minimizes the window.
\r
1828 void CIrrDeviceWin32::minimizeWindow()
\r
1830 WINDOWPLACEMENT wndpl;
\r
1831 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1832 GetWindowPlacement(HWnd, &wndpl);
\r
1833 wndpl.showCmd = SW_SHOWMINNOACTIVE;
\r
1834 SetWindowPlacement(HWnd, &wndpl);
\r
1838 //! Maximizes the window.
\r
1839 void CIrrDeviceWin32::maximizeWindow()
\r
1841 WINDOWPLACEMENT wndpl;
\r
1842 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1843 GetWindowPlacement(HWnd, &wndpl);
\r
1844 wndpl.showCmd = SW_SHOWMAXIMIZED;
\r
1845 SetWindowPlacement(HWnd, &wndpl);
\r
1849 //! Restores the window to its original size.
\r
1850 void CIrrDeviceWin32::restoreWindow()
\r
1852 WINDOWPLACEMENT wndpl;
\r
1853 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1854 GetWindowPlacement(HWnd, &wndpl);
\r
1855 wndpl.showCmd = SW_SHOWNORMAL;
\r
1856 SetWindowPlacement(HWnd, &wndpl);
\r
1859 core::position2di CIrrDeviceWin32::getWindowPosition()
\r
1861 WINDOWPLACEMENT wndpl;
\r
1862 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1863 if (GetWindowPlacement(HWnd, &wndpl))
\r
1865 return core::position2di((int)wndpl.rcNormalPosition.left,
\r
1866 (int)wndpl.rcNormalPosition.top);
\r
1870 // No reason for this to happen
\r
1871 os::Printer::log("Failed to retrieve window location", ELL_ERROR);
\r
1872 return core::position2di(-1, -1);
\r
1876 bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
\r
1879 return JoyControl->activateJoysticks(joystickInfo);
\r
1885 //! Set the current Gamma Value for the Display
\r
1886 bool CIrrDeviceWin32::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )
\r
1891 calculateGammaRamp( ramp[0], red, brightness, contrast );
\r
1892 calculateGammaRamp( ramp[1], green, brightness, contrast );
\r
1893 calculateGammaRamp( ramp[2], blue, brightness, contrast );
\r
1895 HDC dc = GetDC(0);
\r
1896 r = SetDeviceGammaRamp ( dc, ramp ) == TRUE;
\r
1897 ReleaseDC(HWnd, dc);
\r
1901 //! Get the current Gamma Value for the Display
\r
1902 bool CIrrDeviceWin32::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )
\r
1907 HDC dc = GetDC(0);
\r
1908 r = GetDeviceGammaRamp ( dc, ramp ) == TRUE;
\r
1909 ReleaseDC(HWnd, dc);
\r
1913 calculateGammaFromRamp(red, ramp[0]);
\r
1914 calculateGammaFromRamp(green, ramp[1]);
\r
1915 calculateGammaFromRamp(blue, ramp[2]);
\r
1925 //! Process system events
\r
1926 void CIrrDeviceWin32::handleSystemMessages()
\r
1930 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
\r
1932 if (ExternalWindow && msg.hwnd == HWnd)
\r
1934 if (msg.hwnd == HWnd)
\r
1936 WndProc(HWnd, msg.message, msg.wParam, msg.lParam);
\r
1940 TranslateMessage(&msg);
\r
1941 DispatchMessage(&msg);
\r
1946 // No message translation because we don't use WM_CHAR and it would conflict with our
\r
1947 // deadkey handling.
\r
1948 DispatchMessage(&msg);
\r
1951 if (msg.message == WM_QUIT)
\r
1957 //! Remove all messages pending in the system message loop
\r
1958 void CIrrDeviceWin32::clearSystemMessages()
\r
1961 while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
\r
1963 while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
\r
1967 // shows last error in a messagebox to help internal debugging.
\r
1968 void CIrrDeviceWin32::ReportLastWinApiError()
\r
1970 // (based on code from ovidiucucu from http://www.codeguru.com/forum/showthread.php?t=318721)
\r
1971 LPCTSTR pszCaption = __TEXT("Windows SDK Error Report");
\r
1972 DWORD dwError = GetLastError();
\r
1974 if(NOERROR == dwError)
\r
1976 MessageBox(NULL, __TEXT("No error"), pszCaption, MB_OK);
\r
1980 const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER |
\r
1981 FORMAT_MESSAGE_IGNORE_INSERTS |
\r
1982 FORMAT_MESSAGE_FROM_SYSTEM;
\r
1984 LPVOID pTextBuffer = NULL;
\r
1985 DWORD dwCount = FormatMessage(dwFormatControl,
\r
1989 (LPTSTR) &pTextBuffer,
\r
1994 MessageBox(NULL, (LPCTSTR)pTextBuffer, pszCaption, MB_OK|MB_ICONERROR);
\r
1995 LocalFree(pTextBuffer);
\r
1999 MessageBox(NULL, __TEXT("Unknown error"), pszCaption, MB_OK|MB_ICONERROR);
\r
2004 // Same function Windows offers in VersionHelpers.h, but we can't use that as it's not available in older sdk's (minimum is SDK 8.1)
\r
2005 bool CIrrDeviceWin32::isWindowsVistaOrGreater()
\r
2007 #if (_WIN32_WINNT >= 0x0500)
\r
2008 OSVERSIONINFOEX osvi;
\r
2009 ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
\r
2010 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
\r
2011 osvi.dwMajorVersion = 6; // Windows Vista
\r
2013 if ( !GetVersionEx((OSVERSIONINFO*)&osvi) )
\r
2018 return VerifyVersionInfo(&osvi, VER_MAJORVERSION, VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL)) ? true : false;
\r
2024 // Convert an Irrlicht texture to a Windows cursor
\r
2025 // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/
\r
2026 HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
\r
2029 // create the bitmaps needed for cursors from the texture
\r
2031 HDC dc = GetDC(hwnd);
\r
2032 HDC andDc = CreateCompatibleDC(dc);
\r
2033 HDC xorDc = CreateCompatibleDC(dc);
\r
2034 HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
\r
2035 HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
\r
2037 HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap);
\r
2038 HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap);
\r
2041 video::ECOLOR_FORMAT format = tex->getColorFormat();
\r
2042 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
\r
2043 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
\r
2044 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
\r
2045 const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
\r
2046 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
\r
2047 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
\r
2049 data += bytesLeftGap;
\r
2050 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
\r
2052 video::SColor pixelCol;
\r
2053 pixelCol.setData((const void*)data, format);
\r
2054 data += bytesPerPixel;
\r
2056 if ( pixelCol.getAlpha() == 0 ) // transparent
\r
2058 SetPixel(andDc, x, y, RGB(255,255,255));
\r
2059 SetPixel(xorDc, x, y, RGB(0,0,0));
\r
2063 SetPixel(andDc, x, y, RGB(0,0,0));
\r
2064 SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue()));
\r
2067 data += bytesRightGap;
\r
2071 SelectObject(andDc, oldAndBitmap);
\r
2072 SelectObject(xorDc, oldXorBitmap);
\r
2077 ReleaseDC(hwnd, dc);
\r
2079 // create the cursor
\r
2081 ICONINFO iconinfo;
\r
2082 iconinfo.fIcon = false; // type is cursor not icon
\r
2083 iconinfo.xHotspot = hotspot.X;
\r
2084 iconinfo.yHotspot = hotspot.Y;
\r
2085 iconinfo.hbmMask = andBitmap;
\r
2086 iconinfo.hbmColor = xorBitmap;
\r
2088 HCURSOR cursor = CreateIconIndirect(&iconinfo);
\r
2090 DeleteObject(andBitmap);
\r
2091 DeleteObject(xorBitmap);
\r
2097 CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen)
\r
2098 : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f),
\r
2099 HWnd(hwnd), BorderX(0), BorderY(0),
\r
2100 UseReferenceRect(false), IsVisible(true)
\r
2101 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)
\r
2103 if (WindowSize.Width!=0)
\r
2104 InvWindowSize.Width = 1.0f / WindowSize.Width;
\r
2106 if (WindowSize.Height!=0)
\r
2107 InvWindowSize.Height = 1.0f / WindowSize.Height;
\r
2109 updateBorderSize(fullscreen, false);
\r
2113 CIrrDeviceWin32::CCursorControl::~CCursorControl()
\r
2115 for ( u32 i=0; i < Cursors.size(); ++i )
\r
2117 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )
\r
2119 DestroyCursor(Cursors[i].Frames[f].IconHW);
\r
2125 void CIrrDeviceWin32::CCursorControl::initCursors()
\r
2127 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) );
\r
2128 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) );
\r
2129 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) );
\r
2130 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) );
\r
2131 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) );
\r
2132 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) );
\r
2133 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) );
\r
2134 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) );
\r
2135 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) );
\r
2136 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) );
\r
2137 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) );
\r
2138 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) );
\r
2139 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) );
\r
2143 void CIrrDeviceWin32::CCursorControl::update()
\r
2145 if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )
\r
2147 // update animated cursors. This could also be done by X11 in case someone wants to figure that out (this way was just easier to implement)
\r
2148 u32 now = Device->getTimer()->getRealTime();
\r
2149 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
\r
2150 SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );
\r
2154 //! Sets the active cursor icon
\r
2155 void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)
\r
2157 if ( iconId >= (s32)Cursors.size() )
\r
2160 ActiveIcon = iconId;
\r
2161 ActiveIconStartTime = Device->getTimer()->getRealTime();
\r
2162 if ( Cursors[ActiveIcon].Frames.size() )
\r
2163 SetCursor( Cursors[ActiveIcon].Frames[0].IconHW );
\r
2167 //! Add a custom sprite as cursor icon.
\r
2168 gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon)
\r
2170 if ( icon.SpriteId >= 0 )
\r
2173 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
\r
2175 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
\r
2177 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
\r
2178 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
\r
2179 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
\r
2181 HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
\r
2182 cW32.Frames.push_back( CursorFrameW32(hc) );
\r
2185 Cursors.push_back( cW32 );
\r
2186 return (gui::ECURSOR_ICON)(Cursors.size() - 1);
\r
2188 return gui::ECI_NORMAL;
\r
2192 //! replace the given cursor icon.
\r
2193 void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)
\r
2195 if ( iconId >= (s32)Cursors.size() )
\r
2198 for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )
\r
2199 DestroyCursor(Cursors[iconId].Frames[i].IconHW);
\r
2201 if ( icon.SpriteId >= 0 )
\r
2204 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
\r
2205 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
\r
2207 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
\r
2208 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
\r
2209 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
\r
2211 HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
\r
2212 cW32.Frames.push_back( CursorFrameW32(hc) );
\r
2215 Cursors[iconId] = cW32;
\r
2220 //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.
\r
2221 core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const
\r
2223 core::dimension2di result;
\r
2225 result.Width = GetSystemMetrics(SM_CXCURSOR);
\r
2226 result.Height = GetSystemMetrics(SM_CYCURSOR);
\r
2233 } // end namespace
\r
2235 #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_
\r