2013-01-13 15:35:06 -08:00
/*
2014-02-10 22:07:04 -08:00
* Copyright 2011 - 2014 Branimir Karadzic . All rights reserved .
2013-01-13 15:35:06 -08:00
* License : http : //www.opensource.org/licenses/BSD-2-Clause
*/
2013-08-14 21:08:46 -07:00
# include "entry_p.h"
2013-01-13 15:35:06 -08:00
2013-08-14 21:08:46 -07:00
# if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_WINDOWS
2013-01-13 15:35:06 -08:00
2013-08-07 23:11:20 -07:00
# include <bgfxplatform.h>
2013-01-16 22:44:51 -08:00
2013-01-13 15:35:06 -08:00
# include <bx/uint32_t.h>
# include <bx/thread.h>
2014-09-18 22:32:33 -07:00
# include <bx/mutex.h>
# include <bx/handlealloc.h>
2014-09-28 11:03:47 -07:00
# include <tinystl/allocator.h>
# include <tinystl/string.h>
2014-10-11 20:42:42 -07:00
# include <windowsx.h>
2013-01-16 22:44:51 -08:00
2013-01-13 15:35:06 -08:00
namespace entry
{
2014-10-11 20:42:42 -07:00
enum
{
WM_USER_WINDOW_CREATE = WM_USER ,
WM_USER_WINDOW_DESTROY ,
WM_USER_WINDOW_SET_TITLE ,
WM_USER_WINDOW_SET_POS ,
WM_USER_WINDOW_SET_SIZE ,
WM_USER_WINDOW_TOGGLE_FRAME ,
WM_USER_WINDOW_MOUSE_LOCK ,
} ;
2013-01-16 22:44:51 -08:00
struct TranslateKeyModifiers
{
int m_vk ;
Modifier : : Enum m_modifier ;
} ;
static const TranslateKeyModifiers s_translateKeyModifiers [ 8 ] =
{
{ VK_LMENU , Modifier : : LeftAlt } ,
{ VK_RMENU , Modifier : : RightAlt } ,
{ VK_LCONTROL , Modifier : : LeftCtrl } ,
{ VK_RCONTROL , Modifier : : RightCtrl } ,
{ VK_LSHIFT , Modifier : : LeftShift } ,
{ VK_RSHIFT , Modifier : : RightShift } ,
{ VK_LWIN , Modifier : : LeftMeta } ,
{ VK_RWIN , Modifier : : RightMeta } ,
} ;
static uint8_t translateKeyModifiers ( )
{
uint8_t modifiers = 0 ;
2013-08-06 21:04:28 -07:00
for ( uint32_t ii = 0 ; ii < BX_COUNTOF ( s_translateKeyModifiers ) ; + + ii )
2013-01-16 22:44:51 -08:00
{
const TranslateKeyModifiers & tkm = s_translateKeyModifiers [ ii ] ;
modifiers | = 0 > GetKeyState ( tkm . m_vk ) ? tkm . m_modifier : Modifier : : None ;
}
return modifiers ;
}
static uint8_t s_translateKey [ 256 ] ;
static Key : : Enum translateKey ( WPARAM _wparam )
{
return ( Key : : Enum ) s_translateKey [ _wparam & 0xff ] ;
}
2013-01-13 15:35:06 -08:00
struct MainThreadEntry
{
int m_argc ;
char * * m_argv ;
2013-01-16 22:44:51 -08:00
static int32_t threadFunc ( void * _userData ) ;
2013-01-13 15:35:06 -08:00
} ;
2014-09-22 19:34:10 -07:00
struct Msg
{
Msg ( )
: m_x ( 0 )
, m_y ( 0 )
, m_width ( 0 )
, m_height ( 0 )
, m_flags ( 0 )
{
}
int32_t m_x ;
int32_t m_y ;
uint32_t m_width ;
uint32_t m_height ;
uint32_t m_flags ;
2014-09-28 11:03:47 -07:00
tinystl : : string m_title ;
2014-09-22 19:34:10 -07:00
} ;
2013-01-13 10:47:30 -08:00
struct Context
{
Context ( )
2014-08-20 21:39:56 -07:00
: m_mz ( 0 )
, m_frame ( true )
2014-09-18 22:32:33 -07:00
, m_mouseLock ( NULL )
2013-01-16 22:44:51 -08:00
, m_init ( false )
2013-01-13 10:47:30 -08:00
, m_exit ( false )
{
2013-01-16 22:44:51 -08:00
memset ( s_translateKey , 0 , sizeof ( s_translateKey ) ) ;
2013-01-17 23:22:38 -08:00
s_translateKey [ VK_ESCAPE ] = Key : : Esc ;
s_translateKey [ VK_RETURN ] = Key : : Return ;
s_translateKey [ VK_TAB ] = Key : : Tab ;
s_translateKey [ VK_BACK ] = Key : : Backspace ;
s_translateKey [ VK_SPACE ] = Key : : Space ;
s_translateKey [ VK_UP ] = Key : : Up ;
s_translateKey [ VK_DOWN ] = Key : : Down ;
s_translateKey [ VK_LEFT ] = Key : : Left ;
s_translateKey [ VK_RIGHT ] = Key : : Right ;
s_translateKey [ VK_PRIOR ] = Key : : PageUp ;
s_translateKey [ VK_NEXT ] = Key : : PageUp ;
s_translateKey [ VK_HOME ] = Key : : Home ;
s_translateKey [ VK_END ] = Key : : End ;
s_translateKey [ VK_SNAPSHOT ] = Key : : Print ;
s_translateKey [ VK_OEM_PLUS ] = Key : : Plus ;
2013-01-16 22:44:51 -08:00
s_translateKey [ VK_OEM_MINUS ] = Key : : Minus ;
2013-01-17 23:22:38 -08:00
s_translateKey [ VK_F1 ] = Key : : F1 ;
s_translateKey [ VK_F2 ] = Key : : F2 ;
s_translateKey [ VK_F3 ] = Key : : F3 ;
s_translateKey [ VK_F4 ] = Key : : F4 ;
s_translateKey [ VK_F5 ] = Key : : F5 ;
s_translateKey [ VK_F6 ] = Key : : F6 ;
s_translateKey [ VK_F7 ] = Key : : F7 ;
s_translateKey [ VK_F8 ] = Key : : F8 ;
s_translateKey [ VK_F9 ] = Key : : F9 ;
s_translateKey [ VK_F10 ] = Key : : F10 ;
s_translateKey [ VK_F11 ] = Key : : F11 ;
s_translateKey [ VK_F12 ] = Key : : F12 ;
s_translateKey [ VK_NUMPAD0 ] = Key : : NumPad0 ;
s_translateKey [ VK_NUMPAD1 ] = Key : : NumPad1 ;
s_translateKey [ VK_NUMPAD2 ] = Key : : NumPad2 ;
s_translateKey [ VK_NUMPAD3 ] = Key : : NumPad3 ;
s_translateKey [ VK_NUMPAD4 ] = Key : : NumPad4 ;
s_translateKey [ VK_NUMPAD5 ] = Key : : NumPad5 ;
s_translateKey [ VK_NUMPAD6 ] = Key : : NumPad6 ;
s_translateKey [ VK_NUMPAD7 ] = Key : : NumPad7 ;
s_translateKey [ VK_NUMPAD8 ] = Key : : NumPad8 ;
s_translateKey [ VK_NUMPAD9 ] = Key : : NumPad9 ;
2014-10-16 19:54:29 -07:00
s_translateKey [ uint8_t ( ' 0 ' ) ] = Key : : Key0 ;
s_translateKey [ uint8_t ( ' 1 ' ) ] = Key : : Key1 ;
s_translateKey [ uint8_t ( ' 2 ' ) ] = Key : : Key2 ;
s_translateKey [ uint8_t ( ' 3 ' ) ] = Key : : Key3 ;
s_translateKey [ uint8_t ( ' 4 ' ) ] = Key : : Key4 ;
s_translateKey [ uint8_t ( ' 5 ' ) ] = Key : : Key5 ;
s_translateKey [ uint8_t ( ' 6 ' ) ] = Key : : Key6 ;
s_translateKey [ uint8_t ( ' 7 ' ) ] = Key : : Key7 ;
s_translateKey [ uint8_t ( ' 8 ' ) ] = Key : : Key8 ;
s_translateKey [ uint8_t ( ' 9 ' ) ] = Key : : Key9 ;
s_translateKey [ uint8_t ( ' A ' ) ] = Key : : KeyA ;
s_translateKey [ uint8_t ( ' B ' ) ] = Key : : KeyB ;
s_translateKey [ uint8_t ( ' C ' ) ] = Key : : KeyC ;
s_translateKey [ uint8_t ( ' D ' ) ] = Key : : KeyD ;
s_translateKey [ uint8_t ( ' E ' ) ] = Key : : KeyE ;
s_translateKey [ uint8_t ( ' F ' ) ] = Key : : KeyF ;
s_translateKey [ uint8_t ( ' G ' ) ] = Key : : KeyG ;
s_translateKey [ uint8_t ( ' H ' ) ] = Key : : KeyH ;
s_translateKey [ uint8_t ( ' I ' ) ] = Key : : KeyI ;
s_translateKey [ uint8_t ( ' J ' ) ] = Key : : KeyJ ;
s_translateKey [ uint8_t ( ' K ' ) ] = Key : : KeyK ;
s_translateKey [ uint8_t ( ' L ' ) ] = Key : : KeyL ;
s_translateKey [ uint8_t ( ' M ' ) ] = Key : : KeyM ;
s_translateKey [ uint8_t ( ' N ' ) ] = Key : : KeyN ;
s_translateKey [ uint8_t ( ' O ' ) ] = Key : : KeyO ;
s_translateKey [ uint8_t ( ' P ' ) ] = Key : : KeyP ;
s_translateKey [ uint8_t ( ' Q ' ) ] = Key : : KeyQ ;
s_translateKey [ uint8_t ( ' R ' ) ] = Key : : KeyR ;
s_translateKey [ uint8_t ( ' S ' ) ] = Key : : KeyS ;
s_translateKey [ uint8_t ( ' T ' ) ] = Key : : KeyT ;
s_translateKey [ uint8_t ( ' U ' ) ] = Key : : KeyU ;
s_translateKey [ uint8_t ( ' V ' ) ] = Key : : KeyV ;
s_translateKey [ uint8_t ( ' W ' ) ] = Key : : KeyW ;
s_translateKey [ uint8_t ( ' X ' ) ] = Key : : KeyX ;
s_translateKey [ uint8_t ( ' Y ' ) ] = Key : : KeyY ;
s_translateKey [ uint8_t ( ' Z ' ) ] = Key : : KeyZ ;
2013-01-13 10:47:30 -08:00
}
2013-04-18 21:16:09 -07:00
int32_t run ( int _argc , char * * _argv )
2013-01-13 10:47:30 -08:00
{
2013-10-10 22:57:42 -07:00
SetDllDirectory ( " . " ) ;
2013-01-13 10:47:30 -08:00
HINSTANCE instance = ( HINSTANCE ) GetModuleHandle ( NULL ) ;
WNDCLASSEX wnd ;
memset ( & wnd , 0 , sizeof ( wnd ) ) ;
wnd . cbSize = sizeof ( wnd ) ;
wnd . style = CS_HREDRAW | CS_VREDRAW ;
wnd . lpfnWndProc = wndProc ;
wnd . hInstance = instance ;
2014-04-16 21:03:36 -07:00
wnd . hIcon = LoadIcon ( NULL , IDI_APPLICATION ) ;
wnd . hCursor = LoadCursor ( NULL , IDC_ARROW ) ;
2013-01-13 10:47:30 -08:00
wnd . lpszClassName = " bgfx " ;
2014-04-16 21:03:36 -07:00
wnd . hIconSm = LoadIcon ( NULL , IDI_APPLICATION ) ;
2013-01-13 10:47:30 -08:00
RegisterClassExA ( & wnd ) ;
2014-09-18 22:32:33 -07:00
m_windowAlloc . alloc ( ) ;
m_hwnd [ 0 ] = CreateWindowA ( " bgfx "
2013-01-13 10:47:30 -08:00
, " BGFX "
, WS_OVERLAPPEDWINDOW | WS_VISIBLE
, 0
, 0
2013-08-14 21:08:46 -07:00
, ENTRY_DEFAULT_WIDTH
, ENTRY_DEFAULT_HEIGHT
2014-09-18 22:32:33 -07:00
, NULL
2013-01-13 10:47:30 -08:00
, NULL
, instance
, 0
) ;
2014-10-11 20:42:42 -07:00
m_flags [ 0 ] = 0
| ENTRY_WINDOW_FLAG_ASPECT_RATIO
| ENTRY_WINDOW_FLAG_FRAME
;
2014-09-22 19:34:10 -07:00
2014-09-18 22:32:33 -07:00
bgfx : : winSetHwnd ( m_hwnd [ 0 ] ) ;
2013-01-13 10:47:30 -08:00
2014-09-18 22:32:33 -07:00
adjust ( m_hwnd [ 0 ] , ENTRY_DEFAULT_WIDTH , ENTRY_DEFAULT_HEIGHT , true ) ;
2014-09-22 22:03:41 -07:00
clear ( m_hwnd [ 0 ] ) ;
2013-08-14 21:08:46 -07:00
m_width = ENTRY_DEFAULT_WIDTH ;
m_height = ENTRY_DEFAULT_HEIGHT ;
m_oldWidth = ENTRY_DEFAULT_WIDTH ;
m_oldHeight = ENTRY_DEFAULT_HEIGHT ;
2013-01-13 10:47:30 -08:00
MainThreadEntry mte ;
mte . m_argc = _argc ;
mte . m_argv = _argv ;
bx : : Thread thread ;
thread . init ( mte . threadFunc , & mte ) ;
2013-01-16 22:44:51 -08:00
m_init = true ;
2013-01-13 10:47:30 -08:00
2014-09-18 22:32:33 -07:00
m_eventQueue . postSizeEvent ( findHandle ( m_hwnd [ 0 ] ) , m_width , m_height ) ;
2013-01-19 12:38:30 -08:00
2013-01-13 10:47:30 -08:00
MSG msg ;
msg . message = WM_NULL ;
while ( ! m_exit )
{
WaitMessage ( ) ;
while ( 0 ! = PeekMessage ( & msg , NULL , 0U , 0U , PM_REMOVE ) )
{
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
}
thread . shutdown ( ) ;
2014-09-18 22:32:33 -07:00
DestroyWindow ( m_hwnd [ 0 ] ) ;
2013-01-16 22:44:51 -08:00
2013-01-13 10:47:30 -08:00
return 0 ;
}
LRESULT process ( HWND _hwnd , UINT _id , WPARAM _wparam , LPARAM _lparam )
{
2013-01-16 22:44:51 -08:00
if ( m_init )
2013-01-13 10:47:30 -08:00
{
2013-01-16 22:44:51 -08:00
switch ( _id )
2013-01-13 10:47:30 -08:00
{
2014-09-22 19:34:10 -07:00
case WM_USER_WINDOW_CREATE :
2014-09-18 22:32:33 -07:00
{
2014-09-22 19:34:10 -07:00
Msg * msg = ( Msg * ) _lparam ;
2014-09-18 22:32:33 -07:00
HWND hwnd = CreateWindowA ( " bgfx "
2014-09-22 19:34:10 -07:00
, msg - > m_title . c_str ( )
2014-09-18 22:32:33 -07:00
, WS_OVERLAPPEDWINDOW | WS_VISIBLE
2014-09-22 19:34:10 -07:00
, msg - > m_x
, msg - > m_y
, msg - > m_width
, msg - > m_height
, m_hwnd [ 0 ]
2014-09-18 22:32:33 -07:00
, NULL
, ( HINSTANCE ) GetModuleHandle ( NULL )
, 0
) ;
2014-09-22 22:03:41 -07:00
clear ( hwnd ) ;
2014-09-18 22:32:33 -07:00
2014-09-23 20:35:39 -07:00
m_hwnd [ _wparam ] = hwnd ;
m_flags [ _wparam ] = msg - > m_flags ;
2014-09-18 22:32:33 -07:00
WindowHandle handle = { ( uint16_t ) _wparam } ;
2014-09-22 19:34:10 -07:00
m_eventQueue . postSizeEvent ( handle , msg - > m_width , msg - > m_height ) ;
2014-09-22 23:00:42 -07:00
m_eventQueue . postWindowEvent ( handle , hwnd ) ;
2014-09-22 19:34:10 -07:00
delete msg ;
}
break ;
case WM_USER_WINDOW_DESTROY :
{
WindowHandle handle = { ( uint16_t ) _wparam } ;
PostMessageA ( m_hwnd [ _wparam ] , WM_CLOSE , 0 , 0 ) ;
m_eventQueue . postWindowEvent ( handle ) ;
2014-09-30 22:20:16 -07:00
DestroyWindow ( m_hwnd [ _wparam ] ) ;
2014-09-22 19:34:10 -07:00
m_hwnd [ _wparam ] = 0 ;
}
break ;
case WM_USER_WINDOW_SET_TITLE :
{
Msg * msg = ( Msg * ) _lparam ;
SetWindowTextA ( m_hwnd [ _wparam ] , msg - > m_title . c_str ( ) ) ;
delete msg ;
2014-09-18 22:32:33 -07:00
}
break ;
2014-09-22 19:34:10 -07:00
case WM_USER_WINDOW_SET_POS :
{
Msg * msg = ( Msg * ) _lparam ;
SetWindowPos ( m_hwnd [ _wparam ] , 0 , msg - > m_x , msg - > m_y , 0 , 0
, SWP_NOACTIVATE
| SWP_NOOWNERZORDER
| SWP_NOSIZE
) ;
delete msg ;
}
break ;
case WM_USER_WINDOW_SET_SIZE :
2013-01-16 22:44:51 -08:00
{
2014-09-18 22:32:33 -07:00
uint32_t width = GET_X_LPARAM ( _lparam ) ;
2013-01-16 22:44:51 -08:00
uint32_t height = GET_Y_LPARAM ( _lparam ) ;
2014-09-18 22:32:33 -07:00
adjust ( m_hwnd [ _wparam ] , width , height , true ) ;
2013-01-16 22:44:51 -08:00
}
break ;
2013-01-13 10:47:30 -08:00
2014-09-22 19:34:10 -07:00
case WM_USER_WINDOW_TOGGLE_FRAME :
2013-01-13 10:47:30 -08:00
{
2013-01-16 22:44:51 -08:00
if ( m_frame )
2013-01-13 10:47:30 -08:00
{
2014-09-22 19:34:10 -07:00
m_oldWidth = m_width ;
2013-01-16 22:44:51 -08:00
m_oldHeight = m_height ;
2013-01-13 10:47:30 -08:00
}
2014-09-18 22:32:33 -07:00
adjust ( m_hwnd [ _wparam ] , m_oldWidth , m_oldHeight , ! m_frame ) ;
2013-01-16 22:44:51 -08:00
}
break ;
2014-09-22 19:34:10 -07:00
case WM_USER_WINDOW_MOUSE_LOCK :
setMouseLock ( m_hwnd [ _wparam ] , ! ! _lparam ) ;
2013-01-19 00:22:25 -08:00
break ;
2013-01-16 22:44:51 -08:00
case WM_DESTROY :
break ;
2013-01-13 10:47:30 -08:00
2013-01-16 22:44:51 -08:00
case WM_QUIT :
case WM_CLOSE :
2014-09-18 22:32:33 -07:00
if ( _hwnd = = m_hwnd [ 0 ] )
{
m_exit = true ;
m_eventQueue . postExitEvent ( ) ;
}
2014-09-22 19:34:10 -07:00
else
{
destroyWindow ( findHandle ( _hwnd ) ) ;
}
2014-09-30 19:04:24 -07:00
// Don't process message. Window will be destroyed later.
return 0 ;
2013-01-16 22:44:51 -08:00
case WM_SIZING :
{
2014-09-22 19:34:10 -07:00
WindowHandle handle = findHandle ( _hwnd ) ;
2013-01-16 22:44:51 -08:00
2014-09-22 19:34:10 -07:00
if ( isValid ( handle )
& & ENTRY_WINDOW_FLAG_ASPECT_RATIO & m_flags [ handle . idx ] )
2013-01-13 10:47:30 -08:00
{
2014-09-22 19:34:10 -07:00
RECT & rect = * ( RECT * ) _lparam ;
uint32_t width = rect . right - rect . left - m_frameWidth ;
uint32_t height = rect . bottom - rect . top - m_frameHeight ;
// Recalculate size according to aspect ratio
switch ( _wparam )
2013-01-16 22:44:51 -08:00
{
2014-09-22 19:34:10 -07:00
case WMSZ_LEFT :
case WMSZ_RIGHT :
{
float aspectRatio = 1.0f / m_aspectRatio ;
width = bx : : uint32_max ( ENTRY_DEFAULT_WIDTH / 4 , width ) ;
height = uint32_t ( float ( width ) * aspectRatio ) ;
}
break ;
default :
{
float aspectRatio = m_aspectRatio ;
height = bx : : uint32_max ( ENTRY_DEFAULT_HEIGHT / 4 , height ) ;
width = uint32_t ( float ( height ) * aspectRatio ) ;
}
break ;
2013-01-16 22:44:51 -08:00
}
2014-09-22 19:34:10 -07:00
// Recalculate position using different anchor points
switch ( _wparam )
2013-01-16 22:44:51 -08:00
{
2014-09-22 19:34:10 -07:00
case WMSZ_LEFT :
case WMSZ_TOPLEFT :
case WMSZ_BOTTOMLEFT :
rect . left = rect . right - width - m_frameWidth ;
rect . bottom = rect . top + height + m_frameHeight ;
break ;
default :
rect . right = rect . left + width + m_frameWidth ;
rect . bottom = rect . top + height + m_frameHeight ;
break ;
2013-01-16 22:44:51 -08:00
}
2013-01-13 10:47:30 -08:00
2014-09-22 19:34:10 -07:00
m_eventQueue . postSizeEvent ( findHandle ( _hwnd ) , width , height ) ;
2013-02-27 01:25:23 -08:00
}
2013-01-16 22:44:51 -08:00
}
return 0 ;
2013-01-13 10:47:30 -08:00
2013-01-16 22:44:51 -08:00
case WM_SIZE :
{
2014-09-22 19:34:10 -07:00
WindowHandle handle = findHandle ( _hwnd ) ;
if ( isValid ( handle ) )
{
uint32_t width = GET_X_LPARAM ( _lparam ) ;
uint32_t height = GET_Y_LPARAM ( _lparam ) ;
2013-01-19 12:11:24 -08:00
2014-09-22 19:34:10 -07:00
m_width = width ;
m_height = height ;
m_eventQueue . postSizeEvent ( handle , m_width , m_height ) ;
}
2013-01-16 22:44:51 -08:00
}
break ;
2013-01-13 10:47:30 -08:00
2013-01-16 22:44:51 -08:00
case WM_SYSCOMMAND :
switch ( _wparam )
2013-01-13 10:47:30 -08:00
{
2013-01-16 22:44:51 -08:00
case SC_MINIMIZE :
case SC_RESTORE :
2013-01-13 10:47:30 -08:00
{
2013-01-16 22:44:51 -08:00
HWND parent = GetWindow ( _hwnd , GW_OWNER ) ;
if ( NULL ! = parent )
{
PostMessage ( parent , _id , _wparam , _lparam ) ;
}
2013-01-13 10:47:30 -08:00
}
}
2013-01-16 22:44:51 -08:00
break ;
2013-01-13 10:47:30 -08:00
2013-01-17 23:22:38 -08:00
case WM_MOUSEMOVE :
{
int32_t mx = GET_X_LPARAM ( _lparam ) ;
int32_t my = GET_Y_LPARAM ( _lparam ) ;
2013-01-19 00:22:25 -08:00
2014-09-18 22:32:33 -07:00
if ( _hwnd = = m_mouseLock )
2013-01-19 00:22:25 -08:00
{
mx - = m_mx ;
my - = m_my ;
if ( 0 = = mx
& & 0 = = my )
{
break ;
}
2014-09-18 22:32:33 -07:00
setMousePos ( _hwnd , m_mx , m_my ) ;
2013-01-19 00:22:25 -08:00
}
2014-09-18 22:32:33 -07:00
m_eventQueue . postMouseEvent ( findHandle ( _hwnd ) , mx , my , m_mz ) ;
2014-08-05 21:13:50 -07:00
}
break ;
case WM_MOUSEWHEEL :
{
2014-08-05 22:03:45 -07:00
POINT pt = { GET_X_LPARAM ( _lparam ) , GET_Y_LPARAM ( _lparam ) } ;
2014-09-18 22:32:33 -07:00
ScreenToClient ( _hwnd , & pt ) ;
2014-08-05 22:03:45 -07:00
int32_t mx = pt . x ;
int32_t my = pt . y ;
2014-08-05 22:37:47 -07:00
m_mz + = GET_WHEEL_DELTA_WPARAM ( _wparam ) ;
2014-09-18 22:32:33 -07:00
m_eventQueue . postMouseEvent ( findHandle ( _hwnd ) , mx , my , m_mz ) ;
2013-01-17 23:22:38 -08:00
}
break ;
2013-01-16 22:44:51 -08:00
case WM_LBUTTONDOWN :
case WM_LBUTTONUP :
case WM_LBUTTONDBLCLK :
{
int32_t mx = GET_X_LPARAM ( _lparam ) ;
int32_t my = GET_Y_LPARAM ( _lparam ) ;
2014-09-18 22:32:33 -07:00
m_eventQueue . postMouseEvent ( findHandle ( _hwnd ) , mx , my , m_mz , MouseButton : : Left , _id = = WM_LBUTTONDOWN ) ;
2013-01-16 22:44:51 -08:00
}
break ;
case WM_MBUTTONDOWN :
case WM_MBUTTONUP :
case WM_MBUTTONDBLCLK :
{
int32_t mx = GET_X_LPARAM ( _lparam ) ;
int32_t my = GET_Y_LPARAM ( _lparam ) ;
2014-09-18 22:32:33 -07:00
m_eventQueue . postMouseEvent ( findHandle ( _hwnd ) , mx , my , m_mz , MouseButton : : Middle , _id = = WM_MBUTTONDOWN ) ;
2013-01-16 22:44:51 -08:00
}
break ;
case WM_RBUTTONUP :
case WM_RBUTTONDOWN :
case WM_RBUTTONDBLCLK :
{
int32_t mx = GET_X_LPARAM ( _lparam ) ;
int32_t my = GET_Y_LPARAM ( _lparam ) ;
2014-09-18 22:32:33 -07:00
m_eventQueue . postMouseEvent ( findHandle ( _hwnd ) , mx , my , m_mz , MouseButton : : Right , _id = = WM_RBUTTONDOWN ) ;
2013-01-16 22:44:51 -08:00
}
break ;
2013-01-13 10:47:30 -08:00
2013-01-16 22:44:51 -08:00
case WM_KEYDOWN :
case WM_SYSKEYDOWN :
case WM_KEYUP :
case WM_SYSKEYUP :
{
uint8_t modifiers = translateKeyModifiers ( ) ;
Key : : Enum key = translateKey ( _wparam ) ;
2013-10-23 22:48:16 -07:00
2014-09-18 22:32:33 -07:00
WindowHandle handle = findHandle ( _hwnd ) ;
2013-10-23 22:48:16 -07:00
if ( Key : : Print = = key
2014-01-13 20:36:33 -08:00
& & 0x3 = = ( ( uint32_t ) ( _lparam ) > > 30 ) )
2013-10-23 22:48:16 -07:00
{
// VK_SNAPSHOT doesn't generate keydown event. Fire on down event when previous
// key state bit is set to 1 and transition state bit is set to 1.
//
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms646280%28v=vs.85%29.aspx
2014-09-18 22:32:33 -07:00
m_eventQueue . postKeyEvent ( handle , key , modifiers , true ) ;
2013-10-23 22:48:16 -07:00
}
2014-09-18 22:32:33 -07:00
m_eventQueue . postKeyEvent ( handle , key , modifiers , _id = = WM_KEYDOWN | | _id = = WM_SYSKEYDOWN ) ;
2013-01-16 22:44:51 -08:00
}
break ;
2014-11-08 20:57:47 -08:00
case WM_CHAR :
{
uint8_t utf8 [ 4 ] = { } ;
uint8_t len = ( uint8_t ) WideCharToMultiByte ( CP_UTF8
, 0
, ( LPCWSTR ) & _wparam
, 1
, ( LPSTR ) utf8
, BX_COUNTOF ( utf8 )
, NULL
, NULL
) ;
if ( 0 ! = len )
{
WindowHandle handle = findHandle ( _hwnd ) ;
m_eventQueue . postCharEvent ( handle , len , utf8 ) ;
}
}
break ;
2013-01-16 22:44:51 -08:00
default :
break ;
}
2013-01-13 10:47:30 -08:00
}
return DefWindowProc ( _hwnd , _id , _wparam , _lparam ) ;
}
2014-09-18 22:32:33 -07:00
WindowHandle findHandle ( HWND _hwnd )
{
bx : : LwMutexScope scope ( m_lock ) ;
for ( uint32_t ii = 0 , num = m_windowAlloc . getNumHandles ( ) ; ii < num ; + + ii )
{
uint16_t idx = m_windowAlloc . getHandleAt ( ii ) ;
if ( _hwnd = = m_hwnd [ idx ] )
{
WindowHandle handle = { idx } ;
return handle ;
}
}
WindowHandle invalid = { UINT16_MAX } ;
return invalid ;
}
2014-09-22 22:03:41 -07:00
void clear ( HWND _hwnd )
{
RECT rect ;
GetWindowRect ( _hwnd , & rect ) ;
HBRUSH brush = CreateSolidBrush ( RGB ( 0 , 0 , 0 ) ) ;
HDC hdc = GetDC ( _hwnd ) ;
SelectObject ( hdc , brush ) ;
FillRect ( hdc , & rect , brush ) ;
}
2014-09-18 22:32:33 -07:00
void adjust ( HWND _hwnd , uint32_t _width , uint32_t _height , bool _windowFrame )
2013-01-13 10:47:30 -08:00
{
m_width = _width ;
m_height = _height ;
m_aspectRatio = float ( _width ) / float ( _height ) ;
2014-09-18 22:32:33 -07:00
ShowWindow ( _hwnd , SW_SHOWNORMAL ) ;
2013-01-13 10:47:30 -08:00
RECT rect ;
RECT newrect = { 0 , 0 , ( LONG ) _width , ( LONG ) _height } ;
DWORD style = WS_POPUP | WS_SYSMENU ;
if ( m_frame )
{
2014-09-18 22:32:33 -07:00
GetWindowRect ( _hwnd , & m_rect ) ;
m_style = GetWindowLong ( _hwnd , GWL_STYLE ) ;
2013-01-13 10:47:30 -08:00
}
if ( _windowFrame )
{
rect = m_rect ;
style = m_style ;
}
else
{
# if defined(__MINGW32__)
2014-09-18 22:32:33 -07:00
rect = m_rect ;
2013-01-13 10:47:30 -08:00
style = m_style ;
# else
2014-09-18 22:32:33 -07:00
HMONITOR monitor = MonitorFromWindow ( _hwnd , MONITOR_DEFAULTTONEAREST ) ;
2013-01-13 10:47:30 -08:00
MONITORINFO mi ;
mi . cbSize = sizeof ( mi ) ;
GetMonitorInfo ( monitor , & mi ) ;
newrect = mi . rcMonitor ;
rect = mi . rcMonitor ;
# endif // !defined(__MINGW__)
}
2014-09-18 22:32:33 -07:00
SetWindowLong ( _hwnd , GWL_STYLE , style ) ;
2013-02-27 01:25:23 -08:00
uint32_t prewidth = newrect . right - newrect . left ;
uint32_t preheight = newrect . bottom - newrect . top ;
2013-01-13 10:47:30 -08:00
AdjustWindowRect ( & newrect , style , FALSE ) ;
2013-02-27 01:25:23 -08:00
m_frameWidth = ( newrect . right - newrect . left ) - prewidth ;
m_frameHeight = ( newrect . bottom - newrect . top ) - preheight ;
2014-09-18 22:32:33 -07:00
UpdateWindow ( _hwnd ) ;
2013-01-13 10:47:30 -08:00
if ( rect . left = = - 32000
2014-09-22 19:34:10 -07:00
| | rect . top = = - 32000 )
2013-01-13 10:47:30 -08:00
{
rect . left = 0 ;
2014-09-22 19:34:10 -07:00
rect . top = 0 ;
2013-01-13 10:47:30 -08:00
}
int32_t left = rect . left ;
int32_t top = rect . top ;
int32_t width = ( newrect . right - newrect . left ) ;
int32_t height = ( newrect . bottom - newrect . top ) ;
if ( ! _windowFrame )
{
float aspectRatio = 1.0f / m_aspectRatio ;
2013-08-14 21:08:46 -07:00
width = bx : : uint32_max ( ENTRY_DEFAULT_WIDTH / 4 , width ) ;
2013-01-13 10:47:30 -08:00
height = uint32_t ( float ( width ) * aspectRatio ) ;
left = newrect . left + ( newrect . right - newrect . left - width ) / 2 ;
top = newrect . top + ( newrect . bottom - newrect . top - height ) / 2 ;
}
2014-09-18 22:32:33 -07:00
HWND parent = GetWindow ( _hwnd , GW_OWNER ) ;
2013-01-13 10:47:30 -08:00
if ( NULL ! = parent )
{
if ( _windowFrame )
{
SetWindowPos ( parent
, HWND_TOP
, - 32000
, - 32000
, 0
, 0
, SWP_SHOWWINDOW
) ;
}
else
{
SetWindowPos ( parent
, HWND_TOP
, newrect . left
, newrect . top
, newrect . right - newrect . left
, newrect . bottom - newrect . top
, SWP_SHOWWINDOW
) ;
}
}
2014-09-18 22:32:33 -07:00
SetWindowPos ( _hwnd
2013-01-13 10:47:30 -08:00
, HWND_TOP
, left
, top
, width
, height
, SWP_SHOWWINDOW
) ;
2014-09-18 22:32:33 -07:00
ShowWindow ( _hwnd , SW_RESTORE ) ;
2013-01-13 10:47:30 -08:00
m_frame = _windowFrame ;
}
2014-09-18 22:32:33 -07:00
void setMousePos ( HWND _hwnd , int32_t _mx , int32_t _my )
2013-01-19 00:22:25 -08:00
{
POINT pt = { _mx , _my } ;
2014-09-18 22:32:33 -07:00
ClientToScreen ( _hwnd , & pt ) ;
2013-01-19 00:22:25 -08:00
SetCursorPos ( pt . x , pt . y ) ;
}
2014-09-18 22:32:33 -07:00
void setMouseLock ( HWND _hwnd , bool _lock )
2013-01-19 00:22:25 -08:00
{
2014-09-18 22:32:33 -07:00
if ( _hwnd ! = m_mouseLock )
2013-01-19 00:22:25 -08:00
{
if ( _lock )
{
m_mx = m_width / 2 ;
m_my = m_height / 2 ;
ShowCursor ( false ) ;
2014-09-18 22:32:33 -07:00
setMousePos ( _hwnd , m_mx , m_my ) ;
2013-01-19 00:22:25 -08:00
}
else
{
2014-09-18 22:32:33 -07:00
setMousePos ( _hwnd , m_mx , m_my ) ;
2013-01-19 00:22:25 -08:00
ShowCursor ( true ) ;
}
2014-09-18 22:32:33 -07:00
m_mouseLock = _hwnd ;
2013-01-19 00:22:25 -08:00
}
}
2013-01-13 10:47:30 -08:00
static LRESULT CALLBACK wndProc ( HWND _hwnd , UINT _id , WPARAM _wparam , LPARAM _lparam ) ;
2013-01-16 22:44:51 -08:00
EventQueue m_eventQueue ;
2014-09-18 22:32:33 -07:00
bx : : LwMutex m_lock ;
2013-01-13 10:47:30 -08:00
2014-09-18 22:32:33 -07:00
bx : : HandleAllocT < ENTRY_CONFIG_MAX_WINDOWS > m_windowAlloc ;
HWND m_hwnd [ ENTRY_CONFIG_MAX_WINDOWS ] ;
2014-09-22 19:34:10 -07:00
uint32_t m_flags [ ENTRY_CONFIG_MAX_WINDOWS ] ;
2013-01-13 10:47:30 -08:00
RECT m_rect ;
DWORD m_style ;
uint32_t m_width ;
uint32_t m_height ;
2013-01-16 22:44:51 -08:00
uint32_t m_oldWidth ;
uint32_t m_oldHeight ;
2013-02-27 01:25:23 -08:00
uint32_t m_frameWidth ;
uint32_t m_frameHeight ;
2013-01-13 10:47:30 -08:00
float m_aspectRatio ;
2013-01-19 00:22:25 -08:00
int32_t m_mx ;
int32_t m_my ;
2014-08-05 22:37:47 -07:00
int32_t m_mz ;
2013-01-19 00:22:25 -08:00
2013-01-13 10:47:30 -08:00
bool m_frame ;
2014-09-18 22:32:33 -07:00
HWND m_mouseLock ;
2013-01-16 22:44:51 -08:00
bool m_init ;
2013-01-13 10:47:30 -08:00
bool m_exit ;
2013-01-16 22:44:51 -08:00
2013-01-13 10:47:30 -08:00
} ;
static Context s_ctx ;
2013-01-13 15:35:06 -08:00
2013-01-13 10:47:30 -08:00
LRESULT CALLBACK Context : : wndProc ( HWND _hwnd , UINT _id , WPARAM _wparam , LPARAM _lparam )
{
return s_ctx . process ( _hwnd , _id , _wparam , _lparam ) ;
}
2013-01-16 22:44:51 -08:00
const Event * poll ( )
{
return s_ctx . m_eventQueue . poll ( ) ;
}
2014-09-22 19:34:10 -07:00
const Event * poll ( WindowHandle _handle )
{
return s_ctx . m_eventQueue . poll ( _handle ) ;
}
2013-01-16 22:44:51 -08:00
void release ( const Event * _event )
{
s_ctx . m_eventQueue . release ( _event ) ;
}
2014-09-22 19:34:10 -07:00
WindowHandle createWindow ( int32_t _x , int32_t _y , uint32_t _width , uint32_t _height , uint32_t _flags , const char * _title )
2014-09-18 22:32:33 -07:00
{
bx : : LwMutexScope scope ( s_ctx . m_lock ) ;
WindowHandle handle = { s_ctx . m_windowAlloc . alloc ( ) } ;
if ( UINT16_MAX ! = handle . idx )
{
2014-09-22 19:34:10 -07:00
Msg * msg = new Msg ;
msg - > m_x = _x ;
msg - > m_y = _y ;
msg - > m_width = _width ;
msg - > m_height = _height ;
msg - > m_title = _title ;
msg - > m_flags = _flags ;
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_CREATE , handle . idx , ( LPARAM ) msg ) ;
2014-09-18 22:32:33 -07:00
}
return handle ;
}
void destroyWindow ( WindowHandle _handle )
{
2014-09-22 19:34:10 -07:00
if ( UINT16_MAX ! = _handle . idx )
{
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_DESTROY , _handle . idx , 0 ) ;
bx : : LwMutexScope scope ( s_ctx . m_lock ) ;
s_ctx . m_windowAlloc . free ( _handle . idx ) ;
}
}
void setWindowPos ( WindowHandle _handle , int32_t _x , int32_t _y )
{
Msg * msg = new Msg ;
msg - > m_x = _x ;
msg - > m_y = _y ;
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_SET_POS , _handle . idx , ( LPARAM ) msg ) ;
2014-09-18 22:32:33 -07:00
}
void setWindowSize ( WindowHandle _handle , uint32_t _width , uint32_t _height )
2013-02-21 21:07:31 -08:00
{
2014-09-22 19:34:10 -07:00
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_SET_SIZE , _handle . idx , ( _height < < 16 ) | ( _width & 0xffff ) ) ;
2013-01-16 22:44:51 -08:00
}
2014-09-18 22:32:33 -07:00
void setWindowTitle ( WindowHandle _handle , const char * _title )
2014-08-05 20:57:52 +01:00
{
2014-09-22 19:34:10 -07:00
Msg * msg = new Msg ;
msg - > m_title = _title ;
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_SET_TITLE , _handle . idx , ( LPARAM ) msg ) ;
2014-08-05 20:57:52 +01:00
}
2014-09-18 22:32:33 -07:00
void toggleWindowFrame ( WindowHandle _handle )
2013-02-21 21:07:31 -08:00
{
2014-09-22 19:34:10 -07:00
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_TOGGLE_FRAME , _handle . idx , 0 ) ;
2013-01-16 22:44:51 -08:00
}
2014-09-18 22:32:33 -07:00
void setMouseLock ( WindowHandle _handle , bool _lock )
2013-01-19 00:22:25 -08:00
{
2014-09-22 19:34:10 -07:00
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_USER_WINDOW_MOUSE_LOCK , _handle . idx , _lock ) ;
2013-01-19 00:22:25 -08:00
}
2013-01-16 22:44:51 -08:00
int32_t MainThreadEntry : : threadFunc ( void * _userData )
2013-01-13 15:35:06 -08:00
{
2013-01-16 22:44:51 -08:00
MainThreadEntry * self = ( MainThreadEntry * ) _userData ;
2013-08-07 21:45:56 -07:00
int32_t result = main ( self - > m_argc , self - > m_argv ) ;
2014-09-18 22:32:33 -07:00
PostMessage ( s_ctx . m_hwnd [ 0 ] , WM_QUIT , 0 , 0 ) ;
2013-01-16 22:44:51 -08:00
return result ;
2013-01-13 15:35:06 -08:00
}
} // namespace entry
int main ( int _argc , char * * _argv )
{
using namespace entry ;
2013-04-18 21:16:09 -07:00
return s_ctx . run ( _argc , _argv ) ;
2013-01-13 15:35:06 -08:00
}
# endif // BX_PLATFORM_WINDOWS