LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { m_inputEvent.keyboardModifiers = 0; if(IsKeyDown(VK_CONTROL)) m_inputEvent.keyboardModifiers |= Fw::KeyboardCtrlModifier; if(IsKeyDown(VK_SHIFT)) m_inputEvent.keyboardModifiers |= Fw::KeyboardShiftModifier; if(IsKeyDown(VK_MENU)) m_inputEvent.keyboardModifiers |= Fw::KeyboardAltModifier; switch(uMsg) { case WM_SETCURSOR: { if(m_cursor) SetCursor(m_cursor); else return DefWindowProc(hWnd, uMsg, wParam, lParam); break; } case WM_ACTIVATE: { m_focused = !(wParam == WA_INACTIVE); releaseAllKeys(); break; } case WM_SETFOCUS: case WM_KILLFOCUS: { releaseAllKeys(); break; } case WM_CHAR: { if(wParam >= 32 && wParam <= 255) { m_inputEvent.reset(Fw::KeyTextInputEvent); m_inputEvent.keyText = wParam; if(m_onInputEvent) m_onInputEvent(m_inputEvent); } break; } case WM_CLOSE: { m_onClose(); break; } case WM_KEYDOWN: { processKeyDown(retranslateVirtualKey(wParam, lParam)); break; } case WM_KEYUP: { processKeyUp(retranslateVirtualKey(wParam, lParam)); break; } case WM_SYSKEYUP: { processKeyUp(retranslateVirtualKey(wParam, lParam)); break; } case WM_SYSKEYDOWN: { if(wParam == VK_F4 && m_inputEvent.keyboardModifiers & Fw::KeyboardAltModifier) return DefWindowProc(hWnd, uMsg, wParam, lParam); processKeyDown(retranslateVirtualKey(wParam, lParam)); break; } case WM_LBUTTONDOWN: { SetCapture(m_window); m_inputEvent.reset(Fw::MousePressInputEvent); m_inputEvent.mouseButton = Fw::MouseLeftButton; m_mouseButtonStates[Fw::MouseLeftButton] = true; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_LBUTTONUP: { SetCapture(NULL); m_inputEvent.reset(Fw::MouseReleaseInputEvent); m_inputEvent.mouseButton = Fw::MouseLeftButton; m_mouseButtonStates[Fw::MouseLeftButton] = false; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_MBUTTONDOWN: { SetCapture(m_window); m_inputEvent.reset(Fw::MousePressInputEvent); m_inputEvent.mouseButton = Fw::MouseMidButton; m_mouseButtonStates[Fw::MouseMidButton] = true; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_MBUTTONUP: { SetCapture(NULL); m_inputEvent.reset(Fw::MouseReleaseInputEvent); m_inputEvent.mouseButton = Fw::MouseMidButton; m_mouseButtonStates[Fw::MouseMidButton] = false; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_RBUTTONDOWN: { SetCapture(m_window); m_inputEvent.reset(Fw::MousePressInputEvent); m_inputEvent.mouseButton = Fw::MouseRightButton; m_mouseButtonStates[Fw::MouseRightButton] = true; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_RBUTTONUP: { SetCapture(NULL); m_inputEvent.reset(Fw::MouseReleaseInputEvent); m_inputEvent.mouseButton = Fw::MouseRightButton; m_mouseButtonStates[Fw::MouseRightButton] = false; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_MOUSEMOVE: { m_inputEvent.reset(Fw::MouseMoveInputEvent); Point newMousePos(LOWORD(lParam), HIWORD(lParam)); if(newMousePos.x >= 32767) newMousePos.x = 0; else newMousePos.x = std::min<int32>(newMousePos.x, m_size.width()); if(newMousePos.y >= 32767) newMousePos.y = 0; else newMousePos.y = std::min<int32>(newMousePos.y, m_size.height()); m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos; m_inputEvent.mousePos = newMousePos; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_MOUSEWHEEL: { m_inputEvent.reset(Fw::MouseWheelInputEvent); m_inputEvent.mouseButton = Fw::MouseMidButton; m_inputEvent.wheelDirection = ((short)HIWORD(wParam)) > 0 ? Fw::MouseWheelUp : Fw::MouseWheelDown; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case WM_MOVE: { m_position.x = (short)LOWORD(lParam); m_position.y = (short)HIWORD(lParam); break; } case WM_GETMINMAXINFO: { LPMINMAXINFO pMMI = (LPMINMAXINFO)lParam; Rect adjustedRect = adjustWindowRect(Rect(0, 0, m_minimumSize)); pMMI->ptMinTrackSize.x = adjustedRect.width(); pMMI->ptMinTrackSize.y = adjustedRect.height(); break; } case WM_SIZE: { bool forceResize = false; switch(wParam) { case SIZE_MAXIMIZED: m_maximized = true; m_visible = true; forceResize = true; break; case SIZE_RESTORED: m_maximized = false; m_visible = true; forceResize = true; break; case SIZE_MINIMIZED: m_visible = false; break; } if(m_visible && m_deviceContext) internalRestoreGLContext(); Size size = Size(LOWORD(lParam), HIWORD(lParam)); size.setWidth(std::max<int32>(std::min<int32>(size.width(), 7680), 32)); size.setHeight(std::max<int32>(std::min<int32>(size.height(), 4320), 32)); if(m_visible && (forceResize || m_size != size)) { m_size = size; m_onResize(m_size); } break; } default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } return 0; }
void X11Window::poll() { bool needsResizeUpdate = false; XEvent event, peekEvent; while(XPending(m_display) > 0) { XNextEvent(m_display, &event); // check for repeated key releases bool repatedKeyRelease = false; if(event.type == KeyRelease && XPending(m_display)) { XPeekEvent(m_display, &peekEvent); if((peekEvent.type == KeyPress) && (peekEvent.xkey.keycode == event.xkey.keycode) && ((peekEvent.xkey.time-event.xkey.time) < 2)) repatedKeyRelease = true; } // process keydown and keyrelease events first if(event.type == KeyPress || (event.type == KeyRelease && !repatedKeyRelease)) { // remove caps lock and shift maks XKeyEvent xkey = event.xkey; xkey.state &= ~(ShiftMask | LockMask); // lookup keysym and translate it KeySym keysym; char buf[32]; XLookupString(&xkey, buf, sizeof(buf), &keysym, 0); Fw::Key keyCode = Fw::KeyUnknown; if(m_keyMap.find(keysym) != m_keyMap.end()) keyCode = m_keyMap[keysym]; if(event.type == KeyPress) processKeyDown(keyCode); else if(event.type == KeyRelease) processKeyUp(keyCode); } // call filter because xim will discard KeyPress events when keys still composing if(XFilterEvent(&event, m_window)) continue; // discard repated key releases if(repatedKeyRelease) continue; switch(event.type) { case ClientMessage: { // close event if((Atom)event.xclient.data.l[0] == m_wmDelete && m_onClose) m_onClose(); break; } case ConfigureNotify: { Size newSize(event.xconfigure.width, event.xconfigure.height); Point newPos(event.xconfigure.x, event.xconfigure.y); // updates window size if(m_size != newSize) { m_size = newSize; needsResizeUpdate = true; } // checks if the window is maximized if(m_visible) { m_maximized = false; Atom wmState = XInternAtom(m_display, "_NET_WM_STATE", False); Atom wmStateMaximizedVert = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); Atom wmStateMaximizedHorz = XInternAtom(m_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); Atom actualType; ulong i, numItems, bytesAfter; uchar *propertyValue = NULL; int actualFormat; if(XGetWindowProperty(m_display, m_window, wmState, 0, 1024, False, XA_ATOM, &actualType, &actualFormat, &numItems, &bytesAfter, &propertyValue) == Success) { Atom *atoms = (Atom*)propertyValue; int maximizedMask = 0; for(i=0; i<numItems; ++i) { if(atoms[i] == wmStateMaximizedVert) maximizedMask |= 1; else if(atoms[i] == wmStateMaximizedHorz) maximizedMask |= 2; } if(maximizedMask == 3) m_maximized = true; XFree(propertyValue); } } // updates window pos if(m_visible) m_position = newPos; updateUnmaximizedCoords(); break; } case SelectionRequest: { XEvent respond; XSelectionRequestEvent *req = &(event.xselectionrequest); Atom targets = XInternAtom(m_display, "TARGETS", False); if(req->target == targets) { Atom typeList[] = { XInternAtom(m_display, "UTF8_STRING", False), XInternAtom(m_display, "TEXT", False), XInternAtom(m_display, "STRING", False), XInternAtom(m_display, "text/plain", False), XInternAtom(m_display, "COMPOUND_TEXT", False), XA_STRING }; XChangeProperty(m_display, req->requestor, req->property, req->target, 8, PropModeReplace, (uchar *)&typeList, sizeof(typeList)); respond.xselection.property = req->property; } else { XChangeProperty(m_display, req->requestor, req->property, req->target, 8, PropModeReplace, (uchar *)m_clipboardText.c_str(), m_clipboardText.length()); respond.xselection.property = req->property; } respond.xselection.type = SelectionNotify; respond.xselection.display = req->display; respond.xselection.requestor = req->requestor; respond.xselection.selection = req->selection; respond.xselection.target = req->target; respond.xselection.time = req->time; XSendEvent(m_display, req->requestor, 0, 0, &respond); XFlush(m_display); break; } // process text events case KeyPress: { // text cant be insert while holding ctrl or alt if(event.xkey.state & ControlMask || event.xkey.state & Mod1Mask) break; // process key text events KeySym keysym; char buf[32]; memset(buf, 0, 32); int len; // lookup for keyText if(m_xic) { // with xim we can get latin1 input correctly Status status; len = XmbLookupString(m_xic, &event.xkey, buf, sizeof(buf), &keysym, &status); } else { // otherwise use XLookupString, but often it doesn't work right with dead keys static XComposeStatus compose = {NULL, 0}; len = XLookupString(&event.xkey, buf, sizeof(buf), &keysym, &compose); } // filter unwanted characters if(len == 0 || (uchar)(buf[0]) < 32 || keysym == XK_BackSpace || keysym == XK_Return || keysym == XK_Delete || keysym == XK_Escape) break; std::string text = buf; //g_logger.debug("char: ", buf[0], " code: ", (int)((uchar)buf[0])); if(m_onInputEvent && text.length() > 0) { m_inputEvent.reset(Fw::KeyTextInputEvent); m_inputEvent.keyText = text; m_onInputEvent(m_inputEvent); } break; } case ButtonPress: case ButtonRelease: { m_inputEvent.reset(); m_inputEvent.type = (event.type == ButtonPress) ? Fw::MousePressInputEvent : Fw::MouseReleaseInputEvent; switch(event.xbutton.button) { case Button1: m_inputEvent.mouseButton = Fw::MouseLeftButton; m_mouseButtonStates[Fw::MouseLeftButton] = (event.type == ButtonPress); break; case Button3: m_inputEvent.mouseButton = Fw::MouseRightButton; m_mouseButtonStates[Fw::MouseRightButton] = (event.type == ButtonPress); break; case Button2: m_inputEvent.mouseButton = Fw::MouseMidButton; m_mouseButtonStates[Fw::MouseMidButton] = (event.type == ButtonPress); break; case Button4: if(event.type == ButtonPress) { m_inputEvent.type = Fw::MouseWheelInputEvent; m_inputEvent.mouseButton = Fw::MouseMidButton; m_inputEvent.wheelDirection = Fw::MouseWheelUp; } break; case Button5: if(event.type == ButtonPress) { m_inputEvent.type = Fw::MouseWheelInputEvent; m_inputEvent.mouseButton = Fw::MouseMidButton; m_inputEvent.wheelDirection = Fw::MouseWheelDown; } break; default: m_inputEvent.type = Fw::NoInputEvent; break; } if(m_inputEvent.type != Fw::NoInputEvent && m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case MotionNotify: { m_inputEvent.reset(); m_inputEvent.type = Fw::MouseMoveInputEvent; Point newMousePos(event.xbutton.x, event.xbutton.y); m_inputEvent.mouseMoved = newMousePos - m_inputEvent.mousePos; m_inputEvent.mousePos = newMousePos; if(m_onInputEvent) m_onInputEvent(m_inputEvent); break; } case MapNotify: m_visible = true; needsResizeUpdate = true; break; case UnmapNotify: m_visible = false; releaseAllKeys(); break; case FocusIn: m_focused = true; releaseAllKeys(); break; case FocusOut: m_focused = false; releaseAllKeys(); break; case Expose: // window needs redraw break; } } if(needsResizeUpdate && m_onResize) m_onResize(m_size); fireKeysPress(); }
void Window::close() { if(m_onClose) m_onClose(*this); this->as<Widget>().remove(); }