18 #ifdef JEVOIS_PLATFORM_PRO
26 #include <imgui_impl_opengl3.h>
29 #include <linux/input.h>
31 #include <linux/keyboard.h>
32 #include <sys/types.h>
45 #define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
50 static std::string clipboardText;
52 char const * ImGui_ImplMALI_GetClipboardText(
void *)
53 {
return clipboardText.c_str(); }
55 void ImGui_ImplMALI_SetClipboardText(
void *,
char const * text)
56 { clipboardText = text; }
85 static char const char_or_func[] =
96 int is_char_key(
unsigned int code)
98 if (code >=
sizeof(char_or_func))
throw std::range_error(
"is_char_key: invalid code " +
std::to_string(code));
99 return char_or_func[code] ==
'c';
124 int to_char_keys_index(
unsigned int keycode)
127 if (keycode >= KEY_1 && keycode <= KEY_EQUAL)
return keycode - KEY_1;
129 if (keycode >= KEY_Q && keycode <= KEY_RIGHTBRACE)
return keycode - KEY_Q + 12;
131 if (keycode >= KEY_A && keycode <= KEY_GRAVE)
return keycode - KEY_A + 24;
133 if (keycode >= KEY_BACKSLASH && keycode <= KEY_SLASH)
return keycode - KEY_BACKSLASH + 36;
135 if (keycode == KEY_102ND)
return 47;
140 int to_func_keys_index(
unsigned int keycode)
143 if (keycode == KEY_ESC)
return 0;
145 if (keycode >= KEY_BACKSPACE && keycode <= KEY_TAB)
return keycode - 13;
147 if (keycode >= KEY_ENTER && keycode <= KEY_LEFTCTRL)
return keycode - 25;
149 if (keycode == KEY_LEFTSHIFT)
return keycode - 37;
151 if (keycode >= KEY_RIGHTSHIFT && keycode <= KEY_KPDOT)
return keycode - 48;
153 if (keycode >= KEY_F11 && keycode <= KEY_F12)
return keycode - 51;
155 if (keycode >= KEY_KPENTER && keycode <= KEY_DELETE)
return keycode - 58;
157 if (keycode == KEY_PAUSE)
return keycode - 65;
159 if (keycode >= KEY_LEFTMETA && keycode <= KEY_COMPOSE)
return keycode - 70;
165 void load_system_keymap(std::array<wchar_t, 49> & char_keys, std::array<wchar_t, 49> & shift_keys,
166 std::array<wchar_t, 49> & altgr_keys)
169 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");
170 if (!dumpkeys) {
LERROR(
"Cannot run dumpkeys -- NOT UPDATING KEYMAP");
return; }
182 LINFO(
"Loading keymap...");
183 char buffer[256];
int n = 0;
184 while (fgets(buffer,
sizeof(buffer), dumpkeys))
187 size_t const ntok = tok.size();
189 if (ntok < 4)
continue;
190 if (tok[ntok - 4] !=
"keycode")
continue;
191 unsigned int const keycode = std::stoi(tok[ntok - 3]);
192 if (!is_char_key(keycode))
continue;
193 if (keycode >=
sizeof(char_or_func))
continue;
194 bool const shift = (tok[1] ==
"shift");
195 bool const altgr = (tok[1] ==
"altgr" || tok[2] ==
"altgr");
196 std::string
const & val = tok[ntok - 1];
197 if (val.empty()) {
LERROR(
"Skipping invalid empty keycode value");
continue; }
199 int index = to_char_keys_index(keycode);
200 wchar_t wch = (wchar_t)jevois::from_string<unsigned int>(val);
201 if (val[0] ==
'+' && (wch & 0xB00)) wch ^= 0xB00;
203 if (tok[0] ==
"keycode") { char_keys[index] = wch; ++n; }
208 if (wch ==
L'\0') wch = towupper(char_keys[index]);
209 shift_keys[index] = wch;
212 else if (altgr) { altgr_keys[index] = wch; ++n; }
216 LINFO(
"Loaded " << n <<
" keymap entries.");
224 wchar_t *wbuffer,
size_t wbuffer_len, std::array<wchar_t, 49>
const & char_keys,
225 std::array<wchar_t, 49>
const & shift_keys, std::array<wchar_t, 49>
const & altgr_keys,
226 wchar_t const func_keys[58][8])
231 if (event->type != EV_KEY)
235 else if (event->code >=
sizeof(char_or_func))
237 len += swprintf(&wbuffer[len], wbuffer_len,
L"<E-%x>", event->code);
241 if (event->code == KEY_LEFTSHIFT || event->code == KEY_RIGHTSHIFT) state->
shift = 1;
242 else if (event->code == KEY_RIGHTALT) state->
altgr = 1;
243 else if (event->code == KEY_LEFTALT) state->
alt = 1;
244 else if (event->code == KEY_LEFTCTRL || event->code == KEY_RIGHTCTRL) state->
ctrl = 1;
245 else if (event->code == KEY_LEFTMETA || event->code == KEY_RIGHTMETA) state->
meta = 1;
249 if (state->
ctrl)
return 0;
252 if (is_char_key(event->code))
256 wch = altgr_keys[to_char_keys_index(event->code)];
259 if (state->
shift) wch = shift_keys[to_char_keys_index(event->code)];
260 else wch = char_keys[to_char_keys_index(event->code)];
263 else if (state->
shift)
265 wch = shift_keys[to_char_keys_index(event->code)];
266 if (wch ==
L'\0') wch = char_keys[to_char_keys_index(event->code)];
268 else wch = char_keys[to_char_keys_index(event->code)];
270 if (wch !=
L'\0') len += swprintf(&wbuffer[len], wbuffer_len,
L"%lc", wch);
273 else if (event->code == 57)
274 len += swprintf(&wbuffer[len], wbuffer_len,
L"%ls", func_keys[to_func_keys_index(event->code)]);
294 if (event->code == KEY_LEFTSHIFT || event->code == KEY_RIGHTSHIFT) state->
shift = 0;
295 else if (event->code == KEY_RIGHTALT) state->
altgr = 0;
296 else if (event->code == KEY_LEFTALT) state->
alt = 0;
297 else if (event->code == KEY_LEFTCTRL || event->code == KEY_RIGHTCTRL) state->
ctrl = 0;
298 else if (event->code == KEY_LEFTMETA || event->code == KEY_RIGHTMETA) state->
meta = 0;
306 char *buffer,
size_t buffer_len, std::array<wchar_t, 49>
const & char_keys,
307 std::array<wchar_t, 49>
const & shift_keys, std::array<wchar_t, 49>
const & altgr_keys,
308 wchar_t const func_keys[58][8])
311 size_t wbuffer_len, len;
313 wbuffer = (
wchar_t*)buffer;
314 wbuffer_len = buffer_len /
sizeof(wchar_t);
316 len = translate_eventw(event, state, wbuffer, wbuffer_len, char_keys, shift_keys, altgr_keys, func_keys);
318 if (!len) *buffer = 0;
319 else wcstombs(buffer, wbuffer, buffer_len);
370 itsMouseX(0), itsMouseY(0), itsConsoleFd(-1), itsTTY(-1), itsKBmode(0)
383 ImGui_ImplOpenGL3_Shutdown();
384 ImGui::DestroyContext();
388 if (itsConsoleFd >= 0) { ioctl(itsConsoleFd, KDSETMODE, KD_TEXT); close(itsConsoleFd); }
408 ioctl(itsConsoleFd, KDSETMODE, KD_GRAPHICS);
416 itsTTY = STDIN_FILENO;
430 itsWidth = w; itsHeight =
h;
431 itsMouseX = w / 2; itsMouseY =
h / 2;
434 IMGUI_CHECKVERSION();
435 ImGui::CreateContext();
436 ImGuiIO & io = ImGui::GetIO();
444 io.BackendPlatformName =
"imgui_impl_sdl";
447 io.KeyMap[ImGuiKey_Tab] = KEY_TAB;
448 io.KeyMap[ImGuiKey_LeftArrow] = KEY_LEFT;
449 io.KeyMap[ImGuiKey_RightArrow] = KEY_RIGHT;
450 io.KeyMap[ImGuiKey_UpArrow] = KEY_UP;
451 io.KeyMap[ImGuiKey_DownArrow] = KEY_DOWN;
452 io.KeyMap[ImGuiKey_PageUp] = KEY_PAGEUP;
453 io.KeyMap[ImGuiKey_PageDown] = KEY_PAGEDOWN;
454 io.KeyMap[ImGuiKey_Home] = KEY_HOME;
455 io.KeyMap[ImGuiKey_End] = KEY_END;
456 io.KeyMap[ImGuiKey_Insert] = KEY_INSERT;
457 io.KeyMap[ImGuiKey_Delete] = KEY_DELETE;
458 io.KeyMap[ImGuiKey_Backspace] = KEY_BACKSPACE;
459 io.KeyMap[ImGuiKey_Space] = KEY_SPACE;
460 io.KeyMap[ImGuiKey_Enter] = KEY_ENTER;
461 io.KeyMap[ImGuiKey_Escape] = KEY_ESC;
462 io.KeyMap[ImGuiKey_KeyPadEnter] = KEY_KPENTER;
463 io.KeyMap[ImGuiKey_A] = KEY_A;
464 io.KeyMap[ImGuiKey_C] = KEY_C;
465 io.KeyMap[ImGuiKey_V] = KEY_V;
466 io.KeyMap[ImGuiKey_X] = KEY_X;
467 io.KeyMap[ImGuiKey_Y] = KEY_Y;
468 io.KeyMap[ImGuiKey_Z] = KEY_Z;
470 io.SetClipboardTextFn = ImGui_ImplMALI_SetClipboardText;
471 io.GetClipboardTextFn = ImGui_ImplMALI_GetClipboardText;
472 io.ClipboardUserData = NULL;
475 io.MouseDrawCursor =
false;
478 ImGui::StyleColorsDark();
481 io.FontGlobalScale = scale;
482 ImGui::GetStyle().ScaleAllSizes(scale);
485 ImGui_ImplOpenGL3_Init(
"#version 300 es");
505 itsInitialized =
true;
511 ImGuiIO & io = ImGui::GetIO();
512 bool gotsome =
false;
515 static int count = 0;
516 if (++count == 100) { scanDevices(); count = 0; }
520 bool mouse_pressed[5] = {
false,
false,
false,
false,
false };
521 bool mouse_released[5] = {
false,
false,
false,
false,
false };
526 static struct timeval tv;
528 FD_ZERO(&rfds); FD_ZERO(&efds);
529 tv.tv_sec = 0; tv.tv_usec = 5;
532 for (
size_t i = 0; i <
NELEMS(itsFd); ++i)
535 FD_SET(itsFd[i], &rfds);
536 FD_SET(itsFd[i], &efds);
537 maxfd = std::max(maxfd, itsFd[i]);
539 if (maxfd <= 0)
return gotsome;
541 int ret = select(maxfd + 1, &rfds,
nullptr, &efds, &tv);
545 if (errno == EINTR)
return gotsome;
549 for (
size_t i = 0; i <
NELEMS(itsFd); ++i)
552 if (itsFd[i] == -1)
continue;
555 if (FD_ISSET(itsFd[i], &efds)) { removeDevice(i);
continue; }
558 if (FD_ISSET(itsFd[i], &rfds))
560 static struct input_event events[32];
561 ssize_t len = read(itsFd[i], events,
sizeof(events));
566 if (errno != EAGAIN && errno != EWOULDBLOCK) removeDevice(i);
571 len /=
sizeof(events[0]);
574 for (ssize_t j = 0; j < len; ++j)
576 unsigned int const code = events[j].code;
577 int const val = events[j].value;
579 switch (events[j].type)
585 if (code >= BTN_MOUSE && code < BTN_MOUSE +
NELEMS(itsMouseButton))
587 if (val) mouse_pressed[code - BTN_MOUSE] =
true;
588 else mouse_released[code - BTN_MOUSE] =
true;
606 io.KeysDown[code] = (val != 0);
607 if (translate_event(&events[j], &itsInputState, itsInputBuffer,
sizeof(itsInputBuffer), itsCharKeys,
608 itsShiftKeys, itsAltgrKeys, itsFuncKeys) > 0)
609 io.AddInputCharactersUTF8(itsInputBuffer);
612 io.KeyAlt = (itsInputState.alt != 0);
613 io.KeyShift = (itsInputState.shift != 0);
614 io.KeyCtrl = (itsInputState.ctrl != 0);
615 io.KeySuper = (itsInputState.meta != 0);
624 case ABS_X: itsMouseX = val;
break;
625 case ABS_Y: itsMouseY = val;
break;
636 if (itsMouseX < 0) itsMouseX = 0;
else if (itsMouseX >=
int(itsWidth)) itsMouseX = itsWidth - 1;
641 if (itsMouseY < 0) itsMouseY = 0;
else if (itsMouseY >=
int(itsHeight)) itsMouseY = itsHeight - 1;
645 io.MouseWheel += val;
649 io.MouseWheelH += val;
661 for (
size_t i = 0; i <
NELEMS(itsMouseButton); ++i)
664 if (mouse_pressed[i]) io.MouseDown[i] =
true;
665 else if (mouse_released[i]) io.MouseDown[i] =
false;
668 io.MousePos = ImVec2(
float(itsMouseX),
float(itsMouseY));
677 ImGui_ImplOpenGL3_NewFrame();
681 ImGuiIO & io = ImGui::GetIO();
682 if (io.Fonts->IsBuilt() ==
false)
LERROR(
"Font atlas not built -- IGNORED");
685 io.DisplaySize = ImVec2(
float(itsWidth),
float(itsHeight));
686 if (itsWidth > 0 && itsHeight > 0) io.DisplayFramebufferScale = ImVec2(1.0
F, 1.0
F);
689 auto const now = std::chrono::steady_clock::now();
690 std::chrono::duration<double>
const dur = now - itsLastNewFrameTime;
691 io.DeltaTime = dur.count();
692 itsLastNewFrameTime = now;
702 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
709 if (num >=
NELEMS(itsFd))
LFATAL(
"Invalid device number " << num);
710 if (itsFd[num] != -1) {
LERROR(
"Invalid device number " << num <<
": already open -- IGNORED");
return; }
711 itsFd[num] = fd;
LINFO(
"Registered new input device " << fd <<
": /dev/input/event" << num);
717 if (num >=
NELEMS(itsFd))
LFATAL(
"Invalid device number " << num);
718 if (itsFd[num] == -1) {
LERROR(
"Invalid device number " << num <<
": not open -- IGNORED");
return; }
720 LINFO(
"Un-registered input device " << itsFd[num]);
728 for (
size_t i = 2; i <
NELEMS(itsFd); ++i)
733 std::string
const devname =
"/dev/input/event" +
std::to_string(i);
735 int fd = open(devname.c_str(), O_RDONLY | O_NONBLOCK);
743 #endif // JEVOIS_PLATFORM_PRO