29 #define WM_DPICHANGED 0x02E0
33 #define WM_TOUCH 0x0240
38 #define TOUCH_COORD_TO_PIXEL(l) ((l) / 100)
43 DECLARE_HANDLE(HTOUCHINPUT);
47 TypeHandle WinGraphicsWindow::WinWindowHandle::_type_handle;
49 WinGraphicsWindow::WindowHandles WinGraphicsWindow::_window_handles;
53 bool WinGraphicsWindow::_cursor_hidden =
false;
55 RECT WinGraphicsWindow::_mouse_unconfined_cliprect;
60 bool WinGraphicsWindow::_got_saved_params =
false;
61 int WinGraphicsWindow::_saved_mouse_trails;
62 BOOL WinGraphicsWindow::_saved_cursor_shadow;
63 BOOL WinGraphicsWindow::_saved_mouse_vanish;
69 int WinGraphicsWindow::_window_class_index = 0;
71 static const char *
const errorbox_title =
"Panda3D Error";
75 typedef BOOL (WINAPI *PFN_REGISTERTOUCHWINDOW)(IN HWND hWnd, IN ULONG ulFlags);
76 typedef BOOL (WINAPI *PFN_GETTOUCHINPUTINFO)(IN HTOUCHINPUT hTouchInput, IN UINT cInputs, OUT PTOUCHINPUT pInputs, IN
int cbSize);
77 typedef BOOL (WINAPI *PFN_CLOSETOUCHINPUTHANDLE)(IN HTOUCHINPUT hTouchInput);
79 static PFN_REGISTERTOUCHWINDOW pRegisterTouchWindow = 0;
80 static PFN_GETTOUCHINPUTINFO pGetTouchInputInfo = 0;
81 static PFN_CLOSETOUCHINPUTHANDLE pCloseTouchInputHandle = 0;
88 const std::string &name,
94 GraphicsWindow(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
96 initialize_input_devices();
100 _tracking_mouse_leaving =
false;
102 _lost_keypresses =
false;
103 _lshift_down =
false;
104 _rshift_down =
false;
105 _lcontrol_down =
false;
106 _rcontrol_down =
false;
117 ~WinGraphicsWindow() {
118 if (_window_handle !=
nullptr) {
119 DCAST(WinWindowHandle, _window_handle)->clear_window();
131 nassertr(device >= 0 && device < (
int)_input_devices.size(),
MouseData());
137 if (device == 0 && result._in_window && GetCursorPos(&cpos) && ScreenToClient(_hWnd, &cpos)) {
139 result._xpos = cpos.x;
140 result._ypos = cpos.y;
166 if (!_properties.get_foreground() )
177 SetCursorPos(view_rect.left + x, view_rect.top + y);
182 if ((device < 1)||(device >= (
int)_input_devices.size())) {
200 HIMC hIMC = ImmGetContext(_hWnd);
202 if (!ImmSetOpenStatus(hIMC,
false)) {
203 windisplay_cat.debug() <<
"ImmSetOpenStatus failed\n";
205 ImmReleaseContext(_hWnd, hIMC);
209 windisplay_cat.debug() <<
"success: closed ime window\n";
257 if (!disable_message_loop) {
260 while (PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE)) {
301 LPoint2i top_left = _properties.get_origin();
302 LPoint2i bottom_right = top_left + _properties.get_size();
304 DWORD window_style = make_style(_properties);
305 SetWindowLong(_hWnd, GWL_STYLE, window_style);
309 SetRect(&view_rect, top_left[0], top_left[1],
310 bottom_right[0], bottom_right[1]);
312 GetWindowInfo(_hWnd, &wi);
313 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
316 SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top,
317 view_rect.right - view_rect.left,
318 view_rect.bottom - view_rect.top,
319 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED |
320 SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
324 std::string title = properties.
get_title();
325 _properties.set_title(title);
328 SetWindowTextW(_hWnd, title_w.c_str());
335 ::SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon);
336 ::SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon);
345 _properties.set_cursor_hidden(hide_cursor);
346 if (_cursor_window ==
this) {
347 hide_or_show_cursor(hide_cursor);
355 _properties.set_cursor_filename(filename);
357 _cursor = get_cursor(filename);
359 _cursor = LoadCursor(
nullptr, IDC_ARROW);
362 if (_cursor_window ==
this) {
370 WindowProperties::ZOrder last_z_order = _properties.get_z_order();
372 adjust_z_order(last_z_order, properties.
get_z_order());
378 if (!SetActiveWindow(_hWnd)) {
379 windisplay_cat.warning()
380 <<
"SetForegroundWindow() failed!\n";
382 _properties.set_foreground(
true);
389 if (_properties.get_minimized() != properties.
get_minimized()) {
391 ShowWindow(_hWnd, SW_MINIMIZE);
393 ShowWindow(_hWnd, SW_RESTORE);
403 if (do_fullscreen_switch()){
404 _properties.set_fullscreen(
true);
407 windisplay_cat.warning()
408 <<
"Switching to fullscreen mode failed!\n";
411 if (do_windowed_switch()){
412 _properties.set_fullscreen(
false);
415 windisplay_cat.warning()
416 <<
"Switching to windowed mode failed!\n";
421 if (properties.has_mouse_mode()) {
422 if (properties.
get_mouse_mode() != _properties.get_mouse_mode()) {
424 case WindowProperties::M_absolute:
425 case WindowProperties::M_relative:
427 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
429 windisplay_cat.info() <<
"Unconfining cursor from window\n";
431 _properties.set_mouse_mode(WindowProperties::M_absolute);
434 case WindowProperties::M_confined:
435 if (confine_cursor()) {
436 _properties.set_mouse_mode(WindowProperties::M_confined);
450 void WinGraphicsWindow::
452 GraphicsWindow::trigger_flip();
458 InvalidateRect(_hWnd,
nullptr, FALSE);
459 _got_expose_event =
false;
461 if (windisplay_cat.is_spam()) {
462 windisplay_cat.spam()
463 <<
"InvalidateRect: " <<
this <<
"\n";
471 void WinGraphicsWindow::
473 set_cursor_out_of_window();
474 DestroyWindow(_hWnd);
478 do_fullscreen_disable();
482 _window_handles.erase(_hWnd);
485 GraphicsWindow::close_window();
492 bool WinGraphicsWindow::
494 if (_properties.has_cursor_filename()) {
495 _cursor = get_cursor(_properties.get_cursor_filename());
498 _cursor = LoadCursor(
nullptr, IDC_ARROW);
500 bool want_foreground = (!_properties.has_foreground() || _properties.get_foreground());
501 bool want_minimized = (_properties.has_minimized() && _properties.get_minimized()) && !want_foreground;
503 HWND old_foreground_window = GetForegroundWindow();
508 _creating_window =
this;
509 bool opened = open_graphic_window();
510 _creating_window =
nullptr;
518 _window_handles.insert(WindowHandles::value_type(_hWnd,
this));
521 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0,
522 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
525 if (want_minimized) {
526 ShowWindow(_hWnd, SW_MINIMIZE);
527 ShowWindow(_hWnd, SW_MINIMIZE);
529 ShowWindow(_hWnd, SW_SHOWNORMAL);
530 ShowWindow(_hWnd, SW_SHOWNORMAL);
533 HWND new_foreground_window = _hWnd;
534 if (!want_foreground) {
537 new_foreground_window = old_foreground_window;
540 if (!SetActiveWindow(new_foreground_window)) {
541 windisplay_cat.warning()
542 <<
"SetActiveWindow() failed!\n";
548 if (!SetForegroundWindow(new_foreground_window)) {
549 windisplay_cat.warning()
550 <<
"SetForegroundWindow() failed!\n";
556 HIMC hIMC = ImmGetContext(_hWnd);
558 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
559 ImmReleaseContext(_hWnd, hIMC);
563 if (_input_devices.size() > 1) {
565 Rid.usUsagePage = 0x01;
568 Rid.hwndTarget = _hWnd;
569 RegisterRawInputDevices(&Rid, 1,
sizeof (Rid));
573 _window_handle = NativeWindowHandle::make_win(_hWnd);
576 _window_handle =
new WinWindowHandle(
this, *_window_handle);
579 if (_parent_window_handle !=
nullptr) {
580 _parent_window_handle->attach_child(_window_handle);
587 static bool initialized =
false;
590 HMODULE user32 = GetModuleHandleA(
"user32.dll");
593 pRegisterTouchWindow = (PFN_REGISTERTOUCHWINDOW)GetProcAddress(user32,
"RegisterTouchWindow");
594 pGetTouchInputInfo = (PFN_GETTOUCHINPUTINFO)GetProcAddress(user32,
"GetTouchInputInfo");
595 pCloseTouchInputHandle = (PFN_CLOSETOUCHINPUTHANDLE)GetProcAddress(user32,
"CloseTouchInputHandle");
600 if (pRegisterTouchWindow !=
nullptr) {
601 pRegisterTouchWindow(_hWnd, 0);
613 void WinGraphicsWindow::
614 initialize_input_devices() {
616 PRAWINPUTDEVICELIST pRawInputDeviceList;
618 nassertv(_input_devices.size() == 0);
621 memset(_input_device_handle, 0,
sizeof(_input_device_handle));
623 GraphicsWindowInputDevice::pointer_and_keyboard(
this,
"keyboard_mouse");
624 add_input_device(device);
628 if (GetRawInputDeviceList(
nullptr, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) != 0) {
633 pRawInputDeviceList = (PRAWINPUTDEVICELIST)alloca(
sizeof(RAWINPUTDEVICELIST) * nInputDevices);
634 if (pRawInputDeviceList==0) {
639 if (GetRawInputDeviceList(pRawInputDeviceList, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) == -1) {
644 for (
int i = 0; i < (int)nInputDevices; i++) {
645 if (pRawInputDeviceList[i].dwType == RIM_TYPEMOUSE) {
648 if (GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)0, &nSize) != 0) {
651 char *psName = (
char*)alloca(
sizeof(TCHAR) * nSize);
652 if (psName == 0)
return;
653 if (GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)psName, &nSize) < 0) {
658 if (strncmp(psName,
"\\??\\Root#RDP_MOU#0000#",22)!=0) {
659 if (_input_devices.size() < 32) {
660 if (strncmp(psName,
"\\??\\",4)==0) psName += 4;
661 char *pound1 = strchr(psName,
'#');
662 char *pound2 = pound1 ? strchr(pound1+1,
'#') : 0;
663 char *pound3 = pound2 ? strchr(pound2+1,
'#') : 0;
664 if (pound3) *pound3 = 0;
665 for (
char *p = psName; *p; p++) {
670 if (pound2) *pound2 =
'.';
671 _input_device_handle[_input_devices.size()] = pRawInputDeviceList[i].hDevice;
674 device->set_pointer_in_window(0, 0);
675 add_input_device(device);
688 void WinGraphicsWindow::
698 void WinGraphicsWindow::
708 bool WinGraphicsWindow::
709 do_reshape_request(
int x_origin,
int y_origin,
bool has_origin,
710 int x_size,
int y_size) {
711 if (windisplay_cat.is_debug()) {
712 windisplay_cat.debug()
713 <<
"Got reshape request (" << x_origin <<
", " << y_origin
714 <<
", " << has_origin <<
", " << x_size <<
", " << y_size <<
")\n";
719 if (x_origin == -2) {
720 x_origin = 0.5 * (_pipe->get_display_width() - x_size);
722 if (y_origin == -2) {
723 y_origin = 0.5 * (_pipe->get_display_height() - y_size);
725 _properties.set_origin(x_origin, y_origin);
727 if (x_origin == -1 && y_origin == -1) {
737 SetRect(&view_rect, x_origin, y_origin,
738 x_origin + x_size, y_origin + y_size);
740 GetWindowInfo(_hWnd, &wi);
741 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
743 UINT flags = SWP_NOZORDER | SWP_NOSENDCHANGING;
746 x_origin = view_rect.left;
747 y_origin = view_rect.top;
749 x_origin = CW_USEDEFAULT;
750 y_origin = CW_USEDEFAULT;
754 SetWindowPos(_hWnd,
nullptr, x_origin, y_origin,
755 view_rect.right - view_rect.left,
756 view_rect.bottom - view_rect.top,
760 if (_properties.has_mouse_mode() &&
761 _properties.get_mouse_mode() == WindowProperties::M_confined) {
770 return do_fullscreen_resize(x_size, y_size);
777 void WinGraphicsWindow::
780 if (!GetClientRect(_hWnd, &view_rect)) {
783 if (windisplay_cat.is_debug()) {
784 windisplay_cat.debug()
785 <<
"GetClientRect() failed in handle_reshape. Ignoring.\n";
792 if (view_rect.left == 0 && view_rect.right == 0 &&
793 view_rect.bottom == 0 && view_rect.top == 0) {
794 if (windisplay_cat.is_debug()) {
795 windisplay_cat.debug()
796 <<
"GetClientRect() returned all zeroes in handle_reshape. Ignoring.\n";
801 bool result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.left));
803 result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.right));
807 if (windisplay_cat.is_debug()) {
808 windisplay_cat.debug()
809 <<
"ClientToScreen() failed in handle_reshape. Ignoring.\n";
815 properties.
set_size((view_rect.right - view_rect.left),
816 (view_rect.bottom - view_rect.top));
819 properties.
set_origin(view_rect.left, view_rect.top);
821 if (windisplay_cat.is_debug()) {
822 windisplay_cat.debug()
823 <<
"reshape to origin: (" << properties.
get_x_origin() <<
","
829 system_changed_properties(properties);
835 bool WinGraphicsWindow::
836 do_fullscreen_resize(
int x_size,
int y_size) {
837 HWND hDesktopWindow = GetDesktopWindow();
838 HDC scrnDC = GetDC(hDesktopWindow);
839 DWORD dwFullScreenBitDepth = GetDeviceCaps(scrnDC, BITSPIXEL);
840 ReleaseDC(hDesktopWindow, scrnDC);
848 if (!find_acceptable_display_mode(x_size, y_size,
849 dwFullScreenBitDepth, dm)) {
850 windisplay_cat.error()
851 <<
"window resize(" << x_size <<
", " << y_size
852 <<
") failed, no compatible fullscreen display mode found!\n";
857 SetWindowPos(_hWnd,
nullptr, 0,0, x_size, y_size,
858 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
859 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
861 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
862 windisplay_cat.error()
863 <<
"resize ChangeDisplaySettings failed (error code: "
864 << chg_result <<
") for specified res: "
865 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
866 <<
" x " << dm.dmBitsPerPel <<
", "
867 << dm.dmDisplayFrequency <<
" Hz\n";
871 _fullscreen_display_mode = dm;
873 windisplay_cat.info()
874 <<
"Resized fullscreen window to " << x_size <<
", " << y_size
875 <<
" bitdepth " << dwFullScreenBitDepth <<
", "
876 << dm.dmDisplayFrequency <<
"Hz\n";
878 _properties.set_size(x_size, y_size);
887 bool WinGraphicsWindow::
888 do_fullscreen_switch() {
889 if (!do_fullscreen_enable()) {
895 props.set_fullscreen(
true);
896 DWORD window_style = make_style(props);
897 SetWindowLong(_hWnd, GWL_STYLE, window_style);
899 WINDOW_METRICS metrics;
901 if (!calculate_metrics(
true, window_style, metrics, has_origin)){
905 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, metrics.width, metrics.height,
906 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
913 bool WinGraphicsWindow::
914 do_windowed_switch() {
915 do_fullscreen_disable();
918 props.set_fullscreen(
false);
919 DWORD window_style = make_style(props);
920 SetWindowLong(_hWnd, GWL_STYLE, window_style);
922 WINDOW_METRICS metrics;
925 if (!calculate_metrics(
false, window_style, metrics, has_origin)){
933 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0,
934 metrics.width, metrics.height,
935 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
938 if (_properties.has_mouse_mode() &&
939 _properties.get_mouse_mode() == WindowProperties::M_confined) {
950 void WinGraphicsWindow::
951 reconsider_fullscreen_size(DWORD &, DWORD &, DWORD &) {
960 void WinGraphicsWindow::
961 support_overlay_window(
bool) {
967 DWORD WinGraphicsWindow::
976 DWORD window_style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
979 window_style |= WS_POPUP | WS_SYSMENU;
981 if (_parent_window_handle) {
982 window_style |= WS_CHILD;
984 window_style |= WS_POPUP;
988 window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
991 window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX);
993 window_style |= WS_BORDER;
1004 bool WinGraphicsWindow::
1005 calculate_metrics(
bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics,
1009 has_origin = _properties.has_origin();
1010 if (!fullscreen && has_origin) {
1011 metrics.x = _properties.get_x_origin();
1012 metrics.y = _properties.get_y_origin();
1015 if (metrics.x == -2) {
1016 metrics.x = 0.5 * (_pipe->get_display_width() - _properties.get_x_size());
1018 if (metrics.y == -2) {
1019 metrics.y = 0.5 * (_pipe->get_display_height() - _properties.get_y_size());
1021 _properties.set_origin(metrics.x, metrics.y);
1023 if (metrics.x == -1 && metrics.y == -1) {
1030 metrics.width = _properties.get_x_size();
1031 metrics.height = _properties.get_y_size();
1035 SetRect(&win_rect, metrics.x, metrics.y,
1036 metrics.x + metrics.width, metrics.y + metrics.height);
1039 if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
1040 windisplay_cat.error()
1041 <<
"AdjustWindowRect failed!" << endl;
1046 metrics.x = win_rect.left;
1047 metrics.y = win_rect.top;
1049 metrics.x = CW_USEDEFAULT;
1050 metrics.y = CW_USEDEFAULT;
1052 metrics.width = win_rect.right - win_rect.left;
1053 metrics.height = win_rect.bottom - win_rect.top;
1062 bool WinGraphicsWindow::
1063 open_graphic_window() {
1064 DWORD window_style = make_style(_properties);
1067 if (_properties.has_title()) {
1069 title = encoder.
decode_text(_properties.get_title());
1072 if (!_properties.has_size()) {
1074 _properties.set_size(640, 480);
1077 WINDOW_METRICS metrics;
1079 if (!calculate_metrics(fullscreen, window_style, metrics, has_origin)){
1083 const WindowClass &wclass = register_window_class(_properties);
1084 HINSTANCE hinstance = GetModuleHandle(
nullptr);
1089 WindowHandle *window_handle = _properties.get_parent_window();
1090 if (window_handle !=
nullptr) {
1091 windisplay_cat.info()
1092 <<
"Got parent_window " << *window_handle <<
"\n";
1094 if (os_handle !=
nullptr) {
1095 windisplay_cat.info()
1096 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1098 if (os_handle->
is_of_type(NativeWindowHandle::WinHandle::get_class_type())) {
1099 NativeWindowHandle::WinHandle *win_handle = DCAST(NativeWindowHandle::WinHandle, os_handle);
1100 _hparent = win_handle->get_handle();
1101 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1103 _hparent = (HWND)int_handle->get_handle();
1107 _parent_window_handle = window_handle;
1109 _parent_window_handle =
nullptr;
1113 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(), window_style,
1114 metrics.x, metrics.y,
1117 nullptr,
nullptr, hinstance, 0);
1122 if (!fullscreen && has_origin) {
1123 x_origin = _properties.get_x_origin();
1124 y_origin = _properties.get_y_origin();
1127 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(),
1128 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ,
1130 _properties.get_x_size(), _properties.get_y_size(),
1131 _hparent,
nullptr, hinstance, 0);
1144 system_changed_properties(properties);
1149 windisplay_cat.error()
1150 <<
"CreateWindow() failed!" << endl;
1151 show_error_message();
1160 if (!do_fullscreen_enable()){
1172 bool WinGraphicsWindow::
1173 do_fullscreen_enable() {
1175 HWND hDesktopWindow = GetDesktopWindow();
1176 HDC scrnDC = GetDC(hDesktopWindow);
1177 DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
1181 ReleaseDC(hDesktopWindow, scrnDC);
1183 DWORD dwWidth = _properties.get_x_size();
1184 DWORD dwHeight = _properties.get_y_size();
1185 DWORD dwFullScreenBitDepth = cur_bitdepth;
1188 reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
1189 if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth, dm)) {
1190 windisplay_cat.error()
1191 <<
"Videocard has no supported display resolutions at specified res ("
1192 << dwWidth <<
" x " << dwHeight <<
" x " << dwFullScreenBitDepth <<
")\n";
1196 dm.dmPelsWidth = dwWidth;
1197 dm.dmPelsHeight = dwHeight;
1198 dm.dmBitsPerPel = dwFullScreenBitDepth;
1199 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1201 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1202 windisplay_cat.error()
1203 <<
"ChangeDisplaySettings failed (error code: "
1204 << chg_result <<
") for specified res: "
1205 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1206 <<
" x " << dm.dmBitsPerPel <<
", "
1207 << dm.dmDisplayFrequency <<
" Hz\n";
1211 _fullscreen_display_mode = dm;
1213 _properties.set_origin(0, 0);
1214 _properties.set_size(dwWidth, dwHeight);
1224 bool WinGraphicsWindow::
1225 do_fullscreen_disable() {
1226 int chg_result = ChangeDisplaySettings(
nullptr, 0x0);
1227 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1228 windisplay_cat.warning()
1229 <<
"ChangeDisplaySettings failed to restore Windowed mode\n";
1238 void WinGraphicsWindow::
1240 WindowProperties::ZOrder z_order = _properties.get_z_order();
1241 adjust_z_order(z_order, z_order);
1247 void WinGraphicsWindow::
1248 adjust_z_order(WindowProperties::ZOrder last_z_order,
1249 WindowProperties::ZOrder this_z_order) {
1251 bool do_change =
false;
1253 switch (this_z_order) {
1254 case WindowProperties::Z_bottom:
1255 order = HWND_BOTTOM;
1259 case WindowProperties::Z_normal:
1260 if ((last_z_order != WindowProperties::Z_normal) &&
1262 (last_z_order != WindowProperties::Z_bottom ||
1263 _properties.get_foreground())
1268 order = HWND_NOTOPMOST;
1273 case WindowProperties::Z_top:
1274 order = HWND_TOPMOST;
1279 BOOL result = SetWindowPos(_hWnd, order, 0,0,0,0,
1280 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
1282 windisplay_cat.warning()
1283 <<
"SetWindowPos failed.\n";
1293 void WinGraphicsWindow::
1294 track_mouse_leaving(HWND hwnd) {
1296 DCAST_INTO_V(winpipe, _pipe);
1298 TRACKMOUSEEVENT tme = {
1299 sizeof(TRACKMOUSEEVENT),
1306 BOOL bSucceeded = TrackMouseEvent(&tme);
1308 if (!bSucceeded && windisplay_cat.is_debug()) {
1309 windisplay_cat.debug()
1310 <<
"TrackMouseEvent failed!, LastError=" << GetLastError() << endl;
1313 _tracking_mouse_leaving =
true;
1319 bool WinGraphicsWindow::
1324 windisplay_cat.info()
1325 <<
"ClipCursor() to " << clip.left <<
"," << clip.top <<
" to "
1326 << clip.right <<
"," << clip.bottom << endl;
1328 if (!ClipCursor(&clip)) {
1329 windisplay_cat.warning()
1330 <<
"Failed to confine cursor to window.\n";
1341 void WinGraphicsWindow::
1343 if (SetFocus(_hWnd) ==
nullptr && GetLastError() != 0) {
1349 if (_parent_window_handle !=
nullptr && _window_handle !=
nullptr) {
1350 _parent_window_handle->request_keyboard_focus(_window_handle);
1353 windisplay_cat.error()
1354 <<
"SetFocus failed: " << GetLastError() <<
"\n";
1380 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
1381 if (windisplay_cat.is_spam()) {
1382 windisplay_cat.spam()
1384 <<
" window_proc(" << (
void *)
this <<
", " << hwnd <<
", "
1385 << msg <<
", " << wparam <<
", " << lparam <<
")\n";
1391 if (!_tracking_mouse_leaving) {
1393 track_mouse_leaving(hwnd);
1395 set_cursor_in_window();
1396 if(handle_mouse_motion(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))))
1401 handle_raw_input((HRAWINPUT)lparam);
1405 _tracking_mouse_leaving =
false;
1406 handle_mouse_exit();
1407 set_cursor_out_of_window();
1412 track_mouse_leaving(hwnd);
1413 ClearToBlack(hwnd, _properties);
1416 GetCursorPos(&cpos);
1417 ScreenToClient(hwnd, &cpos);
1419 GetClientRect(hwnd, &clientRect);
1420 if (PtInRect(&clientRect,cpos)) {
1421 set_cursor_in_window();
1423 set_cursor_out_of_window();
1456 if (!close_request_event.empty()) {
1459 throw_event(close_request_event);
1467 system_changed_properties(properties);
1474 case WM_CHILDACTIVATE:
1475 if (windisplay_cat.is_debug()) {
1476 windisplay_cat.debug()
1477 <<
"WM_CHILDACTIVATE: " << hwnd <<
"\n";
1482 if (windisplay_cat.is_debug()) {
1483 windisplay_cat.debug()
1484 <<
"WM_ACTIVATE: " << hwnd <<
", " << wparam <<
", " << lparam <<
"\n";
1487 if ((wparam & 0xffff) != WA_INACTIVE)
1495 ChangeDisplaySettings(&_fullscreen_display_mode, CDS_FULLSCREEN);
1496 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1497 const DEVMODE &dm = _fullscreen_display_mode;
1498 windisplay_cat.error()
1499 <<
"restore ChangeDisplaySettings failed (error code: "
1500 << chg_result <<
") for specified res: "
1501 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1502 <<
" x " << dm.dmBitsPerPel <<
", "
1503 << dm.dmDisplayFrequency <<
" Hz\n";
1507 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
1508 fullscreen_restored(properties);
1512 if (_properties.has_mouse_mode() &&
1513 _properties.get_mouse_mode() == WindowProperties::M_confined) {
1514 if (!confine_cursor()) {
1531 ShowWindow(_hWnd, SW_MINIMIZE);
1533 do_fullscreen_disable();
1534 fullscreen_minimized(properties);
1539 system_changed_properties(properties);
1545 if (windisplay_cat.is_debug()) {
1546 windisplay_cat.debug()
1547 <<
"WM_SIZE: " << hwnd <<
", " << wparam <<
"\n";
1551 case WM_EXITSIZEMOVE:
1552 if (windisplay_cat.is_debug()) {
1553 windisplay_cat.debug()
1554 <<
"WM_EXITSIZEMOVE: " << hwnd <<
", " << wparam <<
"\n";
1558 if (_properties.has_mouse_mode() &&
1559 _properties.get_mouse_mode() == WindowProperties::M_confined) {
1564 case WM_WINDOWPOSCHANGED:
1565 if (windisplay_cat.is_debug()) {
1566 windisplay_cat.debug()
1567 <<
"WM_WINDOWPOSCHANGED: " << hwnd <<
", " << wparam <<
"\n";
1569 if (_hWnd !=
nullptr) {
1579 if (GetUpdateRect(_hWnd,
nullptr,
false)) {
1580 if (windisplay_cat.is_spam()) {
1581 windisplay_cat.spam()
1582 <<
"Got update regions: " <<
this <<
"\n";
1584 _got_expose_event =
true;
1588 case WM_LBUTTONDOWN:
1589 if (_lost_keypresses) {
1590 resend_lost_keypresses();
1600 case WM_MBUTTONDOWN:
1601 if (_lost_keypresses) {
1602 resend_lost_keypresses();
1611 case WM_RBUTTONDOWN:
1612 if (_lost_keypresses) {
1613 resend_lost_keypresses();
1622 case WM_XBUTTONDOWN:
1624 if (_lost_keypresses) {
1625 resend_lost_keypresses();
1628 int whichButton = GET_XBUTTON_WPARAM(wparam);
1630 if (whichButton == XBUTTON1) {
1632 }
else if (whichButton == XBUTTON2) {
1639 if (_lost_keypresses) {
1640 resend_lost_keypresses();
1647 if (_lost_keypresses) {
1648 resend_lost_keypresses();
1655 if (_lost_keypresses) {
1656 resend_lost_keypresses();
1664 if (_lost_keypresses) {
1665 resend_lost_keypresses();
1668 int whichButton = GET_XBUTTON_WPARAM(wparam);
1669 if (whichButton == XBUTTON1) {
1671 }
else if (whichButton == XBUTTON2) {
1679 int delta = GET_WHEEL_DELTA_WPARAM(wparam);
1682 GetCursorPos(&point);
1683 ScreenToClient(hwnd, &point);
1684 double time = get_message_time();
1690 delta -= WHEEL_DELTA;
1696 delta += WHEEL_DELTA;
1704 case WM_IME_SETCONTEXT:
1708 windisplay_cat.debug() <<
"hwnd = " << hwnd <<
" and GetFocus = " << GetFocus() << endl;
1709 _ime_hWnd = ImmGetDefaultIMEWnd(hwnd);
1710 if (::SendMessage(_ime_hWnd, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0))
1712 windisplay_cat.debug() <<
"SendMessage failed for " << _ime_hWnd << endl;
1714 windisplay_cat.debug() <<
"SendMessage Succeeded for " << _ime_hWnd << endl;
1716 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1717 lparam &= ~ISC_SHOWUIALL;
1718 if (ImmIsUIMessage(_ime_hWnd, msg, wparam, lparam))
1719 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1725 if (wparam == IMN_SETOPENSTATUS) {
1726 HIMC hIMC = ImmGetContext(hwnd);
1727 nassertr(hIMC != 0, 0);
1728 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
1730 _ime_active =
false;
1734 COMPOSITIONFORM comf;
1736 ImmGetCompositionWindow(hIMC, &comf);
1737 ImmGetCandidateWindow(hIMC, 0, &canf);
1738 windisplay_cat.debug() <<
1739 "comf style " << comf.dwStyle <<
1740 " comf point: x" << comf.ptCurrentPos.x <<
",y " << comf.ptCurrentPos.y <<
1741 " comf rect: l " << comf.rcArea.left <<
",t " << comf.rcArea.top <<
",r " <<
1742 comf.rcArea.right <<
",b " << comf.rcArea.bottom << endl;
1743 windisplay_cat.debug() <<
1744 "canf style " << canf.dwStyle <<
1745 " canf point: x" << canf.ptCurrentPos.x <<
",y " << canf.ptCurrentPos.y <<
1746 " canf rect: l " << canf.rcArea.left <<
",t " << canf.rcArea.top <<
",r " <<
1747 canf.rcArea.right <<
",b " << canf.rcArea.bottom << endl;
1748 comf.dwStyle = CFS_POINT;
1749 comf.ptCurrentPos.x = 2000;
1750 comf.ptCurrentPos.y = 2000;
1752 canf.dwStyle = CFS_EXCLUDE;
1754 canf.ptCurrentPos.x = 0;
1755 canf.ptCurrentPos.y = 0;
1756 canf.rcArea.left = 0;
1757 canf.rcArea.top = 0;
1758 canf.rcArea.right = 640;
1759 canf.rcArea.bottom = 480;
1762 comf.rcArea.left = 200;
1763 comf.rcArea.top = 200;
1764 comf.rcArea.right = 0;
1765 comf.rcArea.bottom = 0;
1768 if (ImmSetCompositionWindow(hIMC, &comf))
1769 windisplay_cat.debug() <<
"set composition form: success\n";
1770 for (
int i=0; i<3; ++i) {
1771 if (ImmSetCandidateWindow(hIMC, &canf))
1772 windisplay_cat.debug() <<
"set candidate form: success\n";
1777 ImmReleaseContext(hwnd, hIMC);
1781 case WM_IME_STARTCOMPOSITION:
1782 support_overlay_window(
true);
1786 case WM_IME_ENDCOMPOSITION:
1787 support_overlay_window(
false);
1788 _ime_active =
false;
1797 case WM_IME_COMPOSITION:
1809 HIMC hIMC = ImmGetContext(hwnd);
1810 nassertr(hIMC != 0, 0);
1812 DWORD result_size = 0;
1813 static const int ime_buffer_size = 256;
1814 static const int ime_buffer_size_bytes = ime_buffer_size /
sizeof(wchar_t);
1815 wchar_t ime_buffer[ime_buffer_size];
1816 size_t cursor_pos, delta_start;
1818 if (lparam & GCS_RESULTSTR) {
1819 result_size = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR,
1820 ime_buffer, ime_buffer_size_bytes);
1821 size_t num_chars = result_size /
sizeof(wchar_t);
1822 for (
size_t i = 0; i < num_chars; ++i) {
1827 if (lparam & GCS_COMPSTR) {
1828 result_size = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS,
nullptr, 0);
1829 cursor_pos = result_size & 0xffff;
1831 result_size = ImmGetCompositionStringW(hIMC, GCS_DELTASTART,
nullptr, 0);
1832 delta_start = result_size & 0xffff;
1833 result_size = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, ime_buffer, ime_buffer_size);
1834 size_t num_chars = result_size /
sizeof(wchar_t);
1836 _input->
candidate(wstring(ime_buffer, num_chars),
1837 std::min(cursor_pos, delta_start),
1838 std::max(cursor_pos, delta_start),
1841 ImmReleaseContext(hwnd, hIMC);
1862 if (_lost_keypresses) {
1863 resend_lost_keypresses();
1865 if (windisplay_cat.is_debug()) {
1866 windisplay_cat.debug()
1867 <<
"syskeydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1873 GetCursorPos(&point);
1874 ScreenToClient(hwnd, &point);
1875 handle_keypress(lookup_key(wparam), point.x, point.y,
1876 get_message_time());
1878 if ((lparam & 0x40000000) == 0) {
1879 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1890 if (wparam == VK_MENU) {
1891 if ((GetKeyState(VK_LMENU) & 0x8000) != 0 && ! _lalt_down) {
1892 handle_keypress(KeyboardButton::lalt(), point.x, point.y,
1893 get_message_time());
1896 if ((GetKeyState(VK_RMENU) & 0x8000) != 0 && ! _ralt_down) {
1897 handle_keypress(KeyboardButton::ralt(), point.x, point.y,
1898 get_message_time());
1902 if (wparam == VK_F10) {
1911 if (wparam == SC_KEYMENU) {
1923 if (_lost_keypresses) {
1924 resend_lost_keypresses();
1926 if (windisplay_cat.is_debug()) {
1927 windisplay_cat.debug()
1928 <<
"keydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1933 if ((lparam & 0x40000000) == 0) {
1935 GetCursorPos(&point);
1936 ScreenToClient(hwnd, &point);
1937 handle_keypress(lookup_key(wparam), point.x, point.y,
1938 get_message_time());
1939 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1945 if (wparam == VK_SHIFT) {
1946 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0 && ! _lshift_down) {
1947 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
1948 get_message_time());
1949 _lshift_down =
true;
1951 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0 && ! _rshift_down) {
1952 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
1953 get_message_time());
1954 _rshift_down =
true;
1956 }
else if(wparam == VK_CONTROL) {
1957 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0 && ! _lcontrol_down) {
1958 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
1959 get_message_time());
1960 _lcontrol_down =
true;
1962 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0 && ! _rcontrol_down) {
1963 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
1964 get_message_time());
1965 _rcontrol_down =
true;
1971 if ((wparam==
'V') && (GetKeyState(VK_CONTROL) < 0) &&
1972 !_input_devices.empty() && paste_emit_keystrokes) {
1976 if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(
nullptr)) {
1978 hglb = GetClipboardData(CF_TEXT);
1979 if (hglb!=
nullptr) {
1980 lptstr = (
char *) GlobalLock(hglb);
1981 if (lptstr !=
nullptr) {
1983 for (pChar = lptstr; *pChar; pChar++) {
1996 GetCursorPos(&point);
1997 ScreenToClient(hwnd, &point);
1998 handle_keypress(lookup_key(wparam), point.x, point.y,
1999 get_message_time());
2012 if (wparam == VK_SHIFT) {
2013 if (((GetKeyState(VK_LSHIFT) & 0x8000) != 0) && ! _lshift_down ) {
2014 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
2015 get_message_time());
2016 _lshift_down =
true;
2017 }
else if (((GetKeyState(VK_RSHIFT) & 0x8000) != 0) && ! _rshift_down ) {
2018 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
2019 get_message_time());
2020 _rshift_down =
true;
2022 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0) {
2023 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
2024 get_message_time());
2026 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0) {
2027 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
2028 get_message_time());
2031 }
else if(wparam == VK_CONTROL) {
2032 if (((GetKeyState(VK_LCONTROL) & 0x8000) != 0) && ! _lcontrol_down ) {
2033 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2034 get_message_time());
2035 _lcontrol_down =
true;
2036 }
else if (((GetKeyState(VK_RCONTROL) & 0x8000) != 0) && ! _rcontrol_down ) {
2037 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2038 get_message_time());
2039 _rcontrol_down =
true;
2041 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0) {
2042 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2043 get_message_time());
2045 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0) {
2046 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2047 get_message_time());
2056 if (_lost_keypresses) {
2057 resend_lost_keypresses();
2059 if (windisplay_cat.is_debug()) {
2060 windisplay_cat.debug()
2061 <<
"keyup: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
2063 handle_keyrelease(lookup_key(wparam), get_message_time());
2064 handle_raw_keyrelease(lookup_raw_key(lparam), get_message_time());
2069 if (wparam == VK_SHIFT) {
2070 if ((GetKeyState(VK_LSHIFT) & 0x8000) == 0 && _lshift_down) {
2071 handle_keyrelease(KeyboardButton::lshift(), get_message_time());
2072 _lshift_down =
false;
2074 if ((GetKeyState(VK_RSHIFT) & 0x8000) == 0 && _rshift_down) {
2075 handle_keyrelease(KeyboardButton::rshift(), get_message_time());
2076 _rshift_down =
false;
2078 }
else if(wparam == VK_CONTROL) {
2079 if ((GetKeyState(VK_LCONTROL) & 0x8000) == 0 && _lcontrol_down) {
2080 handle_keyrelease(KeyboardButton::lcontrol(), get_message_time());
2081 _lcontrol_down =
false;
2083 if ((GetKeyState(VK_RCONTROL) & 0x8000) == 0 && _rcontrol_down) {
2084 handle_keyrelease(KeyboardButton::rcontrol(), get_message_time());
2085 _rcontrol_down =
false;
2087 }
else if(wparam == VK_MENU) {
2088 if ((GetKeyState(VK_LMENU) & 0x8000) == 0 && _lalt_down) {
2089 handle_keyrelease(KeyboardButton::lalt(), get_message_time());
2092 if ((GetKeyState(VK_RMENU) & 0x8000) == 0 && _ralt_down) {
2093 handle_keyrelease(KeyboardButton::ralt(), get_message_time());
2100 if (windisplay_cat.is_debug()) {
2101 windisplay_cat.debug()
2107 system_changed_properties(properties);
2129 if (windisplay_cat.is_debug()) {
2130 windisplay_cat.debug()
2134 if (_lost_keypresses) {
2135 resend_lost_keypresses();
2139 system_changed_properties(properties);
2143 if (windisplay_cat.is_debug()) {
2144 windisplay_cat.debug()
2148 system_changed_properties(properties);
2152 if (windisplay_cat.is_debug()) {
2153 windisplay_cat.debug()
2157 system_changed_properties(properties);
2163 if (windisplay_cat.is_debug()) {
2164 windisplay_cat.debug() <<
"DPI changed to " << LOWORD(wparam);
2166 if (LOWORD(wparam) != HIWORD(wparam)) {
2167 windisplay_cat.debug(
false) <<
"x" << HIWORD(wparam) <<
"\n";
2169 windisplay_cat.debug(
false) <<
"\n";
2174 if (!_properties.get_fixed_size() && dpi_window_resize) {
2175 RECT &rect = *(LPRECT)lparam;
2176 SetWindowPos(_hWnd, HWND_TOP, rect.left, rect.top,
2177 rect.right - rect.left, rect.bottom - rect.top,
2178 SWP_NOZORDER | SWP_NOACTIVATE);
2183 _num_touches = LOWORD(wparam);
2184 if (_num_touches > MAX_TOUCHES) {
2185 _num_touches = MAX_TOUCHES;
2187 if (pGetTouchInputInfo != 0) {
2188 pGetTouchInputInfo((HTOUCHINPUT)lparam, _num_touches, _touches,
sizeof(TOUCHINPUT));
2189 pCloseTouchInputHandle((HTOUCHINPUT)lparam);
2195 for ( WinProcClasses::iterator it=_window_proc_classes.begin() ; it != _window_proc_classes.end(); it++ ){
2196 (*it)->wnd_proc(
this, hwnd, msg, wparam, lparam);
2199 return DefWindowProcW(hwnd, msg, wparam, lparam);
2210 WindowHandles::const_iterator wi;
2211 wi = _window_handles.find(hwnd);
2212 if (wi != _window_handles.end()) {
2214 return (*wi).second->window_proc(hwnd, msg, wparam, lparam);
2218 if (_creating_window !=
nullptr) {
2219 return _creating_window->
window_proc(hwnd, msg, wparam, lparam);
2224 return DefWindowProcW(hwnd, msg, wparam, lparam);
2230 void WinGraphicsWindow::
2234 if (!GetMessage(&msg,
nullptr, 0, 0)) {
2241 TranslateMessage(&msg);
2243 DispatchMessage(&msg);
2251 void WinGraphicsWindow::
2252 resend_lost_keypresses() {
2253 nassertv(_lost_keypresses);
2258 _lost_keypresses =
false;
2265 void WinGraphicsWindow::
2267 bool hide_cursor =
false;
2268 if (to_window ==
nullptr) {
2271 if (_got_saved_params) {
2272 SystemParametersInfo(SPI_SETMOUSETRAILS, _saved_mouse_trails,
2274 SystemParametersInfo(SPI_SETCURSORSHADOW, 0,
2275 _saved_cursor_shadow ? (PVOID)1 :
nullptr, 0);
2276 SystemParametersInfo(SPI_SETMOUSEVANISH, 0,
2277 _saved_mouse_vanish ? (PVOID)1 :
nullptr, 0);
2278 _got_saved_params =
false;
2290 if (!_got_saved_params) {
2291 SystemParametersInfo(SPI_GETMOUSETRAILS, 0,
2292 &_saved_mouse_trails, 0);
2293 SystemParametersInfo(SPI_GETCURSORSHADOW, 0,
2294 &_saved_cursor_shadow, 0);
2295 SystemParametersInfo(SPI_GETMOUSEVANISH, 0,
2296 &_saved_mouse_vanish, 0);
2297 _got_saved_params =
true;
2299 SystemParametersInfo(SPI_SETMOUSETRAILS, 0, (PVOID)0, 0);
2300 SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (PVOID)
false, 0);
2301 SystemParametersInfo(SPI_SETMOUSEVANISH, 0, (PVOID)
false, 0);
2304 SetCursor(to_window->_cursor);
2307 hide_or_show_cursor(hide_cursor);
2309 _cursor_window = to_window;
2317 void WinGraphicsWindow::
2318 hide_or_show_cursor(
bool hide_cursor) {
2320 if (!_cursor_hidden) {
2322 _cursor_hidden =
true;
2325 if (_cursor_hidden) {
2327 _cursor_hidden =
false;
2333 #define MIN_REFRESH_RATE 60
2336 #define ACCEPTABLE_REFRESH_RATE(RATE) ((RATE >= MIN_REFRESH_RATE) || (RATE==0) || (RATE==1))
2342 bool WinGraphicsWindow::
2343 find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
2348 ZeroMemory(&cur_dm,
sizeof(cur_dm));
2349 cur_dm.dmSize =
sizeof(cur_dm);
2350 EnumDisplaySettings(
nullptr, ENUM_CURRENT_SETTINGS, &cur_dm);
2353 int saved_modenum = -1;
2356 ZeroMemory(&dm,
sizeof(dm));
2357 dm.dmSize =
sizeof(dm);
2359 if (!EnumDisplaySettings(
nullptr, modenum, &dm)) {
2363 if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
2364 (dm.dmBitsPerPel == bpp)) {
2367 if (dm.dmDisplayFrequency == cur_dm.dmDisplayFrequency) {
2369 }
else if (saved_modenum == -1) {
2370 saved_modenum = modenum;
2378 if (saved_modenum != -1) {
2379 ZeroMemory(&dm,
sizeof(dm));
2380 dm.dmSize =
sizeof(dm);
2382 if (EnumDisplaySettings(
nullptr, saved_modenum, &dm)) {
2394 void WinGraphicsWindow::
2395 show_error_message(DWORD message_id) {
2396 LPTSTR message_buffer;
2398 if (message_id == 0) {
2399 message_id = GetLastError();
2402 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2403 nullptr, message_id,
2404 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2405 (LPTSTR)&message_buffer,
2407 MessageBox(GetDesktopWindow(), message_buffer, _T(errorbox_title), MB_OK);
2408 windisplay_cat.fatal() <<
"System error msg: " << message_buffer << endl;
2409 LocalFree(message_buffer);
2415 void WinGraphicsWindow::
2416 handle_keypress(
ButtonHandle key,
int x,
int y,
double time) {
2418 if (key != ButtonHandle::none()) {
2427 void WinGraphicsWindow::
2429 if (key != ButtonHandle::none()) {
2437 void WinGraphicsWindow::
2439 if (key != ButtonHandle::none()) {
2447 void WinGraphicsWindow::
2449 if (key != ButtonHandle::none()) {
2457 void WinGraphicsWindow::
2459 if (key != ButtonHandle::none()) {
2469 lookup_key(WPARAM wparam)
const {
2474 case VK_BACK:
return KeyboardButton::backspace();
2475 case VK_DELETE:
return KeyboardButton::del();
2476 case VK_ESCAPE:
return KeyboardButton::escape();
2477 case VK_SPACE:
return KeyboardButton::space();
2478 case VK_UP:
return KeyboardButton::up();
2479 case VK_DOWN:
return KeyboardButton::down();
2480 case VK_LEFT:
return KeyboardButton::left();
2481 case VK_RIGHT:
return KeyboardButton::right();
2488 case VK_TAB:
return KeyboardButton::tab();
2489 case VK_PRIOR:
return KeyboardButton::page_up();
2490 case VK_NEXT:
return KeyboardButton::page_down();
2491 case VK_HOME:
return KeyboardButton::home();
2492 case VK_END:
return KeyboardButton::end();
2493 case VK_F1:
return KeyboardButton::f1();
2494 case VK_F2:
return KeyboardButton::f2();
2495 case VK_F3:
return KeyboardButton::f3();
2496 case VK_F4:
return KeyboardButton::f4();
2497 case VK_F5:
return KeyboardButton::f5();
2498 case VK_F6:
return KeyboardButton::f6();
2499 case VK_F7:
return KeyboardButton::f7();
2500 case VK_F8:
return KeyboardButton::f8();
2501 case VK_F9:
return KeyboardButton::f9();
2502 case VK_F10:
return KeyboardButton::f10();
2503 case VK_F11:
return KeyboardButton::f11();
2504 case VK_F12:
return KeyboardButton::f12();
2505 case VK_INSERT:
return KeyboardButton::insert();
2506 case VK_CAPITAL:
return KeyboardButton::caps_lock();
2507 case VK_NUMLOCK:
return KeyboardButton::num_lock();
2508 case VK_SCROLL:
return KeyboardButton::scroll_lock();
2509 case VK_PAUSE:
return KeyboardButton::pause();
2510 case VK_SNAPSHOT:
return KeyboardButton::print_screen();
2512 case VK_SHIFT:
return KeyboardButton::shift();
2513 case VK_LSHIFT:
return KeyboardButton::lshift();
2514 case VK_RSHIFT:
return KeyboardButton::rshift();
2516 case VK_CONTROL:
return KeyboardButton::control();
2517 case VK_LCONTROL:
return KeyboardButton::lcontrol();
2518 case VK_RCONTROL:
return KeyboardButton::rcontrol();
2520 case VK_MENU:
return KeyboardButton::alt();
2521 case VK_LMENU:
return KeyboardButton::lalt();
2522 case VK_RMENU:
return KeyboardButton::ralt();
2525 int key = MapVirtualKey(wparam, 2);
2526 if (isascii(key) && key != 0) {
2541 return ButtonHandle::none();
2549 lookup_raw_key(LPARAM lparam)
const {
2550 unsigned char vsc = (lparam & 0xff0000) >> 16;
2552 if (lparam & 0x1000000) {
2555 case 28:
return KeyboardButton::enter();
2556 case 29:
return KeyboardButton::rcontrol();
2558 case 55:
return KeyboardButton::print_screen();
2559 case 56:
return KeyboardButton::ralt();
2560 case 69:
return KeyboardButton::num_lock();
2561 case 71:
return KeyboardButton::home();
2562 case 72:
return KeyboardButton::up();
2563 case 73:
return KeyboardButton::page_up();
2564 case 75:
return KeyboardButton::left();
2565 case 77:
return KeyboardButton::right();
2566 case 79:
return KeyboardButton::end();
2567 case 80:
return KeyboardButton::down();
2568 case 81:
return KeyboardButton::page_down();
2569 case 82:
return KeyboardButton::insert();
2570 case 83:
return KeyboardButton::del();
2571 case 91:
return KeyboardButton::lmeta();
2572 case 92:
return KeyboardButton::rmeta();
2573 case 93:
return KeyboardButton::menu();
2579 ButtonHandle::none(),
2580 KeyboardButton::escape(),
2593 KeyboardButton::backspace(),
2594 KeyboardButton::tab(),
2607 KeyboardButton::enter(),
2608 KeyboardButton::lcontrol(),
2621 KeyboardButton::lshift(),
2633 KeyboardButton::rshift(),
2635 KeyboardButton::lalt(),
2636 KeyboardButton::space(),
2637 KeyboardButton::caps_lock(),
2638 KeyboardButton::f1(),
2639 KeyboardButton::f2(),
2640 KeyboardButton::f3(),
2641 KeyboardButton::f4(),
2642 KeyboardButton::f5(),
2643 KeyboardButton::f6(),
2644 KeyboardButton::f7(),
2645 KeyboardButton::f8(),
2646 KeyboardButton::f9(),
2647 KeyboardButton::f10(),
2648 KeyboardButton::pause(),
2649 KeyboardButton::scroll_lock(),
2664 return raw_map[vsc];
2669 case 87:
return KeyboardButton::f11();
2670 case 88:
return KeyboardButton::f12();
2671 default:
return ButtonHandle::none();
2683 get_keyboard_map()
const {
2688 unsigned short ex_vsc[] = {0x57, 0x58,
2689 0x011c, 0x011d, 0x0135, 0x0137, 0x0138, 0x0145, 0x0147, 0x0148, 0x0149, 0x014b, 0x014d, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x015b, 0x015c, 0x015d};
2691 for (
int k = 1; k < 84 + 17; ++k) {
2693 vsc = ex_vsc[k - 84];
2698 UINT lparam = vsc << 16;
2700 if (raw_button == ButtonHandle::none()) {
2706 button = KeyboardButton::pause();
2708 }
else if (vsc >= 0x47 && vsc <= 0x53) {
2710 button = raw_button;
2722 UINT vk = MapVirtualKeyA(vsc, MAPVK_VSC_TO_VK_EX);
2723 button = lookup_key(vk);
2729 int len = GetKeyNameTextW(lparam, text, 256);
2741 void WinGraphicsWindow::
2742 handle_raw_input(HRAWINPUT hraw) {
2749 if (GetRawInputData(hraw, RID_INPUT,
nullptr, &dwSize,
sizeof(RAWINPUTHEADER)) == -1) {
2753 lpb = (LPBYTE)alloca(
sizeof(LPBYTE) * dwSize);
2754 if (lpb ==
nullptr) {
2758 if (GetRawInputData(hraw, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize) {
2762 RAWINPUT *raw = (RAWINPUT *)lpb;
2763 if (raw->header.hDevice == 0) {
2767 for (
size_t i = 1; i < _input_devices.size(); ++i) {
2768 if (_input_device_handle[i] == raw->header.hDevice) {
2772 int adjx = raw->data.mouse.lLastX;
2773 int adjy = raw->data.mouse.lLastY;
2775 if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
2776 input->set_pointer_in_window(adjx, adjy);
2778 input->pointer_moved(adjx, adjy);
2781 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {
2784 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) {
2787 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) {
2790 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) {
2793 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) {
2796 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) {
2799 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
2802 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
2805 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
2808 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
2818 bool WinGraphicsWindow::
2819 handle_mouse_motion(
int x,
int y) {
2827 void WinGraphicsWindow::
2828 handle_mouse_exit() {
2837 HICON WinGraphicsWindow::
2838 get_icon(
const Filename &filename) {
2840 IconFilenames::iterator fi = _icon_filenames.find(filename);
2841 if (fi != _icon_filenames.end()) {
2842 return (HICON)((*fi).second);
2856 windisplay_cat.warning()
2857 <<
"Could not find icon filename " << filename <<
"\n";
2861 fi = _icon_filenames.find(resolved);
2862 if (fi != _icon_filenames.end()) {
2863 _icon_filenames[filename] = (*fi).second;
2864 return (HICON)((*fi).second);
2869 HANDLE h = LoadImage(
nullptr, os.c_str(),
2870 IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2872 windisplay_cat.warning()
2873 <<
"windows icon filename '" << os <<
"' could not be loaded!!\n";
2876 _icon_filenames[filename] = h;
2877 _icon_filenames[resolved] = h;
2885 HCURSOR WinGraphicsWindow::
2886 get_cursor(
const Filename &filename) {
2888 if (filename.empty()) {
2893 IconFilenames::iterator fi = _cursor_filenames.find(filename);
2894 if (fi != _cursor_filenames.end()) {
2895 return (HCURSOR)((*fi).second);
2905 windisplay_cat.warning()
2906 <<
"Could not find cursor filename " << filename <<
"\n";
2909 fi = _cursor_filenames.find(resolved);
2910 if (fi != _cursor_filenames.end()) {
2911 _cursor_filenames[filename] = (*fi).second;
2912 return (HCURSOR)((*fi).second);
2917 HANDLE h = LoadImage(
nullptr, os.c_str(),
2918 IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
2920 windisplay_cat.warning()
2921 <<
"windows cursor filename '" << os <<
"' could not be loaded!!\n";
2922 show_error_message();
2925 _cursor_filenames[filename] = h;
2926 _cursor_filenames[resolved] = h;
2930 static HCURSOR get_cursor(
const Filename &filename);
2936 const WinGraphicsWindow::WindowClass &WinGraphicsWindow::
2938 WindowClass wcreg(props);
2939 std::wostringstream wclass_name;
2940 wclass_name << L
"WinGraphicsWindow" << _window_class_index;
2941 wcreg._name = wclass_name.str();
2943 std::pair<WindowClasses::iterator, bool> found = _window_classes.insert(wcreg);
2944 const WindowClass &wclass = (*found.first);
2946 if (!found.second) {
2952 _window_class_index++;
2956 HINSTANCE instance = GetModuleHandle(
nullptr);
2959 ZeroMemory(&wc,
sizeof(wc));
2960 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
2962 wc.hInstance = instance;
2964 wc.hIcon = wclass._icon;
2966 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
2967 wc.lpszMenuName =
nullptr;
2968 wc.lpszClassName = wclass._name.c_str();
2970 if (!RegisterClassW(&wc)) {
2971 windisplay_cat.error()
2972 <<
"could not register window class " << wclass._name <<
"!" << endl;
2982 WinGraphicsWindow::WinWindowHandle::
2994 void WinGraphicsWindow::WinWindowHandle::
3003 void WinGraphicsWindow::WinWindowHandle::
3004 receive_windows_message(
unsigned int msg,
int wparam,
int lparam) {
3005 if (_window !=
nullptr) {
3012 void PrintErrorMessage(DWORD msgID) {
3013 LPTSTR pMessageBuffer;
3015 if (msgID==PRINT_LAST_ERROR)
3016 msgID=GetLastError();
3018 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
3020 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3021 (LPTSTR) &pMessageBuffer,
3023 MessageBox(GetDesktopWindow(),pMessageBuffer,_T(errorbox_title),MB_OK);
3024 windisplay_cat.fatal() <<
"System error msg: " << pMessageBuffer << endl;
3025 LocalFree( pMessageBuffer );
3031 if (windisplay_cat.is_debug()) {
3032 windisplay_cat.debug()
3033 <<
"Skipping ClearToBlack, no origin specified yet.\n";
3038 if (windisplay_cat.is_debug()) {
3039 windisplay_cat.debug()
3040 <<
"ClearToBlack(" << hWnd <<
", " << props <<
")\n";
3043 HDC hDC=GetDC(hWnd);
3049 FillRect(hDC,&clrRect,(HBRUSH)GetStockObject(BLACK_BRUSH));
3050 ReleaseDC(hWnd,hDC);
3059 GetClientRect(hwnd, view_rect);
3062 ul.x = view_rect->left;
3063 ul.y = view_rect->top;
3064 lr.x = view_rect->right;
3065 lr.y = view_rect->bottom;
3067 ClientToScreen(hwnd, &ul);
3068 ClientToScreen(hwnd, &lr);
3070 view_rect->left = ul.x;
3071 view_rect->top = ul.y;
3072 view_rect->right = lr.x;
3073 view_rect->bottom = lr.y;
3082 nassertv(wnd_proc !=
nullptr);
3091 nassertv(wnd_proc !=
nullptr);
3100 _window_proc_classes.clear();
3117 return callbackData->get_msg() == WM_TOUCH;
3126 return _num_touches;
3135 nassertr(index >= 0 && index < MAX_TOUCHES,
TouchInfo());
3137 TOUCHINPUT ti = _touches[index];
3139 point.x = TOUCH_COORD_TO_PIXEL(ti.x);
3140 point.y = TOUCH_COORD_TO_PIXEL(ti.y);
3141 ScreenToClient(_hWnd, &point);
3146 ret.set_id(ti.dwID);
3147 ret.set_flags(ti.dwFlags);