2020-01-03 20:05:16 +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
# 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 "os.h"
# include "CTimer.h"
# include "irrString.h"
# include "COSOperator.h"
# include "dimension2d.h"
# include "IGUISpriteBank.h"
# include <winuser.h>
# include "SExposedVideoData.h"
2022-02-26 11:38:43 +01:00
2020-01-03 20:05:16 +01:00
# 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>
# endif
# endif
# if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)
# include "CEGLManager.h"
# endif
# if defined(_IRR_COMPILE_WITH_OPENGL_)
# include "CWGLManager.h"
# endif
namespace irr
{
namespace video
{
# ifdef _IRR_COMPILE_WITH_OPENGL_
IVideoDriver * createOpenGLDriver ( const irr : : SIrrlichtCreationParameters & params , io : : IFileSystem * io , IContextManager * contextManager ) ;
# endif
# ifdef _IRR_COMPILE_WITH_OGLES1_
IVideoDriver * createOGLES1Driver ( const irr : : SIrrlichtCreationParameters & params , io : : IFileSystem * io , IContextManager * contextManager ) ;
# endif
# ifdef _IRR_COMPILE_WITH_OGLES2_
IVideoDriver * createOGLES2Driver ( 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 ( ) ;
2020-01-03 20:05:16 +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 ] ;
2022-02-26 11:18:19 +01:00
snprintf_irr ( logString , sizeof ( logString ) , " Found joystick %d, %d axes, %d buttons '%s' " ,
2020-01-03 20:05:16 +01:00
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
namespace
{
struct SEnvMapper
{
HWND hWnd ;
irr : : CIrrDeviceWin32 * irrDev ;
} ;
// NOTE: This is global. We can have more than one Irrlicht Device at same time.
irr : : core : : array < SEnvMapper > EnvMap ;
HKL KEYBOARD_INPUT_HKL = 0 ;
}
irr : : CIrrDeviceWin32 * getDeviceFromHWnd ( HWND hWnd )
{
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 ;
}
return 0 ;
}
LRESULT CALLBACK WndProc ( HWND hWnd , UINT message , WPARAM wParam , LPARAM lParam )
{
# 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 ( wParam & MK_XBUTTON1 )
event . MouseInput . ButtonStates | = irr : : EMBSM_EXTRA1 ;
if ( wParam & MK_XBUTTON2 )
event . MouseInput . ButtonStates | = irr : : EMBSM_EXTRA2 ;
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 ) ;
if ( event . KeyInput . Key = = irr : : KEY_SHIFT )
{
2021-07-16 00:32:15 +02:00
event . KeyInput . Key = ( irr : : EKEY_CODE ) MapVirtualKey ( ( ( lParam > > 16 ) & 255 ) , MAPVK_VSC_TO_VK_EX ) ;
2020-01-03 20:05:16 +01:00
}
if ( event . KeyInput . Key = = irr : : KEY_CONTROL )
{
2021-07-16 00:32:15 +02:00
event . KeyInput . Key = ( irr : : EKEY_CODE ) MapVirtualKey ( ( ( lParam > > 16 ) & 255 ) , MAPVK_VSC_TO_VK_EX ) ;
2020-01-03 20:05:16 +01:00
// 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 )
{
2021-07-16 00:32:15 +02:00
event . KeyInput . Key = ( irr : : EKEY_CODE ) MapVirtualKey ( ( ( lParam > > 16 ) & 255 ) , MAPVK_VSC_TO_VK_EX ) ;
2020-01-03 20:05:16 +01:00
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 ) ;
2021-07-16 00:32:15 +02:00
// Handle unicode and deadkeys
WCHAR keyChars [ 2 ] ;
2020-01-03 20:05:16 +01:00
UINT scanCode = HIWORD ( lParam ) ;
2021-07-16 00:32:15 +02:00
int conversionResult = ToUnicodeEx ( static_cast < UINT > ( wParam ) , scanCode , allKeys , keyChars , 2 , 0 , KEYBOARD_INPUT_HKL ) ;
2020-01-03 20:05:16 +01:00
if ( conversionResult = = 1 )
2021-07-16 00:32:15 +02:00
event . KeyInput . Char = keyChars [ 0 ] ;
2020-01-03 20:05:16 +01:00
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 )
2022-10-14 15:52:10 +02:00
return DefWindowProcW ( hWnd , message , wParam , lParam ) ;
2020-01-03 20:05:16 +01:00
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_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 ) ;
return 0 ;
}
2022-10-14 15:52:10 +02:00
return DefWindowProcW ( hWnd , message , wParam , lParam ) ;
2020-01-03 20:05:16 +01:00
}
namespace irr
{
//! constructor
CIrrDeviceWin32 : : CIrrDeviceWin32 ( const SIrrlichtCreationParameters & params )
2021-06-15 18:00:14 +02:00
: CIrrDeviceStub ( params ) , HWnd ( 0 ) , Resized ( false ) ,
2023-02-06 15:05:44 +01:00
ExternalWindow ( false ) , Win32CursorControl ( 0 ) , JoyControl ( 0 ) ,
WindowMaximized ( params . WindowMaximized )
2020-01-03 20:05:16 +01:00
{
# 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 ) ;
// create the window if we need to and we do not use the null device
if ( ! CreationParams . WindowId & & CreationParams . DriverType ! = video : : EDT_NULL )
{
2022-10-14 15:52:10 +02:00
const wchar_t * ClassName = L " CIrrDeviceWin32 " ;
2020-01-03 20:05:16 +01:00
// Register Class
2022-10-14 15:52:10 +02:00
WNDCLASSEXW wcex ;
wcex . cbSize = sizeof ( WNDCLASSEXW ) ;
2020-01-03 20:05:16 +01:00
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 ;
2022-10-14 15:52:10 +02:00
RegisterClassExW ( & wcex ) ;
2020-01-03 20:05:16 +01:00
// calculate client size
RECT clientSize ;
clientSize . top = 0 ;
clientSize . left = 0 ;
clientSize . right = CreationParams . WindowSize . Width ;
clientSize . bottom = CreationParams . WindowSize . Height ;
2021-08-26 23:57:27 +02:00
DWORD style = getWindowStyle ( CreationParams . Fullscreen , CreationParams . WindowResizable > 0 ? true : false ) ;
2020-01-03 20:05:16 +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
2022-10-14 15:52:10 +02:00
HWnd = CreateWindowW ( ClassName , L " " , style , windowLeft , windowTop ,
2020-01-03 20:05:16 +01:00
realWidth , realHeight , NULL , NULL , hInstance , NULL ) ;
if ( ! HWnd )
{
os : : Printer : : log ( " Window could not be created. " , ELL_ERROR ) ;
}
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 ) ;
}
KEYBOARD_INPUT_HKL = GetKeyboardLayout ( 0 ) ;
// inform driver about the window size etc.
resizeIfNecessary ( ) ;
2023-02-06 15:05:44 +01:00
if ( params . WindowMaximized )
maximizeWindow ( ) ;
2020-01-03 20:05:16 +01:00
}
//! destructor
CIrrDeviceWin32 : : ~ CIrrDeviceWin32 ( )
{
delete JoyControl ;
// unregister environment
for ( u32 i = 0 ; i < EnvMap . size ( ) ; + + i )
{
if ( EnvMap [ i ] . hWnd = = HWnd )
{
EnvMap . erase ( i ) ;
break ;
}
}
}
//! create the driver
void CIrrDeviceWin32 : : createDriver ( )
{
switch ( CreationParams . DriverType )
{
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_OGLES1 :
# ifdef _IRR_COMPILE_WITH_OGLES1_
switchToFullScreen ( ) ;
ContextManager = new video : : CEGLManager ( ) ;
ContextManager - > initialize ( CreationParams , video : : SExposedVideoData ( HWnd ) ) ;
VideoDriver = video : : createOGLES1Driver ( CreationParams , FileSystem , ContextManager ) ;
if ( ! VideoDriver )
os : : Printer : : log ( " Could not create OpenGL-ES1 driver. " , ELL_ERROR ) ;
# else
os : : Printer : : log ( " OpenGL-ES1 driver was not compiled in. " , ELL_ERROR ) ;
# endif
break ;
case video : : EDT_OGLES2 :
# ifdef _IRR_COMPILE_WITH_OGLES2_
switchToFullScreen ( ) ;
ContextManager = new video : : CEGLManager ( ) ;
ContextManager - > initialize ( CreationParams , video : : SExposedVideoData ( HWnd ) ) ;
VideoDriver = video : : createOGLES2Driver ( CreationParams , FileSystem , ContextManager ) ;
if ( ! VideoDriver )
os : : Printer : : log ( " Could not create OpenGL-ES2 driver. " , ELL_ERROR ) ;
# else
os : : Printer : : log ( " OpenGL-ES2 driver was not compiled in. " , ELL_ERROR ) ;
# endif
break ;
2021-02-25 21:17:23 +01:00
case video : : EDT_WEBGL1 :
2020-01-03 20:05:16 +01:00
os : : Printer : : log ( " WebGL1 driver not supported on Win32 device. " , ELL_ERROR ) ;
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 ( )
{
Sleep ( 1 ) ;
}
//! 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 )
{
2022-02-26 11:18:19 +01:00
snprintf_irr ( tmp , sizeof ( tmp ) , " Ignoring resize operation to (%ld %ld) " , r . right , r . bottom ) ;
2020-01-03 20:05:16 +01:00
os : : Printer : : log ( tmp ) ;
}
else
{
2022-02-26 11:18:19 +01:00
snprintf_irr ( tmp , sizeof ( tmp ) , " Resizing window (%ld %ld) " , r . right , r . bottom ) ;
2020-01-03 20:05:16 +01:00
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 ;
}
//! 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 ) ;
}
2023-03-25 01:40:13 +01:00
//! Sets the window icon.
bool CIrrDeviceWin32 : : setWindowIcon ( const video : : IImage * img )
{
// Ignore the img, instead load the ICON from resource file
// (This is minetest-specific!)
const HICON hicon = LoadIcon ( GetModuleHandle ( NULL ) ,
MAKEINTRESOURCE ( 130 ) // The ID of the ICON defined in
// winresource.rc
) ;
if ( hicon ) {
SendMessage ( HWnd , WM_SETICON , ICON_BIG , reinterpret_cast < LPARAM > ( hicon ) ) ;
SendMessage ( HWnd , WM_SETICON , ICON_SMALL ,
reinterpret_cast < LPARAM > ( hicon ) ) ;
return true ;
}
return false ;
}
2020-01-03 20:05:16 +01:00
//! notifies the device that it should close itself
void CIrrDeviceWin32 : : closeDevice ( )
{
if ( ! ExternalWindow )
{
2020-09-29 22:22:28 +02:00
MSG msg ;
PeekMessage ( & msg , NULL , WM_QUIT , WM_QUIT , PM_REMOVE ) ;
PostQuitMessage ( 0 ) ;
PeekMessage ( & msg , NULL , WM_QUIT , WM_QUIT , PM_REMOVE ) ;
2020-01-03 20:05:16 +01:00
DestroyWindow ( HWnd ) ;
2022-10-14 15:52:10 +02:00
const wchar_t * ClassName = L " CIrrDeviceWin32 " ;
2020-01-03 20:05:16 +01:00
HINSTANCE hInstance = GetModuleHandle ( 0 ) ;
2022-10-14 15:52:10 +02:00
UnregisterClassW ( ClassName , hInstance ) ;
2020-01-03 20:05:16 +01:00
}
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 ;
}
2023-02-06 15:05:44 +01:00
//! returns last state from maximizeWindow() and restoreWindow()
bool CIrrDeviceWin32 : : isWindowMaximized ( ) const
{
return WindowMaximized ;
}
2020-01-03 20:05:16 +01:00
//! switches to fullscreen
2021-06-15 18:00:14 +02:00
bool CIrrDeviceWin32 : : switchToFullScreen ( )
2020-01-03 20:05:16 +01:00
{
if ( ! CreationParams . Fullscreen )
return true ;
2021-06-15 18:14:10 +02:00
// No border, title bar, etc. is already set up through getWindowStyle()
// We only set the window size to match the monitor.
MONITORINFO mi ;
mi . cbSize = sizeof ( mi ) ;
if ( GetMonitorInfo ( MonitorFromWindow ( HWnd , MONITOR_DEFAULTTOPRIMARY ) , & mi ) )
{
UINT flags = SWP_NOCOPYBITS | SWP_NOOWNERZORDER | SWP_FRAMECHANGED ;
SetWindowPos ( HWnd , HWND_TOP , mi . rcMonitor . left , mi . rcMonitor . top ,
mi . rcMonitor . right - mi . rcMonitor . left ,
mi . rcMonitor . bottom - mi . rcMonitor . top , flags ) ;
}
else
{
CreationParams . Fullscreen = false ;
}
return CreationParams . Fullscreen ;
2020-01-03 20:05:16 +01:00
}
//! returns the win32 cursor control
CIrrDeviceWin32 : : CCursorControl * CIrrDeviceWin32 : : getWin32CursorControl ( )
{
return Win32CursorControl ;
}
void CIrrDeviceWin32 : : getWindowsVersion ( core : : stringc & out )
{
2021-07-16 00:32:15 +02:00
OSVERSIONINFO osvi ;
2020-01-03 20:05:16 +01:00
2021-07-16 00:32:15 +02:00
ZeroMemory ( & osvi , sizeof ( OSVERSIONINFO ) ) ;
osvi . dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ) ;
GetVersionEx ( & osvi ) ;
2020-01-03 20:05:16 +01:00
2021-07-16 00:32:15 +02:00
char tmp [ 255 ] ;
snprintf ( tmp , sizeof ( tmp ) , " Microsoft Windows %lu.%lu %s " , osvi . dwMajorVersion , osvi . dwMinorVersion , osvi . szCSDVersion ) ;
out . append ( tmp ) ;
2020-01-03 20:05:16 +01:00
}
//! 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 ) ;
2023-02-06 15:05:44 +01:00
WindowMaximized = true ;
2020-01-03 20:05:16 +01:00
}
//! 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 ) ;
2023-02-06 15:05:44 +01:00
WindowMaximized = false ;
2020-01-03 20:05:16 +01:00
}
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 ;
}
//! 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 ) )
{ }
}
2023-03-25 01:40:13 +01:00
//! Get the display density in dots per inch.
float CIrrDeviceWin32 : : getDisplayDensity ( ) const
{
HDC hdc = GetDC ( HWnd ) ;
float dpi = GetDeviceCaps ( hdc , LOGPIXELSX ) ;
ReleaseDC ( HWnd , hdc ) ;
return dpi ;
}
2020-01-03 20:05:16 +01:00
// 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