diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp | 2068 |
1 files changed, 2068 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp new file mode 100644 index 0000000..22c405e --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CIrrDeviceWin32.cpp | |||
@@ -0,0 +1,2068 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | |||
7 | #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ | ||
8 | |||
9 | #include "CIrrDeviceWin32.h" | ||
10 | #include "IEventReceiver.h" | ||
11 | #include "irrList.h" | ||
12 | #include "os.h" | ||
13 | |||
14 | #include "CTimer.h" | ||
15 | #include "irrString.h" | ||
16 | #include "COSOperator.h" | ||
17 | #include "dimension2d.h" | ||
18 | #include "IGUISpriteBank.h" | ||
19 | #include <winuser.h> | ||
20 | #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) | ||
21 | #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ | ||
22 | #define DIRECTINPUT_VERSION 0x0800 | ||
23 | #include <dinput.h> | ||
24 | #ifdef _MSC_VER | ||
25 | #pragma comment(lib, "dinput8.lib") | ||
26 | #pragma comment(lib, "dxguid.lib") | ||
27 | #endif | ||
28 | #else | ||
29 | #ifdef _MSC_VER | ||
30 | #pragma comment(lib, "winmm.lib") | ||
31 | #endif | ||
32 | #endif | ||
33 | #endif | ||
34 | |||
35 | namespace irr | ||
36 | { | ||
37 | namespace video | ||
38 | { | ||
39 | #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
40 | IVideoDriver* createDirectX8Driver(const irr::SIrrlichtCreationParameters& params, | ||
41 | io::IFileSystem* io, HWND window); | ||
42 | #endif | ||
43 | |||
44 | #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ | ||
45 | IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, | ||
46 | io::IFileSystem* io, HWND window); | ||
47 | #endif | ||
48 | |||
49 | #ifdef _IRR_COMPILE_WITH_OPENGL_ | ||
50 | IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, | ||
51 | io::IFileSystem* io, CIrrDeviceWin32* device); | ||
52 | #endif | ||
53 | } | ||
54 | } // end namespace irr | ||
55 | |||
56 | namespace irr | ||
57 | { | ||
58 | struct SJoystickWin32Control | ||
59 | { | ||
60 | CIrrDeviceWin32* Device; | ||
61 | |||
62 | #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) | ||
63 | IDirectInput8* DirectInputDevice; | ||
64 | #endif | ||
65 | #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) | ||
66 | struct JoystickInfo | ||
67 | { | ||
68 | u32 Index; | ||
69 | #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ | ||
70 | core::stringc Name; | ||
71 | GUID guid; | ||
72 | LPDIRECTINPUTDEVICE8 lpdijoy; | ||
73 | DIDEVCAPS devcaps; | ||
74 | u8 axisValid[8]; | ||
75 | #else | ||
76 | JOYCAPS Caps; | ||
77 | #endif | ||
78 | }; | ||
79 | core::array<JoystickInfo> ActiveJoysticks; | ||
80 | #endif | ||
81 | |||
82 | SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev) | ||
83 | { | ||
84 | #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) | ||
85 | DirectInputDevice=0; | ||
86 | if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL))) | ||
87 | { | ||
88 | os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING); | ||
89 | return; | ||
90 | } | ||
91 | #endif | ||
92 | } | ||
93 | ~SJoystickWin32Control() | ||
94 | { | ||
95 | #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) | ||
96 | for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) | ||
97 | { | ||
98 | LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy; | ||
99 | if (dev) | ||
100 | { | ||
101 | dev->Unacquire(); | ||
102 | } | ||
103 | dev->Release(); | ||
104 | } | ||
105 | |||
106 | if (DirectInputDevice) | ||
107 | DirectInputDevice->Release(); | ||
108 | #endif | ||
109 | } | ||
110 | |||
111 | #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_) | ||
112 | static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp) | ||
113 | { | ||
114 | SJoystickWin32Control* p=(SJoystickWin32Control*)cp; | ||
115 | p->directInputAddJoystick(lpddi); | ||
116 | return DIENUM_CONTINUE; | ||
117 | } | ||
118 | void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi) | ||
119 | { | ||
120 | //Get the GUID of the joystuck | ||
121 | const GUID guid = lpddi->guidInstance; | ||
122 | |||
123 | JoystickInfo activeJoystick; | ||
124 | activeJoystick.Index=ActiveJoysticks.size(); | ||
125 | activeJoystick.guid=guid; | ||
126 | activeJoystick.Name=lpddi->tszProductName; | ||
127 | if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL))) | ||
128 | { | ||
129 | os::Printer::log("Could not create DirectInput device", ELL_WARNING); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps); | ||
134 | if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps))) | ||
135 | { | ||
136 | os::Printer::log("Could not create DirectInput device", ELL_WARNING); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE))) | ||
141 | { | ||
142 | os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2))) | ||
147 | { | ||
148 | os::Printer::log("Could not set DirectInput device data format", ELL_WARNING); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | if (FAILED(activeJoystick.lpdijoy->Acquire())) | ||
153 | { | ||
154 | os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING); | ||
155 | return; | ||
156 | } | ||
157 | |||
158 | DIJOYSTATE2 info; | ||
159 | if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info))) | ||
160 | { | ||
161 | os::Printer::log("Could not read DirectInput device state", ELL_WARNING); | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid)); | ||
166 | activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0; | ||
167 | activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0; | ||
168 | activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0; | ||
169 | activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0; | ||
170 | activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0; | ||
171 | activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0; | ||
172 | |||
173 | int caxis=0; | ||
174 | for (u8 i=0; i<6; i++) | ||
175 | { | ||
176 | if (activeJoystick.axisValid[i]) | ||
177 | caxis++; | ||
178 | } | ||
179 | |||
180 | for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++) | ||
181 | { | ||
182 | if (i+caxis < 8) | ||
183 | activeJoystick.axisValid[i+caxis]=1; | ||
184 | } | ||
185 | |||
186 | ActiveJoysticks.push_back(activeJoystick); | ||
187 | } | ||
188 | #endif | ||
189 | |||
190 | void pollJoysticks() | ||
191 | { | ||
192 | #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ | ||
193 | #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ | ||
194 | if(0 == ActiveJoysticks.size()) | ||
195 | return; | ||
196 | |||
197 | u32 joystick; | ||
198 | DIJOYSTATE2 info; | ||
199 | |||
200 | for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) | ||
201 | { | ||
202 | // needs to be reset for each joystick | ||
203 | // request ALL values and POV as continuous if possible | ||
204 | |||
205 | const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps; | ||
206 | // if no POV is available don't ask for POV values | ||
207 | |||
208 | if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info))) | ||
209 | { | ||
210 | SEvent event; | ||
211 | |||
212 | event.EventType = irr::EET_JOYSTICK_INPUT_EVENT; | ||
213 | event.JoystickEvent.Joystick = (u8)joystick; | ||
214 | |||
215 | event.JoystickEvent.POV = (u16)info.rgdwPOV[0]; | ||
216 | // set to undefined if no POV value was returned or the value | ||
217 | // is out of range | ||
218 | if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900)) | ||
219 | event.JoystickEvent.POV = 65535; | ||
220 | |||
221 | for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis) | ||
222 | event.JoystickEvent.Axis[axis] = 0; | ||
223 | |||
224 | u16 dxAxis=0; | ||
225 | u16 irrAxis=0; | ||
226 | |||
227 | while (dxAxis < 6 && irrAxis <caps.dwAxes) | ||
228 | { | ||
229 | bool axisFound=0; | ||
230 | s32 axisValue=0; | ||
231 | |||
232 | switch (dxAxis) | ||
233 | { | ||
234 | case 0: | ||
235 | axisValue=info.lX; | ||
236 | break; | ||
237 | case 1: | ||
238 | axisValue=info.lY; | ||
239 | break; | ||
240 | case 2: | ||
241 | axisValue=info.lZ; | ||
242 | break; | ||
243 | case 3: | ||
244 | axisValue=info.lRx; | ||
245 | break; | ||
246 | case 4: | ||
247 | axisValue=info.lRy; | ||
248 | break; | ||
249 | case 5: | ||
250 | axisValue=info.lRz; | ||
251 | break; | ||
252 | case 6: | ||
253 | axisValue=info.rglSlider[0]; | ||
254 | break; | ||
255 | case 7: | ||
256 | axisValue=info.rglSlider[1]; | ||
257 | break; | ||
258 | default: | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | if (ActiveJoysticks[joystick].axisValid[dxAxis]>0) | ||
263 | axisFound=1; | ||
264 | |||
265 | if (axisFound) | ||
266 | { | ||
267 | s32 val=axisValue - 32768; | ||
268 | |||
269 | if (val <-32767) val=-32767; | ||
270 | if (val > 32767) val=32767; | ||
271 | event.JoystickEvent.Axis[irrAxis]=(s16)(val); | ||
272 | irrAxis++; | ||
273 | } | ||
274 | |||
275 | dxAxis++; | ||
276 | } | ||
277 | |||
278 | u32 buttons=0; | ||
279 | BYTE* bytebuttons=info.rgbButtons; | ||
280 | for (u16 i=0; i<32; i++) | ||
281 | { | ||
282 | if (bytebuttons[i] >0) | ||
283 | { | ||
284 | buttons |= (1 << i); | ||
285 | } | ||
286 | } | ||
287 | event.JoystickEvent.ButtonStates = buttons; | ||
288 | |||
289 | (void)Device->postEventFromUser(event); | ||
290 | } | ||
291 | } | ||
292 | #else | ||
293 | if (0 == ActiveJoysticks.size()) | ||
294 | return; | ||
295 | |||
296 | u32 joystick; | ||
297 | JOYINFOEX info; | ||
298 | |||
299 | for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) | ||
300 | { | ||
301 | // needs to be reset for each joystick | ||
302 | // request ALL values and POV as continuous if possible | ||
303 | info.dwSize = sizeof(info); | ||
304 | info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS; | ||
305 | const JOYCAPS & caps = ActiveJoysticks[joystick].Caps; | ||
306 | // if no POV is available don't ask for POV values | ||
307 | if (!(caps.wCaps & JOYCAPS_HASPOV)) | ||
308 | info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS); | ||
309 | if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info)) | ||
310 | { | ||
311 | SEvent event; | ||
312 | |||
313 | event.EventType = irr::EET_JOYSTICK_INPUT_EVENT; | ||
314 | event.JoystickEvent.Joystick = (u8)joystick; | ||
315 | |||
316 | event.JoystickEvent.POV = (u16)info.dwPOV; | ||
317 | // set to undefined if no POV value was returned or the value | ||
318 | // is out of range | ||
319 | if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900)) | ||
320 | event.JoystickEvent.POV = 65535; | ||
321 | |||
322 | for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis) | ||
323 | event.JoystickEvent.Axis[axis] = 0; | ||
324 | |||
325 | event.JoystickEvent.ButtonStates = info.dwButtons; | ||
326 | |||
327 | switch(caps.wNumAxes) | ||
328 | { | ||
329 | default: | ||
330 | case 6: | ||
331 | event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] = | ||
332 | (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768); | ||
333 | |||
334 | case 5: | ||
335 | event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] = | ||
336 | (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768); | ||
337 | |||
338 | case 4: | ||
339 | event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] = | ||
340 | (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768); | ||
341 | |||
342 | case 3: | ||
343 | event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] = | ||
344 | (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768); | ||
345 | |||
346 | case 2: | ||
347 | event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] = | ||
348 | (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768); | ||
349 | |||
350 | case 1: | ||
351 | event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] = | ||
352 | (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768); | ||
353 | } | ||
354 | |||
355 | (void)Device->postEventFromUser(event); | ||
356 | } | ||
357 | } | ||
358 | #endif | ||
359 | #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ | ||
360 | } | ||
361 | |||
362 | bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo) | ||
363 | { | ||
364 | #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ | ||
365 | #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ | ||
366 | if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY ))) | ||
367 | { | ||
368 | os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING); | ||
369 | return false; | ||
370 | } | ||
371 | |||
372 | for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick) | ||
373 | { | ||
374 | JoystickInfo& activeJoystick = ActiveJoysticks[joystick]; | ||
375 | SJoystickInfo info; | ||
376 | info.Axes=activeJoystick.devcaps.dwAxes; | ||
377 | info.Buttons=activeJoystick.devcaps.dwButtons; | ||
378 | info.Name=activeJoystick.Name; | ||
379 | info.PovHat = (activeJoystick.devcaps.dwPOVs != 0) | ||
380 | ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT; | ||
381 | joystickInfo.push_back(info); | ||
382 | } | ||
383 | return true; | ||
384 | #else | ||
385 | joystickInfo.clear(); | ||
386 | ActiveJoysticks.clear(); | ||
387 | |||
388 | const u32 numberOfJoysticks = ::joyGetNumDevs(); | ||
389 | JOYINFOEX info; | ||
390 | info.dwSize = sizeof(info); | ||
391 | info.dwFlags = JOY_RETURNALL; | ||
392 | |||
393 | JoystickInfo activeJoystick; | ||
394 | SJoystickInfo returnInfo; | ||
395 | |||
396 | joystickInfo.reallocate(numberOfJoysticks); | ||
397 | ActiveJoysticks.reallocate(numberOfJoysticks); | ||
398 | |||
399 | u32 joystick = 0; | ||
400 | for(; joystick < numberOfJoysticks; ++joystick) | ||
401 | { | ||
402 | if(JOYERR_NOERROR == joyGetPosEx(joystick, &info) | ||
403 | && | ||
404 | JOYERR_NOERROR == joyGetDevCaps(joystick, | ||
405 | &activeJoystick.Caps, | ||
406 | sizeof(activeJoystick.Caps))) | ||
407 | { | ||
408 | activeJoystick.Index = joystick; | ||
409 | ActiveJoysticks.push_back(activeJoystick); | ||
410 | |||
411 | returnInfo.Joystick = (u8)joystick; | ||
412 | returnInfo.Axes = activeJoystick.Caps.wNumAxes; | ||
413 | returnInfo.Buttons = activeJoystick.Caps.wNumButtons; | ||
414 | returnInfo.Name = activeJoystick.Caps.szPname; | ||
415 | returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV) | ||
416 | ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT; | ||
417 | |||
418 | joystickInfo.push_back(returnInfo); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | for(joystick = 0; joystick < joystickInfo.size(); ++joystick) | ||
423 | { | ||
424 | char logString[256]; | ||
425 | (void)sprintf(logString, "Found joystick %d, %d axes, %d buttons '%s'", | ||
426 | joystick, joystickInfo[joystick].Axes, | ||
427 | joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); | ||
428 | os::Printer::log(logString, ELL_INFORMATION); | ||
429 | } | ||
430 | |||
431 | return true; | ||
432 | #endif | ||
433 | #else | ||
434 | return false; | ||
435 | #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ | ||
436 | } | ||
437 | }; | ||
438 | } // end namespace irr | ||
439 | |||
440 | // Get the codepage from the locale language id | ||
441 | // Based on the table from http://www.science.co.il/Language/Locale-Codes.asp?s=decimal | ||
442 | static unsigned int LocaleIdToCodepage(unsigned int lcid) | ||
443 | { | ||
444 | switch ( lcid ) | ||
445 | { | ||
446 | case 1098: // Telugu | ||
447 | case 1095: // Gujarati | ||
448 | case 1094: // Punjabi | ||
449 | case 1103: // Sanskrit | ||
450 | case 1111: // Konkani | ||
451 | case 1114: // Syriac | ||
452 | case 1099: // Kannada | ||
453 | case 1102: // Marathi | ||
454 | case 1125: // Divehi | ||
455 | case 1067: // Armenian | ||
456 | case 1081: // Hindi | ||
457 | case 1079: // Georgian | ||
458 | case 1097: // Tamil | ||
459 | return 0; | ||
460 | case 1054: // Thai | ||
461 | return 874; | ||
462 | case 1041: // Japanese | ||
463 | return 932; | ||
464 | case 2052: // Chinese (PRC) | ||
465 | case 4100: // Chinese (Singapore) | ||
466 | return 936; | ||
467 | case 1042: // Korean | ||
468 | return 949; | ||
469 | case 5124: // Chinese (Macau S.A.R.) | ||
470 | case 3076: // Chinese (Hong Kong S.A.R.) | ||
471 | case 1028: // Chinese (Taiwan) | ||
472 | return 950; | ||
473 | case 1048: // Romanian | ||
474 | case 1060: // Slovenian | ||
475 | case 1038: // Hungarian | ||
476 | case 1051: // Slovak | ||
477 | case 1045: // Polish | ||
478 | case 1052: // Albanian | ||
479 | case 2074: // Serbian (Latin) | ||
480 | case 1050: // Croatian | ||
481 | case 1029: // Czech | ||
482 | return 1250; | ||
483 | case 1104: // Mongolian (Cyrillic) | ||
484 | case 1071: // FYRO Macedonian | ||
485 | case 2115: // Uzbek (Cyrillic) | ||
486 | case 1058: // Ukrainian | ||
487 | case 2092: // Azeri (Cyrillic) | ||
488 | case 1092: // Tatar | ||
489 | case 1087: // Kazakh | ||
490 | case 1059: // Belarusian | ||
491 | case 1088: // Kyrgyz (Cyrillic) | ||
492 | case 1026: // Bulgarian | ||
493 | case 3098: // Serbian (Cyrillic) | ||
494 | case 1049: // Russian | ||
495 | return 1251; | ||
496 | case 8201: // English (Jamaica) | ||
497 | case 3084: // French (Canada) | ||
498 | case 1036: // French (France) | ||
499 | case 5132: // French (Luxembourg) | ||
500 | case 5129: // English (New Zealand) | ||
501 | case 6153: // English (Ireland) | ||
502 | case 1043: // Dutch (Netherlands) | ||
503 | case 9225: // English (Caribbean) | ||
504 | case 4108: // French (Switzerland) | ||
505 | case 4105: // English (Canada) | ||
506 | case 1110: // Galician | ||
507 | case 10249: // English (Belize) | ||
508 | case 3079: // German (Austria) | ||
509 | case 6156: // French (Monaco) | ||
510 | case 12297: // English (Zimbabwe) | ||
511 | case 1069: // Basque | ||
512 | case 2067: // Dutch (Belgium) | ||
513 | case 2060: // French (Belgium) | ||
514 | case 1035: // Finnish | ||
515 | case 1080: // Faroese | ||
516 | case 1031: // German (Germany) | ||
517 | case 3081: // English (Australia) | ||
518 | case 1033: // English (United States) | ||
519 | case 2057: // English (United Kingdom) | ||
520 | case 1027: // Catalan | ||
521 | case 11273: // English (Trinidad) | ||
522 | case 7177: // English (South Africa) | ||
523 | case 1030: // Danish | ||
524 | case 13321: // English (Philippines) | ||
525 | case 15370: // Spanish (Paraguay) | ||
526 | case 9226: // Spanish (Colombia) | ||
527 | case 5130: // Spanish (Costa Rica) | ||
528 | case 7178: // Spanish (Dominican Republic) | ||
529 | case 12298: // Spanish (Ecuador) | ||
530 | case 17418: // Spanish (El Salvador) | ||
531 | case 4106: // Spanish (Guatemala) | ||
532 | case 18442: // Spanish (Honduras) | ||
533 | case 3082: // Spanish (International Sort) | ||
534 | case 13322: // Spanish (Chile) | ||
535 | case 19466: // Spanish (Nicaragua) | ||
536 | case 2058: // Spanish (Mexico) | ||
537 | case 10250: // Spanish (Peru) | ||
538 | case 20490: // Spanish (Puerto Rico) | ||
539 | case 1034: // Spanish (Traditional Sort) | ||
540 | case 14346: // Spanish (Uruguay) | ||
541 | case 8202: // Spanish (Venezuela) | ||
542 | case 1089: // Swahili | ||
543 | case 1053: // Swedish | ||
544 | case 2077: // Swedish (Finland) | ||
545 | case 5127: // German (Liechtenstein) | ||
546 | case 1078: // Afrikaans | ||
547 | case 6154: // Spanish (Panama) | ||
548 | case 4103: // German (Luxembourg) | ||
549 | case 16394: // Spanish (Bolivia) | ||
550 | case 2055: // German (Switzerland) | ||
551 | case 1039: // Icelandic | ||
552 | case 1057: // Indonesian | ||
553 | case 1040: // Italian (Italy) | ||
554 | case 2064: // Italian (Switzerland) | ||
555 | case 2068: // Norwegian (Nynorsk) | ||
556 | case 11274: // Spanish (Argentina) | ||
557 | case 1046: // Portuguese (Brazil) | ||
558 | case 1044: // Norwegian (Bokmal) | ||
559 | case 1086: // Malay (Malaysia) | ||
560 | case 2110: // Malay (Brunei Darussalam) | ||
561 | case 2070: // Portuguese (Portugal) | ||
562 | return 1252; | ||
563 | case 1032: // Greek | ||
564 | return 1253; | ||
565 | case 1091: // Uzbek (Latin) | ||
566 | case 1068: // Azeri (Latin) | ||
567 | case 1055: // Turkish | ||
568 | return 1254; | ||
569 | case 1037: // Hebrew | ||
570 | return 1255; | ||
571 | case 5121: // Arabic (Algeria) | ||
572 | case 15361: // Arabic (Bahrain) | ||
573 | case 9217: // Arabic (Yemen) | ||
574 | case 3073: // Arabic (Egypt) | ||
575 | case 2049: // Arabic (Iraq) | ||
576 | case 11265: // Arabic (Jordan) | ||
577 | case 13313: // Arabic (Kuwait) | ||
578 | case 12289: // Arabic (Lebanon) | ||
579 | case 4097: // Arabic (Libya) | ||
580 | case 6145: // Arabic (Morocco) | ||
581 | case 8193: // Arabic (Oman) | ||
582 | case 16385: // Arabic (Qatar) | ||
583 | case 1025: // Arabic (Saudi Arabia) | ||
584 | case 10241: // Arabic (Syria) | ||
585 | case 14337: // Arabic (U.A.E.) | ||
586 | case 1065: // Farsi | ||
587 | case 1056: // Urdu | ||
588 | case 7169: // Arabic (Tunisia) | ||
589 | return 1256; | ||
590 | case 1061: // Estonian | ||
591 | case 1062: // Latvian | ||
592 | case 1063: // Lithuanian | ||
593 | return 1257; | ||
594 | case 1066: // Vietnamese | ||
595 | return 1258; | ||
596 | } | ||
597 | return 65001; // utf-8 | ||
598 | } | ||
599 | |||
600 | namespace | ||
601 | { | ||
602 | struct SEnvMapper | ||
603 | { | ||
604 | HWND hWnd; | ||
605 | irr::CIrrDeviceWin32* irrDev; | ||
606 | }; | ||
607 | irr::core::list<SEnvMapper> EnvMap; | ||
608 | |||
609 | HKL KEYBOARD_INPUT_HKL=0; | ||
610 | unsigned int KEYBOARD_INPUT_CODEPAGE = 1252; | ||
611 | } | ||
612 | |||
613 | SEnvMapper* getEnvMapperFromHWnd(HWND hWnd) | ||
614 | { | ||
615 | irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin(); | ||
616 | for (; it!= EnvMap.end(); ++it) | ||
617 | if ((*it).hWnd == hWnd) | ||
618 | return &(*it); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | |||
624 | irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd) | ||
625 | { | ||
626 | irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin(); | ||
627 | for (; it!= EnvMap.end(); ++it) | ||
628 | if ((*it).hWnd == hWnd) | ||
629 | return (*it).irrDev; | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | |||
635 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | ||
636 | { | ||
637 | #ifndef WM_MOUSEWHEEL | ||
638 | #define WM_MOUSEWHEEL 0x020A | ||
639 | #endif | ||
640 | #ifndef WHEEL_DELTA | ||
641 | #define WHEEL_DELTA 120 | ||
642 | #endif | ||
643 | |||
644 | irr::CIrrDeviceWin32* dev = 0; | ||
645 | irr::SEvent event; | ||
646 | |||
647 | static irr::s32 ClickCount=0; | ||
648 | if (GetCapture() != hWnd && ClickCount > 0) | ||
649 | ClickCount = 0; | ||
650 | |||
651 | |||
652 | struct messageMap | ||
653 | { | ||
654 | irr::s32 group; | ||
655 | UINT winMessage; | ||
656 | irr::s32 irrMessage; | ||
657 | }; | ||
658 | |||
659 | static messageMap mouseMap[] = | ||
660 | { | ||
661 | {0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN}, | ||
662 | {1, WM_LBUTTONUP, irr::EMIE_LMOUSE_LEFT_UP}, | ||
663 | {0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN}, | ||
664 | {1, WM_RBUTTONUP, irr::EMIE_RMOUSE_LEFT_UP}, | ||
665 | {0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN}, | ||
666 | {1, WM_MBUTTONUP, irr::EMIE_MMOUSE_LEFT_UP}, | ||
667 | {2, WM_MOUSEMOVE, irr::EMIE_MOUSE_MOVED}, | ||
668 | {3, WM_MOUSEWHEEL, irr::EMIE_MOUSE_WHEEL}, | ||
669 | {-1, 0, 0} | ||
670 | }; | ||
671 | |||
672 | // handle grouped events | ||
673 | messageMap * m = mouseMap; | ||
674 | while ( m->group >=0 && m->winMessage != message ) | ||
675 | m += 1; | ||
676 | |||
677 | if ( m->group >= 0 ) | ||
678 | { | ||
679 | if ( m->group == 0 ) // down | ||
680 | { | ||
681 | ClickCount++; | ||
682 | SetCapture(hWnd); | ||
683 | } | ||
684 | else | ||
685 | if ( m->group == 1 ) // up | ||
686 | { | ||
687 | ClickCount--; | ||
688 | if (ClickCount<1) | ||
689 | { | ||
690 | ClickCount=0; | ||
691 | ReleaseCapture(); | ||
692 | } | ||
693 | } | ||
694 | |||
695 | event.EventType = irr::EET_MOUSE_INPUT_EVENT; | ||
696 | event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage; | ||
697 | event.MouseInput.X = (short)LOWORD(lParam); | ||
698 | event.MouseInput.Y = (short)HIWORD(lParam); | ||
699 | event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0); | ||
700 | event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0); | ||
701 | // left and right mouse buttons | ||
702 | event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON); | ||
703 | // middle and extra buttons | ||
704 | if (wParam & MK_MBUTTON) | ||
705 | event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE; | ||
706 | #if(_WIN32_WINNT >= 0x0500) | ||
707 | if (wParam & MK_XBUTTON1) | ||
708 | event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1; | ||
709 | if (wParam & MK_XBUTTON2) | ||
710 | event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2; | ||
711 | #endif | ||
712 | event.MouseInput.Wheel = 0.f; | ||
713 | |||
714 | // wheel | ||
715 | if ( m->group == 3 ) | ||
716 | { | ||
717 | POINT p; // fixed by jox | ||
718 | p.x = 0; p.y = 0; | ||
719 | ClientToScreen(hWnd, &p); | ||
720 | event.MouseInput.X -= p.x; | ||
721 | event.MouseInput.Y -= p.y; | ||
722 | event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA; | ||
723 | } | ||
724 | |||
725 | dev = getDeviceFromHWnd(hWnd); | ||
726 | if (dev) | ||
727 | { | ||
728 | dev->postEventFromUser(event); | ||
729 | |||
730 | if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN ) | ||
731 | { | ||
732 | irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event); | ||
733 | if ( clicks == 2 ) | ||
734 | { | ||
735 | event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN); | ||
736 | dev->postEventFromUser(event); | ||
737 | } | ||
738 | else if ( clicks == 3 ) | ||
739 | { | ||
740 | event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN); | ||
741 | dev->postEventFromUser(event); | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | switch (message) | ||
749 | { | ||
750 | case WM_PAINT: | ||
751 | { | ||
752 | PAINTSTRUCT ps; | ||
753 | BeginPaint(hWnd, &ps); | ||
754 | EndPaint(hWnd, &ps); | ||
755 | } | ||
756 | return 0; | ||
757 | |||
758 | case WM_ERASEBKGND: | ||
759 | return 0; | ||
760 | |||
761 | case WM_SYSKEYDOWN: | ||
762 | case WM_SYSKEYUP: | ||
763 | case WM_KEYDOWN: | ||
764 | case WM_KEYUP: | ||
765 | { | ||
766 | BYTE allKeys[256]; | ||
767 | |||
768 | event.EventType = irr::EET_KEY_INPUT_EVENT; | ||
769 | event.KeyInput.Key = (irr::EKEY_CODE)wParam; | ||
770 | event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN); | ||
771 | |||
772 | 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. | ||
773 | if ( event.KeyInput.Key == irr::KEY_SHIFT ) | ||
774 | { | ||
775 | // this will fail on systems before windows NT/2000/XP, not sure _what_ will return there instead. | ||
776 | event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX ); | ||
777 | } | ||
778 | if ( event.KeyInput.Key == irr::KEY_CONTROL ) | ||
779 | { | ||
780 | event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX ); | ||
781 | // some keyboards will just return LEFT for both - left and right keys. So also check extend bit. | ||
782 | if (lParam & 0x1000000) | ||
783 | event.KeyInput.Key = irr::KEY_RCONTROL; | ||
784 | } | ||
785 | if ( event.KeyInput.Key == irr::KEY_MENU ) | ||
786 | { | ||
787 | event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MY_MAPVK_VSC_TO_VK_EX ); | ||
788 | if (lParam & 0x1000000) | ||
789 | event.KeyInput.Key = irr::KEY_RMENU; | ||
790 | } | ||
791 | |||
792 | GetKeyboardState(allKeys); | ||
793 | |||
794 | event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0); | ||
795 | event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0); | ||
796 | |||
797 | // Handle unicode and deadkeys in a way that works since Windows 95 and nt4.0 | ||
798 | // Using ToUnicode instead would be shorter, but would to my knowledge not run on 95 and 98. | ||
799 | WORD keyChars[2]; | ||
800 | UINT scanCode = HIWORD(lParam); | ||
801 | int conversionResult = ToAsciiEx(wParam,scanCode,allKeys,keyChars,0,KEYBOARD_INPUT_HKL); | ||
802 | if (conversionResult == 1) | ||
803 | { | ||
804 | WORD unicodeChar; | ||
805 | MultiByteToWideChar( | ||
806 | KEYBOARD_INPUT_CODEPAGE, | ||
807 | MB_PRECOMPOSED, // default | ||
808 | (LPCSTR)keyChars, | ||
809 | sizeof(keyChars), | ||
810 | (WCHAR*)&unicodeChar, | ||
811 | 1 ); | ||
812 | event.KeyInput.Char = unicodeChar; | ||
813 | } | ||
814 | else | ||
815 | event.KeyInput.Char = 0; | ||
816 | |||
817 | // allow composing characters like '@' with Alt Gr on non-US keyboards | ||
818 | if ((allKeys[VK_MENU] & 0x80) != 0) | ||
819 | event.KeyInput.Control = 0; | ||
820 | |||
821 | dev = getDeviceFromHWnd(hWnd); | ||
822 | if (dev) | ||
823 | dev->postEventFromUser(event); | ||
824 | |||
825 | if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP) | ||
826 | return DefWindowProc(hWnd, message, wParam, lParam); | ||
827 | else | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | case WM_SIZE: | ||
832 | { | ||
833 | // resize | ||
834 | dev = getDeviceFromHWnd(hWnd); | ||
835 | if (dev) | ||
836 | dev->OnResized(); | ||
837 | } | ||
838 | return 0; | ||
839 | |||
840 | case WM_DESTROY: | ||
841 | PostQuitMessage(0); | ||
842 | return 0; | ||
843 | |||
844 | case WM_SYSCOMMAND: | ||
845 | // prevent screensaver or monitor powersave mode from starting | ||
846 | if ((wParam & 0xFFF0) == SC_SCREENSAVE || | ||
847 | (wParam & 0xFFF0) == SC_MONITORPOWER || | ||
848 | (wParam & 0xFFF0) == SC_KEYMENU | ||
849 | ) | ||
850 | return 0; | ||
851 | |||
852 | break; | ||
853 | |||
854 | case WM_ACTIVATE: | ||
855 | // we need to take care for screen changes, e.g. Alt-Tab | ||
856 | dev = getDeviceFromHWnd(hWnd); | ||
857 | if (dev && dev->isFullscreen()) | ||
858 | { | ||
859 | if ((wParam&0xFF)==WA_INACTIVE) | ||
860 | { | ||
861 | // If losing focus we minimize the app to show other one | ||
862 | ShowWindow(hWnd,SW_MINIMIZE); | ||
863 | // and switch back to default resolution | ||
864 | dev->switchToFullScreen(true); | ||
865 | } | ||
866 | else | ||
867 | { | ||
868 | // Otherwise we retore the fullscreen Irrlicht app | ||
869 | SetForegroundWindow(hWnd); | ||
870 | ShowWindow(hWnd, SW_RESTORE); | ||
871 | // and set the fullscreen resolution again | ||
872 | dev->switchToFullScreen(); | ||
873 | } | ||
874 | } | ||
875 | break; | ||
876 | |||
877 | case WM_USER: | ||
878 | event.EventType = irr::EET_USER_EVENT; | ||
879 | event.UserEvent.UserData1 = (irr::s32)wParam; | ||
880 | event.UserEvent.UserData2 = (irr::s32)lParam; | ||
881 | dev = getDeviceFromHWnd(hWnd); | ||
882 | |||
883 | if (dev) | ||
884 | dev->postEventFromUser(event); | ||
885 | |||
886 | return 0; | ||
887 | |||
888 | case WM_SETCURSOR: | ||
889 | // because Windows forgot about that in the meantime | ||
890 | dev = getDeviceFromHWnd(hWnd); | ||
891 | if (dev) | ||
892 | { | ||
893 | dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() ); | ||
894 | dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() ); | ||
895 | } | ||
896 | break; | ||
897 | |||
898 | case WM_INPUTLANGCHANGE: | ||
899 | // get the new codepage used for keyboard input | ||
900 | KEYBOARD_INPUT_HKL = GetKeyboardLayout(0); | ||
901 | KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) ); | ||
902 | return 0; | ||
903 | } | ||
904 | return DefWindowProc(hWnd, message, wParam, lParam); | ||
905 | } | ||
906 | |||
907 | |||
908 | namespace irr | ||
909 | { | ||
910 | |||
911 | //! constructor | ||
912 | CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params) | ||
913 | : CIrrDeviceStub(params), HWnd(0), ChangedToFullScreen(false), Resized(false), | ||
914 | ExternalWindow(false), Win32CursorControl(0), JoyControl(0) | ||
915 | { | ||
916 | #ifdef _DEBUG | ||
917 | setDebugName("CIrrDeviceWin32"); | ||
918 | #endif | ||
919 | |||
920 | // get windows version and create OS operator | ||
921 | core::stringc winversion; | ||
922 | getWindowsVersion(winversion); | ||
923 | Operator = new COSOperator(winversion); | ||
924 | os::Printer::log(winversion.c_str(), ELL_INFORMATION); | ||
925 | |||
926 | // get handle to exe file | ||
927 | HINSTANCE hInstance = GetModuleHandle(0); | ||
928 | |||
929 | // Store original desktop mode. | ||
930 | |||
931 | memset(&DesktopMode, 0, sizeof(DesktopMode)); | ||
932 | DesktopMode.dmSize = sizeof(DesktopMode); | ||
933 | |||
934 | EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &DesktopMode); | ||
935 | |||
936 | // create the window if we need to and we do not use the null device | ||
937 | if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL) | ||
938 | { | ||
939 | const fschar_t* ClassName = __TEXT("CIrrDeviceWin32"); | ||
940 | |||
941 | // Register Class | ||
942 | WNDCLASSEX wcex; | ||
943 | wcex.cbSize = sizeof(WNDCLASSEX); | ||
944 | wcex.style = CS_HREDRAW | CS_VREDRAW; | ||
945 | wcex.lpfnWndProc = WndProc; | ||
946 | wcex.cbClsExtra = 0; | ||
947 | wcex.cbWndExtra = 0; | ||
948 | wcex.hInstance = hInstance; | ||
949 | wcex.hIcon = NULL; | ||
950 | wcex.hCursor = 0; // LoadCursor(NULL, IDC_ARROW); | ||
951 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); | ||
952 | wcex.lpszMenuName = 0; | ||
953 | wcex.lpszClassName = ClassName; | ||
954 | wcex.hIconSm = 0; | ||
955 | |||
956 | // if there is an icon, load it | ||
957 | wcex.hIcon = (HICON)LoadImage(hInstance, __TEXT("irrlicht.ico"), IMAGE_ICON, 0,0, LR_LOADFROMFILE); | ||
958 | |||
959 | RegisterClassEx(&wcex); | ||
960 | |||
961 | // calculate client size | ||
962 | |||
963 | RECT clientSize; | ||
964 | clientSize.top = 0; | ||
965 | clientSize.left = 0; | ||
966 | clientSize.right = CreationParams.WindowSize.Width; | ||
967 | clientSize.bottom = CreationParams.WindowSize.Height; | ||
968 | |||
969 | DWORD style = WS_POPUP; | ||
970 | |||
971 | if (!CreationParams.Fullscreen) | ||
972 | style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; | ||
973 | |||
974 | AdjustWindowRect(&clientSize, style, FALSE); | ||
975 | |||
976 | const s32 realWidth = clientSize.right - clientSize.left; | ||
977 | const s32 realHeight = clientSize.bottom - clientSize.top; | ||
978 | |||
979 | s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; | ||
980 | s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; | ||
981 | |||
982 | if ( windowLeft < 0 ) | ||
983 | windowLeft = 0; | ||
984 | if ( windowTop < 0 ) | ||
985 | windowTop = 0; // make sure window menus are in screen on creation | ||
986 | |||
987 | if (CreationParams.Fullscreen) | ||
988 | { | ||
989 | windowLeft = 0; | ||
990 | windowTop = 0; | ||
991 | } | ||
992 | |||
993 | // create window | ||
994 | |||
995 | HWnd = CreateWindow( ClassName, __TEXT(""), style, windowLeft, windowTop, | ||
996 | realWidth, realHeight, NULL, NULL, hInstance, NULL); | ||
997 | CreationParams.WindowId = HWnd; | ||
998 | // CreationParams.WindowSize.Width = realWidth; | ||
999 | // CreationParams.WindowSize.Height = realHeight; | ||
1000 | |||
1001 | ShowWindow(HWnd, SW_SHOWNORMAL); | ||
1002 | UpdateWindow(HWnd); | ||
1003 | |||
1004 | // fix ugly ATI driver bugs. Thanks to ariaci | ||
1005 | MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE); | ||
1006 | |||
1007 | // make sure everything gets updated to the real sizes | ||
1008 | Resized = true; | ||
1009 | } | ||
1010 | else if (CreationParams.WindowId) | ||
1011 | { | ||
1012 | // attach external window | ||
1013 | HWnd = static_cast<HWND>(CreationParams.WindowId); | ||
1014 | RECT r; | ||
1015 | GetWindowRect(HWnd, &r); | ||
1016 | CreationParams.WindowSize.Width = r.right - r.left; | ||
1017 | CreationParams.WindowSize.Height = r.bottom - r.top; | ||
1018 | CreationParams.Fullscreen = false; | ||
1019 | ExternalWindow = true; | ||
1020 | } | ||
1021 | |||
1022 | // create cursor control | ||
1023 | |||
1024 | Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen); | ||
1025 | CursorControl = Win32CursorControl; | ||
1026 | JoyControl = new SJoystickWin32Control(this); | ||
1027 | |||
1028 | // initialize doubleclicks with system values | ||
1029 | MouseMultiClicks.DoubleClickTime = GetDoubleClickTime(); | ||
1030 | |||
1031 | // create driver | ||
1032 | |||
1033 | createDriver(); | ||
1034 | |||
1035 | if (VideoDriver) | ||
1036 | createGUIAndScene(); | ||
1037 | |||
1038 | // register environment | ||
1039 | |||
1040 | SEnvMapper em; | ||
1041 | em.irrDev = this; | ||
1042 | em.hWnd = HWnd; | ||
1043 | EnvMap.push_back(em); | ||
1044 | |||
1045 | // set this as active window | ||
1046 | if (!ExternalWindow) | ||
1047 | { | ||
1048 | SetActiveWindow(HWnd); | ||
1049 | SetForegroundWindow(HWnd); | ||
1050 | } | ||
1051 | |||
1052 | // get the codepage used for keyboard input | ||
1053 | KEYBOARD_INPUT_HKL = GetKeyboardLayout(0); | ||
1054 | KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage( LOWORD(KEYBOARD_INPUT_HKL) ); | ||
1055 | |||
1056 | // inform driver about the window size etc. | ||
1057 | resizeIfNecessary(); | ||
1058 | } | ||
1059 | |||
1060 | |||
1061 | //! destructor | ||
1062 | CIrrDeviceWin32::~CIrrDeviceWin32() | ||
1063 | { | ||
1064 | delete JoyControl; | ||
1065 | |||
1066 | // unregister environment | ||
1067 | |||
1068 | irr::core::list<SEnvMapper>::Iterator it = EnvMap.begin(); | ||
1069 | for (; it!= EnvMap.end(); ++it) | ||
1070 | { | ||
1071 | if ((*it).hWnd == HWnd) | ||
1072 | { | ||
1073 | EnvMap.erase(it); | ||
1074 | break; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | switchToFullScreen(true); | ||
1079 | } | ||
1080 | |||
1081 | |||
1082 | //! create the driver | ||
1083 | void CIrrDeviceWin32::createDriver() | ||
1084 | { | ||
1085 | switch(CreationParams.DriverType) | ||
1086 | { | ||
1087 | case video::EDT_DIRECT3D8: | ||
1088 | #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
1089 | |||
1090 | VideoDriver = video::createDirectX8Driver(CreationParams, FileSystem, HWnd); | ||
1091 | |||
1092 | if (!VideoDriver) | ||
1093 | { | ||
1094 | os::Printer::log("Could not create DIRECT3D8 Driver.", ELL_ERROR); | ||
1095 | } | ||
1096 | #else | ||
1097 | os::Printer::log("DIRECT3D8 Driver was not compiled into this dll. Try another one.", ELL_ERROR); | ||
1098 | #endif // _IRR_COMPILE_WITH_DIRECT3D_8_ | ||
1099 | |||
1100 | break; | ||
1101 | |||
1102 | case video::EDT_DIRECT3D9: | ||
1103 | #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ | ||
1104 | |||
1105 | VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd); | ||
1106 | |||
1107 | if (!VideoDriver) | ||
1108 | { | ||
1109 | os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR); | ||
1110 | } | ||
1111 | #else | ||
1112 | os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR); | ||
1113 | #endif // _IRR_COMPILE_WITH_DIRECT3D_9_ | ||
1114 | |||
1115 | break; | ||
1116 | |||
1117 | case video::EDT_OPENGL: | ||
1118 | |||
1119 | #ifdef _IRR_COMPILE_WITH_OPENGL_ | ||
1120 | switchToFullScreen(); | ||
1121 | |||
1122 | VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, this); | ||
1123 | if (!VideoDriver) | ||
1124 | { | ||
1125 | os::Printer::log("Could not create OpenGL driver.", ELL_ERROR); | ||
1126 | } | ||
1127 | #else | ||
1128 | os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR); | ||
1129 | #endif | ||
1130 | break; | ||
1131 | |||
1132 | case video::EDT_SOFTWARE: | ||
1133 | |||
1134 | #ifdef _IRR_COMPILE_WITH_SOFTWARE_ | ||
1135 | switchToFullScreen(); | ||
1136 | |||
1137 | VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); | ||
1138 | #else | ||
1139 | os::Printer::log("Software driver was not compiled in.", ELL_ERROR); | ||
1140 | #endif | ||
1141 | |||
1142 | break; | ||
1143 | |||
1144 | case video::EDT_BURNINGSVIDEO: | ||
1145 | #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ | ||
1146 | switchToFullScreen(); | ||
1147 | |||
1148 | VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this); | ||
1149 | #else | ||
1150 | os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR); | ||
1151 | #endif | ||
1152 | break; | ||
1153 | |||
1154 | case video::EDT_NULL: | ||
1155 | // create null driver | ||
1156 | VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); | ||
1157 | break; | ||
1158 | |||
1159 | default: | ||
1160 | os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); | ||
1161 | break; | ||
1162 | } | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | //! runs the device. Returns false if device wants to be deleted | ||
1167 | bool CIrrDeviceWin32::run() | ||
1168 | { | ||
1169 | os::Timer::tick(); | ||
1170 | |||
1171 | static_cast<CCursorControl*>(CursorControl)->update(); | ||
1172 | |||
1173 | handleSystemMessages(); | ||
1174 | |||
1175 | if (!Close) | ||
1176 | resizeIfNecessary(); | ||
1177 | |||
1178 | if(!Close && JoyControl) | ||
1179 | JoyControl->pollJoysticks(); | ||
1180 | |||
1181 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1182 | return !Close; | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | //! Pause the current process for the minimum time allowed only to allow other processes to execute | ||
1187 | void CIrrDeviceWin32::yield() | ||
1188 | { | ||
1189 | Sleep(1); | ||
1190 | } | ||
1191 | |||
1192 | //! Pause execution and let other processes to run for a specified amount of time. | ||
1193 | void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer) | ||
1194 | { | ||
1195 | const bool wasStopped = Timer ? Timer->isStopped() : true; | ||
1196 | if (pauseTimer && !wasStopped) | ||
1197 | Timer->stop(); | ||
1198 | |||
1199 | Sleep(timeMs); | ||
1200 | |||
1201 | if (pauseTimer && !wasStopped) | ||
1202 | Timer->start(); | ||
1203 | } | ||
1204 | |||
1205 | |||
1206 | void CIrrDeviceWin32::resizeIfNecessary() | ||
1207 | { | ||
1208 | if (!Resized || !getVideoDriver()) | ||
1209 | return; | ||
1210 | |||
1211 | RECT r; | ||
1212 | GetClientRect(HWnd, &r); | ||
1213 | |||
1214 | char tmp[255]; | ||
1215 | |||
1216 | if (r.right < 2 || r.bottom < 2) | ||
1217 | { | ||
1218 | sprintf(tmp, "Ignoring resize operation to (%ld %ld)", r.right, r.bottom); | ||
1219 | os::Printer::log(tmp); | ||
1220 | } | ||
1221 | else | ||
1222 | { | ||
1223 | sprintf(tmp, "Resizing window (%ld %ld)", r.right, r.bottom); | ||
1224 | os::Printer::log(tmp); | ||
1225 | |||
1226 | getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom)); | ||
1227 | getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize()); | ||
1228 | } | ||
1229 | |||
1230 | Resized = false; | ||
1231 | } | ||
1232 | |||
1233 | |||
1234 | //! sets the caption of the window | ||
1235 | void CIrrDeviceWin32::setWindowCaption(const wchar_t* text) | ||
1236 | { | ||
1237 | // We use SendMessage instead of SetText to ensure proper | ||
1238 | // function even in cases where the HWND was created in a different thread | ||
1239 | DWORD_PTR dwResult; | ||
1240 | SendMessageTimeoutW(HWnd, WM_SETTEXT, 0, | ||
1241 | reinterpret_cast<LPARAM>(text), | ||
1242 | SMTO_ABORTIFHUNG, 2000, &dwResult); | ||
1243 | } | ||
1244 | |||
1245 | |||
1246 | //! presents a surface in the client area | ||
1247 | bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rect<s32>* src) | ||
1248 | { | ||
1249 | HWND hwnd = HWnd; | ||
1250 | if ( windowId ) | ||
1251 | hwnd = reinterpret_cast<HWND>(windowId); | ||
1252 | |||
1253 | HDC dc = GetDC(hwnd); | ||
1254 | |||
1255 | if ( dc ) | ||
1256 | { | ||
1257 | RECT rect; | ||
1258 | GetClientRect(hwnd, &rect); | ||
1259 | const void* memory = (const void *)image->lock(); | ||
1260 | |||
1261 | BITMAPV4HEADER bi; | ||
1262 | ZeroMemory (&bi, sizeof(bi)); | ||
1263 | bi.bV4Size = sizeof(BITMAPINFOHEADER); | ||
1264 | bi.bV4BitCount = (WORD)image->getBitsPerPixel(); | ||
1265 | bi.bV4Planes = 1; | ||
1266 | bi.bV4Width = image->getDimension().Width; | ||
1267 | bi.bV4Height = -((s32)image->getDimension().Height); | ||
1268 | bi.bV4V4Compression = BI_BITFIELDS; | ||
1269 | bi.bV4AlphaMask = image->getAlphaMask(); | ||
1270 | bi.bV4RedMask = image->getRedMask(); | ||
1271 | bi.bV4GreenMask = image->getGreenMask(); | ||
1272 | bi.bV4BlueMask = image->getBlueMask(); | ||
1273 | |||
1274 | if ( src ) | ||
1275 | { | ||
1276 | StretchDIBits(dc, 0,0, rect.right, rect.bottom, | ||
1277 | src->UpperLeftCorner.X, src->UpperLeftCorner.Y, | ||
1278 | src->getWidth(), src->getHeight(), | ||
1279 | memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY); | ||
1280 | } | ||
1281 | else | ||
1282 | { | ||
1283 | StretchDIBits(dc, 0,0, rect.right, rect.bottom, | ||
1284 | 0, 0, image->getDimension().Width, image->getDimension().Height, | ||
1285 | memory, (const BITMAPINFO*)(&bi), DIB_RGB_COLORS, SRCCOPY); | ||
1286 | } | ||
1287 | |||
1288 | image->unlock(); | ||
1289 | |||
1290 | ReleaseDC(hwnd, dc); | ||
1291 | } | ||
1292 | return true; | ||
1293 | } | ||
1294 | |||
1295 | |||
1296 | //! notifies the device that it should close itself | ||
1297 | void CIrrDeviceWin32::closeDevice() | ||
1298 | { | ||
1299 | MSG msg; | ||
1300 | PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); | ||
1301 | PostQuitMessage(0); | ||
1302 | PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE); | ||
1303 | if (!ExternalWindow) | ||
1304 | { | ||
1305 | DestroyWindow(HWnd); | ||
1306 | const fschar_t* ClassName = __TEXT("CIrrDeviceWin32"); | ||
1307 | HINSTANCE hInstance = GetModuleHandle(0); | ||
1308 | UnregisterClass(ClassName, hInstance); | ||
1309 | } | ||
1310 | Close=true; | ||
1311 | } | ||
1312 | |||
1313 | |||
1314 | //! returns if window is active. if not, nothing needs to be drawn | ||
1315 | bool CIrrDeviceWin32::isWindowActive() const | ||
1316 | { | ||
1317 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1318 | return (GetActiveWindow() == HWnd); | ||
1319 | } | ||
1320 | |||
1321 | |||
1322 | //! returns if window has focus | ||
1323 | bool CIrrDeviceWin32::isWindowFocused() const | ||
1324 | { | ||
1325 | bool ret = (GetFocus() == HWnd); | ||
1326 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1327 | return ret; | ||
1328 | } | ||
1329 | |||
1330 | |||
1331 | //! returns if window is minimized | ||
1332 | bool CIrrDeviceWin32::isWindowMinimized() const | ||
1333 | { | ||
1334 | WINDOWPLACEMENT plc; | ||
1335 | plc.length=sizeof(WINDOWPLACEMENT); | ||
1336 | bool ret=false; | ||
1337 | if (GetWindowPlacement(HWnd,&plc)) | ||
1338 | ret=(plc.showCmd & SW_SHOWMINIMIZED)!=0; | ||
1339 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1340 | return ret; | ||
1341 | } | ||
1342 | |||
1343 | |||
1344 | //! switches to fullscreen | ||
1345 | bool CIrrDeviceWin32::switchToFullScreen(bool reset) | ||
1346 | { | ||
1347 | if (!CreationParams.Fullscreen) | ||
1348 | return true; | ||
1349 | |||
1350 | if (reset) | ||
1351 | { | ||
1352 | if (ChangedToFullScreen) | ||
1353 | { | ||
1354 | return (ChangeDisplaySettings(&DesktopMode,0)==DISP_CHANGE_SUCCESSFUL); | ||
1355 | } | ||
1356 | else | ||
1357 | return true; | ||
1358 | } | ||
1359 | |||
1360 | // use default values from current setting | ||
1361 | |||
1362 | DEVMODE dm; | ||
1363 | memset(&dm, 0, sizeof(dm)); | ||
1364 | dm.dmSize = sizeof(dm); | ||
1365 | |||
1366 | EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm); | ||
1367 | dm.dmPelsWidth = CreationParams.WindowSize.Width; | ||
1368 | dm.dmPelsHeight = CreationParams.WindowSize.Height; | ||
1369 | dm.dmBitsPerPel = CreationParams.Bits; | ||
1370 | dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY; | ||
1371 | |||
1372 | LONG res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); | ||
1373 | if (res != DISP_CHANGE_SUCCESSFUL) | ||
1374 | { // try again without forcing display frequency | ||
1375 | dm.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; | ||
1376 | res = ChangeDisplaySettings(&dm, CDS_FULLSCREEN); | ||
1377 | } | ||
1378 | |||
1379 | bool ret = false; | ||
1380 | switch(res) | ||
1381 | { | ||
1382 | case DISP_CHANGE_SUCCESSFUL: | ||
1383 | ChangedToFullScreen = true; | ||
1384 | ret = true; | ||
1385 | break; | ||
1386 | case DISP_CHANGE_RESTART: | ||
1387 | os::Printer::log("Switch to fullscreen: The computer must be restarted in order for the graphics mode to work.", ELL_ERROR); | ||
1388 | break; | ||
1389 | case DISP_CHANGE_BADFLAGS: | ||
1390 | os::Printer::log("Switch to fullscreen: An invalid set of flags was passed in.", ELL_ERROR); | ||
1391 | break; | ||
1392 | case DISP_CHANGE_BADPARAM: | ||
1393 | os::Printer::log("Switch to fullscreen: An invalid parameter was passed in. This can include an invalid flag or combination of flags.", ELL_ERROR); | ||
1394 | break; | ||
1395 | case DISP_CHANGE_FAILED: | ||
1396 | os::Printer::log("Switch to fullscreen: The display driver failed the specified graphics mode.", ELL_ERROR); | ||
1397 | break; | ||
1398 | case DISP_CHANGE_BADMODE: | ||
1399 | os::Printer::log("Switch to fullscreen: The graphics mode is not supported.", ELL_ERROR); | ||
1400 | break; | ||
1401 | default: | ||
1402 | os::Printer::log("An unknown error occured while changing to fullscreen.", ELL_ERROR); | ||
1403 | break; | ||
1404 | } | ||
1405 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
1406 | return ret; | ||
1407 | } | ||
1408 | |||
1409 | |||
1410 | //! returns the win32 cursor control | ||
1411 | CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl() | ||
1412 | { | ||
1413 | return Win32CursorControl; | ||
1414 | } | ||
1415 | |||
1416 | |||
1417 | //! \return Returns a pointer to a list with all video modes supported | ||
1418 | //! by the gfx adapter. | ||
1419 | video::IVideoModeList* CIrrDeviceWin32::getVideoModeList() | ||
1420 | { | ||
1421 | if (!VideoModeList.getVideoModeCount()) | ||
1422 | { | ||
1423 | // enumerate video modes. | ||
1424 | DWORD i=0; | ||
1425 | DEVMODE mode; | ||
1426 | memset(&mode, 0, sizeof(mode)); | ||
1427 | mode.dmSize = sizeof(mode); | ||
1428 | |||
1429 | while (EnumDisplaySettings(NULL, i, &mode)) | ||
1430 | { | ||
1431 | VideoModeList.addMode(core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight), | ||
1432 | mode.dmBitsPerPel); | ||
1433 | |||
1434 | ++i; | ||
1435 | } | ||
1436 | |||
1437 | if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode)) | ||
1438 | VideoModeList.setDesktop(mode.dmBitsPerPel, core::dimension2d<u32>(mode.dmPelsWidth, mode.dmPelsHeight)); | ||
1439 | } | ||
1440 | |||
1441 | return &VideoModeList; | ||
1442 | } | ||
1443 | |||
1444 | typedef BOOL (WINAPI *PGPI)(DWORD, DWORD, DWORD, DWORD, PDWORD); | ||
1445 | // Needed for old windows apis | ||
1446 | // depending on the SDK version and compilers some defines might be available | ||
1447 | // or not | ||
1448 | #ifndef PRODUCT_ULTIMATE | ||
1449 | #define PRODUCT_ULTIMATE 0x00000001 | ||
1450 | #define PRODUCT_HOME_BASIC 0x00000002 | ||
1451 | #define PRODUCT_HOME_PREMIUM 0x00000003 | ||
1452 | #define PRODUCT_ENTERPRISE 0x00000004 | ||
1453 | #define PRODUCT_HOME_BASIC_N 0x00000005 | ||
1454 | #define PRODUCT_BUSINESS 0x00000006 | ||
1455 | #define PRODUCT_STARTER 0x0000000B | ||
1456 | #endif | ||
1457 | #ifndef PRODUCT_ULTIMATE_N | ||
1458 | #define PRODUCT_BUSINESS_N 0x00000010 | ||
1459 | #define PRODUCT_HOME_PREMIUM_N 0x0000001A | ||
1460 | #define PRODUCT_ENTERPRISE_N 0x0000001B | ||
1461 | #define PRODUCT_ULTIMATE_N 0x0000001C | ||
1462 | #endif | ||
1463 | #ifndef PRODUCT_STARTER_N | ||
1464 | #define PRODUCT_STARTER_N 0x0000002F | ||
1465 | #endif | ||
1466 | #ifndef PRODUCT_PROFESSIONAL | ||
1467 | #define PRODUCT_PROFESSIONAL 0x00000030 | ||
1468 | #define PRODUCT_PROFESSIONAL_N 0x00000031 | ||
1469 | #endif | ||
1470 | #ifndef PRODUCT_ULTIMATE_E | ||
1471 | #define PRODUCT_STARTER_E 0x00000042 | ||
1472 | #define PRODUCT_HOME_BASIC_E 0x00000043 | ||
1473 | #define PRODUCT_HOME_PREMIUM_E 0x00000044 | ||
1474 | #define PRODUCT_PROFESSIONAL_E 0x00000045 | ||
1475 | #define PRODUCT_ENTERPRISE_E 0x00000046 | ||
1476 | #define PRODUCT_ULTIMATE_E 0x00000047 | ||
1477 | #endif | ||
1478 | |||
1479 | void CIrrDeviceWin32::getWindowsVersion(core::stringc& out) | ||
1480 | { | ||
1481 | OSVERSIONINFOEX osvi; | ||
1482 | PGPI pGPI; | ||
1483 | BOOL bOsVersionInfoEx; | ||
1484 | |||
1485 | ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); | ||
1486 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | ||
1487 | |||
1488 | bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO*) &osvi); | ||
1489 | if (!bOsVersionInfoEx) | ||
1490 | { | ||
1491 | osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | ||
1492 | if (! GetVersionEx((OSVERSIONINFO *) &osvi)) | ||
1493 | return; | ||
1494 | } | ||
1495 | |||
1496 | switch (osvi.dwPlatformId) | ||
1497 | { | ||
1498 | case VER_PLATFORM_WIN32_NT: | ||
1499 | if (osvi.dwMajorVersion <= 4) | ||
1500 | out.append("Microsoft Windows NT "); | ||
1501 | else | ||
1502 | if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) | ||
1503 | out.append("Microsoft Windows 2000 "); | ||
1504 | else | ||
1505 | if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) | ||
1506 | out.append("Microsoft Windows XP "); | ||
1507 | else | ||
1508 | if (osvi.dwMajorVersion == 6 ) | ||
1509 | { | ||
1510 | if (osvi.dwMinorVersion == 0) | ||
1511 | { | ||
1512 | if (osvi.wProductType == VER_NT_WORKSTATION) | ||
1513 | out.append("Microsoft Windows Vista "); | ||
1514 | else | ||
1515 | out.append("Microsoft Windows Server 2008 "); | ||
1516 | } | ||
1517 | else if (osvi.dwMinorVersion == 1) | ||
1518 | { | ||
1519 | if (osvi.wProductType == VER_NT_WORKSTATION) | ||
1520 | out.append("Microsoft Windows 7 "); | ||
1521 | else | ||
1522 | out.append("Microsoft Windows Server 2008 R2 "); | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | if (bOsVersionInfoEx) | ||
1527 | { | ||
1528 | if (osvi.dwMajorVersion == 6) | ||
1529 | { | ||
1530 | DWORD dwType; | ||
1531 | pGPI = (PGPI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetProductInfo"); | ||
1532 | pGPI(osvi.dwMajorVersion, osvi.dwMinorVersion, 0, 0, &dwType); | ||
1533 | |||
1534 | switch (dwType) | ||
1535 | { | ||
1536 | case PRODUCT_ULTIMATE: | ||
1537 | case PRODUCT_ULTIMATE_E: | ||
1538 | case PRODUCT_ULTIMATE_N: | ||
1539 | out.append("Ultimate Edition "); | ||
1540 | break; | ||
1541 | case PRODUCT_PROFESSIONAL: | ||
1542 | case PRODUCT_PROFESSIONAL_E: | ||
1543 | case PRODUCT_PROFESSIONAL_N: | ||
1544 | out.append("Professional Edition "); | ||
1545 | break; | ||
1546 | case PRODUCT_HOME_BASIC: | ||
1547 | case PRODUCT_HOME_BASIC_E: | ||
1548 | case PRODUCT_HOME_BASIC_N: | ||
1549 | out.append("Home Basic Edition "); | ||
1550 | break; | ||
1551 | case PRODUCT_HOME_PREMIUM: | ||
1552 | case PRODUCT_HOME_PREMIUM_E: | ||
1553 | case PRODUCT_HOME_PREMIUM_N: | ||
1554 | out.append("Home Premium Edition "); | ||
1555 | break; | ||
1556 | case PRODUCT_ENTERPRISE: | ||
1557 | case PRODUCT_ENTERPRISE_E: | ||
1558 | case PRODUCT_ENTERPRISE_N: | ||
1559 | out.append("Enterprise Edition "); | ||
1560 | break; | ||
1561 | case PRODUCT_BUSINESS: | ||
1562 | case PRODUCT_BUSINESS_N: | ||
1563 | out.append("Business Edition "); | ||
1564 | break; | ||
1565 | case PRODUCT_STARTER: | ||
1566 | case PRODUCT_STARTER_E: | ||
1567 | case PRODUCT_STARTER_N: | ||
1568 | out.append("Starter Edition "); | ||
1569 | break; | ||
1570 | } | ||
1571 | } | ||
1572 | #ifdef VER_SUITE_ENTERPRISE | ||
1573 | else | ||
1574 | if (osvi.wProductType == VER_NT_WORKSTATION) | ||
1575 | { | ||
1576 | #ifndef __BORLANDC__ | ||
1577 | if( osvi.wSuiteMask & VER_SUITE_PERSONAL ) | ||
1578 | out.append("Personal "); | ||
1579 | else | ||
1580 | out.append("Professional "); | ||
1581 | #endif | ||
1582 | } | ||
1583 | else if (osvi.wProductType == VER_NT_SERVER) | ||
1584 | { | ||
1585 | if( osvi.wSuiteMask & VER_SUITE_DATACENTER ) | ||
1586 | out.append("DataCenter Server "); | ||
1587 | else if( osvi.wSuiteMask & VER_SUITE_ENTERPRISE ) | ||
1588 | out.append("Advanced Server "); | ||
1589 | else | ||
1590 | out.append("Server "); | ||
1591 | } | ||
1592 | #endif | ||
1593 | } | ||
1594 | else | ||
1595 | { | ||
1596 | HKEY hKey; | ||
1597 | char szProductType[80]; | ||
1598 | DWORD dwBufLen; | ||
1599 | |||
1600 | RegOpenKeyEx( HKEY_LOCAL_MACHINE, | ||
1601 | __TEXT("SYSTEM\\CurrentControlSet\\Control\\ProductOptions"), | ||
1602 | 0, KEY_QUERY_VALUE, &hKey ); | ||
1603 | RegQueryValueEx( hKey, __TEXT("ProductType"), NULL, NULL, | ||
1604 | (LPBYTE) szProductType, &dwBufLen); | ||
1605 | RegCloseKey( hKey ); | ||
1606 | |||
1607 | if (_strcmpi( "WINNT", szProductType) == 0 ) | ||
1608 | out.append("Professional "); | ||
1609 | if (_strcmpi( "LANMANNT", szProductType) == 0) | ||
1610 | out.append("Server "); | ||
1611 | if (_strcmpi( "SERVERNT", szProductType) == 0) | ||
1612 | out.append("Advanced Server "); | ||
1613 | } | ||
1614 | |||
1615 | // Display version, service pack (if any), and build number. | ||
1616 | |||
1617 | char tmp[255]; | ||
1618 | |||
1619 | if (osvi.dwMajorVersion <= 4 ) | ||
1620 | { | ||
1621 | sprintf(tmp, "version %ld.%ld %s (Build %ld)", | ||
1622 | osvi.dwMajorVersion, | ||
1623 | osvi.dwMinorVersion, | ||
1624 | irr::core::stringc(osvi.szCSDVersion).c_str(), | ||
1625 | osvi.dwBuildNumber & 0xFFFF); | ||
1626 | } | ||
1627 | else | ||
1628 | { | ||
1629 | sprintf(tmp, "%s (Build %ld)", irr::core::stringc(osvi.szCSDVersion).c_str(), | ||
1630 | osvi.dwBuildNumber & 0xFFFF); | ||
1631 | } | ||
1632 | |||
1633 | out.append(tmp); | ||
1634 | break; | ||
1635 | |||
1636 | case VER_PLATFORM_WIN32_WINDOWS: | ||
1637 | |||
1638 | if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) | ||
1639 | { | ||
1640 | out.append("Microsoft Windows 95 "); | ||
1641 | if ( osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B' ) | ||
1642 | out.append("OSR2 " ); | ||
1643 | } | ||
1644 | |||
1645 | if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) | ||
1646 | { | ||
1647 | out.append("Microsoft Windows 98 "); | ||
1648 | if ( osvi.szCSDVersion[1] == 'A' ) | ||
1649 | out.append( "SE " ); | ||
1650 | } | ||
1651 | |||
1652 | if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) | ||
1653 | out.append("Microsoft Windows Me "); | ||
1654 | |||
1655 | break; | ||
1656 | |||
1657 | case VER_PLATFORM_WIN32s: | ||
1658 | out.append("Microsoft Win32s "); | ||
1659 | break; | ||
1660 | } | ||
1661 | } | ||
1662 | |||
1663 | //! Notifies the device, that it has been resized | ||
1664 | void CIrrDeviceWin32::OnResized() | ||
1665 | { | ||
1666 | Resized = true; | ||
1667 | } | ||
1668 | |||
1669 | //! Sets if the window should be resizable in windowed mode. | ||
1670 | void CIrrDeviceWin32::setResizable(bool resize) | ||
1671 | { | ||
1672 | if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen) | ||
1673 | return; | ||
1674 | |||
1675 | LONG_PTR style = WS_POPUP; | ||
1676 | |||
1677 | if (!resize) | ||
1678 | style = WS_SYSMENU | WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; | ||
1679 | else | ||
1680 | style = WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX; | ||
1681 | |||
1682 | if (!SetWindowLongPtr(HWnd, GWL_STYLE, style)) | ||
1683 | os::Printer::log("Could not change window style."); | ||
1684 | |||
1685 | RECT clientSize; | ||
1686 | clientSize.top = 0; | ||
1687 | clientSize.left = 0; | ||
1688 | clientSize.right = getVideoDriver()->getScreenSize().Width; | ||
1689 | clientSize.bottom = getVideoDriver()->getScreenSize().Height; | ||
1690 | |||
1691 | AdjustWindowRect(&clientSize, style, FALSE); | ||
1692 | |||
1693 | const s32 realWidth = clientSize.right - clientSize.left; | ||
1694 | const s32 realHeight = clientSize.bottom - clientSize.top; | ||
1695 | |||
1696 | const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2; | ||
1697 | const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; | ||
1698 | |||
1699 | SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight, | ||
1700 | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW); | ||
1701 | |||
1702 | static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize); | ||
1703 | } | ||
1704 | |||
1705 | |||
1706 | //! Minimizes the window. | ||
1707 | void CIrrDeviceWin32::minimizeWindow() | ||
1708 | { | ||
1709 | WINDOWPLACEMENT wndpl; | ||
1710 | wndpl.length = sizeof(WINDOWPLACEMENT); | ||
1711 | GetWindowPlacement(HWnd, &wndpl); | ||
1712 | wndpl.showCmd = SW_SHOWMINNOACTIVE; | ||
1713 | SetWindowPlacement(HWnd, &wndpl); | ||
1714 | } | ||
1715 | |||
1716 | |||
1717 | //! Maximizes the window. | ||
1718 | void CIrrDeviceWin32::maximizeWindow() | ||
1719 | { | ||
1720 | WINDOWPLACEMENT wndpl; | ||
1721 | wndpl.length = sizeof(WINDOWPLACEMENT); | ||
1722 | GetWindowPlacement(HWnd, &wndpl); | ||
1723 | wndpl.showCmd = SW_SHOWMAXIMIZED; | ||
1724 | SetWindowPlacement(HWnd, &wndpl); | ||
1725 | } | ||
1726 | |||
1727 | |||
1728 | //! Restores the window to its original size. | ||
1729 | void CIrrDeviceWin32::restoreWindow() | ||
1730 | { | ||
1731 | WINDOWPLACEMENT wndpl; | ||
1732 | wndpl.length = sizeof(WINDOWPLACEMENT); | ||
1733 | GetWindowPlacement(HWnd, &wndpl); | ||
1734 | wndpl.showCmd = SW_SHOWNORMAL; | ||
1735 | SetWindowPlacement(HWnd, &wndpl); | ||
1736 | } | ||
1737 | |||
1738 | |||
1739 | bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo) | ||
1740 | { | ||
1741 | if (JoyControl) | ||
1742 | return JoyControl->activateJoysticks(joystickInfo); | ||
1743 | else | ||
1744 | return false; | ||
1745 | } | ||
1746 | |||
1747 | |||
1748 | //! Set the current Gamma Value for the Display | ||
1749 | bool CIrrDeviceWin32::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast ) | ||
1750 | { | ||
1751 | bool r; | ||
1752 | u16 ramp[3][256]; | ||
1753 | |||
1754 | calculateGammaRamp( ramp[0], red, brightness, contrast ); | ||
1755 | calculateGammaRamp( ramp[1], green, brightness, contrast ); | ||
1756 | calculateGammaRamp( ramp[2], blue, brightness, contrast ); | ||
1757 | |||
1758 | HDC dc = GetDC(0); | ||
1759 | r = SetDeviceGammaRamp ( dc, ramp ) == TRUE; | ||
1760 | ReleaseDC(HWnd, dc); | ||
1761 | return r; | ||
1762 | } | ||
1763 | |||
1764 | //! Get the current Gamma Value for the Display | ||
1765 | bool CIrrDeviceWin32::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast ) | ||
1766 | { | ||
1767 | bool r; | ||
1768 | u16 ramp[3][256]; | ||
1769 | |||
1770 | HDC dc = GetDC(0); | ||
1771 | r = GetDeviceGammaRamp ( dc, ramp ) == TRUE; | ||
1772 | ReleaseDC(HWnd, dc); | ||
1773 | |||
1774 | if ( r ) | ||
1775 | { | ||
1776 | calculateGammaFromRamp(red, ramp[0]); | ||
1777 | calculateGammaFromRamp(green, ramp[1]); | ||
1778 | calculateGammaFromRamp(blue, ramp[2]); | ||
1779 | } | ||
1780 | |||
1781 | brightness = 0.f; | ||
1782 | contrast = 0.f; | ||
1783 | |||
1784 | return r; | ||
1785 | |||
1786 | } | ||
1787 | |||
1788 | |||
1789 | //! Process system events | ||
1790 | void CIrrDeviceWin32::handleSystemMessages() | ||
1791 | { | ||
1792 | MSG msg; | ||
1793 | |||
1794 | while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | ||
1795 | { | ||
1796 | // No message translation because we don't use WM_CHAR and it would conflict with our | ||
1797 | // deadkey handling. | ||
1798 | |||
1799 | if (ExternalWindow && msg.hwnd == HWnd) | ||
1800 | WndProc(HWnd, msg.message, msg.wParam, msg.lParam); | ||
1801 | else | ||
1802 | DispatchMessage(&msg); | ||
1803 | |||
1804 | if (msg.message == WM_QUIT) | ||
1805 | Close = true; | ||
1806 | } | ||
1807 | } | ||
1808 | |||
1809 | |||
1810 | //! Remove all messages pending in the system message loop | ||
1811 | void CIrrDeviceWin32::clearSystemMessages() | ||
1812 | { | ||
1813 | MSG msg; | ||
1814 | while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) | ||
1815 | {} | ||
1816 | while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) | ||
1817 | {} | ||
1818 | } | ||
1819 | |||
1820 | // shows last error in a messagebox to help internal debugging. | ||
1821 | void CIrrDeviceWin32::ReportLastWinApiError() | ||
1822 | { | ||
1823 | // (based on code from ovidiucucu from http://www.codeguru.com/forum/showthread.php?t=318721) | ||
1824 | LPCTSTR pszCaption = __TEXT("Windows SDK Error Report"); | ||
1825 | DWORD dwError = GetLastError(); | ||
1826 | |||
1827 | if(NOERROR == dwError) | ||
1828 | { | ||
1829 | MessageBox(NULL, __TEXT("No error"), pszCaption, MB_OK); | ||
1830 | } | ||
1831 | else | ||
1832 | { | ||
1833 | const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER | | ||
1834 | FORMAT_MESSAGE_IGNORE_INSERTS | | ||
1835 | FORMAT_MESSAGE_FROM_SYSTEM; | ||
1836 | |||
1837 | LPVOID pTextBuffer = NULL; | ||
1838 | DWORD dwCount = FormatMessage(dwFormatControl, | ||
1839 | NULL, | ||
1840 | dwError, | ||
1841 | 0, | ||
1842 | (LPTSTR) &pTextBuffer, | ||
1843 | 0, | ||
1844 | NULL); | ||
1845 | if(0 != dwCount) | ||
1846 | { | ||
1847 | MessageBox(NULL, (LPCTSTR)pTextBuffer, pszCaption, MB_OK|MB_ICONERROR); | ||
1848 | LocalFree(pTextBuffer); | ||
1849 | } | ||
1850 | else | ||
1851 | { | ||
1852 | MessageBox(NULL, __TEXT("Unknown error"), pszCaption, MB_OK|MB_ICONERROR); | ||
1853 | } | ||
1854 | } | ||
1855 | } | ||
1856 | |||
1857 | // Convert an Irrlicht texture to a Windows cursor | ||
1858 | // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/ | ||
1859 | HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot) | ||
1860 | { | ||
1861 | // | ||
1862 | // create the bitmaps needed for cursors from the texture | ||
1863 | |||
1864 | HDC dc = GetDC(hwnd); | ||
1865 | HDC andDc = CreateCompatibleDC(dc); | ||
1866 | HDC xorDc = CreateCompatibleDC(dc); | ||
1867 | HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight()); | ||
1868 | HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight()); | ||
1869 | |||
1870 | HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap); | ||
1871 | HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap); | ||
1872 | |||
1873 | |||
1874 | video::ECOLOR_FORMAT format = tex->getColorFormat(); | ||
1875 | u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8; | ||
1876 | u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel; | ||
1877 | u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel; | ||
1878 | const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0); | ||
1879 | data += sourceRect.UpperLeftCorner.Y*tex->getPitch(); | ||
1880 | for ( s32 y = 0; y < sourceRect.getHeight(); ++y ) | ||
1881 | { | ||
1882 | data += bytesLeftGap; | ||
1883 | for ( s32 x = 0; x < sourceRect.getWidth(); ++x ) | ||
1884 | { | ||
1885 | video::SColor pixelCol; | ||
1886 | pixelCol.setData((const void*)data, format); | ||
1887 | data += bytesPerPixel; | ||
1888 | |||
1889 | if ( pixelCol.getAlpha() == 0 ) // transparent | ||
1890 | { | ||
1891 | SetPixel(andDc, x, y, RGB(255,255,255)); | ||
1892 | SetPixel(xorDc, x, y, RGB(0,0,0)); | ||
1893 | } | ||
1894 | else // color | ||
1895 | { | ||
1896 | SetPixel(andDc, x, y, RGB(0,0,0)); | ||
1897 | SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue())); | ||
1898 | } | ||
1899 | } | ||
1900 | data += bytesRightGap; | ||
1901 | } | ||
1902 | tex->unlock(); | ||
1903 | |||
1904 | SelectObject(andDc, oldAndBitmap); | ||
1905 | SelectObject(xorDc, oldXorBitmap); | ||
1906 | |||
1907 | DeleteDC(xorDc); | ||
1908 | DeleteDC(andDc); | ||
1909 | |||
1910 | ReleaseDC(hwnd, dc); | ||
1911 | |||
1912 | // create the cursor | ||
1913 | |||
1914 | ICONINFO iconinfo; | ||
1915 | iconinfo.fIcon = false; // type is cursor not icon | ||
1916 | iconinfo.xHotspot = hotspot.X; | ||
1917 | iconinfo.yHotspot = hotspot.Y; | ||
1918 | iconinfo.hbmMask = andBitmap; | ||
1919 | iconinfo.hbmColor = xorBitmap; | ||
1920 | |||
1921 | HCURSOR cursor = CreateIconIndirect(&iconinfo); | ||
1922 | |||
1923 | DeleteObject(andBitmap); | ||
1924 | DeleteObject(xorBitmap); | ||
1925 | |||
1926 | return cursor; | ||
1927 | } | ||
1928 | |||
1929 | |||
1930 | CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen) | ||
1931 | : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f), | ||
1932 | HWnd(hwnd), BorderX(0), BorderY(0), | ||
1933 | UseReferenceRect(false), IsVisible(true) | ||
1934 | , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0) | ||
1935 | { | ||
1936 | if (WindowSize.Width!=0) | ||
1937 | InvWindowSize.Width = 1.0f / WindowSize.Width; | ||
1938 | |||
1939 | if (WindowSize.Height!=0) | ||
1940 | InvWindowSize.Height = 1.0f / WindowSize.Height; | ||
1941 | |||
1942 | updateBorderSize(fullscreen, false); | ||
1943 | initCursors(); | ||
1944 | } | ||
1945 | |||
1946 | CIrrDeviceWin32::CCursorControl::~CCursorControl() | ||
1947 | { | ||
1948 | for ( u32 i=0; i < Cursors.size(); ++i ) | ||
1949 | { | ||
1950 | for ( u32 f=0; f < Cursors[i].Frames.size(); ++f ) | ||
1951 | { | ||
1952 | DestroyCursor(Cursors[i].Frames[f].IconHW); | ||
1953 | } | ||
1954 | } | ||
1955 | } | ||
1956 | |||
1957 | |||
1958 | void CIrrDeviceWin32::CCursorControl::initCursors() | ||
1959 | { | ||
1960 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) ); | ||
1961 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) ); | ||
1962 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) ); | ||
1963 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) ); | ||
1964 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) ); | ||
1965 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) ); | ||
1966 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) ); | ||
1967 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) ); | ||
1968 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) ); | ||
1969 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) ); | ||
1970 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) ); | ||
1971 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) ); | ||
1972 | Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) ); | ||
1973 | } | ||
1974 | |||
1975 | |||
1976 | void CIrrDeviceWin32::CCursorControl::update() | ||
1977 | { | ||
1978 | if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime ) | ||
1979 | { | ||
1980 | // 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) | ||
1981 | u32 now = Device->getTimer()->getRealTime(); | ||
1982 | u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size(); | ||
1983 | SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW ); | ||
1984 | } | ||
1985 | } | ||
1986 | |||
1987 | //! Sets the active cursor icon | ||
1988 | void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId) | ||
1989 | { | ||
1990 | if ( iconId >= (s32)Cursors.size() ) | ||
1991 | return; | ||
1992 | |||
1993 | ActiveIcon = iconId; | ||
1994 | ActiveIconStartTime = Device->getTimer()->getRealTime(); | ||
1995 | if ( Cursors[ActiveIcon].Frames.size() ) | ||
1996 | SetCursor( Cursors[ActiveIcon].Frames[0].IconHW ); | ||
1997 | } | ||
1998 | |||
1999 | |||
2000 | //! Add a custom sprite as cursor icon. | ||
2001 | gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon) | ||
2002 | { | ||
2003 | if ( icon.SpriteId >= 0 ) | ||
2004 | { | ||
2005 | CursorW32 cW32; | ||
2006 | cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; | ||
2007 | |||
2008 | for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i ) | ||
2009 | { | ||
2010 | irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; | ||
2011 | irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; | ||
2012 | irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId]; | ||
2013 | |||
2014 | HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); | ||
2015 | cW32.Frames.push_back( CursorFrameW32(hc) ); | ||
2016 | } | ||
2017 | |||
2018 | Cursors.push_back( cW32 ); | ||
2019 | return (gui::ECURSOR_ICON)(Cursors.size() - 1); | ||
2020 | } | ||
2021 | return gui::ECI_NORMAL; | ||
2022 | } | ||
2023 | |||
2024 | |||
2025 | //! replace the given cursor icon. | ||
2026 | void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon) | ||
2027 | { | ||
2028 | if ( iconId >= (s32)Cursors.size() ) | ||
2029 | return; | ||
2030 | |||
2031 | for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i ) | ||
2032 | DestroyCursor(Cursors[iconId].Frames[i].IconHW); | ||
2033 | |||
2034 | if ( icon.SpriteId >= 0 ) | ||
2035 | { | ||
2036 | CursorW32 cW32; | ||
2037 | cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime; | ||
2038 | for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i ) | ||
2039 | { | ||
2040 | irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber; | ||
2041 | irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber; | ||
2042 | irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId]; | ||
2043 | |||
2044 | HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot); | ||
2045 | cW32.Frames.push_back( CursorFrameW32(hc) ); | ||
2046 | } | ||
2047 | |||
2048 | Cursors[iconId] = cW32; | ||
2049 | } | ||
2050 | } | ||
2051 | |||
2052 | |||
2053 | //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work. | ||
2054 | core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const | ||
2055 | { | ||
2056 | core::dimension2di result; | ||
2057 | |||
2058 | result.Width = GetSystemMetrics(SM_CXCURSOR); | ||
2059 | result.Height = GetSystemMetrics(SM_CYCURSOR); | ||
2060 | |||
2061 | return result; | ||
2062 | } | ||
2063 | |||
2064 | |||
2065 | |||
2066 | } // end namespace | ||
2067 | |||
2068 | #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_ | ||