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(&dm,
sizeof(dm));
2364 dm.dmSize =
sizeof(dm);
2366 if (!EnumDisplaySettings(NULL, modenum, &dm)) {
2370 if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
2371 (dm.dmBitsPerPel == bpp)) {
2387 void WinGraphicsWindow::
2388 show_error_message(DWORD message_id) {
2389 LPTSTR message_buffer;
2391 if (message_id == 0) {
2392 message_id = GetLastError();
2395 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
2397 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2398 (LPTSTR)&message_buffer,
2400 MessageBox(GetDesktopWindow(), message_buffer, _T(errorbox_title), MB_OK);
2401 windisplay_cat.fatal() <<
"System error msg: " << message_buffer << endl;
2402 LocalFree(message_buffer);
2410 void WinGraphicsWindow::
2411 handle_keypress(
ButtonHandle key,
int x,
int y,
double time) {
2412 _input_devices[0].set_pointer_in_window(x, y);
2414 _input_devices[0].button_down(key, time);
2425 void WinGraphicsWindow::
2428 _input_devices[0].button_resume_down(key, time);
2437 void WinGraphicsWindow::
2440 _input_devices[0].button_up(key, time);
2449 void WinGraphicsWindow::
2452 _input_devices[0].raw_button_down(key, time);
2461 void WinGraphicsWindow::
2464 _input_devices[0].raw_button_up(key, time);
2475 lookup_key(WPARAM wparam)
const {
2480 case VK_BACK:
return KeyboardButton::backspace();
2481 case VK_DELETE:
return KeyboardButton::del();
2482 case VK_ESCAPE:
return KeyboardButton::escape();
2483 case VK_SPACE:
return KeyboardButton::space();
2484 case VK_UP:
return KeyboardButton::up();
2485 case VK_DOWN:
return KeyboardButton::down();
2486 case VK_LEFT:
return KeyboardButton::left();
2487 case VK_RIGHT:
return KeyboardButton::right();
2494 case VK_TAB:
return KeyboardButton::tab();
2495 case VK_PRIOR:
return KeyboardButton::page_up();
2496 case VK_NEXT:
return KeyboardButton::page_down();
2497 case VK_HOME:
return KeyboardButton::home();
2498 case VK_END:
return KeyboardButton::end();
2499 case VK_F1:
return KeyboardButton::f1();
2500 case VK_F2:
return KeyboardButton::f2();
2501 case VK_F3:
return KeyboardButton::f3();
2502 case VK_F4:
return KeyboardButton::f4();
2503 case VK_F5:
return KeyboardButton::f5();
2504 case VK_F6:
return KeyboardButton::f6();
2505 case VK_F7:
return KeyboardButton::f7();
2506 case VK_F8:
return KeyboardButton::f8();
2507 case VK_F9:
return KeyboardButton::f9();
2508 case VK_F10:
return KeyboardButton::f10();
2509 case VK_F11:
return KeyboardButton::f11();
2510 case VK_F12:
return KeyboardButton::f12();
2511 case VK_INSERT:
return KeyboardButton::insert();
2512 case VK_CAPITAL:
return KeyboardButton::caps_lock();
2513 case VK_NUMLOCK:
return KeyboardButton::num_lock();
2514 case VK_SCROLL:
return KeyboardButton::scroll_lock();
2515 case VK_PAUSE:
return KeyboardButton::pause();
2516 case VK_SNAPSHOT:
return KeyboardButton::print_screen();
2518 case VK_SHIFT:
return KeyboardButton::shift();
2519 case VK_LSHIFT:
return KeyboardButton::lshift();
2520 case VK_RSHIFT:
return KeyboardButton::rshift();
2522 case VK_CONTROL:
return KeyboardButton::control();
2523 case VK_LCONTROL:
return KeyboardButton::lcontrol();
2524 case VK_RCONTROL:
return KeyboardButton::rcontrol();
2526 case VK_MENU:
return KeyboardButton::alt();
2527 case VK_LMENU:
return KeyboardButton::lalt();
2528 case VK_RMENU:
return KeyboardButton::ralt();
2531 int key = MapVirtualKey(wparam, 2);
2532 if (isascii(key) && key != 0) {
2560 lookup_raw_key(LPARAM lparam)
const {
2561 unsigned char vsc = (lparam & 0xff0000) >> 16;
2563 if (lparam & 0x1000000) {
2566 case 28:
return KeyboardButton::enter();
2567 case 29:
return KeyboardButton::rcontrol();
2569 case 55:
return KeyboardButton::print_screen();
2570 case 56:
return KeyboardButton::ralt();
2571 case 69:
return KeyboardButton::num_lock();
2572 case 71:
return KeyboardButton::home();
2573 case 72:
return KeyboardButton::up();
2574 case 73:
return KeyboardButton::page_up();
2575 case 75:
return KeyboardButton::left();
2576 case 77:
return KeyboardButton::right();
2577 case 79:
return KeyboardButton::end();
2578 case 80:
return KeyboardButton::down();
2579 case 81:
return KeyboardButton::page_down();
2580 case 82:
return KeyboardButton::insert();
2581 case 83:
return KeyboardButton::del();
2582 case 91:
return KeyboardButton::lmeta();
2583 case 92:
return KeyboardButton::rmeta();
2584 case 93:
return KeyboardButton::menu();
2591 KeyboardButton::escape(),
2604 KeyboardButton::backspace(),
2605 KeyboardButton::tab(),
2618 KeyboardButton::enter(),
2619 KeyboardButton::lcontrol(),
2632 KeyboardButton::lshift(),
2644 KeyboardButton::rshift(),
2646 KeyboardButton::lalt(),
2647 KeyboardButton::space(),
2648 KeyboardButton::caps_lock(),
2649 KeyboardButton::f1(),
2650 KeyboardButton::f2(),
2651 KeyboardButton::f3(),
2652 KeyboardButton::f4(),
2653 KeyboardButton::f5(),
2654 KeyboardButton::f6(),
2655 KeyboardButton::f7(),
2656 KeyboardButton::f8(),
2657 KeyboardButton::f9(),
2658 KeyboardButton::f10(),
2659 KeyboardButton::pause(),
2660 KeyboardButton::scroll_lock(),
2675 return raw_map[vsc];
2680 case 87:
return KeyboardButton::f11();
2681 case 88:
return KeyboardButton::f12();
2696 get_keyboard_map()
const {
2701 unsigned short ex_vsc[] = {0x57, 0x58,
2702 0x011c, 0x011d, 0x0135, 0x0137, 0x0138, 0x0145, 0x0147, 0x0148, 0x0149, 0x014b, 0x014d, 0x014f, 0x0150, 0x0151, 0x0152, 0x0153, 0x015b, 0x015c, 0x015d};
2704 for (
int k = 1; k < 84 + 17; ++k) {
2706 vsc = ex_vsc[k - 84];
2711 UINT lparam = vsc << 16;
2719 button = KeyboardButton::pause();
2721 }
else if (vsc >= 0x47 && vsc <= 0x53) {
2723 button = raw_button;
2735 UINT vk = MapVirtualKeyA(vsc, MAPVK_VSC_TO_VK_EX);
2736 button = lookup_key(vk);
2742 int len = GetKeyNameTextA(lparam, text, 256);
2743 string label (text, len);
2755 void WinGraphicsWindow::
2756 handle_raw_input(HRAWINPUT hraw) {
2763 if (pGetRawInputData(hraw, RID_INPUT, NULL, &dwSize,
sizeof(RAWINPUTHEADER)) == -1) {
2767 lpb = (LPBYTE)alloca(
sizeof(LPBYTE) * dwSize);
2772 if (pGetRawInputData(hraw, RID_INPUT, lpb, &dwSize,
sizeof(RAWINPUTHEADER)) != dwSize) {
2776 RAWINPUT *raw = (RAWINPUT *)lpb;
2777 if (raw->header.hDevice == 0) {
2781 for (
int i = 1; i < (int)(_input_devices.size()); ++i) {
2782 if (_input_device_handle[i] == raw->header.hDevice) {
2783 int adjx = raw->data.mouse.lLastX;
2784 int adjy = raw->data.mouse.lLastY;
2786 if (raw->data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE) {
2787 _input_devices[i].set_pointer_in_window(adjx, adjy);
2789 int oldx = _input_devices[i].get_raw_pointer().get_x();
2790 int oldy = _input_devices[i].get_raw_pointer().get_y();
2791 _input_devices[i].set_pointer_in_window(oldx + adjx, oldy + adjy);
2794 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) {
2797 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) {
2800 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) {
2803 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) {
2806 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) {
2809 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) {
2812 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) {
2815 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) {
2818 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) {
2821 if (raw->data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) {
2833 bool WinGraphicsWindow::
2834 handle_mouse_motion(
int x,
int y) {
2835 _input_devices[0].set_pointer_in_window(x, y);
2844 void WinGraphicsWindow::
2845 handle_mouse_exit() {
2847 _input_devices[0].set_pointer_out_of_window();
2857 HICON WinGraphicsWindow::
2858 get_icon(
const Filename &filename) {
2860 IconFilenames::iterator fi = _icon_filenames.find(filename);
2861 if (fi != _icon_filenames.end()) {
2862 return (HICON)((*fi).second);
2877 windisplay_cat.warning()
2878 <<
"Could not find icon filename " << filename <<
"\n";
2882 fi = _icon_filenames.find(resolved);
2883 if (fi != _icon_filenames.end()) {
2884 _icon_filenames[filename] = (*fi).second;
2885 return (HICON)((*fi).second);
2890 HANDLE h = LoadImage(NULL, os.c_str(),
2891 IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
2893 windisplay_cat.warning()
2894 <<
"windows icon filename '" << os <<
"' could not be loaded!!\n";
2897 _icon_filenames[filename] = h;
2898 _icon_filenames[resolved] = h;
2909 HCURSOR WinGraphicsWindow::
2910 get_cursor(
const Filename &filename) {
2912 if (filename.empty()) {
2917 IconFilenames::iterator fi = _cursor_filenames.find(filename);
2918 if (fi != _cursor_filenames.end()) {
2919 return (HCURSOR)((*fi).second);
2930 windisplay_cat.warning()
2931 <<
"Could not find cursor filename " << filename <<
"\n";
2934 fi = _cursor_filenames.find(resolved);
2935 if (fi != _cursor_filenames.end()) {
2936 _cursor_filenames[filename] = (*fi).second;
2937 return (HCURSOR)((*fi).second);
2942 HANDLE h = LoadImage(NULL, os.c_str(),
2943 IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
2945 windisplay_cat.warning()
2946 <<
"windows cursor filename '" << os <<
"' could not be loaded!!\n";
2947 show_error_message();
2950 _cursor_filenames[filename] = h;
2951 _cursor_filenames[resolved] = h;
2955 static HCURSOR get_cursor(
const Filename &filename);
2964 const WinGraphicsWindow::WindowClass &WinGraphicsWindow::
2966 WindowClass wcreg(props);
2967 wostringstream wclass_name;
2968 wclass_name << L
"WinGraphicsWindow" << _window_class_index;
2969 wcreg._name = wclass_name.str();
2971 pair<WindowClasses::iterator, bool> found = _window_classes.insert(wcreg);
2972 const WindowClass &wclass = (*found.first);
2974 if (!found.second) {
2980 _window_class_index++;
2984 HINSTANCE instance = GetModuleHandle(NULL);
2987 ZeroMemory(&wc,
sizeof(wc));
2988 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
2990 wc.hInstance = instance;
2992 wc.hIcon = wclass._icon;
2994 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
2995 wc.lpszMenuName = NULL;
2996 wc.lpszClassName = wclass._name.c_str();
2998 if (!RegisterClassW(&wc)) {
2999 windisplay_cat.error()
3000 <<
"could not register window class " << wclass._name <<
"!" << endl;
3012 WinGraphicsWindow::WinWindowHandle::
3027 void WinGraphicsWindow::WinWindowHandle::
3038 void WinGraphicsWindow::WinWindowHandle::
3039 receive_windows_message(
unsigned int msg,
int wparam,
int lparam) {
3040 if (_window != NULL) {
3047 void PrintErrorMessage(DWORD msgID) {
3048 LPTSTR pMessageBuffer;
3050 if (msgID==PRINT_LAST_ERROR)
3051 msgID=GetLastError();
3053 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
3055 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
3056 (LPTSTR) &pMessageBuffer,
3058 MessageBox(GetDesktopWindow(),pMessageBuffer,_T(errorbox_title),MB_OK);
3059 windisplay_cat.fatal() <<
"System error msg: " << pMessageBuffer << endl;
3060 LocalFree( pMessageBuffer );
3066 if (windisplay_cat.is_debug()) {
3067 windisplay_cat.debug()
3068 <<
"Skipping ClearToBlack, no origin specified yet.\n";
3073 if (windisplay_cat.is_debug()) {
3074 windisplay_cat.debug()
3075 <<
"ClearToBlack(" << hWnd <<
", " << props <<
")\n";
3078 HDC hDC=GetDC(hWnd);
3084 FillRect(hDC,&clrRect,(HBRUSH)GetStockObject(BLACK_BRUSH));
3085 ReleaseDC(hWnd,hDC);
3095 void get_client_rect_screen(HWND hwnd, RECT *view_rect) {
3096 GetClientRect(hwnd, view_rect);
3099 ul.x = view_rect->left;
3100 ul.y = view_rect->top;
3101 lr.x = view_rect->right;
3102 lr.y = view_rect->bottom;
3104 ClientToScreen(hwnd, &ul);
3105 ClientToScreen(hwnd, &lr);
3107 view_rect->left = ul.x;
3108 view_rect->top = ul.y;
3109 view_rect->right = lr.x;
3110 view_rect->bottom = lr.y;
3121 nassertv(wnd_proc != NULL);
3132 nassertv(wnd_proc != NULL);
3143 _window_proc_classes.clear();
3164 #ifdef HAVE_WIN_TOUCHINPUT
3165 return callbackData->get_msg() == WM_TOUCH;
3179 #ifdef HAVE_WIN_TOUCHINPUT
3194 #ifdef HAVE_WIN_TOUCHINPUT
3195 TOUCHINPUT ti = _touches[index];
3197 point.x = TOUCH_COORD_TO_PIXEL(ti.x);
3198 point.y = TOUCH_COORD_TO_PIXEL(ti.y);
3199 ScreenToClient(_hWnd, &point);
3204 ret.set_id(ti.dwID);
3205 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...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
int get_x_origin() const
Returns the x coordinate of the window's top-left corner, not including decorations.
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.
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.
bool has_cursor_filename() const
Returns true if set_cursor_filename() has been specified.
This object represents a window on the desktop, not necessarily a Panda window.
const Filename & get_icon_filename() const
Returns the icon filename associated with the window.
virtual bool supports_window_procs() const
Returns whether this window supports adding of windows proc handlers.
bool is_fullscreen() const
Returns true if the window has been opened as a fullscreen window, false otherwise.
void clear_foreground()
Removes the foreground specification from the properties.
bool has_cursor_hidden() const
Returns true if set_cursor_hidden() has been specified.
const WindowProperties get_properties() const
Returns the current properties of the window.
const string & get_title() const
Returns the window's title.
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...
bool get_minimized() const
Returns true if the window is minimized.
bool has_icon_filename() const
Returns true if set_icon_filename() has been specified.
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 is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
int get_y_size() const
Returns size in pixels in the y dimension of the useful part of the window, not including decorations...
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.
int get_y_origin() const
Returns the y coordinate of the window's top-left corner, not including decorations.
void clear_title()
Removes the title specification from the properties.
virtual int get_num_touches()
Returns the current number of touches on this window.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
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...
virtual void remove_window_proc(const GraphicsWindowProc *wnd_proc_object)
Removes the specified Windows proc event handler.
bool has_z_order() const
Returns true if the window z_order has been specified, false otherwise.
void clear_minimized()
Removes the minimized specification from the properties.
bool get_fullscreen() const
Returns true if the window is in fullscreen mode.
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.
virtual LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
This is the nonstatic window_proc function.
MouseMode get_mouse_mode() const
See set_mouse_mode().
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).
string get_close_request_event() const
Returns the name of the event set via set_close_request_event().
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.
void clear_icon_filename()
Removes the icon_filename specification from the properties.
void clear_mouse_mode()
Removes the mouse_mode specification from the properties.
const Filename & get_cursor_filename() const
Returns the icon filename associated with the mouse cursor.
bool has_title() const
Returns true if the window title has been specified, false otherwise.
An object to create GraphicsOutputs that share a particular 3-D API.
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 get_foreground() const
Returns true if the window is in the foreground.
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.
wstring decode_text(const string &text) const
Returns the given wstring decoded to a single-byte string, via the current encoding system...
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
This is a base class for the various different classes that represent the result of a frame of render...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
bool has_minimized() const
Returns true if set_minimized() has been specified.
bool is_any_specified() const
Returns true if any properties have been specified, false otherwise.
bool has_origin() const
Returns true if the window origin 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...
int get_x_size() const
Returns size in pixels in the x dimension of the useful part of the window, not including decorations...
void clear_z_order()
Removes the z_order specification from the properties.
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).
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.
This is our own Panda specialization on the default STL set.
This class is the main interface to controlling the render process.
ZOrder get_z_order() const
Returns the window's z_order.
double get_real_time() const
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
TypeHandle is the identifier used to differentiate C++ class types.
OSHandle * get_os_handle() const
Returns the OS-specific handle stored internally to the WindowHandle wrapper.
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...
virtual void close_ime()
Forces the ime window to close, if any.
void set_open(bool open)
Specifies whether the window should be open.
void clear_fullscreen()
Removes the fullscreen specification from the properties.
bool has_fullscreen() const
Returns true if set_fullscreen() has been specified.
bool get_unexposed_draw() const
See set_unexposed_draw().