2019-12-12 17:32:41 +01:00
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
# include "IrrCompileConfig.h"
# ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_
# if defined (__STRICT_ANSI__)
# 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.
# endif
# include "CIrrDeviceWin32.h"
# include "IEventReceiver.h"
# include "irrList.h"
# include "os.h"
# include "CTimer.h"
# include "irrString.h"
# include "COSOperator.h"
# include "dimension2d.h"
# include "IGUISpriteBank.h"
# include <winuser.h>
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
# include <mmsystem.h>
# include <regstr.h>
# ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
# define DIRECTINPUT_VERSION 0x0800
# include <dinput.h>
# ifdef _MSC_VER
# pragma comment(lib, "dinput8.lib")
# pragma comment(lib, "dxguid.lib")
# endif
# else
# ifdef _MSC_VER
# pragma comment(lib, "winmm.lib")
# endif
# endif
# endif
# if defined(_IRR_COMPILE_WITH_OPENGL_)
# include "CWGLManager.h"
# endif
namespace irr
{
namespace video
{
# ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
IVideoDriver * createDirectX9Driver ( const irr : : SIrrlichtCreationParameters & params , io : : IFileSystem * io , HWND window ) ;
# endif
# ifdef _IRR_COMPILE_WITH_OPENGL_
IVideoDriver * createOpenGLDriver ( const irr : : SIrrlichtCreationParameters & params , io : : IFileSystem * io , IContextManager * contextManager ) ;
# endif
}
} // end namespace irr
namespace irr
{
struct SJoystickWin32Control
{
CIrrDeviceWin32 * Device ;
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
IDirectInput8 * DirectInputDevice ;
# endif
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_)
struct JoystickInfo
{
u32 Index ;
# ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
core : : stringc Name ;
GUID guid ;
LPDIRECTINPUTDEVICE8 lpdijoy ;
DIDEVCAPS devcaps ;
u8 axisValid [ 8 ] ;
# else
JOYCAPS Caps ;
# endif
} ;
core : : array < JoystickInfo > ActiveJoysticks ;
# endif
SJoystickWin32Control ( CIrrDeviceWin32 * dev ) ;
~ SJoystickWin32Control ( ) ;
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
static BOOL CALLBACK EnumJoysticks ( LPCDIDEVICEINSTANCE lpddi , LPVOID cp ) ;
void directInputAddJoystick ( LPCDIDEVICEINSTANCE lpddi ) ;
# endif
void pollJoysticks ( ) ;
bool activateJoysticks ( core : : array < SJoystickInfo > & joystickInfo ) ;
irr : : core : : stringc findJoystickName ( int index , const JOYCAPS & caps ) const ;
} ;
SJoystickWin32Control : : SJoystickWin32Control ( CIrrDeviceWin32 * dev ) : Device ( dev )
{
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
DirectInputDevice = 0 ;
if ( DI_OK ! = ( DirectInput8Create ( GetModuleHandle ( NULL ) , DIRECTINPUT_VERSION , IID_IDirectInput8 , ( void * * ) & DirectInputDevice , NULL ) ) )
{
os : : Printer : : log ( " Could not create DirectInput8 Object " , ELL_WARNING ) ;
return ;
}
# endif
}
SJoystickWin32Control : : ~ SJoystickWin32Control ( )
{
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
for ( u32 joystick = 0 ; joystick < ActiveJoysticks . size ( ) ; + + joystick )
{
LPDIRECTINPUTDEVICE8 dev = ActiveJoysticks [ joystick ] . lpdijoy ;
if ( dev )
{
dev - > Unacquire ( ) ;
2022-11-19 17:41:11 +01:00
dev - > Release ( ) ;
2019-12-12 17:32:41 +01:00
}
}
if ( DirectInputDevice )
DirectInputDevice - > Release ( ) ;
# endif
}
# if defined(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) && defined(_IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_)
BOOL CALLBACK SJoystickWin32Control : : EnumJoysticks ( LPCDIDEVICEINSTANCE lpddi , LPVOID cp )
{
SJoystickWin32Control * p = ( SJoystickWin32Control * ) cp ;
p - > directInputAddJoystick ( lpddi ) ;
return DIENUM_CONTINUE ;
}
void SJoystickWin32Control : : directInputAddJoystick ( LPCDIDEVICEINSTANCE lpddi )
{
//Get the GUID of the joystuck
const GUID guid = lpddi - > guidInstance ;
JoystickInfo activeJoystick ;
activeJoystick . Index = ActiveJoysticks . size ( ) ;
activeJoystick . guid = guid ;
activeJoystick . Name = lpddi - > tszProductName ;
if ( FAILED ( DirectInputDevice - > CreateDevice ( guid , & activeJoystick . lpdijoy , NULL ) ) )
{
os : : Printer : : log ( " Could not create DirectInput device " , ELL_WARNING ) ;
return ;
}
activeJoystick . devcaps . dwSize = sizeof ( activeJoystick . devcaps ) ;
if ( FAILED ( activeJoystick . lpdijoy - > GetCapabilities ( & activeJoystick . devcaps ) ) )
{
os : : Printer : : log ( " Could not create DirectInput device " , ELL_WARNING ) ;
return ;
}
if ( FAILED ( activeJoystick . lpdijoy - > SetCooperativeLevel ( Device - > HWnd , DISCL_BACKGROUND | DISCL_EXCLUSIVE ) ) )
{
os : : Printer : : log ( " Could not set DirectInput device cooperative level " , ELL_WARNING ) ;
return ;
}
if ( FAILED ( activeJoystick . lpdijoy - > SetDataFormat ( & c_dfDIJoystick2 ) ) )
{
os : : Printer : : log ( " Could not set DirectInput device data format " , ELL_WARNING ) ;
return ;
}
if ( FAILED ( activeJoystick . lpdijoy - > Acquire ( ) ) )
{
os : : Printer : : log ( " Could not set DirectInput cooperative level " , ELL_WARNING ) ;
return ;
}
DIJOYSTATE2 info ;
if ( FAILED ( activeJoystick . lpdijoy - > GetDeviceState ( sizeof ( info ) , & info ) ) )
{
os : : Printer : : log ( " Could not read DirectInput device state " , ELL_WARNING ) ;
return ;
}
ZeroMemory ( activeJoystick . axisValid , sizeof ( activeJoystick . axisValid ) ) ;
activeJoystick . axisValid [ 0 ] = ( info . lX ! = 0 ) ? 1 : 0 ;
activeJoystick . axisValid [ 1 ] = ( info . lY ! = 0 ) ? 1 : 0 ;
activeJoystick . axisValid [ 2 ] = ( info . lZ ! = 0 ) ? 1 : 0 ;
activeJoystick . axisValid [ 3 ] = ( info . lRx ! = 0 ) ? 1 : 0 ;
activeJoystick . axisValid [ 4 ] = ( info . lRy ! = 0 ) ? 1 : 0 ;
activeJoystick . axisValid [ 5 ] = ( info . lRz ! = 0 ) ? 1 : 0 ;
int caxis = 0 ;
for ( u8 i = 0 ; i < 6 ; i + + )
{
if ( activeJoystick . axisValid [ i ] )
caxis + + ;
}
for ( u8 i = 0 ; i < ( activeJoystick . devcaps . dwAxes ) - caxis ; i + + )
{
if ( i + caxis < 8 )
activeJoystick . axisValid [ i + caxis ] = 1 ;
}
ActiveJoysticks . push_back ( activeJoystick ) ;
}
# endif
void SJoystickWin32Control : : pollJoysticks ( )
{
# if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
# ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
if ( 0 = = ActiveJoysticks . size ( ) )
return ;
u32 joystick ;
DIJOYSTATE2 info ;
for ( joystick = 0 ; joystick < ActiveJoysticks . size ( ) ; + + joystick )
{
// needs to be reset for each joystick
// request ALL values and POV as continuous if possible
const DIDEVCAPS & caps = ActiveJoysticks [ joystick ] . devcaps ;
// if no POV is available don't ask for POV values
if ( ! FAILED ( ActiveJoysticks [ joystick ] . lpdijoy - > GetDeviceState ( sizeof ( info ) , & info ) ) )
{
SEvent event ;
event . EventType = irr : : EET_JOYSTICK_INPUT_EVENT ;
event . JoystickEvent . Joystick = ( u8 ) joystick ;
event . JoystickEvent . POV = ( u16 ) info . rgdwPOV [ 0 ] ;
// set to undefined if no POV value was returned or the value
// is out of range
if ( ( caps . dwPOVs = = 0 ) | | ( event . JoystickEvent . POV > 35900 ) )
event . JoystickEvent . POV = 65535 ;
for ( int axis = 0 ; axis < SEvent : : SJoystickEvent : : NUMBER_OF_AXES ; + + axis )
event . JoystickEvent . Axis [ axis ] = 0 ;
u16 dxAxis = 0 ;
u16 irrAxis = 0 ;
while ( dxAxis < 6 & & irrAxis < caps . dwAxes )
{
bool axisFound = 0 ;
s32 axisValue = 0 ;
switch ( dxAxis )
{
case 0 :
axisValue = info . lX ;
break ;
case 1 :
axisValue = info . lY ;
break ;
case 2 :
axisValue = info . lZ ;
break ;
case 3 :
axisValue = info . lRx ;
break ;
case 4 :
axisValue = info . lRy ;
break ;
case 5 :
axisValue = info . lRz ;
break ;
case 6 :
axisValue = info . rglSlider [ 0 ] ;
break ;
case 7 :
axisValue = info . rglSlider [ 1 ] ;
break ;
default :
break ;
}
if ( ActiveJoysticks [ joystick ] . axisValid [ dxAxis ] > 0 )
axisFound = 1 ;
if ( axisFound )
{
s32 val = axisValue - 32768 ;
if ( val < - 32767 ) val = - 32767 ;
if ( val > 32767 ) val = 32767 ;
event . JoystickEvent . Axis [ irrAxis ] = ( s16 ) ( val ) ;
irrAxis + + ;
}
dxAxis + + ;
}
u32 buttons = 0 ;
BYTE * bytebuttons = info . rgbButtons ;
for ( u16 i = 0 ; i < 32 ; i + + )
{
if ( bytebuttons [ i ] > 0 )
{
buttons | = ( 1 < < i ) ;
}
}
event . JoystickEvent . ButtonStates = buttons ;
( void ) Device - > postEventFromUser ( event ) ;
}
}
# else
if ( 0 = = ActiveJoysticks . size ( ) )
return ;
u32 joystick ;
JOYINFOEX info ;
for ( joystick = 0 ; joystick < ActiveJoysticks . size ( ) ; + + joystick )
{
// needs to be reset for each joystick
// request ALL values and POV as continuous if possible
info . dwSize = sizeof ( info ) ;
info . dwFlags = JOY_RETURNALL | JOY_RETURNPOVCTS ;
const JOYCAPS & caps = ActiveJoysticks [ joystick ] . Caps ;
// if no POV is available don't ask for POV values
if ( ! ( caps . wCaps & JOYCAPS_HASPOV ) )
info . dwFlags & = ~ ( JOY_RETURNPOV | JOY_RETURNPOVCTS ) ;
if ( JOYERR_NOERROR = = joyGetPosEx ( ActiveJoysticks [ joystick ] . Index , & info ) )
{
SEvent event ;
event . EventType = irr : : EET_JOYSTICK_INPUT_EVENT ;
event . JoystickEvent . Joystick = ( u8 ) joystick ;
event . JoystickEvent . POV = ( u16 ) info . dwPOV ;
// set to undefined if no POV value was returned or the value
// is out of range
if ( ! ( info . dwFlags & JOY_RETURNPOV ) | | ( event . JoystickEvent . POV > 35900 ) )
event . JoystickEvent . POV = 65535 ;
for ( int axis = 0 ; axis < SEvent : : SJoystickEvent : : NUMBER_OF_AXES ; + + axis )
event . JoystickEvent . Axis [ axis ] = 0 ;
event . JoystickEvent . ButtonStates = info . dwButtons ;
switch ( caps . wNumAxes )
{
default :
case 6 :
event . JoystickEvent . Axis [ SEvent : : SJoystickEvent : : AXIS_V ] =
( s16 ) ( ( 65535 * ( info . dwVpos - caps . wVmin ) ) / ( caps . wVmax - caps . wVmin ) - 32768 ) ;
case 5 :
event . JoystickEvent . Axis [ SEvent : : SJoystickEvent : : AXIS_U ] =
( s16 ) ( ( 65535 * ( info . dwUpos - caps . wUmin ) ) / ( caps . wUmax - caps . wUmin ) - 32768 ) ;
case 4 :
event . JoystickEvent . Axis [ SEvent : : SJoystickEvent : : AXIS_R ] =
( s16 ) ( ( 65535 * ( info . dwRpos - caps . wRmin ) ) / ( caps . wRmax - caps . wRmin ) - 32768 ) ;
case 3 :
event . JoystickEvent . Axis [ SEvent : : SJoystickEvent : : AXIS_Z ] =
( s16 ) ( ( 65535 * ( info . dwZpos - caps . wZmin ) ) / ( caps . wZmax - caps . wZmin ) - 32768 ) ;
case 2 :
event . JoystickEvent . Axis [ SEvent : : SJoystickEvent : : AXIS_Y ] =
( s16 ) ( ( 65535 * ( info . dwYpos - caps . wYmin ) ) / ( caps . wYmax - caps . wYmin ) - 32768 ) ;
case 1 :
event . JoystickEvent . Axis [ SEvent : : SJoystickEvent : : AXIS_X ] =
( s16 ) ( ( 65535 * ( info . dwXpos - caps . wXmin ) ) / ( caps . wXmax - caps . wXmin ) - 32768 ) ;
}
( void ) Device - > postEventFromUser ( event ) ;
}
}
# endif
# endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
}
/** This function is ported from SDL and released under zlib-license:
* Copyright ( C ) 1997 - 2014 Sam Lantinga < slouken @ libsdl . org > */
irr : : core : : stringc SJoystickWin32Control : : findJoystickName ( int index , const JOYCAPS & caps ) const
{
# if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
// As a default use the name given in the joystick structure.
// It is always the same name, independent of joystick.
irr : : core : : stringc result ( caps . szPname ) ;
core : : stringc key = core : : stringc ( REGSTR_PATH_JOYCONFIG ) + " \\ " + caps . szRegKey + " \\ " + REGSTR_KEY_JOYCURR ;
HKEY hTopKey = HKEY_LOCAL_MACHINE ;
HKEY hKey ;
long regresult = RegOpenKeyExA ( hTopKey , key . c_str ( ) , 0 , KEY_READ , & hKey ) ;
if ( regresult ! = ERROR_SUCCESS )
{
hTopKey = HKEY_CURRENT_USER ;
regresult = RegOpenKeyExA ( hTopKey , key . c_str ( ) , 0 , KEY_READ , & hKey ) ;
}
if ( regresult ! = ERROR_SUCCESS )
return result ;
/* find the registry key name for the joystick's properties */
char regname [ 256 ] ;
DWORD regsize = sizeof ( regname ) ;
core : : stringc regvalue = core : : stringc ( " Joystick " ) + core : : stringc ( index + 1 ) + REGSTR_VAL_JOYOEMNAME ;
regresult = RegQueryValueExA ( hKey , regvalue . c_str ( ) , 0 , 0 , ( LPBYTE ) regname , & regsize ) ;
RegCloseKey ( hKey ) ;
if ( regresult ! = ERROR_SUCCESS )
return result ;
/* open that registry key */
core : : stringc regkey = core : : stringc ( REGSTR_PATH_JOYOEM ) + " \\ " + regname ;
regresult = RegOpenKeyExA ( hTopKey , regkey . c_str ( ) , 0 , KEY_READ , & hKey ) ;
if ( regresult ! = ERROR_SUCCESS )
return result ;
/* find the size for the OEM name text */
regsize = sizeof ( regvalue ) ;
regresult = RegQueryValueEx ( hKey , REGSTR_VAL_JOYOEMNAME , 0 , 0 ,
NULL , & regsize ) ;
if ( regresult = = ERROR_SUCCESS )
{
char * name ;
/* allocate enough memory for the OEM name text ... */
name = new char [ regsize ] ;
if ( name )
{
/* ... and read it from the registry */
regresult = RegQueryValueEx ( hKey , REGSTR_VAL_JOYOEMNAME , 0 , 0 ,
( LPBYTE ) name , & regsize ) ;
result = name ;
}
delete [ ] name ;
}
RegCloseKey ( hKey ) ;
return result ;
# endif
return " " ;
}
bool SJoystickWin32Control : : activateJoysticks ( core : : array < SJoystickInfo > & joystickInfo )
{
# if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
joystickInfo . clear ( ) ;
ActiveJoysticks . clear ( ) ;
# ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_
if ( ! DirectInputDevice | | ( DirectInputDevice - > EnumDevices ( DI8DEVCLASS_GAMECTRL , SJoystickWin32Control : : EnumJoysticks , this , DIEDFL_ATTACHEDONLY ) ) )
{
os : : Printer : : log ( " Could not enum DirectInput8 controllers " , ELL_WARNING ) ;
return false ;
}
for ( u32 joystick = 0 ; joystick < ActiveJoysticks . size ( ) ; + + joystick )
{
JoystickInfo & activeJoystick = ActiveJoysticks [ joystick ] ;
SJoystickInfo info ;
info . Axes = activeJoystick . devcaps . dwAxes ;
info . Buttons = activeJoystick . devcaps . dwButtons ;
info . Name = activeJoystick . Name ;
info . PovHat = ( activeJoystick . devcaps . dwPOVs ! = 0 )
? SJoystickInfo : : POV_HAT_PRESENT : SJoystickInfo : : POV_HAT_ABSENT ;
joystickInfo . push_back ( info ) ;
}
return true ;
# else
const u32 numberOfJoysticks = : : joyGetNumDevs ( ) ;
JOYINFOEX info ;
info . dwSize = sizeof ( info ) ;
info . dwFlags = JOY_RETURNALL ;
JoystickInfo activeJoystick ;
SJoystickInfo returnInfo ;
joystickInfo . reallocate ( numberOfJoysticks ) ;
ActiveJoysticks . reallocate ( numberOfJoysticks ) ;
u32 joystick = 0 ;
for ( ; joystick < numberOfJoysticks ; + + joystick )
{
if ( JOYERR_NOERROR = = joyGetPosEx ( joystick , & info )
& &
JOYERR_NOERROR = = joyGetDevCaps ( joystick ,
& activeJoystick . Caps ,
sizeof ( activeJoystick . Caps ) ) )
{
activeJoystick . Index = joystick ;
ActiveJoysticks . push_back ( activeJoystick ) ;
returnInfo . Joystick = ( u8 ) joystick ;
returnInfo . Axes = activeJoystick . Caps . wNumAxes ;
returnInfo . Buttons = activeJoystick . Caps . wNumButtons ;
returnInfo . Name = findJoystickName ( joystick , activeJoystick . Caps ) ;
returnInfo . PovHat = ( ( activeJoystick . Caps . wCaps & JOYCAPS_HASPOV ) = = JOYCAPS_HASPOV )
? SJoystickInfo : : POV_HAT_PRESENT : SJoystickInfo : : POV_HAT_ABSENT ;
joystickInfo . push_back ( returnInfo ) ;
}
}
for ( joystick = 0 ; joystick < joystickInfo . size ( ) ; + + joystick )
{
char logString [ 256 ] ;
( void ) sprintf ( logString , " Found joystick %d, %d axes, %d buttons '%s' " ,
joystick , joystickInfo [ joystick ] . Axes ,
joystickInfo [ joystick ] . Buttons , joystickInfo [ joystick ] . Name . c_str ( ) ) ;
os : : Printer : : log ( logString , ELL_INFORMATION ) ;
}
return true ;
# endif
# else
return false ;
# endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_
}
} // end namespace irr
// Get the codepage from the locale language id
// Based on the table from http://www.science.co.il/Language/Locale-Codes.asp?s=decimal
static unsigned int LocaleIdToCodepage ( unsigned int lcid )
{
switch ( lcid )
{
case 1098 : // Telugu
case 1095 : // Gujarati
case 1094 : // Punjabi
case 1103 : // Sanskrit
case 1111 : // Konkani
case 1114 : // Syriac
case 1099 : // Kannada
case 1102 : // Marathi
case 1125 : // Divehi
case 1067 : // Armenian
case 1081 : // Hindi
case 1079 : // Georgian
case 1097 : // Tamil
return 0 ;
case 1054 : // Thai
return 874 ;
case 1041 : // Japanese
return 932 ;
case 2052 : // Chinese (PRC)
case 4100 : // Chinese (Singapore)
return 936 ;
case 1042 : // Korean
return 949 ;
case 5124 : // Chinese (Macau S.A.R.)
case 3076 : // Chinese (Hong Kong S.A.R.)
case 1028 : // Chinese (Taiwan)
return 950 ;
case 1048 : // Romanian
case 1060 : // Slovenian
case 1038 : // Hungarian
case 1051 : // Slovak
case 1045 : // Polish
case 1052 : // Albanian
case 2074 : // Serbian (Latin)
case 1050 : // Croatian
case 1029 : // Czech
return 1250 ;
case 1104 : // Mongolian (Cyrillic)
case 1071 : // FYRO Macedonian
case 2115 : // Uzbek (Cyrillic)
case 1058 : // Ukrainian
case 2092 : // Azeri (Cyrillic)
case 1092 : // Tatar
case 1087 : // Kazakh
case 1059 : // Belarusian
case 1088 : // Kyrgyz (Cyrillic)
case 1026 : // Bulgarian
case 3098 : // Serbian (Cyrillic)
case 1049 : // Russian
return 1251 ;
case 8201 : // English (Jamaica)
case 3084 : // French (Canada)
case 1036 : // French (France)
case 5132 : // French (Luxembourg)
case 5129 : // English (New Zealand)
case 6153 : // English (Ireland)
case 1043 : // Dutch (Netherlands)
case 9225 : // English (Caribbean)
case 4108 : // French (Switzerland)
case 4105 : // English (Canada)
case 1110 : // Galician
case 10249 : // English (Belize)
case 3079 : // German (Austria)
case 6156 : // French (Monaco)
case 12297 : // English (Zimbabwe)
case 1069 : // Basque
case 2067 : // Dutch (Belgium)
case 2060 : // French (Belgium)
case 1035 : // Finnish
case 1080 : // Faroese
case 1031 : // German (Germany)
case 3081 : // English (Australia)
case 1033 : // English (United States)
case 2057 : // English (United Kingdom)
case 1027 : // Catalan
case 11273 : // English (Trinidad)
case 7177 : // English (South Africa)
case 1030 : // Danish
case 13321 : // English (Philippines)
case 15370 : // Spanish (Paraguay)
case 9226 : // Spanish (Colombia)
case 5130 : // Spanish (Costa Rica)
case 7178 : // Spanish (Dominican Republic)
case 12298 : // Spanish (Ecuador)
case 17418 : // Spanish (El Salvador)
case 4106 : // Spanish (Guatemala)
case 18442 : // Spanish (Honduras)
case 3082 : // Spanish (International Sort)
case 13322 : // Spanish (Chile)
case 19466 : // Spanish (Nicaragua)
case 2058 : // Spanish (Mexico)
case 10250 : // Spanish (Peru)
case 20490 : // Spanish (Puerto Rico)
case 1034 : // Spanish (Traditional Sort)
case 14346 : // Spanish (Uruguay)
case 8202 : // Spanish (Venezuela)
case 1089 : // Swahili
case 1053 : // Swedish
case 2077 : // Swedish (Finland)
case 5127 : // German (Liechtenstein)
case 1078 : // Afrikaans
case 6154 : // Spanish (Panama)
case 4103 : // German (Luxembourg)
case 16394 : // Spanish (Bolivia)
case 2055 : // German (Switzerland)
case 1039 : // Icelandic
case 1057 : // Indonesian
case 1040 : // Italian (Italy)
case 2064 : // Italian (Switzerland)
case 2068 : // Norwegian (Nynorsk)
case 11274 : // Spanish (Argentina)
case 1046 : // Portuguese (Brazil)
case 1044 : // Norwegian (Bokmal)
case 1086 : // Malay (Malaysia)
case 2110 : // Malay (Brunei Darussalam)
case 2070 : // Portuguese (Portugal)
return 1252 ;
case 1032 : // Greek
return 1253 ;
case 1091 : // Uzbek (Latin)
case 1068 : // Azeri (Latin)
case 1055 : // Turkish
return 1254 ;
case 1037 : // Hebrew
return 1255 ;
case 5121 : // Arabic (Algeria)
case 15361 : // Arabic (Bahrain)
case 9217 : // Arabic (Yemen)
case 3073 : // Arabic (Egypt)
case 2049 : // Arabic (Iraq)
case 11265 : // Arabic (Jordan)
case 13313 : // Arabic (Kuwait)
case 12289 : // Arabic (Lebanon)
case 4097 : // Arabic (Libya)
case 6145 : // Arabic (Morocco)
case 8193 : // Arabic (Oman)
case 16385 : // Arabic (Qatar)
case 1025 : // Arabic (Saudi Arabia)
case 10241 : // Arabic (Syria)
case 14337 : // Arabic (U.A.E.)
case 1065 : // Farsi
case 1056 : // Urdu
case 7169 : // Arabic (Tunisia)
return 1256 ;
case 1061 : // Estonian
case 1062 : // Latvian
case 1063 : // Lithuanian
return 1257 ;
case 1066 : // Vietnamese
return 1258 ;
}
return 65001 ; // utf-8
}
namespace
{
struct SEnvMapper
{
HWND hWnd ;
irr : : CIrrDeviceWin32 * irrDev ;
} ;
2019-12-12 18:31:22 +01:00
// NOTE: This is global. We can have more than one Irrlicht Device at same time.
irr : : core : : array < SEnvMapper > EnvMap ;
2019-12-12 17:32:41 +01:00
HKL KEYBOARD_INPUT_HKL = 0 ;
unsigned int KEYBOARD_INPUT_CODEPAGE = 1252 ;
}
irr : : CIrrDeviceWin32 * getDeviceFromHWnd ( HWND hWnd )
{
2019-12-12 18:31:22 +01:00
const irr : : u32 end = EnvMap . size ( ) ;
for ( irr : : u32 i = 0 ; i < end ; + + i )
{
const SEnvMapper & env = EnvMap [ i ] ;
if ( env . hWnd = = hWnd )
return env . irrDev ;
}
2019-12-12 17:32:41 +01:00
return 0 ;
}
LRESULT CALLBACK WndProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
{
# ifndef WM_MOUSEWHEEL
# define WM_MOUSEWHEEL 0x020A
# endif
# ifndef WHEEL_DELTA
# define WHEEL_DELTA 120
# endif
irr : : CIrrDeviceWin32 * dev = 0 ;
irr : : SEvent event ;
static irr : : s32 ClickCount = 0 ;
if ( GetCapture ( ) ! = hWnd & & ClickCount > 0 )
ClickCount = 0 ;
struct messageMap
{
irr : : s32 group ;
UINT winMessage ;
irr : : s32 irrMessage ;
} ;
static messageMap mouseMap [ ] =
{
{ 0 , WM_LBUTTONDOWN , irr : : EMIE_LMOUSE_PRESSED_DOWN } ,
{ 1 , WM_LBUTTONUP , irr : : EMIE_LMOUSE_LEFT_UP } ,
{ 0 , WM_RBUTTONDOWN , irr : : EMIE_RMOUSE_PRESSED_DOWN } ,
{ 1 , WM_RBUTTONUP , irr : : EMIE_RMOUSE_LEFT_UP } ,
{ 0 , WM_MBUTTONDOWN , irr : : EMIE_MMOUSE_PRESSED_DOWN } ,
{ 1 , WM_MBUTTONUP , irr : : EMIE_MMOUSE_LEFT_UP } ,
{ 2 , WM_MOUSEMOVE , irr : : EMIE_MOUSE_MOVED } ,
{ 3 , WM_MOUSEWHEEL , irr : : EMIE_MOUSE_WHEEL } ,
{ - 1 , 0 , 0 }
} ;
// handle grouped events
messageMap * m = mouseMap ;
while ( m - > group > = 0 & & m - > winMessage ! = message )
m + = 1 ;
if ( m - > group > = 0 )
{
if ( m - > group = = 0 ) // down
{
ClickCount + + ;
SetCapture ( hWnd ) ;
}
else
if ( m - > group = = 1 ) // up
{
ClickCount - - ;
if ( ClickCount < 1 )
{
ClickCount = 0 ;
ReleaseCapture ( ) ;
}
}
event . EventType = irr : : EET_MOUSE_INPUT_EVENT ;
event . MouseInput . Event = ( irr : : EMOUSE_INPUT_EVENT ) m - > irrMessage ;
event . MouseInput . X = ( short ) LOWORD ( lParam ) ;
event . MouseInput . Y = ( short ) HIWORD ( lParam ) ;
event . MouseInput . Shift = ( ( LOWORD ( wParam ) & MK_SHIFT ) ! = 0 ) ;
event . MouseInput . Control = ( ( LOWORD ( wParam ) & MK_CONTROL ) ! = 0 ) ;
// left and right mouse buttons
event . MouseInput . ButtonStates = wParam & ( MK_LBUTTON | MK_RBUTTON ) ;
// middle and extra buttons
if ( wParam & MK_MBUTTON )
event . MouseInput . ButtonStates | = irr : : EMBSM_MIDDLE ;
# if(_WIN32_WINNT >= 0x0500)
if ( wParam & MK_XBUTTON1 )
event . MouseInput . ButtonStates | = irr : : EMBSM_EXTRA1 ;
if ( wParam & MK_XBUTTON2 )
event . MouseInput . ButtonStates | = irr : : EMBSM_EXTRA2 ;
# endif
event . MouseInput . Wheel = 0.f ;
// wheel
if ( m - > group = = 3 )
{
POINT p ; // fixed by jox
p . x = 0 ; p . y = 0 ;
ClientToScreen ( hWnd , & p ) ;
event . MouseInput . X - = p . x ;
event . MouseInput . Y - = p . y ;
event . MouseInput . Wheel = ( ( irr : : f32 ) ( ( short ) HIWORD ( wParam ) ) ) / ( irr : : f32 ) WHEEL_DELTA ;
}
dev = getDeviceFromHWnd ( hWnd ) ;
if ( dev )
{
dev - > postEventFromUser ( event ) ;
if ( event . MouseInput . Event > = irr : : EMIE_LMOUSE_PRESSED_DOWN & & event . MouseInput . Event < = irr : : EMIE_MMOUSE_PRESSED_DOWN )
{
irr : : u32 clicks = dev - > checkSuccessiveClicks ( event . MouseInput . X , event . MouseInput . Y , event . MouseInput . Event ) ;
if ( clicks = = 2 )
{
event . MouseInput . Event = ( irr : : EMOUSE_INPUT_EVENT ) ( irr : : EMIE_LMOUSE_DOUBLE_CLICK + event . MouseInput . Event - irr : : EMIE_LMOUSE_PRESSED_DOWN ) ;
dev - > postEventFromUser ( event ) ;
}
else if ( clicks = = 3 )
{
event . MouseInput . Event = ( irr : : EMOUSE_INPUT_EVENT ) ( irr : : EMIE_LMOUSE_TRIPLE_CLICK + event . MouseInput . Event - irr : : EMIE_LMOUSE_PRESSED_DOWN ) ;
dev - > postEventFromUser ( event ) ;
}
}
}
return 0 ;
}
switch ( message )
{
case WM_PAINT :
{
PAINTSTRUCT ps ;
BeginPaint ( hWnd , & ps ) ;
EndPaint ( hWnd , & ps ) ;
}
return 0 ;
case WM_ERASEBKGND :
return 0 ;
case WM_SYSKEYDOWN :
case WM_SYSKEYUP :
case WM_KEYDOWN :
case WM_KEYUP :
{
BYTE allKeys [ 256 ] ;
event . EventType = irr : : EET_KEY_INPUT_EVENT ;
event . KeyInput . Key = ( irr : : EKEY_CODE ) wParam ;
event . KeyInput . PressedDown = ( message = = WM_KEYDOWN | | message = = WM_SYSKEYDOWN ) ;
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.
if ( event . KeyInput . Key = = irr : : KEY_SHIFT )
{
// this will fail on systems before windows NT/2000/XP, not sure _what_ will return there instead.
event . KeyInput . Key = ( irr : : EKEY_CODE ) MapVirtualKey ( ( ( lParam > > 16 ) & 255 ) , MY_MAPVK_VSC_TO_VK_EX ) ;
}
if ( event . KeyInput . Key = = irr : : KEY_CONTROL )
{
event . KeyInput . Key = ( irr : : EKEY_CODE ) MapVirtualKey ( ( ( lParam > > 16 ) & 255 ) , MY_MAPVK_VSC_TO_VK_EX ) ;
// some keyboards will just return LEFT for both - left and right keys. So also check extend bit.
if ( lParam & 0x1000000 )
event . KeyInput . Key = irr : : KEY_RCONTROL ;
}
if ( event . KeyInput . Key = = irr : : KEY_MENU )
{
event . KeyInput . Key = ( irr : : EKEY_CODE ) MapVirtualKey ( ( ( lParam > > 16 ) & 255 ) , MY_MAPVK_VSC_TO_VK_EX ) ;
if ( lParam & 0x1000000 )
event . KeyInput . Key = irr : : KEY_RMENU ;
}
GetKeyboardState ( allKeys ) ;
event . KeyInput . Shift = ( ( allKeys [ VK_SHIFT ] & 0x80 ) ! = 0 ) ;
event . KeyInput . Control = ( ( allKeys [ VK_CONTROL ] & 0x80 ) ! = 0 ) ;
// Handle unicode and deadkeys in a way that works since Windows 95 and nt4.0
// Using ToUnicode instead would be shorter, but would to my knowledge not run on 95 and 98.
WORD keyChars [ 2 ] ;
UINT scanCode = HIWORD ( lParam ) ;
int conversionResult = ToAsciiEx ( static_cast < UINT > ( wParam ) , scanCode , allKeys , keyChars , 0 , KEYBOARD_INPUT_HKL ) ;
if ( conversionResult = = 1 )
{
WORD unicodeChar ;
MultiByteToWideChar (
KEYBOARD_INPUT_CODEPAGE ,
MB_PRECOMPOSED , // default
( LPCSTR ) keyChars ,
sizeof ( keyChars ) ,
( WCHAR * ) & unicodeChar ,
1 ) ;
event . KeyInput . Char = unicodeChar ;
}
else
event . KeyInput . Char = 0 ;
// allow composing characters like '@' with Alt Gr on non-US keyboards
if ( ( allKeys [ VK_MENU ] & 0x80 ) ! = 0 )
event . KeyInput . Control = 0 ;
dev = getDeviceFromHWnd ( hWnd ) ;
if ( dev )
dev - > postEventFromUser ( event ) ;
if ( message = = WM_SYSKEYDOWN | | message = = WM_SYSKEYUP )
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
else
return 0 ;
}
case WM_SIZE :
{
// resize
dev = getDeviceFromHWnd ( hWnd ) ;
if ( dev )
dev - > OnResized ( ) ;
}
return 0 ;
case WM_DESTROY :
PostQuitMessage ( 0 ) ;
return 0 ;
case WM_SYSCOMMAND :
// prevent screensaver or monitor powersave mode from starting
if ( ( wParam & 0xFFF0 ) = = SC_SCREENSAVE | |
( wParam & 0xFFF0 ) = = SC_MONITORPOWER | |
( wParam & 0xFFF0 ) = = SC_KEYMENU
)
return 0 ;
break ;
case WM_ACTIVATE :
// we need to take care for screen changes, e.g. Alt-Tab
dev = getDeviceFromHWnd ( hWnd ) ;
if ( dev & & dev - > isFullscreen ( ) )
{
if ( ( wParam & 0xFF ) = = WA_INACTIVE )
{
// If losing focus we minimize the app to show other one
ShowWindow ( hWnd , SW_MINIMIZE ) ;
// and switch back to default resolution
dev - > switchToFullScreen ( true ) ;
}
else
{
// Otherwise we retore the fullscreen Irrlicht app
SetForegroundWindow ( hWnd ) ;
ShowWindow ( hWnd , SW_RESTORE ) ;
// and set the fullscreen resolution again
dev - > switchToFullScreen ( ) ;
}
}
break ;
case WM_USER :
event . EventType = irr : : EET_USER_EVENT ;
event . UserEvent . UserData1 = static_cast < size_t > ( wParam ) ;
event . UserEvent . UserData2 = static_cast < size_t > ( lParam ) ;
dev = getDeviceFromHWnd ( hWnd ) ;
if ( dev )
dev - > postEventFromUser ( event ) ;
return 0 ;
case WM_SETCURSOR :
// because Windows forgot about that in the meantime
dev = getDeviceFromHWnd ( hWnd ) ;
if ( dev )
{
dev - > getCursorControl ( ) - > setActiveIcon ( dev - > getCursorControl ( ) - > getActiveIcon ( ) ) ;
dev - > getCursorControl ( ) - > setVisible ( dev - > getCursorControl ( ) - > isVisible ( ) ) ;
}
break ;
case WM_INPUTLANGCHANGE :
// get the new codepage used for keyboard input
KEYBOARD_INPUT_HKL = GetKeyboardLayout ( 0 ) ;
KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage ( LOWORD ( KEYBOARD_INPUT_HKL ) ) ;
return 0 ;
}
return DefWindowProc ( hWnd , message , wParam , lParam ) ;
}
namespace irr
{
//! constructor
CIrrDeviceWin32 : : CIrrDeviceWin32 ( const SIrrlichtCreationParameters & params )
: CIrrDeviceStub ( params ) , HWnd ( 0 ) , ChangedToFullScreen ( false ) , Resized ( false ) ,
ExternalWindow ( false ) , Win32CursorControl ( 0 ) , JoyControl ( 0 )
{
# ifdef _DEBUG
setDebugName ( " CIrrDeviceWin32 " ) ;
# endif
// get windows version and create OS operator
core : : stringc winversion ;
getWindowsVersion ( winversion ) ;
Operator = new COSOperator ( winversion ) ;
os : : Printer : : log ( winversion . c_str ( ) , ELL_INFORMATION ) ;
// get handle to exe file
HINSTANCE hInstance = GetModuleHandle ( 0 ) ;
// Store original desktop mode.
memset ( & DesktopMode , 0 , sizeof ( DesktopMode ) ) ;
DesktopMode . dmSize = sizeof ( DesktopMode ) ;
EnumDisplaySettings ( NULL , ENUM_CURRENT_SETTINGS , & DesktopMode ) ;
// create the window if we need to and we do not use the null device
if ( ! CreationParams . WindowId & & CreationParams . DriverType ! = video : : EDT_NULL )
{
const fschar_t * ClassName = __TEXT ( " CIrrDeviceWin32 " ) ;
// Register Class
WNDCLASSEX wcex ;
wcex . cbSize = sizeof ( WNDCLASSEX ) ;
wcex . style = CS_HREDRAW | CS_VREDRAW ;
wcex . lpfnWndProc = WndProc ;
wcex . cbClsExtra = 0 ;
wcex . cbWndExtra = 0 ;
wcex . hInstance = hInstance ;
wcex . hIcon = NULL ;
wcex . hCursor = 0 ; // LoadCursor(NULL, IDC_ARROW);
wcex . hbrBackground = ( HBRUSH ) ( COLOR_WINDOW + 1 ) ;
wcex . lpszMenuName = 0 ;
wcex . lpszClassName = ClassName ;
wcex . hIconSm = 0 ;
// if there is an icon, load it
wcex . hIcon = ( HICON ) LoadImage ( hInstance , __TEXT ( " irrlicht.ico " ) , IMAGE_ICON , 0 , 0 , LR_LOADFROMFILE | LR_DEFAULTSIZE ) ;
RegisterClassEx ( & wcex ) ;
// calculate client size
RECT clientSize ;
clientSize . top = 0 ;
clientSize . left = 0 ;
clientSize . right = CreationParams . WindowSize . Width ;
clientSize . bottom = CreationParams . WindowSize . Height ;
2021-03-06 16:49:43 +01:00
DWORD style = getWindowStyle ( CreationParams . Fullscreen , CreationParams . WindowResizable > 0 ? true : false ) ;
2019-12-12 17:32:41 +01:00
AdjustWindowRect ( & clientSize , style , FALSE ) ;
const s32 realWidth = clientSize . right - clientSize . left ;
const s32 realHeight = clientSize . bottom - clientSize . top ;
s32 windowLeft = ( CreationParams . WindowPosition . X = = - 1 ?
( GetSystemMetrics ( SM_CXSCREEN ) - realWidth ) / 2 :
CreationParams . WindowPosition . X ) ;
s32 windowTop = ( CreationParams . WindowPosition . Y = = - 1 ?
( GetSystemMetrics ( SM_CYSCREEN ) - realHeight ) / 2 :
CreationParams . WindowPosition . Y ) ;
if ( windowLeft < 0 )
windowLeft = 0 ;
if ( windowTop < 0 )
windowTop = 0 ; // make sure window menus are in screen on creation
if ( CreationParams . Fullscreen )
{
windowLeft = 0 ;
windowTop = 0 ;
}
// create window
HWnd = CreateWindow ( ClassName , __TEXT ( " " ) , style , windowLeft , windowTop ,
realWidth , realHeight , NULL , NULL , hInstance , NULL ) ;
CreationParams . WindowId = HWnd ;
// CreationParams.WindowSize.Width = realWidth;
// CreationParams.WindowSize.Height = realHeight;
ShowWindow ( HWnd , SW_SHOWNORMAL ) ;
UpdateWindow ( HWnd ) ;
// fix ugly ATI driver bugs. Thanks to ariaci
MoveWindow ( HWnd , windowLeft , windowTop , realWidth , realHeight , TRUE ) ;
// make sure everything gets updated to the real sizes
Resized = true ;
}
else if ( CreationParams . WindowId )
{
// attach external window
HWnd = static_cast < HWND > ( CreationParams . WindowId ) ;
RECT r ;
GetWindowRect ( HWnd , & r ) ;
CreationParams . WindowSize . Width = r . right - r . left ;
CreationParams . WindowSize . Height = r . bottom - r . top ;
CreationParams . Fullscreen = false ;
ExternalWindow = true ;
}
// create cursor control
Win32CursorControl = new CCursorControl ( this , CreationParams . WindowSize , HWnd , CreationParams . Fullscreen ) ;
CursorControl = Win32CursorControl ;
JoyControl = new SJoystickWin32Control ( this ) ;
// initialize doubleclicks with system values
MouseMultiClicks . DoubleClickTime = GetDoubleClickTime ( ) ;
// create driver
createDriver ( ) ;
if ( VideoDriver )
createGUIAndScene ( ) ;
// register environment
SEnvMapper em ;
em . irrDev = this ;
em . hWnd = HWnd ;
EnvMap . push_back ( em ) ;
// set this as active window
if ( ! ExternalWindow )
{
SetActiveWindow ( HWnd ) ;
SetForegroundWindow ( HWnd ) ;
}
// get the codepage used for keyboard input
KEYBOARD_INPUT_HKL = GetKeyboardLayout ( 0 ) ;
KEYBOARD_INPUT_CODEPAGE = LocaleIdToCodepage ( LOWORD ( KEYBOARD_INPUT_HKL ) ) ;
// inform driver about the window size etc.
resizeIfNecessary ( ) ;
}
//! destructor
CIrrDeviceWin32 : : ~ CIrrDeviceWin32 ( )
{
delete JoyControl ;
// unregister environment
2019-12-12 18:31:22 +01:00
for ( u32 i = 0 ; i < EnvMap . size ( ) ; + + i )
2019-12-12 17:32:41 +01:00
{
2019-12-12 18:31:22 +01:00
if ( EnvMap [ i ] . hWnd = = HWnd )
2019-12-12 17:32:41 +01:00
{
2019-12-12 18:31:22 +01:00
EnvMap . erase ( i ) ;
2019-12-12 17:32:41 +01:00
break ;
}
}
switchToFullScreen ( true ) ;
}
//! create the driver
void CIrrDeviceWin32 : : createDriver ( )
{
switch ( CreationParams . DriverType )
{
case video : : DEPRECATED_EDT_DIRECT3D8_NO_LONGER_EXISTS :
os : : Printer : : log ( " DIRECT3D8 Driver is no longer supported in Irrlicht. Try another one. " , ELL_ERROR ) ;
break ;
case video : : EDT_DIRECT3D9 :
# ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
VideoDriver = video : : createDirectX9Driver ( CreationParams , FileSystem , HWnd ) ;
if ( ! VideoDriver )
os : : Printer : : log ( " Could not create DIRECT3D9 Driver. " , ELL_ERROR ) ;
# else
os : : Printer : : log ( " DIRECT3D9 Driver was not compiled into this dll. Try another one. " , ELL_ERROR ) ;
# endif
break ;
case video : : EDT_OPENGL :
# ifdef _IRR_COMPILE_WITH_OPENGL_
switchToFullScreen ( ) ;
ContextManager = new video : : CWGLManager ( ) ;
ContextManager - > initialize ( CreationParams , video : : SExposedVideoData ( HWnd ) ) ;
VideoDriver = video : : createOpenGLDriver ( CreationParams , FileSystem , ContextManager ) ;
if ( ! VideoDriver )
os : : Printer : : log ( " Could not create OpenGL driver. " , ELL_ERROR ) ;
# else
os : : Printer : : log ( " OpenGL driver was not compiled in. " , ELL_ERROR ) ;
# endif
break ;
case video : : EDT_SOFTWARE :
# ifdef _IRR_COMPILE_WITH_SOFTWARE_
switchToFullScreen ( ) ;
VideoDriver = video : : createSoftwareDriver ( CreationParams . WindowSize , CreationParams . Fullscreen , FileSystem , this ) ;
# else
os : : Printer : : log ( " Software driver was not compiled in. " , ELL_ERROR ) ;
# endif
break ;
case video : : EDT_BURNINGSVIDEO :
# ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_
switchToFullScreen ( ) ;
VideoDriver = video : : createBurningVideoDriver ( CreationParams , FileSystem , this ) ;
# else
os : : Printer : : log ( " Burning's Video driver was not compiled in. " , ELL_ERROR ) ;
# endif
break ;
case video : : EDT_NULL :
VideoDriver = video : : createNullDriver ( FileSystem , CreationParams . WindowSize ) ;
break ;
default :
os : : Printer : : log ( " Unable to create video driver of unknown type. " , ELL_ERROR ) ;
break ;
}
}
//! runs the device. Returns false if device wants to be deleted
bool CIrrDeviceWin32 : : run ( )
{
os : : Timer : : tick ( ) ;
static_cast < CCursorControl * > ( CursorControl ) - > update ( ) ;
handleSystemMessages ( ) ;
if ( ! Close )
resizeIfNecessary ( ) ;
if ( ! Close & & JoyControl )
JoyControl - > pollJoysticks ( ) ;
return ! Close ;
}
//! Pause the current process for the minimum time allowed only to allow other processes to execute
void CIrrDeviceWin32 : : yield ( )
{
2023-04-03 17:32:41 +02:00
Sleep ( 0 ) ;
2019-12-12 17:32:41 +01:00
}
//! Pause execution and let other processes to run for a specified amount of time.
void CIrrDeviceWin32 : : sleep ( u32 timeMs , bool pauseTimer )
{
const bool wasStopped = Timer ? Timer - > isStopped ( ) : true ;
if ( pauseTimer & & ! wasStopped )
Timer - > stop ( ) ;
Sleep ( timeMs ) ;
if ( pauseTimer & & ! wasStopped )
Timer - > start ( ) ;
}
void CIrrDeviceWin32 : : resizeIfNecessary ( )
{
if ( ! Resized | | ! getVideoDriver ( ) )
return ;
RECT r ;
GetClientRect ( HWnd , & r ) ;
char tmp [ 255 ] ;
if ( r . right < 2 | | r . bottom < 2 )
{
sprintf ( tmp , " Ignoring resize operation to (%ld %ld) " , r . right , r . bottom ) ;
os : : Printer : : log ( tmp ) ;
}
else
{
sprintf ( tmp , " Resizing window (%ld %ld) " , r . right , r . bottom ) ;
os : : Printer : : log ( tmp ) ;
getVideoDriver ( ) - > OnResize ( irr : : core : : dimension2du ( ( u32 ) r . right , ( u32 ) r . bottom ) ) ;
getWin32CursorControl ( ) - > OnResize ( getVideoDriver ( ) - > getScreenSize ( ) ) ;
}
Resized = false ;
}
DWORD CIrrDeviceWin32 : : getWindowStyle ( bool fullscreen , bool resizable ) const
{
if ( fullscreen )
return WS_POPUP ;
if ( resizable )
return WS_THICKFRAME | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX ;
return WS_BORDER | WS_SYSMENU | WS_CAPTION | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ;
2021-03-06 16:49:43 +01:00
}
2019-12-12 17:32:41 +01:00
//! sets the caption of the window
void CIrrDeviceWin32 : : setWindowCaption ( const wchar_t * text )
{
// We use SendMessage instead of SetText to ensure proper
// function even in cases where the HWND was created in a different thread
DWORD_PTR dwResult ;
SendMessageTimeoutW ( HWnd , WM_SETTEXT , 0 ,
reinterpret_cast < LPARAM > ( text ) ,
SMTO_ABORTIFHUNG , 2000 , & dwResult ) ;
}
//! presents a surface in the client area
bool CIrrDeviceWin32 : : present ( video : : IImage * image , void * windowId , core : : rect < s32 > * src )
{
HWND hwnd = HWnd ;
if ( windowId )
2022-01-08 19:22:20 +01:00
hwnd = static_cast < HWND > ( windowId ) ;
2019-12-12 17:32:41 +01:00
HDC dc = GetDC ( hwnd ) ;
if ( dc )
{
RECT rect ;
GetClientRect ( hwnd , & rect ) ;
const void * memory = ( const void * ) image - > getData ( ) ;
BITMAPV4HEADER bi ;
ZeroMemory ( & bi , sizeof ( bi ) ) ;
bi . bV4Size = sizeof ( BITMAPINFOHEADER ) ;
bi . bV4BitCount = ( WORD ) image - > getBitsPerPixel ( ) ;
bi . bV4Planes = 1 ;
bi . bV4Width = image - > getDimension ( ) . Width ;
bi . bV4Height = - ( ( s32 ) image - > getDimension ( ) . Height ) ;
bi . bV4V4Compression = BI_BITFIELDS ;
bi . bV4AlphaMask = image - > getAlphaMask ( ) ;
bi . bV4RedMask = image - > getRedMask ( ) ;
bi . bV4GreenMask = image - > getGreenMask ( ) ;
bi . bV4BlueMask = image - > getBlueMask ( ) ;
if ( src )
{
StretchDIBits ( dc , 0 , 0 , rect . right , rect . bottom ,
src - > UpperLeftCorner . X , src - > UpperLeftCorner . Y ,
src - > getWidth ( ) , src - > getHeight ( ) ,
memory , ( const BITMAPINFO * ) ( & bi ) , DIB_RGB_COLORS , SRCCOPY ) ;
}
else
{
StretchDIBits ( dc , 0 , 0 , rect . right , rect . bottom ,
0 , 0 , image - > getDimension ( ) . Width , image - > getDimension ( ) . Height ,
memory , ( const BITMAPINFO * ) ( & bi ) , DIB_RGB_COLORS , SRCCOPY ) ;
}
ReleaseDC ( hwnd , dc ) ;
}
return true ;
}
//! notifies the device that it should close itself
void CIrrDeviceWin32 : : closeDevice ( )
{
if ( ! ExternalWindow )
{
2020-08-11 21:17:24 +02:00
MSG msg ;
PeekMessage ( & msg , NULL , WM_QUIT , WM_QUIT , PM_REMOVE ) ;
PostQuitMessage ( 0 ) ;
PeekMessage ( & msg , NULL , WM_QUIT , WM_QUIT , PM_REMOVE ) ;
2019-12-12 17:32:41 +01:00
DestroyWindow ( HWnd ) ;
const fschar_t * ClassName = __TEXT ( " CIrrDeviceWin32 " ) ;
HINSTANCE hInstance = GetModuleHandle ( 0 ) ;
UnregisterClass ( ClassName , hInstance ) ;
}
Close = true ;
}
//! returns if window is active. if not, nothing needs to be drawn
bool CIrrDeviceWin32 : : isWindowActive ( ) const
{
return ( GetActiveWindow ( ) = = HWnd ) ;
}
//! returns if window has focus
bool CIrrDeviceWin32 : : isWindowFocused ( ) const
{
bool ret = ( GetFocus ( ) = = HWnd ) ;
return ret ;
}
//! returns if window is minimized
bool CIrrDeviceWin32 : : isWindowMinimized ( ) const
{
WINDOWPLACEMENT plc ;
plc . length = sizeof ( WINDOWPLACEMENT ) ;
bool ret = false ;
if ( GetWindowPlacement ( HWnd , & plc ) )
ret = plc . showCmd = = SW_SHOWMINIMIZED ;
return ret ;
}
//! switches to fullscreen
bool CIrrDeviceWin32 : : switchToFullScreen ( bool reset )
{
if ( ! CreationParams . Fullscreen )
return true ;
if ( reset )
{
if ( ChangedToFullScreen )
{
return ( ChangeDisplaySettings ( & DesktopMode , 0 ) = = DISP_CHANGE_SUCCESSFUL ) ;
}
else
return true ;
}
// use default values from current setting
DEVMODE dm ;
memset ( & dm , 0 , sizeof ( dm ) ) ;
dm . dmSize = sizeof ( dm ) ;
EnumDisplaySettings ( NULL , ENUM_CURRENT_SETTINGS , & dm ) ;
dm . dmPelsWidth = CreationParams . WindowSize . Width ;
dm . dmPelsHeight = CreationParams . WindowSize . Height ;
dm . dmBitsPerPel = CreationParams . Bits ;
dm . dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY ;
LONG res = ChangeDisplaySettings ( & dm , CDS_FULLSCREEN ) ;
if ( res ! = DISP_CHANGE_SUCCESSFUL )
{ // try again without forcing display frequency
dm . dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT ;
res = ChangeDisplaySettings ( & dm , CDS_FULLSCREEN ) ;
}
bool ret = false ;
switch ( res )
{
case DISP_CHANGE_SUCCESSFUL :
ChangedToFullScreen = true ;
ret = true ;
break ;
case DISP_CHANGE_RESTART :
os : : Printer : : log ( " Switch to fullscreen: The computer must be restarted in order for the graphics mode to work. " , ELL_ERROR ) ;
break ;
case DISP_CHANGE_BADFLAGS :
os : : Printer : : log ( " Switch to fullscreen: An invalid set of flags was passed in. " , ELL_ERROR ) ;
break ;
case DISP_CHANGE_BADPARAM :
os : : Printer : : log ( " Switch to fullscreen: An invalid parameter was passed in. This can include an invalid flag or combination of flags. " , ELL_ERROR ) ;
break ;
case DISP_CHANGE_FAILED :
os : : Printer : : log ( " Switch to fullscreen: The display driver failed the specified graphics mode. " , ELL_ERROR ) ;
break ;
case DISP_CHANGE_BADMODE :
os : : Printer : : log ( " Switch to fullscreen: The graphics mode is not supported. " , ELL_ERROR ) ;
break ;
default :
os : : Printer : : log ( " An unknown error occurred while changing to fullscreen. " , ELL_ERROR ) ;
break ;
}
return ret ;
}
//! returns the win32 cursor control
CIrrDeviceWin32 : : CCursorControl * CIrrDeviceWin32 : : getWin32CursorControl ( )
{
return Win32CursorControl ;
}
//! \return Returns a pointer to a list with all video modes supported
//! by the gfx adapter.
video : : IVideoModeList * CIrrDeviceWin32 : : getVideoModeList ( )
{
if ( ! VideoModeList - > getVideoModeCount ( ) )
{
// enumerate video modes.
DWORD i = 0 ;
DEVMODE mode ;
memset ( & mode , 0 , sizeof ( mode ) ) ;
mode . dmSize = sizeof ( mode ) ;
while ( EnumDisplaySettings ( NULL , i , & mode ) )
{
VideoModeList - > addMode ( core : : dimension2d < u32 > ( mode . dmPelsWidth , mode . dmPelsHeight ) ,
mode . dmBitsPerPel ) ;
+ + i ;
}
if ( EnumDisplaySettings ( NULL , ENUM_CURRENT_SETTINGS , & mode ) )
VideoModeList - > setDesktop ( mode . dmBitsPerPel , core : : dimension2d < u32 > ( mode . dmPelsWidth , mode . dmPelsHeight ) ) ;
}
return VideoModeList ;
}
typedef BOOL ( WINAPI * PGPI ) ( DWORD , DWORD , DWORD , DWORD , PDWORD ) ;
// Needed for old windows apis
// depending on the SDK version and compilers some defines might be available
// or not
# ifndef PRODUCT_ULTIMATE
# define PRODUCT_ULTIMATE 0x00000001
# define PRODUCT_HOME_BASIC 0x00000002
# define PRODUCT_HOME_PREMIUM 0x00000003
# define PRODUCT_ENTERPRISE 0x00000004
# define PRODUCT_HOME_BASIC_N 0x00000005
# define PRODUCT_BUSINESS 0x00000006
# define PRODUCT_STARTER 0x0000000B
# endif
# ifndef PRODUCT_ULTIMATE_N
# define PRODUCT_BUSINESS_N 0x00000010
# define PRODUCT_HOME_PREMIUM_N 0x0000001A
# define PRODUCT_ENTERPRISE_N 0x0000001B
# define PRODUCT_ULTIMATE_N 0x0000001C
# endif
# ifndef PRODUCT_STARTER_N
# define PRODUCT_STARTER_N 0x0000002F
# endif
# ifndef PRODUCT_PROFESSIONAL
# define PRODUCT_PROFESSIONAL 0x00000030
# define PRODUCT_PROFESSIONAL_N 0x00000031
# endif
# ifndef PRODUCT_ULTIMATE_E
# define PRODUCT_STARTER_E 0x00000042
# define PRODUCT_HOME_BASIC_E 0x00000043
# define PRODUCT_HOME_PREMIUM_E 0x00000044
# define PRODUCT_PROFESSIONAL_E 0x00000045
# define PRODUCT_ENTERPRISE_E 0x00000046
# define PRODUCT_ULTIMATE_E 0x00000047
# endif
void CIrrDeviceWin32 : : getWindowsVersion ( core : : stringc & out )
{
OSVERSIONINFOEX osvi ;
BOOL bOsVersionInfoEx ;
ZeroMemory ( & osvi , sizeof ( OSVERSIONINFOEX ) ) ;
osvi . dwOSVersionInfoSize = sizeof ( OSVERSIONINFOEX ) ;
bOsVersionInfoEx = GetVersionEx ( ( OSVERSIONINFO * ) & osvi ) ;
if ( ! bOsVersionInfoEx )
{
osvi . dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ) ;
if ( ! GetVersionEx ( ( OSVERSIONINFO * ) & osvi ) )
return ;
}
switch ( osvi . dwPlatformId )
{
case VER_PLATFORM_WIN32_NT :
if ( osvi . dwMajorVersion < = 4 )
out . append ( " Microsoft Windows NT " ) ;
else
if ( osvi . dwMajorVersion = = 5 & & osvi . dwMinorVersion = = 0 )
out . append ( " Microsoft Windows 2000 " ) ;
else
if ( osvi . dwMajorVersion = = 5 & & osvi . dwMinorVersion = = 1 )
out . append ( " Microsoft Windows XP " ) ;
else
if ( osvi . dwMajorVersion = = 6 )
{
if ( osvi . dwMinorVersion = = 0 )
{
if ( osvi . wProductType = = VER_NT_WORKSTATION )
out . append ( " Microsoft Windows Vista " ) ;
else
out . append ( " Microsoft Windows Server 2008 " ) ;
}
else if ( osvi . dwMinorVersion = = 1 )
{
if ( osvi . wProductType = = VER_NT_WORKSTATION )
out . append ( " Microsoft Windows 7 " ) ;
else
out . append ( " Microsoft Windows Server 2008 R2 " ) ;
}
else if ( osvi . dwMinorVersion = = 2 )
{
out . append ( " Microsoft Windows 8 or later " ) ;
}
}
if ( bOsVersionInfoEx )
{
if ( osvi . dwMajorVersion = = 6 )
{
2022-05-14 17:10:22 +02:00
DWORD dwType = 0 ; // (PRODUCT_UNDEFINED not available on MinGW)
2022-05-13 17:03:27 +02:00
HMODULE hmKernel32 = GetModuleHandle ( TEXT ( " kernel32.dll " ) ) ;
if ( hmKernel32 )
{
PGPI pGPI = ( PGPI ) GetProcAddress ( hmKernel32 , " GetProductInfo " ) ;
if ( pGPI )
pGPI ( osvi . dwMajorVersion , osvi . dwMinorVersion , 0 , 0 , & dwType ) ;
}
2019-12-12 17:32:41 +01:00
switch ( dwType )
{
case PRODUCT_ULTIMATE :
case PRODUCT_ULTIMATE_E :
case PRODUCT_ULTIMATE_N :
out . append ( " Ultimate Edition " ) ;
break ;
case PRODUCT_PROFESSIONAL :
case PRODUCT_PROFESSIONAL_E :
case PRODUCT_PROFESSIONAL_N :
out . append ( " Professional Edition " ) ;
break ;
case PRODUCT_HOME_BASIC :
case PRODUCT_HOME_BASIC_E :
case PRODUCT_HOME_BASIC_N :
out . append ( " Home Basic Edition " ) ;
break ;
case PRODUCT_HOME_PREMIUM :
case PRODUCT_HOME_PREMIUM_E :
case PRODUCT_HOME_PREMIUM_N :
out . append ( " Home Premium Edition " ) ;
break ;
case PRODUCT_ENTERPRISE :
case PRODUCT_ENTERPRISE_E :
case PRODUCT_ENTERPRISE_N :
out . append ( " Enterprise Edition " ) ;
break ;
case PRODUCT_BUSINESS :
case PRODUCT_BUSINESS_N :
out . append ( " Business Edition " ) ;
break ;
case PRODUCT_STARTER :
case PRODUCT_STARTER_E :
case PRODUCT_STARTER_N :
out . append ( " Starter Edition " ) ;
break ;
}
}
# ifdef VER_SUITE_ENTERPRISE
else
if ( osvi . wProductType = = VER_NT_WORKSTATION )
{
# ifndef __BORLANDC__
if ( osvi . wSuiteMask & VER_SUITE_PERSONAL )
out . append ( " Personal " ) ;
else
out . append ( " Professional " ) ;
# endif
}
else if ( osvi . wProductType = = VER_NT_SERVER )
{
if ( osvi . wSuiteMask & VER_SUITE_DATACENTER )
out . append ( " DataCenter Server " ) ;
else if ( osvi . wSuiteMask & VER_SUITE_ENTERPRISE )
out . append ( " Advanced Server " ) ;
else
out . append ( " Server " ) ;
}
# endif
}
else
{
HKEY hKey ;
char szProductType [ 80 ] ;
DWORD dwBufLen ;
RegOpenKeyEx ( HKEY_LOCAL_MACHINE ,
__TEXT ( " SYSTEM \\ CurrentControlSet \\ Control \\ ProductOptions " ) ,
0 , KEY_QUERY_VALUE , & hKey ) ;
RegQueryValueEx ( hKey , __TEXT ( " ProductType " ) , NULL , NULL ,
( LPBYTE ) szProductType , & dwBufLen ) ;
RegCloseKey ( hKey ) ;
2021-03-06 16:49:43 +01:00
2019-12-12 17:32:41 +01:00
if ( irr : : core : : stringc ( " WINNT " ) . equals_ignore_case ( szProductType ) )
out . append ( " Professional " ) ;
if ( irr : : core : : stringc ( " LANMANNT " ) . equals_ignore_case ( szProductType ) )
out . append ( " Server " ) ;
if ( irr : : core : : stringc ( " SERVERNT " ) . equals_ignore_case ( szProductType ) )
out . append ( " Advanced Server " ) ;
}
// Display version, service pack (if any), and build number.
char tmp [ 255 ] ;
if ( osvi . dwMajorVersion < = 4 )
{
sprintf ( tmp , " version %lu.%lu %s (Build %lu) " ,
osvi . dwMajorVersion ,
osvi . dwMinorVersion ,
irr : : core : : stringc ( osvi . szCSDVersion ) . c_str ( ) ,
osvi . dwBuildNumber & 0xFFFF ) ;
}
else
{
sprintf ( tmp , " %s (Build %lu) " , irr : : core : : stringc ( osvi . szCSDVersion ) . c_str ( ) ,
osvi . dwBuildNumber & 0xFFFF ) ;
}
out . append ( tmp ) ;
break ;
case VER_PLATFORM_WIN32_WINDOWS :
if ( osvi . dwMajorVersion = = 4 & & osvi . dwMinorVersion = = 0 )
{
out . append ( " Microsoft Windows 95 " ) ;
if ( osvi . szCSDVersion [ 1 ] = = ' C ' | | osvi . szCSDVersion [ 1 ] = = ' B ' )
out . append ( " OSR2 " ) ;
}
if ( osvi . dwMajorVersion = = 4 & & osvi . dwMinorVersion = = 10 )
{
out . append ( " Microsoft Windows 98 " ) ;
if ( osvi . szCSDVersion [ 1 ] = = ' A ' )
out . append ( " SE " ) ;
}
if ( osvi . dwMajorVersion = = 4 & & osvi . dwMinorVersion = = 90 )
out . append ( " Microsoft Windows Me " ) ;
break ;
case VER_PLATFORM_WIN32s :
out . append ( " Microsoft Win32s " ) ;
break ;
}
}
//! Notifies the device, that it has been resized
void CIrrDeviceWin32 : : OnResized ( )
{
Resized = true ;
}
//! Resize the render window.
void CIrrDeviceWin32 : : setWindowSize ( const irr : : core : : dimension2d < u32 > & size )
{
if ( ExternalWindow | | ! getVideoDriver ( ) | | CreationParams . Fullscreen )
return ;
// get size of the window for the give size of the client area
DWORD style = static_cast < DWORD > ( GetWindowLongPtr ( HWnd , GWL_STYLE ) ) ;
DWORD exStyle = static_cast < DWORD > ( GetWindowLongPtr ( HWnd , GWL_EXSTYLE ) ) ;
RECT clientSize ;
clientSize . top = 0 ;
clientSize . left = 0 ;
clientSize . right = size . Width ;
clientSize . bottom = size . Height ;
AdjustWindowRectEx ( & clientSize , style , false , exStyle ) ;
const s32 realWidth = clientSize . right - clientSize . left ;
const s32 realHeight = clientSize . bottom - clientSize . top ;
UINT flags = SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER ;
SetWindowPos ( HWnd , HWND_TOP , 0 , 0 , realWidth , realHeight , flags ) ;
}
//! Sets if the window should be resizable in windowed mode.
void CIrrDeviceWin32 : : setResizable ( bool resize )
{
if ( ExternalWindow | | ! getVideoDriver ( ) | | CreationParams . Fullscreen )
return ;
LONG_PTR style = ( LONG_PTR ) getWindowStyle ( false , resize ) ;
if ( ! SetWindowLongPtr ( HWnd , GWL_STYLE , style ) )
os : : Printer : : log ( " Could not change window style. " ) ;
RECT clientSize ;
clientSize . top = 0 ;
clientSize . left = 0 ;
clientSize . right = getVideoDriver ( ) - > getScreenSize ( ) . Width ;
clientSize . bottom = getVideoDriver ( ) - > getScreenSize ( ) . Height ;
AdjustWindowRect ( & clientSize , static_cast < DWORD > ( style ) , FALSE ) ;
const s32 realWidth = clientSize . right - clientSize . left ;
const s32 realHeight = clientSize . bottom - clientSize . top ;
const s32 windowLeft = ( GetSystemMetrics ( SM_CXSCREEN ) - realWidth ) / 2 ;
const s32 windowTop = ( GetSystemMetrics ( SM_CYSCREEN ) - realHeight ) / 2 ;
SetWindowPos ( HWnd , HWND_TOP , windowLeft , windowTop , realWidth , realHeight ,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_SHOWWINDOW ) ;
static_cast < CCursorControl * > ( CursorControl ) - > updateBorderSize ( CreationParams . Fullscreen , resize ) ;
}
//! Minimizes the window.
void CIrrDeviceWin32 : : minimizeWindow ( )
{
WINDOWPLACEMENT wndpl ;
wndpl . length = sizeof ( WINDOWPLACEMENT ) ;
GetWindowPlacement ( HWnd , & wndpl ) ;
wndpl . showCmd = SW_SHOWMINNOACTIVE ;
SetWindowPlacement ( HWnd , & wndpl ) ;
}
//! Maximizes the window.
void CIrrDeviceWin32 : : maximizeWindow ( )
{
WINDOWPLACEMENT wndpl ;
wndpl . length = sizeof ( WINDOWPLACEMENT ) ;
GetWindowPlacement ( HWnd , & wndpl ) ;
wndpl . showCmd = SW_SHOWMAXIMIZED ;
SetWindowPlacement ( HWnd , & wndpl ) ;
}
//! Restores the window to its original size.
void CIrrDeviceWin32 : : restoreWindow ( )
{
WINDOWPLACEMENT wndpl ;
wndpl . length = sizeof ( WINDOWPLACEMENT ) ;
GetWindowPlacement ( HWnd , & wndpl ) ;
wndpl . showCmd = SW_SHOWNORMAL ;
SetWindowPlacement ( HWnd , & wndpl ) ;
}
core : : position2di CIrrDeviceWin32 : : getWindowPosition ( )
{
WINDOWPLACEMENT wndpl ;
wndpl . length = sizeof ( WINDOWPLACEMENT ) ;
if ( GetWindowPlacement ( HWnd , & wndpl ) )
{
return core : : position2di ( ( int ) wndpl . rcNormalPosition . left ,
( int ) wndpl . rcNormalPosition . top ) ;
}
else
{
// No reason for this to happen
os : : Printer : : log ( " Failed to retrieve window location " , ELL_ERROR ) ;
return core : : position2di ( - 1 , - 1 ) ;
}
}
bool CIrrDeviceWin32 : : activateJoysticks ( core : : array < SJoystickInfo > & joystickInfo )
{
if ( JoyControl )
return JoyControl - > activateJoysticks ( joystickInfo ) ;
else
return false ;
}
//! Set the current Gamma Value for the Display
bool CIrrDeviceWin32 : : setGammaRamp ( f32 red , f32 green , f32 blue , f32 brightness , f32 contrast )
{
bool r ;
u16 ramp [ 3 ] [ 256 ] ;
calculateGammaRamp ( ramp [ 0 ] , red , brightness , contrast ) ;
calculateGammaRamp ( ramp [ 1 ] , green , brightness , contrast ) ;
calculateGammaRamp ( ramp [ 2 ] , blue , brightness , contrast ) ;
HDC dc = GetDC ( 0 ) ;
r = SetDeviceGammaRamp ( dc , ramp ) = = TRUE ;
ReleaseDC ( HWnd , dc ) ;
return r ;
}
//! Get the current Gamma Value for the Display
bool CIrrDeviceWin32 : : getGammaRamp ( f32 & red , f32 & green , f32 & blue , f32 & brightness , f32 & contrast )
{
bool r ;
u16 ramp [ 3 ] [ 256 ] ;
HDC dc = GetDC ( 0 ) ;
r = GetDeviceGammaRamp ( dc , ramp ) = = TRUE ;
ReleaseDC ( HWnd , dc ) ;
if ( r )
{
calculateGammaFromRamp ( red , ramp [ 0 ] ) ;
calculateGammaFromRamp ( green , ramp [ 1 ] ) ;
calculateGammaFromRamp ( blue , ramp [ 2 ] ) ;
}
brightness = 0.f ;
contrast = 0.f ;
return r ;
}
//! Process system events
void CIrrDeviceWin32 : : handleSystemMessages ( )
{
MSG msg ;
while ( PeekMessage ( & msg , NULL , 0 , 0 , PM_REMOVE ) )
{
if ( ExternalWindow & & msg . hwnd = = HWnd )
{
if ( msg . hwnd = = HWnd )
{
WndProc ( HWnd , msg . message , msg . wParam , msg . lParam ) ;
}
else
{
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
else
{
// No message translation because we don't use WM_CHAR and it would conflict with our
// deadkey handling.
DispatchMessage ( & msg ) ;
}
if ( msg . message = = WM_QUIT )
Close = true ;
}
}
//! Remove all messages pending in the system message loop
void CIrrDeviceWin32 : : clearSystemMessages ( )
{
MSG msg ;
while ( PeekMessage ( & msg , NULL , WM_KEYFIRST , WM_KEYLAST , PM_REMOVE ) )
{ }
while ( PeekMessage ( & msg , NULL , WM_MOUSEFIRST , WM_MOUSELAST , PM_REMOVE ) )
{ }
}
// shows last error in a messagebox to help internal debugging.
void CIrrDeviceWin32 : : ReportLastWinApiError ( )
{
// (based on code from ovidiucucu from http://www.codeguru.com/forum/showthread.php?t=318721)
LPCTSTR pszCaption = __TEXT ( " Windows SDK Error Report " ) ;
DWORD dwError = GetLastError ( ) ;
if ( NOERROR = = dwError )
{
MessageBox ( NULL , __TEXT ( " No error " ) , pszCaption , MB_OK ) ;
}
else
{
const DWORD dwFormatControl = FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM ;
LPVOID pTextBuffer = NULL ;
DWORD dwCount = FormatMessage ( dwFormatControl ,
NULL ,
dwError ,
0 ,
( LPTSTR ) & pTextBuffer ,
0 ,
NULL ) ;
if ( 0 ! = dwCount )
{
MessageBox ( NULL , ( LPCTSTR ) pTextBuffer , pszCaption , MB_OK | MB_ICONERROR ) ;
LocalFree ( pTextBuffer ) ;
}
else
{
MessageBox ( NULL , __TEXT ( " Unknown error " ) , pszCaption , MB_OK | MB_ICONERROR ) ;
}
}
}
// Same function Windows offers in VersionHelpers.h, but we can't use that as it's not available in older sdk's (minimum is SDK 8.1)
bool CIrrDeviceWin32 : : isWindowsVistaOrGreater ( )
{
# if (_WIN32_WINNT >= 0x0500)
OSVERSIONINFOEX osvi ;
ZeroMemory ( & osvi , sizeof ( OSVERSIONINFOEX ) ) ;
osvi . dwOSVersionInfoSize = sizeof ( OSVERSIONINFOEX ) ;
osvi . dwMajorVersion = 6 ; // Windows Vista
if ( ! GetVersionEx ( ( OSVERSIONINFO * ) & osvi ) )
{
return false ;
}
return VerifyVersionInfo ( & osvi , VER_MAJORVERSION , VerSetConditionMask ( 0 , VER_MAJORVERSION , VER_GREATER_EQUAL ) ) ? true : false ;
# else
return false ;
# endif
}
// Convert an Irrlicht texture to a Windows cursor
// Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/
HCURSOR CIrrDeviceWin32 : : TextureToCursor ( HWND hwnd , irr : : video : : ITexture * tex , const core : : rect < s32 > & sourceRect , const core : : position2d < s32 > & hotspot )
{
//
// create the bitmaps needed for cursors from the texture
HDC dc = GetDC ( hwnd ) ;
HDC andDc = CreateCompatibleDC ( dc ) ;
HDC xorDc = CreateCompatibleDC ( dc ) ;
HBITMAP andBitmap = CreateCompatibleBitmap ( dc , sourceRect . getWidth ( ) , sourceRect . getHeight ( ) ) ;
HBITMAP xorBitmap = CreateCompatibleBitmap ( dc , sourceRect . getWidth ( ) , sourceRect . getHeight ( ) ) ;
HBITMAP oldAndBitmap = ( HBITMAP ) SelectObject ( andDc , andBitmap ) ;
HBITMAP oldXorBitmap = ( HBITMAP ) SelectObject ( xorDc , xorBitmap ) ;
video : : ECOLOR_FORMAT format = tex - > getColorFormat ( ) ;
u32 bytesPerPixel = video : : IImage : : getBitsPerPixelFromFormat ( format ) / 8 ;
u32 bytesLeftGap = sourceRect . UpperLeftCorner . X * bytesPerPixel ;
u32 bytesRightGap = tex - > getPitch ( ) - sourceRect . LowerRightCorner . X * bytesPerPixel ;
const u8 * data = ( const u8 * ) tex - > lock ( video : : ETLM_READ_ONLY , 0 ) ;
data + = sourceRect . UpperLeftCorner . Y * tex - > getPitch ( ) ;
for ( s32 y = 0 ; y < sourceRect . getHeight ( ) ; + + y )
{
data + = bytesLeftGap ;
for ( s32 x = 0 ; x < sourceRect . getWidth ( ) ; + + x )
{
video : : SColor pixelCol ;
pixelCol . setData ( ( const void * ) data , format ) ;
data + = bytesPerPixel ;
if ( pixelCol . getAlpha ( ) = = 0 ) // transparent
{
SetPixel ( andDc , x , y , RGB ( 255 , 255 , 255 ) ) ;
SetPixel ( xorDc , x , y , RGB ( 0 , 0 , 0 ) ) ;
}
else // color
{
SetPixel ( andDc , x , y , RGB ( 0 , 0 , 0 ) ) ;
SetPixel ( xorDc , x , y , RGB ( pixelCol . getRed ( ) , pixelCol . getGreen ( ) , pixelCol . getBlue ( ) ) ) ;
}
}
data + = bytesRightGap ;
}
tex - > unlock ( ) ;
SelectObject ( andDc , oldAndBitmap ) ;
SelectObject ( xorDc , oldXorBitmap ) ;
DeleteDC ( xorDc ) ;
DeleteDC ( andDc ) ;
ReleaseDC ( hwnd , dc ) ;
// create the cursor
ICONINFO iconinfo ;
iconinfo . fIcon = false ; // type is cursor not icon
iconinfo . xHotspot = hotspot . X ;
iconinfo . yHotspot = hotspot . Y ;
iconinfo . hbmMask = andBitmap ;
iconinfo . hbmColor = xorBitmap ;
HCURSOR cursor = CreateIconIndirect ( & iconinfo ) ;
DeleteObject ( andBitmap ) ;
DeleteObject ( xorBitmap ) ;
return cursor ;
}
CIrrDeviceWin32 : : CCursorControl : : CCursorControl ( CIrrDeviceWin32 * device , const core : : dimension2d < u32 > & wsize , HWND hwnd , bool fullscreen )
: Device ( device ) , WindowSize ( wsize ) , InvWindowSize ( 0.0f , 0.0f ) ,
HWnd ( hwnd ) , BorderX ( 0 ) , BorderY ( 0 ) ,
UseReferenceRect ( false ) , IsVisible ( true )
, ActiveIcon ( gui : : ECI_NORMAL ) , ActiveIconStartTime ( 0 )
{
if ( WindowSize . Width ! = 0 )
InvWindowSize . Width = 1.0f / WindowSize . Width ;
if ( WindowSize . Height ! = 0 )
InvWindowSize . Height = 1.0f / WindowSize . Height ;
updateBorderSize ( fullscreen , false ) ;
initCursors ( ) ;
}
CIrrDeviceWin32 : : CCursorControl : : ~ CCursorControl ( )
{
for ( u32 i = 0 ; i < Cursors . size ( ) ; + + i )
{
for ( u32 f = 0 ; f < Cursors [ i ] . Frames . size ( ) ; + + f )
{
DestroyCursor ( Cursors [ i ] . Frames [ f ] . IconHW ) ;
}
}
}
void CIrrDeviceWin32 : : CCursorControl : : initCursors ( )
{
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_ARROW ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_CROSS ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_HAND ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_HELP ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_IBEAM ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_NO ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_WAIT ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_SIZEALL ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_SIZENESW ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_SIZENWSE ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_SIZENS ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_SIZEWE ) ) ) ;
Cursors . push_back ( CursorW32 ( LoadCursor ( NULL , IDC_UPARROW ) ) ) ;
}
void CIrrDeviceWin32 : : CCursorControl : : update ( )
{
if ( ! Cursors [ ActiveIcon ] . Frames . empty ( ) & & Cursors [ ActiveIcon ] . FrameTime )
{
// 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)
u32 now = Device - > getTimer ( ) - > getRealTime ( ) ;
u32 frame = ( ( now - ActiveIconStartTime ) / Cursors [ ActiveIcon ] . FrameTime ) % Cursors [ ActiveIcon ] . Frames . size ( ) ;
SetCursor ( Cursors [ ActiveIcon ] . Frames [ frame ] . IconHW ) ;
}
}
//! Sets the active cursor icon
void CIrrDeviceWin32 : : CCursorControl : : setActiveIcon ( gui : : ECURSOR_ICON iconId )
{
if ( iconId > = ( s32 ) Cursors . size ( ) )
return ;
ActiveIcon = iconId ;
ActiveIconStartTime = Device - > getTimer ( ) - > getRealTime ( ) ;
if ( Cursors [ ActiveIcon ] . Frames . size ( ) )
SetCursor ( Cursors [ ActiveIcon ] . Frames [ 0 ] . IconHW ) ;
}
//! Add a custom sprite as cursor icon.
gui : : ECURSOR_ICON CIrrDeviceWin32 : : CCursorControl : : addIcon ( const gui : : SCursorSprite & icon )
{
if ( icon . SpriteId > = 0 )
{
CursorW32 cW32 ;
cW32 . FrameTime = icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . frameTime ;
for ( u32 i = 0 ; i < icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . Frames . size ( ) ; + + i )
{
irr : : u32 texId = icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . Frames [ i ] . textureNumber ;
irr : : u32 rectId = icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . Frames [ i ] . rectNumber ;
irr : : core : : rect < s32 > rectIcon = icon . SpriteBank - > getPositions ( ) [ rectId ] ;
HCURSOR hc = Device - > TextureToCursor ( HWnd , icon . SpriteBank - > getTexture ( texId ) , rectIcon , icon . HotSpot ) ;
cW32 . Frames . push_back ( CursorFrameW32 ( hc ) ) ;
}
Cursors . push_back ( cW32 ) ;
return ( gui : : ECURSOR_ICON ) ( Cursors . size ( ) - 1 ) ;
}
return gui : : ECI_NORMAL ;
}
//! replace the given cursor icon.
void CIrrDeviceWin32 : : CCursorControl : : changeIcon ( gui : : ECURSOR_ICON iconId , const gui : : SCursorSprite & icon )
{
if ( iconId > = ( s32 ) Cursors . size ( ) )
return ;
for ( u32 i = 0 ; i < Cursors [ iconId ] . Frames . size ( ) ; + + i )
DestroyCursor ( Cursors [ iconId ] . Frames [ i ] . IconHW ) ;
if ( icon . SpriteId > = 0 )
{
CursorW32 cW32 ;
cW32 . FrameTime = icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . frameTime ;
for ( u32 i = 0 ; i < icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . Frames . size ( ) ; + + i )
{
irr : : u32 texId = icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . Frames [ i ] . textureNumber ;
irr : : u32 rectId = icon . SpriteBank - > getSprites ( ) [ icon . SpriteId ] . Frames [ i ] . rectNumber ;
irr : : core : : rect < s32 > rectIcon = icon . SpriteBank - > getPositions ( ) [ rectId ] ;
HCURSOR hc = Device - > TextureToCursor ( HWnd , icon . SpriteBank - > getTexture ( texId ) , rectIcon , icon . HotSpot ) ;
cW32 . Frames . push_back ( CursorFrameW32 ( hc ) ) ;
}
Cursors [ iconId ] = cW32 ;
}
}
//! Return a system-specific size which is supported for cursors. Larger icons will fail, smaller icons might work.
core : : dimension2di CIrrDeviceWin32 : : CCursorControl : : getSupportedIconSize ( ) const
{
core : : dimension2di result ;
result . Width = GetSystemMetrics ( SM_CXCURSOR ) ;
result . Height = GetSystemMetrics ( SM_CYCURSOR ) ;
return result ;
}
} // end namespace
# endif // _IRR_COMPILE_WITH_WINDOWS_DEVICE_