17# define _WIN32_IE 0x0501
24#include <shellscalingapi.h>
45#ifdef WITH_OPENGL_BACKEND
48#ifdef WITH_VULKAN_BACKEND
61# define VK_SEMICOLON 0xBA
64# define VK_PERIOD 0xBE
70# define VK_BACK_QUOTE 0xC0
76# define VK_BACK_SLASH 0xDC
79# define VK_EQUALS 0xBB
81#ifndef VK_OPEN_BRACKET
82# define VK_OPEN_BRACKET 0xDB
84#ifndef VK_CLOSE_BRACKET
85# define VK_CLOSE_BRACKET 0xDD
88# define VK_GR_LESS 0xE2
101#define BROKEN_PEEK_TOUCHPAD
134#ifdef WITH_INPUT_NDOF
135# define DEVICE_COUNT 2
137# define DEVICE_COUNT 1
141 memset(devices, 0,
DEVICE_COUNT *
sizeof(RAWINPUTDEVICE));
145 devices[0].usUsagePage = 0x01;
146 devices[0].usUsage = 0x06;
148#ifdef WITH_INPUT_NDOF
150 devices[1].usUsagePage = 0x01;
151 devices[1].usUsage = 0x08;
154 if (RegisterRawInputDevices(devices,
DEVICE_COUNT,
sizeof(RAWINPUTDEVICE))) {
158 GHOST_PRINTF(
"could not register for RawInput: %d\n",
int(GetLastError()));
171 SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
175 SetCurrentProcessExplicitAppUserModelID(BLENDER_WIN_APPID_16);
185#ifdef WITH_INPUT_NDOF
203 __int64 delta = perf_ticks * 1000;
213 return ::GetTickCount64();
218 ::QueryPerformanceCounter((LARGE_INTEGER *)&
count);
231 int64_t t_delta = GetMessageTime() - GetTickCount();
244 return ::GetSystemMetrics(SM_CMONITORS);
249 width = ::GetSystemMetrics(SM_CXSCREEN);
250 height = ::GetSystemMetrics(SM_CYSCREEN);
255 width = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
256 height = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
267 const bool is_dialog,
291 GHOST_PRINT(
"GHOST_SystemWin32::createWindow(): window invalid\n");
309#ifdef WITH_VULKAN_BACKEND
310 case GHOST_kDrawingContextTypeVulkan: {
313 if (context->initializeDrawingContext()) {
321#ifdef WITH_OPENGL_BACKEND
322 case GHOST_kDrawingContextTypeOpenGL: {
325 HWND wnd = CreateWindowA(
"STATIC",
327 WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
334 GetModuleHandle(
nullptr),
337 HDC mHDC = GetDC(wnd);
338 HDC prev_hdc = wglGetCurrentDC();
339 HGLRC prev_context = wglGetCurrentContext();
341 for (
int minor = 6; minor >= 3; --minor) {
347 WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
350 (debug_context ? WGL_CONTEXT_DEBUG_BIT_ARB : 0),
353 if (context->initializeDrawingContext()) {
354 wglMakeCurrent(prev_hdc, prev_context);
359 wglMakeCurrent(prev_hdc, prev_context);
388 HWND wnd = CreateWindowA(
"STATIC",
390 WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
397 GetModuleHandle(
nullptr),
401 if (context->initializeDrawingContext()) {
418 bool hasEventHandled =
false;
423 if (waitForEvent && !::PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE)) {
433 else if (maxSleep >= 0.0) {
434 ::SetTimer(
nullptr, 0, maxSleep,
nullptr);
436 ::KillTimer(
nullptr, 0);
442 hasEventHandled =
true;
448 while (::PeekMessageW(&msg,
nullptr, 0, 0, PM_REMOVE) != 0) {
451 ::TranslateMessage(&msg);
452 ::DispatchMessageW(&msg);
453 hasEventHandled =
true;
463 }
while (waitForEvent && !hasEventHandled);
465 return hasEventHandled;
471 if (::GetCursorPos(&point)) {
481 if (!::GetActiveWindow()) {
490 if (!GetCursorPos(&point)) {
494 HDC dc = GetDC(NULL);
499 COLORREF color = GetPixel(dc, point.x, point.y);
502 if (color == CLR_INVALID) {
506 r_color[0] = GetRValue(color) / 255.0f;
507 r_color[1] = GetGValue(color) / 255.0f;
508 r_color[2] = GetBValue(color) / 255.0f;
517 if (!GetCursorPos(&point)) {
521 HWND win = WindowFromPoint(point);
526 return m_windowManager->getWindowAssociatedWithOSWindow((
const void *)win);
534 bool down = HIBYTE(::GetAsyncKeyState(VK_LSHIFT)) != 0;
536 down = HIBYTE(::GetAsyncKeyState(VK_RSHIFT)) != 0;
539 down = HIBYTE(::GetAsyncKeyState(VK_LMENU)) != 0;
541 down = HIBYTE(::GetAsyncKeyState(VK_RMENU)) != 0;
544 down = HIBYTE(::GetAsyncKeyState(VK_LCONTROL)) != 0;
546 down = HIBYTE(::GetAsyncKeyState(VK_RCONTROL)) != 0;
549 down = HIBYTE(::GetAsyncKeyState(VK_LWIN)) != 0;
551 down = HIBYTE(::GetAsyncKeyState(VK_RWIN)) != 0;
562 bool swapped = ::GetSystemMetrics(SM_SWAPBUTTON) == TRUE;
564 bool down = HIBYTE(::GetAsyncKeyState(VK_LBUTTON)) != 0;
567 down = HIBYTE(::GetAsyncKeyState(VK_MBUTTON)) != 0;
570 down = HIBYTE(::GetAsyncKeyState(VK_RBUTTON)) != 0;
590 InitCommonControls();
593 SetProcessDPIAware();
601 wc.style = CS_HREDRAW | CS_VREDRAW;
605 wc.hInstance = ::GetModuleHandle(0);
606 wc.hIcon = ::LoadIcon(wc.hInstance,
"APPICON");
609 ::LoadIcon(
nullptr, IDI_APPLICATION);
611 wc.hCursor = ::LoadCursor(0, IDC_ARROW);
612 wc.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
614 wc.lpszClassName =
L"GHOST_WindowClass";
617 if (::RegisterClassW(&wc) == 0) {
633 uint msg = raw.data.keyboard.Message;
634 *r_key_down = !(raw.data.keyboard.Flags & RI_KEY_BREAK) && msg != WM_KEYUP && msg != WM_SYSKEYUP;
636 return this->
convertKey(raw.data.keyboard.VKey,
637 raw.data.keyboard.MakeCode,
638 (raw.data.keyboard.Flags & (RI_KEY_E1 | RI_KEY_E0)));
655 char ch = char(MapVirtualKeyA(vKey, MAPVK_VK_TO_CHAR));
676 if (vKey == VK_OEM_7) {
679 else if (vKey == VK_OEM_8) {
680 if (PRIMARYLANGID(
m_langId) == LANG_FRENCH) {
695 if ((vKey >=
'0') && (vKey <=
'9')) {
699 else if ((vKey >=
'A') && (vKey <=
'Z')) {
703 else if ((vKey >= VK_F1) && (vKey <= VK_F24)) {
825 if (scanCode == 0x36) {
828 else if (scanCode == 0x2a) {
862 case VK_MEDIA_PLAY_PAUSE:
868 case VK_MEDIA_PREV_TRACK:
871 case VK_MEDIA_NEXT_TRACK:
897 DWORD msgPos = ::GetMessagePos();
898 int msgPosX = GET_X_LPARAM(msgPos);
899 int msgPosY = GET_Y_LPARAM(msgPos);
924 std::vector<GHOST_WintabInfoWin32> wintabInfo;
933 bool mouseMoveHandled;
954 switch (info.button) {
956 message = WM_LBUTTONDOWN;
959 message = WM_RBUTTONDOWN;
962 message = WM_MBUTTONDOWN;
972 if (PeekMessage(&msg, window->
getHWND(), message, message, PM_NOYIELD) &&
973 msg.message != WM_QUIT)
977 useWintabPos = wt->
testCoordinates(msg.pt.x, msg.pt.y, info.x, info.y);
979 WINTAB_PRINTF(
" ... but associated system button mismatched position\n");
986 PeekMessage(&msg, window->
getHWND(), message, message, PM_REMOVE | PM_NOYIELD);
996 new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
998 mouseMoveHandled =
true;
1007 if (!useWintabPos) {
1013 switch (info.button) {
1015 message = WM_LBUTTONUP;
1018 message = WM_RBUTTONUP;
1021 message = WM_MBUTTONUP;
1031 if (PeekMessage(&msg, window->
getHWND(), message, message, PM_REMOVE | PM_NOYIELD) &&
1032 msg.message != WM_QUIT)
1038 new GHOST_EventButton(info.time, info.type, window, info.button, info.tabletData));
1051 if (!mouseMoveHandled) {
1052 DWORD
pos = GetMessagePos();
1053 int x = GET_X_LPARAM(
pos);
1054 int y = GET_Y_LPARAM(
pos);
1072 std::vector<GHOST_PointerInfoWin32> pointerInfo;
1079 case WM_POINTERUPDATE: {
1082 for (uint32_t
i = pointerInfo.size();
i-- > 0;) {
1086 pointerInfo[
i].pixelLocation.x,
1087 pointerInfo[
i].pixelLocation.y,
1088 pointerInfo[
i].tabletData));
1095 case WM_POINTERDOWN: {
1100 pointerInfo[0].pixelLocation.x,
1101 pointerInfo[0].pixelLocation.y,
1102 pointerInfo[0].tabletData));
1106 pointerInfo[0].buttonMask,
1107 pointerInfo[0].tabletData));
1111 eventHandled =
true;
1115 case WM_POINTERUP: {
1119 pointerInfo[0].buttonMask,
1120 pointerInfo[0].tabletData));
1124 eventHandled =
true;
1144 int32_t x_screen = screen_co[0], y_screen = screen_co[1];
1149 static bool is_warping_x =
false;
1150 static bool is_warping_y =
false;
1178 bounds.wrapPoint(x_new, y_new, bounds_margin, bounds_axis);
1182 if (x_new != x_screen || y_new != y_screen) {
1186 if (!is_warping_x) {
1187 is_warping_x = x_new != x_screen;
1189 x_accum += (x_screen - x_new);
1193 if (!is_warping_y) {
1194 is_warping_y = y_new != y_screen;
1196 y_accum += (y_screen - y_new);
1206 is_warping_x =
false;
1207 is_warping_y =
false;
1208 x_screen += x_accum;
1209 y_screen += y_accum;
1227 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
1229 if (acc * delta < 0) {
1234 int direction = (acc >= 0) ? 1 : -1;
1237 while (acc >= WHEEL_DELTA) {
1253 int delta = GET_WHEEL_DELTA_WPARAM(wParam);
1255 if (acc * delta < 0) {
1260 int direction = (acc >= 0) ? 1 : -1;
1263 while (acc >= WHEEL_DELTA) {
1273 const char vk = raw.data.keyboard.VKey;
1274 bool key_down =
false;
1281 constexpr USHORT ALTGR_MAKE_CODE = 0x38;
1286 if (system->
m_hasAltGr && vk == VK_CONTROL && raw.data.keyboard.MakeCode == ALTGR_MAKE_CODE &&
1287 (raw.data.keyboard.Flags & RI_KEY_E0))
1298 bool is_repeat =
false;
1299 bool is_repeated_modifier =
false;
1301 if (HIBYTE(::GetKeyState(vk)) != 0) {
1311 if (!is_repeated_modifier) {
1312 char utf8_char[6] = {0};
1314 const BOOL has_state = GetKeyboardState((PBYTE)
state);
1315 const bool ctrl_pressed = has_state &&
state[VK_CONTROL] & 0x80;
1316 const bool alt_pressed = has_state &&
state[VK_MENU] & 0x80;
1317 const bool win_pressed = has_state && (
state[VK_LWIN] |
state[VK_RWIN]) & 0x80;
1322 if (ctrl_pressed && !alt_pressed) {
1325 else if (win_pressed) {
1331 else if (MapVirtualKeyW(vk, MAPVK_VK_TO_CHAR) != 0) {
1332 wchar_t utf16[3] = {0};
1336 if ((r = ToUnicodeEx(
1339 if ((r > 0 && r < 3)) {
1344 utf8_char[0] =
'\0';
1349 utf8_char[0] =
'\0';
1353#ifdef WITH_INPUT_IME
1354 if (key_down && ((utf8_char[0] & 0x80) == 0)) {
1355 const char ascii = utf8_char[0];
1356 if (window->getImeInput()->IsImeKeyEvent(ascii, key)) {
1409#ifdef WITH_INPUT_IME
1428 getMessageTime(system), eventType, draggedObjectType, window, mouseX, mouseY,
data));
1464 minmax->ptMinTrackSize.x = 320;
1465 minmax->ptMinTrackSize.y = 240;
1468#ifdef WITH_INPUT_NDOF
1469bool GHOST_SystemWin32::processNDOF(RAWINPUT
const &raw)
1471 bool eventSent =
false;
1474 RID_DEVICE_INFO info;
1475 unsigned infoSize =
sizeof(RID_DEVICE_INFO);
1476 info.cbSize = infoSize;
1478 GetRawInputDeviceInfo(raw.header.hDevice, RIDI_DEVICEINFO, &info, &infoSize);
1480 if (info.dwType == RIM_TYPEHID) {
1481 m_ndofManager->setDevice(info.hid.dwVendorId, info.hid.dwProductId);
1484 GHOST_PRINT(
"<!> not a HID device... mouse/kb perhaps?\n");
1491 BYTE
const *
data = raw.data.hid.bRawData;
1493 BYTE packetType =
data[0];
1494 switch (packetType) {
1496 const short *axis = (
short *)(
data + 1);
1498 const int t[3] = {axis[0], -axis[2], axis[1]};
1499 m_ndofManager->updateTranslation(t, now);
1501 if (raw.data.hid.dwSizeHid == 13) {
1503 const int r[3] = {-axis[3], axis[5], -axis[4]};
1504 m_ndofManager->updateRotation(r, now);
1513 const short *axis = (
short *)(
data + 1);
1514 const int r[3] = {-axis[0], axis[2], -axis[1]};
1515 m_ndofManager->updateRotation(r, now);
1520 memcpy(&button_bits,
data + 1,
sizeof(button_bits));
1521 m_ndofManager->updateButtonsBitmask(button_bits, now);
1527 for (
int i = 0;
i < buttons.size();
i++) {
1536 for (
int i = 0;
i < buttons.size();
i++) {
1551 if (active_window) {
1561 if (!active_window) {
1571 if (trackpad_info.
x != 0 || trackpad_info.
y != 0) {
1581 if (trackpad_info.
scale != 0) {
1587 trackpad_info.
scale,
1596 bool eventHandled =
false;
1598 LRESULT lResult = 0;
1600#ifdef WITH_INPUT_IME
1603 GHOST_ASSERT(system,
"GHOST_SystemWin32::s_wndProc(): system not initialized");
1607 if (msg == WM_NCCREATE) {
1610 HMODULE m_user32 = ::LoadLibrary(
"User32.dll");
1614 "EnableNonClientDpiScaling");
1615 if (fpEnableNonClientDpiScaling) {
1616 fpEnableNonClientDpiScaling(hwnd);
1625 case WM_INPUTLANGCHANGE: {
1627#ifdef WITH_INPUT_IME
1628 window->getImeInput()->UpdateInputLanguage();
1629 window->getImeInput()->UpdateConversionStatus(hwnd);
1638 RAWINPUT *raw_ptr = &raw;
1639 uint rawSize =
sizeof(RAWINPUT);
1641 GetRawInputData((HRAWINPUT)lParam, RID_INPUT, raw_ptr, &rawSize,
sizeof(RAWINPUTHEADER));
1643 switch (raw.header.dwType) {
1644 case RIM_TYPEKEYBOARD: {
1647 GHOST_PRINT(
"GHOST_SystemWin32::wndProc: key event ");
1653#ifdef WITH_INPUT_NDOF
1655 if (system->processNDOF(raw)) {
1656 eventHandled =
true;
1664#ifdef WITH_INPUT_IME
1668 case WM_IME_NOTIFY: {
1670 if (wParam == IMN_SETOPENSTATUS || wParam == IMN_SETCONVERSIONMODE) {
1671 window->getImeInput()->UpdateConversionStatus(hwnd);
1675 case WM_IME_SETCONTEXT: {
1676 GHOST_ImeWin32 *ime = window->getImeInput();
1677 ime->UpdateInputLanguage();
1678 ime->UpdateConversionStatus(hwnd);
1679 ime->CreateImeWindow(hwnd);
1680 ime->CleanupComposition(hwnd);
1681 ime->CheckFirst(hwnd);
1684 case WM_IME_STARTCOMPOSITION: {
1685 GHOST_ImeWin32 *ime = window->getImeInput();
1686 eventHandled =
true;
1687 ime->CreateImeWindow(hwnd);
1688 ime->ResetComposition(hwnd);
1692 case WM_IME_COMPOSITION: {
1693 GHOST_ImeWin32 *ime = window->getImeInput();
1694 eventHandled =
true;
1695 ime->UpdateImeWindow(hwnd);
1696 ime->UpdateInfo(hwnd);
1697 if (ime->eventImeData.result.size()) {
1704 case WM_IME_ENDCOMPOSITION: {
1705 GHOST_ImeWin32 *ime = window->getImeInput();
1706 eventHandled =
true;
1709 ime->ResetComposition(hwnd);
1710 ime->DestroyImeWindow(hwnd);
1736 case WM_SYSDEADCHAR:
1749 case WM_SYSCOMMAND: {
1757 switch (wParam & 0xFFF0) {
1759 eventHandled =
true;
1763 ::ShowWindow(hwnd, SW_RESTORE);
1771 eventHandled =
true;
1796 case WT_CSRCHANGE: {
1802 eventHandled =
true;
1805 case WT_PROXIMITY: {
1807 if (LOWORD(lParam)) {
1813 if (HIWORD(lParam)) {
1814 WINTAB_PRINTF(
" Cursor entering or leaving hardware proximity.\n");
1817 WINTAB_PRINTF(
" Cursor neither entering nor leaving hardware proximity.\n");
1822 bool inRange = LOWORD(lParam);
1831 eventHandled =
true;
1834 case WT_INFOCHANGE: {
1844 eventHandled =
true;
1849 eventHandled =
true;
1863 case WT_CTXUPDATE: {
1867 case WT_CTXOVERLAP: {
1870 case CXS_DISABLED: {
1874 case CXS_OBSCURED: {
1888 case WM_POINTERUPDATE:
1889 case WM_POINTERDOWN:
1890 case WM_POINTERUP: {
1894 case WM_POINTERLEAVE: {
1896 POINTER_INFO pointerInfo;
1897 if (!GetPointerInfo(pointerId, &pointerInfo)) {
1902 if (pointerInfo.pointerType == PT_PEN) {
1904 eventHandled =
true;
1911 case WM_LBUTTONDOWN: {
1915 case WM_MBUTTONDOWN: {
1919 case WM_RBUTTONDOWN: {
1923 case WM_XBUTTONDOWN: {
1924 if (
short(HIWORD(wParam)) == XBUTTON1) {
1927 else if (
short(HIWORD(wParam)) == XBUTTON2) {
1932 case WM_LBUTTONUP: {
1936 case WM_MBUTTONUP: {
1940 case WM_RBUTTONUP: {
1944 case WM_XBUTTONUP: {
1945 if (
short(HIWORD(wParam)) == XBUTTON1) {
1948 else if (
short(HIWORD(wParam)) == XBUTTON2) {
1953 case WM_MOUSEMOVE: {
1956 TRACKMOUSEEVENT tme = {
sizeof(tme)};
1958 tme.dwFlags = TME_LEAVE;
1961 tme.dwFlags |= TME_HOVER;
1962 tme.dwHoverTime = 100;
1964 tme.hwndTrack = hwnd;
1965 TrackMouseEvent(&tme);
1973 const int32_t window_co[2] = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
1980 case WM_MOUSEHOVER: {
1986 HWND old_hwnd = ::GetFocus();
1987 if (old_hwnd && hwnd != old_hwnd) {
1988 HWND new_parent = ::GetParent(hwnd);
1989 HWND old_parent = ::GetParent(old_hwnd);
1990 if (hwnd == old_parent || old_hwnd == new_parent) {
1994 else if (new_parent != HWND_DESKTOP && new_parent == old_parent) {
1998 else if (!new_parent && !old_parent) {
2000 RECT new_rect, old_rect, dest_rect;
2003 DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &new_rect,
sizeof(RECT));
2004 ::InflateRect(&new_rect, -1, -1);
2005 DwmGetWindowAttribute(
2006 old_hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &old_rect,
sizeof(RECT));
2007 ::InflateRect(&old_rect, -1, -1);
2009 if (!IntersectRect(&dest_rect, &new_rect, &old_rect)) {
2016 case WM_MOUSEWHEEL: {
2025 eventHandled =
true;
2026#ifdef BROKEN_PEEK_TOUCHPAD
2027 PostMessage(hwnd, WM_USER, 0, 0);
2031 case WM_MOUSEHWHEEL: {
2033 eventHandled =
true;
2036 case WM_SETCURSOR: {
2043 if (LOWORD(lParam) == HTCLIENT) {
2055 case WM_MOUSELEAVE: {
2060 int32_t screen_co[2] = {0, 0};
2073 case WM_NCMOUSEMOVE: {
2079 case WM_NCHITTEST: {
2093 if (IsIconic(hwnd)) {
2094 ShowWindow(hwnd, SW_RESTORE);
2113 if (LOWORD(wParam) == WA_INACTIVE) {
2117 lResult = ::DefWindowProc(hwnd, msg, wParam, lParam);
2120 case WM_ENTERSIZEMOVE: {
2131 case WM_EXITSIZEMOVE: {
2144 ::ValidateRect(hwnd,
nullptr);
2147 eventHandled =
true;
2151 case WM_GETMINMAXINFO: {
2175 case WM_CAPTURECHANGED: {
2201 case WM_DPICHANGED: {
2208 RECT *
const suggestedWindowRect = (RECT *)lParam;
2213 eventHandled =
true;
2218 suggestedWindowRect->left,
2219 suggestedWindowRect->top,
2220 suggestedWindowRect->right - suggestedWindowRect->left,
2221 suggestedWindowRect->bottom - suggestedWindowRect->top,
2222 SWP_NOZORDER | SWP_NOACTIVATE);
2227 case WM_DISPLAYCHANGE: {
2234 case WM_KILLFOCUS: {
2238 if (!wParam && hwnd == ::GetActiveWindow()) {
2243 case WM_SETTINGCHANGE: {
2246 if (((
void *)lParam !=
nullptr) && (wcscmp(LPCWSTR(lParam),
L"ImmersiveColorSet") == 0))
2255 case WM_WINDOWPOSCHANGED:
2269 HBRUSH bgBrush = (HBRUSH)GetClassLongPtr(hwnd, GCLP_HBRBACKGROUND);
2272 GetClientRect(hwnd, &rect);
2273 FillRect((HDC)(wParam), &rect, bgBrush);
2276 SetClassLongPtr(hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)
nullptr);
2292 case WM_NCDESTROY: {
2303 case WM_WINDOWPOSCHANGING:
2317 case WM_ACTIVATEAPP:
2333 case DM_POINTERHITTEST: {
2346 GHOST_PRINT(
"GHOST_SystemWin32::wndProc: GHOST window event before creation\n");
2358 GHOST_PRINT(
"GHOST_SystemWin32::wndProc: event without window\n");
2363 eventHandled =
true;
2366 if (!eventHandled) {
2367 lResult = ::DefWindowProcW(hwnd, msg, wParam, lParam);
2375 if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(
nullptr)) {
2377 HANDLE hData = GetClipboardData(CF_UNICODETEXT);
2378 if (hData ==
nullptr) {
2382 buffer = (
wchar_t *)GlobalLock(hData);
2392 GlobalUnlock(hData);
2397 if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(
nullptr)) {
2400 HANDLE hData = GetClipboardData(CF_TEXT);
2401 if (hData ==
nullptr) {
2405 buffer = (
char *)GlobalLock(hData);
2411 len = strlen(buffer);
2412 char *temp_buff = (
char *)malloc(
len + 1);
2413 memcpy(temp_buff, buffer,
len + 1);
2417 GlobalUnlock(hData);
2427 if (selection || !buffer) {
2431 if (OpenClipboard(
nullptr)) {
2437 HGLOBAL clipbuffer = GlobalAlloc(GMEM_MOVEABLE,
sizeof(
wchar_t) *
len);
2439 wchar_t *
data = (
wchar_t *)GlobalLock(clipbuffer);
2443 GlobalUnlock(clipbuffer);
2444 SetClipboardData(CF_UNICODETEXT, clipbuffer);
2453 if (IsClipboardFormatAvailable(CF_DIBV5) ||
2454 IsClipboardFormatAvailable(RegisterClipboardFormat(
"PNG")))
2461 if (IsClipboardFormatAvailable(CF_HDROP)) {
2462 if (OpenClipboard(
nullptr)) {
2463 if (HANDLE hGlobal = GetClipboardData(CF_HDROP)) {
2464 if (HDROP hDrop =
static_cast<HDROP
>(GlobalLock(hGlobal))) {
2465 UINT fileCount = DragQueryFile(hDrop, 0xffffffff,
nullptr, 0);
2466 if (fileCount == 1) {
2467 WCHAR lpszFile[MAX_PATH] = {0};
2468 DragQueryFileW(hDrop, 0, lpszFile, MAX_PATH);
2478 GlobalUnlock(hGlobal);
2489 char *filepath =
nullptr;
2491 if (OpenClipboard(
nullptr)) {
2492 if (HANDLE hGlobal = GetClipboardData(CF_HDROP)) {
2493 if (HDROP hDrop =
static_cast<HDROP
>(GlobalLock(hGlobal))) {
2494 UINT fileCount = DragQueryFile(hDrop, 0xffffffff,
nullptr, 0);
2495 if (fileCount == 1) {
2496 WCHAR lpszFile[MAX_PATH] = {0};
2497 DragQueryFileW(hDrop, 0, lpszFile, MAX_PATH);
2500 GlobalUnlock(hGlobal);
2511 *r_height = ibuf->
y;
2513 uint *rgba =
static_cast<uint *
>(malloc(byte_count));
2527 HANDLE hGlobal = GetClipboardData(CF_DIBV5);
2528 if (hGlobal ==
nullptr) {
2532 BITMAPV5HEADER *bitmapV5Header = (BITMAPV5HEADER *)GlobalLock(hGlobal);
2533 if (bitmapV5Header ==
nullptr) {
2537 int offset = bitmapV5Header->bV5Size + bitmapV5Header->bV5ClrUsed *
sizeof(RGBQUAD);
2539 BYTE *buffer = (BYTE *)bitmapV5Header + offset;
2540 int bitcount = bitmapV5Header->bV5BitCount;
2541 int width = bitmapV5Header->bV5Width;
2542 int height = bitmapV5Header->bV5Height;
2546 if (
uint64_t(width) *
uint64_t(height) > (std::numeric_limits<DWORD>::max() / 4)) {
2547 GlobalUnlock(hGlobal);
2554 DWORD ColorMasks[4];
2555 ColorMasks[0] = bitmapV5Header->bV5RedMask ? bitmapV5Header->bV5RedMask : 0xff;
2556 ColorMasks[1] = bitmapV5Header->bV5GreenMask ? bitmapV5Header->bV5GreenMask : 0xff00;
2557 ColorMasks[2] = bitmapV5Header->bV5BlueMask ? bitmapV5Header->bV5BlueMask : 0xff0000;
2558 ColorMasks[3] = bitmapV5Header->bV5AlphaMask ? bitmapV5Header->bV5AlphaMask : 0xff000000;
2561 DWORD ColorShifts[4];
2562 for (
int i = 0;
i < 4;
i++) {
2563 _BitScanForward(&ColorShifts[
i], ColorMasks[
i]);
2568 uint8_t *target = (uint8_t *)rgba;
2570 if (bitmapV5Header->bV5Compression == BI_BITFIELDS && bitcount == 32) {
2571 for (
int h = 0; h < height; h++) {
2572 for (
int w = 0;
w < width;
w++, target += 4, source += 4) {
2573 DWORD *pix = (DWORD *)source;
2574 target[0] = uint8_t((*pix & ColorMasks[0]) >> ColorShifts[0]);
2575 target[1] = uint8_t((*pix & ColorMasks[1]) >> ColorShifts[1]);
2576 target[2] = uint8_t((*pix & ColorMasks[2]) >> ColorShifts[2]);
2577 target[3] = uint8_t((*pix & ColorMasks[3]) >> ColorShifts[3]);
2581 else if (bitmapV5Header->bV5Compression == BI_RGB && bitcount == 32) {
2582 for (
int h = 0; h < height; h++) {
2583 for (
int w = 0;
w < width;
w++, target += 4, source += 4) {
2584 RGBQUAD *
quad = (RGBQUAD *)source;
2585 target[0] = uint8_t(
quad->rgbRed);
2586 target[1] = uint8_t(
quad->rgbGreen);
2587 target[2] = uint8_t(
quad->rgbBlue);
2588 target[3] = (bitmapV5Header->bV5AlphaMask) ? uint8_t(
quad->rgbReserved) : 255;
2592 else if (bitmapV5Header->bV5Compression == BI_RGB && bitcount == 24) {
2593 int bytes_per_row = ((((width * bitcount) + 31) & ~31) >> 3);
2594 int slack = bytes_per_row - (width * 3);
2595 for (
int h = 0; h < height; h++, source += slack) {
2596 for (
int w = 0;
w < width;
w++, target += 4, source += 3) {
2597 RGBTRIPLE *
triple = (RGBTRIPLE *)source;
2598 target[0] = uint8_t(
triple->rgbtRed);
2599 target[1] = uint8_t(
triple->rgbtGreen);
2600 target[2] = uint8_t(
triple->rgbtBlue);
2606 GlobalUnlock(hGlobal);
2613 HANDLE hGlobal = GetClipboardData(
format);
2614 if (hGlobal ==
nullptr) {
2618 LPVOID pMem = GlobalLock(hGlobal);
2623 uint *rgba =
nullptr;
2630 *r_height = ibuf->
y;
2632 rgba = (
uint *)malloc(byte_count);
2637 GlobalUnlock(hGlobal);
2643 if (IsClipboardFormatAvailable(CF_HDROP)) {
2647 if (!OpenClipboard(
nullptr)) {
2652 UINT cfPNG = RegisterClipboardFormat(
"PNG");
2654 for (
int cf = EnumClipboardFormats(0); cf; cf = EnumClipboardFormats(cf)) {
2655 if (
ELEM(cf, CF_DIBV5, cfPNG)) {
2658 if (cf == CF_DIBV5 || (cf == CF_BITMAP &&
format == cfPNG)) {
2663 uint *rgba =
nullptr;
2665 if (
format == CF_DIBV5) {
2668 else if (
format == cfPNG) {
2685 if (
uint64_t(width) *
uint64_t(height) > (std::numeric_limits<DWORD>::max() / 4)) {
2689 DWORD size_pixels = width * height * 4;
2691 HGLOBAL hMem = GlobalAlloc(GHND,
sizeof(BITMAPV5HEADER) + size_pixels);
2696 BITMAPV5HEADER *hdr = (BITMAPV5HEADER *)GlobalLock(hMem);
2702 hdr->bV5Size =
sizeof(BITMAPV5HEADER);
2703 hdr->bV5Width = width;
2704 hdr->bV5Height = height;
2706 hdr->bV5BitCount = 32;
2707 hdr->bV5SizeImage = size_pixels;
2708 hdr->bV5Compression = BI_BITFIELDS;
2709 hdr->bV5RedMask = 0x000000ff;
2710 hdr->bV5GreenMask = 0x0000ff00;
2711 hdr->bV5BlueMask = 0x00ff0000;
2712 hdr->bV5AlphaMask = 0xff000000;
2713 hdr->bV5CSType = LCS_sRGB;
2714 hdr->bV5Intent = LCS_GM_IMAGES;
2715 hdr->bV5ClrUsed = 0;
2717 memcpy((
char *)hdr +
sizeof(BITMAPV5HEADER), rgba, size_pixels);
2721 if (!SetClipboardData(CF_DIBV5, hMem)) {
2731 UINT cf = RegisterClipboardFormat(
"PNG");
2748 LPVOID pMem = GlobalLock(hMem);
2760 if (!SetClipboardData(cf, hMem)) {
2770 if (!OpenClipboard(
nullptr) || !EmptyClipboard()) {
2787 const char *message,
2788 const char *help_label,
2789 const char *continue_label,
2798 int nButtonPressed = 0;
2799 TASKDIALOGCONFIG config = {0};
2800 const TASKDIALOG_BUTTON buttons[] = {{IDOK, help_label_16}, {IDCONTINUE, continue_label_16}};
2802 config.cbSize =
sizeof(config);
2803 config.hInstance = 0;
2804 config.dwCommonButtons = 0;
2807 TD_INFORMATION_ICON);
2808 config.pszWindowTitle =
L"Blender";
2809 config.pszMainInstruction = title_16;
2810 config.pszContent = message_16;
2811 const bool has_link = link && strlen(link);
2812 config.pButtons = has_link ? buttons : buttons + 1;
2813 config.cButtons = has_link ? 2 : 1;
2815 TaskDialogIndirect(&config, &nButtonPressed,
nullptr,
nullptr);
2816 switch (nButtonPressed) {
2818 ShellExecute(
nullptr,
"open", link,
nullptr,
nullptr, SW_SHOWNORMAL);
2826 free((
void *)title_16);
2827 free((
void *)message_16);
2828 free((
void *)help_label_16);
2829 free((
void *)continue_label_16);
2839 PROCESSENTRY32 pe32 = {0};
2840 DWORD ppid = 0, pid = GetCurrentProcessId();
2841 snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
2842 if (snapshot == INVALID_HANDLE_VALUE) {
2845 pe32.dwSize =
sizeof(pe32);
2846 if (!Process32First(snapshot, &pe32)) {
2847 CloseHandle(snapshot);
2851 if (pe32.th32ProcessID == pid) {
2852 ppid = pe32.th32ParentProcessID;
2855 }
while (Process32Next(snapshot, &pe32));
2856 CloseHandle(snapshot);
2863 HANDLE handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, pid);
2865 GetModuleFileNameEx(handle, 0, buffer, max_len);
2868 CloseHandle(handle);
2874 HWND hwnd = GetConsoleWindow();
2877 DWORD pid = (DWORD)-1;
2879 char parent_name[MAX_PATH];
2880 bool start_from_launcher =
false;
2882 GetWindowThreadProcessId(hwnd, &pid);
2884 char *filename = strrchr(parent_name,
'\\');
2885 if (filename !=
nullptr) {
2886 start_from_launcher = strstr(filename,
"blender.exe") !=
nullptr;
2891 if (pid != (start_from_launcher ? ppid : GetCurrentProcessId())) {
2901 HWND wnd = GetConsoleWindow();
2906 ShowWindow(wnd, SW_HIDE);
2912 ShowWindow(wnd, SW_HIDE);
2917 ShowWindow(wnd, SW_SHOW);
2919 DeleteMenu(GetSystemMenu(wnd,
FALSE), SC_CLOSE, MF_BYCOMMAND);
2928 DeleteMenu(GetSystemMenu(wnd,
FALSE), SC_CLOSE, MF_BYCOMMAND);
void BLI_kdtree_nd_ free(KDTree *tree)
#define GHOST_OPENGL_WGL_RESET_NOTIFICATION_STRATEGY
#define GHOST_PRINTF(x,...)
#define GHOST_ASSERT(x, info)
std::array< GHOST_NDOF_ButtonT, 6 > NDOF_Button_Array
static uint * getClipboardImageFilepath(int *r_width, int *r_height)
static void initRawInput()
static bool putClipboardImageDibV5(uint *rgba, int width, int height)
static uint * getClipboardImageImBuf(int *r_width, int *r_height, UINT format)
static const std::map< uint16_t, GHOST_NDOF_ButtonT > longButtonHIDsToGHOST_NDOFButtons
static GHOST_NDOF_ButtonT translateLongButtonToNDOFButton(uint16_t longKey)
BOOL(API * GHOST_WIN32_EnableNonClientDpiScaling)(HWND)
static bool isStartedFromCommandPrompt()
static uint * getClipboardImageDibV5(int *r_width, int *r_height)
static bool putClipboardImagePNG(uint *rgba, int width, int height)
static uint64_t getMessageTime(GHOST_SystemWin32 *system)
static DWORD GetParentProcessID(void)
static bool getProcessName(int pid, char *buffer, int max_len)
@ GHOST_kEventWheelAxisVertical
@ GHOST_kEventWheelAxisHorizontal
@ GHOST_kTrackpadEventMagnify
@ GHOST_kTrackpadEventScroll
@ GHOST_kWindowStateMinimized
@ GHOST_kStandardCursorDefault
@ GHOST_NDOF_BUTTON_TILT_CCW
@ GHOST_NDOF_BUTTON_SAVE_V1
@ GHOST_NDOF_BUTTON_ROLL_CCW
@ GHOST_NDOF_BUTTON_SPIN_CCW
@ GHOST_NDOF_BUTTON_SAVE_V3
@ GHOST_NDOF_BUTTON_SAVE_V2
@ GHOST_NDOF_BUTTON_BOTTOM
@ GHOST_kEventWindowClose
@ GHOST_kEventImeComposition
@ GHOST_kEventWindowActivate
@ GHOST_kEventWindowUpdate
@ GHOST_kEventWindowDeactivate
@ GHOST_kEventImeCompositionStart
@ GHOST_kEventImeCompositionEnd
@ GHOST_kEventWindowDPIHintChanged
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
#define GHOST_KEY_MODIFIER_CHECK(key)
@ GHOST_kCapabilityKeyboardHyperKey
@ GHOST_kCapabilityPrimaryClipboard
#define GHOST_CAPABILITY_FLAG_ALL
@ GHOST_kKeyNumpadAsterisk
@ GHOST_kModifierKeyRightControl
@ GHOST_kModifierKeyLeftControl
@ GHOST_kModifierKeyRightAlt
@ GHOST_kModifierKeyRightShift
@ GHOST_kModifierKeyLeftAlt
@ GHOST_kModifierKeyLeftShift
@ GHOST_kModifierKeyLeftOS
@ GHOST_kModifierKeyRightOS
@ GHOST_kButtonMaskButton4
@ GHOST_kButtonMaskButton5
@ GHOST_kButtonMaskMiddle
GHOST_TConsoleWindowState
@ GHOST_kConsoleWindowStateShow
@ GHOST_kConsoleWindowStateHideForNonConsoleLaunch
@ GHOST_kConsoleWindowStateHide
@ GHOST_kConsoleWindowStateToggle
@ GHOST_kTabletWinPointer
#define GET_POINTERID_WPARAM(wParam)
#define WINTAB_PRINTF(x,...)
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
ImBuf * IMB_load_image_from_memory(const unsigned char *mem, const size_t size, const int flags, const char *descr, const char *filepath=nullptr, char r_colorspace[IM_MAX_SPACE]=nullptr)
ImBuf * IMB_allocFromBuffer(const uint8_t *byte_buffer, const float *float_buffer, unsigned int w, unsigned int h, unsigned int channels)
void IMB_freeImBuf(ImBuf *ibuf)
bool IMB_save_image(ImBuf *ibuf, const char *filepath, const int flags)
BMesh const char void * data
unsigned long long int uint64_t
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
SIMD_FORCE_INLINE btScalar triple(const btVector3 &v1, const btVector3 &v2) const
void removeTypeEvents(GHOST_TEventType type, const GHOST_IWindow *window=nullptr)
static GHOST_ISystem * getSystem()
GHOST_TKey hardKey(RAWINPUT const &raw, bool *r_key_down)
void setTabletAPI(GHOST_TTabletAPI api) override
GHOST_TSuccess putClipboardImage(uint *rgba, int width, int height) const override
static GHOST_EventButton * processButtonEvent(GHOST_TEventType type, GHOST_WindowWin32 *window, GHOST_TButton mask)
GHOST_TKey processSpecialKey(short vKey, short scanCode) const
static GHOST_Event * processWindowSizeEvent(GHOST_WindowWin32 *window)
GHOST_TKey convertKey(short vKey, short ScanCode, short extend) const
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y) override
GHOST_TSuccess showMessageBox(const char *title, const char *message, const char *help_label, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options) const override
static void processWheelEventHorizontal(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam)
static GHOST_EventCursor * processCursorEvent(GHOST_WindowWin32 *window, const int32_t screen_co[2])
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const override
static GHOST_ContextD3D * createOffscreenContextD3D()
GHOST_IContext * createOffscreenContext(GHOST_GPUSettings gpuSettings) override
static GHOST_TSuccess disposeContextD3D(GHOST_ContextD3D *context)
GHOST_TSuccess hasClipboardImage() const override
static void processWintabEvent(GHOST_WindowWin32 *window)
uint64_t performanceCounterToMillis(__int64 perf_ticks) const
uint * getClipboardImage(int *r_width, int *r_height) const override
GHOST_TCapabilityFlag getCapabilities() const override
static GHOST_EventKey * processKeyEvent(GHOST_WindowWin32 *window, RAWINPUT const &raw)
void initDebug(GHOST_Debug debug) override
int m_wheelDeltaAccumVertical
char * getClipboard(bool selection) const override
GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const override
uint8_t getNumDisplays() const override
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override
static void processMinMaxInfo(MINMAXINFO *minmax)
static void processWheelEventVertical(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam)
void putClipboard(const char *buffer, bool selection) const override
static GHOST_Event * processWindowEvent(GHOST_TEventType type, GHOST_WindowWin32 *window)
void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const override
GHOST_TSuccess init() override
bool setConsoleWindowState(GHOST_TConsoleWindowState action) override
int m_wheelDeltaAccumHorizontal
GHOST_IWindow * createWindow(const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, GHOST_GPUSettings gpuSettings, const bool exclusive=false, const bool is_dialog=false, const GHOST_IWindow *parentWindow=nullptr) override
GHOST_TSuccess exit() override
bool processEvents(bool waitForEvent) override
static void processPointerEvent(UINT type, GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam, bool &eventhandled)
~GHOST_SystemWin32() override
uint64_t getMilliSeconds() const override
void handleKeyboardChange()
GHOST_IWindow * getWindowUnderCursor(int32_t, int32_t) override
GHOST_TSuccess getPixelAtCursor(float r_color[3]) const override
static LRESULT WINAPI s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType, GHOST_WindowWin32 *window, int mouseX, int mouseY, void *data)
GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const override
GHOST_TSuccess disposeContext(GHOST_IContext *context) override
bool m_hasPerformanceCounter
GHOST_EventManager * getEventManager() const
GHOST_WindowManager * getWindowManager() const
GHOST_TSuccess pushEvent(const GHOST_IEvent *event)
bool m_multitouchGestures
GHOST_TSuccess init() override
GHOST_TimerManager * getTimerManager() const
void initDebug(GHOST_Debug debug) override
void setTabletAPI(GHOST_TTabletAPI api) override
GHOST_WindowManager * m_windowManager
GHOST_EventManager * m_eventManager
GHOST_TSuccess exit() override
void dispatchEvents() override
bool fireTimers(uint64_t time)
const std::vector< GHOST_IWindow * > & getWindows() const
GHOST_IWindow * getActiveWindow() const
GHOST_TSuccess setActiveWindow(GHOST_IWindow *window)
void setWindowInactive(const GHOST_IWindow *window)
void resetPointerPenInfo()
GHOST_TTrackpadInfo getTrackpadInfo()
void updateDirectManipulation()
void loadCursor(bool visible, GHOST_TStandardCursor cursorShape) const
bool usingTabletAPI(GHOST_TTabletAPI api) const
GHOST_TSuccess getPointerInfo(std::vector< GHOST_PointerInfoWin32 > &outPointerInfo, WPARAM wParam, LPARAM lParam)
void loadWintab(bool enable)
GHOST_TabletData getTabletData()
GHOST_Wintab * getWintab() const
void updateMouseCapture(GHOST_MouseCaptureEventWin32 event)
GHOST_TSuccess setState(GHOST_TWindowState state)
void getClientBounds(GHOST_Rect &bounds) const
void onPointerHitTest(WPARAM wParam)
void clientToScreen(int32_t inX, int32_t inY, int32_t &outX, int32_t &outY) const
GHOST_TWindowState getState() const
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override
void setCursorGrabAccum(int32_t x, int32_t y)
GHOST_TAxisFlag getCursorGrabAxis() const
GHOST_TStandardCursor getCursorShape() const override
bool getCursorVisibility() const override
GHOST_TGrabCursorMode getCursorGrabMode() const
bool getCursorGrabModeIsWarp() const
void getCursorGrabAccum(int32_t &x, int32_t &y) const
void mapWintabToSysCoordinates(int x_in, int y_in, int &x_out, int &y_out)
GHOST_TabletData getLastTabletData()
void getInput(std::vector< GHOST_WintabInfoWin32 > &outWintabInfo)
void processInfoChange(LPARAM lParam)
bool testCoordinates(int sysX, int sysY, int wtX, int wtY)
static void setDebug(bool debug)
blender::gpu::Batch * quad
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
GHOST_TDrawingContextType context_type
GHOST_GPUDevice preferred_device
void set(GHOST_TModifierKey mask, bool down)
bool isScrollDirectionInverted
ImbFormatOptions foptions
ImBufByteBuffer byte_buffer
unsigned int encoded_buffer_size
ImBufByteBuffer encoded_buffer
wchar_t * alloc_utf16_from_8(const char *in8, size_t add)
char * alloc_utf_8_from_16(const wchar_t *in16, size_t add)
int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16)
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8)
size_t count_utf_16_from_8(const char *string8)
#define UTF16_ENCODE(in8str)
#define UTF16_UN_ENCODE(in8str)