]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CIrrDeviceWin32.cpp
CIrrDeviceWin32: readd fullscreen using borderless maximized window
[irrlicht.git] / source / Irrlicht / CIrrDeviceWin32.cpp
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
4 \r
5 #include "IrrCompileConfig.h"\r
6 \r
7 #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r
8 \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
11 #endif\r
12 \r
13 #include "CIrrDeviceWin32.h"\r
14 #include "IEventReceiver.h"\r
15 #include "irrList.h"\r
16 #include "os.h"\r
17 \r
18 #include "CTimer.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
27 #include <regstr.h>\r
28 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
29 #define DIRECTINPUT_VERSION 0x0800\r
30 #include <dinput.h>\r
31 #ifdef _MSC_VER\r
32 #pragma comment(lib, "dinput8.lib")\r
33 #pragma comment(lib, "dxguid.lib")\r
34 #endif\r
35 #else\r
36 #ifdef _MSC_VER\r
37 #pragma comment(lib, "winmm.lib")\r
38 #endif\r
39 #endif\r
40 #endif\r
41 \r
42 #if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)\r
43 #include "CEGLManager.h"\r
44 #endif\r
45 \r
46 #if defined(_IRR_COMPILE_WITH_OPENGL_)\r
47 #include "CWGLManager.h"\r
48 #endif\r
49 \r
50 namespace irr\r
51 {\r
52         namespace video\r
53         {\r
54 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_\r
55                 IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, HWND window);\r
56 #endif\r
57 \r
58 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
59                 IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
60 #endif\r
61 \r
62 #ifdef _IRR_COMPILE_WITH_OGLES1_\r
63         IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
64 #endif\r
65 \r
66 #ifdef _IRR_COMPILE_WITH_OGLES2_\r
67         IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);\r
68 #endif\r
69         }\r
70 } // end namespace irr\r
71 \r
72 namespace irr\r
73 {\r
74     struct SJoystickWin32Control\r
75     {\r
76         CIrrDeviceWin32* Device;\r
77 \r
78     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)\r
79         IDirectInput8* DirectInputDevice;\r
80     #endif\r
81     #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)\r
82         struct JoystickInfo\r
83         {\r
84             u32 Index;\r
85     #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
86             core::stringc Name;\r
87             GUID guid;\r
88             LPDIRECTINPUTDEVICE8 lpdijoy;\r
89             DIDEVCAPS devcaps;\r
90             u8 axisValid[8];\r
91     #else\r
92             JOYCAPS Caps;\r
93     #endif\r
94         };\r
95         core::array<JoystickInfo> ActiveJoysticks;\r
96     #endif\r
97 \r
98         SJoystickWin32Control(CIrrDeviceWin32* dev);\r
99         ~SJoystickWin32Control();\r
100 \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
104     #endif\r
105 \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
109     };\r
110 \r
111 \r
112         SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev)\r
113         {\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
117                 {\r
118                         os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING);\r
119                         return;\r
120                 }\r
121 #endif\r
122         }\r
123 \r
124         SJoystickWin32Control::~SJoystickWin32Control()\r
125         {\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
128                 {\r
129                         LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy;\r
130                         if (dev)\r
131                         {\r
132                                 dev->Unacquire();\r
133                         }\r
134                         dev->Release();\r
135                 }\r
136 \r
137                 if (DirectInputDevice)\r
138                         DirectInputDevice->Release();\r
139 #endif\r
140         }\r
141 \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
144         {\r
145                 SJoystickWin32Control* p=(SJoystickWin32Control*)cp;\r
146                 p->directInputAddJoystick(lpddi);\r
147                 return DIENUM_CONTINUE;\r
148         }\r
149         void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi)\r
150         {\r
151                 //Get the GUID of the joystuck\r
152                 const GUID guid = lpddi->guidInstance;\r
153 \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
159                 {\r
160                         os::Printer::log("Could not create DirectInput device", ELL_WARNING);\r
161                         return;\r
162                 }\r
163 \r
164                 activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps);\r
165                 if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps)))\r
166                 {\r
167                         os::Printer::log("Could not create DirectInput device", ELL_WARNING);\r
168                         return;\r
169                 }\r
170 \r
171                 if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))\r
172                 {\r
173                         os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING);\r
174                         return;\r
175                 }\r
176 \r
177                 if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2)))\r
178                 {\r
179                         os::Printer::log("Could not set DirectInput device data format", ELL_WARNING);\r
180                         return;\r
181                 }\r
182 \r
183                 if (FAILED(activeJoystick.lpdijoy->Acquire()))\r
184                 {\r
185                         os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING);\r
186                         return;\r
187                 }\r
188 \r
189                 DIJOYSTATE2 info;\r
190                 if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info)))\r
191                 {\r
192                         os::Printer::log("Could not read DirectInput device state", ELL_WARNING);\r
193                         return;\r
194                 }\r
195 \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
203 \r
204                 int caxis=0;\r
205                 for (u8 i=0; i<6; i++)\r
206                 {\r
207                         if (activeJoystick.axisValid[i])\r
208                                 caxis++;\r
209                 }\r
210 \r
211                 for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++)\r
212                 {\r
213                         if (i+caxis < 8)\r
214                                 activeJoystick.axisValid[i+caxis]=1;\r
215                 }\r
216 \r
217                 ActiveJoysticks.push_back(activeJoystick);\r
218         }\r
219 #endif\r
220 \r
221 void SJoystickWin32Control::pollJoysticks()\r
222 {\r
223 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
224 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_\r
225         if(0 == ActiveJoysticks.size())\r
226                 return;\r
227 \r
228         u32 joystick;\r
229         DIJOYSTATE2 info;\r
230 \r
231         for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
232         {\r
233                 // needs to be reset for each joystick\r
234                 // request ALL values and POV as continuous if possible\r
235 \r
236                 const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps;\r
237                 // if no POV is available don't ask for POV values\r
238 \r
239                 if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info)))\r
240                 {\r
241                         SEvent event;\r
242 \r
243                         event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;\r
244                         event.JoystickEvent.Joystick = (u8)joystick;\r
245 \r
246                         event.JoystickEvent.POV = (u16)info.rgdwPOV[0];\r
247                         // set to undefined if no POV value was returned or the value\r
248                         // is out of range\r
249                         if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900))\r
250                                 event.JoystickEvent.POV = 65535;\r
251 \r
252                         for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)\r
253                                 event.JoystickEvent.Axis[axis] = 0;\r
254 \r
255                         u16 dxAxis=0;\r
256                         u16 irrAxis=0;\r
257 \r
258                         while (dxAxis < 6 && irrAxis <caps.dwAxes)\r
259                         {\r
260                                 bool axisFound=0;\r
261                                 s32 axisValue=0;\r
262 \r
263                                 switch (dxAxis)\r
264                                 {\r
265                                 case 0:\r
266                                         axisValue=info.lX;\r
267                                         break;\r
268                                 case 1:\r
269                                         axisValue=info.lY;\r
270                                         break;\r
271                                 case 2:\r
272                                         axisValue=info.lZ;\r
273                                         break;\r
274                                 case 3:\r
275                                         axisValue=info.lRx;\r
276                                         break;\r
277                                 case 4:\r
278                                         axisValue=info.lRy;\r
279                                         break;\r
280                                 case 5:\r
281                                         axisValue=info.lRz;\r
282                                         break;\r
283                                 case 6:\r
284                                         axisValue=info.rglSlider[0];\r
285                                         break;\r
286                                 case 7:\r
287                                         axisValue=info.rglSlider[1];\r
288                                         break;\r
289                                 default:\r
290                                         break;\r
291                                 }\r
292 \r
293                                 if (ActiveJoysticks[joystick].axisValid[dxAxis]>0)\r
294                                         axisFound=1;\r
295 \r
296                                 if (axisFound)\r
297                                 {\r
298                                         s32 val=axisValue - 32768;\r
299 \r
300                                         if (val <-32767) val=-32767;\r
301                                         if (val > 32767) val=32767;\r
302                                         event.JoystickEvent.Axis[irrAxis]=(s16)(val);\r
303                                         irrAxis++;\r
304                                 }\r
305 \r
306                                 dxAxis++;\r
307                         }\r
308 \r
309                         u32 buttons=0;\r
310                         BYTE* bytebuttons=info.rgbButtons;\r
311                         for (u16 i=0; i<32; i++)\r
312                         {\r
313                                 if (bytebuttons[i] >0)\r
314                                 {\r
315                                         buttons |= (1 << i);\r
316                                 }\r
317                         }\r
318                         event.JoystickEvent.ButtonStates = buttons;\r
319 \r
320                         (void)Device->postEventFromUser(event);\r
321                 }\r
322         }\r
323 #else\r
324         if (0 == ActiveJoysticks.size())\r
325                 return;\r
326 \r
327         u32 joystick;\r
328         JOYINFOEX info;\r
329 \r
330         for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
331         {\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
341                 {\r
342                         SEvent event;\r
343 \r
344                         event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;\r
345                         event.JoystickEvent.Joystick = (u8)joystick;\r
346 \r
347                         event.JoystickEvent.POV = (u16)info.dwPOV;\r
348                         // set to undefined if no POV value was returned or the value\r
349                         // is out of range\r
350                         if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900))\r
351                                 event.JoystickEvent.POV = 65535;\r
352 \r
353                         for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)\r
354                                 event.JoystickEvent.Axis[axis] = 0;\r
355 \r
356                         event.JoystickEvent.ButtonStates = info.dwButtons;\r
357 \r
358                         switch(caps.wNumAxes)\r
359                         {\r
360                         default:\r
361                         case 6:\r
362                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] =\r
363                                         (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768);\r
364 \r
365                         case 5:\r
366                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] =\r
367                                         (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768);\r
368 \r
369                         case 4:\r
370                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] =\r
371                                         (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768);\r
372 \r
373                         case 3:\r
374                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] =\r
375                                         (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768);\r
376 \r
377                         case 2:\r
378                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] =\r
379                                         (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768);\r
380 \r
381                         case 1:\r
382                                 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =\r
383                                         (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768);\r
384                         }\r
385 \r
386                         (void)Device->postEventFromUser(event);\r
387                 }\r
388         }\r
389 #endif\r
390 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
391 }\r
392 \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
396 {\r
397 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
398 \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
402 \r
403     core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+ "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR;\r
404     HKEY hTopKey = HKEY_LOCAL_MACHINE;\r
405     HKEY hKey;\r
406     long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);\r
407     if (regresult != ERROR_SUCCESS)\r
408     {\r
409         hTopKey = HKEY_CURRENT_USER;\r
410         regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);\r
411     }\r
412     if (regresult != ERROR_SUCCESS)\r
413         return result;\r
414 \r
415     /* find the registry key name for the joystick's properties */\r
416     char regname[256];\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, &regsize);\r
420     RegCloseKey(hKey);\r
421     if (regresult != ERROR_SUCCESS)\r
422         return result;\r
423 \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
428         return result;\r
429 \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
433                                  NULL, &regsize);\r
434     if (regresult == ERROR_SUCCESS)\r
435     {\r
436         char *name;\r
437         /* allocate enough memory for the OEM name text ... */\r
438         name = new char[regsize];\r
439         if (name)\r
440         {\r
441             /* ... and read it from the registry */\r
442             regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,\r
443                                          (LPBYTE)name, &regsize );\r
444             result = name;\r
445         }\r
446         delete[] name;\r
447     }\r
448     RegCloseKey(hKey);\r
449 \r
450     return result;\r
451 #endif\r
452         return "";\r
453 }\r
454 \r
455 bool SJoystickWin32Control::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)\r
456 {\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
462         {\r
463                 os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING);\r
464                 return false;\r
465         }\r
466 \r
467         for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)\r
468         {\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
477         }\r
478         return true;\r
479 #else\r
480         const u32 numberOfJoysticks = ::joyGetNumDevs();\r
481         JOYINFOEX info;\r
482         info.dwSize = sizeof(info);\r
483         info.dwFlags = JOY_RETURNALL;\r
484 \r
485         JoystickInfo activeJoystick;\r
486         SJoystickInfo returnInfo;\r
487 \r
488         joystickInfo.reallocate(numberOfJoysticks);\r
489         ActiveJoysticks.reallocate(numberOfJoysticks);\r
490 \r
491         u32 joystick = 0;\r
492         for(; joystick < numberOfJoysticks; ++joystick)\r
493         {\r
494                 if(JOYERR_NOERROR == joyGetPosEx(joystick, &info)\r
495                         &&\r
496                         JOYERR_NOERROR == joyGetDevCaps(joystick,\r
497                                                                                         &activeJoystick.Caps,\r
498                                                                                         sizeof(activeJoystick.Caps)))\r
499                 {\r
500                         activeJoystick.Index = joystick;\r
501                         ActiveJoysticks.push_back(activeJoystick);\r
502 \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
509 \r
510                         joystickInfo.push_back(returnInfo);\r
511                 }\r
512         }\r
513 \r
514         for(joystick = 0; joystick < joystickInfo.size(); ++joystick)\r
515         {\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
521         }\r
522 \r
523         return true;\r
524 #endif\r
525 #else\r
526         return false;\r
527 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_\r
528 }\r
529 } // end namespace irr\r
530 \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
534 {\r
535         switch ( lcid )\r
536         {\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
550                         return 0;\r
551                 case 1054:  // Thai\r
552                         return 874;\r
553                 case 1041:  // Japanese\r
554                         return 932;\r
555                 case 2052:  // Chinese (PRC)\r
556                 case 4100:  // Chinese (Singapore)\r
557                         return 936;\r
558                 case 1042:  // Korean\r
559                         return 949;\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
563                         return 950;\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
573                         return 1250;\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
586                         return 1251;\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
653                         return 1252;\r
654                 case 1032:  // Greek\r
655                         return 1253;\r
656                 case 1091:  // Uzbek (Latin)\r
657                 case 1068:  // Azeri (Latin)\r
658                 case 1055:  // Turkish\r
659                         return 1254;\r
660                 case 1037:  // Hebrew\r
661                         return 1255;\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
678                 case 1056:  // Urdu\r
679                 case 7169:  // Arabic (Tunisia)\r
680                         return 1256;\r
681                 case 1061:  // Estonian\r
682                 case 1062:  // Latvian\r
683                 case 1063:  // Lithuanian\r
684                         return 1257;\r
685                 case 1066:  // Vietnamese\r
686                         return 1258;\r
687         }\r
688         return 65001;   // utf-8\r
689 }\r
690 \r
691 namespace\r
692 {\r
693         struct SEnvMapper\r
694         {\r
695                 HWND hWnd;\r
696                 irr::CIrrDeviceWin32* irrDev;\r
697         };\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
700 \r
701         HKL KEYBOARD_INPUT_HKL=0;\r
702         unsigned int KEYBOARD_INPUT_CODEPAGE = 1252;\r
703 }\r
704 \r
705 irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)\r
706 {\r
707         const irr::u32 end = EnvMap.size();\r
708         for ( irr::u32 i=0; i < end; ++i )\r
709         {\r
710                 const SEnvMapper& env = EnvMap[i];\r
711                 if ( env.hWnd == hWnd )\r
712                         return env.irrDev;\r
713         }\r
714 \r
715         return 0;\r
716 }\r
717 \r
718 \r
719 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)\r
720 {\r
721         #ifndef WM_MOUSEWHEEL\r
722         #define WM_MOUSEWHEEL 0x020A\r
723         #endif\r
724         #ifndef WHEEL_DELTA\r
725         #define WHEEL_DELTA 120\r
726         #endif\r
727 \r
728         irr::CIrrDeviceWin32* dev = 0;\r
729         irr::SEvent event;\r
730 \r
731         static irr::s32 ClickCount=0;\r
732         if (GetCapture() != hWnd && ClickCount > 0)\r
733                 ClickCount = 0;\r
734 \r
735 \r
736         struct messageMap\r
737         {\r
738                 irr::s32 group;\r
739                 UINT winMessage;\r
740                 irr::s32 irrMessage;\r
741         };\r
742 \r
743         static messageMap mouseMap[] =\r
744         {\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
753                 {-1, 0, 0}\r
754         };\r
755 \r
756         // handle grouped events\r
757         messageMap * m = mouseMap;\r
758         while ( m->group >=0 && m->winMessage != message )\r
759                 m += 1;\r
760 \r
761         if ( m->group >= 0 )\r
762         {\r
763                 if ( m->group == 0 )    // down\r
764                 {\r
765                         ClickCount++;\r
766                         SetCapture(hWnd);\r
767                 }\r
768                 else\r
769                 if ( m->group == 1 )    // up\r
770                 {\r
771                         ClickCount--;\r
772                         if (ClickCount<1)\r
773                         {\r
774                                 ClickCount=0;\r
775                                 ReleaseCapture();\r
776                         }\r
777                 }\r
778 \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
795 #endif\r
796                 event.MouseInput.Wheel = 0.f;\r
797 \r
798                 // wheel\r
799                 if ( m->group == 3 )\r
800                 {\r
801                         POINT p; // fixed by jox\r
802                         p.x = 0; p.y = 0;\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
807                 }\r
808 \r
809                 dev = getDeviceFromHWnd(hWnd);\r
810                 if (dev)\r
811                 {\r
812                         dev->postEventFromUser(event);\r
813 \r
814                         if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN )\r
815                         {\r
816                                 irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event);\r
817                                 if ( clicks == 2 )\r
818                                 {\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
821                                 }\r
822                                 else if ( clicks == 3 )\r
823                                 {\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
826                                 }\r
827                         }\r
828                 }\r
829                 return 0;\r
830         }\r
831 \r
832         switch (message)\r
833         {\r
834         case WM_PAINT:\r
835                 {\r
836                         PAINTSTRUCT ps;\r
837                         BeginPaint(hWnd, &ps);\r
838                         EndPaint(hWnd, &ps);\r
839                 }\r
840                 return 0;\r
841 \r
842         case WM_ERASEBKGND:\r
843                 return 0;\r
844 \r
845         case WM_SYSKEYDOWN:\r
846         case WM_SYSKEYUP:\r
847         case WM_KEYDOWN:\r
848         case WM_KEYUP:\r
849                 {\r
850                         BYTE allKeys[256];\r
851 \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
855 \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
858                         {\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
861                         }\r
862                         if ( event.KeyInput.Key == irr::KEY_CONTROL )\r
863                         {\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
868                         }\r
869                         if ( event.KeyInput.Key == irr::KEY_MENU )\r
870                         {\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
874                         }\r
875 \r
876                         GetKeyboardState(allKeys);\r
877 \r
878                         event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0);\r
879                         event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0);\r
880 \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
883                         WORD keyChars[2];\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
887                         {\r
888                                 WORD unicodeChar;\r
889                                 MultiByteToWideChar(\r
890                                                 KEYBOARD_INPUT_CODEPAGE,\r
891                                                 MB_PRECOMPOSED, // default\r
892                                                 (LPCSTR)keyChars,\r
893                                                 sizeof(keyChars),\r
894                                                 (WCHAR*)&unicodeChar,\r
895                                                 1 );\r
896                                 event.KeyInput.Char = unicodeChar;\r
897                         }\r
898                         else\r
899                                 event.KeyInput.Char = 0;\r
900 \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
904 \r
905                         dev = getDeviceFromHWnd(hWnd);\r
906                         if (dev)\r
907                                 dev->postEventFromUser(event);\r
908 \r
909                         if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)\r
910                                 return DefWindowProc(hWnd, message, wParam, lParam);\r
911                         else\r
912                                 return 0;\r
913                 }\r
914 \r
915         case WM_SIZE:\r
916                 {\r
917                         // resize\r
918                         dev = getDeviceFromHWnd(hWnd);\r
919                         if (dev)\r
920                                 dev->OnResized();\r
921                 }\r
922                 return 0;\r
923 \r
924         case WM_DESTROY:\r
925                 PostQuitMessage(0);\r
926                 return 0;\r
927 \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
933                         )\r
934                         return 0;\r
935 \r
936                 break;\r
937 \r
938         case WM_USER:\r
939                 event.EventType = irr::EET_USER_EVENT;\r
940                 event.UserEvent.UserData1 = static_cast<size_t>(wParam);\r
941                 event.UserEvent.UserData2 = static_cast<size_t>(lParam);\r
942                 dev = getDeviceFromHWnd(hWnd);\r
943 \r
944                 if (dev)\r
945                         dev->postEventFromUser(event);\r
946 \r
947                 return 0;\r
948 \r
949         case WM_SETCURSOR:\r
950                 // because Windows forgot about that in the meantime\r
951                 dev = getDeviceFromHWnd(hWnd);\r
952                 if (dev)\r
953                 {\r
954                         dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );\r
955                         dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );\r
956                 }\r
957                 break;\r
958 \r
959         case WM_INPUTLANGCHANGE:\r
960                 // get the new codepage used for keyboard input\r
961                 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);\r
962                 KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );\r
963                 return 0;\r
964         }\r
965         return DefWindowProc(hWnd, message, wParam, lParam);\r
966 }\r
967 \r
968 \r
969 namespace irr\r
970 {\r
971 \r
972 //! constructor\r
973 CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)\r
974 : CIrrDeviceStub(params), HWnd(0), Resized(false),\r
975         ExternalWindow(false), Win32CursorControl(0), JoyControl(0)\r
976 {\r
977         #ifdef _DEBUG\r
978         setDebugName("CIrrDeviceWin32");\r
979         #endif\r
980 \r
981         // get windows version and create OS operator\r
982         core::stringc winversion;\r
983         getWindowsVersion(winversion);\r
984         Operator = new COSOperator(winversion);\r
985         os::Printer::log(winversion.c_str(), ELL_INFORMATION);\r
986 \r
987         // get handle to exe file\r
988         HINSTANCE hInstance = GetModuleHandle(0);\r
989 \r
990         // create the window if we need to and we do not use the null device\r
991         if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)\r
992         {\r
993                 const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");\r
994 \r
995                 // Register Class\r
996                 WNDCLASSEX wcex;\r
997                 wcex.cbSize                     = sizeof(WNDCLASSEX);\r
998                 wcex.style                      = CS_HREDRAW | CS_VREDRAW;\r
999                 wcex.lpfnWndProc        = WndProc;\r
1000                 wcex.cbClsExtra         = 0;\r
1001                 wcex.cbWndExtra         = 0;\r
1002                 wcex.hInstance          = hInstance;\r
1003                 wcex.hIcon                      = NULL;\r
1004                 wcex.hCursor            = 0; // LoadCursor(NULL, IDC_ARROW);\r
1005                 wcex.hbrBackground      = (HBRUSH)(COLOR_WINDOW+1);\r
1006                 wcex.lpszMenuName       = 0;\r
1007                 wcex.lpszClassName      = ClassName;\r
1008                 wcex.hIconSm            = 0;\r
1009 \r
1010                 // if there is an icon, load it\r
1011                 wcex.hIcon = (HICON)LoadImage(hInstance, __TEXT("irrlicht.ico"), IMAGE_ICON, 0,0, LR_LOADFROMFILE | LR_DEFAULTSIZE);\r
1012 \r
1013                 RegisterClassEx(&wcex);\r
1014 \r
1015                 // calculate client size\r
1016 \r
1017                 RECT clientSize;\r
1018                 clientSize.top = 0;\r
1019                 clientSize.left = 0;\r
1020                 clientSize.right = CreationParams.WindowSize.Width;\r
1021                 clientSize.bottom = CreationParams.WindowSize.Height;\r
1022 \r
1023                 DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable);\r
1024                 AdjustWindowRect(&clientSize, style, FALSE);\r
1025 \r
1026                 const s32 realWidth = clientSize.right - clientSize.left;\r
1027                 const s32 realHeight = clientSize.bottom - clientSize.top;\r
1028 \r
1029                 s32 windowLeft = (CreationParams.WindowPosition.X == -1 ?\r
1030                                      (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 :\r
1031                                      CreationParams.WindowPosition.X);\r
1032                 s32 windowTop = (CreationParams.WindowPosition.Y == -1 ?\r
1033                                      (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 :\r
1034                                      CreationParams.WindowPosition.Y);\r
1035 \r
1036                 if ( windowLeft < 0 )\r
1037                         windowLeft = 0;\r
1038                 if ( windowTop < 0 )\r
1039                         windowTop = 0;  // make sure window menus are in screen on creation\r
1040 \r
1041                 if (CreationParams.Fullscreen)\r
1042                 {\r
1043                         windowLeft = 0;\r
1044                         windowTop = 0;\r
1045                 }\r
1046 \r
1047                 // create window\r
1048                 HWnd = CreateWindow( ClassName, __TEXT(""), style, windowLeft, windowTop,\r
1049                                         realWidth, realHeight, NULL, NULL, hInstance, NULL);\r
1050                 if (!HWnd)\r
1051                 {\r
1052                         os::Printer::log("Window could not be created.", ELL_ERROR);\r
1053                 }\r
1054 \r
1055                 CreationParams.WindowId = HWnd;\r
1056 //              CreationParams.WindowSize.Width = realWidth;\r
1057 //              CreationParams.WindowSize.Height = realHeight;\r
1058 \r
1059                 ShowWindow(HWnd, SW_SHOWNORMAL);\r
1060                 UpdateWindow(HWnd);\r
1061 \r
1062                 // fix ugly ATI driver bugs. Thanks to ariaci\r
1063                 MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);\r
1064 \r
1065                 // make sure everything gets updated to the real sizes\r
1066                 Resized = true;\r
1067         }\r
1068         else if (CreationParams.WindowId)\r
1069         {\r
1070                 // attach external window\r
1071                 HWnd = static_cast<HWND>(CreationParams.WindowId);\r
1072                 RECT r;\r
1073                 GetWindowRect(HWnd, &r);\r
1074                 CreationParams.WindowSize.Width = r.right - r.left;\r
1075                 CreationParams.WindowSize.Height = r.bottom - r.top;\r
1076                 CreationParams.Fullscreen = false;\r
1077                 ExternalWindow = true;\r
1078         }\r
1079 \r
1080         // create cursor control\r
1081 \r
1082         Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);\r
1083         CursorControl = Win32CursorControl;\r
1084         JoyControl = new SJoystickWin32Control(this);\r
1085 \r
1086         // initialize doubleclicks with system values\r
1087         MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();\r
1088 \r
1089         // create driver\r
1090 \r
1091         createDriver();\r
1092 \r
1093         if (VideoDriver)\r
1094                 createGUIAndScene();\r
1095 \r
1096         // register environment\r
1097 \r
1098         SEnvMapper em;\r
1099         em.irrDev = this;\r
1100         em.hWnd = HWnd;\r
1101         EnvMap.push_back(em);\r
1102 \r
1103         // set this as active window\r
1104         if (!ExternalWindow)\r
1105         {\r
1106                 SetActiveWindow(HWnd);\r
1107                 SetForegroundWindow(HWnd);\r
1108         }\r
1109 \r
1110         // get the codepage used for keyboard input\r
1111         KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);\r
1112         KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) );\r
1113 \r
1114         // inform driver about the window size etc.\r
1115         resizeIfNecessary();\r
1116 }\r
1117 \r
1118 \r
1119 //! destructor\r
1120 CIrrDeviceWin32::~CIrrDeviceWin32()\r
1121 {\r
1122         delete JoyControl;\r
1123 \r
1124         // unregister environment\r
1125         for (u32 i=0; i< EnvMap.size(); ++i)\r
1126         {\r
1127                 if (EnvMap[i].hWnd == HWnd)\r
1128                 {\r
1129                         EnvMap.erase(i);\r
1130                         break;\r
1131                 }\r
1132         }\r
1133 }\r
1134 \r
1135 \r
1136 //! create the driver\r
1137 void CIrrDeviceWin32::createDriver()\r
1138 {\r
1139         switch(CreationParams.DriverType)\r
1140         {\r
1141         case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:\r
1142                 os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR);\r
1143                 break;\r
1144         case video::EDT_DIRECT3D9:\r
1145 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_\r
1146                 VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);\r
1147 \r
1148                 if (!VideoDriver)\r
1149                         os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);\r
1150 #else\r
1151                 os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);\r
1152 #endif\r
1153                 break;\r
1154         case video::EDT_OPENGL:\r
1155 #ifdef _IRR_COMPILE_WITH_OPENGL_\r
1156                 switchToFullScreen();\r
1157 \r
1158                 ContextManager = new video::CWGLManager();\r
1159                 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));\r
1160 \r
1161                 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);\r
1162 \r
1163                 if (!VideoDriver)\r
1164                         os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);\r
1165 #else\r
1166                 os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);\r
1167 #endif\r
1168                 break;\r
1169         case video::EDT_OGLES1:\r
1170 #ifdef _IRR_COMPILE_WITH_OGLES1_\r
1171                 switchToFullScreen();\r
1172 \r
1173                 ContextManager = new video::CEGLManager();\r
1174                 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));\r
1175 \r
1176                 VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);\r
1177 \r
1178                 if (!VideoDriver)\r
1179                         os::Printer::log("Could not create OpenGL-ES1 driver.", ELL_ERROR);\r
1180 #else\r
1181                 os::Printer::log("OpenGL-ES1 driver was not compiled in.", ELL_ERROR);\r
1182 #endif\r
1183                 break;\r
1184         case video::EDT_OGLES2:\r
1185 #ifdef _IRR_COMPILE_WITH_OGLES2_\r
1186                 switchToFullScreen();\r
1187 \r
1188                 ContextManager = new video::CEGLManager();\r
1189                 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));\r
1190 \r
1191                 VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);\r
1192 \r
1193                 if (!VideoDriver)\r
1194                         os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR);\r
1195 #else\r
1196                 os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR);\r
1197 #endif\r
1198                 break;\r
1199         case video::EDT_WEBGL1:\r
1200                 os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR);\r
1201                 break;\r
1202         case video::EDT_SOFTWARE:\r
1203 #ifdef _IRR_COMPILE_WITH_SOFTWARE_\r
1204                 switchToFullScreen();\r
1205 \r
1206                 VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);\r
1207 #else\r
1208                 os::Printer::log("Software driver was not compiled in.", ELL_ERROR);\r
1209 #endif\r
1210                 break;\r
1211         case video::EDT_BURNINGSVIDEO:\r
1212 #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
1213                 switchToFullScreen();\r
1214 \r
1215                 VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);\r
1216 #else\r
1217                 os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR);\r
1218 #endif\r
1219                 break;\r
1220         case video::EDT_NULL:\r
1221                 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);\r
1222                 break;\r
1223         default:\r
1224                 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);\r
1225                 break;\r
1226         }\r
1227 }\r
1228 \r
1229 \r
1230 //! runs the device. Returns false if device wants to be deleted\r
1231 bool CIrrDeviceWin32::run()\r
1232 {\r
1233         os::Timer::tick();\r
1234 \r
1235         static_cast<CCursorControl*>(CursorControl)->update();\r
1236 \r
1237         handleSystemMessages();\r
1238 \r
1239         if (!Close)\r
1240                 resizeIfNecessary();\r
1241 \r
1242         if(!Close && JoyControl)\r
1243                 JoyControl->pollJoysticks();\r
1244 \r
1245         return !Close;\r
1246 }\r
1247 \r
1248 \r
1249 //! Pause the current process for the minimum time allowed only to allow other processes to execute\r
1250 void CIrrDeviceWin32::yield()\r
1251 {\r
1252         Sleep(1);\r
1253 }\r
1254 \r
1255 //! Pause execution and let other processes to run for a specified amount of time.\r
1256 void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer)\r
1257 {\r
1258         const bool wasStopped = Timer ? Timer->isStopped() : true;\r
1259         if (pauseTimer && !wasStopped)\r
1260                 Timer->stop();\r
1261 \r
1262         Sleep(timeMs);\r
1263 \r
1264         if (pauseTimer && !wasStopped)\r
1265                 Timer->start();\r
1266 }\r
1267 \r
1268 \r
1269 void CIrrDeviceWin32::resizeIfNecessary()\r
1270 {\r
1271         if (!Resized || !getVideoDriver())\r
1272                 return;\r
1273 \r
1274         RECT r;\r
1275         GetClientRect(HWnd, &r);\r
1276 \r
1277         char tmp[255];\r
1278 \r
1279         if (r.right < 2 || r.bottom < 2)\r
1280         {\r
1281                 sprintf(tmp, "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);\r
1282                 os::Printer::log(tmp);\r
1283         }\r
1284         else\r
1285         {\r
1286                 sprintf(tmp, "Resizing window (%ld %ld)", r.right, r.bottom);\r
1287                 os::Printer::log(tmp);\r
1288 \r
1289                 getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom));\r
1290                 getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize());\r
1291         }\r
1292 \r
1293         Resized = false;\r
1294 }\r
1295 \r
1296 \r
1297 DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const\r
1298 {\r
1299         if ( fullscreen )\r
1300                 return WS_POPUP;\r
1301 \r
1302         if ( resizable )\r
1303                 return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;\r
1304 \r
1305         return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;\r
1306 }\r
1307 \r
1308 //! sets the caption of the window\r
1309 void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)\r
1310 {\r
1311         // We use SendMessage instead of SetText to ensure proper\r
1312         // function even in cases where the HWND was created in a different thread\r
1313         DWORD_PTR dwResult;\r
1314         SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,\r
1315                         reinterpret_cast<LPARAM>(text),\r
1316                         SMTO_ABORTIFHUNG, 2000, &dwResult);\r
1317 }\r
1318 \r
1319 \r
1320 //! presents a surface in the client area\r
1321 bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rect<s32>* src)\r
1322 {\r
1323         HWND hwnd = HWnd;\r
1324         if ( windowId )\r
1325                 hwnd = reinterpret_cast<HWND>(windowId);\r
1326 \r
1327         HDC dc = GetDC(hwnd);\r
1328 \r
1329         if ( dc )\r
1330         {\r
1331                 RECT rect;\r
1332                 GetClientRect(hwnd, &rect);\r
1333                 const void* memory = (const void *)image->getData();\r
1334 \r
1335                 BITMAPV4HEADER bi;\r
1336                 ZeroMemory (&bi, sizeof(bi));\r
1337                 bi.bV4Size = sizeof(BITMAPINFOHEADER);\r
1338                 bi.bV4BitCount = (WORD)image->getBitsPerPixel();\r
1339                 bi.bV4Planes = 1;\r
1340                 bi.bV4Width = image->getDimension().Width;\r
1341                 bi.bV4Height = -((s32)image->getDimension().Height);\r
1342                 bi.bV4V4Compression = BI_BITFIELDS;\r
1343                 bi.bV4AlphaMask = image->getAlphaMask();\r
1344                 bi.bV4RedMask = image->getRedMask();\r
1345                 bi.bV4GreenMask = image->getGreenMask();\r
1346                 bi.bV4BlueMask = image->getBlueMask();\r
1347 \r
1348                 if ( src )\r
1349                 {\r
1350                         StretchDIBits(dc, 0,0, rect.right, rect.bottom,\r
1351                                         src->UpperLeftCorner.X, src->UpperLeftCorner.Y,\r
1352                                         src->getWidth(), src->getHeight(),\r
1353                                         memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);\r
1354                 }\r
1355                 else\r
1356                 {\r
1357                         StretchDIBits(dc, 0,0, rect.right, rect.bottom,\r
1358                                         0, 0, image->getDimension().Width, image->getDimension().Height,\r
1359                                         memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY);\r
1360                 }\r
1361 \r
1362                 ReleaseDC(hwnd, dc);\r
1363         }\r
1364         return true;\r
1365 }\r
1366 \r
1367 \r
1368 //! notifies the device that it should close itself\r
1369 void CIrrDeviceWin32::closeDevice()\r
1370 {\r
1371         if (!ExternalWindow)\r
1372         {\r
1373                 MSG msg;\r
1374                 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);\r
1375                 PostQuitMessage(0);\r
1376                 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);\r
1377                 DestroyWindow(HWnd);\r
1378                 const fschar_t* ClassName = __TEXT("CIrrDeviceWin32");\r
1379                 HINSTANCE hInstance = GetModuleHandle(0);\r
1380                 UnregisterClass(ClassName, hInstance);\r
1381         }\r
1382         Close=true;\r
1383 }\r
1384 \r
1385 \r
1386 //! returns if window is active. if not, nothing needs to be drawn\r
1387 bool CIrrDeviceWin32::isWindowActive() const\r
1388 {\r
1389         return (GetActiveWindow() == HWnd);\r
1390 }\r
1391 \r
1392 \r
1393 //! returns if window has focus\r
1394 bool CIrrDeviceWin32::isWindowFocused() const\r
1395 {\r
1396         bool ret = (GetFocus() == HWnd);\r
1397         return ret;\r
1398 }\r
1399 \r
1400 \r
1401 //! returns if window is minimized\r
1402 bool CIrrDeviceWin32::isWindowMinimized() const\r
1403 {\r
1404         WINDOWPLACEMENT plc;\r
1405         plc.length=sizeof(WINDOWPLACEMENT);\r
1406         bool ret=false;\r
1407         if (GetWindowPlacement(HWnd,&plc))\r
1408                 ret = plc.showCmd == SW_SHOWMINIMIZED;\r
1409         return ret;\r
1410 }\r
1411 \r
1412 \r
1413 //! switches to fullscreen\r
1414 bool CIrrDeviceWin32::switchToFullScreen()\r
1415 {\r
1416         if (!CreationParams.Fullscreen)\r
1417                 return true;\r
1418 \r
1419         // No border, title bar, etc. is already set up through getWindowStyle()\r
1420         // We only set the window size to match the monitor.\r
1421 \r
1422         MONITORINFO mi;\r
1423         mi.cbSize = sizeof(mi);\r
1424         if (GetMonitorInfo(MonitorFromWindow(HWnd,MONITOR_DEFAULTTOPRIMARY),&mi))\r
1425         {\r
1426                 UINT flags = SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_FRAMECHANGED;\r
1427                 SetWindowPos(HWnd, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,\r
1428                         mi.rcMonitor.right - mi.rcMonitor.left,\r
1429                         mi.rcMonitor.bottom - mi.rcMonitor.top, flags);\r
1430         }\r
1431         else\r
1432         {\r
1433                 CreationParams.Fullscreen = false;\r
1434         }\r
1435 \r
1436         return CreationParams.Fullscreen;\r
1437 }\r
1438 \r
1439 \r
1440 //! returns the win32 cursor control\r
1441 CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()\r
1442 {\r
1443         return Win32CursorControl;\r
1444 }\r
1445 \r
1446 \r
1447 typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD);\r
1448 // Needed for old windows apis\r
1449 // depending on the SDK version and compilers some defines might be available\r
1450 // or not\r
1451 #ifndef PRODUCT_ULTIMATE\r
1452 #define PRODUCT_ULTIMATE        0x00000001\r
1453 #define PRODUCT_HOME_BASIC      0x00000002\r
1454 #define PRODUCT_HOME_PREMIUM    0x00000003\r
1455 #define PRODUCT_ENTERPRISE      0x00000004\r
1456 #define PRODUCT_HOME_BASIC_N    0x00000005\r
1457 #define PRODUCT_BUSINESS        0x00000006\r
1458 #define PRODUCT_STARTER         0x0000000B\r
1459 #endif\r
1460 #ifndef PRODUCT_ULTIMATE_N\r
1461 #define PRODUCT_BUSINESS_N      0x00000010\r
1462 #define PRODUCT_HOME_PREMIUM_N  0x0000001A\r
1463 #define PRODUCT_ENTERPRISE_N    0x0000001B\r
1464 #define PRODUCT_ULTIMATE_N      0x0000001C\r
1465 #endif\r
1466 #ifndef PRODUCT_STARTER_N\r
1467 #define PRODUCT_STARTER_N       0x0000002F\r
1468 #endif\r
1469 #ifndef PRODUCT_PROFESSIONAL\r
1470 #define PRODUCT_PROFESSIONAL    0x00000030\r
1471 #define PRODUCT_PROFESSIONAL_N  0x00000031\r
1472 #endif\r
1473 #ifndef PRODUCT_ULTIMATE_E\r
1474 #define PRODUCT_STARTER_E       0x00000042\r
1475 #define PRODUCT_HOME_BASIC_E    0x00000043\r
1476 #define PRODUCT_HOME_PREMIUM_E  0x00000044\r
1477 #define PRODUCT_PROFESSIONAL_E  0x00000045\r
1478 #define PRODUCT_ENTERPRISE_E    0x00000046\r
1479 #define PRODUCT_ULTIMATE_E      0x00000047\r
1480 #endif\r
1481 \r
1482 void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)\r
1483 {\r
1484         OSVERSIONINFOEX osvi;\r
1485         PGPI pGPI;\r
1486         BOOL bOsVersionInfoEx;\r
1487 \r
1488         ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));\r
1489         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
1490 \r
1491         bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi);\r
1492         if (!bOsVersionInfoEx)\r
1493         {\r
1494                 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);\r
1495                 if (! GetVersionEx((OSVERSIONINFO *) &osvi))\r
1496                         return;\r
1497         }\r
1498 \r
1499         switch (osvi.dwPlatformId)\r
1500         {\r
1501         case VER_PLATFORM_WIN32_NT:\r
1502                 if (osvi.dwMajorVersion <= 4)\r
1503                         out.append("Microsoft Windows NT ");\r
1504                 else\r
1505                 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0)\r
1506                         out.append("Microsoft Windows 2000 ");\r
1507                 else\r
1508                 if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)\r
1509                         out.append("Microsoft Windows XP ");\r
1510                 else\r
1511                 if (osvi.dwMajorVersion == 6 )\r
1512                 {\r
1513                         if (osvi.dwMinorVersion == 0)\r
1514                         {\r
1515                                 if (osvi.wProductType == VER_NT_WORKSTATION)\r
1516                                         out.append("Microsoft Windows Vista ");\r
1517                                 else\r
1518                                         out.append("Microsoft Windows Server 2008 ");\r
1519                         }\r
1520                         else if (osvi.dwMinorVersion == 1)\r
1521                         {\r
1522                                 if (osvi.wProductType == VER_NT_WORKSTATION)\r
1523                                         out.append("Microsoft Windows 7 ");\r
1524                                 else\r
1525                                         out.append("Microsoft Windows Server 2008 R2 ");\r
1526                         }\r
1527                         else if (osvi.dwMinorVersion == 2)\r
1528                         {\r
1529                                 out.append("Microsoft Windows 8 or later ");\r
1530                         }\r
1531                 }\r
1532 \r
1533                 if (bOsVersionInfoEx)\r
1534                 {\r
1535                         if (osvi.dwMajorVersion == 6)\r
1536                         {\r
1537                                 DWORD dwType;\r
1538                                 pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo");\r
1539                                 pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType);\r
1540 \r
1541                                 switch (dwType)\r
1542                                 {\r
1543                                 case PRODUCT_ULTIMATE:\r
1544                                 case PRODUCT_ULTIMATE_E:\r
1545                                 case PRODUCT_ULTIMATE_N:\r
1546                                         out.append("Ultimate Edition ");\r
1547                                         break;\r
1548                                 case PRODUCT_PROFESSIONAL:\r
1549                                 case PRODUCT_PROFESSIONAL_E:\r
1550                                 case PRODUCT_PROFESSIONAL_N:\r
1551                                         out.append("Professional Edition ");\r
1552                                         break;\r
1553                                 case PRODUCT_HOME_BASIC:\r
1554                                 case PRODUCT_HOME_BASIC_E:\r
1555                                 case PRODUCT_HOME_BASIC_N:\r
1556                                         out.append("Home Basic Edition ");\r
1557                                         break;\r
1558                                 case PRODUCT_HOME_PREMIUM:\r
1559                                 case PRODUCT_HOME_PREMIUM_E:\r
1560                                 case PRODUCT_HOME_PREMIUM_N:\r
1561                                         out.append("Home Premium Edition ");\r
1562                                         break;\r
1563                                 case PRODUCT_ENTERPRISE:\r
1564                                 case PRODUCT_ENTERPRISE_E:\r
1565                                 case PRODUCT_ENTERPRISE_N:\r
1566                                         out.append("Enterprise Edition ");\r
1567                                         break;\r
1568                                 case PRODUCT_BUSINESS:\r
1569                                 case PRODUCT_BUSINESS_N:\r
1570                                         out.append("Business Edition ");\r
1571                                         break;\r
1572                                 case PRODUCT_STARTER:\r
1573                                 case PRODUCT_STARTER_E:\r
1574                                 case PRODUCT_STARTER_N:\r
1575                                         out.append("Starter Edition ");\r
1576                                         break;\r
1577                                 }\r
1578                         }\r
1579 #ifdef VER_SUITE_ENTERPRISE\r
1580                         else\r
1581                         if (osvi.wProductType == VER_NT_WORKSTATION)\r
1582                         {\r
1583 #ifndef __BORLANDC__\r
1584                                 if( osvi.wSuiteMask & VER_SUITE_PERSONAL )\r
1585                                         out.append("Personal ");\r
1586                                 else\r
1587                                         out.append("Professional ");\r
1588 #endif\r
1589                         }\r
1590                         else if (osvi.wProductType == VER_NT_SERVER)\r
1591                         {\r
1592                                 if( osvi.wSuiteMask & VER_SUITE_DATACENTER )\r
1593                                         out.append("DataCenter Server ");\r
1594                                 else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE )\r
1595                                         out.append("Advanced Server ");\r
1596                                 else\r
1597                                         out.append("Server ");\r
1598                         }\r
1599 #endif\r
1600                 }\r
1601                 else\r
1602                 {\r
1603                         HKEY hKey;\r
1604                         char szProductType[80];\r
1605                         DWORD dwBufLen;\r
1606 \r
1607                         RegOpenKeyEx( HKEY_LOCAL_MACHINE,\r
1608                                         __TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"),\r
1609                                         0, KEY_QUERY_VALUE, &hKey );\r
1610                         RegQueryValueEx( hKey, __TEXT("ProductType"), NULL, NULL,\r
1611                                         (LPBYTE) szProductType, &dwBufLen);\r
1612                         RegCloseKey( hKey );\r
1613 \r
1614                         \r
1615                         if (irr::core::stringc("WINNT").equals_ignore_case(szProductType))\r
1616                                 out.append("Professional ");\r
1617                         if (irr::core::stringc("LANMANNT").equals_ignore_case(szProductType))\r
1618                                 out.append("Server ");\r
1619                         if (irr::core::stringc("SERVERNT").equals_ignore_case(szProductType))\r
1620                                 out.append("Advanced Server ");\r
1621                 }\r
1622 \r
1623                 // Display version, service pack (if any), and build number.\r
1624 \r
1625                 char tmp[255];\r
1626 \r
1627                 if (osvi.dwMajorVersion <= 4 )\r
1628                 {\r
1629                         sprintf(tmp, "version %lu.%lu %s (Build %lu)",\r
1630                                         osvi.dwMajorVersion,\r
1631                                         osvi.dwMinorVersion,\r
1632                                         irr::core::stringc(osvi.szCSDVersion).c_str(),\r
1633                                         osvi.dwBuildNumber & 0xFFFF);\r
1634                 }\r
1635                 else\r
1636                 {\r
1637                         sprintf(tmp, "%s (Build %lu)", irr::core::stringc(osvi.szCSDVersion).c_str(),\r
1638                         osvi.dwBuildNumber & 0xFFFF);\r
1639                 }\r
1640 \r
1641                 out.append(tmp);\r
1642                 break;\r
1643 \r
1644         case VER_PLATFORM_WIN32_WINDOWS:\r
1645 \r
1646                 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0)\r
1647                 {\r
1648                         out.append("Microsoft Windows 95 ");\r
1649                         if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' )\r
1650                                 out.append("OSR2 " );\r
1651                 }\r
1652 \r
1653                 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)\r
1654                 {\r
1655                         out.append("Microsoft Windows 98 ");\r
1656                         if ( osvi.szCSDVersion[1] == 'A' )\r
1657                                 out.append( "SE " );\r
1658                 }\r
1659 \r
1660                 if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)\r
1661                         out.append("Microsoft Windows Me ");\r
1662 \r
1663                 break;\r
1664 \r
1665         case VER_PLATFORM_WIN32s:\r
1666                 out.append("Microsoft Win32s ");\r
1667                 break;\r
1668         }\r
1669 }\r
1670 \r
1671 //! Notifies the device, that it has been resized\r
1672 void CIrrDeviceWin32::OnResized()\r
1673 {\r
1674         Resized = true;\r
1675 }\r
1676 \r
1677 //! Resize the render window.\r
1678 void CIrrDeviceWin32::setWindowSize(const irr::core::dimension2d<u32>& size)\r
1679 {\r
1680         if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)\r
1681                 return;\r
1682 \r
1683         // get size of the window for the give size of the client area\r
1684         DWORD style = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_STYLE));\r
1685         DWORD exStyle = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_EXSTYLE));\r
1686         RECT clientSize;\r
1687         clientSize.top = 0;\r
1688         clientSize.left = 0;\r
1689         clientSize.right = size.Width;\r
1690         clientSize.bottom = size.Height;\r
1691         AdjustWindowRectEx(&clientSize, style, false, exStyle);\r
1692         const s32 realWidth = clientSize.right - clientSize.left;\r
1693         const s32 realHeight = clientSize.bottom - clientSize.top;\r
1694 \r
1695         UINT flags = SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;\r
1696         SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags);\r
1697 }\r
1698 \r
1699 //! Sets if the window should be resizable in windowed mode.\r
1700 void CIrrDeviceWin32::setResizable(bool resize)\r
1701 {\r
1702         if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)\r
1703                 return;\r
1704 \r
1705         LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize);\r
1706         if (!SetWindowLongPtr(HWnd, GWL_STYLE, style))\r
1707                 os::Printer::log("Could not change window style.");\r
1708 \r
1709         RECT clientSize;\r
1710         clientSize.top = 0;\r
1711         clientSize.left = 0;\r
1712         clientSize.right = getVideoDriver()->getScreenSize().Width;\r
1713         clientSize.bottom = getVideoDriver()->getScreenSize().Height;\r
1714 \r
1715         AdjustWindowRect(&clientSize, static_cast<DWORD>(style), FALSE);\r
1716 \r
1717         const s32 realWidth = clientSize.right - clientSize.left;\r
1718         const s32 realHeight = clientSize.bottom - clientSize.top;\r
1719 \r
1720         const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;\r
1721         const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;\r
1722 \r
1723         SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,\r
1724                 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);\r
1725 \r
1726         static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize);\r
1727 }\r
1728 \r
1729 \r
1730 //! Minimizes the window.\r
1731 void CIrrDeviceWin32::minimizeWindow()\r
1732 {\r
1733         WINDOWPLACEMENT wndpl;\r
1734         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1735         GetWindowPlacement(HWnd, &wndpl);\r
1736         wndpl.showCmd = SW_SHOWMINNOACTIVE;\r
1737         SetWindowPlacement(HWnd, &wndpl);\r
1738 }\r
1739 \r
1740 \r
1741 //! Maximizes the window.\r
1742 void CIrrDeviceWin32::maximizeWindow()\r
1743 {\r
1744         WINDOWPLACEMENT wndpl;\r
1745         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1746         GetWindowPlacement(HWnd, &wndpl);\r
1747         wndpl.showCmd = SW_SHOWMAXIMIZED;\r
1748         SetWindowPlacement(HWnd, &wndpl);\r
1749 }\r
1750 \r
1751 \r
1752 //! Restores the window to its original size.\r
1753 void CIrrDeviceWin32::restoreWindow()\r
1754 {\r
1755         WINDOWPLACEMENT wndpl;\r
1756         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1757         GetWindowPlacement(HWnd, &wndpl);\r
1758         wndpl.showCmd = SW_SHOWNORMAL;\r
1759         SetWindowPlacement(HWnd, &wndpl);\r
1760 }\r
1761 \r
1762 core::position2di CIrrDeviceWin32::getWindowPosition()\r
1763 {\r
1764         WINDOWPLACEMENT wndpl;\r
1765         wndpl.length = sizeof(WINDOWPLACEMENT);\r
1766         if (GetWindowPlacement(HWnd, &wndpl))\r
1767         {\r
1768                 return core::position2di((int)wndpl.rcNormalPosition.left,\r
1769                                          (int)wndpl.rcNormalPosition.top);\r
1770         }\r
1771         else\r
1772         {\r
1773                 // No reason for this to happen\r
1774                 os::Printer::log("Failed to retrieve window location", ELL_ERROR);\r
1775                 return core::position2di(-1, -1);\r
1776         }\r
1777 }\r
1778 \r
1779 bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)\r
1780 {\r
1781         if (JoyControl)\r
1782                 return JoyControl->activateJoysticks(joystickInfo);\r
1783         else\r
1784                 return false;\r
1785 }\r
1786 \r
1787 \r
1788 //! Set the current Gamma Value for the Display\r
1789 bool CIrrDeviceWin32::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )\r
1790 {\r
1791         bool r;\r
1792         u16 ramp[3][256];\r
1793 \r
1794         calculateGammaRamp( ramp[0], red, brightness, contrast );\r
1795         calculateGammaRamp( ramp[1], green, brightness, contrast );\r
1796         calculateGammaRamp( ramp[2], blue, brightness, contrast );\r
1797 \r
1798         HDC dc = GetDC(0);\r
1799         r = SetDeviceGammaRamp ( dc, ramp ) == TRUE;\r
1800         ReleaseDC(HWnd, dc);\r
1801         return r;\r
1802 }\r
1803 \r
1804 //! Get the current Gamma Value for the Display\r
1805 bool CIrrDeviceWin32::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )\r
1806 {\r
1807         bool r;\r
1808         u16 ramp[3][256];\r
1809 \r
1810         HDC dc = GetDC(0);\r
1811         r = GetDeviceGammaRamp ( dc, ramp ) == TRUE;\r
1812         ReleaseDC(HWnd, dc);\r
1813 \r
1814         if (r)\r
1815         {\r
1816                 calculateGammaFromRamp(red, ramp[0]);\r
1817                 calculateGammaFromRamp(green, ramp[1]);\r
1818                 calculateGammaFromRamp(blue, ramp[2]);\r
1819         }\r
1820 \r
1821         brightness = 0.f;\r
1822         contrast = 0.f;\r
1823 \r
1824         return r;\r
1825 }\r
1826 \r
1827 \r
1828 //! Process system events\r
1829 void CIrrDeviceWin32::handleSystemMessages()\r
1830 {\r
1831         MSG msg;\r
1832 \r
1833         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))\r
1834         {\r
1835                 if (ExternalWindow && msg.hwnd == HWnd)\r
1836                 {\r
1837                         if (msg.hwnd == HWnd)\r
1838             {\r
1839                                 WndProc(HWnd, msg.message, msg.wParam, msg.lParam);\r
1840             }\r
1841             else\r
1842             {\r
1843                 TranslateMessage(&msg);\r
1844                 DispatchMessage(&msg);\r
1845             }\r
1846                 }\r
1847                 else\r
1848                 {\r
1849                         // No message translation because we don't use WM_CHAR and it would conflict with our\r
1850                         // deadkey handling.\r
1851                         DispatchMessage(&msg);\r
1852                 }\r
1853 \r
1854                 if (msg.message == WM_QUIT)\r
1855                         Close = true;\r
1856         }\r
1857 }\r
1858 \r
1859 \r
1860 //! Remove all messages pending in the system message loop\r
1861 void CIrrDeviceWin32::clearSystemMessages()\r
1862 {\r
1863         MSG msg;\r
1864         while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))\r
1865         {}\r
1866         while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))\r
1867         {}\r
1868 }\r
1869 \r
1870 // shows last error in a messagebox to help internal debugging.\r
1871 void CIrrDeviceWin32::ReportLastWinApiError()\r
1872 {\r
1873         // (based on code from ovidiucucu from http://www.codeguru.com/forum/showthread.php?t=318721)\r
1874         LPCTSTR pszCaption = __TEXT("Windows SDK Error Report");\r
1875         DWORD dwError = GetLastError();\r
1876 \r
1877         if(NOERROR == dwError)\r
1878         {\r
1879                 MessageBox(NULL, __TEXT("No error"), pszCaption, MB_OK);\r
1880         }\r
1881         else\r
1882         {\r
1883                 const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER |\r
1884                                                                                 FORMAT_MESSAGE_IGNORE_INSERTS |\r
1885                                                                                 FORMAT_MESSAGE_FROM_SYSTEM;\r
1886 \r
1887                 LPVOID pTextBuffer = NULL;\r
1888                 DWORD dwCount = FormatMessage(dwFormatControl,\r
1889                                                                                 NULL,\r
1890                                                                                 dwError,\r
1891                                                                                 0,\r
1892                                                                                 (LPTSTR) &pTextBuffer,\r
1893                                                                                 0,\r
1894                                                                                 NULL);\r
1895                 if(0 != dwCount)\r
1896                 {\r
1897                         MessageBox(NULL, (LPCTSTR)pTextBuffer, pszCaption, MB_OK|MB_ICONERROR);\r
1898                         LocalFree(pTextBuffer);\r
1899                 }\r
1900                 else\r
1901                 {\r
1902                         MessageBox(NULL, __TEXT("Unknown error"), pszCaption, MB_OK|MB_ICONERROR);\r
1903                 }\r
1904         }\r
1905 }\r
1906 \r
1907 // 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
1908 bool CIrrDeviceWin32::isWindowsVistaOrGreater()\r
1909 {\r
1910 #if (_WIN32_WINNT >= 0x0500)\r
1911         OSVERSIONINFOEX osvi;\r
1912         ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));\r
1913         osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);\r
1914         osvi.dwMajorVersion = 6; //  Windows Vista\r
1915 \r
1916         if ( !GetVersionEx((OSVERSIONINFO*)&osvi) )\r
1917         {\r
1918                 return false;\r
1919         }\r
1920 \r
1921         return VerifyVersionInfo(&osvi, VER_MAJORVERSION, VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL)) ? true : false;\r
1922 #else\r
1923     return false;\r
1924 #endif\r
1925 }\r
1926 \r
1927 // Convert an Irrlicht texture to a Windows cursor\r
1928 // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/\r
1929 HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)\r
1930 {\r
1931         //\r
1932         // create the bitmaps needed for cursors from the texture\r
1933 \r
1934         HDC dc = GetDC(hwnd);\r
1935         HDC andDc = CreateCompatibleDC(dc);\r
1936         HDC xorDc = CreateCompatibleDC(dc);\r
1937         HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());\r
1938         HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());\r
1939 \r
1940         HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap);\r
1941         HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap);\r
1942 \r
1943 \r
1944         video::ECOLOR_FORMAT format = tex->getColorFormat();\r
1945         u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;\r
1946         u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;\r
1947         u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;\r
1948         const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);\r
1949         data += sourceRect.UpperLeftCorner.Y*tex->getPitch();\r
1950         for ( s32 y = 0; y < sourceRect.getHeight(); ++y )\r
1951         {\r
1952                 data += bytesLeftGap;\r
1953                 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )\r
1954                 {\r
1955                         video::SColor pixelCol;\r
1956                         pixelCol.setData((const void*)data, format);\r
1957                         data += bytesPerPixel;\r
1958 \r
1959                         if ( pixelCol.getAlpha() == 0 ) // transparent\r
1960                         {\r
1961                                 SetPixel(andDc, x, y, RGB(255,255,255));\r
1962                                 SetPixel(xorDc, x, y, RGB(0,0,0));\r
1963                         }\r
1964                         else    // color\r
1965                         {\r
1966                                 SetPixel(andDc, x, y, RGB(0,0,0));\r
1967                                 SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue()));\r
1968                         }\r
1969                 }\r
1970                 data += bytesRightGap;\r
1971         }\r
1972         tex->unlock();\r
1973 \r
1974         SelectObject(andDc, oldAndBitmap);\r
1975         SelectObject(xorDc, oldXorBitmap);\r
1976 \r
1977         DeleteDC(xorDc);\r
1978         DeleteDC(andDc);\r
1979 \r
1980         ReleaseDC(hwnd, dc);\r
1981 \r
1982         // create the cursor\r
1983 \r
1984         ICONINFO iconinfo;\r
1985         iconinfo.fIcon = false; // type is cursor not icon\r
1986         iconinfo.xHotspot = hotspot.X;\r
1987         iconinfo.yHotspot = hotspot.Y;\r
1988         iconinfo.hbmMask = andBitmap;\r
1989         iconinfo.hbmColor = xorBitmap;\r
1990 \r
1991         HCURSOR cursor = CreateIconIndirect(&iconinfo);\r
1992 \r
1993         DeleteObject(andBitmap);\r
1994         DeleteObject(xorBitmap);\r
1995 \r
1996         return cursor;\r
1997 }\r
1998 \r
1999 \r
2000 CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen)\r
2001         : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f),\r
2002                 HWnd(hwnd), BorderX(0), BorderY(0),\r
2003                 UseReferenceRect(false), IsVisible(true)\r
2004                 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)\r
2005 {\r
2006         if (WindowSize.Width!=0)\r
2007                 InvWindowSize.Width = 1.0f / WindowSize.Width;\r
2008 \r
2009         if (WindowSize.Height!=0)\r
2010                 InvWindowSize.Height = 1.0f / WindowSize.Height;\r
2011 \r
2012         updateBorderSize(fullscreen, false);\r
2013         initCursors();\r
2014 }\r
2015 \r
2016 CIrrDeviceWin32::CCursorControl::~CCursorControl()\r
2017 {\r
2018         for ( u32 i=0; i < Cursors.size(); ++i )\r
2019         {\r
2020                 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )\r
2021                 {\r
2022                         DestroyCursor(Cursors[i].Frames[f].IconHW);\r
2023                 }\r
2024         }\r
2025 }\r
2026 \r
2027 \r
2028 void CIrrDeviceWin32::CCursorControl::initCursors()\r
2029 {\r
2030         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) );\r
2031         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) );\r
2032         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) );\r
2033         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) );\r
2034         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) );\r
2035         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) );\r
2036         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) );\r
2037         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) );\r
2038         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) );\r
2039         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) );\r
2040         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) );\r
2041         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) );\r
2042         Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) );\r
2043 }\r
2044 \r
2045 \r
2046 void CIrrDeviceWin32::CCursorControl::update()\r
2047 {\r
2048         if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )\r
2049         {\r
2050                 // 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
2051                 u32 now = Device->getTimer()->getRealTime();\r
2052                 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();\r
2053                 SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );\r
2054         }\r
2055 }\r
2056 \r
2057 //! Sets the active cursor icon\r
2058 void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)\r
2059 {\r
2060         if ( iconId >= (s32)Cursors.size() )\r
2061                 return;\r
2062 \r
2063         ActiveIcon = iconId;\r
2064         ActiveIconStartTime = Device->getTimer()->getRealTime();\r
2065         if ( Cursors[ActiveIcon].Frames.size() )\r
2066                 SetCursor( Cursors[ActiveIcon].Frames[0].IconHW );\r
2067 }\r
2068 \r
2069 \r
2070 //! Add a custom sprite as cursor icon.\r
2071 gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon)\r
2072 {\r
2073         if ( icon.SpriteId >= 0 )\r
2074         {\r
2075                 CursorW32 cW32;\r
2076                 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;\r
2077 \r
2078                 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )\r
2079                 {\r
2080                         irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;\r
2081                         irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;\r
2082                         irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];\r
2083 \r
2084                         HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);\r
2085                         cW32.Frames.push_back( CursorFrameW32(hc) );\r
2086                 }\r
2087 \r
2088                 Cursors.push_back( cW32 );\r
2089                 return (gui::ECURSOR_ICON)(Cursors.size() - 1);\r
2090         }\r
2091         return gui::ECI_NORMAL;\r
2092 }\r
2093 \r
2094 \r
2095 //! replace the given cursor icon.\r
2096 void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)\r
2097 {\r
2098         if ( iconId >= (s32)Cursors.size() )\r
2099                 return;\r
2100 \r
2101         for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )\r
2102                 DestroyCursor(Cursors[iconId].Frames[i].IconHW);\r
2103 \r
2104         if ( icon.SpriteId >= 0 )\r
2105         {\r
2106                 CursorW32 cW32;\r
2107                 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;\r
2108                 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )\r
2109                 {\r
2110                         irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;\r
2111                         irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;\r
2112                         irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];\r
2113 \r
2114                         HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);\r
2115                         cW32.Frames.push_back( CursorFrameW32(hc) );\r
2116                 }\r
2117 \r
2118                 Cursors[iconId] = cW32;\r
2119         }\r
2120 }\r
2121 \r
2122 \r
2123 //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.\r
2124 core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const\r
2125 {\r
2126         core::dimension2di result;\r
2127 \r
2128         result.Width = GetSystemMetrics(SM_CXCURSOR);\r
2129         result.Height = GetSystemMetrics(SM_CYCURSOR);\r
2130 \r
2131         return result;\r
2132 }\r
2133 \r
2134 \r
2135 \r
2136 } // end namespace\r
2137 \r
2138 #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_\r