15 #include "winGraphicsWindow.h" 16 #include "config_windisplay.h" 17 #include "winGraphicsPipe.h" 19 #include "graphicsPipe.h" 20 #include "keyboardButton.h" 21 #include "mouseButton.h" 22 #include "clockObject.h" 23 #include "config_util.h" 24 #include "throw_event.h" 25 #include "nativeWindowHandle.h" 30 #define WM_DPICHANGED 0x02E0 34 TypeHandle WinGraphicsWindow::WinWindowHandle::_type_handle;
36 WinGraphicsWindow::WindowHandles WinGraphicsWindow::_window_handles;
40 bool WinGraphicsWindow::_cursor_hidden =
false;
42 RECT WinGraphicsWindow::_mouse_unconfined_cliprect;
47 bool WinGraphicsWindow::_got_saved_params =
false;
48 int WinGraphicsWindow::_saved_mouse_trails;
49 BOOL WinGraphicsWindow::_saved_cursor_shadow;
50 BOOL WinGraphicsWindow::_saved_mouse_vanish;
56 int WinGraphicsWindow::_window_class_index = 0;
58 static const char *
const errorbox_title =
"Panda3D Error";
67 typedef WINUSERAPI UINT (WINAPI *tGetRawInputDeviceList)
68 (OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PUINT puiNumDevices, IN UINT cbSize);
69 typedef WINUSERAPI UINT(WINAPI *tGetRawInputData)
70 (IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PUINT pcbSize, IN UINT cbSizeHeader);
71 typedef WINUSERAPI UINT(WINAPI *tGetRawInputDeviceInfoA)
72 (IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PUINT pcbSize);
73 typedef WINUSERAPI BOOL (WINAPI *tRegisterRawInputDevices)
74 (IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize);
76 static tGetRawInputDeviceList pGetRawInputDeviceList;
77 static tGetRawInputData pGetRawInputData;
78 static tGetRawInputDeviceInfoA pGetRawInputDeviceInfoA;
79 static tRegisterRawInputDevices pRegisterRawInputDevices;
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;
110 #ifdef HAVE_WIN_TOUCHINPUT 121 ~WinGraphicsWindow() {
123 DCAST(WinWindowHandle, _window_handle)->clear_window();
148 if (!_properties.get_foreground() )
157 get_client_rect_screen(_hWnd, &view_rect);
159 SetCursorPos(view_rect.left + x, view_rect.top + y);
160 _input_devices[0].set_pointer_in_window(x, y);
164 if ((device < 1)||(device >= (
int)_input_devices.size())) {
167 _input_devices[device].set_pointer_in_window(x, y);
184 HIMC hIMC = ImmGetContext(_hWnd);
186 if (!ImmSetOpenStatus(hIMC,
false)) {
187 windisplay_cat.debug() <<
"ImmSetOpenStatus failed\n";
189 ImmReleaseContext(_hWnd, hIMC);
193 windisplay_cat.debug() <<
"success: closed ime window\n";
250 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
284 _properties.set_title(title);
287 SetWindowTextW(_hWnd, title_w.c_str());
294 ::SendMessage(_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon);
295 ::SendMessage(_hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon);
304 _properties.set_cursor_hidden(hide_cursor);
305 if (_cursor_window ==
this) {
306 hide_or_show_cursor(hide_cursor);
314 _properties.set_cursor_filename(filename);
316 _cursor = get_cursor(filename);
318 _cursor = LoadCursor(NULL, IDC_ARROW);
321 if (_cursor_window ==
this) {
329 WindowProperties::ZOrder last_z_order = _properties.get_z_order();
331 adjust_z_order(last_z_order, properties.
get_z_order());
337 if (!SetActiveWindow(_hWnd)) {
338 windisplay_cat.warning()
339 <<
"SetForegroundWindow() failed!\n";
341 _properties.set_foreground(
true);
348 if (_properties.get_minimized() != properties.
get_minimized()) {
350 ShowWindow(_hWnd, SW_MINIMIZE);
352 ShowWindow(_hWnd, SW_RESTORE);
362 if (do_fullscreen_switch()){
363 _properties.set_fullscreen(
true);
366 windisplay_cat.warning()
367 <<
"Switching to fullscreen mode failed!\n";
370 if (do_windowed_switch()){
371 _properties.set_fullscreen(
false);
374 windisplay_cat.warning()
375 <<
"Switching to windowed mode failed!\n";
380 if (properties.has_mouse_mode()) {
381 if (properties.
get_mouse_mode() != _properties.get_mouse_mode()) {
383 case WindowProperties::M_absolute:
384 case WindowProperties::M_relative:
386 if (_properties.get_mouse_mode() == WindowProperties::M_confined) {
388 windisplay_cat.info() <<
"Unconfining cursor from window\n";
390 _properties.set_mouse_mode(WindowProperties::M_absolute);
393 case WindowProperties::M_confined:
397 if (!GetWindowRect(_hWnd, &clip)) {
398 windisplay_cat.warning()
399 <<
"GetWindowRect() failed in set_properties_now. Cannot confine cursor.\n";
401 windisplay_cat.info()
402 <<
"ClipCursor() to " << clip.left <<
"," << clip.top <<
" to " 403 << clip.right <<
"," << clip.bottom << endl;
405 GetClipCursor(&_mouse_unconfined_cliprect);
406 if (!ClipCursor(&clip)) {
407 windisplay_cat.warning()
408 <<
"ClipCursor() failed in set_properties_now. Ignoring.\n";
410 _properties.set_mouse_mode(WindowProperties::M_confined);
411 windisplay_cat.info() <<
"Confining cursor to window\n";
430 void WinGraphicsWindow::
432 GraphicsWindow::trigger_flip();
438 InvalidateRect(_hWnd, NULL, FALSE);
439 _got_expose_event =
false;
441 if (windisplay_cat.is_spam()) {
442 windisplay_cat.spam()
443 <<
"InvalidateRect: " <<
this <<
"\n";
454 void WinGraphicsWindow::
456 set_cursor_out_of_window();
457 DestroyWindow(_hWnd);
461 do_fullscreen_disable();
465 _window_handles.erase(_hWnd);
468 GraphicsWindow::close_window();
478 bool WinGraphicsWindow::
480 if (_properties.has_cursor_filename()) {
481 _cursor = get_cursor(_properties.get_cursor_filename());
484 _cursor = LoadCursor(NULL, IDC_ARROW);
486 bool want_foreground = (!_properties.has_foreground() || _properties.get_foreground());
487 bool want_minimized = (_properties.has_minimized() && _properties.get_minimized()) && !want_foreground;
489 HWND old_foreground_window = GetForegroundWindow();
495 _creating_window =
this;
505 _window_handles.insert(WindowHandles::value_type(_hWnd,
this));
508 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0,
509 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
512 if (want_minimized) {
513 ShowWindow(_hWnd, SW_MINIMIZE);
514 ShowWindow(_hWnd, SW_MINIMIZE);
516 ShowWindow(_hWnd, SW_SHOWNORMAL);
517 ShowWindow(_hWnd, SW_SHOWNORMAL);
520 HWND new_foreground_window = _hWnd;
521 if (!want_foreground) {
524 new_foreground_window = old_foreground_window;
527 if (!SetActiveWindow(new_foreground_window)) {
528 windisplay_cat.warning()
529 <<
"SetActiveWindow() failed!\n";
535 if (!SetForegroundWindow(new_foreground_window)) {
536 windisplay_cat.warning()
537 <<
"SetForegroundWindow() failed!\n";
543 HIMC hIMC = ImmGetContext(_hWnd);
545 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
546 ImmReleaseContext(_hWnd, hIMC);
550 if ((pRegisterRawInputDevices)&&(_input_devices.size() > 1)) {
552 Rid.usUsagePage = 0x01;
555 Rid.hwndTarget = _hWnd;
556 pRegisterRawInputDevices(&Rid, 1,
sizeof (Rid));
560 _window_handle = NativeWindowHandle::make_win(_hWnd);
563 _window_handle =
new WinWindowHandle(
this, *_window_handle);
567 _parent_window_handle->attach_child(_window_handle);
574 #ifdef HAVE_WIN_TOUCHINPUT 575 RegisterTouchWindow(_hWnd, 0);
591 void WinGraphicsWindow::
592 initialize_input_devices() {
594 PRAWINPUTDEVICELIST pRawInputDeviceList;
596 nassertv(_input_devices.size() == 0);
599 memset(_input_device_handle, 0,
sizeof(_input_device_handle));
602 add_input_device(device);
605 if (pRegisterRawInputDevices==0) {
606 HMODULE user32 = LoadLibrary(
"user32.dll");
608 pRegisterRawInputDevices = (tRegisterRawInputDevices)GetProcAddress(user32,
"RegisterRawInputDevices");
609 pGetRawInputDeviceList = (tGetRawInputDeviceList) GetProcAddress(user32,
"GetRawInputDeviceList");
610 pGetRawInputDeviceInfoA = (tGetRawInputDeviceInfoA) GetProcAddress(user32,
"GetRawInputDeviceInfoA");
611 pGetRawInputData = (tGetRawInputData) GetProcAddress(user32,
"GetRawInputData");
615 if (pRegisterRawInputDevices==0)
return;
616 if (pGetRawInputDeviceList==0)
return;
617 if (pGetRawInputDeviceInfoA==0)
return;
618 if (pGetRawInputData==0)
return;
621 if (pGetRawInputDeviceList(NULL, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) != 0)
625 pRawInputDeviceList = (PRAWINPUTDEVICELIST)alloca(
sizeof(RAWINPUTDEVICELIST) * nInputDevices);
626 if (pRawInputDeviceList==0)
return;
629 if (pGetRawInputDeviceList(pRawInputDeviceList, &nInputDevices,
sizeof(RAWINPUTDEVICELIST)) == -1)
633 for (
int i = 0; i < (int)nInputDevices; i++) {
634 if (pRawInputDeviceList[i].dwType == RIM_TYPEMOUSE) {
637 if (pGetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)0, &nSize) != 0)
639 char *psName = (
char*)alloca(
sizeof(TCHAR) * nSize);
640 if (psName == 0)
return;
641 if (pGetRawInputDeviceInfoA(pRawInputDeviceList[i].hDevice, RIDI_DEVICENAME, (LPVOID)psName, &nSize) < 0)
645 if (strncmp(psName,
"\\??\\Root#RDP_MOU#0000#",22)!=0) {
646 if (_input_devices.size() < 32) {
647 if (strncmp(psName,
"\\??\\",4)==0) psName += 4;
648 char *pound1 = strchr(psName,
'#');
649 char *pound2 = pound1 ? strchr(pound1+1,
'#') : 0;
650 char *pound3 = pound2 ? strchr(pound2+1,
'#') : 0;
651 if (pound3) *pound3 = 0;
652 for (
char *p = psName; *p; p++) {
653 if (((*p<
'a')||(*p>
'z')) && ((*p<
'A')||(*p>
'Z')) && ((*p<
'0')||(*p>
'9'))) {
657 if (pound2) *pound2 =
'.';
658 _input_device_handle[_input_devices.size()] = pRawInputDeviceList[i].hDevice;
661 add_input_device(device);
677 void WinGraphicsWindow::
690 void WinGraphicsWindow::
703 bool WinGraphicsWindow::
704 do_reshape_request(
int x_origin,
int y_origin,
bool has_origin,
705 int x_size,
int y_size) {
706 if (windisplay_cat.is_debug()) {
707 windisplay_cat.debug()
708 <<
"Got reshape request (" << x_origin <<
", " << y_origin
709 <<
", " << has_origin <<
", " << x_size <<
", " << y_size <<
")\n";
714 if (x_origin == -2) {
715 x_origin = 0.5 * (_pipe->get_display_width() - x_size);
717 if (y_origin == -2) {
718 y_origin = 0.5 * (_pipe->get_display_height() - y_size);
720 _properties.set_origin(x_origin, y_origin);
722 if (x_origin == -1 && y_origin == -1) {
732 SetRect(&view_rect, x_origin, y_origin,
733 x_origin + x_size, y_origin + y_size);
735 GetWindowInfo(_hWnd, &wi);
736 AdjustWindowRectEx(&view_rect, wi.dwStyle, FALSE, wi.dwExStyle);
738 UINT flags = SWP_NOZORDER | SWP_NOSENDCHANGING;
741 x_origin = view_rect.left;
742 y_origin = view_rect.top;
744 x_origin = CW_USEDEFAULT;
745 y_origin = CW_USEDEFAULT;
749 SetWindowPos(_hWnd, NULL, x_origin, y_origin,
750 view_rect.right - view_rect.left,
751 view_rect.bottom - view_rect.top,
759 return do_fullscreen_resize(x_size, y_size);
769 void WinGraphicsWindow::
772 if (!GetClientRect(_hWnd, &view_rect)) {
776 if (windisplay_cat.is_debug()) {
777 windisplay_cat.debug()
778 <<
"GetClientRect() failed in handle_reshape. Ignoring.\n";
785 if (view_rect.left == 0 && view_rect.right == 0 &&
786 view_rect.bottom == 0 && view_rect.top == 0) {
787 if (windisplay_cat.is_debug()) {
788 windisplay_cat.debug()
789 <<
"GetClientRect() returned all zeroes in handle_reshape. Ignoring.\n";
794 bool result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.left));
796 result = (FALSE != ClientToScreen(_hWnd, (POINT*)&view_rect.right));
800 if (windisplay_cat.is_debug()) {
801 windisplay_cat.debug()
802 <<
"ClientToScreen() failed in handle_reshape. Ignoring.\n";
808 properties.
set_size((view_rect.right - view_rect.left),
809 (view_rect.bottom - view_rect.top));
812 properties.
set_origin(view_rect.left, view_rect.top);
814 if (windisplay_cat.is_debug()) {
815 windisplay_cat.debug()
816 <<
"reshape to origin: (" << properties.
get_x_origin() <<
"," 822 system_changed_properties(properties);
831 bool WinGraphicsWindow::
832 do_fullscreen_resize(
int x_size,
int y_size) {
833 HWND hDesktopWindow = GetDesktopWindow();
834 HDC scrnDC = GetDC(hDesktopWindow);
835 DWORD dwFullScreenBitDepth = GetDeviceCaps(scrnDC, BITSPIXEL);
836 ReleaseDC(hDesktopWindow, scrnDC);
845 if (!find_acceptable_display_mode(x_size, y_size,
846 dwFullScreenBitDepth, dm)) {
847 windisplay_cat.error()
848 <<
"window resize(" << x_size <<
", " << y_size
849 <<
") failed, no compatible fullscreen display mode found!\n";
854 SetWindowPos(_hWnd, NULL, 0,0, x_size, y_size,
855 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
856 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
858 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
859 windisplay_cat.error()
860 <<
"resize ChangeDisplaySettings failed (error code: " 861 << chg_result <<
") for specified res: " 862 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
863 <<
" x " << dm.dmBitsPerPel <<
", " 864 << dm.dmDisplayFrequency <<
" Hz\n";
868 _fullscreen_display_mode = dm;
870 windisplay_cat.info()
871 <<
"Resized fullscreen window to " << x_size <<
", " << y_size
872 <<
" bitdepth " << dwFullScreenBitDepth <<
", " 873 << dm.dmDisplayFrequency <<
"Hz\n";
875 _properties.set_size(x_size, y_size);
887 bool WinGraphicsWindow::
888 do_fullscreen_switch() {
889 if (!do_fullscreen_enable()) {
894 DWORD window_style = make_style(
true);
895 SetWindowLong(_hWnd, GWL_STYLE, window_style);
899 if (!calculate_metrics(
true, window_style, metrics, has_origin)){
903 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0, metrics.width, metrics.height,
904 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
914 bool WinGraphicsWindow::
915 do_windowed_switch() {
916 do_fullscreen_disable();
917 DWORD window_style = make_style(
false);
918 SetWindowLong(_hWnd, GWL_STYLE, window_style);
923 if (!calculate_metrics(
false, window_style, metrics, has_origin)){
931 SetWindowPos(_hWnd, HWND_NOTOPMOST, 0, 0,
932 metrics.width, metrics.height,
933 SWP_FRAMECHANGED | SWP_SHOWWINDOW);
945 void WinGraphicsWindow::
946 reconsider_fullscreen_size(DWORD &, DWORD &, DWORD &) {
959 void WinGraphicsWindow::
960 support_overlay_window(
bool) {
969 DWORD WinGraphicsWindow::
970 make_style(
bool fullscreen) {
979 DWORD window_style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
982 window_style |= WS_SYSMENU;
983 }
else if (!_properties.get_undecorated()) {
984 window_style |= (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX);
986 if (!_properties.get_fixed_size()) {
987 window_style |= (WS_SIZEBOX | WS_MAXIMIZEBOX);
989 window_style |= WS_BORDER;
1001 bool WinGraphicsWindow::
1002 calculate_metrics(
bool fullscreen, DWORD window_style,
WINDOW_METRICS &metrics,
1006 has_origin = _properties.has_origin();
1007 if (!fullscreen && has_origin) {
1008 metrics.x = _properties.get_x_origin();
1009 metrics.y = _properties.get_y_origin();
1012 if (metrics.x == -2) {
1013 metrics.x = 0.5 * (_pipe->get_display_width() - _properties.get_x_size());
1015 if (metrics.y == -2) {
1016 metrics.y = 0.5 * (_pipe->get_display_height() - _properties.get_y_size());
1018 _properties.set_origin(metrics.x, metrics.y);
1020 if (metrics.x == -1 && metrics.y == -1) {
1027 metrics.width = _properties.get_x_size();
1028 metrics.height = _properties.get_y_size();
1032 SetRect(&win_rect, metrics.x, metrics.y,
1033 metrics.x + metrics.width, metrics.y + metrics.height);
1036 if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
1037 windisplay_cat.error()
1038 <<
"AdjustWindowRect failed!" << endl;
1043 metrics.x = win_rect.left;
1044 metrics.y = win_rect.top;
1046 metrics.x = CW_USEDEFAULT;
1047 metrics.y = CW_USEDEFAULT;
1049 metrics.width = win_rect.right - win_rect.left;
1050 metrics.height = win_rect.bottom - win_rect.top;
1061 bool WinGraphicsWindow::
1062 open_graphic_window(
bool fullscreen) {
1063 DWORD window_style = make_style(fullscreen);
1066 if (_properties.has_title()) {
1068 title = encoder.
decode_text(_properties.get_title());
1071 if (!_properties.has_size()) {
1073 _properties.set_size(640, 480);
1078 if (!calculate_metrics(fullscreen, window_style, metrics, has_origin)){
1082 const WindowClass &wclass = register_window_class(_properties);
1083 HINSTANCE hinstance = GetModuleHandle(NULL);
1088 WindowHandle *window_handle = _properties.get_parent_window();
1089 if (window_handle != NULL) {
1090 windisplay_cat.info()
1091 <<
"Got parent_window " << *window_handle <<
"\n";
1093 if (os_handle != NULL) {
1094 windisplay_cat.info()
1095 <<
"os_handle type " << os_handle->get_type() <<
"\n";
1097 if (os_handle->
is_of_type(NativeWindowHandle::WinHandle::get_class_type())) {
1098 NativeWindowHandle::WinHandle *win_handle = DCAST(NativeWindowHandle::WinHandle, os_handle);
1099 _hparent = win_handle->get_handle();
1100 }
else if (os_handle->
is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
1102 _hparent = (HWND)int_handle->get_handle();
1106 _parent_window_handle = window_handle;
1108 _parent_window_handle = NULL;
1112 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(), window_style,
1113 metrics.x, metrics.y,
1116 NULL, NULL, hinstance, 0);
1121 if (!fullscreen && has_origin) {
1122 x_origin = _properties.get_x_origin();
1123 y_origin = _properties.get_y_origin();
1126 _hWnd = CreateWindowW(wclass._name.c_str(), title.c_str(),
1127 WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS ,
1129 _properties.get_x_size(), _properties.get_y_size(),
1130 _hparent, NULL, hinstance, 0);
1142 system_changed_properties(properties);
1147 windisplay_cat.error()
1148 <<
"CreateWindow() failed!" << endl;
1149 show_error_message();
1158 if (!do_fullscreen_enable()){
1173 bool WinGraphicsWindow::
1174 do_fullscreen_enable() {
1176 HWND hDesktopWindow = GetDesktopWindow();
1177 HDC scrnDC = GetDC(hDesktopWindow);
1178 DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
1182 ReleaseDC(hDesktopWindow, scrnDC);
1184 DWORD dwWidth = _properties.get_x_size();
1185 DWORD dwHeight = _properties.get_y_size();
1186 DWORD dwFullScreenBitDepth = cur_bitdepth;
1189 reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
1190 if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth, dm)) {
1191 windisplay_cat.error()
1192 <<
"Videocard has no supported display resolutions at specified res (" 1193 << dwWidth <<
" x " << dwHeight <<
" x " << dwFullScreenBitDepth <<
")\n";
1197 dm.dmPelsWidth = dwWidth;
1198 dm.dmPelsHeight = dwHeight;
1199 dm.dmBitsPerPel = dwFullScreenBitDepth;
1200 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
1202 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1203 windisplay_cat.error()
1204 <<
"ChangeDisplaySettings failed (error code: " 1205 << chg_result <<
") for specified res: " 1206 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1207 <<
" x " << dm.dmBitsPerPel <<
", " 1208 << dm.dmDisplayFrequency <<
" Hz\n";
1212 _fullscreen_display_mode = dm;
1214 _properties.set_origin(0, 0);
1215 _properties.set_size(dwWidth, dwHeight);
1228 bool WinGraphicsWindow::
1229 do_fullscreen_disable() {
1230 int chg_result = ChangeDisplaySettings(NULL, 0x0);
1231 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1232 windisplay_cat.warning()
1233 <<
"ChangeDisplaySettings failed to restore Windowed mode\n";
1245 void WinGraphicsWindow::
1247 WindowProperties::ZOrder z_order = _properties.get_z_order();
1248 adjust_z_order(z_order, z_order);
1257 void WinGraphicsWindow::
1258 adjust_z_order(WindowProperties::ZOrder last_z_order,
1259 WindowProperties::ZOrder this_z_order) {
1261 bool do_change =
false;
1263 switch (this_z_order) {
1264 case WindowProperties::Z_bottom:
1265 order = HWND_BOTTOM;
1269 case WindowProperties::Z_normal:
1270 if ((last_z_order != WindowProperties::Z_normal) &&
1273 (last_z_order != WindowProperties::Z_bottom ||
1274 _properties.get_foreground())
1279 order = HWND_NOTOPMOST;
1284 case WindowProperties::Z_top:
1285 order = HWND_TOPMOST;
1290 BOOL result = SetWindowPos(_hWnd, order, 0,0,0,0,
1291 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
1293 windisplay_cat.warning()
1294 <<
"SetWindowPos failed.\n";
1307 void WinGraphicsWindow::
1308 track_mouse_leaving(HWND hwnd) {
1314 DCAST_INTO_V(winpipe, _pipe);
1316 if (winpipe->_pfnTrackMouseEvent != NULL) {
1317 TRACKMOUSEEVENT tme = {
1318 sizeof(TRACKMOUSEEVENT),
1325 BOOL bSucceeded = winpipe->_pfnTrackMouseEvent(&tme);
1327 if ((!bSucceeded) && windisplay_cat.is_debug()) {
1328 windisplay_cat.debug()
1329 <<
"TrackMouseEvent failed!, LastError=" << GetLastError() << endl;
1332 _tracking_mouse_leaving =
true;
1342 void WinGraphicsWindow::
1344 if (SetFocus(_hWnd) == NULL && GetLastError() != 0) {
1350 if (_parent_window_handle != NULL && _window_handle != NULL) {
1351 _parent_window_handle->request_keyboard_focus(_window_handle);
1354 windisplay_cat.error()
1355 <<
"SetFocus failed: " << GetLastError() <<
"\n";
1389 if (windisplay_cat.is_spam()) {
1390 windisplay_cat.spam()
1392 <<
" window_proc(" << (
void *)
this <<
", " << hwnd <<
", " 1393 << msg <<
", " << wparam <<
", " << lparam <<
")\n";
1400 if (!_tracking_mouse_leaving) {
1402 track_mouse_leaving(hwnd);
1404 set_cursor_in_window();
1405 if(handle_mouse_motion(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))))
1410 handle_raw_input((HRAWINPUT)lparam);
1414 _tracking_mouse_leaving =
false;
1415 handle_mouse_exit();
1416 set_cursor_out_of_window();
1421 track_mouse_leaving(hwnd);
1422 ClearToBlack(hwnd, _properties);
1425 GetCursorPos(&cpos);
1426 ScreenToClient(hwnd, &cpos);
1428 GetClientRect(hwnd, &clientRect);
1429 if (PtInRect(&clientRect,cpos)) {
1430 set_cursor_in_window();
1432 set_cursor_out_of_window();
1465 if (!close_request_event.empty()) {
1468 throw_event(close_request_event);
1476 system_changed_properties(properties);
1483 case WM_CHILDACTIVATE:
1484 if (windisplay_cat.is_debug()) {
1485 windisplay_cat.debug()
1486 <<
"WM_CHILDACTIVATE: " << hwnd <<
"\n";
1491 if (windisplay_cat.is_debug()) {
1492 windisplay_cat.debug()
1493 <<
"WM_ACTIVATE: " << hwnd <<
", " << wparam <<
", " << lparam <<
"\n";
1496 if ((wparam & 0xffff) != WA_INACTIVE)
1504 ChangeDisplaySettings(&_fullscreen_display_mode, CDS_FULLSCREEN);
1505 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
1506 const DEVMODE &dm = _fullscreen_display_mode;
1507 windisplay_cat.error()
1508 <<
"restore ChangeDisplaySettings failed (error code: " 1509 << chg_result <<
") for specified res: " 1510 << dm.dmPelsWidth <<
" x " << dm.dmPelsHeight
1511 <<
" x " << dm.dmBitsPerPel <<
", " 1512 << dm.dmDisplayFrequency <<
" Hz\n";
1516 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0, SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
1517 fullscreen_restored(properties);
1532 ShowWindow(_hWnd, SW_MINIMIZE);
1534 do_fullscreen_disable();
1535 fullscreen_minimized(properties);
1540 system_changed_properties(properties);
1544 if (windisplay_cat.is_debug()) {
1545 windisplay_cat.debug()
1546 <<
"WM_SIZE: " << hwnd <<
", " << wparam <<
"\n";
1550 if (_hWnd != NULL) {
1555 case WM_EXITSIZEMOVE:
1559 case WM_WINDOWPOSCHANGED:
1567 if (GetUpdateRect(_hWnd, NULL,
false)) {
1568 if (windisplay_cat.is_spam()) {
1569 windisplay_cat.spam()
1570 <<
"Got update regions: " <<
this <<
"\n";
1572 _got_expose_event =
true;
1576 case WM_LBUTTONDOWN:
1577 if (_lost_keypresses) {
1578 resend_lost_keypresses();
1581 _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
1588 case WM_MBUTTONDOWN:
1589 if (_lost_keypresses) {
1590 resend_lost_keypresses();
1593 _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
1599 case WM_RBUTTONDOWN:
1600 if (_lost_keypresses) {
1601 resend_lost_keypresses();
1604 _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
1610 case WM_XBUTTONDOWN:
1612 if (_lost_keypresses) {
1613 resend_lost_keypresses();
1616 int whichButton = GET_XBUTTON_WPARAM(wparam);
1617 _input_devices[0].set_pointer_in_window(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
1618 if (whichButton == XBUTTON1) {
1620 }
else if (whichButton == XBUTTON2) {
1627 if (_lost_keypresses) {
1628 resend_lost_keypresses();
1635 if (_lost_keypresses) {
1636 resend_lost_keypresses();
1643 if (_lost_keypresses) {
1644 resend_lost_keypresses();
1652 if (_lost_keypresses) {
1653 resend_lost_keypresses();
1656 int whichButton = GET_XBUTTON_WPARAM(wparam);
1657 if (whichButton == XBUTTON1) {
1659 }
else if (whichButton == XBUTTON2) {
1667 int delta = GET_WHEEL_DELTA_WPARAM(wparam);
1670 GetCursorPos(&point);
1671 ScreenToClient(hwnd, &point);
1672 double time = get_message_time();
1678 delta -= WHEEL_DELTA;
1684 delta += WHEEL_DELTA;
1692 case WM_IME_SETCONTEXT:
1696 windisplay_cat.debug() <<
"hwnd = " << hwnd <<
" and GetFocus = " << GetFocus() << endl;
1697 _ime_hWnd = ImmGetDefaultIMEWnd(hwnd);
1698 if (::SendMessage(_ime_hWnd, WM_IME_CONTROL, IMC_CLOSESTATUSWINDOW, 0))
1700 windisplay_cat.debug() <<
"SendMessage failed for " << _ime_hWnd << endl;
1702 windisplay_cat.debug() <<
"SendMessage Succeeded for " << _ime_hWnd << endl;
1704 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1705 lparam &= ~ISC_SHOWUIALL;
1706 if (ImmIsUIMessage(_ime_hWnd, msg, wparam, lparam))
1707 windisplay_cat.debug() <<
"wparam is " << wparam <<
", lparam is " << lparam << endl;
1713 if (wparam == IMN_SETOPENSTATUS) {
1714 HIMC hIMC = ImmGetContext(hwnd);
1715 nassertr(hIMC != 0, 0);
1716 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
1718 _ime_active =
false;
1722 COMPOSITIONFORM comf;
1724 ImmGetCompositionWindow(hIMC, &comf);
1725 ImmGetCandidateWindow(hIMC, 0, &canf);
1726 windisplay_cat.debug() <<
1727 "comf style " << comf.dwStyle <<
1728 " comf point: x" << comf.ptCurrentPos.x <<
",y " << comf.ptCurrentPos.y <<
1729 " comf rect: l " << comf.rcArea.left <<
",t " << comf.rcArea.top <<
",r " <<
1730 comf.rcArea.right <<
",b " << comf.rcArea.bottom << endl;
1731 windisplay_cat.debug() <<
1732 "canf style " << canf.dwStyle <<
1733 " canf point: x" << canf.ptCurrentPos.x <<
",y " << canf.ptCurrentPos.y <<
1734 " canf rect: l " << canf.rcArea.left <<
",t " << canf.rcArea.top <<
",r " <<
1735 canf.rcArea.right <<
",b " << canf.rcArea.bottom << endl;
1736 comf.dwStyle = CFS_POINT;
1737 comf.ptCurrentPos.x = 2000;
1738 comf.ptCurrentPos.y = 2000;
1740 canf.dwStyle = CFS_EXCLUDE;
1742 canf.ptCurrentPos.x = 0;
1743 canf.ptCurrentPos.y = 0;
1744 canf.rcArea.left = 0;
1745 canf.rcArea.top = 0;
1746 canf.rcArea.right = 640;
1747 canf.rcArea.bottom = 480;
1750 comf.rcArea.left = 200;
1751 comf.rcArea.top = 200;
1752 comf.rcArea.right = 0;
1753 comf.rcArea.bottom = 0;
1756 if (ImmSetCompositionWindow(hIMC, &comf))
1757 windisplay_cat.debug() <<
"set composition form: success\n";
1758 for (
int i=0; i<3; ++i) {
1759 if (ImmSetCandidateWindow(hIMC, &canf))
1760 windisplay_cat.debug() <<
"set candidate form: success\n";
1765 ImmReleaseContext(hwnd, hIMC);
1769 case WM_IME_STARTCOMPOSITION:
1770 support_overlay_window(
true);
1774 case WM_IME_ENDCOMPOSITION:
1775 support_overlay_window(
false);
1776 _ime_active =
false;
1780 _input_devices[0].candidate(ws, 0, 0, 0);
1785 case WM_IME_COMPOSITION:
1797 HIMC hIMC = ImmGetContext(hwnd);
1798 nassertr(hIMC != 0, 0);
1800 DWORD result_size = 0;
1801 static const int ime_buffer_size = 256;
1802 static const int ime_buffer_size_bytes = ime_buffer_size /
sizeof(wchar_t);
1803 wchar_t ime_buffer[ime_buffer_size];
1804 size_t cursor_pos, delta_start;
1806 if (lparam & GCS_RESULTSTR) {
1807 result_size = ImmGetCompositionStringW(hIMC, GCS_RESULTSTR,
1808 ime_buffer, ime_buffer_size_bytes);
1809 size_t num_chars = result_size /
sizeof(wchar_t);
1810 for (
size_t i = 0; i < num_chars; ++i) {
1811 _input_devices[0].keystroke(ime_buffer[i]);
1815 if (lparam & GCS_COMPSTR) {
1816 result_size = ImmGetCompositionStringW(hIMC, GCS_CURSORPOS, NULL, 0);
1817 cursor_pos = result_size & 0xffff;
1819 result_size = ImmGetCompositionStringW(hIMC, GCS_DELTASTART, NULL, 0);
1820 delta_start = result_size & 0xffff;
1821 result_size = ImmGetCompositionStringW(hIMC, GCS_COMPSTR, ime_buffer, ime_buffer_size);
1822 size_t num_chars = result_size /
sizeof(wchar_t);
1824 _input_devices[0].candidate(wstring(ime_buffer, num_chars),
1825 min(cursor_pos, delta_start),
1826 max(cursor_pos, delta_start),
1829 ImmReleaseContext(hwnd, hIMC);
1846 _input_devices[0].keystroke(wparam);
1851 if (_lost_keypresses) {
1852 resend_lost_keypresses();
1854 if (windisplay_cat.is_debug()) {
1855 windisplay_cat.debug()
1856 <<
"syskeydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1863 GetCursorPos(&point);
1864 ScreenToClient(hwnd, &point);
1865 handle_keypress(lookup_key(wparam), point.x, point.y,
1866 get_message_time());
1868 if ((lparam & 0x40000000) == 0) {
1869 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1880 if (wparam == VK_MENU) {
1881 if ((GetKeyState(VK_LMENU) & 0x8000) != 0 && ! _lalt_down) {
1882 handle_keypress(KeyboardButton::lalt(), point.x, point.y,
1883 get_message_time());
1886 if ((GetKeyState(VK_RMENU) & 0x8000) != 0 && ! _ralt_down) {
1887 handle_keypress(KeyboardButton::ralt(), point.x, point.y,
1888 get_message_time());
1892 if (wparam == VK_F10) {
1901 if (wparam == SC_KEYMENU) {
1915 if (_lost_keypresses) {
1916 resend_lost_keypresses();
1918 if (windisplay_cat.is_debug()) {
1919 windisplay_cat.debug()
1920 <<
"keydown: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
1926 if ((lparam & 0x40000000) == 0) {
1928 GetCursorPos(&point);
1929 ScreenToClient(hwnd, &point);
1930 handle_keypress(lookup_key(wparam), point.x, point.y,
1931 get_message_time());
1932 handle_raw_keypress(lookup_raw_key(lparam), get_message_time());
1938 if (wparam == VK_SHIFT) {
1939 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0 && ! _lshift_down) {
1940 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
1941 get_message_time());
1942 _lshift_down =
true;
1944 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0 && ! _rshift_down) {
1945 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
1946 get_message_time());
1947 _rshift_down =
true;
1949 }
else if(wparam == VK_CONTROL) {
1950 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0 && ! _lcontrol_down) {
1951 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
1952 get_message_time());
1953 _lcontrol_down =
true;
1955 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0 && ! _rcontrol_down) {
1956 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
1957 get_message_time());
1958 _rcontrol_down =
true;
1964 if ((wparam==
'V') && (GetKeyState(VK_CONTROL) < 0) &&
1965 !_input_devices.empty()) {
1969 if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) {
1972 hglb = GetClipboardData(CF_TEXT);
1974 lptstr = (
char *) GlobalLock(hglb);
1975 if (lptstr != NULL) {
1977 for (pChar=lptstr; *pChar!=NULL; pChar++) {
1978 _input_devices[0].keystroke((uchar)*pChar);
1990 GetCursorPos(&point);
1991 ScreenToClient(hwnd, &point);
1992 handle_keypress(lookup_key(wparam), point.x, point.y,
1993 get_message_time());
2007 if (wparam == VK_SHIFT) {
2008 if (((GetKeyState(VK_LSHIFT) & 0x8000) != 0) && ! _lshift_down ) {
2009 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
2010 get_message_time());
2011 _lshift_down =
true;
2012 }
else if (((GetKeyState(VK_RSHIFT) & 0x8000) != 0) && ! _rshift_down ) {
2013 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
2014 get_message_time());
2015 _rshift_down =
true;
2017 if ((GetKeyState(VK_LSHIFT) & 0x8000) != 0) {
2018 handle_keypress(KeyboardButton::lshift(), point.x, point.y,
2019 get_message_time());
2021 if ((GetKeyState(VK_RSHIFT) & 0x8000) != 0) {
2022 handle_keypress(KeyboardButton::rshift(), point.x, point.y,
2023 get_message_time());
2026 }
else if(wparam == VK_CONTROL) {
2027 if (((GetKeyState(VK_LCONTROL) & 0x8000) != 0) && ! _lcontrol_down ) {
2028 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2029 get_message_time());
2030 _lcontrol_down =
true;
2031 }
else if (((GetKeyState(VK_RCONTROL) & 0x8000) != 0) && ! _rcontrol_down ) {
2032 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2033 get_message_time());
2034 _rcontrol_down =
true;
2036 if ((GetKeyState(VK_LCONTROL) & 0x8000) != 0) {
2037 handle_keypress(KeyboardButton::lcontrol(), point.x, point.y,
2038 get_message_time());
2040 if ((GetKeyState(VK_RCONTROL) & 0x8000) != 0) {
2041 handle_keypress(KeyboardButton::rcontrol(), point.x, point.y,
2042 get_message_time());
2051 if (_lost_keypresses) {
2052 resend_lost_keypresses();
2054 if (windisplay_cat.is_debug()) {
2055 windisplay_cat.debug()
2056 <<
"keyup: " << wparam <<
" (" << lookup_key(wparam) <<
")\n";
2058 handle_keyrelease(lookup_key(wparam), get_message_time());
2059 handle_raw_keyrelease(lookup_raw_key(lparam), get_message_time());
2065 if (wparam == VK_SHIFT) {
2066 if ((GetKeyState(VK_LSHIFT) & 0x8000) == 0 && _lshift_down) {
2067 handle_keyrelease(KeyboardButton::lshift(), get_message_time());
2068 _lshift_down =
false;
2070 if ((GetKeyState(VK_RSHIFT) & 0x8000) == 0 && _rshift_down) {
2071 handle_keyrelease(KeyboardButton::rshift(), get_message_time());
2072 _rshift_down =
false;
2074 }
else if(wparam == VK_CONTROL) {
2075 if ((GetKeyState(VK_LCONTROL) & 0x8000) == 0 && _lcontrol_down) {
2076 handle_keyrelease(KeyboardButton::lcontrol(), get_message_time());
2077 _lcontrol_down =
false;
2079 if ((GetKeyState(VK_RCONTROL) & 0x8000) == 0 && _rcontrol_down) {
2080 handle_keyrelease(KeyboardButton::rcontrol(), get_message_time());
2081 _rcontrol_down =
false;
2083 }
else if(wparam == VK_MENU) {
2084 if ((GetKeyState(VK_LMENU) & 0x8000) == 0 && _lalt_down) {
2085 handle_keyrelease(KeyboardButton::lalt(), get_message_time());
2088 if ((GetKeyState(VK_RMENU) & 0x8000) == 0 && _ralt_down) {
2089 handle_keyrelease(KeyboardButton::ralt(), get_message_time());
2096 if (windisplay_cat.is_debug()) {
2097 windisplay_cat.debug()
2101 _input_devices[0].focus_lost(get_message_time());
2103 system_changed_properties(properties);
2127 if (windisplay_cat.is_debug()) {
2128 windisplay_cat.debug()
2132 if (_lost_keypresses) {
2133 resend_lost_keypresses();
2137 system_changed_properties(properties);
2141 if (windisplay_cat.is_debug()) {
2142 windisplay_cat.debug()
2146 system_changed_properties(properties);
2150 if (windisplay_cat.is_debug()) {
2151 windisplay_cat.debug()
2155 system_changed_properties(properties);
2161 if (windisplay_cat.is_debug()) {
2162 windisplay_cat.debug() <<
"DPI changed to " << LOWORD(wparam);
2164 if (LOWORD(wparam) != HIWORD(wparam)) {
2165 windisplay_cat.debug(
false) <<
"x" << HIWORD(wparam) <<
"\n";
2167 windisplay_cat.debug(
false) <<
"\n";
2172 if (!_properties.get_fixed_size() && dpi_window_resize) {
2173 RECT &rect = *(LPRECT)lparam;
2174 SetWindowPos(_hWnd, HWND_TOP, rect.left, rect.top,
2175 rect.right - rect.left, rect.bottom - rect.top,
2176 SWP_NOZORDER | SWP_NOACTIVATE);
2180 #ifdef HAVE_WIN_TOUCHINPUT 2182 _numTouches = LOWORD(wparam);
2183 if(_numTouches > MAX_TOUCHES)
2184 _numTouches = MAX_TOUCHES;
2185 GetTouchInputInfo((HTOUCHINPUT)lparam, _numTouches, _touches,
sizeof(TOUCHINPUT));
2186 CloseTouchInputHandle((HTOUCHINPUT)lparam);
2192 for ( WinProcClasses::iterator it=_window_proc_classes.begin() ; it != _window_proc_classes.end(); it++ ){
2193 (*it)->wnd_proc(
this, hwnd, msg, wparam, lparam);
2196 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);
2219 return _creating_window->
window_proc(hwnd, msg, wparam, lparam);
2224 return DefWindowProcW(hwnd, msg, wparam, lparam);
2232 void WinGraphicsWindow::
2236 if (!GetMessage(&msg, NULL, 0, 0)) {
2243 TranslateMessage(&msg);
2245 DispatchMessage(&msg);
2257 void WinGraphicsWindow::
2258 resend_lost_keypresses() {
2259 nassertv(_lost_keypresses);
2264 _lost_keypresses =
false;
2274 void WinGraphicsWindow::
2276 bool hide_cursor =
false;
2280 if (_got_saved_params) {
2281 SystemParametersInfo(SPI_SETMOUSETRAILS, NULL,
2282 (PVOID)_saved_mouse_trails, NULL);
2283 SystemParametersInfo(SPI_SETCURSORSHADOW, NULL,
2284 (PVOID)_saved_cursor_shadow, NULL);
2285 SystemParametersInfo(SPI_SETMOUSEVANISH, NULL,
2286 (PVOID)_saved_mouse_vanish, NULL);
2287 _got_saved_params =
false;
2300 if (!_got_saved_params) {
2301 SystemParametersInfo(SPI_GETMOUSETRAILS, NULL,
2302 &_saved_mouse_trails, NULL);
2303 SystemParametersInfo(SPI_GETCURSORSHADOW, NULL,
2304 &_saved_cursor_shadow, NULL);
2305 SystemParametersInfo(SPI_GETMOUSEVANISH, NULL,
2306 &_saved_mouse_vanish, NULL);
2307 _got_saved_params =
true;
2309 SystemParametersInfo(SPI_SETMOUSETRAILS, NULL, (PVOID)0, NULL);
2310 SystemParametersInfo(SPI_SETCURSORSHADOW, NULL, (PVOID)
false, NULL);
2311 SystemParametersInfo(SPI_SETMOUSEVANISH, NULL, (PVOID)
false, NULL);
2314 SetCursor(to_window->_cursor);
2317 hide_or_show_cursor(hide_cursor);
2319 _cursor_window = to_window;
2330 void WinGraphicsWindow::
2331 hide_or_show_cursor(
bool hide_cursor) {
2333 if (!_cursor_hidden) {
2335 _cursor_hidden =
true;
2338 if (_cursor_hidden) {
2340 _cursor_hidden =
false;
2346 #define MIN_REFRESH_RATE 60 2348 #define ACCEPTABLE_REFRESH_RATE(RATE) ((RATE >= MIN_REFRESH_RATE) || (RATE==0) || (RATE==1)) 2357 bool WinGraphicsWindow::
2358 find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
2363 ZeroMemory(&cur_dm,
sizeof(cur_dm));
2364 cur_dm.dmSize =
sizeof(cur_dm);
2365 EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &cur_dm);
2368 int saved_modenum = -1;
2371 ZeroMemory(&dm,
sizeof(dm));
2372 dm.dmSize =
sizeof(dm);
2374 if (!EnumDisplaySettings(NULL, modenum, &dm)) {
2378 if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
2379 (dm.dmBitsPerPel == bpp)) {
2382 if (dm.dmDisplayFrequency == cur_dm.dmDisplayFrequency) {
2384 }
else if (saved_modenum == -1) {
2385 saved_modenum = modenum;
2393 if (saved_modenum != -1) {
2394 ZeroMemory(&dm,
sizeof(dm));
2395 dm.dmSize =
sizeof(dm);
2397 if (EnumDisplaySettings(NULL, saved_modenum, &dm)) {
2412 void WinGraphicsWindow::
2413 show_error_message(DWORD message_id) {
2414 LPTSTR message_buffer;
2416 if (message_id == 0) {
2417 message_id = GetLastError();
2420 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2422 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2423 (LPTSTR)&message_buffer,
2425 MessageBox(GetDesktopWindow(), message_buffer, _T(errorbox_title), MB_OK);
2426 windisplay_cat.fatal() <<
"System error msg: " << message_buffer << endl;
2427 LocalFree(message_buffer);
2435 void WinGraphicsWindow::
2436 handle_keypress(
ButtonHandle key,
int x,
int y,
double time) {
2437 _input_devices[0].set_pointer_in_window(x, y);
2439 _input_devices[0].button_down(key, time);
2450 void WinGraphicsWindow::
2453 _input_devices[0].button_resume_down(key, time);
2462 void WinGraphicsWindow::
2465 _input_devices[0].button_up(key, time);
2474 void WinGraphicsWindow::
2477 _input_devices[0].raw_button_down(key, time);
2486 void WinGraphicsWindow::
2489 _input_devices[0].raw_button_up(key, time);
2500 lookup_key(WPARAM wparam)
const {
2505 case VK_BACK:
return KeyboardButton::backspace();
2506 case VK_DELETE:
return KeyboardButton::del();
2507 case VK_ESCAPE:
return KeyboardButton::escape();
2508 case VK_SPACE:
return KeyboardButton::space();
2509 case VK_UP:
return KeyboardButton::up();
2510 case VK_DOWN:
return KeyboardButton::down();
2511 case VK_LEFT:
return KeyboardButton::left();
2512 case VK_RIGHT:
return KeyboardButton::right();
2519 case VK_TAB:
return KeyboardButton::tab();
2520 case VK_PRIOR:
return KeyboardButton::page_up();
2521 case VK_NEXT:
return KeyboardButton::page_down();
2522 case VK_HOME:
return KeyboardButton::home();
2523 case VK_END:
return KeyboardButton::end();
2524 case VK_F1:
return KeyboardButton::f1();
2525 case VK_F2:
return KeyboardButton::f2();
2526 case VK_F3:
return KeyboardButton::f3();
2527 case VK_F4:
return KeyboardButton::f4();
2528 case VK_F5:
return KeyboardButton::f5();
2529 case VK_F6:
return KeyboardButton::f6();
2530 case VK_F7:
return KeyboardButton::f7();
2531 case VK_F8:
return KeyboardButton::f8();
2532 case VK_F9:
return KeyboardButton::f9();
2533 case VK_F10:
return KeyboardButton::f10();
2534 case VK_F11:
return KeyboardButton::f11();
2535 case VK_F12:
return KeyboardButton::f12();
2536 case VK_INSERT:
return KeyboardButton::insert();
2537 case VK_CAPITAL:
return KeyboardButton::caps_lock();
2538 case VK_NUMLOCK:
return KeyboardButton::num_lock();
2539 case VK_SCROLL:
return KeyboardButton::scroll_lock();
2540 case VK_PAUSE:
return KeyboardButton::pause();
2541 case VK_SNAPSHOT:
return KeyboardButton::print_screen();
2543 case VK_SHIFT:
return KeyboardButton::shift();
2544 case VK_LSHIFT:
return KeyboardButton::lshift();
2545 case VK_RSHIFT:
return KeyboardButton::rshift();
2547 case VK_CONTROL:
return KeyboardButton::control();
2548 case VK_LCONTROL:
return KeyboardButton::lcontrol();
2549 case VK_RCONTROL:
return KeyboardButton::rcontrol();
2551 case VK_MENU:
return KeyboardButton::alt();
2552 case VK_LMENU:
return KeyboardButton::lalt();
2553 case VK_RMENU:
return KeyboardButton::ralt();
2556 int key = MapVirtualKey(wparam, 2);
2557 if (isascii(key) && key != 0) {
2585 lookup_raw_key(LPARAM lparam)
const {
2586 unsigned char vsc = (lparam & 0xff0000) >> 16;
2588 if (lparam & 0x1000000) {
2591 case 28:
return KeyboardButton::enter();
2592 case 29:
return KeyboardButton::rcontrol();
2594 case 55:
return KeyboardButton::print_screen();
2595 case 56:
return KeyboardButton::ralt();
2596 case 69:
return KeyboardButton::num_lock();
2597 case 71:
return KeyboardButton::home();
2598 case 72:
return KeyboardButton::up();
2599 case 73:
return KeyboardButton::page_up();
2600 case 75:
return KeyboardButton::left();
2601 case 77:
return KeyboardButton::right();
2602 case 79:
return KeyboardButton::end();
2603 case 80:
return KeyboardButton::down();
2604 case 81:
return KeyboardButton::page_down();
2605 case 82:
return KeyboardButton::insert();
2606 case 83:
return KeyboardButton::del();
2607 case 91:
return KeyboardButton::lmeta();
2608 case 92:
return KeyboardButton::rmeta();
2609 case 93:
return KeyboardButton::menu();
2616 KeyboardButton::escape(),
2629 KeyboardButton::backspace(),
2630 KeyboardButton::tab(),
2643 KeyboardButton::enter(),
2644 KeyboardButton::lcontrol(),
2657 KeyboardButton::lshift(),
2669 KeyboardButton::rshift(),
2671 KeyboardButton::lalt(),
2672 KeyboardButton::space(),
2673 KeyboardButton::caps_lock(),
2674 KeyboardButton::f1(),
2675 KeyboardButton::f2(),
2676 KeyboardButton::f3(),
2677 KeyboardButton::f4(),
2678 KeyboardButton::f5(),
2679 KeyboardButton::f6(),
2680 KeyboardButton::f7(),
2681 KeyboardButton::f8(),
2682 KeyboardButton::f9(),
2683 KeyboardButton::f10(),
2684 KeyboardButton::pause(),
2685 KeyboardButton::scroll_lock(),
2700 return raw_map[vsc];
2705 case 87:
return KeyboardButton::f11();
2706 case 88:
return KeyboardButton::f12();
2721 get_keyboard_map()
const {
2726 unsigned short ex_vsc[] = {0x57, 0x58,
2727 0x011c, 0x011d, 0x0135, 0x0137, 0x0138, 0x0145, 0x0147, 0x0148, 0x0149, 0x014b, 0x014d, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x015b, 0x015c, 0x015d};
2729 for (
int k = 1; k < 84 + 17; ++k) {
2731 vsc = ex_vsc[k - 84];
2736 UINT lparam = vsc << 16;
2744 button = KeyboardButton::pause();
2746 }
else if (vsc >= 0x47 && vsc <= 0x53) {
2748 button = raw_button;
2760 UINT vk = MapVirtualKeyA(vsc, MAPVK_VSC_TO_VK_EX);
2761 button = lookup_key(vk);
2767 int len = GetKeyNameTextW(lparam, text, 256);
2781 void WinGraphicsWindow::
2782 handle_raw_input(HRAWINPUT hraw) {
2789 if (pGetRawInputData(hraw, RID_INPUT, NULL, &dwSize,
sizeof(RAWINPUTHEADER)) == -1) {
2793 lpb = (LPBYTE)alloca(
sizeof(LPBYTE) * dwSize);
2798 if (pGetRawInputData(hraw, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize) {
2802 RAWINPUT *raw = (RAWINPUT *)lpb;
2803 if (raw->header.hDevice == 0) {
2807 for (
int i = 1; i < (int)(_input_devices.size()); ++i) {
2808 if (_input_device_handle[i] == raw->header.hDevice) {
2809 int adjx = raw->data.mouse.lLastX;
2810 int adjy = raw->data.mouse.lLastY;
2812 if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
2813 _input_devices[i].set_pointer_in_window(adjx, adjy);
2815 int oldx = _input_devices[i].get_raw_pointer().get_x();
2816 int oldy = _input_devices[i].get_raw_pointer().get_y();
2817 _input_devices[i].set_pointer_in_window(oldx + adjx, oldy + adjy);
2820 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {
2823 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) {
2826 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) {
2829 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) {
2832 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) {
2835 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) {
2838 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
2841 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
2844 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
2847 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
2859 bool WinGraphicsWindow::
2860 handle_mouse_motion(
int x,
int y) {
2861 _input_devices[0].set_pointer_in_window(x, y);
2870 void WinGraphicsWindow::
2871 handle_mouse_exit() {
2873 _input_devices[0].set_pointer_out_of_window();
2883 HICON WinGraphicsWindow::
2884 get_icon(
const Filename &filename) {
2886 IconFilenames::iterator fi = _icon_filenames.find(filename);
2887 if (fi != _icon_filenames.end()) {
2888 return (HICON)((*fi).second);
2903 windisplay_cat.warning()
2904 <<
"Could not find icon filename " << filename <<
"\n";
2908 fi = _icon_filenames.find(resolved);
2909 if (fi != _icon_filenames.end()) {
2910 _icon_filenames[filename] = (*fi).second;
2911 return (HICON)((*fi).second);
2916 HANDLE h = LoadImage(NULL, os.c_str(),
2917 IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2919 windisplay_cat.warning()
2920 <<
"windows icon filename '" << os <<
"' could not be loaded!!\n";
2923 _icon_filenames[filename] = h;
2924 _icon_filenames[resolved] = h;
2935 HCURSOR WinGraphicsWindow::
2936 get_cursor(
const Filename &filename) {
2938 if (filename.empty()) {
2943 IconFilenames::iterator fi = _cursor_filenames.find(filename);
2944 if (fi != _cursor_filenames.end()) {
2945 return (HCURSOR)((*fi).second);
2956 windisplay_cat.warning()
2957 <<
"Could not find cursor filename " << filename <<
"\n";
2960 fi = _cursor_filenames.find(resolved);
2961 if (fi != _cursor_filenames.end()) {
2962 _cursor_filenames[filename] = (*fi).second;
2963 return (HCURSOR)((*fi).second);
2968 HANDLE h = LoadImage(NULL, os.c_str(),
2969 IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
2971 windisplay_cat.warning()
2972 <<
"windows cursor filename '" << os <<
"' could not be loaded!!\n";
2973 show_error_message();
2976 _cursor_filenames[filename] = h;
2977 _cursor_filenames[resolved] = h;
2981 static HCURSOR get_cursor(
const Filename &filename);
2990 const WinGraphicsWindow::WindowClass &WinGraphicsWindow::
2992 WindowClass wcreg(props);
2993 wostringstream wclass_name;
2994 wclass_name << L
"WinGraphicsWindow" << _window_class_index;
2995 wcreg._name = wclass_name.str();
2997 pair<WindowClasses::iterator, bool> found = _window_classes.insert(wcreg);
2998 const WindowClass &wclass = (*found.first);
3000 if (!found.second) {
3006 _window_class_index++;
3010 HINSTANCE instance = GetModuleHandle(NULL);
3013 ZeroMemory(&wc,
sizeof(wc));
3014 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
3016 wc.hInstance = instance;
3018 wc.hIcon = wclass._icon;
3020 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
3021 wc.lpszMenuName = NULL;
3022 wc.lpszClassName = wclass._name.c_str();
3024 if (!RegisterClassW(&wc)) {
3025 windisplay_cat.error()
3026 <<
"could not register window class " << wclass._name <<
"!" << endl;
3038 WinGraphicsWindow::WinWindowHandle::
3053 void WinGraphicsWindow::WinWindowHandle::
3064 void WinGraphicsWindow::WinWindowHandle::
3065 receive_windows_message(
unsigned int msg,
int wparam,
int lparam) {
3066 if (_window != NULL) {
3073 void PrintErrorMessage(DWORD msgID) {
3074 LPTSTR pMessageBuffer;
3076 if (msgID==PRINT_LAST_ERROR)
3077 msgID=GetLastError();
3079 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
3081 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3082 (LPTSTR) &pMessageBuffer,
3084 MessageBox(GetDesktopWindow(),pMessageBuffer,_T(errorbox_title),MB_OK);
3085 windisplay_cat.fatal() <<
"System error msg: " << pMessageBuffer << endl;
3086 LocalFree( pMessageBuffer );
3092 if (windisplay_cat.is_debug()) {
3093 windisplay_cat.debug()
3094 <<
"Skipping ClearToBlack, no origin specified yet.\n";
3099 if (windisplay_cat.is_debug()) {
3100 windisplay_cat.debug()
3101 <<
"ClearToBlack(" << hWnd <<
", " << props <<
")\n";
3104 HDC hDC=GetDC(hWnd);
3110 FillRect(hDC,&clrRect,(HBRUSH)GetStockObject(BLACK_BRUSH));
3111 ReleaseDC(hWnd,hDC);
3121 void get_client_rect_screen(HWND hwnd, RECT *view_rect) {
3122 GetClientRect(hwnd, view_rect);
3125 ul.x = view_rect->left;
3126 ul.y = view_rect->top;
3127 lr.x = view_rect->right;
3128 lr.y = view_rect->bottom;
3130 ClientToScreen(hwnd, &ul);
3131 ClientToScreen(hwnd, &lr);
3133 view_rect->left = ul.x;
3134 view_rect->top = ul.y;
3135 view_rect->right = lr.x;
3136 view_rect->bottom = lr.y;
3147 nassertv(wnd_proc != NULL);
3158 nassertv(wnd_proc != NULL);
3169 _window_proc_classes.clear();
3190 #ifdef HAVE_WIN_TOUCHINPUT 3191 return callbackData->get_msg() == WM_TOUCH;
3205 #ifdef HAVE_WIN_TOUCHINPUT 3220 #ifdef HAVE_WIN_TOUCHINPUT 3221 TOUCHINPUT ti = _touches[index];
3223 point.x = TOUCH_COORD_TO_PIXEL(ti.x);
3224 point.y = TOUCH_COORD_TO_PIXEL(ti.y);
3225 ScreenToClient(_hWnd, &point);
3230 ret.set_id(ti.dwID);
3231 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...
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...
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
MouseMode get_mouse_mode() const
See set_mouse_mode().
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.
bool get_foreground() const
Returns true if the window is in the foreground.
void clear_foreground()
Removes the foreground specification from the properties.
This class can be used to convert text between multiple representations, e.g.
virtual TouchInfo get_touch_info(int index)
Returns the TouchInfo object describing the specified touch.
virtual void begin_flip()
This function will be called within the draw thread after end_frame() has been called on all windows...
ZOrder get_z_order() const
Returns the window's z_order.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
bool has_icon_filename() const
Returns true if set_icon_filename() has been specified.
bool get_minimized() const
Returns true if the window is minimized.
wstring decode_text(const string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system...
virtual bool move_pointer(int device, int x, int y)
Forces the pointer to the indicated position within the window, if possible.
void set_size(const LVector2i &size)
Specifies the requested size of the window, in pixels.
bool has_origin() const
Returns true if the window origin has been specified, false otherwise.
void clear_title()
Removes the title specification from the properties.
const string & get_title() const
Returns the window's title.
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...
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.
void clear_minimized()
Removes the minimized specification from the properties.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
string get_close_request_event() const
Returns the name of the event set via set_close_request_event().
const WindowProperties get_properties() const
Returns the current properties of the window.
bool get_unexposed_draw() const
See set_unexposed_draw().
A window, fullscreen or on a desktop, into which a graphics device sends its output for interactive d...
bool resolve_filename(const DSearchPath &searchpath, const string &default_extension=string())
Searches the given search path for the filename.
bool has_fullscreen() const
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.
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, graphics windows that interface with the Microsoft Windows API).
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...
Stores information for a single touch event.
The name of a file, such as a texture file or an Egg file.
OSHandle * get_os_handle() const
Returns the OS-specific handle stored internally to the WindowHandle wrapper.
void clear_icon_filename()
Removes the icon_filename specification from the properties.
bool get_fullscreen() const
Returns true if the window is in fullscreen mode.
void clear_mouse_mode()
Removes the mouse_mode specification from the properties.
An object to create GraphicsOutputs that share a particular 3-D API.
double get_real_time() const
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
const Filename & get_icon_filename() const
Returns the icon filename associated with the window.
virtual void set_properties_now(WindowProperties &properties)
Applies the requested set of properties to the window, if possible, for instance to request a change ...
const Filename & get_cursor_filename() const
Returns the icon filename associated with the mouse cursor.
void set_origin(const LPoint2i &origin)
Specifies the origin on the screen (in pixels, relative to the top-left corner) at which the window s...
bool has_foreground() const
Returns true if set_foreground() has been specified.
bool has_cursor_hidden() const
Returns true if set_cursor_hidden() has been specified.
This is a base class for the various different classes that represent the result of a frame of render...
bool has_z_order() const
Returns true if the window z_order has been specified, false otherwise.
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...
bool get_cursor_hidden() const
Returns true if the mouse cursor is invisible.
void set_foreground(bool foreground)
Specifies whether the window should be opened in the foreground (true), or left in the background (fa...
void clear_z_order()
Removes the z_order specification from the properties.
bool has_cursor_filename() const
Returns true if set_cursor_filename() has been specified.
This is an abstract base class for wglGraphicsPipe and wdxGraphicsPipe; that is, those graphics pipes...
void clear_cursor_hidden()
Removes the cursor_hidden specification from the properties.
void set_minimized(bool minimized)
Specifies whether the window should be created minimized (true), or normal (false).
bool has_minimized() const
Returns true if set_minimized() has been specified.
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.
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...
bool has_title() const
Returns true if the window title has been specified, false otherwise.
TypeHandle is the identifier used to differentiate C++ class types.
void clear_cursor_filename()
Removes the cursor_filename specification from the properties.
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
void set_wtext(const wstring &wtext)
Changes the text that is stored in the encoder.
virtual void close_ime()
Forces the ime window to close, if any.
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
void set_open(bool 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.
void clear_fullscreen()
Removes the fullscreen specification from the properties.
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
string get_text() const
Returns the current text, as encoded via the current encoding system.
virtual bool supports_window_procs() const
Returns whether this window supports adding of windows proc handlers.