10 REM > KBDTrans
   20 REM Universal keyboard character input
   30 REM Translates top-bit keypresses to uniform key values
   40 :
   50 escOn$="ESC ON":escOff$="ESC OFF"
   60 ON ERROR escOn$="FX229":escOff$="FX229,1"
   70 OSCLI escOn$:ON ERROR OFF
   80 :
   90 PROCkbd_Init
  100 OSCLI escOff$
  110 PRINT"Press Esc+Esc to finish"
  120 col%=0:key%=0
  130 REPEAT
  140   last%=key%
  150   key%=FNkbd_GET
  160   PRINT FNh0(key%,3)'STRING$(col%,CHR$9);
  170   FOR A%=0 TO 3:IF A%=2:A%=3
  180     A$=EVAL("FNc"+STR$(A%)+"("+STR$(key%AND255)+")")
  190     PRINT A$;'STRING$(col%,CHR$9);
  200   NEXT A%
  210   PRINT STRING$(4,CHR$11);STRING$(5,CHR$9);
  220   col%=col%+5:IF POS<5:PRINTCHR$8'''':col%=0
  230 UNTIL (key%=27 AND last%=27) OR (INKEY-1 AND INKEY-113)
  240 OSCLI "FX4":OSCLI "FX225,1":OSCLI escOn$:IF col%:PRINT ''''
  250 END
  260 :
  270 REM Character conversions
  280 DEFFNc0(A%):IF A%>127:="|!"+FNc0(A% AND 127)
  290 IF A%<32 OR A%=127:="|"+CHR$(A% EOR 64) ELSE =LEFT$("|",A%=34 OR A%=124)+CHR$A%
  300 DEFFNc1(A%):IF ((A%+1) AND 127)<33:="^"+CHR$(A% EOR 64) ELSE =CHR$A%
  310 DEFFNc2(A%):IF A%<32 OR A%=127:="." ELSE =CHR$A%
  320 DEFFNc3(A%):IF ((A%+1) AND 127)<33:="." ELSE =CHR$A%
  330 DEFFNh0(A%,N%)=RIGHT$("0000000"+STR$~A%,N%)
  340 :
  350 :
  360 DEFPROCkbd_Init
  370 A%=0:X%=1:os%=((USR&FFF4)AND&FF00)DIV256
  380 kbd%=(os%<8):IF(INKEY-256AND&DB)=&53:kbd%=1
  390 REM kbd%   f1  f10  cursor
  400 REM  -1    81   CA   8C+n  RISC OS semi-regular
  410 REM   0    81   8A   CC+n  Regular
  420 REM   1    91   9A   88+n  RTR offset regular
  430 FOR A%=0 TO 7:OSCLI"FX"+STR$(221+A%)+","+STR$((A%EOR4)*16+128):NEXT
  440 OSCLI "FX4,2":OSCLI "FX219,9":OSCLI "FX254,128"
  450 ENDPROC
  460 :
  470 REM General cross-platform regular key input
  480 DEFFNkbd_GET:LOCAL A%:REPEAT A%=FNkbd_INKEY(100):UNTIL A%<>-1:=A%
  490 DEFFNkbd_INKEY(T%):LOCAL A%,S%
  500 A%=INKEYT%:S%=(INKEY-1AND16)+(INKEY-2AND32)+(INKEY-3AND48)
  510 IF A%=30:IF kbd%<0:IFINKEY-63:=&C8+S% :REM RISC OS Home
  520 IF A%=127:IF kbd%<0:=&C7+S%           :REM Delete
  530 IF A%<128 OR kbd%=0:=A%               :REM No translation
  540 IF kbd%>0:A%=A%-16                    :REM RTR topset keys
  550 IF kbd%>0:IF(A%AND&F0)=&70:=EVAL("&"+MID$("CD89BA67CDEFABAB",A%-&6F,1))+S%+&C0         :REM RTR editing keys
  560 IF kbd%>0:IF(A%AND&F0)=&80:IFA%>&8A:IFS%AND48:=((A%+&5C)EOR((A%>&8D)AND1))+18*(A%=&8B) :REM RTR Ctrl-editing keys
  570 IF kbd%>0:=A%
  580 IF (A%AND&CF)=&CD:=A%-7                 :REM Insert
  590 IF (A%AND&8F)>&89:A%=A%EOR&40           :REM f10-f12/cursors
  600 IF (A%AND&CF)=&CB:=A%-2                 :REM End
  610 IF (A%AND&DE)=&CE:=A%+(INKEY-1AND12)    :REM Down/Up or Shift-PgDn/Shift-PgUp
  620 IF (A%AND&DE)=&DE:=A%-20+(INKEY-1AND20) :REM Shift-Down/Shift-Up or PgDn/PgUp
  630 =A%
  640 :