yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
b118451e3
master
1#ifdef _WIN32 2 3#include "../window.h" 4 5#include <windows.h> 6#include <windowsx.h> 7using namespace Slang ; 8 9#pragma comment(lib, "Gdi32") 10 11namespace platform 12{ 13 14static const wchar_t * kWindowClassName = L"slang-platform-window" ; 15 16typedef BOOL (WINAPI * EnableNonClientDpiScalingProc )(_In_ HWND hwnd ); 17 18class Win32AppContext 19{ 20public : 21static EnableNonClientDpiScalingProc enableNonClientDpiScaling ; 22static RefPtr < Window > mainWindow ; 23static OrderedDictionary < HWND ,Window *> windows ; 24static HWND mainWindowHandle ; 25static bool isTerminated ; 26static bool isWindows81OrGreater ; 27}; 28 29EnableNonClientDpiScalingProc Win32AppContext ::enableNonClientDpiScaling = nullptr ; 30HWND Win32AppContext ::mainWindowHandle = nullptr ; 31RefPtr < Window > Win32AppContext ::mainWindow ; 32OrderedDictionary < HWND ,Window *> Win32AppContext ::windows ; 33bool Win32AppContext ::isTerminated = false; 34bool Win32AppContext ::isWindows81OrGreater = false; 35 36 37ButtonState ::Enum _addButtonState (ButtonState ::Enum val ,ButtonState ::Enum newState ) 38{ 39return (ButtonState ::Enum )((int )val | (int )newState ); 40} 41 42ButtonState ::Enum getModifierState () 43{ 44ButtonState ::Enum result = ButtonState ::Enum ::None ; 45if (GetAsyncKeyState (VK_CONTROL )) 46result = _addButtonState (result ,ButtonState ::Enum ::Control ); 47if (GetAsyncKeyState (VK_SHIFT )) 48result = _addButtonState (result ,ButtonState ::Enum ::Shift ); 49if (GetAsyncKeyState (VK_MENU )) 50result = _addButtonState (result ,ButtonState ::Enum ::Alt ); 51return result ; 52} 53 54ButtonState ::Enum getModifierState (WPARAM wParam ) 55{ 56ButtonState ::Enum result = ButtonState ::Enum ::None ; 57if (wParam & MK_CONTROL ) 58result = _addButtonState (result ,ButtonState ::Enum ::Control ); 59if (wParam & MK_MBUTTON ) 60result = _addButtonState (result ,ButtonState ::Enum ::MiddleButton ); 61if (wParam & MK_RBUTTON ) 62result = _addButtonState (result ,ButtonState ::Enum ::RightButton ); 63if (wParam & MK_SHIFT ) 64result = _addButtonState (result ,ButtonState ::Enum ::Shift ); 65if (GetAsyncKeyState (VK_MENU )) 66result = _addButtonState (result ,ButtonState ::Enum ::Alt ); 67return result ; 68} 69 70LRESULT CALLBACK WndProc (HWND hWnd ,UINT message ,WPARAM wParam ,LPARAM lParam ) 71{ 72bool useDefProc = true; 73Window * window = nullptr ; 74Win32AppContext ::windows .tryGetValue (hWnd ,window ); 75switch (message ) 76 { 77case WM_LBUTTONUP : 78case WM_MBUTTONUP : 79case WM_RBUTTONUP : 80 { 81int mx = GET_X_LPARAM (lParam ); 82int my = GET_Y_LPARAM (lParam ); 83bool processed = false; 84if (window ) 85 { 86window -> events .mouseUp (MouseEventArgs {mx ,my ,0 ,getModifierState (wParam )}); 87 } 88 } 89break ; 90case WM_LBUTTONDOWN : 91case WM_MBUTTONDOWN : 92case WM_RBUTTONDOWN : 93 { 94int mx = GET_X_LPARAM (lParam ); 95int my = GET_Y_LPARAM (lParam ); 96bool processed = false; 97if (window ) 98 { 99window -> events .mouseDown (MouseEventArgs {mx ,my ,0 ,getModifierState (wParam )}); 100 } 101 } 102break ; 103case WM_MOUSEMOVE : 104 { 105int mx = GET_X_LPARAM (lParam ); 106int my = GET_Y_LPARAM (lParam ); 107if (window ) 108 { 109window -> events .mouseMove (MouseEventArgs {mx ,my ,0 ,getModifierState (wParam )}); 110 } 111 } 112break ; 113case WM_MOUSEWHEEL : 114 { 115int delta = GET_WHEEL_DELTA_WPARAM (wParam ); 116if (window ) 117 { 118window -> events .mouseMove (MouseEventArgs {0 ,0 ,delta ,getModifierState (wParam )}); 119 } 120 } 121break ; 122case WM_CHAR : 123 { 124if (window ) 125 { 126KeyEventArgs keyEventArgs = 127 {KeyCode ::None , (wchar_t )(wParam ),ButtonState ::Enum ::None , false}; 128window -> events .keyPress (keyEventArgs ); 129if (keyEventArgs .cancelEvent ) 130useDefProc = false; 131 } 132 } 133break ; 134case WM_KEYDOWN : 135 { 136if (window ) 137 { 138KeyEventArgs keyEventArgs = {(KeyCode )(wParam ),0 ,getModifierState (), false}; 139window -> events .keyDown (keyEventArgs ); 140if (keyEventArgs .cancelEvent ) 141useDefProc = false; 142 } 143 } 144break ; 145case WM_KEYUP : 146 { 147if (window ) 148 { 149KeyEventArgs keyEventArgs = {(KeyCode )(wParam ),0 ,getModifierState (), false}; 150window -> events .keyUp (keyEventArgs ); 151if (keyEventArgs .cancelEvent ) 152useDefProc = false; 153 } 154 } 155break ; 156case WM_SETFOCUS : 157 { 158if (window ) 159 { 160window -> events .focus (); 161 } 162 } 163break ; 164case WM_KILLFOCUS : 165 { 166if (window ) 167 { 168window -> events .lostFocus (); 169 } 170 } 171break ; 172case WM_SIZE : 173 { 174if (window ) 175 { 176window -> events .sizeChanged (); 177 } 178 } 179break ; 180case WM_NCCREATE : 181 { 182if (Win32AppContext ::enableNonClientDpiScaling ) 183Win32AppContext ::enableNonClientDpiScaling (hWnd ); 184return DefWindowProc (hWnd ,message ,wParam ,lParam ); 185 } 186break ; 187default : 188break ; 189 } 190if (message == WM_DESTROY && hWnd == Win32AppContext ::mainWindowHandle ) 191 { 192PostQuitMessage (0 ); 193return 0 ; 194 } 195if (useDefProc ) 196return DefWindowProc (hWnd ,message ,wParam ,lParam ); 197return 0 ; 198} 199 200void registerWindowClass () 201{ 202WNDCLASSEX wcex ; 203 204wcex .cbSize = sizeof (WNDCLASSEX ); 205 206wcex .style = CS_HREDRAW |CS_VREDRAW |CS_OWNDC |CS_DBLCLKS ; 207wcex .lpfnWndProc = WndProc ; 208wcex .cbClsExtra = 0 ; 209wcex .cbWndExtra = 0 ; 210wcex .hInstance = GetModuleHandle (NULL ); 211wcex .hIcon = 0 ; 212wcex .hCursor = LoadCursor (NULL ,IDC_ARROW ); 213wcex .hbrBackground = (HBRUSH )(COLOR_BTNFACE + 1 ); 214wcex .lpszMenuName = 0 ; 215wcex .lpszClassName = kWindowClassName ; 216wcex .hIconSm = 0 ; 217 218RegisterClassExW (& wcex ); 219} 220 221void unregisterWindowClass () 222{ 223UnregisterClassW (kWindowClassName ,GetModuleHandle (NULL )); 224} 225 226HRESULT (WINAPI * getDpiForMonitor ) 227(void * hmonitor ,int dpiType ,unsigned int * dpiX ,unsigned int * dpiY ); 228 229void Application ::init () 230{ 231* (FARPROC * )& Win32AppContext ::enableNonClientDpiScaling = 232GetProcAddress (GetModuleHandleA ("User32" ),"EnableNonClientDpiScaling" ); 233void * (WINAPI * RtlGetVersion )(LPOSVERSIONINFOEXW ); 234OSVERSIONINFOEXW osInfo ; 235* (FARPROC * )& RtlGetVersion = GetProcAddress (GetModuleHandleA ("ntdll" ),"RtlGetVersion" ); 236 237if (RtlGetVersion ) 238 { 239osInfo .dwOSVersionInfoSize = sizeof (osInfo ); 240RtlGetVersion (& osInfo ); 241if (osInfo .dwMajorVersion > 8 || (osInfo .dwMajorVersion == 8 && osInfo .dwMinorVersion >=1 )) 242Win32AppContext ::isWindows81OrGreater = true; 243 } 244HRESULT (WINAPI * setProcessDpiAwareness )(int value ); 245* (FARPROC * )& setProcessDpiAwareness = 246GetProcAddress (GetModuleHandleA ("Shcore" ),"SetProcessDpiAwareness" ); 247* (FARPROC * )& getDpiForMonitor = GetProcAddress (GetModuleHandleA ("Shcore" ),"GetDpiForMonitor" ); 248if (setProcessDpiAwareness ) 249 { 250if (Win32AppContext ::isWindows81OrGreater ) 251setProcessDpiAwareness (2 );// PROCESS_PER_MONITOR_DPI_AWARE 252else 253setProcessDpiAwareness (1 );// PROCESS_SYSTEM_DPI_AWARE 254 } 255registerWindowClass (); 256} 257 258void doEventsImpl (bool waitForEvents ) 259{ 260int hasMsg = 0 ; 261do 262 { 263MSG msg = {}; 264hasMsg = 265 (waitForEvents ?GetMessage (& msg ,NULL ,0 ,0 ) :PeekMessage (& msg ,NULL ,0 ,0 , TRUE)); 266if (hasMsg ) 267 { 268TranslateMessage (& msg ); 269DispatchMessage (& msg ); 270 } 271if (msg .message == WM_QUIT ) 272Win32AppContext ::isTerminated = true; 273 }while (!Win32AppContext ::isTerminated && hasMsg ); 274} 275 276void Application ::doEvents () 277{ 278doEventsImpl (false); 279} 280 281void Application ::quit () 282{ 283Win32AppContext ::isTerminated = true; 284} 285 286void Application ::dispose () 287{ 288Win32AppContext ::mainWindow = nullptr ; 289Win32AppContext ::windows = decltype(Win32AppContext ::windows )(); 290unregisterWindowClass (); 291} 292 293void Application ::run (Window * mainWindow ,bool waitForEvents ) 294{ 295if (mainWindow ) 296 { 297Win32AppContext ::mainWindow = mainWindow ; 298Win32AppContext ::mainWindowHandle = (HWND )mainWindow -> getNativeHandle ().handleValues [0 ]; 299ShowWindow (Win32AppContext ::mainWindowHandle ,SW_SHOW ); 300UpdateWindow (Win32AppContext ::mainWindowHandle ); 301 } 302while (!Win32AppContext ::isTerminated ) 303 { 304doEventsImpl (waitForEvents ); 305if (Win32AppContext ::isTerminated ) 306break ; 307if (mainWindow ) 308 { 309mainWindow -> events .mainLoop (); 310 } 311 } 312} 313 314class Win32PlatformWindow :public Window 315{ 316public : 317HWND handle ; 318DWORD style ; 319bool visible = false; 320Win32PlatformWindow (const WindowDesc & desc ) 321 { 322DWORD windowExtendedStyle = 0 ; 323style = WS_OVERLAPPED |WS_CAPTION |WS_SYSMENU ; 324if (desc .style == WindowStyle ::Default ) 325 { 326style |=WS_MAXIMIZEBOX |WS_MINIMIZEBOX |WS_THICKFRAME ; 327 } 328 329HINSTANCE instance = (HINSTANCE )GetModuleHandle (0 ); 330 331RECT windowRect ; 332windowRect .left = 0 ; 333windowRect .top = 0 ; 334windowRect .bottom = desc .height ; 335windowRect .right = desc .width ; 336AdjustWindowRect (& windowRect ,style , FALSE); 337 338handle = CreateWindowExW ( 339windowExtendedStyle , 340 (LPWSTR )kWindowClassName , 341String (desc .title ).toWString ().begin (), 342style , 343CW_USEDEFAULT , 3440 ,// x, y 345windowRect .right , 346windowRect .bottom , 347NULL ,// parent 348NULL ,// menu 349instance , 350NULL ); 351if (handle ) 352Win32AppContext ::windows [handle ]= this ; 353 } 354 355 ~Win32PlatformWindow () {close (); } 356 357virtual void setClientSize (uint32_t width ,uint32_t height )override 358 { 359RECT currentRect ; 360GetWindowRect (handle ,& currentRect ); 361 362RECT windowRect ; 363windowRect .left = currentRect .left ; 364windowRect .top = currentRect .top ; 365windowRect .bottom = height ; 366windowRect .right = width ; 367AdjustWindowRect (& windowRect ,style , FALSE); 368 369MoveWindow ( 370handle , 371windowRect .left , 372windowRect .top , 373windowRect .right - windowRect .left , 374windowRect .bottom - windowRect .top , 375 FALSE); 376 } 377 378virtual Rect getClientRect ()override 379 { 380RECT currentRect ; 381GetClientRect (handle ,& currentRect ); 382Rect rect ; 383rect .x = currentRect .left ; 384rect .y = currentRect .top ; 385rect .width = currentRect .right - currentRect .left ; 386rect .height = currentRect .bottom - currentRect .top ; 387return rect ; 388 } 389 390virtual void centerScreen ()override 391 { 392RECT screenRect ; 393GetClientRect (GetDesktopWindow (),& screenRect ); 394RECT currentRect ; 395GetWindowRect (handle ,& currentRect ); 396 397auto width = currentRect .right - currentRect .left ; 398auto height = currentRect .bottom - currentRect .top ; 399 400auto left = (screenRect .right - width ) /2 ; 401auto top = (screenRect .bottom - height ) /2 ; 402 403MoveWindow (handle ,left ,top ,width ,height , FALSE); 404 } 405 406virtual void close ()override 407 { 408if (handle ) 409 { 410Win32AppContext ::windows .remove (handle ); 411 } 412DestroyWindow (handle ); 413handle = NULL ; 414 } 415virtual bool getFocused ()override {return GetFocus ()== handle ; } 416virtual bool getVisible ()override {return visible ; } 417virtual WindowHandle getNativeHandle ()override {return WindowHandle ::fromHwnd (handle ); } 418virtual void setText (Slang ::String text )override 419 { 420SetWindowText (handle ,text .toWString ().begin ()); 421 } 422virtual void show ()override 423 { 424ShowWindow (handle ,SW_SHOW ); 425visible = true; 426 } 427virtual void hide ()override 428 { 429ShowWindow (handle ,SW_HIDE ); 430visible = false; 431 } 432virtual int getCurrentDpi ()override 433 { 434int dpi = 96 ; 435if (Win32AppContext ::isWindows81OrGreater && getDpiForMonitor ) 436 { 437getDpiForMonitor ( 438MonitorFromWindow (handle ,MONITOR_DEFAULTTOPRIMARY ), 4390 , 440 (UINT * )& dpi , 441 (UINT * )& dpi ); 442return dpi ; 443 } 444dpi = GetDeviceCaps (NULL ,LOGPIXELSY ); 445return dpi ; 446 } 447}; 448 449Window * Application ::createWindow (const WindowDesc & desc ) 450{ 451return new Win32PlatformWindow (desc ); 452} 453 454 455}// namespace platform 456 457#endif