| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323 |
- #include "anki/input/Input.h"
- #include "anki/core/Logger.h"
- #include "anki/input/InputX11.h"
- #if ANKI_WINDOW_BACKEND_GLXX11
- # include "anki/core/NativeWindowGlxX11.h"
- #elif ANKI_WINDOW_BACKEND_EGLX11
- # include "anki/core/NativeWindowEglX11.h"
- #else
- # error "See file"
- #endif
- #include <X11/XKBlib.h>
- #include <cstring>
- #define DEBUG_EVENTS 0
- #if DEBUG_EVENTS
- # define DBG_LOGI(x_) ANKI_LOGI(x_)
- #else
- # define DBG_LOGI(x_) ((void)0)
- #endif
- // Undef stupid X11 defines
- #undef Bool
- namespace anki {
- //==============================================================================
- struct X11KeyCodeToAnki
- {
- U32 x;
- KeyCode ak;
- };
- static const X11KeyCodeToAnki x2a[] = {
- {XK_Return, KC_RETURN},
- {XK_Escape, KC_ESCAPE},
- {XK_BackSpace, KC_BACKSPACE},
- {XK_Tab, KC_TAB},
- {XK_space, KC_SPACE},
- {XK_exclam, KC_EXCLAIM},
- {XK_quotedbl, KC_QUOTEDBL},
- {XK_numbersign, KC_HASH},
- {XK_percent, KC_PERCENT},
- {XK_dollar, KC_DOLLAR},
- {XK_ampersand, KC_AMPERSAND},
- {XK_apostrophe, KC_QUOTE},
- {XK_parenleft, KC_LEFTPAREN},
- {XK_parenright, KC_RIGHTPAREN},
- {XK_asterisk, KC_ASTERISK},
- {XK_plus, KC_PLUS},
- {XK_comma, KC_COMMA},
- {XK_minus, KC_MINUS},
- {XK_period, KC_PERIOD},
- {XK_slash, KC_SLASH},
- {XK_0, KC_0},
- {XK_1, KC_1},
- {XK_2, KC_2},
- {XK_3, KC_3},
- {XK_4, KC_4},
- {XK_5, KC_5},
- {XK_6, KC_6},
- {XK_7, KC_7},
- {XK_8, KC_8},
- {XK_9, KC_9},
- {XK_colon, KC_COLON},
- {XK_semicolon, KC_SEMICOLON},
- {XK_less, KC_LESS},
- {XK_equal, KC_EQUALS},
- {XK_greater, KC_GREATER},
- {XK_question, KC_QUESTION},
- {XK_at, KC_AT},
- {XK_bracketleft, KC_LEFTBRACKET},
- {XK_backslash, KC_BACKSLASH},
- {XK_bracketright, KC_RIGHTBRACKET},
- /*{XK_caret, KC_CARET},*/
- {XK_underscore, KC_UNDERSCORE},
- {XK_grave, KC_BACKQUOTE},
- {XK_a, KC_A},
- {XK_b, KC_B},
- {XK_c, KC_C},
- {XK_d, KC_D},
- {XK_e, KC_E},
- {XK_f, KC_F},
- {XK_g, KC_G},
- {XK_h, KC_H},
- {XK_i, KC_I},
- {XK_j, KC_J},
- {XK_k, KC_K},
- {XK_l, KC_L},
- {XK_m, KC_M},
- {XK_n, KC_N},
- {XK_o, KC_O},
- {XK_p, KC_P},
- {XK_q, KC_Q},
- {XK_r, KC_R},
- {XK_s, KC_S},
- {XK_t, KC_T},
- {XK_u, KC_U},
- {XK_v, KC_V},
- {XK_w, KC_W},
- {XK_x, KC_X},
- {XK_y, KC_Y},
- {XK_z, KC_Z},
- {XK_Delete, KC_DELETE},
- {XK_F1, KC_F1},
- {XK_F2, KC_F2},
- {XK_F3, KC_F3},
- {XK_F4, KC_F4},
- {XK_F5, KC_F5},
- {XK_F6, KC_F6},
- {XK_F7, KC_F7},
- {XK_F8, KC_F8},
- {XK_F9, KC_F9},
- {XK_F10, KC_F10},
- {XK_F11, KC_F11},
- {XK_F12, KC_F12},
- {XK_Up, KC_UP},
- {XK_Down, KC_DOWN},
- {XK_Left, KC_LEFT},
- {XK_Right, KC_RIGHT}
- };
- #define XKEYCODE2ANKI(k_) impl->nativeKeyToAnki[k_ & 0xFF]
- //==============================================================================
- static Bool eventsPending(Display* display)
- {
- XFlush(display);
- if(XEventsQueued(display, QueuedAlready))
- {
- return true;
- }
- static struct timeval zero_time;
- int x11_fd;
- fd_set fdset;
- x11_fd = ConnectionNumber(display);
- FD_ZERO(&fdset);
- FD_SET(x11_fd, &fdset);
- if(select(x11_fd + 1, &fdset, NULL, NULL, &zero_time) == 1)
- {
- return XPending(display);
- }
- return false;
- }
- //==============================================================================
- Input::~Input()
- {}
- //==============================================================================
- void Input::init(NativeWindow* nativeWindow_)
- {
- ANKI_ASSERT(nativeWindow == nullptr);
- nativeWindow = nativeWindow_;
-
- NativeWindowImpl& nwin = nativeWindow->getNative();
- XSelectInput(nwin.xDisplay, nwin.xWindow,
- ExposureMask | ButtonPressMask | KeyPressMask | KeyReleaseMask
- | PointerMotionMask | FocusChangeMask | EnterWindowMask
- | LeaveWindowMask);
- // Init native
- impl.reset(new InputImpl);
- memset(
- &impl->nativeKeyToAnki[0], sizeof(impl->nativeKeyToAnki), KC_UNKNOWN);
- for(const X11KeyCodeToAnki& a : x2a)
- {
- // Convert X11 keycode to something else
- U32 somethingElse = a.x & 0xFF;
- impl->nativeKeyToAnki[somethingElse] = a.ak;
- }
- reset();
- }
- //==============================================================================
- void Input::handleEvents()
- {
- ANKI_ASSERT(nativeWindow != nullptr);
- // add the times a key is being pressed
- for(auto& k : keys)
- {
- if(k)
- {
- ++k;
- }
- }
- for(auto& k : mouseBtns)
- {
- if(k)
- {
- ++k;
- }
- }
- NativeWindowImpl& win = nativeWindow->getNative();
- Display* disp = win.xDisplay;
- //DBG_LOGI("----------------------");
- while(eventsPending(disp))
- {
- XEvent event;
- ::KeyCode keycode = 0;
- KeySym keysym;
- XNextEvent(disp, &event);
- skipXNextEvent:
- switch(event.type)
- {
- case KeyPress:
- keysym = XLookupKeysym(&event.xkey, 0);
- keycode = event.xkey.keycode;
- keys[XKEYCODE2ANKI(keysym)] = 1;
- DBG_LOGI("Key pressed: 0x" << std::hex << (U32)keysym);
- break;
- case KeyRelease:
- keycode = event.xkey.keycode;
- keysym = XLookupKeysym(&event.xkey, 0);
- if(eventsPending(disp))
- {
- XEvent event1;
- XNextEvent(disp, &event1);
- if(event1.type == KeyPress && event1.xkey.keycode == keycode)
- {
- // Repeat
- //DBG_LOGI("Key autorepeat: 0x" << std::hex << (U32)keysym);
- //++keys[XKEYCODE2ANKI(keysym)];
- }
- else
- {
- DBG_LOGI("Key released: 0x" << std::hex << (U32)keysym);
- keys[XKEYCODE2ANKI(keysym)] = 0;
- event = event1;
- goto skipXNextEvent;
- }
- }
- else
- {
- DBG_LOGI("Key released #2: 0x" << std::hex << (U32)keysym);
- keys[XKEYCODE2ANKI(keysym)] = 0;
- }
- break;
- case MotionNotify:
- mousePosNdc.x() =
- (F32)event.xmotion.x / nativeWindow->getWidth() * 2.0 - 1.0;
- mousePosNdc.y() =
- -((F32)event.xmotion.y / nativeWindow->getHeight() * 2.0 - 1.0);
- DBG_LOGI("MotionNotify: " << event.xmotion.x << " "
- << event.xmotion.y << " (" << mousePosNdc << ")");
- break;
- case EnterNotify:
- DBG_LOGI("EnterNotify: ");
- break;
- case LeaveNotify:
- DBG_LOGI("LeaveNotify: ");
- break;
- default:
- DBG_LOGI("Unknown X event");
- break;
- }
- }
- // Lock mouse
- if(lockCurs)
- {
- moveCursor(Vec2(0.0));
- }
- }
- //==============================================================================
- void Input::moveCursor(const Vec2& pos)
- {
- DBG_LOGI("Moving to: " << pos.x() << " " << pos.y());
- if(pos != mousePosNdc)
- {
- NativeWindowImpl& nwi = nativeWindow->getNative();
- XWarpPointer(nwi.xDisplay, None, nwi.xWindow, 0, 0, 0, 0,
- (F32)nativeWindow->getWidth() * (pos.x() / 2.0 + 0.5),
- (F32)nativeWindow->getHeight() * (-pos.y() / 2.0 + 0.5));
- XSync(nwi.xDisplay, False);
- }
- }
- //==============================================================================
- void Input::hideCursor(Bool hide)
- {
- Display* dis = nativeWindow->getNative().xDisplay;
- Window win = nativeWindow->getNative().xWindow;
- if(impl->emptyCursor == None)
- {
- char data[1] = {0};
- XColor color;
- Pixmap pixmap;
- color.red = color.green = color.blue = 0;
- pixmap = XCreateBitmapFromData(dis, DefaultRootWindow(dis), data, 1, 1);
- if(pixmap)
- {
- impl->emptyCursor = XCreatePixmapCursor(dis, pixmap, pixmap,
- &color, &color, 0, 0);
- XFreePixmap(dis, pixmap);
- }
- }
- XDefineCursor(dis, win, impl->emptyCursor);
- XFlush(dis);
- }
- } // end namespace anki
|