MAKING AN ONSCREEN KEYBOARD FOR OUR TERMINAL:
Fbkeyboard is a framebuffer keyboard that we can port to Kobo's fbink library, following the fbpad-eink example.
$ mkdir fbkeyboard-build
$ cd fbkeyboard-build/
***
First we build fbpad as in the previous post, except we leave some rows empty at the bottom of the screen for the keyboard.
Assuming you have already built KOReader's koxtoolchain, NiLuJe's FBInk library, and Aligrudi/Droske's fbpads as before:
$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare
$ unzip fbpad-eink-master.zip
$ cd fbpad-eink-master/
$ cp -r ../FBInk-v1.25.0/Release FBInk/
$ cp ../FBInk-v1.25.0/fbink.h FBInk/
(First make fbpadkbS, the small font version of fbpad for onscreen keyboard.)
$ nano -l conf.h
Code:
17 typedef int fbval_t;
$ nano -l Makefile
Code:
3 CC := arm-kobo-linux-gnueabihf-gcc
4 all: fbpadkbS
...
11 fbpadkbS: fbpad.o term.o pad.o draw.o font.o isdw.o scrsnap.o FBInk/Release/libfbink.a
...
15 rm -f *.o fbpadkbS
$ nano -l pad.c
Code:
25 rows = fb_rows() * 29 / 51 / fnrows;
$ make
Copy the fbpadkbS binary to the /mnt/onboard/.adds/koreader/scripts/ folder on your Kobo.
(Now make fbpadkb, the large font version of fbpad for onscreen keyboard.)
$ cp ../fbpads-master/fbpad_mkfn/ar.tf fonts/
$ cp ../fbpads-master/fbpad_mkfn/ai.tf fonts/
$ cp ../fbpads-master/fbpad_mkfn/ab.tf fonts/
$ nano -l conf.h
Code:
20 #define FR "ab.tf"
21 #define FI "ab.tf"
22 #define FB "ab.tf"
$ nano -l Makefile
Code:
4 all: fbpadkb
10 xxd -i fonts/ab.tf > font.h
11 fbpadkb: fbpad.o term.o pad.o draw.o font.o isdw.o scrsnap.o FBInk/Release/libfbink.a
...
15 rm -f *.o fbpadkb
$ nano -l font.c
Code:
40 memcpy(&head, fonts_ab_tf, sizeof(head));
...
46 font->glyphs = (int*)(fonts_ab_tf + sizeof(head));
47 font->data =(char*) (fonts_ab_tf + sizeof(head) + font->n * sizeof(int));
$ xxd -i fonts/ab.tf > font.h
$ nano -l pad.c
Code:
25 rows = fb_rows() * 25 / 42 / fnrows;
$ make
Copy the fbpadkb binary to the /mnt/onboard/.adds/koreader/scripts/ folder on your Kobo.
$ cd ..
Add the following entries to /mnt/onboard/.adds/nm/config.txt:
Code:
...
menu_item :main :fbpadkb :cmd_spawn :quiet:/mnt/onboard/.adds/koreader/scripts/fbpadkb /bin/sh 0</dev/tty1
chain_success :dbg_toast :Started fbpadkb
chain_failure :dbg_toast :Error
menu_item :main :Stop fbpadkb :cmd_spawn :quiet:/usr/bin/pkill fbpadkb
chain_success :dbg_toast :Stopped fbpadkb
chain_failure :dbg_toast :Error
...
***
Freetype is a dependency of Fbkeyboard:
Freetype
https://freetype.org/download.html
Download from:
https://sourceforge.net/projects/fre...etype2/2.13.1/
$ tar zxvf freetype-2.13.1.tar.gz
$ cd freetype-2.13.1/
$ ./configure --host=arm-kobo-linux-gnueabihf
$ make
$ cd ..
***
bakonyiferenc/fbkeyboard
forked from julianwi/fbkeyboard
https://github.com/bakonyiferenc/fbkeyboard
$ wget
https://github.com/bakonyiferenc/fbk...ads/master.zip
$ mv master.zip fbkeyboard-master.zip
$ unzip fbkeyboard-master.zip
$ cd fbkeyboard-master/
$ nano -l fbkeyboard.c
Code:
...
18 */
19
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <linux/fb.h>
28 #include <linux/input.h>
29 #include <linux/uinput.h>
30 #include <linux/vt.h>
31 #include <ft2build.h>
32 #include FT_FREETYPE_H
33 #include "conf.h"
34 #include "draw.h"
35 volatile sig_atomic_t done = 0;
36 char *font = "/mnt/onboard/.adds/koreader/fonts/noto/NotoSans-Bold.ttf";
...
38 char *special[][7] = {
39 { "Esc", "Tab", "Up ", "Dn ", "Lt ", "Rt ", "PgD" },
...
53 __u16 keys[][26] = {
54 { KEY_ESC, KEY_TAB, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_PAGEDOWN },
......
88 FT_Face face;
89 int advance; // offset to the next glyph
90 int fduinput;
91 struct input_event ie;
92 int oldrow = 0, oldpressed = 0;
93 struct timeval oldstamp, newstamp, diffstamp;
94 int theight; // of touchscreen
95 int twidth; // of touchscreen
96 int trowh; // heigth of one keyboard row on touchscreen
97
98 void fill_rect(int x, int y, int w, int h, int color)
...
299 void show_fbkeyboard(int fbfd)
300 {
301 switch (rotate) {
302 case FB_ROTATE_UR:
303 lseek(fbfd, fblinelength * (fbheight - height * 6), SEEK_SET);
304 write(fbfd, buf, buflen);
305 keyb_refresh(fbfd, fbheight - height * 6, 0, width, fbheight);
306 break;
307 case FB_ROTATE_UD:
308 lseek(fbfd, 0, SEEK_SET);
309 write(fbfd, buf, buflen);
310 keyb_refresh(fbfd, 0, 0, width, height * 5);
311 break;
312 case FB_ROTATE_CW:
313 for (int i = 0; i < width; i++) {
314 lseek(fbfd, fblinelength * i, SEEK_SET);
315 write(fbfd, (int32_t *) (buf + linelength * i), linelength);
316 }
317 keyb_refresh(fbfd, 0, 0, height * 5, width);
318 break;
319 case FB_ROTATE_CCW:
320 for (int i = 0; i < width; i++) {
321 lseek(fbfd, fblinelength * i + (fbwidth - height * 5) * 4, SEEK_SET);
322 write(fbfd, (int32_t *) (buf + linelength * i), linelength);
323 }
324 keyb_refresh(fbfd, 0, fbwidth - height * 5, fbwidth, width);
325 break;
326 }
327 }
328 /* Waits for a relevant input event. Returns 0 if touched, 1 if released. */
329 int check_input_events(int fdinput, int *x, int *y)
330 {
331 int released = 0;
332 int key = 1;
333 int absolute_x = -1, absolute_y = -1;
334 while (!done && !released && (absolute_x == -1 || absolute_y == -1))
335 while (read(fdinput, &ie, sizeof(struct input_event))
336 && !(ie.type == EV_SYN && ie.code == SYN_REPORT)) {
337 if (ie.type == EV_ABS) {
338 switch (ie.code) {
339 case ABS_MT_POSITION_X:
340 absolute_x = ie.value;
341 released = 0;
342 key = 0;
343 break;
344 case ABS_MT_POSITION_Y:
345 absolute_y = ie.value;
346 released = 0;
347 key = 0;
348 break;
349 case ABS_MT_TRACKING_ID:
350 if (ie.value == -1) {
351 released = 1;
352 }
353 break;
354 }
355 }
...
356 if (ie.type == EV_SYN && ie.code == SYN_MT_REPORT) {
...
357 released = 1;
358 }
359 }
360 switch (rotate) {
361 case FB_ROTATE_UR:
362 *x = 0x10000 - absolute_y * 0x10000 / theight;
363 *y = absolute_x * 0x10000 / twidth;
364 break;
365 case FB_ROTATE_UD:
366 *x = 0x10000 - absolute_x * 0x10000 / twidth;
367 *y = 0x10000 - absolute_y * 0x10000 / theight;
368 break;
369 case FB_ROTATE_CW:
370 *x = absolute_y * 0x10000 / theight;
371 *y = 0x10000 - absolute_x * 0x10000 / twidth;
372 break;
373 case FB_ROTATE_CCW:
374 *x = 0x10000 - absolute_y * 0x10000 / theight;
375 *y = absolute_x * 0x10000 / twidth;
376 break;
377 }
378 oldstamp.tv_sec = newstamp.tv_sec;
379 oldstamp.tv_usec = newstamp.tv_usec;
380 newstamp.tv_sec = ie.time.tv_sec;
381 newstamp.tv_usec = ie.time.tv_usec;
382 timersub(&newstamp,&oldstamp,&diffstamp);
383 return released;
384 }
385 /* x, y and trowh are scaled to 2^16 (e.g. min x = 0, max x = 65535) */
386 void identify_touched_key(int x, int y, int *row, int *pressed)
387 {
388 switch ((0x10000 - y) / trowh) {
389 case 5:
390 *row = 0; // Esc, Tab, F10, etc
391 *pressed = x * 7 / 0x10000;
392 break;
393 case 4:
394 *row = 1; // q - p
395 *pressed = x * 10 / 0x10000;
396 break;
397 case 3:
398 *row = 1; // a - l
399 if (x > 0x10000 / 20 && x < 0x10000 * 19 / 20)
400 *pressed = 10 + (x * 10 - 0x10000 / 2) / 0x10000;
401 break;
402 case 2:
403 if (x < 0x10000 * 3 / 20) {
404 *row = 3;
405 *pressed = 0; // Left Shift
406 } else if (x < 0x10000 * 17 / 20) {
407 *row = 1; // z - m
408 *pressed = 19 + (x * 10 - 0x10000 * 3 / 2) / 0x10000;
409 } else {
410 *row = 3;
411 *pressed = 1; // Bcksp
412 }
413 break;
414 case 1:
415 *row = 4;
416 if (x < 0x10000 * 3 / 20)
417 *pressed = 99; // 123!@
418 else if (x < 0x10000 * 5 / 20)
419 *pressed = 0; // Left Alt
420 else if (x < 0x10000 * 15 / 20)
421 *pressed = 1; // Space
422 else if (x < 0x10000 * 17 / 20)
423 *pressed = 2; // Right Ctrl
424 else
425 *pressed = 3; // Enter
426 break;
427 default:
428 *row = 5; // cursor, Enter, Home, PgDn, etc
429 *pressed = 3 * y / (0x10000 - trowh * 6);
430 *pressed *= 3;
431 *pressed += 3 * x / 0x10000;
432 break;
433 }
434 }
435
...
489 } else {
490 send_key(keys[row][pressed]);
491 }
492 oldrow = row;
493 oldpressed = pressed;
494 }
495 /* return max of rows */
496 int reset_window_size(int fd)
...
559
560 /* fdcons = open("/dev/tty1", O_RDWR | O_NOCTTY);
561 if (fdcons < 0) {
562 perror("Error opening /dev/tty1");
563 exit(-1);
564 } */
565
...
599
600 if (fb_init(FBDEV)) {
601 fprintf(stderr, "fbkeyboard: failed to initialize the framebuffer\n");
602 return 1;
603 }
604 if (sizeof(fbval_t) != FBM_BPP(fb_mode())) {
605 fprintf(stderr, "fbkeyboard: fbval_t does not match framebuffer depth (%d bytes$
606 return 1;
607 }
608
609 timerclear(&oldstamp);
610 timerclear(&newstamp);
611 timerclear(&diffstamp);
612 fbfd = fb_fd();
613 fbwidth = fb_cols();
614 fbheight = fb_rows();
615 fblinelength = fb_length();
616 switch (rotate) {
617 case FB_ROTATE_UR:
...
724
725 while (!done) {
726 /* if (!ioctl(fdcons, VT_GETSTATE, &ttyinfo)) {
727 if (tty != ttyinfo.v_active) {
728 tty = ttyinfo.v_active;
729 close(fdcons);
730 fdcons = open("/dev/tty1", O_RDWR | O_NOCTTY);
731 set_window_size(fdcons);
732 resized[tty] = 1;
733 }
734 } else {
735 perror("VT_GETSTATE ioctl failed");
736 } */
737
738 draw_keyboard(row, pressed);
739 show_fbkeyboard(fbfd);
740 released = check_input_events(fdinput, &x, &y);
741
742 if (released)
743 identify_touched_key(x, y, &row, &pressed);
744 if (pressed != -1 && (pressed != oldpressed || (long)diffstamp.tv_usec > 50000))
745 send_uinput_event(row, pressed);
746 pressed = -1;
747 }
748
...
760 reset_window_size(fdcons);
761 }
762 }
763 fb_free();
764 }
765
...
$ mkdir FBInk
$ cp -r ../FBInk-v1.25.0/Release FBInk/
$ cp ../FBInk-v1.25.0/fbink.h FBInk/
$ cp ../fbpad-eink-master/draw.c .
$ cp ../fbpad-eink-master/draw.h .
$ cp ../fbpad-eink-master/conf.h .
$ cp ../freetype-2.13.1/objs/.libs/libfreetype.so* .
$ nano -l draw.c
Code:
...
160
161 int fb_length(void)
162 {
163 return finfo.line_length;
164 }
165
166 void keyb_refresh(int fd, int invalid_top, int invalid_left, int invalid_right, int invalid_bot$
167 fbink_refresh( fb_fd(),
168 invalid_top,
169 invalid_left,
170 invalid_right - invalid_left,
171 invalid_bottom - invalid_top,
172 cfg() );
173 /* invalid_nonempty = 0; */
174 invalid_top = invalid_bottom = invalid_left = invalid_right = 0;
175 }
176
$ nano -l draw.h
Code:
19 int fb_length(void);
20 void keyb_refresh(int fd, int invalid_top, int invalid_left, int invalid_right, int invalid_bottom);
$ cp ../freetype-2.13.1/objs/.libs/libfreetype.a .
$ arm-kobo-linux-gnueabihf-gcc -o fbkeyboard -I../freetype-2.13.1/include/ fbkeyboard.c draw.c libfreetype.a FBInk/Release/libfbink.a
Copy the fbkeyboard binary to the /mnt/onboard/.adds/koreader/scripts/ folder on your Kobo.
$ cd ..
Add the following entries to /mnt/onboard/.adds/nm/config.txt:
Code:
...
menu_item :main :fbkeyboard :cmd_spawn :quiet:/mnt/onboard/.adds/koreader/scripts/fbkeyboard
chain_success :dbg_toast :Started fbkeyboard
chain_failure :dbg_toast :Error
menu_item :main :Stop fbkeyboard :cmd_spawn :quiet:/usr/bin/pkill fbkeyboard
chain_success :dbg_toast :Stopped fbkeyboard
chain_failure :dbg_toast :Error
...
From MyBooks, go to the Activity page on your Kobo (second tab from left at bottom of screen.)
***UPDATE***
If you are not in SideloadedMode=true (in [ApplicationPreferences] in /mnt/onboard/.kobo/Kobo/Kobo eReader.conf) then you go to More (second tab from RIGHT at bottom of screen, then select Activity.)
***
From NickelMenu select Stop Agetty, fbpadkb, and fbkeyboard entries. (i.e. requires that you implemented the USB keyboard hack of the previous post.) Edit: Agetty not needed for fbkeyboard, just for fbpad+USB keyboard.
Unfortunately too slow for practical use right now.
Hopefully something can be tweaked to optimize it.
Can exit with Stop fbkeyboard and Stop fbpadkb entries.
***
EDIT: Added arrow keys to lines 39, 40 and 54 of fbkeyboard.c:
Code:
38 char *special[][7] = {
39 { "Esc", "Tab", " ^ ", " v ", " < ", " > ", ">>⇓" },
40 { "Esc", "Tab", " ^ ", " v ", " < ", " > ", ">>⇓" },
41 };
...
53 __u16 keys[][26] = {
54 { KEY_ESC, KEY_TAB, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_PAGEDOWN },
...
EDIT: Added non-blocking IO to fbkeyboard.c to get faster response:
Code:
...
334 while (!done && !released && (absolute_x == -1 || absolute_y == -1))
335 while ((read(fdinput, &ie, sizeof(struct input_event)) > 0)
336 /* && !(ie.type == EV_SYN && ie.code == SYN_REPORT) */ ) {
337 if (ie.type == EV_ABS) {
338 switch (ie.code) {
339 case ABS_MT_POSITION_X:
340 absolute_x = ie.value;
341 released = 0;
342 key = 0;
343 break;
344 case ABS_MT_POSITION_Y:
345 absolute_y = ie.value;
346 released = 0;
347 key = 0;
348 break;
349 case ABS_MT_TRACKING_ID:
350 if (ie.value == -1) {
351 released = 1;
352 }
353 break;
354 }
355 }
356 if (ie.type == EV_SYN && ie.code == SYN_REPORT) {
357 released = 1;
358 }
359 }
360 switch (rotate) {
'''
659 while ((dptr = readdir(inputdevs))) {
660 if ((fdinput =
661 openat(dirfd(inputdevs), dptr->d_name,
662 O_RDONLY | O_NONBLOCK)) != -1
663 && ioctl(fdinput, EVIOCGBIT(0, sizeof(key)),
664 &key) != -1 && key >> EV_ABS & 1)
665 break;
...
742 if (released)
743 identify_touched_key(x, y, &row, &pressed);
744 if (pressed != -1 && (pressed != oldpressed || (long)diffstamp.tv_usec > 200000))
745 send_uinput_event(row, pressed);
746 pressed = -1;
747 usleep(50000);
748 }
749 int i;
...
Unicode Character 21d3 (PageDown arrow on line 39) was entered while holding Ctrl-Sh-u.
https://en.wikipedia.org/wiki/Arrow_(symbol)
***
This code is probably in need of cleanup.
Feel free to jump in!
***
***UPDATE***
See POST #7 - Need WiFi ON (or USB networking) to avoid freezing.
***
***UPDATE***
CRITICAL STEP (or agetty won't run):
# cp /mnt/onboard/.adds/koreader/libs/ld-musl-armhf.so.1 /lib/
Edit: Agetty not needed for fbkeyboard, just for fbpad+USB keyboard.
***