00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "winGraphicsWindow.h"
00020 #include "config_windisplay.h"
00021 #include "winGraphicsPipe.h"
00022
00023 #include "graphicsPipe.h"
00024 #include "keyboardButton.h"
00025 #include "mouseButton.h"
00026 #include "clockObject.h"
00027
00028 #include <tchar.h>
00029
00030 TypeHandle WinGraphicsWindow::_type_handle;
00031
00032 bool WinGraphicsWindow::_loaded_custom_cursor;
00033 HCURSOR WinGraphicsWindow::_mouse_cursor;
00034 const char * const WinGraphicsWindow::_window_class_name = "WinGraphicsWindow";
00035 bool WinGraphicsWindow::_window_class_registered = false;
00036
00037 WinGraphicsWindow::WindowHandles WinGraphicsWindow::_window_handles;
00038 WinGraphicsWindow *WinGraphicsWindow::_creating_window = NULL;
00039
00040 WinGraphicsWindow *WinGraphicsWindow::_cursor_window = NULL;
00041 bool WinGraphicsWindow::_cursor_hidden = false;
00042
00043
00044
00045
00046 bool WinGraphicsWindow::_got_saved_params = false;
00047 int WinGraphicsWindow::_saved_mouse_trails;
00048 BOOL WinGraphicsWindow::_saved_cursor_shadow;
00049 BOOL WinGraphicsWindow::_saved_mouse_vanish;
00050
00051 static const char * const errorbox_title = "Panda3D Error";
00052
00053
00054
00055
00056
00057
00058 WinGraphicsWindow::
00059 WinGraphicsWindow(GraphicsPipe *pipe, GraphicsStateGuardian *gsg) :
00060 GraphicsWindow(pipe, gsg)
00061 {
00062 GraphicsWindowInputDevice device =
00063 GraphicsWindowInputDevice::pointer_and_keyboard("keyboard/mouse");
00064 _input_devices.push_back(device);
00065 _hWnd = (HWND)0;
00066 _ime_open = false;
00067 _ime_active = false;
00068 _ime_composition_w = false;
00069 _tracking_mouse_leaving = false;
00070 _maximized = false;
00071 memset(_keyboard_state, 0, sizeof(BYTE) * num_virtual_keys);
00072 }
00073
00074
00075
00076
00077
00078
00079 WinGraphicsWindow::
00080 ~WinGraphicsWindow() {
00081 }
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 void WinGraphicsWindow::
00098 begin_flip() {
00099 }
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 void WinGraphicsWindow::
00112 process_events() {
00113 GraphicsWindow::process_events();
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131 MSG msg;
00132
00133
00134
00135
00136 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
00137 process_1_event();
00138 }
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 void WinGraphicsWindow::
00160 set_properties_now(WindowProperties &properties) {
00161 GraphicsWindow::set_properties_now(properties);
00162 if (!properties.is_any_specified()) {
00163
00164 return;
00165 }
00166 }
00167
00168
00169
00170
00171
00172
00173
00174 void WinGraphicsWindow::
00175 close_window() {
00176 set_cursor_out_of_window();
00177 DestroyWindow(_hWnd);
00178
00179
00180 _window_handles.erase(_hWnd);
00181 _hWnd = (HWND)0;
00182
00183 if (is_fullscreen()) {
00184
00185 ChangeDisplaySettings(NULL, 0x0);
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
00196 bool WinGraphicsWindow::
00197 open_window() {
00198
00199
00200
00201
00202 _creating_window = this;
00203 bool opened;
00204 if (is_fullscreen()) {
00205 opened = open_fullscreen_window();
00206 } else {
00207 opened = open_regular_window();
00208 }
00209 _creating_window = (WinGraphicsWindow *)NULL;
00210
00211 if (!opened) {
00212 return false;
00213 }
00214
00215
00216
00217 _window_handles.insert(WindowHandles::value_type(_hWnd, this));
00218
00219
00220 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0,
00221 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE);
00222
00223
00224 ShowWindow(_hWnd, SW_SHOWNORMAL);
00225 ShowWindow(_hWnd, SW_SHOWNORMAL);
00226
00227 if (!SetForegroundWindow(_hWnd)) {
00228 windisplay_cat.warning()
00229 << "SetForegroundWindow() failed!\n";
00230 }
00231
00232
00233 _ime_open = false;
00234 _ime_active = false;
00235 HIMC hIMC = ImmGetContext(_hWnd);
00236 if (hIMC != 0) {
00237 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
00238 ImmReleaseContext(_hWnd, hIMC);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 _ime_composition_w = ime_composition_w;
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 return true;
00277 }
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 void WinGraphicsWindow::
00289 fullscreen_minimized(WindowProperties &) {
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 void WinGraphicsWindow::
00302 fullscreen_restored(WindowProperties &) {
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 bool WinGraphicsWindow::
00315 do_reshape_request(int x_origin, int y_origin, int x_size, int y_size) {
00316 windisplay_cat.info()
00317 << "Got reshape request (" << x_origin << ", " << y_origin
00318 << ", " << x_size << ", " << y_size << ")\n";
00319 if (!is_fullscreen()) {
00320
00321
00322 RECT view_rect;
00323 SetRect(&view_rect, x_origin, y_origin,
00324 x_origin + x_size, y_origin + y_size);
00325 WINDOWINFO wi;
00326 GetWindowInfo(_hWnd, &wi);
00327 AdjustWindowRectEx(&view_rect, wi.dwStyle, false, wi.dwExStyle);
00328
00329 SetWindowPos(_hWnd, NULL, view_rect.left, view_rect.top,
00330 view_rect.right - view_rect.left,
00331 view_rect.bottom - view_rect.top,
00332 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
00333
00334
00335
00336
00337
00338 handle_reshape();
00339 return true;
00340 }
00341
00342
00343 return do_fullscreen_resize(x_size, y_size);
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353 void WinGraphicsWindow::
00354 handle_reshape() {
00355 RECT view_rect;
00356 GetClientRect(_hWnd, &view_rect);
00357 ClientToScreen(_hWnd, (POINT*)&view_rect.left);
00358 ClientToScreen(_hWnd, (POINT*)&view_rect.right);
00359
00360 WindowProperties properties;
00361 properties.set_size((view_rect.right - view_rect.left),
00362 (view_rect.bottom - view_rect.top));
00363
00364
00365 properties.set_origin(view_rect.left, view_rect.top);
00366
00367 if (windisplay_cat.is_spam()) {
00368 windisplay_cat.spam()
00369 << "reshape to origin: (" << properties.get_x_origin() << ","
00370 << properties.get_y_origin() << "), size: (" << properties.get_x_size()
00371 << "," << properties.get_y_size() << ")\n";
00372 }
00373
00374 system_changed_properties(properties);
00375 }
00376
00377
00378
00379
00380
00381
00382
00383 bool WinGraphicsWindow::
00384 do_fullscreen_resize(int x_size, int y_size) {
00385 HWND hDesktopWindow = GetDesktopWindow();
00386 HDC scrnDC = GetDC(hDesktopWindow);
00387 DWORD dwFullScreenBitDepth = GetDeviceCaps(scrnDC, BITSPIXEL);
00388 ReleaseDC(hDesktopWindow, scrnDC);
00389
00390
00391
00392
00393
00394
00395
00396 DEVMODE dm;
00397 if (!find_acceptable_display_mode(x_size, y_size,
00398 dwFullScreenBitDepth, dm)) {
00399 windisplay_cat.error()
00400 << "window resize(" << x_size << ", " << y_size
00401 << ") failed, no compatible fullscreen display mode found!\n";
00402 return false;
00403 }
00404
00405
00406 SetWindowPos(_hWnd, NULL, 0,0, x_size, y_size,
00407 SWP_NOZORDER | SWP_NOMOVE | SWP_NOSENDCHANGING);
00408 int chg_result = ChangeDisplaySettings(&dm, CDS_FULLSCREEN);
00409
00410 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
00411 windisplay_cat.error()
00412 << "resize ChangeDisplaySettings failed (error code: "
00413 << chg_result << ") for specified res (" << x_size << " x "
00414 << y_size << " x " << dwFullScreenBitDepth << "), "
00415 << dm.dmDisplayFrequency << "Hz\n";
00416 return false;
00417 }
00418
00419 _fullscreen_display_mode = dm;
00420
00421 windisplay_cat.info()
00422 << "Resized fullscreen window to " << x_size << ", " << y_size
00423 << " bitdepth " << dwFullScreenBitDepth << ", "
00424 << dm.dmDisplayFrequency << "Hz\n";
00425
00426 return true;
00427 }
00428
00429
00430
00431
00432
00433
00434
00435
00436 void WinGraphicsWindow::
00437 reconsider_fullscreen_size(DWORD &, DWORD &, DWORD &) {
00438 }
00439
00440
00441
00442
00443
00444
00445 bool WinGraphicsWindow::
00446 open_fullscreen_window() {
00447
00448
00449
00450
00451
00452
00453
00454 DWORD window_style =
00455 WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
00456
00457 if (!_properties.has_size()) {
00458
00459 _properties.set_size(640, 480);
00460 }
00461
00462 HWND hDesktopWindow = GetDesktopWindow();
00463 HDC scrnDC = GetDC(hDesktopWindow);
00464 DWORD cur_bitdepth = GetDeviceCaps(scrnDC, BITSPIXEL);
00465
00466
00467
00468 ReleaseDC(hDesktopWindow, scrnDC);
00469
00470 DWORD dwWidth = _properties.get_x_size();
00471 DWORD dwHeight = _properties.get_y_size();
00472 DWORD dwFullScreenBitDepth = cur_bitdepth;
00473
00474 reconsider_fullscreen_size(dwWidth, dwHeight, dwFullScreenBitDepth);
00475 if (!find_acceptable_display_mode(dwWidth, dwHeight, dwFullScreenBitDepth,
00476 _fullscreen_display_mode)) {
00477 windisplay_cat.error()
00478 << "Videocard has no supported display resolutions at specified res ("
00479 << dwWidth << " x " << dwHeight << " x " << dwFullScreenBitDepth <<")\n";
00480 return false;
00481 }
00482
00483 string title;
00484 if (_properties.has_title()) {
00485 title = _properties.get_title();
00486 }
00487
00488
00489
00490
00491 register_window_class();
00492 HINSTANCE hinstance = GetModuleHandle(NULL);
00493 _hWnd = CreateWindow(_window_class_name, title.c_str(), window_style,
00494 0, 0, dwWidth, dwHeight,
00495 hDesktopWindow, NULL, hinstance, 0);
00496 if (!_hWnd) {
00497 windisplay_cat.error()
00498 << "CreateWindow() failed!" << endl;
00499 show_error_message();
00500 return false;
00501 }
00502
00503 int chg_result = ChangeDisplaySettings(&_fullscreen_display_mode,
00504 CDS_FULLSCREEN);
00505 if (chg_result != DISP_CHANGE_SUCCESSFUL) {
00506 windisplay_cat.error()
00507 << "ChangeDisplaySettings failed (error code: "
00508 << chg_result << ") for specified res (" << dwWidth
00509 << " x " << dwHeight << " x " << dwFullScreenBitDepth
00510 << "), " << _fullscreen_display_mode.dmDisplayFrequency << "Hz\n";
00511 return false;
00512 }
00513
00514 _properties.set_origin(0, 0);
00515 _properties.set_size(dwWidth, dwHeight);
00516 return true;
00517 }
00518
00519
00520
00521
00522
00523
00524 bool WinGraphicsWindow::
00525 open_regular_window() {
00526
00527
00528
00529
00530
00531
00532
00533 DWORD window_style =
00534 WS_POPUP | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
00535
00536 if (!_properties.has_undecorated() || !_properties.get_undecorated()) {
00537 window_style |= WS_OVERLAPPEDWINDOW;
00538 }
00539
00540 if (!_properties.has_origin()) {
00541 _properties.set_origin(0, 0);
00542 }
00543 if (!_properties.has_size()) {
00544 _properties.set_size(100, 100);
00545 }
00546
00547 RECT win_rect;
00548 SetRect(&win_rect,
00549 _properties.get_x_origin(),
00550 _properties.get_y_origin(),
00551 _properties.get_x_origin() + _properties.get_x_size(),
00552 _properties.get_y_origin() + _properties.get_y_size());
00553
00554
00555 if (!AdjustWindowRect(&win_rect, window_style, FALSE)) {
00556 windisplay_cat.error()
00557 << "AdjustWindowRect failed!" << endl;
00558 return false;
00559 }
00560
00561
00562 if (win_rect.left < 0) {
00563 win_rect.right += abs(win_rect.left);
00564 win_rect.left = 0;
00565 }
00566 if (win_rect.top < 0) {
00567 win_rect.bottom += abs(win_rect.top);
00568 win_rect.top = 0;
00569 }
00570
00571 string title;
00572 if (_properties.has_title()) {
00573 title = _properties.get_title();
00574 }
00575
00576 register_window_class();
00577 HINSTANCE hinstance = GetModuleHandle(NULL);
00578 _hWnd = CreateWindow(_window_class_name, title.c_str(), window_style,
00579 win_rect.left, win_rect.top,
00580 win_rect.right - win_rect.left,
00581 win_rect.bottom - win_rect.top,
00582 NULL, NULL, hinstance, 0);
00583
00584 if (!_hWnd) {
00585 windisplay_cat.error()
00586 << "CreateWindow() failed!" << endl;
00587 show_error_message();
00588 return false;
00589 }
00590
00591 return true;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 void WinGraphicsWindow::
00603 track_mouse_leaving(HWND hwnd) {
00604
00605
00606
00607
00608 WinGraphicsPipe *winpipe;
00609 DCAST_INTO_V(winpipe, _pipe);
00610
00611 if (winpipe->_pfnTrackMouseEvent != NULL) {
00612 TRACKMOUSEEVENT tme = {
00613 sizeof(TRACKMOUSEEVENT),
00614 TME_LEAVE,
00615 hwnd,
00616 0
00617 };
00618
00619
00620 BOOL bSucceeded = winpipe->_pfnTrackMouseEvent(&tme);
00621
00622 if ((!bSucceeded) && windisplay_cat.is_debug()) {
00623 windisplay_cat.debug()
00624 << "TrackMouseEvent failed!, LastError=" << GetLastError() << endl;
00625 }
00626
00627 _tracking_mouse_leaving = true;
00628 }
00629 }
00630
00631
00632
00633
00634
00635
00636
00637
00638 LONG WinGraphicsWindow::
00639 window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
00640
00641
00642
00643
00644
00645 WindowProperties properties;
00646 int button = -1;
00647
00648 switch (msg) {
00649 case WM_MOUSEMOVE:
00650 if (!_tracking_mouse_leaving) {
00651
00652 track_mouse_leaving(hwnd);
00653 }
00654 set_cursor_in_window();
00655 if(handle_mouse_motion(translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam))))
00656 return 0;
00657 break;
00658
00659 case WM_MOUSELEAVE:
00660 _tracking_mouse_leaving = false;
00661 handle_mouse_exit();
00662 set_cursor_out_of_window();
00663 break;
00664
00665
00666 case WM_NCMOUSEMOVE: {
00667 if(!_properties.get_cursor_hidden()) {
00668 if(!_bCursor_in_WindowClientArea) {
00669
00670 ShowCursor(true);
00671 _bCursor_in_WindowClientArea=true;
00672 }
00673 }
00674 break;
00675 }
00676
00677 case WM_NCMOUSELEAVE: {
00678 if(!_properties.get_cursor_hidden()) {
00679 ShowCursor(false);
00680
00681 _bCursor_in_WindowClientArea=false;
00682 }
00683 break;
00684 }
00685
00686 case WM_CREATE: {
00687 track_mouse_leaving(hwnd);
00688 _bCursor_in_WindowClientArea=false;
00689 ClearToBlack(hwnd,_properties);
00690
00691 POINT cpos;
00692 GetCursorPos(&cpos);
00693 ScreenToClient(hwnd,&cpos);
00694 RECT clientRect;
00695 GetClientRect(hwnd, &clientRect);
00696 if(PtInRect(&clientRect,cpos))
00697 set_cursor_in_window();
00698 else set_cursor_out_of_window();
00699
00700 break;
00701 }
00702
00703 case WM_CLOSE:
00704 properties.set_open(false);
00705 system_changed_properties(properties);
00706
00707
00708 break;
00709
00710 case WM_ACTIVATE:
00711 properties.set_minimized((wparam & 0xffff0000) != 0);
00712 if ((wparam & 0xffff) != WA_INACTIVE) {
00713 properties.set_foreground(true);
00714 if (is_fullscreen()) {
00715
00716
00717 ChangeDisplaySettings(&_fullscreen_display_mode, CDS_FULLSCREEN);
00718 GdiFlush();
00719 SetWindowPos(_hWnd, HWND_TOP, 0,0,0,0,
00720 SWP_NOMOVE | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOOWNERZORDER);
00721 fullscreen_restored(properties);
00722 }
00723 } else {
00724 properties.set_foreground(false);
00725 if (is_fullscreen()) {
00726
00727
00728 properties.set_minimized(true);
00729
00730
00731
00732
00733 ShowWindow(_hWnd, SW_MINIMIZE);
00734 GdiFlush();
00735 ChangeDisplaySettings(NULL, 0x0);
00736 fullscreen_minimized(properties);
00737 }
00738 }
00739 system_changed_properties(properties);
00740 break;
00741
00742 case WM_SIZE:
00743
00744
00745 if (wparam == SIZE_MAXIMIZED) {
00746 _maximized = true;
00747 handle_reshape();
00748
00749 } else if (wparam == SIZE_RESTORED && _maximized) {
00750
00751
00752
00753
00754
00755 _maximized = false;
00756 handle_reshape();
00757 }
00758 break;
00759
00760 case WM_EXITSIZEMOVE:
00761 handle_reshape();
00762 break;
00763
00764 case WM_LBUTTONDOWN:
00765 button = 0;
00766
00767 case WM_MBUTTONDOWN:
00768 if (button < 0) {
00769 button = 1;
00770 }
00771
00772 case WM_RBUTTONDOWN:
00773 if (button < 0) {
00774 button = 2;
00775 }
00776 SetCapture(hwnd);
00777 handle_keypress(MouseButton::button(button),
00778 translate_mouse(LOWORD(lparam)), translate_mouse(HIWORD(lparam)));
00779 break;
00780
00781 case WM_LBUTTONUP:
00782 button = 0;
00783
00784 case WM_MBUTTONUP:
00785 if (button < 0) {
00786 button = 1;
00787 }
00788
00789 case WM_RBUTTONUP:
00790 if (button < 0) {
00791 button = 2;
00792 }
00793 ReleaseCapture();
00794 handle_keyrelease(MouseButton::button(button));
00795 break;
00796
00797 case WM_IME_NOTIFY:
00798 if (wparam == IMN_SETOPENSTATUS) {
00799 HIMC hIMC = ImmGetContext(hwnd);
00800 nassertr(hIMC != 0, 0);
00801 _ime_open = (ImmGetOpenStatus(hIMC) != 0);
00802 if (!_ime_open) {
00803 _ime_active = false;
00804 }
00805 ImmReleaseContext(hwnd, hIMC);
00806 }
00807 break;
00808
00809 case WM_IME_STARTCOMPOSITION:
00810 _ime_active = true;
00811 break;
00812
00813 case WM_IME_ENDCOMPOSITION:
00814 _ime_active = false;
00815 break;
00816
00817 case WM_IME_COMPOSITION:
00818 if (lparam & GCS_RESULTSTR) {
00819 HIMC hIMC = ImmGetContext(hwnd);
00820 nassertr(hIMC != 0, 0);
00821
00822 static const int max_ime_result = 128;
00823 static char ime_result[max_ime_result];
00824
00825 if (_ime_composition_w) {
00826
00827
00828
00829
00830
00831
00832 DWORD result_size =
00833 ImmGetCompositionStringW(hIMC, GCS_RESULTSTR,
00834 ime_result, max_ime_result);
00835
00836
00837
00838
00839
00840
00841
00842
00843 for (DWORD i = 0; i < result_size; i += 2) {
00844 int result =
00845 ((int)(unsigned char)ime_result[i + 1] << 8) |
00846 (unsigned char)ime_result[i];
00847 _input_devices[0].keystroke(result);
00848 }
00849 } else {
00850
00851
00852
00853 DWORD result_size =
00854 ImmGetCompositionStringA(hIMC, GCS_RESULTSTR,
00855 ime_result, max_ime_result);
00856
00857
00858
00859
00860 static const int max_wide_result = 128;
00861 static wchar_t wide_result[max_wide_result];
00862
00863 int wide_size =
00864 MultiByteToWideChar(CP_ACP, 0,
00865 ime_result, result_size,
00866 wide_result, max_wide_result);
00867 if (wide_size == 0) {
00868 show_error_message();
00869 }
00870 for (int i = 0; i < wide_size; i++) {
00871 _input_devices[0].keystroke(wide_result[i]);
00872 }
00873 }
00874
00875 ImmReleaseContext(hwnd, hIMC);
00876 return 0;
00877 }
00878 break;
00879
00880 case WM_CHAR:
00881
00882
00883
00884
00885
00886 if (!_ime_open) {
00887 _input_devices[0].keystroke(wparam);
00888 }
00889 break;
00890
00891 case WM_SYSKEYDOWN:
00892 {
00893
00894
00895
00896 POINT point;
00897 GetCursorPos(&point);
00898 ScreenToClient(hwnd, &point);
00899 handle_keypress(lookup_key(wparam), point.x, point.y);
00900 if (wparam == VK_F10) {
00901
00902
00903 return 0;
00904 }
00905 }
00906 break;
00907
00908 case WM_SYSCOMMAND:
00909 if (wparam == SC_KEYMENU) {
00910
00911
00912
00913
00914 return 0;
00915 }
00916 break;
00917
00918 case WM_KEYDOWN:
00919 {
00920 POINT point;
00921
00922 GetCursorPos(&point);
00923 ScreenToClient(hwnd, &point);
00924 handle_keypress(lookup_key(wparam), point.x, point.y);
00925
00926
00927
00928 if ((wparam=='V') && (GetKeyState(VK_CONTROL) < 0) &&
00929 !_input_devices.empty()) {
00930 HGLOBAL hglb;
00931 char *lptstr;
00932
00933 if (IsClipboardFormatAvailable(CF_TEXT) && OpenClipboard(NULL)) {
00934
00935
00936 hglb = GetClipboardData(CF_TEXT);
00937 if (hglb!=NULL) {
00938 lptstr = (char *) GlobalLock(hglb);
00939 if (lptstr != NULL) {
00940 char *pChar;
00941 for (pChar=lptstr; *pChar!=NULL; pChar++) {
00942 _input_devices[0].keystroke((uchar)*pChar);
00943 }
00944 GlobalUnlock(hglb);
00945 }
00946 }
00947 CloseClipboard();
00948 }
00949 }
00950 }
00951 break;
00952
00953 case WM_SYSKEYUP:
00954 case WM_KEYUP:
00955 handle_keyrelease(lookup_key(wparam));
00956 break;
00957
00958 case WM_KILLFOCUS:
00959
00960
00961 GetKeyboardState(_keyboard_state);
00962 break;
00963
00964 case WM_SETFOCUS:
00965 {
00966
00967
00968
00969
00970
00971
00972 if (GetForegroundWindow() != _hWnd) {
00973
00974
00975
00976
00977
00978
00979 if(windisplay_cat.is_debug())
00980 windisplay_cat.debug() << "Ignoring non-foreground WM_SETFOCUS\n";
00981 break;
00982 }
00983
00984 BYTE new_keyboard_state[num_virtual_keys];
00985 GetKeyboardState(new_keyboard_state);
00986 for (int i = 0; i < num_virtual_keys; i++) {
00987
00988
00989
00990
00991
00992
00993 if (i != VK_SHIFT && i != VK_CONTROL && i != VK_MENU) {
00994 if (((new_keyboard_state[i] ^ _keyboard_state[i]) & 0x80) != 0) {
00995
00996 if ((new_keyboard_state[i] & 0x80) != 0) {
00997
00998
00999 handle_keyresume(lookup_key(i));
01000 } else {
01001
01002 handle_keyrelease(lookup_key(i));
01003 }
01004 }
01005 }
01006 }
01007
01008
01009
01010
01011
01012 memcpy(_keyboard_state, new_keyboard_state,
01013 sizeof(BYTE) * num_virtual_keys);
01014 }
01015 break;
01016 }
01017
01018 return DefWindowProc(hwnd, msg, wparam, lparam);
01019 }
01020
01021
01022
01023
01024
01025
01026
01027
01028 LONG WINAPI WinGraphicsWindow::
01029 static_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
01030
01031 WindowHandles::const_iterator wi;
01032 wi = _window_handles.find(hwnd);
01033 if (wi != _window_handles.end()) {
01034
01035 return (*wi).second->window_proc(hwnd, msg, wparam, lparam);
01036 }
01037
01038
01039 if (_creating_window != (WinGraphicsWindow *)NULL) {
01040 return _creating_window->window_proc(hwnd, msg, wparam, lparam);
01041 }
01042
01043
01044
01045 return DefWindowProc(hwnd, msg, wparam, lparam);
01046 }
01047
01048
01049
01050
01051
01052
01053 void WinGraphicsWindow::
01054 process_1_event() {
01055 MSG msg;
01056
01057 if (!GetMessage(&msg, NULL, 0, 0)) {
01058
01059
01060 exit(msg.wParam);
01061 }
01062
01063
01064 TranslateMessage(&msg);
01065
01066 DispatchMessage(&msg);
01067 }
01068
01069
01070
01071
01072
01073
01074
01075
01076 void WinGraphicsWindow::
01077 update_cursor_window(WinGraphicsWindow *to_window) {
01078 bool hide_cursor = false;
01079 if (to_window == (WinGraphicsWindow *)NULL) {
01080
01081
01082 if (_got_saved_params) {
01083 SystemParametersInfo(SPI_SETMOUSETRAILS, NULL,
01084 (PVOID)_saved_mouse_trails, NULL);
01085 SystemParametersInfo(SPI_SETCURSORSHADOW, NULL,
01086 (PVOID)_saved_cursor_shadow, NULL);
01087 SystemParametersInfo(SPI_SETMOUSEVANISH, NULL,
01088 (PVOID)_saved_mouse_vanish, NULL);
01089 _got_saved_params = false;
01090 }
01091
01092 } else {
01093 const WindowProperties &to_props = to_window->get_properties();
01094 hide_cursor = to_props.get_cursor_hidden();
01095
01096
01097
01098
01099
01100
01101
01102 if (!_got_saved_params) {
01103 SystemParametersInfo(SPI_GETMOUSETRAILS, NULL,
01104 &_saved_mouse_trails, NULL);
01105 SystemParametersInfo(SPI_GETCURSORSHADOW, NULL,
01106 &_saved_cursor_shadow, NULL);
01107 SystemParametersInfo(SPI_GETMOUSEVANISH, NULL,
01108 &_saved_mouse_vanish, NULL);
01109 _got_saved_params = true;
01110
01111 SystemParametersInfo(SPI_SETMOUSETRAILS, NULL, (PVOID)0, NULL);
01112 SystemParametersInfo(SPI_SETCURSORSHADOW, NULL, (PVOID)false, NULL);
01113 SystemParametersInfo(SPI_SETMOUSEVANISH, NULL, (PVOID)false, NULL);
01114 }
01115 }
01116
01117 if (hide_cursor) {
01118
01119 if (!_cursor_hidden) {
01120 ShowCursor(false);
01121 _cursor_hidden = true;
01122 }
01123 } else {
01124
01125 if (_cursor_hidden) {
01126 ShowCursor(true);
01127 _cursor_hidden = false;
01128 }
01129 }
01130
01131 _cursor_window = to_window;
01132 }
01133
01134
01135
01136
01137
01138
01139
01140 void WinGraphicsWindow::
01141 register_window_class() {
01142 if (_window_class_registered) {
01143 return;
01144 }
01145
01146 WNDCLASS wc;
01147
01148 HINSTANCE instance = GetModuleHandle(NULL);
01149
01150
01151 ZeroMemory(&wc, sizeof(WNDCLASS));
01152 wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
01153 wc.lpfnWndProc = (WNDPROC)static_window_proc;
01154 wc.hInstance = instance;
01155
01156
01157
01158 string windows_icon_filename = get_icon_filename().to_os_specific();
01159 string windows_mono_cursor_filename = get_mono_cursor_filename().to_os_specific();
01160
01161 if (!windows_icon_filename.empty()) {
01162
01163
01164
01165
01166 wc.hIcon = (HICON)LoadImage(NULL, windows_icon_filename.c_str(),
01167 IMAGE_ICON, 0, 0, LR_LOADFROMFILE);
01168
01169 if (wc.hIcon == NULL) {
01170 windisplay_cat.warning()
01171 << "windows icon filename '" << windows_icon_filename
01172 << "' not found!!\n";
01173 }
01174 } else {
01175 wc.hIcon = NULL;
01176 }
01177
01178 _loaded_custom_cursor = false;
01179 if (!windows_mono_cursor_filename.empty()) {
01180
01181
01182
01183
01184 DWORD load_flags = LR_LOADFROMFILE;
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201 _mouse_cursor = (HCURSOR) LoadImage(NULL, windows_mono_cursor_filename.c_str(), IMAGE_CURSOR, 0, 0, load_flags);
01202
01203 if (_mouse_cursor == NULL) {
01204 windisplay_cat.warning()
01205 << "windows cursor filename '" << windows_mono_cursor_filename
01206 << "' not found!!\n";
01207 } else {
01208 _loaded_custom_cursor = true;
01209 }
01210 }
01211
01212 if (!_loaded_custom_cursor) {
01213 _mouse_cursor = LoadCursor(NULL, IDC_ARROW);
01214 }
01215
01216
01217
01218 wc.hCursor = _mouse_cursor;
01219 wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
01220 wc.lpszMenuName = NULL;
01221 wc.lpszClassName = _window_class_name;
01222
01223 if (!RegisterClass(&wc)) {
01224 windisplay_cat.error()
01225 << "could not register window class!" << endl;
01226 return;
01227 }
01228 _window_class_registered = true;
01229 }
01230
01231
01232 #define MIN_REFRESH_RATE 60
01233
01234 #define ACCEPTABLE_REFRESH_RATE(RATE) ((RATE >= MIN_REFRESH_RATE) || (RATE==0) || (RATE==1))
01235
01236
01237
01238
01239
01240
01241
01242
01243 bool WinGraphicsWindow::
01244 find_acceptable_display_mode(DWORD dwWidth, DWORD dwHeight, DWORD bpp,
01245 DEVMODE &dm) {
01246 int modenum = 0;
01247
01248 while (1) {
01249 ZeroMemory(&dm, sizeof(dm));
01250 dm.dmSize = sizeof(dm);
01251
01252 if (!EnumDisplaySettings(NULL, modenum, &dm)) {
01253 break;
01254 }
01255
01256 if ((dm.dmPelsWidth == dwWidth) && (dm.dmPelsHeight == dwHeight) &&
01257 (dm.dmBitsPerPel == bpp) &&
01258 ACCEPTABLE_REFRESH_RATE(dm.dmDisplayFrequency)) {
01259 return true;
01260 }
01261 modenum++;
01262 }
01263
01264 return false;
01265 }
01266
01267
01268
01269
01270
01271
01272
01273
01274 void WinGraphicsWindow::
01275 show_error_message(DWORD message_id) {
01276 LPTSTR message_buffer;
01277
01278 if (message_id == 0) {
01279 message_id = GetLastError();
01280 }
01281
01282 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
01283 NULL, message_id,
01284 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
01285 (LPTSTR)&message_buffer,
01286 1024, NULL);
01287 MessageBox(GetDesktopWindow(), message_buffer, _T(errorbox_title), MB_OK);
01288 windisplay_cat.fatal() << "System error msg: " << message_buffer << endl;
01289 LocalFree(message_buffer);
01290 }
01291
01292
01293
01294
01295
01296
01297
01298 ButtonHandle WinGraphicsWindow::
01299 lookup_key(WPARAM wparam) const {
01300
01301
01302 if (!_ime_active) {
01303 switch(wparam) {
01304 case VK_BACK: return KeyboardButton::backspace();
01305 case VK_DELETE: return KeyboardButton::del();
01306 case VK_ESCAPE: return KeyboardButton::escape();
01307 case VK_SPACE: return KeyboardButton::space();
01308 case VK_UP: return KeyboardButton::up();
01309 case VK_DOWN: return KeyboardButton::down();
01310 case VK_LEFT: return KeyboardButton::left();
01311 case VK_RIGHT: return KeyboardButton::right();
01312 }
01313 }
01314
01315
01316
01317 switch(wparam) {
01318 case VK_TAB: return KeyboardButton::tab();
01319 case VK_PRIOR: return KeyboardButton::page_up();
01320 case VK_NEXT: return KeyboardButton::page_down();
01321 case VK_HOME: return KeyboardButton::home();
01322 case VK_END: return KeyboardButton::end();
01323 case VK_F1: return KeyboardButton::f1();
01324 case VK_F2: return KeyboardButton::f2();
01325 case VK_F3: return KeyboardButton::f3();
01326 case VK_F4: return KeyboardButton::f4();
01327 case VK_F5: return KeyboardButton::f5();
01328 case VK_F6: return KeyboardButton::f6();
01329 case VK_F7: return KeyboardButton::f7();
01330 case VK_F8: return KeyboardButton::f8();
01331 case VK_F9: return KeyboardButton::f9();
01332 case VK_F10: return KeyboardButton::f10();
01333 case VK_F11: return KeyboardButton::f11();
01334 case VK_F12: return KeyboardButton::f12();
01335 case VK_INSERT: return KeyboardButton::insert();
01336 case VK_CAPITAL: return KeyboardButton::caps_lock();
01337 case VK_NUMLOCK: return KeyboardButton::num_lock();
01338 case VK_SCROLL: return KeyboardButton::scroll_lock();
01339 case VK_SNAPSHOT: return KeyboardButton::print_screen();
01340
01341 case VK_SHIFT:
01342 case VK_LSHIFT:
01343 case VK_RSHIFT:
01344 return KeyboardButton::shift();
01345
01346 case VK_CONTROL:
01347 case VK_LCONTROL:
01348 case VK_RCONTROL:
01349 return KeyboardButton::control();
01350
01351 case VK_MENU:
01352 case VK_LMENU:
01353 case VK_RMENU:
01354 return KeyboardButton::alt();
01355
01356 default:
01357 int key = MapVirtualKey(wparam, 2);
01358 if (isascii(key) && key != 0) {
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372 return KeyboardButton::ascii_key(tolower(key));
01373 }
01374 break;
01375 }
01376 return ButtonHandle::none();
01377 }
01378
01379
01380
01381
01382
01383
01384 bool WinGraphicsWindow::
01385 handle_mouse_motion(int x, int y) {
01386 _input_devices[0].set_pointer_in_window(x, y);
01387 return false;
01388 }
01389
01390
01391
01392
01393
01394
01395 void WinGraphicsWindow::
01396 handle_mouse_exit() {
01397
01398 _input_devices[0].set_pointer_out_of_window();
01399 }
01400
01401
01402 void PrintErrorMessage(DWORD msgID) {
01403 LPTSTR pMessageBuffer;
01404
01405 if (msgID==PRINT_LAST_ERROR)
01406 msgID=GetLastError();
01407
01408 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
01409 NULL,msgID,
01410 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
01411 (LPTSTR) &pMessageBuffer,
01412 1024, NULL);
01413 MessageBox(GetDesktopWindow(),pMessageBuffer,_T(errorbox_title),MB_OK);
01414 windisplay_cat.fatal() << "System error msg: " << pMessageBuffer << endl;
01415 LocalFree( pMessageBuffer );
01416 }
01417
01418 void
01419 ClearToBlack(HWND hWnd, const WindowProperties &props) {
01420 if (!props.has_origin()) {
01421 windisplay_cat.info()
01422 << "Skipping ClearToBlack, no origin specified yet.\n";
01423 return;
01424 }
01425
01426 if (windisplay_cat.is_debug()) {
01427 windisplay_cat.debug()
01428 << "ClearToBlack(" << hWnd << ", " << props << ")\n";
01429 }
01430
01431 HDC hDC=GetDC(hWnd);
01432 RECT clrRect = {
01433 props.get_x_origin(), props.get_y_origin(),
01434 props.get_x_origin() + props.get_x_size(),
01435 props.get_y_origin() + props.get_y_size()
01436 };
01437 FillRect(hDC,&clrRect,(HBRUSH)GetStockObject(BLACK_BRUSH));
01438 ReleaseDC(hWnd,hDC);
01439 GdiFlush();
01440 }
01441
01442
01443
01444
01445
01446
01447
01448 void get_client_rect_screen(HWND hwnd, RECT *view_rect) {
01449 GetClientRect(hwnd, view_rect);
01450
01451 POINT ul, lr;
01452 ul.x = view_rect->left;
01453 ul.y = view_rect->top;
01454 lr.x = view_rect->right;
01455 lr.y = view_rect->bottom;
01456
01457 ClientToScreen(hwnd, &ul);
01458 ClientToScreen(hwnd, &lr);
01459
01460 view_rect->left = ul.x;
01461 view_rect->top = ul.y;
01462 view_rect->right = lr.x;
01463 view_rect->bottom = lr.y;
01464 }