From fb2ec4fd62e8218ac485c4ad1992c7e01951159d Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 30 Apr 2012 06:10:29 +0000 Subject: Implement special keys and keyboard modifiers on X11. --- pugl/pugl.h | 46 +++++++++++++++++++++++++++++++++++++++++ pugl/pugl_internal.h | 16 ++++++++++++++- pugl/pugl_win.cpp | 4 ++-- pugl/pugl_x11.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++-- pugl_test.c | 32 ++++++++++++++++++++++++----- 5 files changed, 146 insertions(+), 10 deletions(-) diff --git a/pugl/pugl.h b/pugl/pugl.h index 8bc3f72..a77a831 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -77,6 +77,37 @@ typedef enum { PUGL_SUCCESS = 0 } PuglStatus; +typedef enum { + PUGL_KEY_F1 = 1, + PUGL_KEY_F2, + PUGL_KEY_F3, + PUGL_KEY_F4, + PUGL_KEY_F5, + PUGL_KEY_F6, + PUGL_KEY_F7, + PUGL_KEY_F8, + PUGL_KEY_F9, + PUGL_KEY_F10, + PUGL_KEY_F11, + PUGL_KEY_F12, + PUGL_KEY_LEFT, + PUGL_KEY_UP, + PUGL_KEY_RIGHT, + PUGL_KEY_DOWN, + PUGL_KEY_PAGE_UP, + PUGL_KEY_PAGE_DOWN, + PUGL_KEY_HOME, + PUGL_KEY_END, + PUGL_KEY_INSERT +} PuglKey; + +typedef enum { + PUGL_MOD_SHIFT = 1, /**< Shift key */ + PUGL_MOD_CTRL = 1 << 1, /**< Control key */ + PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ + PUGL_MOD_SUPER = 1 << 3, /**< Mod4/Command/Windows key */ +} PuglModifier; + /** Handle for opaque user data. */ @@ -90,6 +121,7 @@ typedef void (*PuglMouseFunc)(PuglView* view, int button, bool down, int x, int y); typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); typedef void (*PuglScrollFunc)(PuglView* view, float dx, float dy); +typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); /** Create a new GL window. @@ -124,6 +156,14 @@ puglSetHandle(PuglView* view, PuglHandle handle); PUGL_API PuglHandle puglGetHandle(PuglView* view); +/** + Get the currently active modifiers (PuglModifier flags). + + This should only be called from an event handler. +*/ +int +puglGetModifiers(PuglView* view); + /** Set the function to call when the window is closed. */ @@ -160,6 +200,12 @@ puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc); PUGL_API void puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc); +/** + Set the function to call on special events. +*/ +PUGL_API void +puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); + /** Set the function to call when the window size changes. */ diff --git a/pugl/pugl_internal.h b/pugl/pugl_internal.h index 0b04e5d..21e9eb4 100644 --- a/pugl/pugl_internal.h +++ b/pugl/pugl_internal.h @@ -36,11 +36,13 @@ struct PuglViewImpl { PuglMouseFunc mouseFunc; PuglReshapeFunc reshapeFunc; PuglScrollFunc scrollFunc; + PuglSpecialFunc specialFunc; PuglPlatformData* impl; int width; int height; + int mods; bool redisplay; }; @@ -56,6 +58,12 @@ puglGetHandle(PuglView* view) return view->handle; } +int +puglGetModifiers(PuglView* view) +{ + return view->mods; +} + void puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc) { @@ -85,7 +93,7 @@ puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc) { view->mouseFunc = mouseFunc; } - + void puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc) { @@ -97,3 +105,9 @@ puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) { view->scrollFunc = scrollFunc; } + +void +puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc) +{ + view->specialFunc = specialFunc; +} diff --git a/pugl/pugl_win.cpp b/pugl/pugl_win.cpp index f487352..a5c9dde 100644 --- a/pugl/pugl_win.cpp +++ b/pugl/pugl_win.cpp @@ -157,8 +157,8 @@ processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam) { if (view->mouseFunc) { view->mouseFunc(view, button, press, - GET_X_LPARAM(lParam), - GET_Y_LPARAM(lParam)); + GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam)); } } diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c index 606f348..f7d6e32 100644 --- a/pugl/pugl_x11.c +++ b/pugl/pugl_x11.c @@ -207,6 +207,45 @@ puglDisplay(PuglView* view) view->redisplay = false; } +static PuglKey +keySymToSpecial(KeySym sym) +{ + switch (sym) { + case XK_F1: return PUGL_KEY_F1; + case XK_F2: return PUGL_KEY_F2; + case XK_F3: return PUGL_KEY_F3; + case XK_F4: return PUGL_KEY_F4; + case XK_F5: return PUGL_KEY_F5; + case XK_F6: return PUGL_KEY_F6; + case XK_F7: return PUGL_KEY_F7; + case XK_F8: return PUGL_KEY_F8; + case XK_F9: return PUGL_KEY_F9; + case XK_F10: return PUGL_KEY_F10; + case XK_F11: return PUGL_KEY_F11; + case XK_F12: return PUGL_KEY_F12; + case XK_Left: return PUGL_KEY_LEFT; + case XK_Up: return PUGL_KEY_UP; + case XK_Right: return PUGL_KEY_RIGHT; + case XK_Down: return PUGL_KEY_DOWN; + case XK_Page_Up: return PUGL_KEY_PAGE_UP; + case XK_Page_Down: return PUGL_KEY_PAGE_DOWN; + case XK_Home: return PUGL_KEY_HOME; + case XK_End: return PUGL_KEY_END; + case XK_Insert: return PUGL_KEY_INSERT; + } + return (PuglKey)0; +} + +static void +setModifiers(PuglView* view, int xstate) +{ + view->mods = 0; + view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0; + view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0; + view->mods |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0; + view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0; +} + PuglStatus puglProcessEvents(PuglView* view) { @@ -235,11 +274,13 @@ puglProcessEvents(PuglView* 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; @@ -255,6 +296,7 @@ puglProcessEvents(PuglView* view) } // nobreak case ButtonRelease: + setModifiers(view, event.xbutton.state); if (view->mouseFunc && (event.xbutton.button < 4 || event.xbutton.button > 7)) { view->mouseFunc(view, @@ -263,13 +305,20 @@ puglProcessEvents(PuglView* view) } break; case KeyPress: + setModifiers(view, event.xkey.state); if (view->keyboardFunc) { KeySym sym = XKeycodeToKeysym( view->impl->display, event.xkey.keycode, 0); - view->keyboardFunc(view, event.type == KeyPress, sym); + PuglKey special = keySymToSpecial(sym); + if (!special) { + view->keyboardFunc(view, true, sym); + } else if (view->specialFunc) { + view->specialFunc(view, true, special); + } } break; case KeyRelease: { + setModifiers(view, event.xkey.state); bool retriggered = false; if (XEventsQueued(view->impl->display, QueuedAfterReading)) { XEvent next; @@ -286,7 +335,12 @@ puglProcessEvents(PuglView* view) if (!retriggered && view->keyboardFunc) { KeySym sym = XKeycodeToKeysym( view->impl->display, event.xkey.keycode, 0); - view->keyboardFunc(view, false, sym); + PuglKey special = keySymToSpecial(sym); + if (!special) { + view->keyboardFunc(view, false, sym); + } else if (view->specialFunc) { + view->specialFunc(view, false, special); + } } } case ClientMessage: diff --git a/pugl_test.c b/pugl_test.c index 4abbcda..cf8da2e 100644 --- a/pugl_test.c +++ b/pugl_test.c @@ -74,15 +74,34 @@ onDisplay(PuglView* view) glEnd(); } +static void +printModifiers(PuglView* view) +{ + int mods = puglGetModifiers(view); + fprintf(stderr, "Modifiers:%s%s%s%s\n", + (mods & PUGL_MOD_SHIFT) ? " Shift" : "", + (mods & PUGL_MOD_CTRL) ? " Ctrl" : "", + (mods & PUGL_MOD_ALT) ? " Alt" : "", + (mods & PUGL_MOD_SUPER) ? " Super" : ""); +} + static void onKeyboard(PuglView* view, bool press, uint32_t key) { - fprintf(stderr, "Key %c %s\n", (char)key, press ? "down" : "up"); + fprintf(stderr, "Key %c %s ", (char)key, press ? "down" : "up"); + printModifiers(view); if (key == 'q' || key == 'Q' || key == KEY_ESCAPE) { quit = 1; } } +static void +onSpecial(PuglView* view, bool press, PuglKey key) +{ + fprintf(stderr, "Special key %d %s ", key, press ? "down" : "up"); + printModifiers(view); +} + static void onMotion(PuglView* view, int x, int y) { @@ -94,14 +113,16 @@ onMotion(PuglView* view, int x, int y) static void onMouse(PuglView* view, int button, bool press, int x, int y) { - fprintf(stderr, "Mouse %d %s at %d,%d\n", + fprintf(stderr, "Mouse %d %s at %d,%d ", button, press ? "down" : "up", x, y); + printModifiers(view); } static void onScroll(PuglView* view, float dx, float dy) { - fprintf(stderr, "Scroll %f %f\n", dx, dy); + fprintf(stderr, "Scroll %f %f ", dx, dy); + printModifiers(view); dist += dy / 4.0f; puglPostRedisplay(view); } @@ -115,12 +136,13 @@ onClose(PuglView* view) int main(int argc, char** argv) { - bool resizable = argc > 1; - PuglView* view = puglCreate(0, "Pugl Test", 512, 512, resizable); + bool resizable = argc > 1; + PuglView* view = puglCreate(0, "Pugl Test", 512, 512, resizable); puglSetKeyboardFunc(view, onKeyboard); puglSetMotionFunc(view, onMotion); puglSetMouseFunc(view, onMouse); puglSetScrollFunc(view, onScroll); + puglSetSpecialFunc(view, onSpecial); puglSetDisplayFunc(view, onDisplay); puglSetCloseFunc(view, onClose); -- cgit v1.2.1