// keyboard_linux_input.cpp /* * FRT - A Godot platform targeting single board computers * Copyright (c) 2017-2019 Emanuele Fornara * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef FRT_TEST #define FRT_MOCK_GODOT_INPUT_MODIFIER_STATE #else #include "core/version.h" #define FRT_MOCK_GODOT_INPUT_MODIFIER_STATE #include "core/input/input_event.h" #endif #include "frt.h" #include <stdio.h> #include <string.h> #include "bits/linux_input.h" #include "import/gdkeys.h" namespace frt { static struct KeyMap { int kernel_code; int gd_code; } keymap[] = { { KEY_SPACE, ' ' }, { KEY_A, 'A' }, { KEY_B, 'B' }, { KEY_C, 'C' }, { KEY_D, 'D' }, { KEY_E, 'E' }, { KEY_F, 'F' }, { KEY_G, 'G' }, { KEY_H, 'H' }, { KEY_I, 'I' }, { KEY_J, 'J' }, { KEY_K, 'K' }, { KEY_L, 'L' }, { KEY_M, 'M' }, { KEY_N, 'N' }, { KEY_O, 'O' }, { KEY_P, 'P' }, { KEY_Q, 'Q' }, { KEY_R, 'R' }, { KEY_S, 'S' }, { KEY_T, 'T' }, { KEY_U, 'U' }, { KEY_V, 'V' }, { KEY_W, 'W' }, { KEY_X, 'X' }, { KEY_Y, 'Y' }, { KEY_Z, 'Z' }, { KEY_0, '0' }, { KEY_1, '1' }, { KEY_2, '2' }, { KEY_3, '3' }, { KEY_4, '4' }, { KEY_5, '5' }, { KEY_6, '6' }, { KEY_7, '7' }, { KEY_8, '8' }, { KEY_9, '9' }, { KEY_F1, GD_KEY_F1 }, { KEY_F2, GD_KEY_F2 }, { KEY_F3, GD_KEY_F3 }, { KEY_F4, GD_KEY_F4 }, { KEY_F5, GD_KEY_F5 }, { KEY_F6, GD_KEY_F6 }, { KEY_F7, GD_KEY_F7 }, { KEY_F8, GD_KEY_F8 }, { KEY_F9, GD_KEY_F9 }, { KEY_F10, GD_KEY_F10 }, { KEY_F11, GD_KEY_F11 }, { KEY_F12, GD_KEY_F12 }, { KEY_UP, GD_KEY_UP }, { KEY_DOWN, GD_KEY_DOWN }, { KEY_LEFT, GD_KEY_LEFT }, { KEY_RIGHT, GD_KEY_RIGHT }, { KEY_TAB, GD_KEY_TAB }, { KEY_BACKSPACE, GD_KEY_BACKSPACE }, { KEY_INSERT, GD_KEY_INSERT }, { KEY_DELETE, GD_KEY_DELETE }, { KEY_HOME, GD_KEY_HOME }, { KEY_END, GD_KEY_END }, { KEY_PAGEUP, GD_KEY_PAGEUP }, { KEY_PAGEDOWN, GD_KEY_PAGEDOWN }, { KEY_ENTER, GD_KEY_RETURN }, { KEY_ESC, GD_KEY_ESCAPE }, { KEY_LEFTCTRL, GD_KEY_CONTROL }, { KEY_RIGHTCTRL, GD_KEY_CONTROL }, { KEY_LEFTALT, GD_KEY_ALT }, { KEY_RIGHTALT, GD_KEY_ALT }, { KEY_LEFTSHIFT, GD_KEY_SHIFT }, { KEY_RIGHTSHIFT, GD_KEY_SHIFT }, { KEY_LEFTMETA, GD_KEY_META }, { KEY_RIGHTMETA, GD_KEY_META }, { KEY_KP0, GD_KEY_KP_0 }, { KEY_KP1, GD_KEY_KP_1 }, { KEY_KP2, GD_KEY_KP_2 }, { KEY_KP3, GD_KEY_KP_3 }, { KEY_KP4, GD_KEY_KP_4 }, { KEY_KP5, GD_KEY_KP_5 }, { KEY_KP6, GD_KEY_KP_6 }, { KEY_KP7, GD_KEY_KP_7 }, { KEY_KP8, GD_KEY_KP_8 }, { KEY_KP9, GD_KEY_KP_9 }, { KEY_KPASTERISK, GD_KEY_KP_MULTIPLY }, { KEY_KPMINUS, GD_KEY_KP_SUBTRACT }, { KEY_KPPLUS, GD_KEY_KP_ADD }, { KEY_KPDOT, GD_KEY_KP_PERIOD }, { KEY_KPENTER, GD_KEY_KP_ENTER }, { KEY_KPSLASH, GD_KEY_KP_DIVIDE }, { 0, 0 }, }; class KeyboardLinuxInput : public Keyboard, public EventDispatcher, public LinuxInput { private: static const int left_mask = 0x01; static const int right_mask = 0x02; static const int wait_ms = 100; bool valid; Handler *h; bool grabbed; InputModifierState st; struct { int shift; int alt; int control; int meta; } left_right_mask; void update_modifier(int in_code, int left_code, int right_code, bool pressed, int &mask, bool &state) { if (in_code != left_code && in_code != right_code) return; if (in_code == left_code) { if (pressed) mask |= left_mask; else mask &= ~left_mask; } else if (in_code == right_code) { if (pressed) mask |= right_mask; else mask &= ~right_mask; } state = mask; } public: KeyboardLinuxInput() : valid(false), h(0), grabbed(false) { st.shift = false; st.alt = false; st.control = false; st.meta = false; left_right_mask.shift = 0; left_right_mask.alt = 0; left_right_mask.control = 0; left_right_mask.meta = 0; } // Module const char *get_id() const { return "keyboard_linux_input"; } bool probe() { valid = open("FRT_KEYBOARD_ID", "event-kbd"); if (valid) App::instance()->add_dispatcher(this); return valid; } void cleanup() { close(); if (valid) App::instance()->remove_dispatcher(this); valid = false; } bool handle_meta(int gd_code, bool pressed) { if (pressed) return false; switch (gd_code) { case 'K': if (LinuxInput::grab(!grabbed, wait_ms)) grabbed = !grabbed; return true; default: return false; } } // LinuxInput void handle(const input_event &ev) { if (ev.type != EV_KEY || (ev.value != KV_Pressed && ev.value != KV_Released)) return; bool pressed = (ev.value == KV_Pressed); update_modifier(ev.code, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, pressed, left_right_mask.shift, st.shift); update_modifier(ev.code, KEY_LEFTALT, KEY_RIGHTALT, pressed, left_right_mask.alt, st.alt); update_modifier(ev.code, KEY_LEFTCTRL, KEY_RIGHTCTRL, pressed, left_right_mask.control, st.control); update_modifier(ev.code, KEY_LEFTMETA, KEY_RIGHTMETA, pressed, left_right_mask.meta, st.meta); for (int i = 0; keymap[i].kernel_code; i++) { if (keymap[i].kernel_code == ev.code) { if (h) h->handle_keyboard_key(keymap[i].gd_code, pressed, 0, false); break; } } } // EventDispatcher void dispatch_events() { poll(); } // Keyboard void set_handler(Handler *handler) { h = handler; grabbed = LinuxInput::grab(true, wait_ms); } void get_modifier_state(InputModifierState &state) const { state = st; } }; FRT_REGISTER(KeyboardLinuxInput) } // namespace frt