18#ifdef JEVOIS_PLATFORM_PRO
26#include <imgui_impl_opengl3.h>
29#include <linux/input.h>
31#include <linux/keyboard.h>
45#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
50 static std::string clipboardText;
52 char const * ImGui_ImplMALI_GetClipboardText(ImGuiContext *)
53 {
return clipboardText.c_str(); }
55 void ImGui_ImplMALI_SetClipboardText(ImGuiContext *,
char const * text)
56 { clipboardText = text; }
58 void ImGui_ImplMALI_PlatformSetImeData(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData* data)
60 if (data->WantVisible)
104 static char const char_or_func[] =
115 int is_char_key(
unsigned int code)
117 if (code >=
sizeof(char_or_func))
throw std::range_error(
"is_char_key: invalid code " + std::to_string(code));
118 return char_or_func[code] ==
'c';
143 int to_char_keys_index(
unsigned int keycode)
146 if (keycode >= KEY_1 && keycode <= KEY_EQUAL)
return keycode - KEY_1;
148 if (keycode >= KEY_Q && keycode <= KEY_RIGHTBRACE)
return keycode - KEY_Q + 12;
150 if (keycode >= KEY_A && keycode <= KEY_GRAVE)
return keycode - KEY_A + 24;
152 if (keycode >= KEY_BACKSLASH && keycode <= KEY_SLASH)
return keycode - KEY_BACKSLASH + 36;
154 if (keycode == KEY_102ND)
return 47;
159 int to_func_keys_index(
unsigned int keycode)
162 if (keycode == KEY_ESC)
return 0;
164 if (keycode >= KEY_BACKSPACE && keycode <= KEY_TAB)
return keycode - 13;
166 if (keycode >= KEY_ENTER && keycode <= KEY_LEFTCTRL)
return keycode - 25;
168 if (keycode == KEY_LEFTSHIFT)
return keycode - 37;
170 if (keycode >= KEY_RIGHTSHIFT && keycode <= KEY_KPDOT)
return keycode - 48;
172 if (keycode >= KEY_F11 && keycode <= KEY_F12)
return keycode - 51;
174 if (keycode >= KEY_KPENTER && keycode <= KEY_DELETE)
return keycode - 58;
176 if (keycode == KEY_PAUSE)
return keycode - 65;
178 if (keycode >= KEY_LEFTMETA && keycode <= KEY_COMPOSE)
return keycode - 70;
184 void load_system_keymap(std::array<wchar_t, 49> & char_keys, std::array<wchar_t, 49> & shift_keys,
185 std::array<wchar_t, 49> & altgr_keys)
188 FILE * dumpkeys = popen(
"/usr/bin/dumpkeys -n | /bin/grep '^\\([[:space:]]shift[[:space:]]\\)*\\([[:space:]]altgr[[:space:]]\\)*keycode' | /bin/sed 's/U+/0x/g' 2>&1",
"r");
189 if (!dumpkeys) {
LERROR(
"Cannot run dumpkeys -- NOT UPDATING KEYMAP");
return; }
201 LINFO(
"Loading keymap...");
202 char buffer[256];
int n = 0;
203 while (fgets(buffer,
sizeof(buffer), dumpkeys))
206 size_t const ntok = tok.size();
208 if (ntok < 4)
continue;
209 if (tok[ntok - 4] !=
"keycode")
continue;
210 unsigned int const keycode = std::stoi(tok[ntok - 3]);
211 if (!is_char_key(keycode))
continue;
212 if (keycode >=
sizeof(char_or_func))
continue;
213 bool const shift = (tok[1] ==
"shift");
214 bool const altgr = (tok[1] ==
"altgr" || tok[2] ==
"altgr");
215 std::string
const & val = tok[ntok - 1];
216 if (val.empty()) {
LERROR(
"Skipping invalid empty keycode value");
continue; }
218 int index = to_char_keys_index(keycode);
219 wchar_t wch = (wchar_t)jevois::from_string<unsigned int>(val);
220 if (val[0] ==
'+' && (wch & 0xB00)) wch ^= 0xB00;
222 if (tok[0] ==
"keycode") { char_keys[index] = wch; ++n; }
227 if (wch ==
L'\0') wch = towupper(char_keys[index]);
228 shift_keys[index] = wch;
231 else if (altgr) { altgr_keys[index] = wch; ++n; }
235 LINFO(
"Loaded " << n <<
" keymap entries.");
243 wchar_t *wbuffer,
size_t wbuffer_len, std::array<wchar_t, 49>
const & char_keys,
244 std::array<wchar_t, 49>
const & shift_keys, std::array<wchar_t, 49>
const & altgr_keys,
245 wchar_t const func_keys[58][8])
250 if (event->type != EV_KEY)
254 else if (event->code >=
sizeof(char_or_func))
256 len += swprintf(&wbuffer[len], wbuffer_len,
L"<E-%x>", event->code);
260 if (event->code == KEY_LEFTSHIFT || event->code == KEY_RIGHTSHIFT) state->
shift = 1;
261 else if (event->code == KEY_RIGHTALT) state->
altgr = 1;
262 else if (event->code == KEY_LEFTALT) state->
alt = 1;
263 else if (event->code == KEY_LEFTCTRL || event->code == KEY_RIGHTCTRL) state->
ctrl = 1;
264 else if (event->code == KEY_LEFTMETA || event->code == KEY_RIGHTMETA) state->
meta = 1;
268 if (state->
ctrl)
return 0;
271 if (is_char_key(event->code))
275 wch = altgr_keys[to_char_keys_index(event->code)];
278 if (state->
shift) wch = shift_keys[to_char_keys_index(event->code)];
279 else wch = char_keys[to_char_keys_index(event->code)];
282 else if (state->
shift)
284 wch = shift_keys[to_char_keys_index(event->code)];
285 if (wch ==
L'\0') wch = char_keys[to_char_keys_index(event->code)];
287 else wch = char_keys[to_char_keys_index(event->code)];
289 if (wch !=
L'\0') len += swprintf(&wbuffer[len], wbuffer_len,
L"%lc", wch);
292 else if (event->code == 57)
293 len += swprintf(&wbuffer[len], wbuffer_len,
L"%ls", func_keys[to_func_keys_index(event->code)]);
313 if (event->code == KEY_LEFTSHIFT || event->code == KEY_RIGHTSHIFT) state->
shift = 0;
314 else if (event->code == KEY_RIGHTALT) state->
altgr = 0;
315 else if (event->code == KEY_LEFTALT) state->
alt = 0;
316 else if (event->code == KEY_LEFTCTRL || event->code == KEY_RIGHTCTRL) state->
ctrl = 0;
317 else if (event->code == KEY_LEFTMETA || event->code == KEY_RIGHTMETA) state->
meta = 0;
325 char *buffer,
size_t buffer_len, std::array<wchar_t, 49>
const & char_keys,
326 std::array<wchar_t, 49>
const & shift_keys, std::array<wchar_t, 49>
const & altgr_keys,
327 wchar_t const func_keys[58][8])
330 size_t wbuffer_len, len;
332 wbuffer = (
wchar_t*)buffer;
333 wbuffer_len = buffer_len /
sizeof(wchar_t);
335 len = translate_eventw(event, state, wbuffer, wbuffer_len, char_keys, shift_keys, altgr_keys, func_keys);
337 if (!len) *buffer = 0;
338 else wcstombs(buffer, wbuffer, buffer_len);
389 itsMouseX(0), itsMouseY(0), itsConsoleFd(-1), itsTTY(-1), itsKBmode(0)
402 ImGui_ImplOpenGL3_Shutdown();
403 ImGui::DestroyContext();
407 if (itsConsoleFd >= 0) { ioctl(itsConsoleFd, KDSETMODE, KD_TEXT); close(itsConsoleFd); }
427 ioctl(itsConsoleFd, KDSETMODE, KD_GRAPHICS);
435 itsTTY = STDIN_FILENO;
449 itsWidth = w; itsHeight =
h;
450 itsMouseX = w / 2; itsMouseY =
h / 2;
453 IMGUI_CHECKVERSION();
455 ImGui::CreateContext();
456 ImGuiIO & io = ImGui::GetIO();
461 io.BackendPlatformName =
"imgui_impl_jevois";
464 io.KeyMap[ImGuiKey_Tab] = KEY_TAB;
465 io.KeyMap[ImGuiKey_LeftArrow] = KEY_LEFT;
466 io.KeyMap[ImGuiKey_RightArrow] = KEY_RIGHT;
467 io.KeyMap[ImGuiKey_UpArrow] = KEY_UP;
468 io.KeyMap[ImGuiKey_DownArrow] = KEY_DOWN;
469 io.KeyMap[ImGuiKey_PageUp] = KEY_PAGEUP;
470 io.KeyMap[ImGuiKey_PageDown] = KEY_PAGEDOWN;
471 io.KeyMap[ImGuiKey_Home] = KEY_HOME;
472 io.KeyMap[ImGuiKey_End] = KEY_END;
473 io.KeyMap[ImGuiKey_Insert] = KEY_INSERT;
474 io.KeyMap[ImGuiKey_Delete] = KEY_DELETE;
475 io.KeyMap[ImGuiKey_Backspace] = KEY_BACKSPACE;
476 io.KeyMap[ImGuiKey_Space] = KEY_SPACE;
477 io.KeyMap[ImGuiKey_Enter] = KEY_ENTER;
478 io.KeyMap[ImGuiKey_Escape] = KEY_ESC;
479 io.KeyMap[ImGuiKey_KeypadEnter] = KEY_KPENTER;
480 io.KeyMap[ImGuiKey_A] = KEY_A;
481 io.KeyMap[ImGuiKey_C] = KEY_C;
482 io.KeyMap[ImGuiKey_V] = KEY_V;
483 io.KeyMap[ImGuiKey_X] = KEY_X;
484 io.KeyMap[ImGuiKey_Y] = KEY_Y;
485 io.KeyMap[ImGuiKey_Z] = KEY_Z;
486 io.KeyMap[ImGuiKey_S] = KEY_S;
488 ImGuiPlatformIO & platform_io = ImGui::GetPlatformIO();
489 platform_io.Platform_SetClipboardTextFn = ImGui_ImplMALI_SetClipboardText;
490 platform_io.Platform_GetClipboardTextFn = ImGui_ImplMALI_GetClipboardText;
491 platform_io.Platform_ClipboardUserData =
nullptr;
492 platform_io.Platform_SetImeDataFn = ImGui_ImplMALI_PlatformSetImeData;
495 static int windowID = 0;
496 ImGuiViewport* main_viewport = ImGui::GetMainViewport();
497 main_viewport->PlatformHandle = (
void*)(intptr_t)windowID;
498 main_viewport->PlatformHandleRaw =
nullptr;
501 io.MouseDrawCursor =
false;
504 ImGui::StyleColorsDark();
505 io.FontGlobalScale = scale;
506 ImGui::GetStyle().ScaleAllSizes(scale);
509 ImGui_ImplOpenGL3_Init(
"#version 300 es");
530 io.ConfigDebugHighlightIdConflicts =
false;
532 itsInitialized =
true;
538 ImGuiIO & io = ImGui::GetIO();
539 bool gotsome =
false;
542 static int count = 0;
543 if (++count == 100) { scanDevices(); count = 0; }
547 bool mouse_pressed[5] = {
false,
false,
false,
false,
false };
548 bool mouse_released[5] = {
false,
false,
false,
false,
false };
553 static struct timeval tv;
555 FD_ZERO(&rfds); FD_ZERO(&efds);
556 tv.tv_sec = 0; tv.tv_usec = 5;
559 for (
size_t i = 0; i <
NELEMS(itsFd); ++i)
562 FD_SET(itsFd[i], &rfds);
563 FD_SET(itsFd[i], &efds);
564 maxfd = std::max(maxfd, itsFd[i]);
566 if (maxfd <= 0)
return gotsome;
568 int ret = select(maxfd + 1, &rfds,
nullptr, &efds, &tv);
572 if (errno == EINTR)
return gotsome;
576 for (
size_t i = 0; i <
NELEMS(itsFd); ++i)
579 if (itsFd[i] == -1)
continue;
582 if (FD_ISSET(itsFd[i], &efds)) { removeDevice(i);
continue; }
585 if (FD_ISSET(itsFd[i], &rfds))
587 static struct input_event events[32];
588 ssize_t len = read(itsFd[i], events,
sizeof(events));
593 if (errno != EAGAIN) removeDevice(i);
598 len /=
sizeof(events[0]);
601 for (ssize_t j = 0; j < len; ++j)
603 unsigned int const code = events[j].code;
604 int const val = events[j].value;
606 switch (events[j].type)
612 if (code >= BTN_MOUSE && code < BTN_MOUSE +
NELEMS(itsMouseButton))
614 if (val) mouse_pressed[code - BTN_MOUSE] =
true;
615 else mouse_released[code - BTN_MOUSE] =
true;
633 io.KeysDown[code] = (val != 0);
634 if (translate_event(&events[j], &itsInputState, itsInputBuffer,
sizeof(itsInputBuffer), itsCharKeys,
635 itsShiftKeys, itsAltgrKeys, itsFuncKeys) > 0)
636 io.AddInputCharactersUTF8(itsInputBuffer);
639 io.KeyAlt = (itsInputState.alt != 0);
640 io.KeyShift = (itsInputState.shift != 0);
641 io.KeyCtrl = (itsInputState.ctrl != 0);
642 io.KeySuper = (itsInputState.meta != 0);
651 case ABS_X: itsMouseX = val;
break;
652 case ABS_Y: itsMouseY = val;
break;
663 if (itsMouseX < 0) itsMouseX = 0;
else if (itsMouseX >=
int(itsWidth)) itsMouseX = itsWidth - 1;
668 if (itsMouseY < 0) itsMouseY = 0;
else if (itsMouseY >=
int(itsHeight)) itsMouseY = itsHeight - 1;
672 io.MouseWheel += val;
676 io.MouseWheelH += val;
688 for (
size_t i = 0; i <
NELEMS(itsMouseButton); ++i)
691 if (mouse_pressed[i]) io.MouseDown[i] =
true;
692 else if (mouse_released[i]) io.MouseDown[i] =
false;
695 io.MousePos = ImVec2(
float(itsMouseX),
float(itsMouseY));
704 ImGui_ImplOpenGL3_NewFrame();
708 ImGuiIO & io = ImGui::GetIO();
709 if (io.Fonts->IsBuilt() ==
false)
LERROR(
"Font atlas not built -- IGNORED");
712 io.DisplaySize = ImVec2(
float(itsWidth),
float(itsHeight));
713 if (itsWidth > 0 && itsHeight > 0) io.DisplayFramebufferScale = ImVec2(1.0F, 1.0F);
716 auto const now = std::chrono::steady_clock::now();
717 std::chrono::duration<double>
const dur = now - itsLastNewFrameTime;
718 io.DeltaTime = dur.count();
719 itsLastNewFrameTime = now;
729 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
736 if (num >=
NELEMS(itsFd))
LFATAL(
"Invalid device number " << num);
737 if (itsFd[num] != -1) {
LERROR(
"Invalid device number " << num <<
": already open -- IGNORED");
return; }
738 itsFd[num] = fd;
LINFO(
"Registered new input device " << fd <<
": /dev/input/event" << num);
744 if (num >=
NELEMS(itsFd))
LFATAL(
"Invalid device number " << num);
745 if (itsFd[num] == -1) {
LERROR(
"Invalid device number " << num <<
": not open -- IGNORED");
return; }
747 LINFO(
"Un-registered input device " << itsFd[num]);
755 for (
size_t i = 2; i <
NELEMS(itsFd); ++i)
760 std::string
const devname =
"/dev/input/event" + std::to_string(i);
762 int fd = open(devname.c_str(), O_RDONLY | O_NONBLOCK);
std::array< wchar_t, 49 > itsShiftKeys
void addDevice(size_t num, int fd)
void removeDevice(size_t num)
std::array< wchar_t, 49 > itsCharKeys
ImGuiBackendMALI()
Constructor.
virtual bool pollEvents(bool &shouldclose) override
Poll events such as mouse movements, buttons, keyboard, joystick, and pass to ImGui.
virtual ~ImGuiBackendMALI()
Virtual destructor for safe inheritance, free resources.
virtual void init(unsigned short w, unsigned short h, bool fullscreen=false, float scale=1.0f, bool conslock=true)
Initialize the underlying engine that will process events, create windows, etc.
virtual void render() override
Render the ImGui graphics.
virtual void newFrame() override
Start a new frame and clear the window/framebuffer.
std::array< wchar_t, 49 > itsAltgrKeys
Backend for VideoDisplay on JeVois-Pro host using MALI.
virtual void init(unsigned short w, unsigned short h, bool fullscreen=false) override
Initialize the underlying engine that will process events, create windows, etc.
virtual void newFrame()
Start a new frame and clear the window/framebuffer.
virtual void render()
Render the VideoDisplay graphics.
void muteKeyboard(int tty, int &kb_mode)
Prevent keystrokes from reaching the tty.
void unMuteKeyboard(int tty, int kb_mode)
Restore the keyboard mode for given tty.
int getActiveTTY()
Get current active tty.
int getConsoleFd()
Get a file descriptor to the console.
bool isInputDevice(int fd)
Indicate whether this fd (which should be from /dev/input/eventX) is keyboard, mouse,...
#define LFATAL(msg)
Convenience macro for users to print out console or syslog messages, FATAL level.
std::string warnAndIgnoreException(std::string const &prefix="")
Convenience function to catch an exception, issue some LERROR (depending on type),...
#define LERROR(msg)
Convenience macro for users to print out console or syslog messages, ERROR level.
#define LINFO(msg)
Convenience macro for users to print out console or syslog messages, INFO level.
std::vector< std::string > split(std::string const &input, std::string const ®ex="\\s+")
Split string into vector of tokens using a regex to specify what to split on; default regex splits by...
Main namespace for all JeVois classes and functions.