View Single Post
Old 11-16-2023, 07:31 PM   #10
elinkser
Groupie
elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.elinkser has survived committing the World's Second Greatest Blunder.
 
Posts: 185
Karma: 146236
Join Date: Oct 2022
Device: Kobo Clara HD
OSK, A FASTER & MORE USER-CONFIGURABLE ONSCREEN KEYBOARD

OSK, A FASTER & MORE USER-CONFIGURABLE ONSCREEN KEYBOARD:

(Found this by accident when looking for something else. It's from 2018, but still works great on my Clara HD.)

USBMS Shenanigans...
https://www.mobileread.com/forums/sh...0&postcount=14

https://github.com/shermp/go-kobo-input
shermp/go-kobo-input


$ mkdir osk-build

$ cd osk-build/

$ wget https://golang.org/dl/go1.20.2.linux-amd64.tar.gz

$ sudo tar -C /usr/local -xzf go1.20.2.linux-amd64.tar.gz

$ echo "export PATH=/usr/local/go/bin:${PATH}" | sudo tee -a $HOME/.profile

$ source $HOME/.profile

$ go version
go version go1.20.2 linux/amd64

$ source ~/koxtoolchain/refs/x-compile.sh kobo env bare
Note: This refers to the KOReader toolchain from:
https://www.mobileread.com/forums/sh...16&postcount=4
You could try a different toolchain if you feel lucky.

$ env GO111MODULE=off go get github.com/shermp/go-fbink-v2

$ cd ~/go/src/github.com/shermp/go-fbink-v2/

$ cd gofbink/

$ env GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build


$ cd ../example/

$ env GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build


Copy the /go/src/github.com/shermp/go-fbink-v2/example/example binary to the /mnt/onboard/.adds/koreader/scripts/ folder of your Kobo.

Run these commands from an SSH session to the Kobo:
# . /korenv.sh
# example

(Should display some nice text messages on Kobo display.)


***

Now for the keyboard:
Back on your PC run:

$ env GO111MODULE=off go get github.com/fogleman/gg

$ env GO111MODULE=off go get github.com/shermp/go-osk

//$ env GO111MODULE=off go get github.com/shermp/kobo-sim-usb/simusb

$ env GO111MODULE=off go get github.com/shermp/go-kobo-input

$ cd ~/go/src/github.com/shermp/go-kobo-input/

$ cd koboin-osk-sample/

$ nano -l main.go
Code:
 25 //      "fmt"
...
 32 //      "github.com/shermp/kobo-sim-usb/simusb"
...
 57 //      u, err := simusb.New(fb)
 58 //      if err != nil {
 59 //              fmt.Println(err)
 60 //      }
 61 //      err = u.Start(true, true)
 62 //      if err != nil {
 63 //              fmt.Println(err)
 64 //              return
 65 //      }
 66 //      defer u.End(true)
Note: the USBMS did work at one time, but stopped along the way, and I am skipping it for now because it's a pain to debug since USB networking must not be activated in this mode.

$ env GO111MODULE=off GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build

$ arm-kobo-linux-gnueabihf-strip koboin-osk-sample

$ file koboin-osk-sample
koboin-osk-sample: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 2.6.33, Go


Copy the ~/go/src/github.com/shermp/go-kobo-input/koboin-osk-sample/koboin-osk-sample binary to the /mnt/onboard/.adds/koreader/scripts/ folder of your Kobo.

Copy the keymap-en_us.json and Roboto-Medium.ttf files from the ~/go/src/github.com/shermp/go-kobo-input/koboin-osk-sample/ folder to the /mnt/onboard/.adds/koreader/ folder of your Kobo.

To avoid keyboard taps activating a Nickel function:
From More tab (second tab from right at bottom of screen), select Activity.
If you are in SideloadedMode=true, then Activity tab is second from left at bottom of screen.

Run these commands from an SSH session to the Kobo:
# . /korenv.sh
# koboin-osk-sample

Tap the CAP key for uppercase letters.
Tap the RET key to exit.


***

To customize our keyboard, we need to:

1. FIX KEY REPEAT ERRORS
2. CHANGE LAYOUT
3. SEND INPUT TO FBPAD

***

$ cd ~/go/src/github.com/shermp/go-osk/

$ cd osk/

1. FIX KEY REPEAT ERRORS:

$ nano -l osk.go
Code:
27 //      "strings"
...
253                                         kc.DrawStringAnchored(string(k.KeyCode), kmx, kmy, 0.5, 0.5)
'''
273                                         if time.Since(v.debounceStartTm) < (200 * time.Millisecond) {

2. CHANGE LAYOUT:

$ nano -l osk.go
Code:
 41         KTesc            = 7
 42         KTtab            = 8
 43         KTup             = 9
 44         KTdown           = 10
 45         KTleft           = 11
 46         KTright          = 12
 47         KTpgUp           = 13
 48         KTpgDn           = 14
...
198         case KTalt:
199                 return "ALT"
200         case KTbackspace:
201                 return "BKSP"
202         case KTcapsLock:
203                 return "CAP"
204         case KTcarriageReturn:
205                 return "RET"
206         case KTcontrol:
207                 return "CTL"
208         case KTdelete:
209                 return "DEL"
210         case KTesc:
211                 return "ESC"
212         case KTtab:
213                 return "TAB"
214         case KTup:
215                 return "^"
216         case KTdown:
217                 return "V"
218         case KTleft:
219                 return "<"
220         case KTright:
221                 return ">"
222         case KTpgUp:
223                 return "<<"
224         case KTpgDn:
225                 return ">>"
$ cd ~/go/src/github.com/shermp/go-kobo-input/

$ cd koboin-osk-sample/

$ nano -l keymap-en_us.json

Spoiler:


Code:
 79                                         "char": "-"
...
 83                                         "keyType": 0,
 84                                         "keyWidth": 1,
 85                                         "char": "="
...
 93                                         "isPadding": false,
 94                                         "keyType": 7,
 95                                         "keyWidth": 1,
 96                                         "char": ""
...
159                                         "isPadding": false,
160                                         "keyType": 2,
161                                         "keyWidth": 1,
162                                         "char": ""
163                                 } 
164                         ]
...
233                                         "char": ";"
...
239                                         "char": "'"
...
249                 {
250                         "rowHeight": 1,
251                         "keys": [
252                                 {
253                                         "isPadding": false,
254                                         "keyType": 8,
255                                         "keyWidth": 1,
256                                         "char": ""
...
316                                         "char": "/"
...
319                                         "isPadding": false,
320                                         "keyType": 0,
321                                         "keyWidth": 1,
322                                         "char": "|"
...
327                         "rowHeight": 1,
328                         "keys": [
329                                 {
330                                         "isPadding": false,
331                                         "keyType": 9,
332                                         "keyWidth": 1,
333                                         "char": ""
334                                 },
335                                 {
336                                         "isPadding": false,
337                                         "keyType": 10,
338                                         "keyWidth": 1,
339                                         "char": ""
340                                 },
341                                 {
342                                         "isPadding": false,
343                                         "keyType": 11,
344                                         "keyWidth": 1,
345                                         "char": ""
346                                 },
347                                 {
348                                         "isPadding": false,
349                                         "keyType": 12,
350                                         "keyWidth": 1,
351                                         "char": ""
352                                 },
353                                 {
354                                         "isPadding": false,
355                                         "keyType": 0,
356                                         "keyWidth": 2,
357                                         "char": " "
358                                 },
359                                 {
360                                         "isPadding": false,
361                                         "keyType": 0,
362                                         "keyWidth": 1,
363                                         "char": "["
364                                 },
365                                 {
366                                         "isPadding": false,
367                                         "keyType": 0,
368                                         "keyWidth": 1,
369                                         "char": "]"
370                                 },
371                                 {
372                                         "isPadding": false,
373                                         "keyType": 13,
374                                         "keyWidth": 1,
375                                         "char": ""
376                                 },
377                                 {
378                                         "isPadding": false,
379                                         "keyType": 14,
380                                         "keyWidth": 1,
381                                         "char": ""
382                                 },
383                                 {
384                                         "isPadding": false,
385                                         "keyType": 5,
386                                         "keyWidth": 1,
387                                         "char": ""
388                                 },
389                                 {
390                                         "isPadding": false,
391                                         "keyType": 1,
392                                         "keyWidth": 1,
393                                         "char": ""
394                                 }
395                         ]
396                 }
397         ]


$ cp keymap-en_us.json keymap1-en_us.json

$ cp keymap-en_us.json keymap2-en_us.json

$ nano -l keymap2-en_us.json

Spoiler:


Code:
 19                                         "char": "!"
...
 25                                         "char": "@"
...
 31                                         "char": "#"
...
 37                                         "char": "$"
...
 43                                         "char": "%"
...
 49                                         "char": "^"
...
 55                                         "char": "&"
...
 61                                         "char": "*"
...
 67                                         "char": "("
...
 73                                         "char": ")"
...
 79                                         "char": "_"
...
 85                                         "char": "+"
...
102                                         "char": "Q"
...
108                                         "char": "W"
...
114                                         "char": "E"
...
120                                         "char": "R"
...
126                                         "char": "T"
...
132                                         "char": "Y"
...
138                                         "char": "U"
...
144                                         "char": "I"
...
150                                         "char": "O"
...
156                                         "char": "P"
...
179                                         "char": "A"
...
185                                         "char": "S"
...
191                                         "char": "D"
...
197                                         "char": "F"
...
203                                         "char": "G"
...
209                                         "char": "H"
...
215                                         "char": "J"
...
221                                         "char": "K"
...
227                                         "char": "L"
...
233                                         "char": ":"
...
239                                         "char": "\""
...
262                                         "char": "Z"
...
268                                         "char": "X"
...
274                                         "char": "C"
...
280                                         "char": "V"
...
286                                         "char": "B"
...
292                                         "char": "N"
...
298                                         "char": "M"
...
304                                         "char": "<"
...
310                                         "char": ">"
...
316                                         "char": "?"
...
322                                         "char": "\\"
...
363                                         "char": "{"
...
369                                         "char": "}"



$ nano -l main.go

Spoiler:


Code:
 27 //      "unicode"
...
 67         fb.Println("Welcome to the test!")
 68         fb.Println("Have Fun!")
 69         var k osk.Key
 70         var prevType int
 71
 72         // Load a keymap file for the OSK
 73         keymap1JSON, _ := ioutil.ReadFile("./keymap1-en_us.json")
 74         km1 := osk.KeyMap{}
 75         json.Unmarshal(keymap1JSON, &km1)
 76         // Create an OSK
 77         vk1, _ := osk.New(&km1, 1080, 1440)
 78         // Generate an image of the OSK
 79         vk1PNG := "./osk1-en_us.png"
 80         vk1Font := "./Roboto-Medium.ttf"
 81         vk1.CreateIMG(vk1PNG, vk1Font)
 82
 83         // Load a keymap file for the OSK
 84         keymap2JSON, _ := ioutil.ReadFile("./keymap2-en_us.json")
 85         km2 := osk.KeyMap{}
 86         json.Unmarshal(keymap2JSON, &km2)
 87         // Create an OSK
 88         vk2, _ := osk.New(&km2, 1080, 1440)
 89         // Generate an image of the OSK
 90         vk2PNG := "./osk2-en_us.png"
 91         vk2Font := "./Roboto-Medium.ttf"
 92         vk2.CreateIMG(vk2PNG, vk2Font)
 93
 94         // Print the image to the screen. Its position on screen should match that stored
 95         // in the keyboard object
 96         fb.PrintImage(vk1PNG, int16(vk1.StartCoords.X), int16(vk1.StartCoords.Y), &cfg)
 97         runeStr := []rune{}
 98         upperCase := false
 99 //      cfg.Row = 16
100         // Read the input from the touch screen
101 L:
...
104                 if err != nil {
105                         continue
106                 }
107                 if upperCase {
108                         k, err = vk2.GetPressedKey(x, y)
109                 } else {
110                         k, err = vk1.GetPressedKey(x, y)
111                 }
112                 if err != nil {
...
119                 case osk.KTstandardChar:
120                         var key rune
121                         key = k.KeyCode
122                         runeStr = append(runeStr, key)
...
130                 case osk.KTcapsLock:
131                         if prevType != osk.KTcapsLock { 
132                                 upperCase = !upperCase
133                                 if upperCase {
134                                         fb.PrintImage(vk2PNG, int16(vk2.StartCoords.X), int16(vk2.StartCoords.Y), &cfg)
135                                 } else {
136                                         fb.PrintImage(vk1PNG, int16(vk1.StartCoords.X), int16(vk1.StartCoords.Y), &cfg)
137                                 }
138                         }
...
143                 }
144                 prevType = k.KeyType
145         }
146 }
147


$ env GO111MODULE=off GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build

$ arm-kobo-linux-gnueabihf-strip koboin-osk-sample

Copy the ~/go/src/github.com/shermp/go-kobo-input/koboin-osk-sample/koboin-osk-sample binary to the /mnt/onboard/.adds/koreader/scripts/ folder of your Kobo.

Copy the keymap1-en_us.json and keymap2-en_us.json files from the ~/go/src/github.com/shermp/go-kobo-input/koboin-osk-sample/ folder to the /mnt/onboard/.adds/koreader/ folder of your Kobo.


To avoid keyboard taps activating a Nickel function:
From More tab (second tab from right at bottom of screen), select Activity.
If you are in SideloadedMode=true, then Activity tab is second from left at bottom of screen.

Run these commands from an SSH session to the Kobo:
# . /korenv.sh
# koboin-osk-sample

Tap the CAP key to change layouts.
Tap the RET key to exit.

***


3. SEND INPUT TO FBPAD:

To be able to use our keyboard with fbpad terminal, we will send ANSI codes with IOCTL calls instead of simulating input events with uinput.


$ cd ~/go/src/github.com/shermp/go-kobo-input/

$ cd koboin-osk-sample/

$ nano -l main.go

Spoiler:


Code:
 21 package main
 22
 23 import (
 24         "encoding/json"
 25         "fmt"
 26         "io/ioutil"
 27 //      "unicode"
 28         "os"
 29         "syscall"
 30         "unsafe"
 31         "github.com/shermp/go-fbink-v2/gofbink"
 32         "github.com/shermp/go-kobo-input/koboin"
 33         "github.com/shermp/go-osk/osk"
 34 //      "github.com/shermp/kobo-sim-usb/simusb"
 35 )
 36
 37 var ttyFile *os.File
 38 var eno syscall.Errno
 39 //var key byte
 40 var     upperCase bool
 41 var     ctlState bool
 42 var     altState bool
 43 // sendAnsiSeq sends an ANSI escape string to open tty  
 44 func sendAnsiSeq(ansiSeq string) syscall.Errno {
 45         seqBytes := []byte(ansiSeq)
 46         for i := 0; i < len(seqBytes); i++ { 
 47                 _, _, eno = syscall.Syscall(syscall.SYS_IOCTL,ttyFile.Fd(),syscall.TIOCSTI,uintptr(unsafe.Pointer(&seqBytes[i])),)
 48                 if eno != 0 {
 49                         return eno
 50                 } 
 51         }
 52         return 0
 53 }
 54
 55 func main() {
...
 73         fb.Init(&cfg)
 74         var err error
 75         var tty = "/dev/pts/0"
 76         ttyFile, err = os.Open(tty)
 77         if err != nil {
 78                 fmt.Println(err)
 79                 tty = "/dev/pts/1"
 80                 ttyFile, err = os.Open(tty)
 81                 if err != nil {
 82                         fmt.Println(err)
 83                 }
 84         }
 85         defer ttyFile.Close()
 86
 87         // Use kobo-sim-usb to enter USBMS mode where we can use the
...
126         // Print the image to the screen. Its position on screen should match that stored
127         // in the keyboard object
128         fb.PrintImage(vk1PNG, int16(vk1.StartCoords.X), int16(vk1.StartCoords.Y), &cfg)
129 //      runeStr := []rune{}
130         upperCase = false
131         ctlState = false
132         altState = false
133 //      cfg.Row = 16
134         // Read the input from the touch screen
135 //L:
...
152                 switch k.KeyType {
153                 case osk.KTstandardChar:
154                         key := k.KeyCode
155                         tabSeq := []byte(string(key))
156                         if (ctlState) {
157                                 byteSeq := []byte(tabSeq)
158                                 if      (byteSeq[0] > 64) && (byteSeq[0] < 91) {
159                                         byteSeq[0] -= 64
160                                         seqErr := sendAnsiSeq(string(byteSeq[0])) 
161                                         if seqErr != 0 {
162                                                 fmt.Println(seqErr)
163                                         }
164                                 } else if (byteSeq[0] > 96) && (byteSeq[0] < 123) {
165                                         byteSeq[0] -= 96
166                                         seqErr := sendAnsiSeq(string(byteSeq[0])) 
167                                         if seqErr != 0 {
168                                                 fmt.Println(seqErr)
169                                         }
170                                 }
171                         } else {
172                                 seqErr := sendAnsiSeq(string(tabSeq)) 
173                                 if seqErr != 0 {
174                                         fmt.Println(seqErr)
175                                 }
176                         }
177                 case osk.KTcarriageReturn:
178                         tabSeq := []byte{13}
179                         seqErr := sendAnsiSeq(string(tabSeq)) 
180                         if seqErr != 0 {
181                                 fmt.Println(seqErr)
182                         }
183                 case osk.KTbackspace:
184                         tabSeq := []byte{8}
185                         seqErr := sendAnsiSeq(string(tabSeq)) 
186                         if seqErr != 0 {
187                                 fmt.Println(seqErr)
188                         }
189                 case osk.KTdelete:
190                         tabSeq := []byte{127}
191                         seqErr := sendAnsiSeq(string(tabSeq)) 
192                         if seqErr != 0 {
193                                 fmt.Println(seqErr)
194                         }
195                 case osk.KTcapsLock:
196                         if prevType != osk.KTcapsLock { 
197                                 upperCase = !upperCase
198                                 if upperCase {
199                                         fb.PrintImage(vk2PNG, int16(vk2.StartCoords.X), int16(vk2.StartCoords.Y), &cfg)
200                                 } else {
201                                         fb.PrintImage(vk1PNG, int16(vk1.StartCoords.X), int16(vk1.StartCoords.Y), &cfg)
202                                 }
203                         }
204                 case osk.KTcontrol:
205                         ctlState = !ctlState
206                 case osk.KTalt:
207                         altState = !altState
208                 case osk.KTesc:
209                         tabSeq := []byte{27}
210                         seqErr := sendAnsiSeq(string(tabSeq)) 
211                         if seqErr != 0 {
212                                 fmt.Println(seqErr)
213                         }
214                 case osk.KTtab:
215                         tabSeq := []byte{9}
216                         seqErr := sendAnsiSeq(string(tabSeq)) 
217                         if seqErr != 0 {
218                                 fmt.Println(seqErr)
219                         }
220                 case osk.KTup:
221                         tabSeq := []byte{27,91,65}
222                         seqErr := sendAnsiSeq(string(tabSeq)) 
223                         if seqErr != 0 {
224                                 fmt.Println(seqErr)
225                         }
226                 case osk.KTdown:
227                         tabSeq := []byte{27,91,66}
228                         seqErr := sendAnsiSeq(string(tabSeq)) 
229                         if seqErr != 0 {
230                                 fmt.Println(seqErr)
231                         }
232                 case osk.KTleft:
233                         tabSeq := []byte{27,91,68}
234                         seqErr := sendAnsiSeq(string(tabSeq)) 
235                         if seqErr != 0 {
236                                 fmt.Println(seqErr)
237                         }
238                 case osk.KTright:
239                         tabSeq := []byte{27,91,67}
240                         seqErr := sendAnsiSeq(string(tabSeq)) 
241                         if seqErr != 0 {
242                                 fmt.Println(seqErr)
243                         }
244                 case osk.KTpgUp:
245                         tabSeq := []byte{27,91,53,126}
246                         seqErr := sendAnsiSeq(string(tabSeq)) 
247                         if seqErr != 0 {
248                                 fmt.Println(seqErr)
249                         }
250                 case osk.KTpgDn:
251                         tabSeq := []byte{27,91,54,126}
252                         seqErr := sendAnsiSeq(string(tabSeq)) 
253                         if seqErr != 0 {
254                                 fmt.Println(seqErr)
255                         }
256 //                      break L
257                 default:
258                         continue
259                 }
260                 prevType = k.KeyType
261         }
262 }



$ env GO111MODULE=off GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-kobo-linux-gnueabihf-gcc CXX=arm-kobo-linux-gnueabihf-g++ go build -o oskansi

$ arm-kobo-linux-gnueabihf-strip oskansi

Copy the ~/go/src/github.com/shermp/go-kobo-input/koboin-osk-sample/oskansi binary to the /mnt/onboard/.adds/koreader/scripts/ folder of your Kobo.

Note: we have renamed the app "oskansi", meaning on screen keyboard that sends keypresses as ANSI sequences.


Now, edit our /mnt/onboard/.adds/koreader/scripts/fbmenu.sh script (from Post #7 above) so we can call our oskansi keyboard app from NickelMenu:

# nano -l /mnt/onboard/.adds/koreader/scripts/fbmenu.sh
Code:
  6 qndb -m dlgConfirmSetTitle "1-Stop agetty; 2-fbpadkb;      3-fbpadkbS;   4-fbpad;          5-fbpadS;        6-oskansi;       7-oskansiS; Select option (1-7):"
...
 18 if [ "$num" == "1" ]; then
 19                 qndb -m mwcToast 500 "You selected 1-Stop agetty+fbpad"
 20                 fbcmd="/usr/bin/pkill agetty"
 21                 qndb -m mwcToast 200 "$fbcmd"
 22                 fberr=$($fbcmd 2>&1)
 23                 fbcmd="/usr/bin/pkill fbpad"
 24                 qndb -m mwcToast 200 "$fbcmd"
 25                 fberr=$($fbcmd 2>&1)
 26                 fbcmd="/usr/bin/pkill fbkeyboard"
 27                 qndb -m mwcToast 200 "$fbcmd"
 28                 fberr=$($fbcmd 2>&1)
 29                 fbcmd="/usr/bin/pkill oskansi"
 30                 qndb -m mwcToast 200 "$fbcmd"
 31                 fberr=$($fbcmd 2>&1)
...
 58 elif [ "$num" == "6" ]; then
 59                 qndb -m mwcToast 1000 "You selected 6-oskansi"
 60                 export HOME="/mnt/onboard/.adds/koreader/"
 61                 cd "$HOME"
 62                 fbcmd="eval /mnt/onboard/.adds/koreader/scripts/fbpadkb /bin/sh 0</dev/tty1"
 63                 qndb -m mwcToast 1000 "$fbcmd"
 64                 fberr=$($fbcmd 2>&1) &
 65                 fbcmd="/mnt/onboard/.adds/koreader/scripts/oskansi"
 66                 qndb -m mwcToast 1000 "$fbcmd"
 67                 fberr=$($fbcmd 2>&1)
 68 elif [ "$num" == "7" ]; then
 69                 qndb -m mwcToast 1000 "You selected 7-oskansiS"
 70                 export HOME="/mnt/onboard/.adds/koreader/"
 71                 cd "$HOME"
 72                 fbcmd="eval /mnt/onboard/.adds/koreader/scripts/fbpadkbS /bin/sh 0</dev/tty1"
 73                 qndb -m mwcToast 1000 "$fbcmd"
 74                 fberr=$($fbcmd 2>&1) &
 75                 fbcmd="/mnt/onboard/.adds/koreader/scripts/oskansi"
 76                 qndb -m mwcToast 1000 "$fbcmd"
 77                 fberr=$($fbcmd 2>&1)
 78 else
 79                 qndb -m mwcToast 1000 "You selected an invalid option" 
 80 fi
 81
 82 qndb -m mwcToast 1000 "${fberr:-"Bye!"}"


***

To avoid keyboard taps activating a Nickel function:
From More tab (second tab from right at bottom of screen), select Activity.
If you are in SideloadedMode=true, then Activity tab is second from left at bottom of screen.

Oskansi keyboard can be started and stopped from NickelMenu and unlike fbkeyboard, doesn't require networking, as well as being much faster, due to sending ANSI codes with IOCTL calls instead of simulating input events with uinput.

The biggest issue might be that nothing appears on the fbpad screen due to e.g. oskansi sending codes to /dev/pts/0 but fbpad being on /dev/pts/1, but that shouldn't happen if you start oskansi before any other SSH session.

*Also pls see *UPDATE below for NickelMenu entry.

***

And don't forget to copy the keymap1-en_us.json, keymap2-en_us.json, and Roboto-Medium.ttf files to the /mnt/onboard/.adds/koreader/ folder of your Kobo.
Oskansi binary or fbmenu.sh script should be in /mnt/onboard/.adds/koreader/scripts/ folder.

If you're using the fbmenu.sh script above to launch oskansi, you need:
1) NickelDBus installed
https://www.mobileread.com/forums/sh...ht=nickel+dbus
2) A NickelMenu config entry like:
menu_item :main :fbmenu :cmd_spawn :quiet:exec /mnt/onboard/.adds/koreader/scripts/fbmenu.sh
chain_success :dbg_toast :Started fbmenu
chain_failure :dbg_toast :Error

If you're not using the fbmenu.sh script, you could try NickelMenu config entries like:
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 starting fbpadkb
menu_item :main : oskansi :cmd_spawn :quiet:exec /mnt/onboard/.adds/koreader/scripts/oskansi
chain_success :dbg_toast :Started oskansi
chain_failure :dbg_toast :Error

*** UPDATE ***
* The NickelMenu command (if not using fbmenu.sh) for oskansi should be:

menu_item :main : oskansi :cmd_spawn :quiet:export HOME="/mnt/onboard/.adds/koreader/" && cd "$HOME" && /mnt/onboard/.adds/koreader/scripts/oskansi

This is because oskansi looks for the font and .json files in the current folder, which would be / by default, so it wouldn't find them if you put them in /mnt/onboard/.adds/koreader/ .
***

And grab the fbpadkb.bin binary from Post #6 above and rename it fbpadkb. You need to run this before oskansi.
You do not need the agetty hack from Post #7 above, and can comment out the line in /etc/udev/rules.d/90-fbpad.rules unless you are using fbpad with a USB keyboard.

Note that the CTL key in oskansi is a toggle so if you forget to retap it you may get funny characters.
Though it only works with alphabetic characters.
ALT key is a dummy key - maybe someone will want to activate it one day!


***

*UPDATE2*

Unfortunately, setting "EnableDebugServices=false" in [DeveloperSettings] in the /mnt/onboard/.kobo/Kobo/Kobo eReader.conf file, stopped oskansi keyboard from talking to fbpadkb.

Fortunately, you just need to run Dropbear or even telnet from NickelMenu beforehand, and then oskansi works again.

https://www.mobileread.com/forums/sh...d.php?t=353810


So it seems that:

-fbpad with USB keyboard needs agetty started and stopped in order to not stall.

-fbkeyboard needs WiFi on (or USB networking connected), though no hotspot connection needed, in order to not eventually freeze.

-oskansi needs either "EnableDebugServices=true" or dropbear/telnet started beforehand via NickelMenu in order to communicate with fbpad.

***
* Must rename oskansi.zip to oskansi.xz and extract with xz -d.
Attached Files
File Type: zip oskansi.zip (1.04 MB, 195 views)
File Type: gz oskansi-src.tar.gz (111.9 KB, 44 views)

Last edited by elinkser; 12-04-2023 at 04:59 PM. Reason: NickelMenu entry,EnableDebugServices=false issue
elinkser is offline   Reply With Quote