core/vgui/impl/win32/vgui_win32_adaptor.cxx
Go to the documentation of this file.
00001 // This is core/vgui/impl/win32/vgui_win32_adaptor.cxx
00002 #include "vgui_win32_adaptor.h"
00003 #include "vgui_win32_utils.h"
00004 
00005 #include <vcl_iostream.h>
00006 #include <vcl_cstring.h> // for vcl_memset
00007 #include <vcl_utility.h> // for vcl_pair
00008 #include <vgui/vgui_gl.h>
00009 #include <vgui/vgui_event.h>
00010 #include <vgui/vgui_macro.h>
00011 #include <vgui/vgui_find.h> // for vgui_find_below_by_type_name
00012 #include <vgui/vgui_image_tableau.h>
00013 #include <vgui/vgui_viewer2D_tableau.h>
00014 #include <vgui/vgui_popup_params.h>
00015 #include <vgui/vgui_command.h>
00016 
00017 vgui_menu vgui_win32_adaptor::last_popup;
00018 
00019 BEGIN_MESSAGE_MAP(vgui_win32_adaptor, vgui_win32_cmdtarget)
00020 END_MESSAGE_MAP()
00021 
00022 vgui_win32_adaptor::vgui_win32_adaptor(HWND hwnd, vgui_window *win)
00023   : hwnd_(hwnd), win_(win), tid_(0),
00024   redraw_posted_(true),
00025   overlay_redraw_posted_(true),
00026   idle_request_posted_(false)
00027 {
00028   // Get the device context for the client area of the specified window hwnd.
00029   hdc_ = GetDC(hwnd);
00030 
00031   // Set up OpenGL environment
00032   hglrc_ = setup_for_gl(hdc_);
00033 }
00034 
00035 vgui_win32_adaptor::~vgui_win32_adaptor()
00036 {
00037   // Although the vgui_DESTROY event is not handled in vgui,
00038   // it is (will be) processed by some vxl applications.
00039   // An examples is example_multiple_windows.
00040   // Note: dispatch the vgui_DESTROY event to tableau hierarchy
00041   // before deleting the rendering context, otherwise
00042   // vgui_projection_inspector::inspect() would fail.
00043   dispatch_to_tableau(vgui_DESTROY);
00044 
00045   if ( hglrc_ ) {
00046     // make the rendering context not current
00047     wglMakeCurrent( NULL, NULL );
00048     // delete the rendering context
00049     wglDeleteContext(hglrc_);
00050   }
00051   ReleaseDC(hwnd_, hdc_);
00052 
00053   // Clear pointers to context-menu callback functions
00054   popup_callbacks.clear();
00055 
00056   // Kill the timer
00057   if ( tid_ )
00058     kill_timer(tid_);
00059 }
00060 
00061 void vgui_win32_adaptor::post_timer(float timeout, int name)
00062 {
00063   vcl_map<unsigned int, vgui_win32_internal_timer>::iterator it = timers_.find(name);
00064   if ( it == timers_.end() ) { // Create at timer if it does rxist
00065     unsigned int tid = SetTimer(hwnd_, name, (unsigned int)timeout, NULL);
00066     if ( tid ) { // function fails to create a timer if tid==0
00067       vgui_win32_internal_timer it(tid, NULL);
00068       timers_.insert(vcl_pair<unsigned int, vgui_win32_internal_timer>(name, it));
00069     }
00070   }
00071 }
00072 
00073 
00074 // Redraw the rendering area.
00075 void vgui_win32_adaptor::post_redraw()
00076 {
00077   if ( !redraw_posted_ ) {
00078     RECT rect;
00079     if ( GetUpdateRect(hwnd_, &rect, FALSE) )
00080       InvalidateRect(hwnd_, &rect, FALSE); // update a region if possible
00081     else
00082       InvalidateRect(hwnd_, NULL, FALSE);  // entire client area
00083     // Redraw scroll bars to reflect to changed image size.
00084     // This operation might be put in vgui_view2D_tableau.
00085     PostMessage(hwnd_, WM_SIZE, 0, MAKELPARAM(width, height));
00086   }
00087   redraw_posted_ = true;
00088 }
00089 
00090 // Redraw overlay buffer
00091 void vgui_win32_adaptor::post_overlay_redraw()
00092 {
00093   if ( !overlay_redraw_posted_ ) {
00094     RECT rect;
00095     if ( GetUpdateRect(hwnd_, &rect, FALSE) )
00096       InvalidateRect(hwnd_, &rect, FALSE); // update a region if possible
00097     else
00098       InvalidateRect(hwnd_, NULL, FALSE);  // entire client area
00099   }
00100   overlay_redraw_posted_ = true;
00101 }
00102 
00103 // TODO: This function is not called yet.
00104 void vgui_win32_adaptor::post_idle_request()
00105 {
00106   idle_request_posted_ = true;
00107 }
00108 
00109 //void post_message(char const *, void const *);
00110 
00111 // Schedules destruction of parent vgui_window.
00112 void vgui_win32_adaptor::post_destroy()
00113 {
00114   // Do not send WM_DESTROY so as to give parent vgui_window
00115   // a chance to give focus to other vgui_window(s).
00116   // See vgui/examples/example_multiple_windows.
00117   PostMessage(hwnd_, WM_CLOSE, 0, 0);
00118 }
00119 
00120 // kill an existing timer
00121 void vgui_win32_adaptor::kill_timer(int name)
00122 {
00123   vcl_map<unsigned int, vgui_win32_internal_timer>::iterator it = timers_.find(name);
00124   if ( it == timers_.end() ) // return if such a timer does not exist
00125     return;
00126 
00127   KillTimer(hwnd_, it->second.timer_id);
00128   timers_.erase(it);
00129 }
00130 
00131 
00132 HGLRC vgui_win32_adaptor::setup_for_gl(HDC hdc)
00133 {
00134   // Set up pixel format.
00135   PIXELFORMATDESCRIPTOR pfd =
00136   {
00137     sizeof(PIXELFORMATDESCRIPTOR),
00138     1,
00139     PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
00140     PFD_TYPE_RGBA,
00141     24,
00142     0, 0, 0, 0, 0, 0,
00143     0, 0,
00144     0, 0, 0, 0, 0,
00145     16,                 // 16-bit depth buffer
00146     0,                  // no stencil buffer
00147     0,                  // no aux buffers
00148     PFD_MAIN_PLANE,     // main layer
00149     0,
00150     0, 0, 0
00151   };
00152 
00153   int  selected_pf = ChoosePixelFormat(hdc, &pfd);
00154   if ( selected_pf == 0 ) {
00155     MessageBox(NULL, TEXT("Failed to ChoosePixelFormat"), TEXT("Error"),
00156                MB_ICONERROR | MB_OK);
00157     vcl_cerr << "Failed to ChoosePixelFormat (error code:" << GetLastError() << ")\n";
00158     return 0;
00159   }
00160 
00161   if ( !SetPixelFormat(hdc, selected_pf, &pfd) ) {
00162     MessageBox(NULL, TEXT("Failed to SetPixelFormat"), TEXT("Error"),
00163                MB_ICONERROR | MB_OK);
00164     vcl_cerr << "Failed to SetPixelFormat (error code:" << GetLastError() << ")\n";
00165     return 0;
00166   }
00167 
00168   // Create a OpenGL rendering context, which is suitable for drawing
00169   // on the device referenced by hdc_.
00170   HGLRC hglrc = wglCreateContext(hdc);
00171   if ( !hglrc ) {
00172     MessageBox(NULL, TEXT("wglCreateContext failed"), TEXT("Error"),
00173                MB_ICONERROR | MB_OK);
00174     vcl_cerr << "wglCreateContext failed (error code:" << GetLastError() << ")\n";
00175     return 0;
00176   }
00177 
00178   // Make all subsequent OpenGL calls to be drawn on the device context hdc_.
00179   if ( !wglMakeCurrent(hdc, hglrc) ) {
00180     MessageBox(NULL, TEXT("wglMakeCurrent failed"), TEXT("Error"),
00181                MB_ICONERROR | MB_OK);
00182     vcl_cerr << "wglMakeCurrent failed (error code:" << GetLastError() << ")\n";
00183     return 0;
00184   }
00185 
00186   // Specify black as clear color
00187   glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00188   // Sepcify the back of the buffer as clear depth
00189   glClearDepth(1.0f);
00190 
00191   glEnable(GL_DEPTH_TEST);
00192   //glEnable(GL_BLEND);
00193   //glShadeModel(GL_SMOOTH);
00194 
00195   return hglrc;
00196 }
00197 
00198 // Handling messages that is related to vgui_adaptor.
00199 BOOL vgui_win32_adaptor::OnCmdMsg(UINT message, WPARAM wParam, LPARAM lParam)
00200 {
00201   switch ( message )
00202   {
00203     case WM_SIZE:
00204       OnSize(wParam, lParam);
00205       break;
00206     case WM_PAINT:
00207       OnPaint();
00208      break;
00209     case WM_TIMER:
00210       OnTimer(wParam, lParam);
00211       break;
00212     case WM_HSCROLL:
00213       OnHScroll(message, wParam, lParam);
00214       break;
00215     case WM_VSCROLL:
00216       OnVScroll(message, wParam, lParam);
00217       break;
00218     case WM_KEYDOWN:
00219       OnKeyDown(wParam, lParam);
00220       //vcl_cerr << "tableau: message WM_KEYDOWN received.\n";
00221       return TRUE;
00222     case WM_KEYUP:
00223       OnKeyUp(wParam, lParam);
00224       //vcl_cerr << "tableau: message WM_KEYUP received.\n";
00225       return TRUE;
00226     case WM_LBUTTONDOWN:
00227       OnLButtonDown(wParam, lParam);
00228       return TRUE;
00229     case WM_MBUTTONDOWN:
00230       OnMButtonDown(wParam, lParam);
00231       return TRUE;
00232     case WM_RBUTTONDOWN:
00233       OnRButtonDown(wParam, lParam);
00234       return TRUE;
00235     case WM_LBUTTONUP:
00236       OnLButtonUp(wParam, lParam);
00237       return TRUE;
00238     case WM_MBUTTONUP:
00239       OnMButtonUp(wParam, lParam);
00240       return TRUE;
00241     case WM_RBUTTONUP:
00242       OnRButtonUp(wParam, lParam);
00243       return TRUE;
00244     case WM_MOUSEMOVE:
00245       OnMouseMove(wParam, lParam);
00246       break;
00247 #ifdef WM_MOUSEWHEEL
00248     case WM_MOUSEWHEEL:
00249       OnMouseWheel(wParam, lParam);
00250       //vcl_cerr << "tableau: message WM_MOUSEWHEEL received.\n";
00251       return TRUE;
00252 #endif
00253     case WM_COMMAND: // child window and menu message
00254       menu_dispatcher(LOWORD(wParam));
00255       return TRUE;
00256     default:
00257       break;
00258   }
00259 
00260   return FALSE;
00261 }
00262 
00263 void vgui_win32_adaptor::menu_dispatcher(int menuId)
00264 {
00265   int item_count = popup_callbacks.size();
00266 
00267   // Make sure nID is in the relevant range
00268   if ( menuId >= POPUPMENU_ID_START && menuId < POPUPMENU_ID_START+item_count )
00269     // Call the callback function associated with the menu item "menuId"
00270     popup_callbacks[menuId-POPUPMENU_ID_START]->execute();
00271 }
00272 
00273 void vgui_win32_adaptor::OnSize(WPARAM wParam, LPARAM lParam)
00274 {
00275   // Get size of rendering area
00276   width  = LOWORD(lParam);
00277   height = HIWORD(lParam);
00278 
00279   // Resize scrollbars according to the window size and rendered image size
00280   // that take into account of zooming.
00281   vgui_tableau_sptr imtab = vgui_find_below_by_type_name(
00282                               this->get_tableau(), "vgui_image_tableau");
00283   vgui_tableau_sptr vrtab = vgui_find_below_by_type_name(
00284                               this->get_tableau(), "vgui_viewer2D_tableau");
00285   if ( imtab && vrtab ) {
00286     int im_width, im_height;
00287 
00288     vgui_image_tableau_sptr im;
00289     im.vertical_cast(imtab);
00290     vgui_viewer2D_tableau_sptr vr;
00291     vr.vertical_cast(vrtab);
00292 
00293     im_width  = im->width() *vr->token.scaleX;
00294     im_height = im->height()*vr->token.scaleY;
00295 
00296     SCROLLINFO si;
00297     // Save vertical scroll bar range and page size
00298     si.cbSize = sizeof(si);
00299     si.fMask = SIF_RANGE | SIF_PAGE;
00300     si.nMin = 0;
00301     si.nMax = 100;
00302     si.nPage = 100.*width/im_width;
00303     si.nPos = -100.*vr->token.offsetX/width;
00304     SetScrollInfo(hwnd_, SB_HORZ, &si, TRUE);
00305 
00306     // Save horizontal scroll bar range and page size
00307     si.nPage = 100.*height/im_height;
00308     si.nPos = -100.*vr->token.offsetY/height;
00309     SetScrollInfo(hwnd_, SB_VERT, &si, TRUE);
00310   }
00311 
00312   dispatch_to_tableau(vgui_RESHAPE);
00313   post_redraw();
00314 }
00315 
00316 void vgui_win32_adaptor::OnPaint()
00317 {
00318   if ( redraw_posted_ ) {
00319     this->make_current();
00320     vgui_macro_report_errors;
00321     dispatch_to_tableau(vgui_event(vgui_DRAW));
00322     vgui_macro_report_errors;
00323     redraw_posted_ = false;
00324   }
00325 
00326   if ( overlay_redraw_posted_ ) {
00327     this->make_current();
00328     vgui_macro_report_errors;
00329     // The following line forces a redraw to erase the previous overlay
00330     dispatch_to_tableau(vgui_event(vgui_DRAW));
00331     dispatch_to_tableau(vgui_event(vgui_DRAW_OVERLAY));
00332     vgui_macro_report_errors;
00333     overlay_redraw_posted_ = false;
00334   }
00335 
00336   swap_buffers();
00337 }
00338 
00339 void vgui_win32_adaptor::OnTimer(WPARAM wParam, LPARAM lParam)
00340 {
00341   vgui_event e(vgui_TIMER);
00342   e.timer_id = wParam;
00343   dispatch_to_tableau(e);
00344 }
00345 
00346 void vgui_win32_adaptor::OnHScroll(UINT message, WPARAM wParam, LPARAM lParam)
00347 {
00348   static SCROLLINFO si;
00349   int iHorzPos;
00350   vgui_event e;
00351 
00352   // Get all the vertical scroll bar information
00353   si.cbSize = sizeof(si);
00354   si.fMask = SIF_ALL;
00355   GetScrollInfo(hwnd_, SB_HORZ, &si);
00356 
00357   // Save the position for comparison later on
00358   iHorzPos = si.nPos;
00359   switch (LOWORD(wParam)) {
00360     case SB_LINELEFT:
00361       si.nPos -= 1;
00362       break;
00363     case SB_LINERIGHT:
00364       si.nPos += 1;
00365       break;
00366     case SB_PAGELEFT:
00367       si.nPos -= si.nPage;
00368       break;
00369     case SB_PAGERIGHT:
00370       si.nPos += si.nPage;
00371       break;
00372     case SB_THUMBPOSITION:
00373       si.nPos = si.nTrackPos;
00374       break;
00375     default:
00376       break;
00377   }
00378 
00379   // Set the position and then retrieve it. Due to adjustments
00380   // by Windows it may not be the same as the value set.
00381   si.fMask = SIF_POS;
00382   SetScrollInfo(hwnd_, SB_HORZ, &si, TRUE);
00383   GetScrollInfo(hwnd_, SB_HORZ, &si);
00384 
00385   // If the position has changed, scroll the window and update it
00386   if ( si.nPos != iHorzPos ) {
00387     e.type = vgui_HSCROLL;
00388     e.data = &si.nPos;
00389     dispatch_to_tableau(e);
00390 
00391     ScrollWindow(hwnd_, 0, (iHorzPos-si.nPos), NULL, NULL);
00392     UpdateWindow(hwnd_);
00393   }
00394 }
00395 
00396 void vgui_win32_adaptor::OnVScroll(UINT message, WPARAM wParam, LPARAM lParam)
00397 {
00398   static SCROLLINFO si;
00399   int iVertPos;
00400   vgui_event e;
00401 
00402   // Get all the vertical scroll bar information
00403   si.cbSize = sizeof(si);
00404   si.fMask = SIF_ALL;
00405   GetScrollInfo(hwnd_, SB_VERT, &si);
00406 
00407   // Save the position for comparison later on
00408   iVertPos = si.nPos;
00409   switch (LOWORD(wParam)) {
00410     case SB_TOP:
00411       si.nPos = si.nMin;
00412       break;
00413     case SB_BOTTOM:
00414       si.nPos = si.nMax;
00415       break;
00416     case SB_LINEUP:
00417       si.nPos -= 1;
00418       break;
00419     case SB_LINEDOWN:
00420       si.nPos += 1;
00421       break;
00422     case SB_PAGEUP:
00423       si.nPos -= si.nPage;
00424       break;
00425     case SB_PAGEDOWN:
00426       si.nPos += si.nPage;
00427       break;
00428     case SB_THUMBTRACK:
00429       si.nPos = si.nTrackPos;
00430       break;
00431     default:
00432       break;
00433   }
00434 
00435   // Set the position and then retrieve it. Due to adjustments
00436   // by Windows it may not be the same as the value set.
00437   si.fMask = SIF_POS;
00438   SetScrollInfo(hwnd_, SB_VERT, &si, TRUE);
00439   GetScrollInfo(hwnd_, SB_VERT, &si);
00440 
00441   // If the position has changed, scroll the window and update it
00442   if ( si.nPos != iVertPos ) {
00443     e.type = vgui_VSCROLL;
00444     e.data = &si.nPos;
00445     dispatch_to_tableau(e);
00446 
00447     ScrollWindow(hwnd_, 0, (iVertPos-si.nPos), NULL, NULL);
00448     UpdateWindow(hwnd_);
00449   }
00450 }
00451 
00452 void vgui_win32_adaptor::OnKeyDown(WPARAM wParam, LPARAM lParam)
00453 {
00454   // Ignore Ctrl and Shift pressed alone.
00455   if ( wParam == VK_SHIFT || wParam == VK_CONTROL )
00456     return;
00457 
00458   vgui_event ev = translate_message(wParam, lParam, vgui_KEY_PRESS);
00459   dispatch_to_tableau(ev);
00460 }
00461 
00462 void vgui_win32_adaptor::OnKeyUp(WPARAM wParam, LPARAM lParam)
00463 {
00464   // Ignore Ctrl and Shift pressed alone.
00465   if ( wParam == VK_SHIFT || wParam == VK_CONTROL )
00466     return;
00467 
00468   vgui_event ev = translate_message(wParam, lParam, vgui_KEY_UP);
00469   dispatch_to_tableau(ev);
00470 }
00471 
00472 void vgui_win32_adaptor::OnLButtonDown(WPARAM wParam, LPARAM lParam)
00473 {
00474   domouse(vgui_BUTTON_DOWN, vgui_LEFT, wParam, LOWORD(lParam), HIWORD(lParam));
00475 }
00476 
00477 void vgui_win32_adaptor::OnLButtonUp(WPARAM wParam, LPARAM lParam)
00478 {
00479   domouse(vgui_BUTTON_UP, vgui_LEFT, wParam, LOWORD(lParam), HIWORD(lParam));
00480 }
00481 
00482 void vgui_win32_adaptor::OnMButtonDown(WPARAM wParam, LPARAM lParam)
00483 {
00484   domouse(vgui_BUTTON_DOWN, vgui_MIDDLE, wParam, LOWORD(lParam), HIWORD(lParam));
00485 }
00486 
00487 void vgui_win32_adaptor::OnMButtonUp(WPARAM wParam, LPARAM lParam)
00488 {
00489   domouse(vgui_BUTTON_UP, vgui_MIDDLE, wParam, LOWORD(lParam), HIWORD(lParam));
00490 }
00491 
00492 void vgui_win32_adaptor::OnRButtonDown(WPARAM wParam, LPARAM lParam)
00493 {
00494   domouse(vgui_BUTTON_DOWN, vgui_RIGHT, wParam, LOWORD(lParam), HIWORD(lParam));
00495 }
00496 
00497 void vgui_win32_adaptor::OnRButtonUp(WPARAM wParam, LPARAM lParam)
00498 {
00499   domouse(vgui_BUTTON_UP, vgui_RIGHT, wParam, LOWORD(lParam), HIWORD(lParam));
00500 }
00501 
00502 
00503 void vgui_win32_adaptor::OnMouseMove(WPARAM wParam, LPARAM lParam)
00504 {
00505   domouse(vgui_MOTION, vgui_BUTTON_NULL, wParam, LOWORD(lParam), HIWORD(lParam));
00506 }
00507 
00508 void vgui_win32_adaptor::OnMouseWheel(WPARAM wParam, LPARAM lParam)
00509 {
00510   short delta = HIWORD(wParam);
00511   domouse( delta > 0 ? vgui_WHEEL_UP : vgui_WHEEL_DOWN,
00512            vgui_BUTTON_NULL, LOWORD(wParam), LOWORD(lParam), HIWORD(lParam));
00513 }
00514 
00515 // Translate a win32 key into the corresponding VGUI key
00516 void vgui_win32_adaptor::translate_key(UINT nChar, UINT nFlags,
00517                                        int *the_key, int *the_ascii_char)
00518 {
00519   if (nFlags & 256) { // The 8-th bit is the extended key
00520     // Extended key, such as a function key or a key on hte numeric keypad.
00521     switch (nChar) {
00522       case VK_NEXT:
00523         *the_key = vgui_PAGE_DOWN;
00524         *the_ascii_char = vgui_PAGE_DOWN;
00525         return;
00526       case VK_PRIOR:
00527         *the_key = vgui_PAGE_UP;
00528         *the_ascii_char = vgui_PAGE_UP;
00529         return;
00530       case VK_HOME:
00531         *the_key = vgui_HOME;
00532         *the_ascii_char = vgui_HOME;
00533         return;
00534       case VK_END:
00535         *the_key = vgui_END;
00536         *the_ascii_char = vgui_END;
00537         return;
00538       case VK_LEFT:
00539         *the_key = vgui_CURSOR_LEFT;
00540         *the_ascii_char = vgui_CURSOR_LEFT;
00541         return;
00542       case VK_UP:
00543         *the_key = vgui_CURSOR_UP;
00544         *the_ascii_char = vgui_CURSOR_UP;
00545         return;
00546       case VK_RIGHT:
00547         *the_key = vgui_CURSOR_RIGHT;
00548         *the_ascii_char = vgui_CURSOR_RIGHT;
00549         return;
00550       case VK_DOWN:
00551         *the_key = vgui_CURSOR_DOWN;
00552         *the_ascii_char = vgui_CURSOR_DOWN;
00553         return;
00554       case VK_DELETE:
00555         *the_key = vgui_DELETE;
00556         *the_ascii_char = vgui_DELETE;
00557         return;
00558       case VK_INSERT:
00559         *the_key = vgui_INSERT;
00560         *the_ascii_char = vgui_INSERT;
00561         return;
00562 
00563       default:
00564         *the_key = vgui_key(0);
00565         *the_ascii_char = vgui_key(0);
00566         return;
00567     }
00568   }
00569   else if (nChar >= VK_F1 && nChar <= VK_F12)
00570   {
00571     *the_key = *the_ascii_char = vgui_F1 + (nChar - VK_F1);
00572   }
00573   else if (nChar == VK_ESCAPE )
00574     *the_key = *the_ascii_char = vgui_ESC;
00575   else if (nChar == VK_TAB )
00576     *the_key = *the_ascii_char = vgui_TAB;
00577   else if (nChar == VK_RETURN )
00578     *the_key = *the_ascii_char = vgui_RETURN;
00579   else
00580   {
00581     unsigned short buf[1024];
00582     unsigned char lpKeyState[256];
00583     vcl_memset(lpKeyState, 0, 256);
00584     vcl_memset(buf, 0, 256);
00585 
00586     int is_ok = ToAscii(nChar, nFlags & 0xff, lpKeyState, buf, 0);
00587     if (is_ok == 1)
00588       *the_key = buf[0];
00589     else
00590       *the_key = nChar;
00591 
00592     // Add modifiers to character:
00593     lpKeyState[VK_SHIFT] = GetKeyState(VK_SHIFT);
00594     lpKeyState[VK_CONTROL] = GetKeyState(VK_CONTROL);
00595 
00596     is_ok = ToAscii(nChar, nFlags & 0xff, lpKeyState, buf, 0);
00597     if (is_ok == 1)
00598       *the_ascii_char = buf[0];
00599     else
00600       *the_ascii_char = nChar;
00601   }
00602 }
00603 
00604 // Translate a Windows message into corresponding vgui event.
00605 vgui_event vgui_win32_adaptor::translate_message(WPARAM wParam,
00606                                                  LPARAM lParam, vgui_event_type evtype)
00607 {
00608   vgui_event ev(evtype);
00609 
00610   // Determine modifier.
00611   if ( GetKeyState(VK_SHIFT) & 0x8000 )
00612     ev.modifier = vgui_SHIFT;
00613   if ( GetKeyState(VK_CONTROL) & 0x8000 )
00614     ev.modifier = vgui_CTRL;
00615   if ( GetKeyState(VK_MENU) & 0x8000 )
00616     ev.modifier = vgui_ALT;
00617 
00618   // Get key and ASCII character
00619   int nChar, nFlags, key, ascii_char;
00620   nChar = wParam; // nChar and nFlags corresponds to the arguments of
00621   nFlags = HIWORD(lParam); // CWnd::OnKeyDown().
00622   translate_key(nChar, nFlags, &key, &ascii_char);
00623   ev.set_key(vgui_key(key));
00624   ev.ascii_char = vgui_key(ascii_char);
00625 
00626   return ev;
00627 }
00628 
00629 void vgui_win32_adaptor::domouse(vgui_event_type et, vgui_button b, UINT nFlags, int x, int y)
00630 {
00631   // awf: BLETCH. This offset is consistent over resize, depth, screen position, machines,
00632   // and I can't find it... Sorry.
00633   x += 2;
00634   y += 2;
00635   // FIXME
00636 
00637   vgui_event e(et);
00638 
00639   e.button = b;
00640 
00641   // Double-check the button. This op may correct the wrong calling argument.
00642   if (nFlags & MK_LBUTTON)
00643     e.button = vgui_LEFT;
00644   if (nFlags & MK_MBUTTON)
00645     e.button = vgui_MIDDLE;
00646   if (nFlags & MK_RBUTTON)
00647     e.button = vgui_RIGHT;
00648 
00649   if (nFlags & MK_SHIFT)
00650     e.modifier = vgui_modifier((int)e.modifier | vgui_SHIFT);
00651   if (nFlags & MK_CONTROL)
00652     e.modifier = vgui_modifier((int)e.modifier | vgui_CTRL);
00653 
00654   e.wx = x;
00655   e.wy = height - y;
00656 
00657   if (e.modifier == mixin::popup_modifier  && e.button == mixin::popup_button
00658                                            && e.type == vgui_BUTTON_UP)
00659   {
00660     vgui_popup_params params;
00661     params.x = x;
00662     params.y = y;
00663     last_popup = get_total_popup(params);
00664 
00665 
00666     HMENU hMenu = vgui_win32_utils::instance()->vgui_menu_to_win32ex(
00667                   last_popup, popup_callbacks, 0, true);
00668 
00669     POINT point;
00670     point.x = x; point.y = y;
00671     // TrackPopupMenu requires screen coordinates whereas (x,y) is
00672     // client coordinates.
00673     ClientToScreen(hwnd_, &point);
00674     HMENU hPopupMenu = GetSubMenu(hMenu, 0);
00675     TrackPopupMenu(hPopupMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd_, NULL);
00676   }
00677   else
00678     dispatch_to_tableau(e);
00679 
00680 # if 0 // explained below:
00681   // Grabbing the mouse here causes an issue with code that runs
00682   // another instance of the event loop in response to the event (sent
00683   // by the dispatch_to_tableau call above).  An example if
00684   // vgui_rubberband_tableau, which, on a point add, could cause a
00685   // dialog to pop up.  In general, grabbing the mouse is a very
00686   // client specific thing, and we should probably not be doing it all
00687   // the time, as it is being done here.  If we want, we may consider
00688   // putting this in the interface.  However, given vgui's goals of
00689   // being a light & thin wrapper, I don't think that's a good idea.
00690 
00691    // Grab mouse?
00692    {
00693      if (et == vgui_BUTTON_DOWN) {
00694        SetCapture(hwnd_);
00695      }
00696      else if (et != vgui_MOTION) {
00697        ReleaseCapture();
00698      }
00699    }
00700 #endif // 0
00701 }
00702