static void dispatchKey(PuglView* view, XEvent* event, bool press) { KeySym sym; char str[5]; const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); if (sym == XK_Escape && view->closeFunc && !press && !view->parent) { view->closeFunc(view); view->redisplay = false; return; } if (n == 0) { return; } if (n > 1) { fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); return; } const PuglKey special = keySymToSpecial(sym); if (special && view->specialFunc) { view->specialFunc(view, press, special); } else if (!special && view->keyboardFunc) { view->keyboardFunc(view, press, str[0]); } }
static void dispatchKey(PuglView* view, XEvent* event, bool press) { KeySym sym; char str[5]; PuglKey special; const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); if (sym == XK_Escape && view->closeFunc && !press && !view->parent) { view->closeFunc(view); view->redisplay = false; return; } if (n == 0) { goto send_event; return; } if (n > 1) { fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); goto send_event; return; } special = keySymToSpecial(sym); if (special && view->specialFunc) { if (view->specialFunc(view, press, special) == 0) { return; } } else if (!special && view->keyboardFunc) { if (view->keyboardFunc(view, press, str[0]) == 0) { return; } } send_event: if (view->parent != 0) { event->xkey.time = 0; // purposefully set an invalid time, used for feedback detection on bad hosts event->xany.window = view->parent; XSendEvent(view->impl->display, view->parent, False, NoEventMask, event); } }
PuglStatus puglProcessEvents(PuglView* view) { XEvent event; while (XPending(view->impl->display) > 0) { XNextEvent(view->impl->display, &event); switch (event.type) { case MapNotify: puglReshape(view, view->width, view->height); break; case ConfigureNotify: if ((event.xconfigure.width != view->width) || (event.xconfigure.height != view->height)) { puglReshape(view, event.xconfigure.width, event.xconfigure.height); } break; case Expose: if (event.xexpose.count != 0) { break; } puglDisplay(view); view->redisplay = false; break; case MotionNotify: setModifiers(view, event.xmotion.state); if (view->motionFunc) { view->motionFunc(view, event.xmotion.x, event.xmotion.y); } break; case ButtonPress: setModifiers(view, event.xbutton.state); if (event.xbutton.button >= 4 && event.xbutton.button <= 7) { if (view->scrollFunc) { float dx = 0, dy = 0; switch (event.xbutton.button) { case 4: dy = 1.0f; break; case 5: dy = -1.0f; break; case 6: dx = -1.0f; break; case 7: dx = 1.0f; break; } view->scrollFunc(view, dx, dy); } break; } // nobreak case ButtonRelease: setModifiers(view, event.xbutton.state); if (view->mouseFunc && (event.xbutton.button < 4 || event.xbutton.button > 7)) { view->mouseFunc(view, event.xbutton.button, event.type == ButtonPress, event.xbutton.x, event.xbutton.y); } break; case KeyPress: { setModifiers(view, event.xkey.state); KeySym sym; char str[5]; int n = XLookupString(&event.xkey, str, 4, &sym, NULL); PuglKey key = keySymToSpecial(sym); if (!key && view->keyboardFunc) { if (n == 1) { view->keyboardFunc(view, true, str[0]); } else { fprintf(stderr, "warning: Unknown key %X\n", (int)sym); } } else if (view->specialFunc) { view->specialFunc(view, true, key); } } break; case KeyRelease: { setModifiers(view, event.xkey.state); bool repeated = false; if (view->ignoreKeyRepeat && XEventsQueued(view->impl->display, QueuedAfterReading)) { XEvent next; XPeekEvent(view->impl->display, &next); if (next.type == KeyPress && next.xkey.time == event.xkey.time && next.xkey.keycode == event.xkey.keycode) { XNextEvent(view->impl->display, &event); repeated = true; } } if (!repeated && view->keyboardFunc) { KeySym sym = XKeycodeToKeysym( view->impl->display, event.xkey.keycode, 0); PuglKey special = keySymToSpecial(sym); if (!special) { view->keyboardFunc(view, false, sym); } else if (view->specialFunc) { view->specialFunc(view, false, special); } } } break; case ClientMessage: if (!strcmp(XGetAtomName(view->impl->display, event.xclient.message_type), "WM_PROTOCOLS")) { if (view->closeFunc) { view->closeFunc(view); } } break; default: break; } } if (view->redisplay) { puglDisplay(view); } return PUGL_SUCCESS; }
static LRESULT handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) { MSG msg; PAINTSTRUCT ps; PuglKey key; setModifiers(view); switch (message) { case WM_CREATE: case WM_SHOWWINDOW: case WM_SIZE: puglReshape(view, view->width, view->height); break; case WM_PAINT: BeginPaint(view->impl->hwnd, &ps); puglDisplay(view); EndPaint(view->impl->hwnd, &ps); break; case WM_MOUSEMOVE: if (view->motionFunc) { view->motionFunc( view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } break; case WM_LBUTTONDOWN: processMouseEvent(view, 1, true, lParam); break; case WM_MBUTTONDOWN: processMouseEvent(view, 2, true, lParam); break; case WM_RBUTTONDOWN: processMouseEvent(view, 3, true, lParam); break; case WM_LBUTTONUP: processMouseEvent(view, 1, false, lParam); break; case WM_MBUTTONUP: processMouseEvent(view, 2, false, lParam); break; case WM_RBUTTONUP: processMouseEvent(view, 3, false, lParam); break; case WM_MOUSEWHEEL: if (view->scrollFunc) { view->scrollFunc( view, 0, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); } break; case WM_MOUSEHWHEEL: if (view->scrollFunc) { view->scrollFunc( view, (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0); } break; case WM_KEYDOWN: if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { break; } // else nobreak case WM_KEYUP: if (key = keySymToSpecial(wParam)) { if (view->specialFunc) { view->specialFunc(view, message == WM_KEYDOWN, key); } } else if (view->keyboardFunc) { view->keyboardFunc(view, message == WM_KEYDOWN, wParam); } break; case WM_QUIT: if (view->closeFunc) { view->closeFunc(view); } break; default: return DefWindowProc( view->impl->hwnd, message, wParam, lParam); } return 0; }
static LRESULT handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; PuglKey key; setModifiers(view); switch (message) { case WM_CREATE: case WM_SHOWWINDOW: case WM_SIZE: RECT rect; GetClientRect(view->impl->hwnd, &rect); puglReshape(view, rect.right, rect.bottom); view->width = rect.right; view->height = rect.bottom; break; case WM_PAINT: BeginPaint(view->impl->hwnd, &ps); puglDisplay(view); EndPaint(view->impl->hwnd, &ps); break; case WM_MOUSEMOVE: if (view->motionFunc) { view->event_timestamp_ms = GetMessageTime(); view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); } break; case WM_LBUTTONDOWN: processMouseEvent(view, 1, true, lParam); break; case WM_MBUTTONDOWN: processMouseEvent(view, 2, true, lParam); break; case WM_RBUTTONDOWN: processMouseEvent(view, 3, true, lParam); break; case WM_LBUTTONUP: processMouseEvent(view, 1, false, lParam); break; case WM_MBUTTONUP: processMouseEvent(view, 2, false, lParam); break; case WM_RBUTTONUP: processMouseEvent(view, 3, false, lParam); break; case WM_MOUSEWHEEL: if (view->scrollFunc) { view->event_timestamp_ms = GetMessageTime(); view->scrollFunc( view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), 0.0f, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); } break; case WM_MOUSEHWHEEL: if (view->scrollFunc) { view->event_timestamp_ms = GetMessageTime(); view->scrollFunc( view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0.0f); } break; case WM_KEYDOWN: if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { break; } // else nobreak case WM_KEYUP: view->event_timestamp_ms = GetMessageTime(); if ((key = keySymToSpecial(wParam))) { if (view->specialFunc) { view->specialFunc(view, message == WM_KEYDOWN, key); } } else if (view->keyboardFunc) { view->keyboardFunc(view, message == WM_KEYDOWN, wParam); } break; case WM_QUIT: case PUGL_LOCAL_CLOSE_MSG: if (view->closeFunc) { view->closeFunc(view); } break; default: return DefWindowProc( view->impl->hwnd, message, wParam, lParam); } return 0; }