Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2011, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00029 /* */ 00030 /**************************************************************************************/ 00031 00032 #include <vlWin32/Win32Window.hpp> 00033 #include <vlCore/Time.hpp> 00034 #include <shellapi.h> 00035 00036 using namespace vl; 00037 using namespace vlWin32; 00038 00039 //----------------------------------------------------------------------------- 00040 namespace vlWin32 00041 { 00042 const wchar_t* gWin32WindowClassName = L"VisualizationLibraryWindowClass"; 00043 00044 bool registerClass() 00045 { 00046 static bool class_already_registered = false; 00047 if (!class_already_registered) 00048 { 00049 WNDCLASS wc; 00050 memset(&wc, 0, sizeof(wc)); 00051 /* only register the window class once. */ 00052 wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS; 00053 wc.lpfnWndProc = (WNDPROC)Win32Window::WindowProc; 00054 wc.cbClsExtra = 0; 00055 wc.cbWndExtra = 0; 00056 wc.hInstance = GetModuleHandle(NULL); 00057 wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); 00058 wc.hCursor = LoadCursor(NULL, IDC_ARROW); 00059 wc.hbrBackground = NULL; 00060 wc.lpszMenuName = NULL; 00061 wc.lpszClassName = gWin32WindowClassName; 00062 00063 if (!RegisterClass(&wc)) 00064 MessageBox(NULL, L"Class registration failed.", L"Visualization Library Error", MB_OK); 00065 else 00066 class_already_registered = true; 00067 } 00068 return class_already_registered; 00069 } 00070 00071 #if 0 00072 // used for debugging purposes 00073 void win32PrintError(LPTSTR lpszFunction) 00074 { 00075 TCHAR szBuf[80]; 00076 LPVOID lpMsgBuf; 00077 DWORD dw = GetLastError(); 00078 00079 FormatMessage( 00080 FORMAT_MESSAGE_ALLOCATE_BUFFER | 00081 FORMAT_MESSAGE_FROM_SYSTEM, 00082 NULL, 00083 dw, 00084 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 00085 (LPTSTR) &lpMsgBuf, 00086 0, NULL ); 00087 00088 wsprintf(szBuf, 00089 L"%s failed with error %d: %s", 00090 lpszFunction, dw, lpMsgBuf); 00091 00092 MessageBox(NULL, szBuf, L"Visualization Library Error", MB_OK); 00093 00094 LocalFree(lpMsgBuf); 00095 } 00096 #endif 00097 } 00098 //----------------------------------------------------------------------------- 00099 std::map< HWND, Win32Window* > Win32Window::mWinMap; 00100 //----------------------------------------------------------------------------- 00101 LONG WINAPI Win32Window::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 00102 { 00103 Win32Window* win = Win32Window::getWindow(hWnd); 00104 if (!win) 00105 return (LONG)DefWindowProc(hWnd, uMsg, wParam, lParam); 00106 00107 switch(uMsg) 00108 { 00109 case WM_PAINT: 00110 { 00111 // handle event and then dispatch: solves MessageBox dialog problem. 00112 LONG val = (LONG)DefWindowProc(hWnd, uMsg, wParam, lParam); 00113 if (win->hglrc() && win->hdc() && win->hwnd()) 00114 win->dispatchRunEvent(); 00115 return val; 00116 } 00117 00118 case WM_SIZE: 00119 { 00120 win->framebuffer()->setWidth( LOWORD(lParam) ); 00121 win->framebuffer()->setHeight( HIWORD(lParam) ); 00122 win->dispatchResizeEvent( LOWORD(lParam), HIWORD(lParam) ); 00123 break; 00124 } 00125 00126 case WM_MOUSEMOVE: 00127 { 00128 POINTS pt = MAKEPOINTS(lParam); 00129 win->dispatchMouseMoveEvent( pt.x, pt.y ); 00130 break; 00131 } 00132 00133 case WM_LBUTTONDBLCLK: 00134 case WM_LBUTTONDOWN: 00135 case WM_MBUTTONDBLCLK: 00136 case WM_MBUTTONDOWN: 00137 case WM_RBUTTONDBLCLK: 00138 case WM_RBUTTONDOWN: 00139 { 00140 win->mMouseDownCount++; 00141 if (win->mMouseDownCount == 1) 00142 SetCapture(win->hwnd()); 00143 EMouseButton button = UnknownButton; 00144 if (uMsg == WM_LBUTTONDBLCLK || uMsg == WM_LBUTTONDOWN) 00145 button = LeftButton; 00146 else if (uMsg == WM_MBUTTONDBLCLK || uMsg == WM_MBUTTONDOWN) 00147 button = MiddleButton; 00148 else if (uMsg == WM_RBUTTONDBLCLK || uMsg == WM_RBUTTONDOWN) 00149 button = RightButton; 00150 POINTS pt = MAKEPOINTS(lParam); 00151 win->dispatchMouseDownEvent( button, pt.x, pt.y ); 00152 break; 00153 } 00154 00155 case WM_LBUTTONUP: 00156 case WM_RBUTTONUP: 00157 case WM_MBUTTONUP: 00158 { 00159 win->mMouseDownCount--; 00160 if (win->mMouseDownCount <= 0) 00161 { 00162 ReleaseCapture(); 00163 win->mMouseDownCount = 0; 00164 } 00165 EMouseButton button = UnknownButton; 00166 if (uMsg == WM_LBUTTONUP) 00167 button = LeftButton; 00168 else if (uMsg == WM_MBUTTONUP) 00169 button = MiddleButton; 00170 else if (uMsg == WM_RBUTTONUP) 00171 button = RightButton; 00172 POINTS pt = MAKEPOINTS(lParam); 00173 win->dispatchMouseUpEvent( button, pt.x, pt.y ); 00174 break; 00175 } 00176 00177 // If you get a compilation error here: 00178 // 1 - you didn't define _WIN32_WINNT as 0x0400 or above. 00179 // 2 - you are trying to compile VL with a VERY old (unsupported) Visual Studio / Platform SDK. 00180 case WM_MOUSEWHEEL: 00181 { 00182 win->dispatchMouseWheelEvent( GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA ); 00183 break; 00184 } 00185 00186 /*case WM_CLOSE: 00187 { 00188 win->dispatchDestroyEvent(); 00189 win->destroyWin32GLWindow(); 00190 break; 00191 }*/ 00192 00193 case WM_DESTROY: 00194 { 00195 Win32Window::mWinMap.erase(hWnd); 00196 win->dispatchDestroyEvent(); 00197 win->destroyWin32GLWindow(); 00198 break; 00199 } 00200 00201 case WM_KEYDOWN: 00202 { 00203 unsigned short unicode_out = 0; 00204 vl::EKey key_out = Key_None; 00205 translateKeyEvent(wParam, lParam, unicode_out, key_out); 00206 win->dispatchKeyPressEvent(unicode_out, key_out); 00207 break; 00208 } 00209 00210 case WM_KEYUP: 00211 { 00212 unsigned short unicode_out = 0; 00213 vl::EKey key_out = Key_None; 00214 translateKeyEvent(wParam, lParam, unicode_out, key_out); 00215 win->dispatchKeyReleaseEvent(unicode_out, key_out); 00216 break; 00217 } 00218 00219 case WM_DROPFILES: 00220 { 00221 HDROP hDrop = (HDROP)wParam; 00222 int count = DragQueryFile(hDrop, 0xFFFFFFFF, 0, 0); 00223 const int char_count = 1024; 00224 std::vector<String> files; 00225 for(int i=0; i<count; ++i) 00226 { 00227 wchar_t file_path[char_count]; 00228 memset(file_path, 0, char_count); 00229 DragQueryFile(hDrop,i,file_path,char_count); 00230 files.push_back(file_path); 00231 } 00232 win->dispatchFileDroppedEvent(files); 00233 break; 00234 } 00235 00236 // WM_SYSKEYDOWN 00237 // WM_SYSKEYUP 00238 // WM_GETICON 00239 // WM_SETCURSOR 00240 // WM_SETICON 00241 // WM_CAPTURECHANGED 00242 // WM_MOUSEFIRST 00243 } 00244 00245 return (LONG)DefWindowProc(hWnd, uMsg, wParam, lParam); 00246 } 00247 //----------------------------------------------------------------------------- 00248 // Win32Window 00249 //----------------------------------------------------------------------------- 00250 Win32Window::Win32Window() 00251 { 00252 mHWND = NULL; 00253 mHDC = NULL; 00254 mHGLRC = NULL; 00255 mMouseDownCount = 0; 00256 00257 mStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; 00258 mExStyle = WS_EX_APPWINDOW | WS_EX_ACCEPTFILES; 00259 mWindowClassName = gWin32WindowClassName; 00260 } 00261 //----------------------------------------------------------------------------- 00262 Win32Window::~Win32Window() 00263 { 00264 destroyWin32GLWindow(); 00265 } 00266 //----------------------------------------------------------------------------- 00267 bool Win32Window::initWin32GLWindow(HWND parent, HGLRC share_context, const vl::String& title, const vl::OpenGLContextFormat& fmt, int x, int y, int width, int height) 00268 { 00269 destroyWin32GLWindow(); 00270 00271 if (!registerClass()) 00272 return false; 00273 00274 unsigned style = mStyle & ~(WS_CHILD|WS_OVERLAPPEDWINDOW);; 00275 style |= parent?WS_CHILD:WS_OVERLAPPEDWINDOW; 00276 00277 mHWND = CreateWindowEx( 00278 mExStyle, 00279 mWindowClassName, 00280 L"Visualization Library Win32", 00281 style, 00282 x, y, width, height, 00283 parent, NULL, GetModuleHandle(NULL), NULL); 00284 00285 if (initWin32GLContext(share_context, title, fmt, x, y, width, height)) 00286 { 00287 mWinMap[mHWND] = this; 00288 return true; 00289 } 00290 else 00291 return false; 00292 } 00293 //----------------------------------------------------------------------------- 00294 Win32Window* Win32Window::getWindow(HWND hWnd) 00295 { 00296 std::map< HWND, Win32Window* >::const_iterator it = mWinMap.find(hWnd); 00297 if (it != mWinMap.end()) 00298 return it->second; 00299 else 00300 return NULL; 00301 } 00302 //----------------------------------------------------------------------------- 00303 void Win32Window::destroyWin32GLWindow() 00304 { 00305 // wglMakeCurrent(NULL, NULL) not needed 00306 00307 if (hwnd()) 00308 { 00309 bool destroy_win = mWinMap.find(mHWND) != mWinMap.end(); 00310 00311 // WM_DESTROY must be dispatched while the OpenGL context is still available! 00312 if (destroy_win) 00313 { 00314 DestroyWindow(mHWND); 00315 mHWND = NULL; 00316 } 00317 if (mHGLRC) 00318 { 00319 if ( wglDeleteContext(mHGLRC) == FALSE ) 00320 { 00321 MessageBox(NULL, L"OpenGL context creation failed.\n" 00322 L"The handle either doesn't specify a valid context or the context is being used by another thread.", L"Visualization Library Error", MB_OK); 00323 } 00324 mHGLRC = NULL; 00325 } 00326 if (mHDC) 00327 { 00328 DeleteDC(mHDC); 00329 mHDC = NULL; 00330 } 00331 } 00332 } 00333 //----------------------------------------------------------------------------- 00334 void vlWin32::dispatchUpdate() 00335 { 00336 // iterate over all opengl contexts 00337 std::map< HWND, Win32Window* > wins = Win32Window::winMap(); 00338 for( std::map< HWND, Win32Window* >::iterator it = wins.begin(); 00339 it != wins.end(); 00340 ++it ) 00341 { 00342 Win32Window* win = it->second; 00343 if ( win->continuousUpdate() ) 00344 win->update(); 00345 else 00346 Sleep(10); 00347 } 00348 } 00349 //----------------------------------------------------------------------------- 00350 void vlWin32::peekMessage(MSG& msg) 00351 { 00352 if ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) 00353 { 00354 if (msg.message != WM_QUIT) 00355 { 00356 TranslateMessage(&msg); 00357 DispatchMessage(&msg); 00358 } 00359 } 00360 else 00361 dispatchUpdate(); 00362 } 00363 //----------------------------------------------------------------------------- 00364 int vlWin32::messageLoop() 00365 { 00366 while(!Win32Window::winMap().empty()) 00367 { 00368 MSG msg = {0,0,0,0,0,0,0}; 00369 peekMessage(msg); 00370 if (msg.message == WM_QUIT) 00371 return (int)msg.wParam; 00372 } 00373 return 0; /* never reached */ 00374 } 00375 //----------------------------------------------------------------------------- 00376 void vlWin32::translateKeyEvent(WPARAM wParam, LPARAM lParam, unsigned short& unicode_out, vl::EKey& key_out) 00377 { 00378 // translate non unicode characters 00379 key_out = Key_None; 00380 unicode_out = 0; 00381 00382 switch(wParam) 00383 { 00384 case VK_CLEAR: key_out = Key_Clear; break; 00385 case VK_CONTROL: key_out = Key_Ctrl; break; 00386 case VK_LCONTROL: key_out = Key_LeftCtrl; break; 00387 case VK_RCONTROL: key_out = Key_RightCtrl; break; 00388 case VK_MENU: key_out = Key_Alt; break; 00389 case VK_LMENU: key_out = Key_LeftAlt; break; 00390 case VK_RMENU: key_out = Key_RightAlt; break; 00391 case VK_SHIFT: key_out = Key_Shift; break; 00392 case VK_LSHIFT: key_out = Key_LeftShift; break; 00393 case VK_RSHIFT: key_out = Key_RightShift; break; 00394 case VK_INSERT: key_out = Key_Insert; break; 00395 case VK_DELETE: key_out = Key_Delete; break; 00396 case VK_HOME: key_out = Key_Home; break; 00397 case VK_END: key_out = Key_End; break; 00398 case VK_PRINT: key_out = Key_Print; break; 00399 case VK_PAUSE: key_out = Key_Pause; break; 00400 case VK_PRIOR: key_out = Key_PageUp; break; 00401 case VK_NEXT: key_out = Key_PageDown; break; 00402 case VK_LEFT: key_out = Key_Left; break; 00403 case VK_RIGHT: key_out = Key_Right; break; 00404 case VK_UP: key_out = Key_Up; break; 00405 case VK_DOWN: key_out = Key_Down; break; 00406 case VK_F1: key_out = Key_F1; break; 00407 case VK_F2: key_out = Key_F2; break; 00408 case VK_F3: key_out = Key_F3; break; 00409 case VK_F4: key_out = Key_F4; break; 00410 case VK_F5: key_out = Key_F5; break; 00411 case VK_F6: key_out = Key_F6; break; 00412 case VK_F7: key_out = Key_F7; break; 00413 case VK_F8: key_out = Key_F8; break; 00414 case VK_F9: key_out = Key_F9; break; 00415 case VK_F10: key_out = Key_F10; break; 00416 case VK_F11: key_out = Key_F11; break; 00417 case VK_F12: key_out = Key_F12; break; 00418 00419 /* 00420 * VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39) 00421 * 0x40 : is unassigned 00422 * VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A) 00423 */ 00424 00425 case L'0': key_out = Key_0; break; 00426 case L'1': key_out = Key_1; break; 00427 case L'2': key_out = Key_2; break; 00428 case L'3': key_out = Key_3; break; 00429 case L'4': key_out = Key_4; break; 00430 case L'5': key_out = Key_5; break; 00431 case L'6': key_out = Key_6; break; 00432 case L'7': key_out = Key_7; break; 00433 case L'8': key_out = Key_8; break; 00434 case L'9': key_out = Key_9; break; 00435 00436 case L'A': key_out = Key_A; break; 00437 case L'B': key_out = Key_B; break; 00438 case L'C': key_out = Key_C; break; 00439 case L'D': key_out = Key_D; break; 00440 case L'E': key_out = Key_E; break; 00441 case L'F': key_out = Key_F; break; 00442 case L'G': key_out = Key_G; break; 00443 case L'H': key_out = Key_H; break; 00444 case L'I': key_out = Key_I; break; 00445 case L'J': key_out = Key_J; break; 00446 case L'K': key_out = Key_K; break; 00447 case L'L': key_out = Key_L; break; 00448 case L'M': key_out = Key_M; break; 00449 case L'N': key_out = Key_N; break; 00450 case L'O': key_out = Key_O; break; 00451 case L'P': key_out = Key_P; break; 00452 case L'Q': key_out = Key_Q; break; 00453 case L'R': key_out = Key_R; break; 00454 case L'S': key_out = Key_S; break; 00455 case L'T': key_out = Key_T; break; 00456 case L'U': key_out = Key_U; break; 00457 case L'V': key_out = Key_V; break; 00458 case L'W': key_out = Key_W; break; 00459 case L'X': key_out = Key_X; break; 00460 case L'Y': key_out = Key_Y; break; 00461 case L'Z': key_out = Key_Z; break; 00462 } 00463 00464 // fill unicode 00465 BYTE mskeys[256]; 00466 memset( mskeys, 0, sizeof(BYTE)*256 ); 00467 WCHAR unicode[4] = { 0, 0 }; 00468 if ( ToUnicode( (UINT)wParam, (UINT)((lParam >> 16) & 0xFF), mskeys, unicode, 4, 0 ) == 1 ) 00469 { 00470 unicode_out = unicode[0]; 00471 00472 // fill key 00473 switch(unicode_out) 00474 { 00475 case L'0': key_out = Key_0; break; 00476 case L'1': key_out = Key_1; break; 00477 case L'2': key_out = Key_2; break; 00478 case L'3': key_out = Key_3; break; 00479 case L'4': key_out = Key_4; break; 00480 case L'5': key_out = Key_5; break; 00481 case L'6': key_out = Key_6; break; 00482 case L'7': key_out = Key_7; break; 00483 case L'8': key_out = Key_8; break; 00484 case L'9': key_out = Key_9; break; 00485 00486 case L'A': key_out = Key_A; break; 00487 case L'B': key_out = Key_B; break; 00488 case L'C': key_out = Key_C; break; 00489 case L'D': key_out = Key_D; break; 00490 case L'E': key_out = Key_E; break; 00491 case L'F': key_out = Key_F; break; 00492 case L'G': key_out = Key_G; break; 00493 case L'H': key_out = Key_H; break; 00494 case L'I': key_out = Key_I; break; 00495 case L'J': key_out = Key_J; break; 00496 case L'K': key_out = Key_K; break; 00497 case L'L': key_out = Key_L; break; 00498 case L'M': key_out = Key_M; break; 00499 case L'N': key_out = Key_N; break; 00500 case L'O': key_out = Key_O; break; 00501 case L'P': key_out = Key_P; break; 00502 case L'Q': key_out = Key_Q; break; 00503 case L'R': key_out = Key_R; break; 00504 case L'S': key_out = Key_S; break; 00505 case L'T': key_out = Key_T; break; 00506 case L'U': key_out = Key_U; break; 00507 case L'V': key_out = Key_V; break; 00508 case L'W': key_out = Key_W; break; 00509 case L'X': key_out = Key_X; break; 00510 case L'Y': key_out = Key_Y; break; 00511 case L'Z': key_out = Key_Z; break; 00512 00513 case L'a': key_out = Key_A; break; 00514 case L'b': key_out = Key_B; break; 00515 case L'c': key_out = Key_C; break; 00516 case L'd': key_out = Key_D; break; 00517 case L'e': key_out = Key_E; break; 00518 case L'f': key_out = Key_F; break; 00519 case L'g': key_out = Key_G; break; 00520 case L'h': key_out = Key_H; break; 00521 case L'i': key_out = Key_I; break; 00522 case L'j': key_out = Key_J; break; 00523 case L'k': key_out = Key_K; break; 00524 case L'l': key_out = Key_L; break; 00525 case L'm': key_out = Key_M; break; 00526 case L'n': key_out = Key_N; break; 00527 case L'o': key_out = Key_O; break; 00528 case L'p': key_out = Key_P; break; 00529 case L'q': key_out = Key_Q; break; 00530 case L'r': key_out = Key_R; break; 00531 case L's': key_out = Key_S; break; 00532 case L't': key_out = Key_T; break; 00533 case L'u': key_out = Key_U; break; 00534 case L'v': key_out = Key_V; break; 00535 case L'w': key_out = Key_W; break; 00536 case L'x': key_out = Key_X; break; 00537 case L'y': key_out = Key_Y; break; 00538 case L'z': key_out = Key_Z; break; 00539 00540 case 13: key_out = Key_Return; break; 00541 case 8: key_out = Key_BackSpace; break; 00542 case 9: key_out = Key_Tab; break; 00543 case L' ': key_out = Key_Space; break; 00544 00545 case 27: key_out = Key_Escape; break; 00546 case L'!': key_out = Key_Exclam; break; 00547 case L'"': key_out = Key_QuoteDbl; break; 00548 case L'#': key_out = Key_Hash; break; 00549 case L'$': key_out = Key_Dollar; break; 00550 case L'&': key_out = Key_Ampersand; break; 00551 case L'\'': key_out = Key_Quote; break; 00552 case L'(': key_out = Key_LeftParen; break; 00553 case L')': key_out = Key_RightParen; break; 00554 case L'*': key_out = Key_Asterisk; break; 00555 case L'+': key_out = Key_Plus; break; 00556 case L',': key_out = Key_Comma; break; 00557 case L'-': key_out = Key_Minus; break; 00558 case L'.': key_out = Key_Period; break; 00559 case L'\\': key_out = Key_Slash; break; 00560 case L':': key_out = Key_Colon; break; 00561 case L';': key_out = Key_Semicolon; break; 00562 case L'<': key_out = Key_Less; break; 00563 case L'=': key_out = Key_Equal; break; 00564 case L'>': key_out = Key_Greater; break; 00565 case L'?': key_out = Key_Question; break; 00566 case L'@': key_out = Key_At; break; 00567 case L'[': key_out = Key_LeftBracket; break; 00568 case L'/': key_out = Key_BackSlash; break; 00569 case L']': key_out = Key_RightBracket; break; 00570 case L'|': key_out = Key_Caret; break; 00571 case L'_': key_out = Key_Underscore; break; 00572 case L'`': key_out = Key_QuoteLeft; break; 00573 } 00574 } 00575 } 00576 //-----------------------------------------------------------------------------