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";
259 while (PeekMessage(&msg,
nullptr, 0, 0, PM_NOREMOVE)) {
299 LPoint2i top_left = _properties.get_origin();
300 LPoint2i bottom_right = top_left + _properties.get_size();
302 DWORD window_style = make_style(_properties);
303 SetWindowLong(_hWnd, GWL_STYLE, window_style);
307 SetRect(&view_rect, top_left[0], top_left[1],
308 bottom_right[0], bottom_right[1]);
310 GetWindowInfo(_hWnd, &wi);
311 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
314 SetWindowPos(_hWnd, HWND_NOTOPMOST, view_rect.left, view_rect.top,
315 view_rect.right - view_rect.left,
316 view_rect.bottom - view_rect.top,
317 SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED |
318 SWP_NOSENDCHANGING | SWP_SHOWWINDOW);
322 std::string title = properties.
get_title();
323 _properties.set_title(title);
326 SetWindowTextW(_hWnd, title_w.c_str());
333 ::SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon);
334 ::SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon);
343 _properties.set_cursor_hidden(hide_cursor);
344 if (_cursor_window ==
this) {
345 hide_or_show_cursor(hide_cursor);
353 _properties.set_cursor_filename(filename);
355 _cursor = get_cursor(filename);
357 _cursor = LoadCursor(
nullptr, IDC_ARROW);
360 if (_cursor_window ==
this) {
368 WindowProperties::ZOrder last_z_order = _properties.get_z_order();
370 adjust_z_order(last_z_order, properties.
get_z_order());
376 if (!SetActiveWindow(_hWnd)) {
377 windisplay_cat.warning()
378 <<
"SetForegroundWindow() failed!\n";
380 _properties.set_foreground(
true);
387 if (_properties.get_minimized() != properties.
get_minimized()) {
389 ShowWindow(_hWnd, SW_MINIMIZE);
391 ShowWindow(_hWnd, SW_RESTORE);
401 if (do_fullscreen_switch()){
402 _properties.set_fullscreen(
true);
405 windisplay_cat.warning()
406 <<
"Switching to fullscreen mode failed!\n";
409 if (do_windowed_switch()){
410 _properties.set_fullscreen(
false);
413 windisplay_cat.warning()
414 <<
"Switching to windowed mode failed!\n";
419 if (properties.has_mouse_mode()) {
420 if (properties.
get_mouse_mode() != _properties.get_mouse_mode()) {
422 case WindowProperties::M_absolute:
423 case WindowProperties::M_relative:
425 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
427 windisplay_cat.info() <<
"Unconfining cursor from window\n";
429 _properties.set_mouse_mode(WindowProperties::M_absolute);
432 case WindowProperties::M_confined:
436 if (!GetWindowRect(_hWnd, &clip)) {
437 windisplay_cat.warning()
438 <<
"GetWindowRect() failed in set_properties_now. Cannot confine cursor.\n";
440 windisplay_cat.info()
441 <<
"ClipCursor() to " << clip.left <<
"," << clip.top <<
" to " 442 << clip.right <<
"," << clip.bottom << endl;
444 GetClipCursor(&_mouse_unconfined_cliprect);
445 if (!ClipCursor(&clip)) {
446 windisplay_cat.warning()
447 <<
"ClipCursor() failed in set_properties_now. Ignoring.\n";
449 _properties.set_mouse_mode(WindowProperties::M_confined);
450 windisplay_cat.info() <<
"Confining cursor to window\n";
466 void WinGraphicsWindow::
468 GraphicsWindow::trigger_flip();
470 if (!get_unexposed_draw()) {
474 InvalidateRect(_hWnd,
nullptr, FALSE);
475 _got_expose_event =
false;
477 if (windisplay_cat.is_spam()) {
478 windisplay_cat.spam()
479 <<
"InvalidateRect: " <<
this <<
"\n";
487 void WinGraphicsWindow::
489 set_cursor_out_of_window();
490 DestroyWindow(_hWnd);
494 do_fullscreen_disable();
498 _window_handles.erase(_hWnd);
501 GraphicsWindow::close_window();
508 bool WinGraphicsWindow::
510 if (_properties.has_cursor_filename()) {
511 _cursor = get_cursor(_properties.get_cursor_filename());
514 _cursor = LoadCursor(
nullptr, IDC_ARROW);
516 bool want_foreground = (!_properties.has_foreground() || _properties.get_foreground());
517 bool want_minimized = (_properties.has_minimized() && _properties.get_minimized()) && !want_foreground;
519 HWND old_foreground_window = GetForegroundWindow();
524 _creating_window =
this;
525 bool opened = open_graphic_window();
526 _creating_window =
nullptr;
534 _window_handles.insert(WindowHandles::value_type(_hWnd,
this));
537 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0,
538 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
541 if (want_minimized) {
542 ShowWindow(_hWnd, SW_MINIMIZE);
543 ShowWindow(_hWnd, SW_MINIMIZE);
545 ShowWindow(_hWnd, SW_SHOWNORMAL);
546 ShowWindow(_hWnd, SW_SHOWNORMAL);
549 HWND new_foreground_window = _hWnd;
550 if (!want_foreground) {
553 new_foreground_window = old_foreground_window;
556 if (!SetActiveWindow(new_foreground_window)) {
557 windisplay_cat.warning()
558 <<
"SetActiveWindow() failed!\n";
564 if (!SetForegroundWindow(new_foreground_window)) {
565 windisplay_cat.warning()
566 <<
"SetForegroundWindow() failed!\n";
572 HIMC hIMC = ImmGetContext(_hWnd);
574 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
575 ImmReleaseContext(_hWnd, hIMC);
579 if (_input_devices.size() > 1) {
581 Rid.usUsagePage = 0x01;
584 Rid.hwndTarget = _hWnd;
585 RegisterRawInputDevices(&Rid, 1,
sizeof (Rid));
589 _window_handle = NativeWindowHandle::make_win(_hWnd);
592 _window_handle =
new WinWindowHandle(
this, *_window_handle);
595 if (_parent_window_handle !=
nullptr) {
596 _parent_window_handle->attach_child(_window_handle);
603 static bool initialized =
false;
606 HMODULE user32 = GetModuleHandleA(
"user32.dll");
609 pRegisterTouchWindow = (PFN_REGISTERTOUCHWINDOW)GetProcAddress(user32,
"RegisterTouchWindow");
610 pGetTouchInputInfo = (PFN_GETTOUCHINPUTINFO)GetProcAddress(user32,
"GetTouchInputInfo");
611 pCloseTouchInputHandle = (PFN_CLOSETOUCHINPUTHANDLE)GetProcAddress(user32,
"CloseTouchInputHandle");
616 if (pRegisterTouchWindow !=
nullptr) {
617 pRegisterTouchWindow(_hWnd, 0);
629 void WinGraphicsWindow::
630 initialize_input_devices() {
632 PRAWINPUTDEVICELIST pRawInputDeviceList;
634 nassertv(_input_devices.size() == 0);
637 memset(_input_device_handle, 0,
sizeof(_input_device_handle));
639 GraphicsWindowInputDevice::pointer_and_keyboard(
this,
"keyboard_mouse");
640 add_input_device(device);
644 if (GetRawInputDeviceList(
nullptr, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) != 0) {
649 pRawInputDeviceList = (PRAWINPUTDEVICELIST)alloca(
sizeof(RAWINPUTDEVICELIST) * nInputDevices);
650 if (pRawInputDeviceList==0) {
655 if (GetRawInputDeviceList(pRawInputDeviceList, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) == -1) {
660 for (
int i = 0; i < (int)nInputDevices; i++) {
661 if (pRawInputDeviceList[i].dwType == RIM_TYPEMOUSE) {
664 if (GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)0, &nSize) != 0) {
667 char *psName = (
char*)alloca(
sizeof(TCHAR) * nSize);
668 if (psName == 0)
return;
669 if (GetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)psName, &nSize) < 0) {
674 if (strncmp(psName,
"\\??\\Root#RDP_MOU#0000#",22)!=0) {
675 if (_input_devices.size() < 32) {
676 if (strncmp(psName,
"\\??\\",4)==0) psName += 4;
677 char *pound1 = strchr(psName,
'#');
678 char *pound2 = pound1 ? strchr(pound1+1,
'#') : 0;
679 char *pound3 = pound2 ? strchr(pound2+1,
'#') : 0;
680 if (pound3) *pound3 = 0;
681 for (
char *p = psName; *p; p++) {
686 if (pound2) *pound2 =
'.';
687 _input_device_handle[_input_devices.size()] = pRawInputDeviceList[i].hDevice;
690 device->set_pointer_in_window(0, 0);
691 add_input_device(device);
704 void WinGraphicsWindow::
714 void WinGraphicsWindow::
724 bool WinGraphicsWindow::
725 do_reshape_request(
int x_origin,
int y_origin,
bool has_origin,
726 int x_size,
int y_size) {
727 if (windisplay_cat.is_debug()) {
728 windisplay_cat.debug()
729 <<
"Got reshape request (" << x_origin <<
", " << y_origin
730 <<
", " << has_origin <<
", " << x_size <<
", " << y_size <<
")\n";
735 if (x_origin == -2) {
736 x_origin = 0.5 * (_pipe->get_display_width() - x_size);
738 if (y_origin == -2) {
739 y_origin = 0.5 * (_pipe->get_display_height() - y_size);
741 _properties.set_origin(x_origin, y_origin);
743 if (x_origin == -1 && y_origin == -1) {
753 SetRect(&view_rect, x_origin, y_origin,
754 x_origin + x_size, y_origin + y_size);
756 GetWindowInfo(_hWnd, &wi);
757 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
759 UINT flags = SWP_NOZORDER | SWP_NOSENDCHANGING;
762 x_origin = view_rect.left;
763 y_origin = view_rect.top;
765 x_origin = CW_USEDEFAULT;
766 y_origin = CW_USEDEFAULT;
770 SetWindowPos(_hWnd,
nullptr, x_origin, y_origin,
771 view_rect.right - view_rect.left,
772 view_rect.bottom - view_rect.top,
780 return do_fullscreen_resize(x_size, y_size);
787 void WinGraphicsWindow::
790 if (!GetClientRect(_hWnd, &view_rect)) {
793 if (windisplay_cat.is_debug()) {
794 windisplay_cat.debug()
795 <<
"GetClientRect() failed in handle_reshape. Ignoring.\n";
802 if (view_rect.left == 0 && view_rect.right == 0 &&
803 view_rect.bottom == 0 && view_rect.top == 0) {
804 if (windisplay_cat.is_debug()) {
805 windisplay_cat.debug()
806 <<
"GetClientRect() returned all zeroes in handle_reshape. Ignoring.\n";
811 bool result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.left));
813 result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.right));
817 if (windisplay_cat.is_debug()) {
818 windisplay_cat.debug()
819 <<
"ClientToScreen() failed in handle_reshape. Ignoring.\n";
825 properties.
set_size((view_rect.right - view_rect.left),
826 (view_rect.bottom - view_rect.top));
829 properties.
set_origin(view_rect.left, view_rect.top);
831 if (windisplay_cat.is_debug()) {
832 windisplay_cat.debug()
833 <<
"reshape to origin: (" << properties.
get_x_origin() <<
"," 839 system_changed_properties(properties);
845 bool WinGraphicsWindow::
846 do_fullscreen_resize(
int x_size,
int y_size) {
847 HWND hDesktopWindow = GetDesktopWindow();
848 HDC scrnDC = GetDC(hDesktopWindow);
849 DWORD dwFullScreenBitDepth = GetDeviceCaps(scrnDC, BITSPIXEL);
850 ReleaseDC(hDesktopWindow, scrnDC);
858 if (!find_acceptable_display_mode(x_size, y_size,
859 dwFullScreenBitDepth, dm)) {
860 windisplay_cat.error()
861 <<
"window resize(" << x_size <<
", " << y_size
862 <<
") failed, no compatible fullscreen display mode found!\n";
867 SetWindowPos(_hWnd,
nullptr, 0,0, x_size, y_size,
868 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
869 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
871 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
872 windisplay_cat.error()
873 <<
"resize ChangeDisplaySettings failed (error code: " 874 << chg_result <<
") for specified res: " 875 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
876 <<
" x " << dm.dmBitsPerPel <<
", " 877 << dm.dmDisplayFrequency <<
" Hz\n";
881 _fullscreen_display_mode = dm;
883 windisplay_cat.info()
884 <<
"Resized fullscreen window to " << x_size <<
", " << y_size
885 <<
" bitdepth " << dwFullScreenBitDepth <<
", " 886 << dm.dmDisplayFrequency <<
"Hz\n";
888 _properties.set_size(x_size, y_size);
897 bool WinGraphicsWindow::
898 do_fullscreen_switch() {
899 if (!do_fullscreen_enable()) {
905 props.set_fullscreen(
true);
906 DWORD window_style = make_style(props);
907 SetWindowLong(_hWnd, GWL_STYLE, window_style);
909 WINDOW_METRICS metrics;
911 if (!calculate_metrics(
true, window_style, metrics, has_origin)){
915 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, metrics.width, metrics.height,
916 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
923 bool WinGraphicsWindow::
924 do_windowed_switch() {
925 do_fullscreen_disable();
928 props.set_fullscreen(
false);
929 DWORD window_style = make_style(props);
930 SetWindowLong(_hWnd, GWL_STYLE, window_style);
932 WINDOW_METRICS metrics;
935 if (!calculate_metrics(
false, window_style, metrics, has_origin)){
943 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0,
944 metrics.width, metrics.height,
945 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
954 void WinGraphicsWindow::
955 reconsider_fullscreen_size(DWORD &, DWORD &, DWORD &) {
964 void WinGraphicsWindow::
965 support_overlay_window(
bool) {
971 DWORD WinGraphicsWindow::
980 DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
982 if (_properties.get_fullscreen()) {
983 window_style |= WS_SYSMENU;
984 }
else if (!_properties.get_undecorated()) {
985 window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
987 if (!_properties.get_fixed_size()) {
988 window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX);
990 window_style |= WS_BORDER;
1000 bool WinGraphicsWindow::
1001 calculate_metrics(
bool fullscreen, DWORD window_style, WINDOW_METRICS &metrics,
1005 has_origin = _properties.has_origin();
1006 if (!fullscreen && has_origin) {
1007 metrics.x = _properties.get_x_origin();
1008 metrics.y = _properties.get_y_origin();
1011 if (metrics.x == -2) {
1012 metrics.x = 0.5 * (_pipe->get_display_width() - _properties.get_x_size());
1014 if (metrics.y == -2) {
1015 metrics.y = 0.5 * (_pipe->get_display_height() - _properties.get_y_size());
1017 _properties.set_origin(metrics.x, metrics.y);
1019 if (metrics.x == -1 && metrics.y == -1) {
1026 metrics.width = _properties.get_x_size();
1027 metrics.height = _properties.get_y_size();
1031 SetRect(&win_rect, metrics.x, metrics.y,
1032 metrics.x + metrics.width, metrics.y + metrics.height);
1035 if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
1036 windisplay_cat.error()
1037 <<
"AdjustWindowRect failed!" << endl;
1042 metrics.x = win_rect.left;
1043 metrics.y = win_rect.top;
1045 metrics.x = CW_USEDEFAULT;
1046 metrics.y = CW_USEDEFAULT;
1048 metrics.width = win_rect.right - win_rect.left;
1049 metrics.height = win_rect.bottom - win_rect.top;
1058 bool WinGraphicsWindow::
1059 open_graphic_window() {
1060 DWORD window_style = make_style(_properties);
1063 if (_properties.has_title()) {
1065 title = encoder.
decode_text(_properties.get_title());
1068 if (!_properties.has_size()) {
1070 _properties.set_size(640, 480);
1073 WINDOW_METRICS metrics;
1075 if (!calculate_metrics(fullscreen, window_style, metrics, has_origin)){
1079 const WindowClass &wclass = register_window_class(_properties);
1080 HINSTANCE hinstance = GetModuleHandle(
nullptr);
1085 WindowHandle *window_handle = _properties.get_parent_window();
1086 if (window_handle !=
nullptr) {
1087 windisplay_cat.info()
1088 <<
"Got parent_window " << *window_handle <<
"\n";
1090 if (os_handle !=
nullptr) {
1091 windisplay_cat.info()
1092 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1094 if (os_handle->
is_of_type(NativeWindowHandle::WinHandle::get_class_type())) {
1095 NativeWindowHandle::WinHandle *win_handle = DCAST(NativeWindowHandle::WinHandle, os_handle);
1096 _hparent = win_handle->get_handle();
1097 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1099 _hparent = (HWND)int_handle->get_handle();
1103 _parent_window_handle = window_handle;
1105 _parent_window_handle =
nullptr;
1109 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(), window_style,
1110 metrics.x, metrics.y,
1113 nullptr,
nullptr, hinstance, 0);
1118 if (!fullscreen && has_origin) {
1119 x_origin = _properties.get_x_origin();
1120 y_origin = _properties.get_y_origin();
1123 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(),
1124 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ,
1126 _properties.get_x_size(), _properties.get_y_size(),
1127 _hparent,
nullptr, hinstance, 0);
1140 system_changed_properties(properties);
1145 windisplay_cat.error()
1146 <<
"CreateWindow() failed!" << endl;
1147 show_error_message();
1156 if (!do_fullscreen_enable()){
1168 bool WinGraphicsWindow::
1169 do_fullscreen_enable() {
1171 HWND hDesktopWindow = GetDesktopWindow();
1172 HDC scrnDC = GetDC(hDesktopWindow);
1173 DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
1177 ReleaseDC(hDesktopWindow, scrnDC);
1179 DWORD dwWidth = _properties.get_x_size();
1180 DWORD dwHeight = _properties.get_y_size();
1181 DWORD dwFullScreenBitDepth = cur_bitdepth;
1184 reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
1185 if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth, dm)) {
1186 windisplay_cat.error()
1187 <<
"Videocard has no supported display resolutions at specified res (" 1188 << dwWidth <<
" x " << dwHeight <<
" x " << dwFullScreenBitDepth <<
")\n";
1192 dm.dmPelsWidth = dwWidth;
1193 dm.dmPelsHeight = dwHeight;
1194 dm.dmBitsPerPel = dwFullScreenBitDepth;
1195 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1197 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1198 windisplay_cat.error()
1199 <<
"ChangeDisplaySettings failed (error code: " 1200 << chg_result <<
") for specified res: " 1201 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1202 <<
" x " << dm.dmBitsPerPel <<
", " 1203 << dm.dmDisplayFrequency <<
" Hz\n";
1207 _fullscreen_display_mode = dm;
1209 _properties.set_origin(0, 0);
1210 _properties.set_size(dwWidth, dwHeight);
1220 bool WinGraphicsWindow::
1221 do_fullscreen_disable() {
1222 int chg_result = ChangeDisplaySettings(
nullptr, 0x0);
1223 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1224 windisplay_cat.warning()
1225 <<
"ChangeDisplaySettings failed to restore Windowed mode\n";
1234 void WinGraphicsWindow::
1236 WindowProperties::ZOrder z_order = _properties.get_z_order();
1237 adjust_z_order(z_order, z_order);
1243 void WinGraphicsWindow::
1244 adjust_z_order(WindowProperties::ZOrder last_z_order,
1245 WindowProperties::ZOrder this_z_order) {
1247 bool do_change =
false;
1249 switch (this_z_order) {
1250 case WindowProperties::Z_bottom:
1251 order = HWND_BOTTOM;
1255 case WindowProperties::Z_normal:
1256 if ((last_z_order != WindowProperties::Z_normal) &&
1258 (last_z_order != WindowProperties::Z_bottom ||
1259 _properties.get_foreground())
1264 order = HWND_NOTOPMOST;
1269 case WindowProperties::Z_top:
1270 order = HWND_TOPMOST;
1275 BOOL result = SetWindowPos(_hWnd, order, 0,0,0,0,
1276 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
1278 windisplay_cat.warning()
1279 <<
"SetWindowPos failed.\n";
1289 void WinGraphicsWindow::
1290 track_mouse_leaving(HWND hwnd) {
1292 DCAST_INTO_V(winpipe, _pipe);
1294 TRACKMOUSEEVENT tme = {
1295 sizeof(TRACKMOUSEEVENT),
1302 BOOL bSucceeded = TrackMouseEvent(&tme);
1304 if (!bSucceeded && windisplay_cat.is_debug()) {
1305 windisplay_cat.debug()
1306 <<
"TrackMouseEvent failed!, LastError=" << GetLastError() << endl;
1309 _tracking_mouse_leaving =
true;
1316 void WinGraphicsWindow::
1318 if (SetFocus(_hWnd) ==
nullptr && GetLastError() != 0) {
1324 if (_parent_window_handle !=
nullptr && _window_handle !=
nullptr) {
1325 _parent_window_handle->request_keyboard_focus(_window_handle);
1328 windisplay_cat.error()
1329 <<
"SetFocus failed: " << GetLastError() <<
"\n";
1356 if (windisplay_cat.is_spam()) {
1357 windisplay_cat.spam()
1359 <<
" window_proc(" << (
void *)
this <<
", " << hwnd <<
", " 1360 << msg <<
", " << wparam <<
", " << lparam <<
")\n";
1366 if (!_tracking_mouse_leaving) {
1368 track_mouse_leaving(hwnd);
1370 set_cursor_in_window();
1371 if(handle_mouse_motion(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))))
1376 handle_raw_input((HRAWINPUT)lparam);
1380 _tracking_mouse_leaving =
false;
1381 handle_mouse_exit();
1382 set_cursor_out_of_window();
1387 track_mouse_leaving(hwnd);
1388 ClearToBlack(hwnd, _properties);
1391 GetCursorPos(&cpos);
1392 ScreenToClient(hwnd, &cpos);
1394 GetClientRect(hwnd, &clientRect);
1395 if (PtInRect(&clientRect,cpos)) {
1396 set_cursor_in_window();
1398 set_cursor_out_of_window();
1431 if (!close_request_event.empty()) {
1434 throw_event(close_request_event);
1442 system_changed_properties(properties);
1449 case WM_CHILDACTIVATE:
1450 if (windisplay_cat.is_debug()) {
1451 windisplay_cat.debug()
1452 <<
"WM_CHILDACTIVATE: " << hwnd <<
"\n";
1457 if (windisplay_cat.is_debug()) {
1458 windisplay_cat.debug()
1459 <<
"WM_ACTIVATE: " << hwnd <<
", " << wparam <<
", " << lparam <<
"\n";
1462 if ((wparam & 0xffff) != WA_INACTIVE)
1470 ChangeDisplaySettings(&_fullscreen_display_mode, CDS_FULLSCREEN);
1471 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1472 const DEVMODE &dm = _fullscreen_display_mode;
1473 windisplay_cat.error()
1474 <<
"restore ChangeDisplaySettings failed (error code: " 1475 << chg_result <<
") for specified res: " 1476 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1477 <<
" x " << dm.dmBitsPerPel <<
", " 1478 << dm.dmDisplayFrequency <<
" Hz\n";
1482 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
1483 fullscreen_restored(properties);
1498 ShowWindow(_hWnd, SW_MINIMIZE);
1500 do_fullscreen_disable();
1501 fullscreen_minimized(properties);
1506 system_changed_properties(properties);
1512 if (windisplay_cat.is_debug()) {
1513 windisplay_cat.debug()
1514 <<
"WM_SIZE: " << hwnd <<
", " << wparam <<
"\n";
1518 case WM_EXITSIZEMOVE:
1522 case WM_WINDOWPOSCHANGED:
1523 if (windisplay_cat.is_debug()) {
1524 windisplay_cat.debug()
1525 <<
"WM_WINDOWPOSCHANGED: " << hwnd <<
", " << wparam <<
"\n";
1527 if (_hWnd !=
nullptr) {
1537 if (GetUpdateRect(_hWnd,
nullptr,
false)) {
1538 if (windisplay_cat.is_spam()) {
1539 windisplay_cat.spam()
1540 <<
"Got update regions: " <<
this <<
"\n";
1542 _got_expose_event =
true;
1546 case WM_LBUTTONDOWN:
1547 if (_lost_keypresses) {
1548 resend_lost_keypresses();
1558 case WM_MBUTTONDOWN:
1559 if (_lost_keypresses) {
1560 resend_lost_keypresses();
1569 case WM_RBUTTONDOWN:
1570 if (_lost_keypresses) {
1571 resend_lost_keypresses();
1580 case WM_XBUTTONDOWN:
1582 if (_lost_keypresses) {
1583 resend_lost_keypresses();
1586 int whichButton = GET_XBUTTON_WPARAM(wparam);
1588 if (whichButton == XBUTTON1) {
1590 }
else if (whichButton == XBUTTON2) {
1597 if (_lost_keypresses) {
1598 resend_lost_keypresses();
1605 if (_lost_keypresses) {
1606 resend_lost_keypresses();
1613 if (_lost_keypresses) {
1614 resend_lost_keypresses();
1622 if (_lost_keypresses) {
1623 resend_lost_keypresses();
1626 int whichButton = GET_XBUTTON_WPARAM(wparam);
1627 if (whichButton == XBUTTON1) {
1629 }
else if (whichButton == XBUTTON2) {
1637 int delta = GET_WHEEL_DELTA_WPARAM(wparam);
1640 GetCursorPos(&point);
1641 ScreenToClient(hwnd, &point);
1642 double time = get_message_time();
1648 delta -= WHEEL_DELTA;
1654 delta += WHEEL_DELTA;
1662 case WM_IME_SETCONTEXT:
1666 windisplay_cat.debug() <<
"hwnd = " << hwnd <<
" and GetFocus = " << GetFocus() << endl;
1667 _ime_hWnd = ImmGetDefaultIMEWnd(hwnd);
1668 if (::SendMessage(_ime_hWnd, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0))
1670 windisplay_cat.debug() <<
"SendMessage failed for " << _ime_hWnd << endl;
1672 windisplay_cat.debug() <<
"SendMessage Succeeded for " << _ime_hWnd << endl;
1674 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1675 lparam &= ~ISC_SHOWUIALL;
1676 if (ImmIsUIMessage(_ime_hWnd, msg, wparam, lparam))
1677 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1683 if (wparam == IMN_SETOPENSTATUS) {
1684 HIMC hIMC = ImmGetContext(hwnd);
1685 nassertr(hIMC != 0, 0);
1686 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
1688 _ime_active =
false;
1692 COMPOSITIONFORM comf;
1694 ImmGetCompositionWindow(hIMC, &comf);
1695 ImmGetCandidateWindow(hIMC, 0, &canf);
1696 windisplay_cat.debug() <<
1697 "comf style " << comf.dwStyle <<
1698 " comf point: x" << comf.ptCurrentPos.x <<
",y " << comf.ptCurrentPos.y <<
1699 " comf rect: l " << comf.rcArea.left <<
",t " << comf.rcArea.top <<
",r " <<
1700 comf.rcArea.right <<
",b " << comf.rcArea.bottom << endl;
1701 windisplay_cat.debug() <<
1702 "canf style " << canf.dwStyle <<
1703 " canf point: x" << canf.ptCurrentPos.x <<
",y " << canf.ptCurrentPos.y <<
1704 " canf rect: l " << canf.rcArea.left <<
",t " << canf.rcArea.top <<
",r " <<
1705 canf.rcArea.right <<
",b " << canf.rcArea.bottom << endl;
1706 comf.dwStyle = CFS_POINT;
1707 comf.ptCurrentPos.x = 2000;
1708 comf.ptCurrentPos.y = 2000;
1710 canf.dwStyle = CFS_EXCLUDE;
1712 canf.ptCurrentPos.x = 0;
1713 canf.ptCurrentPos.y = 0;
1714 canf.rcArea.left = 0;
1715 canf.rcArea.top = 0;
1716 canf.rcArea.right = 640;
1717 canf.rcArea.bottom = 480;
1720 comf.rcArea.left = 200;
1721 comf.rcArea.top = 200;
1722 comf.rcArea.right = 0;
1723 comf.rcArea.bottom = 0;
1726 if (ImmSetCompositionWindow(hIMC, &comf))
1727 windisplay_cat.debug() <<
"set composition form: success\n";
1728 for (
int i=0; i<3; ++i) {
1729 if (ImmSetCandidateWindow(hIMC, &canf))
1730 windisplay_cat.debug() <<
"set candidate form: success\n";
1735 ImmReleaseContext(hwnd, hIMC);
1739 case WM_IME_STARTCOMPOSITION:
1740 support_overlay_window(
true);
1744 case WM_IME_ENDCOMPOSITION:
1745 support_overlay_window(
false);
1746 _ime_active =
false;
1755 case WM_IME_COMPOSITION:
1767 HIMC hIMC = ImmGetContext(hwnd);
1768 nassertr(hIMC != 0, 0);
1770 DWORD result_size = 0;
1771 static const int ime_buffer_size = 256;
1772 static const int ime_buffer_size_bytes = ime_buffer_size /
sizeof(wchar_t);
1773 wchar_t ime_buffer[ime_buffer_size];
1774 size_t cursor_pos, delta_start;
1776 if (lparam & GCS_RESULTSTR) {
1777 result_size = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR,
1778 ime_buffer, ime_buffer_size_bytes);
1779 size_t num_chars = result_size /
sizeof(wchar_t);
1780 for (
size_t i = 0; i < num_chars; ++i) {
1785 if (lparam & GCS_COMPSTR) {
1786 result_size = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS,
nullptr, 0);
1787 cursor_pos = result_size & 0xffff;
1789 result_size = ImmGetCompositionStringW(hIMC, GCS_DELTASTART,
nullptr, 0);
1790 delta_start = result_size & 0xffff;
1791 result_size = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, ime_buffer, ime_buffer_size);
1792 size_t num_chars = result_size /
sizeof(wchar_t);
1794 _input->
candidate(wstring(ime_buffer, num_chars),
1795 std::min(cursor_pos, delta_start),
1796 std::max(cursor_pos, delta_start),
1799 ImmReleaseContext(hwnd, hIMC);
1820 if (_lost_keypresses) {
1821 resend_lost_keypresses();
1823 if (windisplay_cat.is_debug()) {
1824 windisplay_cat.debug()
1825 <<
"syskeydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1831 GetCursorPos(&point);
1832 ScreenToClient(hwnd, &point);
1833 handle_keypress(lookup_key(wparam), point.x, point.y,
1834 get_message_time());
1836 if ((lparam & 0x40000000) == 0) {
1837 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1848 if (wparam == VK_MENU) {
1849 if ((GetKeyState(VK_LMENU) & 0x8000) != 0 && ! _lalt_down) {
1850 handle_keypress(KeyboardButton::lalt(), point.x, point.y,
1851 get_message_time());
1854 if ((GetKeyState(VK_RMENU) & 0x8000) != 0 && ! _ralt_down) {
1855 handle_keypress(KeyboardButton::ralt(), point.x, point.y,
1856 get_message_time());
1860 if (wparam == VK_F10) {
1869 if (wparam == SC_KEYMENU) {
1881 if (_lost_keypresses) {
1882 resend_lost_keypresses();
1884 if (windisplay_cat.is_debug()) {
1885 windisplay_cat.debug()
1886 <<
"keydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1891 if ((lparam & 0x40000000) == 0) {
1893 GetCursorPos(&point);
1894 ScreenToClient(hwnd, &point);
1895 handle_keypress(lookup_key(wparam), point.x, point.y,
1896 get_message_time());
1897 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1903 if (wparam == VK_SHIFT) {
1904 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0 && ! _lshift_down) {
1905 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
1906 get_message_time());
1907 _lshift_down =
true;
1909 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0 && ! _rshift_down) {
1910 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
1911 get_message_time());
1912 _rshift_down =
true;
1914 }
else if(wparam == VK_CONTROL) {
1915 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0 && ! _lcontrol_down) {
1916 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
1917 get_message_time());
1918 _lcontrol_down =
true;
1920 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0 && ! _rcontrol_down) {
1921 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
1922 get_message_time());
1923 _rcontrol_down =
true;
1929 if ((wparam==
'V') && (GetKeyState(VK_CONTROL) < 0) &&
1930 !_input_devices.empty()) {
1934 if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(
nullptr)) {
1936 hglb = GetClipboardData(CF_TEXT);
1937 if (hglb!=
nullptr) {
1938 lptstr = (
char *) GlobalLock(hglb);
1939 if (lptstr !=
nullptr) {
1941 for (pChar = lptstr; *pChar; pChar++) {
1954 GetCursorPos(&point);
1955 ScreenToClient(hwnd, &point);
1956 handle_keypress(lookup_key(wparam), point.x, point.y,
1957 get_message_time());
1970 if (wparam == VK_SHIFT) {
1971 if (((GetKeyState(VK_LSHIFT) & 0x8000) != 0) && ! _lshift_down ) {
1972 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
1973 get_message_time());
1974 _lshift_down =
true;
1975 }
else if (((GetKeyState(VK_RSHIFT) & 0x8000) != 0) && ! _rshift_down ) {
1976 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
1977 get_message_time());
1978 _rshift_down =
true;
1980 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0) {
1981 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
1982 get_message_time());
1984 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0) {
1985 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
1986 get_message_time());
1989 }
else if(wparam == VK_CONTROL) {
1990 if (((GetKeyState(VK_LCONTROL) & 0x8000) != 0) && ! _lcontrol_down ) {
1991 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
1992 get_message_time());
1993 _lcontrol_down =
true;
1994 }
else if (((GetKeyState(VK_RCONTROL) & 0x8000) != 0) && ! _rcontrol_down ) {
1995 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
1996 get_message_time());
1997 _rcontrol_down =
true;
1999 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0) {
2000 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2001 get_message_time());
2003 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0) {
2004 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2005 get_message_time());
2014 if (_lost_keypresses) {
2015 resend_lost_keypresses();
2017 if (windisplay_cat.is_debug()) {
2018 windisplay_cat.debug()
2019 <<
"keyup: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
2021 handle_keyrelease(lookup_key(wparam), get_message_time());
2022 handle_raw_keyrelease(lookup_raw_key(lparam), get_message_time());
2027 if (wparam == VK_SHIFT) {
2028 if ((GetKeyState(VK_LSHIFT) & 0x8000) == 0 && _lshift_down) {
2029 handle_keyrelease(KeyboardButton::lshift(), get_message_time());
2030 _lshift_down =
false;
2032 if ((GetKeyState(VK_RSHIFT) & 0x8000) == 0 && _rshift_down) {
2033 handle_keyrelease(KeyboardButton::rshift(), get_message_time());
2034 _rshift_down =
false;
2036 }
else if(wparam == VK_CONTROL) {
2037 if ((GetKeyState(VK_LCONTROL) & 0x8000) == 0 && _lcontrol_down) {
2038 handle_keyrelease(KeyboardButton::lcontrol(), get_message_time());
2039 _lcontrol_down =
false;
2041 if ((GetKeyState(VK_RCONTROL) & 0x8000) == 0 && _rcontrol_down) {
2042 handle_keyrelease(KeyboardButton::rcontrol(), get_message_time());
2043 _rcontrol_down =
false;
2045 }
else if(wparam == VK_MENU) {
2046 if ((GetKeyState(VK_LMENU) & 0x8000) == 0 && _lalt_down) {
2047 handle_keyrelease(KeyboardButton::lalt(), get_message_time());
2050 if ((GetKeyState(VK_RMENU) & 0x8000) == 0 && _ralt_down) {
2051 handle_keyrelease(KeyboardButton::ralt(), get_message_time());
2058 if (windisplay_cat.is_debug()) {
2059 windisplay_cat.debug()
2065 system_changed_properties(properties);
2087 if (windisplay_cat.is_debug()) {
2088 windisplay_cat.debug()
2092 if (_lost_keypresses) {
2093 resend_lost_keypresses();
2097 system_changed_properties(properties);
2101 if (windisplay_cat.is_debug()) {
2102 windisplay_cat.debug()
2106 system_changed_properties(properties);
2110 if (windisplay_cat.is_debug()) {
2111 windisplay_cat.debug()
2115 system_changed_properties(properties);
2121 if (windisplay_cat.is_debug()) {
2122 windisplay_cat.debug() <<
"DPI changed to " << LOWORD(wparam);
2124 if (LOWORD(wparam) != HIWORD(wparam)) {
2125 windisplay_cat.debug(
false) <<
"x" << HIWORD(wparam) <<
"\n";
2127 windisplay_cat.debug(
false) <<
"\n";
2132 if (!_properties.get_fixed_size() && dpi_window_resize) {
2133 RECT &rect = *(LPRECT)lparam;
2134 SetWindowPos(_hWnd, HWND_TOP, rect.left, rect.top,
2135 rect.right - rect.left, rect.bottom - rect.top,
2136 SWP_NOZORDER | SWP_NOACTIVATE);
2141 _num_touches = LOWORD(wparam);
2142 if (_num_touches > MAX_TOUCHES) {
2143 _num_touches = MAX_TOUCHES;
2145 if (pGetTouchInputInfo != 0) {
2146 pGetTouchInputInfo((HTOUCHINPUT)lparam, _num_touches, _touches,
sizeof(TOUCHINPUT));
2147 pCloseTouchInputHandle((HTOUCHINPUT)lparam);
2153 for ( WinProcClasses::iterator it=_window_proc_classes.begin() ; it != _window_proc_classes.end(); it++ ){
2154 (*it)->wnd_proc(
this, hwnd, msg, wparam, lparam);
2157 return DefWindowProcW(hwnd, msg, wparam, lparam);
2168 WindowHandles::const_iterator wi;
2169 wi = _window_handles.find(hwnd);
2170 if (wi != _window_handles.end()) {
2172 return (*wi).second->window_proc(hwnd, msg, wparam, lparam);
2176 if (_creating_window !=
nullptr) {
2177 return _creating_window->
window_proc(hwnd, msg, wparam, lparam);
2182 return DefWindowProcW(hwnd, msg, wparam, lparam);
2188 void WinGraphicsWindow::
2192 if (!GetMessage(&msg,
nullptr, 0, 0)) {
2199 TranslateMessage(&msg);
2201 DispatchMessage(&msg);
2209 void WinGraphicsWindow::
2210 resend_lost_keypresses() {
2211 nassertv(_lost_keypresses);
2216 _lost_keypresses =
false;
2223 void WinGraphicsWindow::
2225 bool hide_cursor =
false;
2226 if (to_window ==
nullptr) {
2229 if (_got_saved_params) {
2230 SystemParametersInfo(SPI_SETMOUSETRAILS, _saved_mouse_trails,
2232 SystemParametersInfo(SPI_SETCURSORSHADOW, 0,
2233 _saved_cursor_shadow ? (PVOID)1 :
nullptr, 0);
2234 SystemParametersInfo(SPI_SETMOUSEVANISH, 0,
2235 _saved_mouse_vanish ? (PVOID)1 :
nullptr, 0);
2236 _got_saved_params =
false;
2248 if (!_got_saved_params) {
2249 SystemParametersInfo(SPI_GETMOUSETRAILS, 0,
2250 &_saved_mouse_trails, 0);
2251 SystemParametersInfo(SPI_GETCURSORSHADOW, 0,
2252 &_saved_cursor_shadow, 0);
2253 SystemParametersInfo(SPI_GETMOUSEVANISH, 0,
2254 &_saved_mouse_vanish, 0);
2255 _got_saved_params =
true;
2257 SystemParametersInfo(SPI_SETMOUSETRAILS, 0, (PVOID)0, 0);
2258 SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (PVOID)
false, 0);
2259 SystemParametersInfo(SPI_SETMOUSEVANISH, 0, (PVOID)
false, 0);
2262 SetCursor(to_window->_cursor);
2265 hide_or_show_cursor(hide_cursor);
2267 _cursor_window = to_window;
2275 void WinGraphicsWindow::
2276 hide_or_show_cursor(
bool hide_cursor) {
2278 if (!_cursor_hidden) {
2280 _cursor_hidden =
true;
2283 if (_cursor_hidden) {
2285 _cursor_hidden =
false;
2291 #define MIN_REFRESH_RATE 60 2294 #define ACCEPTABLE_REFRESH_RATE(RATE) ((RATE >= MIN_REFRESH_RATE) || (RATE==0) || (RATE==1)) 2300 bool WinGraphicsWindow::
2301 find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
2306 ZeroMemory(&cur_dm,
sizeof(cur_dm));
2307 cur_dm.dmSize =
sizeof(cur_dm);
2308 EnumDisplaySettings(
nullptr, ENUM_CURRENT_SETTINGS, &cur_dm);
2311 int saved_modenum = -1;
2314 ZeroMemory(&dm,
sizeof(dm));
2315 dm.dmSize =
sizeof(dm);
2317 if (!EnumDisplaySettings(
nullptr, modenum, &dm)) {
2321 if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
2322 (dm.dmBitsPerPel == bpp)) {
2325 if (dm.dmDisplayFrequency == cur_dm.dmDisplayFrequency) {
2327 }
else if (saved_modenum == -1) {
2328 saved_modenum = modenum;
2336 if (saved_modenum != -1) {
2337 ZeroMemory(&dm,
sizeof(dm));
2338 dm.dmSize =
sizeof(dm);
2340 if (EnumDisplaySettings(
nullptr, saved_modenum, &dm)) {
2352 void WinGraphicsWindow::
2353 show_error_message(DWORD message_id) {
2354 LPTSTR message_buffer;
2356 if (message_id == 0) {
2357 message_id = GetLastError();
2360 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2361 nullptr, message_id,
2362 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2363 (LPTSTR)&message_buffer,
2365 MessageBox(GetDesktopWindow(), message_buffer, _T(errorbox_title), MB_OK);
2366 windisplay_cat.fatal() <<
"System error msg: " << message_buffer << endl;
2367 LocalFree(message_buffer);
2373 void WinGraphicsWindow::
2374 handle_keypress(
ButtonHandle key,
int x,
int y,
double time) {
2376 if (key != ButtonHandle::none()) {
2385 void WinGraphicsWindow::
2387 if (key != ButtonHandle::none()) {
2395 void WinGraphicsWindow::
2397 if (key != ButtonHandle::none()) {
2405 void WinGraphicsWindow::
2407 if (key != ButtonHandle::none()) {
2415 void WinGraphicsWindow::
2417 if (key != ButtonHandle::none()) {
2427 lookup_key(WPARAM wparam)
const {
2432 case VK_BACK:
return KeyboardButton::backspace();
2433 case VK_DELETE:
return KeyboardButton::del();
2434 case VK_ESCAPE:
return KeyboardButton::escape();
2435 case VK_SPACE:
return KeyboardButton::space();
2436 case VK_UP:
return KeyboardButton::up();
2437 case VK_DOWN:
return KeyboardButton::down();
2438 case VK_LEFT:
return KeyboardButton::left();
2439 case VK_RIGHT:
return KeyboardButton::right();
2446 case VK_TAB:
return KeyboardButton::tab();
2447 case VK_PRIOR:
return KeyboardButton::page_up();
2448 case VK_NEXT:
return KeyboardButton::page_down();
2449 case VK_HOME:
return KeyboardButton::home();
2450 case VK_END:
return KeyboardButton::end();
2451 case VK_F1:
return KeyboardButton::f1();
2452 case VK_F2:
return KeyboardButton::f2();
2453 case VK_F3:
return KeyboardButton::f3();
2454 case VK_F4:
return KeyboardButton::f4();
2455 case VK_F5:
return KeyboardButton::f5();
2456 case VK_F6:
return KeyboardButton::f6();
2457 case VK_F7:
return KeyboardButton::f7();
2458 case VK_F8:
return KeyboardButton::f8();
2459 case VK_F9:
return KeyboardButton::f9();
2460 case VK_F10:
return KeyboardButton::f10();
2461 case VK_F11:
return KeyboardButton::f11();
2462 case VK_F12:
return KeyboardButton::f12();
2463 case VK_INSERT:
return KeyboardButton::insert();
2464 case VK_CAPITAL:
return KeyboardButton::caps_lock();
2465 case VK_NUMLOCK:
return KeyboardButton::num_lock();
2466 case VK_SCROLL:
return KeyboardButton::scroll_lock();
2467 case VK_PAUSE:
return KeyboardButton::pause();
2468 case VK_SNAPSHOT:
return KeyboardButton::print_screen();
2470 case VK_SHIFT:
return KeyboardButton::shift();
2471 case VK_LSHIFT:
return KeyboardButton::lshift();
2472 case VK_RSHIFT:
return KeyboardButton::rshift();
2474 case VK_CONTROL:
return KeyboardButton::control();
2475 case VK_LCONTROL:
return KeyboardButton::lcontrol();
2476 case VK_RCONTROL:
return KeyboardButton::rcontrol();
2478 case VK_MENU:
return KeyboardButton::alt();
2479 case VK_LMENU:
return KeyboardButton::lalt();
2480 case VK_RMENU:
return KeyboardButton::ralt();
2483 int key = MapVirtualKey(wparam, 2);
2484 if (isascii(key) && key != 0) {
2499 return ButtonHandle::none();
2507 lookup_raw_key(LPARAM lparam)
const {
2508 unsigned char vsc = (lparam & 0xff0000) >> 16;
2510 if (lparam & 0x1000000) {
2513 case 28:
return KeyboardButton::enter();
2514 case 29:
return KeyboardButton::rcontrol();
2516 case 55:
return KeyboardButton::print_screen();
2517 case 56:
return KeyboardButton::ralt();
2518 case 69:
return KeyboardButton::num_lock();
2519 case 71:
return KeyboardButton::home();
2520 case 72:
return KeyboardButton::up();
2521 case 73:
return KeyboardButton::page_up();
2522 case 75:
return KeyboardButton::left();
2523 case 77:
return KeyboardButton::right();
2524 case 79:
return KeyboardButton::end();
2525 case 80:
return KeyboardButton::down();
2526 case 81:
return KeyboardButton::page_down();
2527 case 82:
return KeyboardButton::insert();
2528 case 83:
return KeyboardButton::del();
2529 case 91:
return KeyboardButton::lmeta();
2530 case 92:
return KeyboardButton::rmeta();
2531 case 93:
return KeyboardButton::menu();
2537 ButtonHandle::none(),
2538 KeyboardButton::escape(),
2551 KeyboardButton::backspace(),
2552 KeyboardButton::tab(),
2565 KeyboardButton::enter(),
2566 KeyboardButton::lcontrol(),
2579 KeyboardButton::lshift(),
2591 KeyboardButton::rshift(),
2593 KeyboardButton::lalt(),
2594 KeyboardButton::space(),
2595 KeyboardButton::caps_lock(),
2596 KeyboardButton::f1(),
2597 KeyboardButton::f2(),
2598 KeyboardButton::f3(),
2599 KeyboardButton::f4(),
2600 KeyboardButton::f5(),
2601 KeyboardButton::f6(),
2602 KeyboardButton::f7(),
2603 KeyboardButton::f8(),
2604 KeyboardButton::f9(),
2605 KeyboardButton::f10(),
2606 KeyboardButton::pause(),
2607 KeyboardButton::scroll_lock(),
2622 return raw_map[vsc];
2627 case 87:
return KeyboardButton::f11();
2628 case 88:
return KeyboardButton::f12();
2629 default:
return ButtonHandle::none();
2641 get_keyboard_map()
const {
2646 unsigned short ex_vsc[] = {0x57, 0x58,
2647 0x011c, 0x011d, 0x0135, 0x0137, 0x0138, 0x0145, 0x0147, 0x0148, 0x0149, 0x014b, 0x014d, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x015b, 0x015c, 0x015d};
2649 for (
int k = 1; k < 84 + 17; ++k) {
2651 vsc = ex_vsc[k - 84];
2656 UINT lparam = vsc << 16;
2658 if (raw_button == ButtonHandle::none()) {
2664 button = KeyboardButton::pause();
2666 }
else if (vsc >= 0x47 && vsc <= 0x53) {
2668 button = raw_button;
2680 UINT vk = MapVirtualKeyA(vsc, MAPVK_VSC_TO_VK_EX);
2681 button = lookup_key(vk);
2687 int len = GetKeyNameTextW(lparam, text, 256);
2699 void WinGraphicsWindow::
2700 handle_raw_input(HRAWINPUT hraw) {
2707 if (GetRawInputData(hraw, RID_INPUT,
nullptr, &dwSize,
sizeof(RAWINPUTHEADER)) == -1) {
2711 lpb = (LPBYTE)alloca(
sizeof(LPBYTE) * dwSize);
2712 if (lpb ==
nullptr) {
2716 if (GetRawInputData(hraw, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize) {
2720 RAWINPUT *raw = (RAWINPUT *)lpb;
2721 if (raw->header.hDevice == 0) {
2725 for (
size_t i = 1; i < _input_devices.size(); ++i) {
2726 if (_input_device_handle[i] == raw->header.hDevice) {
2730 int adjx = raw->data.mouse.lLastX;
2731 int adjy = raw->data.mouse.lLastY;
2733 if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
2734 input->set_pointer_in_window(adjx, adjy);
2736 input->pointer_moved(adjx, adjy);
2739 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {
2742 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) {
2745 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) {
2748 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) {
2751 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) {
2754 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) {
2757 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
2760 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
2763 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
2766 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
2776 bool WinGraphicsWindow::
2777 handle_mouse_motion(
int x,
int y) {
2785 void WinGraphicsWindow::
2786 handle_mouse_exit() {
2795 HICON WinGraphicsWindow::
2796 get_icon(
const Filename &filename) {
2798 IconFilenames::iterator fi = _icon_filenames.find(filename);
2799 if (fi != _icon_filenames.end()) {
2800 return (HICON)((*fi).second);
2814 windisplay_cat.warning()
2815 <<
"Could not find icon filename " << filename <<
"\n";
2819 fi = _icon_filenames.find(resolved);
2820 if (fi != _icon_filenames.end()) {
2821 _icon_filenames[filename] = (*fi).second;
2822 return (HICON)((*fi).second);
2827 HANDLE h = LoadImage(
nullptr, os.c_str(),
2828 IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2830 windisplay_cat.warning()
2831 <<
"windows icon filename '" << os <<
"' could not be loaded!!\n";
2834 _icon_filenames[filename] = h;
2835 _icon_filenames[resolved] = h;
2843 HCURSOR WinGraphicsWindow::
2844 get_cursor(
const Filename &filename) {
2846 if (filename.empty()) {
2851 IconFilenames::iterator fi = _cursor_filenames.find(filename);
2852 if (fi != _cursor_filenames.end()) {
2853 return (HCURSOR)((*fi).second);
2863 windisplay_cat.warning()
2864 <<
"Could not find cursor filename " << filename <<
"\n";
2867 fi = _cursor_filenames.find(resolved);
2868 if (fi != _cursor_filenames.end()) {
2869 _cursor_filenames[filename] = (*fi).second;
2870 return (HCURSOR)((*fi).second);
2875 HANDLE h = LoadImage(
nullptr, os.c_str(),
2876 IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
2878 windisplay_cat.warning()
2879 <<
"windows cursor filename '" << os <<
"' could not be loaded!!\n";
2880 show_error_message();
2883 _cursor_filenames[filename] = h;
2884 _cursor_filenames[resolved] = h;
2888 static HCURSOR get_cursor(
const Filename &filename);
2894 const WinGraphicsWindow::WindowClass &WinGraphicsWindow::
2896 WindowClass wcreg(props);
2897 std::wostringstream wclass_name;
2898 wclass_name << L
"WinGraphicsWindow" << _window_class_index;
2899 wcreg._name = wclass_name.str();
2901 std::pair<WindowClasses::iterator, bool> found = _window_classes.insert(wcreg);
2902 const WindowClass &wclass = (*found.first);
2904 if (!found.second) {
2910 _window_class_index++;
2914 HINSTANCE instance = GetModuleHandle(
nullptr);
2917 ZeroMemory(&wc,
sizeof(wc));
2918 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
2920 wc.hInstance = instance;
2922 wc.hIcon = wclass._icon;
2924 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
2925 wc.lpszMenuName =
nullptr;
2926 wc.lpszClassName = wclass._name.c_str();
2928 if (!RegisterClassW(&wc)) {
2929 windisplay_cat.error()
2930 <<
"could not register window class " << wclass._name <<
"!" << endl;
2940 WinGraphicsWindow::WinWindowHandle::
2952 void WinGraphicsWindow::WinWindowHandle::
2961 void WinGraphicsWindow::WinWindowHandle::
2962 receive_windows_message(
unsigned int msg,
int wparam,
int lparam) {
2963 if (_window !=
nullptr) {
2970 void PrintErrorMessage(DWORD msgID) {
2971 LPTSTR pMessageBuffer;
2973 if (msgID==PRINT_LAST_ERROR)
2974 msgID=GetLastError();
2976 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2978 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2979 (LPTSTR) &pMessageBuffer,
2981 MessageBox(GetDesktopWindow(),pMessageBuffer,_T(errorbox_title),MB_OK);
2982 windisplay_cat.fatal() <<
"System error msg: " << pMessageBuffer << endl;
2983 LocalFree( pMessageBuffer );
2989 if (windisplay_cat.is_debug()) {
2990 windisplay_cat.debug()
2991 <<
"Skipping ClearToBlack, no origin specified yet.\n";
2996 if (windisplay_cat.is_debug()) {
2997 windisplay_cat.debug()
2998 <<
"ClearToBlack(" << hWnd <<
", " << props <<
")\n";
3001 HDC hDC=GetDC(hWnd);
3007 FillRect(hDC,&clrRect,(HBRUSH)GetStockObject(BLACK_BRUSH));
3008 ReleaseDC(hWnd,hDC);
3017 GetClientRect(hwnd, view_rect);
3020 ul.x = view_rect->left;
3021 ul.y = view_rect->top;
3022 lr.x = view_rect->right;
3023 lr.y = view_rect->bottom;
3025 ClientToScreen(hwnd, &ul);
3026 ClientToScreen(hwnd, &lr);
3028 view_rect->left = ul.x;
3029 view_rect->top = ul.y;
3030 view_rect->right = lr.x;
3031 view_rect->bottom = lr.y;
3040 nassertv(wnd_proc !=
nullptr);
3049 nassertv(wnd_proc !=
nullptr);
3058 _window_proc_classes.clear();
3075 return callbackData->get_msg() == WM_TOUCH;
3084 return _num_touches;
3093 nassertr(index >= 0 && index < MAX_TOUCHES,
TouchInfo());
3095 TOUCHINPUT ti = _touches[index];
3097 point.x = TOUCH_COORD_TO_PIXEL(ti.x);
3098 point.y = TOUCH_COORD_TO_PIXEL(ti.y);
3099 ScreenToClient(_hWnd, &point);
3104 ret.set_id(ti.dwID);
3105 ret.set_flags(ti.dwFlags);
virtual void receive_windows_message(unsigned int msg, int wparam, int lparam)
Called on a child handle to deliver a keyboard button event generated in the parent window.
has_cursor_filename
Returns true if set_cursor_filename() has been specified.
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
This specialization on CallbackData is passed when the callback is initiated from from an implementat...
clear_z_order
Removes the z_order specification from the properties.
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
get_mouse_mode
See set_mouse_mode().
has_icon_filename
Returns true if set_icon_filename() has been specified.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
has_minimized
Returns true if set_minimized() has been specified.
void set_size_and_recalc(int x, int y)
Changes the x_size and y_size, then recalculates structures that depend on size.
This is our own Panda specialization on the default STL map.
This object represents a window on the desktop, not necessarily a Panda window.
get_fixed_size
Returns true if the window cannot be resized by the user, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_size
Specifies the requested size of the window, in pixels.
get_cursor_hidden
Returns true if the mouse cursor is invisible.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
BEGIN_PUBLISH typedef PointerData MouseData
Deprecated alias for PointerData.
This class can be used to convert text between multiple representations, e.g.
get_foreground
Returns true if the window is in the foreground.
virtual TouchInfo get_touch_info(int index)
Returns the TouchInfo object describing the specified touch.
clear_cursor_filename
Removes the cursor_filename specification from the properties.
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows,...
clear_icon_filename
Removes the icon_filename specification from the properties.
set_minimized
Specifies whether the window should be created minimized (true), or normal (false).
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_cursor_filename
Returns the icon filename associated with the mouse cursor.
clear_fixed_size
Removes the fixed_size specification from the properties.
bool resolve_filename(const DSearchPath &searchpath, const std::string &default_extension=std::string())
Searches the given search path for the filename.
virtual bool move_pointer(int device, int x, int y)
Forces the pointer to the indicated position within the window, if possible.
virtual int get_num_touches()
Returns the current number of touches on this window.
void receive_windows_message(unsigned int msg, int wparam, int lparam)
This is called to receive a keyboard event generated by proxy by another window in a parent process.
get_os_handle
Returns the OS-specific handle stored internally to the WindowHandle wrapper.
int get_y_origin() const
Returns the y coordinate of the window's top-left corner, not including decorations.
virtual void remove_window_proc(const GraphicsWindowProc *wnd_proc_object)
Removes the specified Windows proc event handler.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_title
Returns the window's title.
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
has_fullscreen
Returns true if set_fullscreen() has been specified.
virtual LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
This is the nonstatic window_proc function.
get_close_request_event
Returns the name of the event set via set_close_request_event().
has_z_order
Returns true if the window z_order has been specified, false otherwise.
A container for the various kinds of properties we might ask to have on a graphics window before we o...
An abstract base class for glGraphicsWindow and dxGraphicsWindow (and, in general,...
static LONG WINAPI static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
This is attached to the window class for all WinGraphicsWindow windows; it is called to handle window...
get_undecorated
Returns true if the window has no border.
clear_undecorated
Removes the undecorated specification from the properties.
has_origin
Returns true if the window origin has been specified, false otherwise.
Stores information for a single touch event.
has_fixed_size
Returns true if set_fixed_size() has been specified.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
set_origin
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
Similar to MutexHolder, but for a light mutex.
get_icon_filename
Returns the icon filename associated with the window.
An object to create GraphicsOutputs that share a particular 3-D API.
clear_mouse_mode
Removes the mouse_mode specification from the properties.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
clear_minimized
Removes the minimized specification from the properties.
clear_cursor_hidden
Removes the cursor_hidden specification from the properties.
get_real_time
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
get_text
Returns the current text, as encoded via the current encoding system.
This is a base class for the various different classes that represent the result of a frame of render...
get_minimized
Returns true if the window is minimized.
virtual MouseData get_pointer(int device) const
Returns the MouseData associated with the nth input device's pointer.
Defines an interface for storing platform-specific window processor methods.
virtual void add_window_proc(const GraphicsWindowProc *wnd_proc_object)
Adds the specified Windows proc event handler to be called whenever a Windows event occurs.
clear_fullscreen
Removes the fullscreen specification from the properties.
void get_client_rect_screen(HWND hwnd, RECT *view_rect)
Fills view_rect with the coordinates of the client area of the indicated window, converted to screen ...
has_cursor_hidden
Returns true if set_cursor_hidden() has been specified.
This is an abstract base class for wglGraphicsPipe and wdxGraphicsPipe; that is, those graphics pipes...
get_properties
Returns the current properties of the window.
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
Encapsulates all the communication with a particular instance of a given rendering backend.
virtual bool is_touch_event(GraphicsWindowProcCallbackData *callbackData)
Returns whether the specified event msg is a touch message.
has_undecorated
Returns true if set_undecorated() has been specified.
has_title
Returns true if the window title has been specified, false otherwise.
virtual void clear_window_procs()
Removes all Windows proc event handlers.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
This is our own Panda specialization on the default STL set.
This class is the main interface to controlling the render process.
int get_y_size() const
Returns size in pixels in the y dimension of the useful part of the window, not including decorations...
int get_x_size() const
Returns size in pixels in the x dimension of the useful part of the window, not including decorations...
get_fullscreen
Returns true if the window is in fullscreen mode.
TypeHandle is the identifier used to differentiate C++ class types.
std::wstring decode_text(const std::string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
clear_foreground
Removes the foreground specification from the properties.
virtual void close_ime()
Forces the ime window to close, if any.
clear_title
Removes the title specification from the properties.
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
set_open
Specifies whether the window should be open.
int get_x_origin() const
Returns the x coordinate of the window's top-left corner, not including decorations.
get_z_order
Returns the window's z_order.
has_foreground
Returns true if set_foreground() has been specified.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_wtext(const std::wstring &wtext)
Changes the text that is stored in the encoder.
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
set_foreground
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
virtual bool supports_window_procs() const
Returns whether this window supports adding of windows proc handlers.