//---------------------------------------------------------------------------- static void SpecialKeyDownCallback (int key, int x, int y) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (theApp) { theApp->OnSpecialKeyDown(key, x, y); } }
//---------------------------------------------------------------------------- static pascal OSStatus ProcessKeyDown (EventHandlerCallRef, EventRef evt, void*) { char charCode; GetEventParameter(evt, kEventParamKeyMacCharCodes, typeChar, 0, sizeof(charCode), 0, &charCode); WindowApplication* theApp = (WindowApplication*)Application::TheApplication; CGrafPtr currPort; GetPort(&currPort); SetPortWindowPort((WindowRef)(theApp->GetWindowID())); Point mouseLoc; GetMouse(&mouseLoc); SetPort(currPort); if (charCode == kEscapeCharCode) { // Quit the application when 'esc' is pressed. QuitApplicationEventLoop(); return eventNotHandledErr; } if (isalnum(charCode) || isprint(charCode)) { theApp->OnKeyDown(charCode, mouseLoc.h, mouseLoc.v); } else { if (charCode == kFunctionKeyCharCode) { // Function key - get key identity. UInt32 keyCode; GetEventParameter(evt, kEventParamKeyCode, typeUInt32, 0, sizeof(keyCode), 0, &keyCode); charCode = keyCode & 0x000000FF; } // Do not filter for specific keys. This allows for keys such as tab, // delete, enter. theApp->OnSpecialKeyDown(charCode, mouseLoc.h, mouseLoc.v); } // Allow standard handler to run. return eventNotHandledErr; }
//---------------------------------------------------------------------------- int WindowApplication::Main (int numArguments, char** arguments) { // Initialize the extra data. TODO: Port the extra-data system of WM4 // to WM5. memset(gsExtraData, 0, APP_EXTRA_DATA_QUANTITY*sizeof(char)); WindowApplication* theApp = (WindowApplication*)TheApplication; theApp->KEY_TERMINATE = KEY_ESCAPE; // OpenGL uses a projection matrix for depth in [-1,1]. Camera::SetDefaultDepthType(Camera::PM_DEPTH_MINUS_ONE_TO_ONE); // Allow work to be done before the window is created. if (!theApp->OnPrecreate()) { return -1; } // Connect to the X server. const char* displayName = 0; Display* display = XOpenDisplay(displayName); if (!display) { return -2; } // Make sure the X server has OpenGL GLX extensions. int errorBase, eventBase; Bool success = glXQueryExtension(display, &errorBase, &eventBase); assertion(success == True, "GLX extensions not found.\n"); if (!success) { return -3; } // Partial construction of a GLX renderer. The window for the renderer // is not yet constructed. When it is, the window identifier is supplied // to the renderer to complete its construction. RendererInput input; input.mDisplay = display; input.mVisual = 0; input.mContext = 0; mRenderer = new0 Renderer(input, theApp->GetWidth(), theApp->GetHeight(), mColorFormat, mDepthStencilFormat, mNumMultisamples); if (!input.mVisual || !input.mContext) { return -4; } // Create an X Window with the visual information created by the renderer // constructor. The visual information might not be the default, so // create an X colormap to use. Window rootWindow = RootWindow(display, input.mVisual->screen); Colormap cMap = XCreateColormap(display, rootWindow, input.mVisual->visual, AllocNone); // Set the event mask to include exposure (paint), button presses (mouse), // and key presses (keyboard). XSetWindowAttributes windowAttributes; windowAttributes.colormap = cMap; windowAttributes.border_pixel = 0; windowAttributes.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | Button1MotionMask | Button2MotionMask | Button3MotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask; int xPos = theApp->GetXPosition(); int yPos = theApp->GetYPosition(); unsigned int width = (unsigned int)theApp->GetWidth(); unsigned int height = (unsigned int)theApp->GetHeight(); unsigned int borderWidth = 0; unsigned long valueMask = CWBorderPixel | CWColormap | CWEventMask; Window window = XCreateWindow(display, rootWindow, xPos, yPos, width, height, borderWidth, input.mVisual->depth, InputOutput, input.mVisual->visual, valueMask, &windowAttributes); XSizeHints hints; hints.flags = PPosition | PSize; hints.x = xPos; hints.y = yPos; hints.width = width; hints.height = height; XSetNormalHints(display, window, &hints); const char* iconName = theApp->GetWindowTitle(); Pixmap iconPixmap = None; XSetStandardProperties(display, window, theApp->GetWindowTitle(), iconName, iconPixmap, arguments, numArguments, &hints); // Intercept the close-window event when the user selects the // window close button. The event is a "client message". Atom wmDelete = XInternAtom(display, "WM_DELETE_WINDOW", False); XSetWMProtocols(display, window, &wmDelete, 1); // Finish the construction of the renderer. GlxRendererData* data = (GlxRendererData*)mRenderer->mData; if (!data->FinishConstruction(window, mRenderer)) { return -5; } if (theApp->OnInitialize()) { // The default OnPreidle() clears the buffers. Allow the application // to fill them before the window is shown and before the event loop // starts. theApp->OnPreidle(); // Display the window. XMapWindow(display, window); // Start the message pump. bool applicationRunning = true; while (applicationRunning) { if (!XPending(display)) { theApp->OnIdle(); continue; } XEvent evt; XNextEvent(display, &evt); int index; bool state; if (evt.type == ButtonPress || evt.type == ButtonRelease) { theApp->OnMouseClick(evt.xbutton.button, evt.xbutton.type, evt.xbutton.x, evt.xbutton.y, evt.xbutton.state); if (evt.type == ButtonPress) { index = GLXAPP_BUTTONDOWN + evt.xbutton.button; state = true; SetExtraData(index, sizeof(bool), &state); } else { index = GLXAPP_BUTTONDOWN + evt.xbutton.button; state = false; SetExtraData(index, sizeof(bool), &state); } continue; } if (evt.type == MotionNotify) { int button = 0; index = GLXAPP_BUTTONDOWN + 1; GetExtraData(index, sizeof(bool), &state); if (state) { button = MOUSE_LEFT_BUTTON; } else { index = GLXAPP_BUTTONDOWN + 2; GetExtraData(index, sizeof(bool), &state); if (state) { button = MOUSE_MIDDLE_BUTTON; } else { index = GLXAPP_BUTTONDOWN + 3; GetExtraData(index, sizeof(bool), &state); if (state) { button = MOUSE_RIGHT_BUTTON; } } } if (button > 0) { theApp->OnMotion(button, evt.xmotion.x, evt.xmotion.y, evt.xmotion.state); } else { theApp->OnPassiveMotion(evt.xmotion.x, evt.xmotion.y); } continue; } if (evt.type == KeyPress || evt.type == KeyRelease) { KeySym keySym = XKeycodeToKeysym(display, evt.xkey.keycode, 0); int key = (keySym & 0x00FF); // Quit application if the KEY_TERMINATE key is pressed. if (key == theApp->KEY_TERMINATE) { XDestroyWindow(display, window); applicationRunning = false; continue; } // Adjust for special keys that exist on the key pad and on // the number pad. if ((keySym & 0xFF00) != 0) { if (0x50 <= key && key <= 0x57) { // keypad Home, {L,U,R,D}Arrow, Pg{Up,Dn}, End key += 0x45; } else if (key == 0x63) { // keypad Insert key = 0x9e; } else if (key == 0xFF) { // keypad Delete key = 0x9f; } else if (key == 0xE1 || key == 0xE2) { // L-shift or R-shift key = KEY_SHIFT; state = (evt.type == KeyPress); SetExtraData(GLXAPP_SHIFTDOWN, sizeof(bool), &state); } else if (key == 0xE3 || key == 0xE4) { // L-ctrl or R-ctrl key = KEY_CONTROL; } else if (key == 0xE9 || key == 0xEA) { // L-alt or R-alt key = KEY_ALT; } else if (key == 0xEB || key == 0xEC) { key = KEY_COMMAND; } } if ((KEY_HOME <= key && key <= KEY_END) || (KEY_F1 <= key && key <= KEY_F12) || (KEY_SHIFT <= key && key <= KEY_COMMAND)) { if (evt.type == KeyPress) { theApp->OnSpecialKeyDown(key, evt.xbutton.x, evt.xbutton.y); } else { theApp->OnSpecialKeyUp(key, evt.xbutton.x, evt.xbutton.y); } } else { // Get key-modifier state. Adjust for shift state. unsigned char ucKey = (unsigned char)key; GetExtraData(GLXAPP_SHIFTDOWN, sizeof(bool), &state); if (state && 'a' <= ucKey && ucKey <= 'z') { ucKey = (unsigned char)(key - 32); } if (evt.type == KeyPress) { theApp->OnKeyDown(ucKey, evt.xbutton.x, evt.xbutton.y); } else { theApp->OnKeyUp(ucKey, evt.xbutton.x, evt.xbutton.y); } } continue; } if (evt.type == Expose) { theApp->OnDisplay(); continue; } if (evt.type == ConfigureNotify) { theApp->OnMove(evt.xconfigure.x, evt.xconfigure.y); theApp->OnResize(evt.xconfigure.width, evt.xconfigure.height); continue; } if (evt.type == ClientMessage && evt.xclient.data.l[0] == wmDelete) { XDestroyWindow(display, window); applicationRunning = false; continue; } } } theApp->OnTerminate(); XCloseDisplay(display); return 0; }
//---------------------------------------------------------------------------- LRESULT CALLBACK MsWindowEventHandler (HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { WindowApplication* theApp = (WindowApplication*)Application::TheApplication; if (!theApp || !theApp->GetWindowID()) { return DefWindowProc(handle, message, wParam, lParam); } switch (message) { case WM_PAINT: { PAINTSTRUCT ps; BeginPaint(handle, &ps); theApp->OnDisplay(); EndPaint(handle, &ps); return 0; } case WM_ERASEBKGND: { // This tells Windows not to erase the background (and that the // application is doing so). return 1; } case WM_MOVE: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMove(xPos, yPos); return 0; } case WM_SIZE: { int width = (int)(LOWORD(lParam)); int height = (int)(HIWORD(lParam)); theApp->OnResize(width, height); return 0; } case WM_CHAR: { unsigned char key = (unsigned char)(char)wParam; // Quit the application if the KEY_TERMINATE key is pressed. if (key == theApp->KEY_TERMINATE) { PostQuitMessage(0); return 0; } // Get the cursor position in client coordinates. POINT point; GetCursorPos(&point); ScreenToClient(handle, &point); int xPos = (int)point.x; int yPos = (int)point.y; theApp->OnKeyDown(key, xPos, yPos); return 0; } case WM_KEYDOWN: { int virtKey = (int)wParam; // Get cursor position client coordinates. POINT point; GetCursorPos(&point); ScreenToClient(handle, &point); int xPos = (int)point.x; int yPos = (int)point.y; if ((VK_F1 <= virtKey && virtKey <= VK_F12) || (VK_PRIOR <= virtKey && virtKey <= VK_DOWN) || (virtKey == VK_INSERT) || (virtKey == VK_DELETE) || (virtKey == VK_SHIFT) || (virtKey == VK_CONTROL)) { theApp->OnSpecialKeyDown(virtKey, xPos, yPos); } return 0; } case WM_KEYUP: { int virtKey = (int)wParam; // get the cursor position in client coordinates POINT point; GetCursorPos(&point); ScreenToClient(handle, &point); int xPos = (int)point.x; int yPos = (int)point.y; if ((VK_F1 <= virtKey && virtKey <= VK_F12) || (VK_PRIOR <= virtKey && virtKey <= VK_DOWN) || (virtKey == VK_INSERT) || (virtKey == VK_DELETE) || (virtKey == VK_SHIFT) || (virtKey == VK_CONTROL)) { theApp->OnSpecialKeyUp(virtKey, xPos, yPos); } else { theApp->OnKeyUp((unsigned char)virtKey, xPos, yPos); } return 0; } case WM_LBUTTONDOWN: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_LEFT_BUTTON, WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_LBUTTONUP: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_LEFT_BUTTON, WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_MBUTTONDOWN: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_MIDDLE_BUTTON, WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_MBUTTONUP: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_MIDDLE_BUTTON, WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_RBUTTONDOWN: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_RIGHT_BUTTON, WindowApplication::MOUSE_DOWN, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_RBUTTONUP: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); theApp->OnMouseClick(WindowApplication::MOUSE_RIGHT_BUTTON, WindowApplication::MOUSE_UP, xPos, yPos, PtrToUint(wParam)); return 0; } case WM_MOUSEMOVE: { int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); int button = -1; if (wParam & MK_LBUTTON) { button = WindowApplication::MOUSE_LEFT_BUTTON; } else if (wParam & MK_MBUTTON) { button = WindowApplication::MOUSE_MIDDLE_BUTTON; } else if (wParam & MK_RBUTTON) { button = WindowApplication::MOUSE_RIGHT_BUTTON; } if (button >= 0) { theApp->OnMotion(button, xPos, yPos, PtrToUint(wParam)); } else { theApp->OnPassiveMotion(xPos, yPos); } return 0; } case WM_MOUSEWHEEL: { short sWParam = (short)(HIWORD(wParam)); int delta = ((int)sWParam)/WHEEL_DELTA; int xPos = (int)(LOWORD(lParam)); int yPos = (int)(HIWORD(lParam)); unsigned int modifiers = (unsigned int)(LOWORD(wParam)); theApp->OnMouseWheel(delta, xPos, yPos, modifiers); return 0; } case WM_DESTROY: { // The DestroyWindow call when recreating the window for // multisampling causes the application to terminate. It is // not clear why the same problem did not occur in WM4. if (!gsIgnoreWindowDestroy) { PostQuitMessage(0); } gsIgnoreWindowDestroy = false; return 0; } } return DefWindowProc(handle, message, wParam, lParam); }