/* * Copyright 2011-2017 Branimir Karadzic. All rights reserved. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause */#include"entry_p.h"#if ENTRY_CONFIG_USE_NATIVE && BX_PLATFORM_WINDOWS#include<bgfx/platform.h>#include<bx/mutex.h>#include<bx/handlealloc.h>#include<bx/os.h>#include<bx/thread.h>#include<bx/timer.h>#include<bx/uint32_t.h>#include<tinystl/allocator.h>#include<tinystl/string.h>#include<windows.h>#include<windowsx.h>#include<xinput.h>#ifndef XINPUT_GAMEPAD_GUIDE# define XINPUT_GAMEPAD_GUIDE 0x400#endif // XINPUT_GAMEPAD_GUIDE#ifndef XINPUT_DLL_A# define XINPUT_DLL_A "xinput.dll"#endif // XINPUT_DLL_Anamespaceentry{///inlinevoidwinSetHwnd(::HWND_window){bgfx::PlatformDatapd;bx::memSet(&pd,0,sizeof(pd));pd.nwh=_window;bgfx::setPlatformData(pd);}typedefDWORD(WINAPI*PFN_XINPUT_GET_STATE)(DWORDdwUserIndex,XINPUT_STATE*pState);typedefvoid(WINAPI*PFN_XINPUT_ENABLE)(BOOLenable);// 1.4+PFN_XINPUT_GET_STATEXInputGetState;PFN_XINPUT_ENABLEXInputEnable;structXInputRemap{uint16_tm_bit;Key::Enumm_key;};staticXInputRemaps_xinputRemap[]={{XINPUT_GAMEPAD_DPAD_UP,Key::GamepadUp},{XINPUT_GAMEPAD_DPAD_DOWN,Key::GamepadDown},{XINPUT_GAMEPAD_DPAD_LEFT,Key::GamepadLeft},{XINPUT_GAMEPAD_DPAD_RIGHT,Key::GamepadRight},{XINPUT_GAMEPAD_START,Key::GamepadStart},{XINPUT_GAMEPAD_BACK,Key::GamepadBack},{XINPUT_GAMEPAD_LEFT_THUMB,Key::GamepadThumbL},{XINPUT_GAMEPAD_RIGHT_THUMB,Key::GamepadThumbR},{XINPUT_GAMEPAD_LEFT_SHOULDER,Key::GamepadShoulderL},{XINPUT_GAMEPAD_RIGHT_SHOULDER,Key::GamepadShoulderR},{XINPUT_GAMEPAD_GUIDE,Key::GamepadGuide},{XINPUT_GAMEPAD_A,Key::GamepadA},{XINPUT_GAMEPAD_B,Key::GamepadB},{XINPUT_GAMEPAD_X,Key::GamepadX},{XINPUT_GAMEPAD_Y,Key::GamepadY},};structXInput{XInput():m_xinputdll(NULL){bx::memSet(m_connected,0,sizeof(m_connected));bx::memSet(m_state,0,sizeof(m_state));m_deadzone[GamepadAxis::LeftX]=m_deadzone[GamepadAxis::LeftY]=XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE;m_deadzone[GamepadAxis::RightX]=m_deadzone[GamepadAxis::RightY]=XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE;m_deadzone[GamepadAxis::LeftZ]=m_deadzone[GamepadAxis::RightZ]=XINPUT_GAMEPAD_TRIGGER_THRESHOLD;bx::memSet(m_flip,1,sizeof(m_flip));m_flip[GamepadAxis::LeftY]=m_flip[GamepadAxis::RightY]=-1;}voidinit(){m_xinputdll=bx::dlopen(XINPUT_DLL_A);if(NULL!=m_xinputdll){XInputGetState=(PFN_XINPUT_GET_STATE)bx::dlsym(m_xinputdll,"XInputGetState");// XInputEnable = (PFN_XINPUT_ENABLE )bx::dlsym(m_xinputdll, "XInputEnable" );if(NULL==XInputGetState){shutdown();}}}voidshutdown(){if(NULL!=m_xinputdll){bx::dlclose(m_xinputdll);m_xinputdll=NULL;}}boolfilter(GamepadAxis::Enum_axis,int32_t_old,int32_t*_value){constint32_tdeadzone=m_deadzone[_axis];int32_tvalue=*_value;value=value>deadzone||value<-deadzone?value:0;*_value=value*m_flip[_axis];return_old!=value;}voidupdate(EventQueue&_eventQueue){int64_tnow=bx::getHPCounter();staticint64_tnext=now;if(now<next){return;}constint64_ttimerFreq=bx::getHPFrequency();next=now+timerFreq/60;if(NULL==m_xinputdll){return;}WindowHandledefaultWindow={0};for(uint16_tii=0;ii<BX_COUNTOF(m_state);++ii){XINPUT_STATEstate;DWORDresult=XInputGetState(ii,&state);GamepadHandlehandle={ii};boolconnected=ERROR_SUCCESS==result;if(connected!=m_connected[ii]){_eventQueue.postGamepadEvent(defaultWindow,handle,connected);}m_connected[ii]=connected;if(connected&&m_state[ii].dwPacketNumber!=state.dwPacketNumber){XINPUT_GAMEPAD&gamepad=m_state[ii].Gamepad;constuint16_tchanged=gamepad.wButtons^state.Gamepad.wButtons;constuint16_tcurrent=gamepad.wButtons;if(0!=changed){for(uint32_tjj=0;jj<BX_COUNTOF(s_xinputRemap);++jj){uint16_tbit=s_xinputRemap[jj].m_bit;if(bit&changed){_eventQueue.postKeyEvent(defaultWindow,s_xinputRemap[jj].m_key,0,0==(current&bit));}}gamepad.wButtons=state.Gamepad.wButtons;}if(gamepad.bLeftTrigger!=state.Gamepad.bLeftTrigger){int32_tvalue=state.Gamepad.bLeftTrigger;if(filter(GamepadAxis::LeftZ,gamepad.bLeftTrigger,&value)){_eventQueue.postAxisEvent(defaultWindow,handle,GamepadAxis::LeftZ,value);}gamepad.bLeftTrigger=state.Gamepad.bLeftTrigger;}if(gamepad.bRightTrigger!=state.Gamepad.bRightTrigger){int32_tvalue=state.Gamepad.bRightTrigger;if(filter(GamepadAxis::RightZ,gamepad.bRightTrigger,&value)){_eventQueue.postAxisEvent(defaultWindow,handle,GamepadAxis::RightZ,value);}gamepad.bRightTrigger=state.Gamepad.bRightTrigger;}if(gamepad.sThumbLX!=state.Gamepad.sThumbLX){int32_tvalue=state.Gamepad.sThumbLX;if(filter(GamepadAxis::LeftX,gamepad.sThumbLX,&value)){_eventQueue.postAxisEvent(defaultWindow,handle,GamepadAxis::LeftX,value);}gamepad.sThumbLX=state.Gamepad.sThumbLX;}if(gamepad.sThumbLY!=state.Gamepad.sThumbLY){int32_tvalue=state.Gamepad.sThumbLY;if(filter(GamepadAxis::LeftY,gamepad.sThumbLY,&value)){_eventQueue.postAxisEvent(defaultWindow,handle,GamepadAxis::LeftY,value);}gamepad.sThumbLY=state.Gamepad.sThumbLY;}if(gamepad.sThumbRX!=state.Gamepad.sThumbRX){int32_tvalue=state.Gamepad.sThumbRX;if(filter(GamepadAxis::RightX,gamepad.sThumbRX,&value)){_eventQueue.postAxisEvent(defaultWindow,handle,GamepadAxis::RightX,value);}gamepad.sThumbRX=state.Gamepad.sThumbRX;}if(gamepad.sThumbRY!=state.Gamepad.sThumbRY){int32_tvalue=state.Gamepad.sThumbRY;if(filter(GamepadAxis::RightY,gamepad.sThumbRY,&value)){_eventQueue.postAxisEvent(defaultWindow,handle,GamepadAxis::RightY,value);}gamepad.sThumbRY=state.Gamepad.sThumbRY;}}}}void*m_xinputdll;int32_tm_deadzone[GamepadAxis::Count];int8_tm_flip[GamepadAxis::Count];XINPUT_STATEm_state[ENTRY_CONFIG_MAX_GAMEPADS];boolm_connected[ENTRY_CONFIG_MAX_GAMEPADS];};XInputs_xinput;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,};structTranslateKeyModifiers{intm_vk;Modifier::Enumm_modifier;};staticconstTranslateKeyModifierss_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},};staticuint8_ttranslateKeyModifiers(){uint8_tmodifiers=0;for(uint32_tii=0;ii<BX_COUNTOF(s_translateKeyModifiers);++ii){constTranslateKeyModifiers&tkm=s_translateKeyModifiers[ii];modifiers|=0>GetKeyState(tkm.m_vk)?tkm.m_modifier:Modifier::None;}returnmodifiers;}staticuint8_ts_translateKey[256];staticKey::EnumtranslateKey(WPARAM_wparam){return(Key::Enum)s_translateKey[_wparam&0xff];}structMainThreadEntry{intm_argc;constchar*const*m_argv;staticint32_tthreadFunc(bx::Thread*_thread,void*_userData);};structMsg{Msg():m_x(0),m_y(0),m_width(0),m_height(0),m_flags(0){}int32_tm_x;int32_tm_y;uint32_tm_width;uint32_tm_height;uint32_tm_flags;tinystl::stringm_title;};staticvoidmouseCapture(HWND_hwnd,bool_capture){if(_capture){SetCapture(_hwnd);}else{ReleaseCapture();}}structContext{Context():m_mz(0),m_frame(true),m_mouseLock(NULL),m_init(false),m_exit(false){bx::memSet(s_translateKey,0,sizeof(s_translateKey));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_INSERT]=Key::Insert;s_translateKey[VK_DELETE]=Key::Delete;s_translateKey[VK_HOME]=Key::Home;s_translateKey[VK_END]=Key::End;s_translateKey[VK_PRIOR]=Key::PageUp;s_translateKey[VK_NEXT]=Key::PageDown;s_translateKey[VK_SNAPSHOT]=Key::Print;s_translateKey[VK_OEM_PLUS]=Key::Plus;s_translateKey[VK_OEM_MINUS]=Key::Minus;s_translateKey[VK_OEM_4]=Key::LeftBracket;s_translateKey[VK_OEM_6]=Key::RightBracket;s_translateKey[VK_OEM_1]=Key::Semicolon;s_translateKey[VK_OEM_7]=Key::Quote;s_translateKey[VK_OEM_COMMA]=Key::Comma;s_translateKey[VK_OEM_PERIOD]=Key::Period;s_translateKey[VK_DECIMAL]=Key::Period;s_translateKey[VK_OEM_2]=Key::Slash;s_translateKey[VK_OEM_5]=Key::Backslash;s_translateKey[VK_OEM_3]=Key::Tilde;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;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;}int32_trun(int_argc,constchar*const*_argv){SetDllDirectoryA(".");s_xinput.init();HINSTANCEinstance=(HINSTANCE)GetModuleHandle(NULL);WNDCLASSEXAwnd;bx::memSet(&wnd,0,sizeof(wnd));wnd.cbSize=sizeof(wnd);wnd.style=CS_HREDRAW|CS_VREDRAW;wnd.lpfnWndProc=wndProc;wnd.hInstance=instance;wnd.hIcon=LoadIcon(NULL,IDI_APPLICATION);wnd.hCursor=LoadCursor(NULL,IDC_ARROW);wnd.lpszClassName="bgfx";wnd.hIconSm=LoadIcon(NULL,IDI_APPLICATION);RegisterClassExA(&wnd);m_windowAlloc.alloc();m_hwnd[0]=CreateWindowA("bgfx","BGFX",WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,ENTRY_DEFAULT_WIDTH,ENTRY_DEFAULT_HEIGHT,NULL,NULL,instance,0);m_flags[0]=0|ENTRY_WINDOW_FLAG_ASPECT_RATIO|ENTRY_WINDOW_FLAG_FRAME;winSetHwnd(m_hwnd[0]);adjust(m_hwnd[0],ENTRY_DEFAULT_WIDTH,ENTRY_DEFAULT_HEIGHT,true);clear(m_hwnd[0]);m_width=ENTRY_DEFAULT_WIDTH;m_height=ENTRY_DEFAULT_HEIGHT;m_oldWidth=ENTRY_DEFAULT_WIDTH;m_oldHeight=ENTRY_DEFAULT_HEIGHT;MainThreadEntrymte;mte.m_argc=_argc;mte.m_argv=_argv;bgfx::renderFrame();bx::Threadthread;thread.init(mte.threadFunc,&mte);m_init=true;m_eventQueue.postSizeEvent(findHandle(m_hwnd[0]),m_width,m_height);MSGmsg;msg.message=WM_NULL;while(!m_exit){bgfx::renderFrame();s_xinput.update(m_eventQueue);WaitForInputIdle(GetCurrentProcess(),16);while(0!=PeekMessage(&msg,NULL,0U,0U,PM_REMOVE)){TranslateMessage(&msg);DispatchMessage(&msg);}}while(bgfx::RenderFrame::NoContext!=bgfx::renderFrame()){};thread.shutdown();DestroyWindow(m_hwnd[0]);s_xinput.shutdown();returnthread.getExitCode();}LRESULTprocess(HWND_hwnd,UINT_id,WPARAM_wparam,LPARAM_lparam){if(m_init){switch(_id){caseWM_USER_WINDOW_CREATE:{Msg*msg=(Msg*)_lparam;HWNDhwnd=CreateWindowA("bgfx",msg->m_title.c_str(),WS_OVERLAPPEDWINDOW|WS_VISIBLE,msg->m_x,msg->m_y,msg->m_width,msg->m_height,NULL,NULL,(HINSTANCE)GetModuleHandle(NULL),0);clear(hwnd);m_hwnd[_wparam]=hwnd;m_flags[_wparam]=msg->m_flags;WindowHandlehandle={(uint16_t)_wparam};m_eventQueue.postSizeEvent(handle,msg->m_width,msg->m_height);m_eventQueue.postWindowEvent(handle,hwnd);deletemsg;}break;caseWM_USER_WINDOW_DESTROY:{WindowHandlehandle={(uint16_t)_wparam};m_eventQueue.postWindowEvent(handle);DestroyWindow(m_hwnd[_wparam]);m_hwnd[_wparam]=0;if(0==handle.idx){m_exit=true;m_eventQueue.postExitEvent();}}break;caseWM_USER_WINDOW_SET_TITLE:{Msg*msg=(Msg*)_lparam;SetWindowTextA(m_hwnd[_wparam],msg->m_title.c_str());deletemsg;}break;caseWM_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);deletemsg;}break;caseWM_USER_WINDOW_SET_SIZE:{uint32_twidth=GET_X_LPARAM(_lparam);uint32_theight=GET_Y_LPARAM(_lparam);adjust(m_hwnd[_wparam],width,height,true);}break;caseWM_USER_WINDOW_TOGGLE_FRAME:{if(m_frame){m_oldWidth=m_width;m_oldHeight=m_height;}adjust(m_hwnd[_wparam],m_oldWidth,m_oldHeight,!m_frame);}break;caseWM_USER_WINDOW_MOUSE_LOCK:setMouseLock(m_hwnd[_wparam],!!_lparam);break;caseWM_DESTROY:break;caseWM_QUIT:caseWM_CLOSE:destroyWindow(findHandle(_hwnd));// Don't process message. Window will be destroyed later.return0;caseWM_SIZING:{WindowHandlehandle=findHandle(_hwnd);if(isValid(handle)&&ENTRY_WINDOW_FLAG_ASPECT_RATIO&m_flags[handle.idx]){RECT&rect=*(RECT*)_lparam;uint32_twidth=rect.right-rect.left-m_frameWidth;uint32_theight=rect.bottom-rect.top-m_frameHeight;// Recalculate size according to aspect ratioswitch(_wparam){caseWMSZ_LEFT:caseWMSZ_RIGHT:{floataspectRatio=1.0f/m_aspectRatio;width=bx::uint32_max(ENTRY_DEFAULT_WIDTH/4,width);height=uint32_t(float(width)*aspectRatio);}break;default:{floataspectRatio=m_aspectRatio;height=bx::uint32_max(ENTRY_DEFAULT_HEIGHT/4,height);width=uint32_t(float(height)*aspectRatio);}break;}// Recalculate position using different anchor pointsswitch(_wparam){caseWMSZ_TOPLEFT:rect.left=rect.right-width-m_frameWidth;rect.top=rect.bottom-height-m_frameHeight;break;caseWMSZ_TOP:caseWMSZ_TOPRIGHT:rect.right=rect.left+width+m_frameWidth;rect.top=rect.bottom-height-m_frameHeight;break;caseWMSZ_LEFT:caseWMSZ_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;}m_eventQueue.postSizeEvent(findHandle(_hwnd),width,height);}}return0;caseWM_SIZE:{WindowHandlehandle=findHandle(_hwnd);if(isValid(handle)){uint32_twidth=GET_X_LPARAM(_lparam);uint32_theight=GET_Y_LPARAM(_lparam);m_width=width;m_height=height;m_eventQueue.postSizeEvent(handle,m_width,m_height);}}break;caseWM_SYSCOMMAND:switch(_wparam){caseSC_MINIMIZE:caseSC_RESTORE:{HWNDparent=GetWindow(_hwnd,GW_OWNER);if(NULL!=parent){PostMessage(parent,_id,_wparam,_lparam);}}}break;caseWM_MOUSEMOVE:{int32_tmx=GET_X_LPARAM(_lparam);int32_tmy=GET_Y_LPARAM(_lparam);if(_hwnd==m_mouseLock){mx-=m_mx;my-=m_my;if(0==mx&&0==my){break;}setMousePos(_hwnd,m_mx,m_my);}m_eventQueue.postMouseEvent(findHandle(_hwnd),mx,my,m_mz);}break;caseWM_MOUSEWHEEL:{POINTpt={GET_X_LPARAM(_lparam),GET_Y_LPARAM(_lparam)};ScreenToClient(_hwnd,&pt);int32_tmx=pt.x;int32_tmy=pt.y;m_mz+=GET_WHEEL_DELTA_WPARAM(_wparam)/WHEEL_DELTA;m_eventQueue.postMouseEvent(findHandle(_hwnd),mx,my,m_mz);}break;caseWM_LBUTTONDOWN:caseWM_LBUTTONUP:caseWM_LBUTTONDBLCLK:{mouseCapture(_hwnd,_id==WM_LBUTTONDOWN);int32_tmx=GET_X_LPARAM(_lparam);int32_tmy=GET_Y_LPARAM(_lparam);m_eventQueue.postMouseEvent(findHandle(_hwnd),mx,my,m_mz,MouseButton::Left,_id==WM_LBUTTONDOWN);}break;caseWM_MBUTTONDOWN:caseWM_MBUTTONUP:caseWM_MBUTTONDBLCLK:{mouseCapture(_hwnd,_id==WM_MBUTTONDOWN);int32_tmx=GET_X_LPARAM(_lparam);int32_tmy=GET_Y_LPARAM(_lparam);m_eventQueue.postMouseEvent(findHandle(_hwnd),mx,my,m_mz,MouseButton::Middle,_id==WM_MBUTTONDOWN);}break;caseWM_RBUTTONDOWN:caseWM_RBUTTONUP:caseWM_RBUTTONDBLCLK:{mouseCapture(_hwnd,_id==WM_RBUTTONDOWN);int32_tmx=GET_X_LPARAM(_lparam);int32_tmy=GET_Y_LPARAM(_lparam);m_eventQueue.postMouseEvent(findHandle(_hwnd),mx,my,m_mz,MouseButton::Right,_id==WM_RBUTTONDOWN);}break;caseWM_KEYDOWN:caseWM_SYSKEYDOWN:caseWM_KEYUP:caseWM_SYSKEYUP:{uint8_tmodifiers=translateKeyModifiers();Key::Enumkey=translateKey(_wparam);WindowHandlehandle=findHandle(_hwnd);if(Key::Print==key&&0x3==((uint32_t)(_lparam)>>30)){// 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.aspxm_eventQueue.postKeyEvent(handle,key,modifiers,true);}m_eventQueue.postKeyEvent(handle,key,modifiers,_id==WM_KEYDOWN||_id==WM_SYSKEYDOWN);}break;caseWM_CHAR:{uint8_tutf8[4]={};uint8_tlen=(uint8_t)WideCharToMultiByte(CP_UTF8,0,(LPCWSTR)&_wparam,1,(LPSTR)utf8,BX_COUNTOF(utf8),NULL,NULL);if(0!=len){WindowHandlehandle=findHandle(_hwnd);m_eventQueue.postCharEvent(handle,len,utf8);}}break;default:break;}}returnDefWindowProc(_hwnd,_id,_wparam,_lparam);}WindowHandlefindHandle(HWND_hwnd){bx::MutexScopescope(m_lock);for(uint16_tii=0,num=m_windowAlloc.getNumHandles();ii<num;++ii){uint16_tidx=m_windowAlloc.getHandleAt(ii);if(_hwnd==m_hwnd[idx]){WindowHandlehandle={idx};returnhandle;}}WindowHandleinvalid={UINT16_MAX};returninvalid;}voidclear(HWND_hwnd){RECTrect;GetWindowRect(_hwnd,&rect);HBRUSHbrush=CreateSolidBrush(RGB(0,0,0));HDChdc=GetDC(_hwnd);SelectObject(hdc,brush);FillRect(hdc,&rect,brush);}voidadjust(HWND_hwnd,uint32_t_width,uint32_t_height,bool_windowFrame){m_width=_width;m_height=_height;m_aspectRatio=float(_width)/float(_height);ShowWindow(_hwnd,SW_SHOWNORMAL);RECTrect;RECTnewrect={0,0,(LONG)_width,(LONG)_height};DWORDstyle=WS_POPUP|WS_SYSMENU;if(m_frame){GetWindowRect(_hwnd,&m_rect);m_style=GetWindowLong(_hwnd,GWL_STYLE);}if(_windowFrame){rect=m_rect;style=m_style;}else{HMONITORmonitor=MonitorFromWindow(_hwnd,MONITOR_DEFAULTTONEAREST);MONITORINFOmi;mi.cbSize=sizeof(mi);GetMonitorInfo(monitor,&mi);newrect=mi.rcMonitor;rect=mi.rcMonitor;m_aspectRatio=float(newrect.right-newrect.left)/float(newrect.bottom-newrect.top);}SetWindowLong(_hwnd,GWL_STYLE,style);uint32_tprewidth=newrect.right-newrect.left;uint32_tpreheight=newrect.bottom-newrect.top;AdjustWindowRect(&newrect,style,FALSE);m_frameWidth=(newrect.right-newrect.left)-prewidth;m_frameHeight=(newrect.bottom-newrect.top)-preheight;UpdateWindow(_hwnd);if(rect.left==-32000||rect.top==-32000){rect.left=0;rect.top=0;}int32_tleft=rect.left;int32_ttop=rect.top;int32_twidth=(newrect.right-newrect.left);int32_theight=(newrect.bottom-newrect.top);if(!_windowFrame){floataspectRatio=1.0f/m_aspectRatio;width=bx::uint32_max(ENTRY_DEFAULT_WIDTH/4,width);height=uint32_t(float(width)*aspectRatio);left=newrect.left+(newrect.right-newrect.left-width)/2;top=newrect.top+(newrect.bottom-newrect.top-height)/2;}SetWindowPos(_hwnd,HWND_TOP,left,top,width,height,SWP_SHOWWINDOW);ShowWindow(_hwnd,SW_RESTORE);m_frame=_windowFrame;}voidsetMousePos(HWND_hwnd,int32_t_mx,int32_t_my){POINTpt={_mx,_my};ClientToScreen(_hwnd,&pt);SetCursorPos(pt.x,pt.y);}voidsetMouseLock(HWND_hwnd,bool_lock){if(_hwnd!=m_mouseLock){if(_lock){m_mx=m_width/2;m_my=m_height/2;ShowCursor(false);setMousePos(_hwnd,m_mx,m_my);}else{setMousePos(_hwnd,m_mx,m_my);ShowCursor(true);}m_mouseLock=_hwnd;}}staticLRESULTCALLBACKwndProc(HWND_hwnd,UINT_id,WPARAM_wparam,LPARAM_lparam);EventQueuem_eventQueue;bx::Mutexm_lock;bx::HandleAllocT<ENTRY_CONFIG_MAX_WINDOWS>m_windowAlloc;HWNDm_hwnd[ENTRY_CONFIG_MAX_WINDOWS];uint32_tm_flags[ENTRY_CONFIG_MAX_WINDOWS];RECTm_rect;DWORDm_style;uint32_tm_width;uint32_tm_height;uint32_tm_oldWidth;uint32_tm_oldHeight;uint32_tm_frameWidth;uint32_tm_frameHeight;floatm_aspectRatio;int32_tm_mx;int32_tm_my;int32_tm_mz;boolm_frame;HWNDm_mouseLock;boolm_init;boolm_exit;};staticContexts_ctx;LRESULTCALLBACKContext::wndProc(HWND_hwnd,UINT_id,WPARAM_wparam,LPARAM_lparam){returns_ctx.process(_hwnd,_id,_wparam,_lparam);}constEvent*poll(){returns_ctx.m_eventQueue.poll();}constEvent*poll(WindowHandle_handle){returns_ctx.m_eventQueue.poll(_handle);}voidrelease(constEvent*_event){s_ctx.m_eventQueue.release(_event);}WindowHandlecreateWindow(int32_t_x,int32_t_y,uint32_t_width,uint32_t_height,uint32_t_flags,constchar*_title){bx::MutexScopescope(s_ctx.m_lock);WindowHandlehandle={s_ctx.m_windowAlloc.alloc()};if(UINT16_MAX!=handle.idx){Msg*msg=newMsg;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);}returnhandle;}voiddestroyWindow(WindowHandle_handle){if(UINT16_MAX!=_handle.idx){PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_DESTROY,_handle.idx,0);bx::MutexScopescope(s_ctx.m_lock);s_ctx.m_windowAlloc.free(_handle.idx);}}voidsetWindowPos(WindowHandle_handle,int32_t_x,int32_t_y){Msg*msg=newMsg;msg->m_x=_x;msg->m_y=_y;PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_SET_POS,_handle.idx,(LPARAM)msg);}voidsetWindowSize(WindowHandle_handle,uint32_t_width,uint32_t_height){PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_SET_SIZE,_handle.idx,(_height<<16)|(_width&0xffff));}voidsetWindowTitle(WindowHandle_handle,constchar*_title){Msg*msg=newMsg;msg->m_title=_title;PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_SET_TITLE,_handle.idx,(LPARAM)msg);}voidtoggleWindowFrame(WindowHandle_handle){PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_TOGGLE_FRAME,_handle.idx,0);}voidtoggleFullscreen(WindowHandle_handle){PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_TOGGLE_FRAME,_handle.idx,0);}voidsetMouseLock(WindowHandle_handle,bool_lock){PostMessage(s_ctx.m_hwnd[0],WM_USER_WINDOW_MOUSE_LOCK,_handle.idx,_lock);}int32_tMainThreadEntry::threadFunc(bx::Thread*/*_thread*/,void*_userData){MainThreadEntry*self=(MainThreadEntry*)_userData;int32_tresult=main(self->m_argc,self->m_argv);PostMessage(s_ctx.m_hwnd[0],WM_QUIT,0,0);returnresult;}}// namespace entryintmain(int_argc,constchar*const*_argv){usingnamespaceentry;returns_ctx.run(_argc,_argv);}#endif // BX_PLATFORM_WINDOWS