1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #include "IrrCompileConfig.h"
\r
7 #ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
\r
9 #if defined (__STRICT_ANSI__)
\r
10 #error Compiling with __STRICT_ANSI__ not supported. g++ does set this when compiling with -std=c++11 or -std=c++0x. Use instead -std=gnu++11 or -std=gnu++0x. Or use -U__STRICT_ANSI__ to disable strict ansi.
\r
13 #include "CIrrDeviceWin32.h"
\r
14 #include "IEventReceiver.h"
\r
18 #include "irrString.h"
\r
19 #include "COSOperator.h"
\r
20 #include "dimension2d.h"
\r
21 #include "IGUISpriteBank.h"
\r
22 #include <winuser.h>
\r
23 #include "SExposedVideoData.h"
\r
25 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
26 #include <mmsystem.h>
\r
28 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
29 #define DIRECTINPUT_VERSION 0x0800
\r
34 #if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
\r
35 #include "CEGLManager.h"
\r
38 #if defined(_IRR_COMPILE_WITH_OPENGL_)
\r
39 #include "CWGLManager.h"
\r
46 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
\r
47 IVideoDriver* createDirectX9Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, HWND window);
\r
50 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
51 IVideoDriver* createOpenGLDriver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
54 #ifdef _IRR_COMPILE_WITH_OGLES1_
\r
55 IVideoDriver* createOGLES1Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
58 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
59 IVideoDriver* createOGLES2Driver(const irr::SIrrlichtCreationParameters& params, io::IFileSystem* io, IContextManager* contextManager);
\r
62 } // end namespace irr
\r
66 struct SJoystickWin32Control
\r
68 CIrrDeviceWin32* Device;
\r
70 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
71 IDirectInput8* DirectInputDevice;
\r
73 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
\r
77 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
80 LPDIRECTINPUTDEVICE8 lpdijoy;
\r
87 core::array<JoystickInfo> ActiveJoysticks;
\r
90 SJoystickWin32Control(CIrrDeviceWin32* dev);
\r
91 ~SJoystickWin32Control();
\r
93 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
94 static BOOL CALLBACK EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp);
\r
95 void directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi);
\r
98 void pollJoysticks();
\r
99 bool activateJoysticks(core::array<SJoystickInfo> & joystickInfo);
\r
100 irr::core::stringc findJoystickName(int index, const JOYCAPS &caps) const;
\r
104 SJoystickWin32Control::SJoystickWin32Control(CIrrDeviceWin32* dev) : Device(dev)
\r
106 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
107 DirectInputDevice=0;
\r
108 if (DI_OK != (DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&DirectInputDevice, NULL)))
\r
110 os::Printer::log("Could not create DirectInput8 Object", ELL_WARNING);
\r
116 SJoystickWin32Control::~SJoystickWin32Control()
\r
118 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
119 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
121 LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks[joystick].lpdijoy;
\r
129 if (DirectInputDevice)
\r
130 DirectInputDevice->Release();
\r
134 #if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
\r
135 BOOL CALLBACK SJoystickWin32Control::EnumJoysticks(LPCDIDEVICEINSTANCE lpddi, LPVOID cp)
\r
137 SJoystickWin32Control* p=(SJoystickWin32Control*)cp;
\r
138 p->directInputAddJoystick(lpddi);
\r
139 return DIENUM_CONTINUE;
\r
141 void SJoystickWin32Control::directInputAddJoystick(LPCDIDEVICEINSTANCE lpddi)
\r
143 //Get the GUID of the joystuck
\r
144 const GUID guid = lpddi->guidInstance;
\r
146 JoystickInfo activeJoystick;
\r
147 activeJoystick.Index=ActiveJoysticks.size();
\r
148 activeJoystick.guid=guid;
\r
149 activeJoystick.Name=lpddi->tszProductName;
\r
150 if (FAILED(DirectInputDevice->CreateDevice(guid, &activeJoystick.lpdijoy, NULL)))
\r
152 os::Printer::log("Could not create DirectInput device", ELL_WARNING);
\r
156 activeJoystick.devcaps.dwSize=sizeof(activeJoystick.devcaps);
\r
157 if (FAILED(activeJoystick.lpdijoy->GetCapabilities(&activeJoystick.devcaps)))
\r
159 os::Printer::log("Could not create DirectInput device", ELL_WARNING);
\r
163 if (FAILED(activeJoystick.lpdijoy->SetCooperativeLevel(Device->HWnd, DISCL_BACKGROUND | DISCL_EXCLUSIVE)))
\r
165 os::Printer::log("Could not set DirectInput device cooperative level", ELL_WARNING);
\r
169 if (FAILED(activeJoystick.lpdijoy->SetDataFormat(&c_dfDIJoystick2)))
\r
171 os::Printer::log("Could not set DirectInput device data format", ELL_WARNING);
\r
175 if (FAILED(activeJoystick.lpdijoy->Acquire()))
\r
177 os::Printer::log("Could not set DirectInput cooperative level", ELL_WARNING);
\r
182 if (FAILED(activeJoystick.lpdijoy->GetDeviceState(sizeof(info),&info)))
\r
184 os::Printer::log("Could not read DirectInput device state", ELL_WARNING);
\r
188 ZeroMemory(activeJoystick.axisValid,sizeof(activeJoystick.axisValid));
\r
189 activeJoystick.axisValid[0]= (info.lX!=0) ? 1 : 0;
\r
190 activeJoystick.axisValid[1]= (info.lY!=0) ? 1 : 0;
\r
191 activeJoystick.axisValid[2]= (info.lZ!=0) ? 1 : 0;
\r
192 activeJoystick.axisValid[3]= (info.lRx!=0) ? 1 : 0;
\r
193 activeJoystick.axisValid[4]= (info.lRy!=0) ? 1 : 0;
\r
194 activeJoystick.axisValid[5]= (info.lRz!=0) ? 1 : 0;
\r
197 for (u8 i=0; i<6; i++)
\r
199 if (activeJoystick.axisValid[i])
\r
203 for (u8 i=0; i<(activeJoystick.devcaps.dwAxes)-caxis; i++)
\r
206 activeJoystick.axisValid[i+caxis]=1;
\r
209 ActiveJoysticks.push_back(activeJoystick);
\r
213 void SJoystickWin32Control::pollJoysticks()
\r
215 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
216 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
217 if(0 == ActiveJoysticks.size())
\r
223 for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
225 // needs to be reset for each joystick
\r
226 // request ALL values and POV as continuous if possible
\r
228 const DIDEVCAPS & caps = ActiveJoysticks[joystick].devcaps;
\r
229 // if no POV is available don't ask for POV values
\r
231 if (!FAILED(ActiveJoysticks[joystick].lpdijoy->GetDeviceState(sizeof(info),&info)))
\r
235 event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
\r
236 event.JoystickEvent.Joystick = (u8)joystick;
\r
238 event.JoystickEvent.POV = (u16)info.rgdwPOV[0];
\r
239 // set to undefined if no POV value was returned or the value
\r
241 if ((caps.dwPOVs==0) || (event.JoystickEvent.POV > 35900))
\r
242 event.JoystickEvent.POV = 65535;
\r
244 for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
\r
245 event.JoystickEvent.Axis[axis] = 0;
\r
250 while (dxAxis < 6 && irrAxis <caps.dwAxes)
\r
267 axisValue=info.lRx;
\r
270 axisValue=info.lRy;
\r
273 axisValue=info.lRz;
\r
276 axisValue=info.rglSlider[0];
\r
279 axisValue=info.rglSlider[1];
\r
285 if (ActiveJoysticks[joystick].axisValid[dxAxis]>0)
\r
290 s32 val=axisValue - 32768;
\r
292 if (val <-32767) val=-32767;
\r
293 if (val > 32767) val=32767;
\r
294 event.JoystickEvent.Axis[irrAxis]=(s16)(val);
\r
302 BYTE* bytebuttons=info.rgbButtons;
\r
303 for (u16 i=0; i<32; i++)
\r
305 if (bytebuttons[i] >0)
\r
307 buttons |= (1 << i);
\r
310 event.JoystickEvent.ButtonStates = buttons;
\r
312 (void)Device->postEventFromUser(event);
\r
316 if (0 == ActiveJoysticks.size())
\r
322 for(joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
324 // needs to be reset for each joystick
\r
325 // request ALL values and POV as continuous if possible
\r
326 info.dwSize = sizeof(info);
\r
327 info.dwFlags = JOY_RETURNALL|JOY_RETURNPOVCTS;
\r
328 const JOYCAPS & caps = ActiveJoysticks[joystick].Caps;
\r
329 // if no POV is available don't ask for POV values
\r
330 if (!(caps.wCaps & JOYCAPS_HASPOV))
\r
331 info.dwFlags &= ~(JOY_RETURNPOV|JOY_RETURNPOVCTS);
\r
332 if(JOYERR_NOERROR == joyGetPosEx(ActiveJoysticks[joystick].Index, &info))
\r
336 event.EventType = irr::EET_JOYSTICK_INPUT_EVENT;
\r
337 event.JoystickEvent.Joystick = (u8)joystick;
\r
339 event.JoystickEvent.POV = (u16)info.dwPOV;
\r
340 // set to undefined if no POV value was returned or the value
\r
342 if (!(info.dwFlags & JOY_RETURNPOV) || (event.JoystickEvent.POV > 35900))
\r
343 event.JoystickEvent.POV = 65535;
\r
345 for(int axis = 0; axis < SEvent::SJoystickEvent::NUMBER_OF_AXES; ++axis)
\r
346 event.JoystickEvent.Axis[axis] = 0;
\r
348 event.JoystickEvent.ButtonStates = info.dwButtons;
\r
350 switch(caps.wNumAxes)
\r
354 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] =
\r
355 (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768);
\r
358 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] =
\r
359 (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768);
\r
362 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_R] =
\r
363 (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768);
\r
366 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] =
\r
367 (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768);
\r
370 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] =
\r
371 (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768);
\r
374 event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] =
\r
375 (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768);
\r
378 (void)Device->postEventFromUser(event);
\r
382 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
385 /** This function is ported from SDL and released under zlib-license:
\r
386 * Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> */
\r
387 irr::core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYCAPS &caps) const
\r
389 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
391 // As a default use the name given in the joystick structure.
\r
392 // It is always the same name, independent of joystick.
\r
393 irr::core::stringc result(caps.szPname);
\r
395 core::stringc key = core::stringc(REGSTR_PATH_JOYCONFIG)+ "\\" + caps.szRegKey + "\\" + REGSTR_KEY_JOYCURR;
\r
396 HKEY hTopKey = HKEY_LOCAL_MACHINE;
\r
398 long regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);
\r
399 if (regresult != ERROR_SUCCESS)
\r
401 hTopKey = HKEY_CURRENT_USER;
\r
402 regresult = RegOpenKeyExA(hTopKey, key.c_str(), 0, KEY_READ, &hKey);
\r
404 if (regresult != ERROR_SUCCESS)
\r
407 /* find the registry key name for the joystick's properties */
\r
409 DWORD regsize = sizeof(regname);
\r
410 core::stringc regvalue = core::stringc("Joystick")+core::stringc(index+1) + REGSTR_VAL_JOYOEMNAME;
\r
411 regresult = RegQueryValueExA(hKey, regvalue.c_str(), 0, 0, (LPBYTE)regname, ®size);
\r
413 if (regresult != ERROR_SUCCESS)
\r
416 /* open that registry key */
\r
417 core::stringc regkey = core::stringc(REGSTR_PATH_JOYOEM) + "\\" + regname;
\r
418 regresult = RegOpenKeyExA(hTopKey, regkey.c_str(), 0, KEY_READ, &hKey);
\r
419 if (regresult != ERROR_SUCCESS)
\r
422 /* find the size for the OEM name text */
\r
423 regsize = sizeof(regvalue);
\r
424 regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
\r
426 if (regresult == ERROR_SUCCESS)
\r
429 /* allocate enough memory for the OEM name text ... */
\r
430 name = new char[regsize];
\r
433 /* ... and read it from the registry */
\r
434 regresult = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0,
\r
435 (LPBYTE)name, ®size );
\r
447 bool SJoystickWin32Control::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
\r
449 #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
450 joystickInfo.clear();
\r
451 ActiveJoysticks.clear();
\r
452 #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
\r
453 if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY )))
\r
455 os::Printer::log("Could not enum DirectInput8 controllers", ELL_WARNING);
\r
459 for(u32 joystick = 0; joystick < ActiveJoysticks.size(); ++joystick)
\r
461 JoystickInfo& activeJoystick = ActiveJoysticks[joystick];
\r
462 SJoystickInfo info;
\r
463 info.Axes=activeJoystick.devcaps.dwAxes;
\r
464 info.Buttons=activeJoystick.devcaps.dwButtons;
\r
465 info.Name=activeJoystick.Name;
\r
466 info.PovHat = (activeJoystick.devcaps.dwPOVs != 0)
\r
467 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
\r
468 joystickInfo.push_back(info);
\r
472 const u32 numberOfJoysticks = ::joyGetNumDevs();
\r
474 info.dwSize = sizeof(info);
\r
475 info.dwFlags = JOY_RETURNALL;
\r
477 JoystickInfo activeJoystick;
\r
478 SJoystickInfo returnInfo;
\r
480 joystickInfo.reallocate(numberOfJoysticks);
\r
481 ActiveJoysticks.reallocate(numberOfJoysticks);
\r
484 for(; joystick < numberOfJoysticks; ++joystick)
\r
486 if(JOYERR_NOERROR == joyGetPosEx(joystick, &info)
\r
488 JOYERR_NOERROR == joyGetDevCaps(joystick,
\r
489 &activeJoystick.Caps,
\r
490 sizeof(activeJoystick.Caps)))
\r
492 activeJoystick.Index = joystick;
\r
493 ActiveJoysticks.push_back(activeJoystick);
\r
495 returnInfo.Joystick = (u8)joystick;
\r
496 returnInfo.Axes = activeJoystick.Caps.wNumAxes;
\r
497 returnInfo.Buttons = activeJoystick.Caps.wNumButtons;
\r
498 returnInfo.Name = findJoystickName(joystick, activeJoystick.Caps);
\r
499 returnInfo.PovHat = ((activeJoystick.Caps.wCaps & JOYCAPS_HASPOV) == JOYCAPS_HASPOV)
\r
500 ? SJoystickInfo::POV_HAT_PRESENT : SJoystickInfo::POV_HAT_ABSENT;
\r
502 joystickInfo.push_back(returnInfo);
\r
506 for(joystick = 0; joystick < joystickInfo.size(); ++joystick)
\r
508 char logString[256];
\r
509 snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'",
\r
510 joystick, joystickInfo[joystick].Axes,
\r
511 joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());
\r
512 os::Printer::log(logString, ELL_INFORMATION);
\r
519 #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
\r
521 } // end namespace irr
\r
528 irr::CIrrDeviceWin32* irrDev;
\r
530 // NOTE: This is global. We can have more than one Irrlicht Device at same time.
\r
531 irr::core::array<SEnvMapper> EnvMap;
\r
533 HKL KEYBOARD_INPUT_HKL=0;
\r
536 irr::CIrrDeviceWin32* getDeviceFromHWnd(HWND hWnd)
\r
538 const irr::u32 end = EnvMap.size();
\r
539 for ( irr::u32 i=0; i < end; ++i )
\r
541 const SEnvMapper& env = EnvMap[i];
\r
542 if ( env.hWnd == hWnd )
\r
550 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
\r
552 #ifndef WHEEL_DELTA
\r
553 #define WHEEL_DELTA 120
\r
556 irr::CIrrDeviceWin32* dev = 0;
\r
559 static irr::s32 ClickCount=0;
\r
560 if (GetCapture() != hWnd && ClickCount > 0)
\r
568 irr::s32 irrMessage;
\r
571 static messageMap mouseMap[] =
\r
573 {0, WM_LBUTTONDOWN, irr::EMIE_LMOUSE_PRESSED_DOWN},
\r
574 {1, WM_LBUTTONUP, irr::EMIE_LMOUSE_LEFT_UP},
\r
575 {0, WM_RBUTTONDOWN, irr::EMIE_RMOUSE_PRESSED_DOWN},
\r
576 {1, WM_RBUTTONUP, irr::EMIE_RMOUSE_LEFT_UP},
\r
577 {0, WM_MBUTTONDOWN, irr::EMIE_MMOUSE_PRESSED_DOWN},
\r
578 {1, WM_MBUTTONUP, irr::EMIE_MMOUSE_LEFT_UP},
\r
579 {2, WM_MOUSEMOVE, irr::EMIE_MOUSE_MOVED},
\r
580 {3, WM_MOUSEWHEEL, irr::EMIE_MOUSE_WHEEL},
\r
584 // handle grouped events
\r
585 messageMap * m = mouseMap;
\r
586 while ( m->group >=0 && m->winMessage != message )
\r
589 if ( m->group >= 0 )
\r
591 if ( m->group == 0 ) // down
\r
597 if ( m->group == 1 ) // up
\r
607 event.EventType = irr::EET_MOUSE_INPUT_EVENT;
\r
608 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT) m->irrMessage;
\r
609 event.MouseInput.X = (short)LOWORD(lParam);
\r
610 event.MouseInput.Y = (short)HIWORD(lParam);
\r
611 event.MouseInput.Shift = ((LOWORD(wParam) & MK_SHIFT) != 0);
\r
612 event.MouseInput.Control = ((LOWORD(wParam) & MK_CONTROL) != 0);
\r
613 // left and right mouse buttons
\r
614 event.MouseInput.ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON);
\r
615 // middle and extra buttons
\r
616 if (wParam & MK_MBUTTON)
\r
617 event.MouseInput.ButtonStates |= irr::EMBSM_MIDDLE;
\r
618 if (wParam & MK_XBUTTON1)
\r
619 event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA1;
\r
620 if (wParam & MK_XBUTTON2)
\r
621 event.MouseInput.ButtonStates |= irr::EMBSM_EXTRA2;
\r
622 event.MouseInput.Wheel = 0.f;
\r
625 if ( m->group == 3 )
\r
627 POINT p; // fixed by jox
\r
629 ClientToScreen(hWnd, &p);
\r
630 event.MouseInput.X -= p.x;
\r
631 event.MouseInput.Y -= p.y;
\r
632 event.MouseInput.Wheel = ((irr::f32)((short)HIWORD(wParam))) / (irr::f32)WHEEL_DELTA;
\r
635 dev = getDeviceFromHWnd(hWnd);
\r
638 dev->postEventFromUser(event);
\r
640 if ( event.MouseInput.Event >= irr::EMIE_LMOUSE_PRESSED_DOWN && event.MouseInput.Event <= irr::EMIE_MMOUSE_PRESSED_DOWN )
\r
642 irr::u32 clicks = dev->checkSuccessiveClicks(event.MouseInput.X, event.MouseInput.Y, event.MouseInput.Event);
\r
645 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_DOUBLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
\r
646 dev->postEventFromUser(event);
\r
648 else if ( clicks == 3 )
\r
650 event.MouseInput.Event = (irr::EMOUSE_INPUT_EVENT)(irr::EMIE_LMOUSE_TRIPLE_CLICK + event.MouseInput.Event-irr::EMIE_LMOUSE_PRESSED_DOWN);
\r
651 dev->postEventFromUser(event);
\r
663 BeginPaint(hWnd, &ps);
\r
664 EndPaint(hWnd, &ps);
\r
668 case WM_ERASEBKGND:
\r
671 case WM_SYSKEYDOWN:
\r
678 event.EventType = irr::EET_KEY_INPUT_EVENT;
\r
679 event.KeyInput.Key = (irr::EKEY_CODE)wParam;
\r
680 event.KeyInput.PressedDown = (message==WM_KEYDOWN || message == WM_SYSKEYDOWN);
\r
682 if ( event.KeyInput.Key == irr::KEY_SHIFT )
\r
684 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );
\r
686 if ( event.KeyInput.Key == irr::KEY_CONTROL )
\r
688 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );
\r
689 // some keyboards will just return LEFT for both - left and right keys. So also check extend bit.
\r
690 if (lParam & 0x1000000)
\r
691 event.KeyInput.Key = irr::KEY_RCONTROL;
\r
693 if ( event.KeyInput.Key == irr::KEY_MENU )
\r
695 event.KeyInput.Key = (irr::EKEY_CODE)MapVirtualKey( ((lParam>>16) & 255), MAPVK_VSC_TO_VK_EX );
\r
696 if (lParam & 0x1000000)
\r
697 event.KeyInput.Key = irr::KEY_RMENU;
\r
700 GetKeyboardState(allKeys);
\r
702 event.KeyInput.Shift = ((allKeys[VK_SHIFT] & 0x80)!=0);
\r
703 event.KeyInput.Control = ((allKeys[VK_CONTROL] & 0x80)!=0);
\r
705 // Handle unicode and deadkeys
\r
707 UINT scanCode = HIWORD(lParam);
\r
708 int conversionResult = ToUnicodeEx(static_cast<UINT>(wParam),scanCode,allKeys,keyChars,2,0,KEYBOARD_INPUT_HKL);
\r
709 if (conversionResult == 1)
\r
710 event.KeyInput.Char = keyChars[0];
\r
712 event.KeyInput.Char = 0;
\r
714 // allow composing characters like '@' with Alt Gr on non-US keyboards
\r
715 if ((allKeys[VK_MENU] & 0x80) != 0)
\r
716 event.KeyInput.Control = 0;
\r
718 dev = getDeviceFromHWnd(hWnd);
\r
720 dev->postEventFromUser(event);
\r
722 if (message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
\r
723 return DefWindowProcW(hWnd, message, wParam, lParam);
\r
731 dev = getDeviceFromHWnd(hWnd);
\r
738 PostQuitMessage(0);
\r
741 case WM_SYSCOMMAND:
\r
742 // prevent screensaver or monitor powersave mode from starting
\r
743 if ((wParam & 0xFFF0) == SC_SCREENSAVE ||
\r
744 (wParam & 0xFFF0) == SC_MONITORPOWER ||
\r
745 (wParam & 0xFFF0) == SC_KEYMENU
\r
752 event.EventType = irr::EET_USER_EVENT;
\r
753 event.UserEvent.UserData1 = static_cast<size_t>(wParam);
\r
754 event.UserEvent.UserData2 = static_cast<size_t>(lParam);
\r
755 dev = getDeviceFromHWnd(hWnd);
\r
758 dev->postEventFromUser(event);
\r
763 // because Windows forgot about that in the meantime
\r
764 dev = getDeviceFromHWnd(hWnd);
\r
767 dev->getCursorControl()->setActiveIcon( dev->getCursorControl()->getActiveIcon() );
\r
768 dev->getCursorControl()->setVisible( dev->getCursorControl()->isVisible() );
\r
772 case WM_INPUTLANGCHANGE:
\r
773 // get the new codepage used for keyboard input
\r
774 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
\r
777 return DefWindowProcW(hWnd, message, wParam, lParam);
\r
785 CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params)
\r
786 : CIrrDeviceStub(params), HWnd(0), Resized(false),
\r
787 ExternalWindow(false), Win32CursorControl(0), JoyControl(0),
\r
788 WindowMaximized(params.WindowMaximized)
\r
791 setDebugName("CIrrDeviceWin32");
\r
794 // get windows version and create OS operator
\r
795 core::stringc winversion;
\r
796 getWindowsVersion(winversion);
\r
797 Operator = new COSOperator(winversion);
\r
798 os::Printer::log(winversion.c_str(), ELL_INFORMATION);
\r
800 // get handle to exe file
\r
801 HINSTANCE hInstance = GetModuleHandle(0);
\r
803 // create the window if we need to and we do not use the null device
\r
804 if (!CreationParams.WindowId && CreationParams.DriverType != video::EDT_NULL)
\r
806 const wchar_t* ClassName = L"CIrrDeviceWin32";
\r
810 wcex.cbSize = sizeof(WNDCLASSEXW);
\r
811 wcex.style = CS_HREDRAW | CS_VREDRAW;
\r
812 wcex.lpfnWndProc = WndProc;
\r
813 wcex.cbClsExtra = 0;
\r
814 wcex.cbWndExtra = 0;
\r
815 wcex.hInstance = hInstance;
\r
817 wcex.hCursor = 0; // LoadCursor(NULL, IDC_ARROW);
\r
818 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
\r
819 wcex.lpszMenuName = 0;
\r
820 wcex.lpszClassName = ClassName;
\r
823 // if there is an icon, load it
\r
824 wcex.hIcon = (HICON)LoadImageW(hInstance, L"irrlicht.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
\r
826 RegisterClassExW(&wcex);
\r
828 // calculate client size
\r
831 clientSize.top = 0;
\r
832 clientSize.left = 0;
\r
833 clientSize.right = CreationParams.WindowSize.Width;
\r
834 clientSize.bottom = CreationParams.WindowSize.Height;
\r
836 DWORD style = getWindowStyle(CreationParams.Fullscreen, CreationParams.WindowResizable > 0 ? true : false);
\r
837 AdjustWindowRect(&clientSize, style, FALSE);
\r
839 const s32 realWidth = clientSize.right - clientSize.left;
\r
840 const s32 realHeight = clientSize.bottom - clientSize.top;
\r
842 s32 windowLeft = (CreationParams.WindowPosition.X == -1 ?
\r
843 (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2 :
\r
844 CreationParams.WindowPosition.X);
\r
845 s32 windowTop = (CreationParams.WindowPosition.Y == -1 ?
\r
846 (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2 :
\r
847 CreationParams.WindowPosition.Y);
\r
849 if ( windowLeft < 0 )
\r
851 if ( windowTop < 0 )
\r
852 windowTop = 0; // make sure window menus are in screen on creation
\r
854 if (CreationParams.Fullscreen)
\r
861 HWnd = CreateWindowW( ClassName, L"", style, windowLeft, windowTop,
\r
862 realWidth, realHeight, NULL, NULL, hInstance, NULL);
\r
865 os::Printer::log("Window could not be created.", ELL_ERROR);
\r
868 CreationParams.WindowId = HWnd;
\r
869 // CreationParams.WindowSize.Width = realWidth;
\r
870 // CreationParams.WindowSize.Height = realHeight;
\r
872 ShowWindow(HWnd, SW_SHOWNORMAL);
\r
873 UpdateWindow(HWnd);
\r
875 // fix ugly ATI driver bugs. Thanks to ariaci
\r
876 MoveWindow(HWnd, windowLeft, windowTop, realWidth, realHeight, TRUE);
\r
878 // make sure everything gets updated to the real sizes
\r
881 else if (CreationParams.WindowId)
\r
883 // attach external window
\r
884 HWnd = static_cast<HWND>(CreationParams.WindowId);
\r
886 GetWindowRect(HWnd, &r);
\r
887 CreationParams.WindowSize.Width = r.right - r.left;
\r
888 CreationParams.WindowSize.Height = r.bottom - r.top;
\r
889 CreationParams.Fullscreen = false;
\r
890 ExternalWindow = true;
\r
893 // create cursor control
\r
895 Win32CursorControl = new CCursorControl(this, CreationParams.WindowSize, HWnd, CreationParams.Fullscreen);
\r
896 CursorControl = Win32CursorControl;
\r
897 JoyControl = new SJoystickWin32Control(this);
\r
899 // initialize doubleclicks with system values
\r
900 MouseMultiClicks.DoubleClickTime = GetDoubleClickTime();
\r
907 createGUIAndScene();
\r
909 // register environment
\r
914 EnvMap.push_back(em);
\r
916 // set this as active window
\r
917 if (!ExternalWindow)
\r
919 SetActiveWindow(HWnd);
\r
920 SetForegroundWindow(HWnd);
\r
923 KEYBOARD_INPUT_HKL = GetKeyboardLayout(0);
\r
925 // inform driver about the window size etc.
\r
926 resizeIfNecessary();
\r
928 if (params.WindowMaximized)
\r
934 CIrrDeviceWin32::~CIrrDeviceWin32()
\r
938 // unregister environment
\r
939 for (u32 i=0; i< EnvMap.size(); ++i)
\r
941 if (EnvMap[i].hWnd == HWnd)
\r
950 //! create the driver
\r
951 void CIrrDeviceWin32::createDriver()
\r
953 switch(CreationParams.DriverType)
\r
955 case video::DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS:
\r
956 os::Printer::log("DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one.", ELL_ERROR);
\r
958 case video::EDT_DIRECT3D9:
\r
959 #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
\r
960 VideoDriver = video::createDirectX9Driver(CreationParams, FileSystem, HWnd);
\r
963 os::Printer::log("Could not create DIRECT3D9 Driver.", ELL_ERROR);
\r
965 os::Printer::log("DIRECT3D9 Driver was not compiled into this dll. Try another one.", ELL_ERROR);
\r
968 case video::EDT_OPENGL:
\r
969 #ifdef _IRR_COMPILE_WITH_OPENGL_
\r
970 switchToFullScreen();
\r
972 ContextManager = new video::CWGLManager();
\r
973 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
\r
975 VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager);
\r
978 os::Printer::log("Could not create OpenGL driver.", ELL_ERROR);
\r
980 os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR);
\r
983 case video::EDT_OGLES1:
\r
984 #ifdef _IRR_COMPILE_WITH_OGLES1_
\r
985 switchToFullScreen();
\r
987 ContextManager = new video::CEGLManager();
\r
988 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
\r
990 VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager);
\r
993 os::Printer::log("Could not create OpenGL-ES1 driver.", ELL_ERROR);
\r
995 os::Printer::log("OpenGL-ES1 driver was not compiled in.", ELL_ERROR);
\r
998 case video::EDT_OGLES2:
\r
999 #ifdef _IRR_COMPILE_WITH_OGLES2_
\r
1000 switchToFullScreen();
\r
1002 ContextManager = new video::CEGLManager();
\r
1003 ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd));
\r
1005 VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager);
\r
1008 os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR);
\r
1010 os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR);
\r
1013 case video::EDT_WEBGL1:
\r
1014 os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR);
\r
1016 case video::EDT_NULL:
\r
1017 VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize);
\r
1020 os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR);
\r
1026 //! runs the device. Returns false if device wants to be deleted
\r
1027 bool CIrrDeviceWin32::run()
\r
1029 os::Timer::tick();
\r
1031 static_cast<CCursorControl*>(CursorControl)->update();
\r
1033 handleSystemMessages();
\r
1036 resizeIfNecessary();
\r
1038 if(!Close && JoyControl)
\r
1039 JoyControl->pollJoysticks();
\r
1045 //! Pause the current process for the minimum time allowed only to allow other processes to execute
\r
1046 void CIrrDeviceWin32::yield()
\r
1051 //! Pause execution and let other processes to run for a specified amount of time.
\r
1052 void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer)
\r
1054 const bool wasStopped = Timer ? Timer->isStopped() : true;
\r
1055 if (pauseTimer && !wasStopped)
\r
1060 if (pauseTimer && !wasStopped)
\r
1065 void CIrrDeviceWin32::resizeIfNecessary()
\r
1067 if (!Resized || !getVideoDriver())
\r
1071 GetClientRect(HWnd, &r);
\r
1075 if (r.right < 2 || r.bottom < 2)
\r
1077 snprintf_irr(tmp, sizeof(tmp), "Ignoring resize operation to (%ld %ld)", r.right, r.bottom);
\r
1078 os::Printer::log(tmp);
\r
1082 snprintf_irr(tmp, sizeof(tmp), "Resizing window (%ld %ld)", r.right, r.bottom);
\r
1083 os::Printer::log(tmp);
\r
1085 getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom));
\r
1086 getWin32CursorControl()->OnResize(getVideoDriver()->getScreenSize());
\r
1093 DWORD CIrrDeviceWin32::getWindowStyle(bool fullscreen, bool resizable) const
\r
1099 return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
\r
1101 return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
\r
1104 //! sets the caption of the window
\r
1105 void CIrrDeviceWin32::setWindowCaption(const wchar_t* text)
\r
1107 // We use SendMessage instead of SetText to ensure proper
\r
1108 // function even in cases where the HWND was created in a different thread
\r
1109 DWORD_PTR dwResult;
\r
1110 SendMessageTimeoutW(HWnd, WM_SETTEXT, 0,
\r
1111 reinterpret_cast<LPARAM>(text),
\r
1112 SMTO_ABORTIFHUNG, 2000, &dwResult);
\r
1116 //! notifies the device that it should close itself
\r
1117 void CIrrDeviceWin32::closeDevice()
\r
1119 if (!ExternalWindow)
\r
1122 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
\r
1123 PostQuitMessage(0);
\r
1124 PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);
\r
1125 DestroyWindow(HWnd);
\r
1126 const wchar_t* ClassName = L"CIrrDeviceWin32";
\r
1127 HINSTANCE hInstance = GetModuleHandle(0);
\r
1128 UnregisterClassW(ClassName, hInstance);
\r
1134 //! returns if window is active. if not, nothing needs to be drawn
\r
1135 bool CIrrDeviceWin32::isWindowActive() const
\r
1137 return (GetActiveWindow() == HWnd);
\r
1141 //! returns if window has focus
\r
1142 bool CIrrDeviceWin32::isWindowFocused() const
\r
1144 bool ret = (GetFocus() == HWnd);
\r
1149 //! returns if window is minimized
\r
1150 bool CIrrDeviceWin32::isWindowMinimized() const
\r
1152 WINDOWPLACEMENT plc;
\r
1153 plc.length=sizeof(WINDOWPLACEMENT);
\r
1155 if (GetWindowPlacement(HWnd,&plc))
\r
1156 ret = plc.showCmd == SW_SHOWMINIMIZED;
\r
1161 //! returns last state from maximizeWindow() and restoreWindow()
\r
1162 bool CIrrDeviceWin32::isWindowMaximized() const
\r
1164 return WindowMaximized;
\r
1168 //! switches to fullscreen
\r
1169 bool CIrrDeviceWin32::switchToFullScreen()
\r
1171 if (!CreationParams.Fullscreen)
\r
1174 // No border, title bar, etc. is already set up through getWindowStyle()
\r
1175 // We only set the window size to match the monitor.
\r
1178 mi.cbSize = sizeof(mi);
\r
1179 if (GetMonitorInfo(MonitorFromWindow(HWnd,MONITOR_DEFAULTTOPRIMARY),&mi))
\r
1181 UINT flags = SWP_NOCOPYBITS|SWP_NOOWNERZORDER|SWP_FRAMECHANGED;
\r
1182 SetWindowPos(HWnd, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
\r
1183 mi.rcMonitor.right - mi.rcMonitor.left,
\r
1184 mi.rcMonitor.bottom - mi.rcMonitor.top, flags);
\r
1188 CreationParams.Fullscreen = false;
\r
1191 return CreationParams.Fullscreen;
\r
1195 //! returns the win32 cursor control
\r
1196 CIrrDeviceWin32::CCursorControl* CIrrDeviceWin32::getWin32CursorControl()
\r
1198 return Win32CursorControl;
\r
1201 void CIrrDeviceWin32::getWindowsVersion(core::stringc& out)
\r
1203 OSVERSIONINFO osvi;
\r
1205 ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
\r
1206 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
\r
1207 GetVersionEx(&osvi);
\r
1210 snprintf(tmp, sizeof(tmp), "Microsoft Windows %lu.%lu %s", osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.szCSDVersion);
\r
1214 //! Notifies the device, that it has been resized
\r
1215 void CIrrDeviceWin32::OnResized()
\r
1220 //! Resize the render window.
\r
1221 void CIrrDeviceWin32::setWindowSize(const irr::core::dimension2d<u32>& size)
\r
1223 if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
\r
1226 // get size of the window for the give size of the client area
\r
1227 DWORD style = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_STYLE));
\r
1228 DWORD exStyle = static_cast<DWORD>(GetWindowLongPtr(HWnd, GWL_EXSTYLE));
\r
1230 clientSize.top = 0;
\r
1231 clientSize.left = 0;
\r
1232 clientSize.right = size.Width;
\r
1233 clientSize.bottom = size.Height;
\r
1234 AdjustWindowRectEx(&clientSize, style, false, exStyle);
\r
1235 const s32 realWidth = clientSize.right - clientSize.left;
\r
1236 const s32 realHeight = clientSize.bottom - clientSize.top;
\r
1238 UINT flags = SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
\r
1239 SetWindowPos(HWnd, HWND_TOP, 0, 0, realWidth, realHeight, flags);
\r
1242 //! Sets if the window should be resizable in windowed mode.
\r
1243 void CIrrDeviceWin32::setResizable(bool resize)
\r
1245 if (ExternalWindow || !getVideoDriver() || CreationParams.Fullscreen)
\r
1248 LONG_PTR style = (LONG_PTR)getWindowStyle(false, resize);
\r
1249 if (!SetWindowLongPtr(HWnd, GWL_STYLE, style))
\r
1250 os::Printer::log("Could not change window style.");
\r
1253 clientSize.top = 0;
\r
1254 clientSize.left = 0;
\r
1255 clientSize.right = getVideoDriver()->getScreenSize().Width;
\r
1256 clientSize.bottom = getVideoDriver()->getScreenSize().Height;
\r
1258 AdjustWindowRect(&clientSize, static_cast<DWORD>(style), FALSE);
\r
1260 const s32 realWidth = clientSize.right - clientSize.left;
\r
1261 const s32 realHeight = clientSize.bottom - clientSize.top;
\r
1263 const s32 windowLeft = (GetSystemMetrics(SM_CXSCREEN) - realWidth) / 2;
\r
1264 const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2;
\r
1266 SetWindowPos(HWnd, HWND_TOP, windowLeft, windowTop, realWidth, realHeight,
\r
1267 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW);
\r
1269 static_cast<CCursorControl*>(CursorControl)->updateBorderSize(CreationParams.Fullscreen, resize);
\r
1273 //! Minimizes the window.
\r
1274 void CIrrDeviceWin32::minimizeWindow()
\r
1276 WINDOWPLACEMENT wndpl;
\r
1277 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1278 GetWindowPlacement(HWnd, &wndpl);
\r
1279 wndpl.showCmd = SW_SHOWMINNOACTIVE;
\r
1280 SetWindowPlacement(HWnd, &wndpl);
\r
1284 //! Maximizes the window.
\r
1285 void CIrrDeviceWin32::maximizeWindow()
\r
1287 WINDOWPLACEMENT wndpl;
\r
1288 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1289 GetWindowPlacement(HWnd, &wndpl);
\r
1290 wndpl.showCmd = SW_SHOWMAXIMIZED;
\r
1291 SetWindowPlacement(HWnd, &wndpl);
\r
1293 WindowMaximized = true;
\r
1297 //! Restores the window to its original size.
\r
1298 void CIrrDeviceWin32::restoreWindow()
\r
1300 WINDOWPLACEMENT wndpl;
\r
1301 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1302 GetWindowPlacement(HWnd, &wndpl);
\r
1303 wndpl.showCmd = SW_SHOWNORMAL;
\r
1304 SetWindowPlacement(HWnd, &wndpl);
\r
1306 WindowMaximized = false;
\r
1309 core::position2di CIrrDeviceWin32::getWindowPosition()
\r
1311 WINDOWPLACEMENT wndpl;
\r
1312 wndpl.length = sizeof(WINDOWPLACEMENT);
\r
1313 if (GetWindowPlacement(HWnd, &wndpl))
\r
1315 return core::position2di((int)wndpl.rcNormalPosition.left,
\r
1316 (int)wndpl.rcNormalPosition.top);
\r
1320 // No reason for this to happen
\r
1321 os::Printer::log("Failed to retrieve window location", ELL_ERROR);
\r
1322 return core::position2di(-1, -1);
\r
1326 bool CIrrDeviceWin32::activateJoysticks(core::array<SJoystickInfo> & joystickInfo)
\r
1329 return JoyControl->activateJoysticks(joystickInfo);
\r
1335 //! Process system events
\r
1336 void CIrrDeviceWin32::handleSystemMessages()
\r
1340 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
\r
1342 if (ExternalWindow && msg.hwnd == HWnd)
\r
1344 if (msg.hwnd == HWnd)
\r
1346 WndProc(HWnd, msg.message, msg.wParam, msg.lParam);
\r
1350 TranslateMessage(&msg);
\r
1351 DispatchMessage(&msg);
\r
1356 // No message translation because we don't use WM_CHAR and it would conflict with our
\r
1357 // deadkey handling.
\r
1358 DispatchMessage(&msg);
\r
1361 if (msg.message == WM_QUIT)
\r
1367 //! Remove all messages pending in the system message loop
\r
1368 void CIrrDeviceWin32::clearSystemMessages()
\r
1371 while (PeekMessage(&msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE))
\r
1373 while (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
\r
1377 // Convert an Irrlicht texture to a Windows cursor
\r
1378 // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/
\r
1379 HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect<s32>& sourceRect, const core::position2d<s32> &hotspot)
\r
1382 // create the bitmaps needed for cursors from the texture
\r
1384 HDC dc = GetDC(hwnd);
\r
1385 HDC andDc = CreateCompatibleDC(dc);
\r
1386 HDC xorDc = CreateCompatibleDC(dc);
\r
1387 HBITMAP andBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
\r
1388 HBITMAP xorBitmap = CreateCompatibleBitmap(dc, sourceRect.getWidth(), sourceRect.getHeight());
\r
1390 HBITMAP oldAndBitmap = (HBITMAP)SelectObject(andDc, andBitmap);
\r
1391 HBITMAP oldXorBitmap = (HBITMAP)SelectObject(xorDc, xorBitmap);
\r
1394 video::ECOLOR_FORMAT format = tex->getColorFormat();
\r
1395 u32 bytesPerPixel = video::IImage::getBitsPerPixelFromFormat(format) / 8;
\r
1396 u32 bytesLeftGap = sourceRect.UpperLeftCorner.X * bytesPerPixel;
\r
1397 u32 bytesRightGap = tex->getPitch() - sourceRect.LowerRightCorner.X * bytesPerPixel;
\r
1398 const u8* data = (const u8*)tex->lock(video::ETLM_READ_ONLY, 0);
\r
1399 data += sourceRect.UpperLeftCorner.Y*tex->getPitch();
\r
1400 for ( s32 y = 0; y < sourceRect.getHeight(); ++y )
\r
1402 data += bytesLeftGap;
\r
1403 for ( s32 x = 0; x < sourceRect.getWidth(); ++x )
\r
1405 video::SColor pixelCol;
\r
1406 pixelCol.setData((const void*)data, format);
\r
1407 data += bytesPerPixel;
\r
1409 if ( pixelCol.getAlpha() == 0 ) // transparent
\r
1411 SetPixel(andDc, x, y, RGB(255,255,255));
\r
1412 SetPixel(xorDc, x, y, RGB(0,0,0));
\r
1416 SetPixel(andDc, x, y, RGB(0,0,0));
\r
1417 SetPixel(xorDc, x, y, RGB(pixelCol.getRed(), pixelCol.getGreen(), pixelCol.getBlue()));
\r
1420 data += bytesRightGap;
\r
1424 SelectObject(andDc, oldAndBitmap);
\r
1425 SelectObject(xorDc, oldXorBitmap);
\r
1430 ReleaseDC(hwnd, dc);
\r
1432 // create the cursor
\r
1434 ICONINFO iconinfo;
\r
1435 iconinfo.fIcon = false; // type is cursor not icon
\r
1436 iconinfo.xHotspot = hotspot.X;
\r
1437 iconinfo.yHotspot = hotspot.Y;
\r
1438 iconinfo.hbmMask = andBitmap;
\r
1439 iconinfo.hbmColor = xorBitmap;
\r
1441 HCURSOR cursor = CreateIconIndirect(&iconinfo);
\r
1443 DeleteObject(andBitmap);
\r
1444 DeleteObject(xorBitmap);
\r
1450 CIrrDeviceWin32::CCursorControl::CCursorControl(CIrrDeviceWin32* device, const core::dimension2d<u32>& wsize, HWND hwnd, bool fullscreen)
\r
1451 : Device(device), WindowSize(wsize), InvWindowSize(0.0f, 0.0f),
\r
1452 HWnd(hwnd), BorderX(0), BorderY(0),
\r
1453 UseReferenceRect(false), IsVisible(true)
\r
1454 , ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)
\r
1456 if (WindowSize.Width!=0)
\r
1457 InvWindowSize.Width = 1.0f / WindowSize.Width;
\r
1459 if (WindowSize.Height!=0)
\r
1460 InvWindowSize.Height = 1.0f / WindowSize.Height;
\r
1462 updateBorderSize(fullscreen, false);
\r
1466 CIrrDeviceWin32::CCursorControl::~CCursorControl()
\r
1468 for ( u32 i=0; i < Cursors.size(); ++i )
\r
1470 for ( u32 f=0; f < Cursors[i].Frames.size(); ++f )
\r
1472 DestroyCursor(Cursors[i].Frames[f].IconHW);
\r
1478 void CIrrDeviceWin32::CCursorControl::initCursors()
\r
1480 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_ARROW)) );
\r
1481 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_CROSS)) );
\r
1482 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HAND)) );
\r
1483 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_HELP)) );
\r
1484 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_IBEAM)) );
\r
1485 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_NO)) );
\r
1486 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_WAIT)) );
\r
1487 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEALL)) );
\r
1488 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENESW)) );
\r
1489 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENWSE)) );
\r
1490 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZENS)) );
\r
1491 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_SIZEWE)) );
\r
1492 Cursors.push_back( CursorW32(LoadCursor(NULL, IDC_UPARROW)) );
\r
1496 void CIrrDeviceWin32::CCursorControl::update()
\r
1498 if ( !Cursors[ActiveIcon].Frames.empty() && Cursors[ActiveIcon].FrameTime )
\r
1500 // 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
1501 u32 now = Device->getTimer()->getRealTime();
\r
1502 u32 frame = ((now - ActiveIconStartTime) / Cursors[ActiveIcon].FrameTime) % Cursors[ActiveIcon].Frames.size();
\r
1503 SetCursor( Cursors[ActiveIcon].Frames[frame].IconHW );
\r
1507 //! Sets the active cursor icon
\r
1508 void CIrrDeviceWin32::CCursorControl::setActiveIcon(gui::ECURSOR_ICON iconId)
\r
1510 if ( iconId >= (s32)Cursors.size() )
\r
1513 ActiveIcon = iconId;
\r
1514 ActiveIconStartTime = Device->getTimer()->getRealTime();
\r
1515 if ( Cursors[ActiveIcon].Frames.size() )
\r
1516 SetCursor( Cursors[ActiveIcon].Frames[0].IconHW );
\r
1520 //! Add a custom sprite as cursor icon.
\r
1521 gui::ECURSOR_ICON CIrrDeviceWin32::CCursorControl::addIcon(const gui::SCursorSprite& icon)
\r
1523 if ( icon.SpriteId >= 0 )
\r
1526 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
\r
1528 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
\r
1530 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
\r
1531 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
\r
1532 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
\r
1534 HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
\r
1535 cW32.Frames.push_back( CursorFrameW32(hc) );
\r
1538 Cursors.push_back( cW32 );
\r
1539 return (gui::ECURSOR_ICON)(Cursors.size() - 1);
\r
1541 return gui::ECI_NORMAL;
\r
1545 //! replace the given cursor icon.
\r
1546 void CIrrDeviceWin32::CCursorControl::changeIcon(gui::ECURSOR_ICON iconId, const gui::SCursorSprite& icon)
\r
1548 if ( iconId >= (s32)Cursors.size() )
\r
1551 for ( u32 i=0; i < Cursors[iconId].Frames.size(); ++i )
\r
1552 DestroyCursor(Cursors[iconId].Frames[i].IconHW);
\r
1554 if ( icon.SpriteId >= 0 )
\r
1557 cW32.FrameTime = icon.SpriteBank->getSprites()[icon.SpriteId].frameTime;
\r
1558 for ( u32 i=0; i < icon.SpriteBank->getSprites()[icon.SpriteId].Frames.size(); ++i )
\r
1560 irr::u32 texId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].textureNumber;
\r
1561 irr::u32 rectId = icon.SpriteBank->getSprites()[icon.SpriteId].Frames[i].rectNumber;
\r
1562 irr::core::rect<s32> rectIcon = icon.SpriteBank->getPositions()[rectId];
\r
1564 HCURSOR hc = Device->TextureToCursor(HWnd, icon.SpriteBank->getTexture(texId), rectIcon, icon.HotSpot);
\r
1565 cW32.Frames.push_back( CursorFrameW32(hc) );
\r
1568 Cursors[iconId] = cW32;
\r
1573 //! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.
\r
1574 core::dimension2di CIrrDeviceWin32::CCursorControl::getSupportedIconSize() const
\r
1576 core::dimension2di result;
\r
1578 result.Width = GetSystemMetrics(SM_CXCURSOR);
\r
1579 result.Height = GetSystemMetrics(SM_CYCURSOR);
\r
1586 } // end namespace
\r
1588 #endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_
\r