]> bicyclesonthemoon.info Git - maszyna/commitdiff
initial state as of 28.7.2022 main
authorb <rowerynaksiezycu@gmail.com>
Thu, 28 Jul 2022 21:37:37 +0000 (23:37 +0200)
committerb <rowerynaksiezycu@gmail.com>
Thu, 28 Jul 2022 21:37:37 +0000 (23:37 +0200)
16 files changed:
Makefile [new file with mode: 0644]
avt2994-avrdude.txt [new file with mode: 0644]
code_page_template.py [new file with mode: 0644]
cp.txt [new file with mode: 0644]
esc.txt [new file with mode: 0644]
keyboard-patterns.c [new file with mode: 0644]
keyboard-patterns.h [new file with mode: 0644]
keyboard-patterns.py [new file with mode: 0755]
keyboard-patterns.txt [new file with mode: 0644]
keyboard.h [new file with mode: 0644]
license.txt [new file with mode: 0644]
maszyna.c [new file with mode: 0644]
maszyna_.c [new file with mode: 0644]
uni.py [new file with mode: 0755]
uni.txt [new file with mode: 0644]
update-template.py [new file with mode: 0755]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..a10c3c0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,645 @@
+# Hey Emacs, this is a -*- makefile -*-\r
+#----------------------------------------------------------------------------\r
+# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.\r
+#\r
+# Released to the Public Domain\r
+#\r
+# Additional material for this makefile was written by:\r
+# Peter Fleury\r
+# Tim Henigan\r
+# Colin O'Flynn\r
+# Reiner Patommel\r
+# Markus Pfaff\r
+# Sander Pool\r
+# Frederik Rouleau\r
+# Carlos Lamas\r
+#\r
+# I (Balthasar Szczepański) made some changes for this project,\r
+# to allow programming with the avt2994 tool and program fuse byte as well.\r
+#\r
+#----------------------------------------------------------------------------\r
+# On command line:\r
+#\r
+# make all = Make software.\r
+#\r
+# make clean = Clean out built project files.\r
+#\r
+# make coff = Convert ELF to AVR COFF.\r
+#\r
+# make extcoff = Convert ELF to AVR Extended COFF.\r
+#\r
+# make program = Download the hex file to the device, using avrdude.\r
+#                Please customize the avrdude settings below first!\r
+#\r
+# make program-fuse = as above but will program the fuse bytes too.\r
+#\r
+# make debug = Start either simulavr or avarice as specified for debugging, \r
+#              with avr-gdb or avr-insight as the front end for debugging.\r
+#\r
+# make filename.s = Just compile filename.c into the assembler code only.\r
+#\r
+# make filename.i = Create a preprocessed source file for use in submitting\r
+#                   bug reports to the GCC project.\r
+#\r
+# To rebuild project do "make clean" then "make all".\r
+#----------------------------------------------------------------------------\r
+\r
+\r
+# MCU name\r
+# MCU = atmega328p\r
+MCU = atmega1284\r
+\r
+\r
+# Processor frequency.\r
+#     This will define a symbol, F_CPU, in all source code files equal to the \r
+#     processor frequency. You can then use this symbol in your source code to \r
+#     calculate timings. Do NOT tack on a 'UL' at the end, this will be done\r
+#     automatically to create a 32-bit value in your source code.\r
+#     Typical values are:\r
+#         F_CPU =  1000000\r
+#         F_CPU =  1843200\r
+#         F_CPU =  2000000\r
+#         F_CPU =  3686400\r
+#         F_CPU =  4000000\r
+#         F_CPU =  7372800\r
+#         F_CPU =  8000000\r
+#         F_CPU = 11059200\r
+#         F_CPU = 14745600\r
+#         F_CPU = 16000000\r
+#         F_CPU = 18432000\r
+#         F_CPU = 20000000\r
+F_CPU = 8000000\r
+\r
+\r
+# Output format. (can be srec, ihex, binary)\r
+FORMAT = ihex\r
+\r
+\r
+# Target file name (without extension).\r
+TARGET = maszyna\r
+\r
+\r
+# Object files directory\r
+#     To put object files in current directory, use a dot (.), do NOT make\r
+#     this an empty or blank macro!\r
+OBJDIR = .\r
+\r
+\r
+# List C source files here. (C dependencies are automatically generated.)\r
+SRC = $(TARGET).c  keyboard-patterns.c\r
+\r
+\r
+# List C++ source files here. (C dependencies are automatically generated.)\r
+CPPSRC = \r
+\r
+\r
+# List Assembler source files here.\r
+#     Make them always end in a capital .S.  Files ending in a lowercase .s\r
+#     will not be considered source files but generated files (assembler\r
+#     output from the compiler), and will be deleted upon "make clean"!\r
+#     Even though the DOS/Win* filesystem matches both .s and .S the same,\r
+#     it will preserve the spelling of the filenames, and gcc itself does\r
+#     care about how the name is spelled on its command-line.\r
+#ASRC = pwm.S\r
+ASRC =\r
+\r
+\r
+# Optimization level, can be [0, 1, 2, 3, s]. \r
+#     0 = turn off optimization. s = optimize for size.\r
+#     (Note: 3 is not always the best optimization level. See avr-libc FAQ.)\r
+OPT = s\r
+\r
+\r
+# Debugging format.\r
+#     Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.\r
+#     AVR Studio 4.10 requires dwarf-2.\r
+#     AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.\r
+# DEBUG = dwarf-2\r
+DEBUG = \r
+\r
+\r
+# List any extra directories to look for include files here.\r
+#     Each directory must be seperated by a space.\r
+#     Use forward slashes for directory separators.\r
+#     For a directory that has spaces, enclose it in quotes.\r
+EXTRAINCDIRS = \r
+\r
+\r
+# Compiler flag to set the C Standard level.\r
+#     c89   = "ANSI" C\r
+#     gnu89 = c89 plus GCC extensions\r
+#     c99   = ISO C99 standard (not yet fully implemented)\r
+#     gnu99 = c99 plus GCC extensions\r
+CSTANDARD = -std=gnu99\r
+\r
+\r
+# Place -D or -U options here for C sources\r
+CDEFS = -DF_CPU=$(F_CPU)UL\r
+\r
+\r
+# Place -D or -U options here for ASM sources\r
+ADEFS = -DF_CPU=$(F_CPU)\r
+\r
+# Place -D or -U options here for C++ sources\r
+CPPDEFS = -DF_CPU=$(F_CPU)UL\r
+#CPPDEFS += -D__STDC_LIMIT_MACROS\r
+#CPPDEFS += -D__STDC_CONSTANT_MACROS\r
+\r
+\r
+\r
+#---------------- Compiler Options C ----------------\r
+#  -g*:          generate debugging information\r
+#  -O*:          optimization level\r
+#  -f...:        tuning, see GCC manual and avr-libc documentation\r
+#  -Wall...:     warning level\r
+#  -Wa,...:      tell GCC to pass this to the assembler.\r
+#    -adhlns...: create assembler listing\r
+# CFLAGS = -g$(DEBUG)\r
+CFLAGS = \r
+CFLAGS += $(CDEFS)\r
+CFLAGS += -O$(OPT)\r
+CFLAGS += -funsigned-char\r
+CFLAGS += -funsigned-bitfields\r
+CFLAGS += -fpack-struct\r
+CFLAGS += -fshort-enums\r
+CFLAGS += -Wall\r
+CFLAGS += -Wstrict-prototypes\r
+#CFLAGS += -mshort-calls\r
+#CFLAGS += -fno-unit-at-a-time\r
+#CFLAGS += -Wundef\r
+#CFLAGS += -Wunreachable-code\r
+#CFLAGS += -Wsign-compare\r
+CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)\r
+CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))\r
+CFLAGS += $(CSTANDARD)\r
+\r
+\r
+#---------------- Compiler Options C++ ----------------\r
+#  -g*:          generate debugging information\r
+#  -O*:          optimization level\r
+#  -f...:        tuning, see GCC manual and avr-libc documentation\r
+#  -Wall...:     warning level\r
+#  -Wa,...:      tell GCC to pass this to the assembler.\r
+#    -adhlns...: create assembler listing\r
+# CPPFLAGS = -g$(DEBUG)\r
+CPPFLAGS = \r
+CPPFLAGS += $(CPPDEFS)\r
+CPPFLAGS += -O$(OPT)\r
+CPPFLAGS += -funsigned-char\r
+CPPFLAGS += -funsigned-bitfields\r
+CPPFLAGS += -fpack-struct\r
+CPPFLAGS += -fshort-enums\r
+CPPFLAGS += -fno-exceptions\r
+CPPFLAGS += -Wall\r
+CPPFLAGS += -Wundef\r
+#CPPFLAGS += -mshort-calls\r
+#CPPFLAGS += -fno-unit-at-a-time\r
+#CPPFLAGS += -Wstrict-prototypes\r
+#CPPFLAGS += -Wunreachable-code\r
+#CPPFLAGS += -Wsign-compare\r
+CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)\r
+CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))\r
+#CPPFLAGS += $(CSTANDARD)\r
+\r
+\r
+#---------------- Assembler Options ----------------\r
+#  -Wa,...:   tell GCC to pass this to the assembler.\r
+#  -adhlns:   create listing\r
+#  -gstabs:   have the assembler create line number information; note that\r
+#             for use in COFF files, additional information about filenames\r
+#             and function names needs to be present in the assembler source\r
+#             files -- see avr-libc docs [FIXME: not yet described there]\r
+#  -listing-cont-lines: Sets the maximum number of continuation lines of hex \r
+#       dump that will be displayed for a given single line of source input.\r
+ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100\r
+\r
+\r
+#---------------- Library Options ----------------\r
+# Minimalistic printf version\r
+PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min\r
+\r
+# Floating point printf version (requires MATH_LIB = -lm below)\r
+PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt\r
+\r
+# If this is left blank, then it will use the Standard printf version.\r
+PRINTF_LIB = \r
+#PRINTF_LIB = $(PRINTF_LIB_MIN)\r
+#PRINTF_LIB = $(PRINTF_LIB_FLOAT)\r
+\r
+\r
+# Minimalistic scanf version\r
+SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min\r
+\r
+# Floating point + %[ scanf version (requires MATH_LIB = -lm below)\r
+SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt\r
+\r
+# If this is left blank, then it will use the Standard scanf version.\r
+SCANF_LIB = \r
+#SCANF_LIB = $(SCANF_LIB_MIN)\r
+#SCANF_LIB = $(SCANF_LIB_FLOAT)\r
+\r
+\r
+MATH_LIB = -lm\r
+\r
+\r
+# List any extra directories to look for libraries here.\r
+#     Each directory must be seperated by a space.\r
+#     Use forward slashes for directory separators.\r
+#     For a directory that has spaces, enclose it in quotes.\r
+EXTRALIBDIRS = \r
+\r
+\r
+\r
+#---------------- External Memory Options ----------------\r
+\r
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),\r
+# used for variables (.data/.bss) and heap (malloc()).\r
+#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff\r
+\r
+# 64 KB of external RAM, starting after internal RAM (ATmega128!),\r
+# only used for heap (malloc()).\r
+#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff\r
+\r
+EXTMEMOPTS =\r
+\r
+\r
+\r
+#---------------- Linker Options ----------------\r
+#  -Wl,...:     tell GCC to pass this to linker.\r
+#    -Map:      create map file\r
+#    --cref:    add cross reference to  map file\r
+LDFLAGS = -Wl,-Map=$(TARGET).map,--cref\r
+LDFLAGS += $(EXTMEMOPTS)\r
+LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))\r
+LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)\r
+#LDFLAGS += -T linker_script.x\r
+\r
+\r
+\r
+#---------------- Programming Options (avrdude) ----------------\r
+\r
+# Programming hardware\r
+# Type: avrdude -c ?\r
+# to get a full listing.\r
+#\r
+# see avt1994-avrdude.txt\r
+AVRDUDE_PROGRAMMER = avt2994\r
+\r
+# com1 = serial port. Use lpt1 to connect to parallel port.\r
+AVRDUDE_PORT = usb:AR0K62QF\r
+\r
+AVRDUDE_BAUD = 57600\r
+# AVRDUDE_BITCLOCK = 400\r
+AVRDUDE_BITCLOCK = 400\r
+#AVRDUDE_BAUD = 115200\r
+#old bootl.=57600, new=115200\r
+\r
+\r
+AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).elf\r
+#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep\r
+AVRDUDE_WRITE_FUSE = -U lfuse:w:$(TARGET).elf -U hfuse:w:$(TARGET).elf -U efuse:w:$(TARGET).elf\r
+\r
+\r
+# Uncomment the following if you want avrdude's erase cycle counter.\r
+# Note that this counter needs to be initialized first using -Yn,\r
+# see avrdude manual.\r
+#AVRDUDE_ERASE_COUNTER = -y\r
+\r
+# Uncomment the following if you do /not/ wish a verification to be\r
+# performed after programming the device.\r
+#AVRDUDE_NO_VERIFY = -V\r
+\r
+# Increase verbosity level.  Please use this when submitting bug\r
+# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> \r
+# to submit bug reports.\r
+#AVRDUDE_VERBOSE = -v -v\r
+\r
+AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) -B $(AVRDUDE_BITCLOCK)\r
+AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)\r
+AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)\r
+AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)\r
+\r
+\r
+\r
+#---------------- Debugging Options ----------------\r
+\r
+# For simulavr only - target MCU frequency.\r
+DEBUG_MFREQ = $(F_CPU)\r
+\r
+# Set the DEBUG_UI to either gdb or insight.\r
+# DEBUG_UI = gdb\r
+DEBUG_UI = insight\r
+\r
+# Set the debugging back-end to either avarice, simulavr.\r
+DEBUG_BACKEND = avarice\r
+#DEBUG_BACKEND = simulavr\r
+\r
+# GDB Init Filename.\r
+GDBINIT_FILE = __avr_gdbinit\r
+\r
+# When using avarice settings for the JTAG\r
+JTAG_DEV = /dev/com1\r
+\r
+# Debugging port used to communicate between GDB / avarice / simulavr.\r
+DEBUG_PORT = 4242\r
+\r
+# Debugging host used to communicate between GDB / avarice / simulavr, normally\r
+#     just set to localhost unless doing some sort of crazy debugging when \r
+#     avarice is running on a different computer.\r
+DEBUG_HOST = localhost\r
+\r
+\r
+\r
+#============================================================================\r
+\r
+\r
+# Define programs and commands.\r
+SHELL = sh\r
+CC = avr-gcc\r
+OBJCOPY = avr-objcopy\r
+OBJDUMP = avr-objdump\r
+SIZE = avr-size\r
+AR = avr-ar rcs\r
+NM = avr-nm\r
+AVRDUDE = avrdude\r
+REMOVE = rm -f\r
+REMOVEDIR = rm -rf\r
+COPY = cp\r
+WINSHELL = cmd\r
+PY = python3\r
+\r
+\r
+# Define Messages\r
+# English\r
+MSG_ERRORS_NONE = Errors: none\r
+MSG_BEGIN = -------- begin --------\r
+MSG_END = --------  end  --------\r
+MSG_SIZE_BEFORE = Size before: \r
+MSG_SIZE_AFTER = Size after:\r
+MSG_COFF = Converting to AVR COFF:\r
+MSG_EXTENDED_COFF = Converting to AVR Extended COFF:\r
+MSG_FLASH = Creating load file for Flash:\r
+MSG_EEPROM = Creating load file for EEPROM:\r
+MSG_EXTENDED_LISTING = Creating Extended Listing:\r
+MSG_SYMBOL_TABLE = Creating Symbol Table:\r
+MSG_LINKING = Linking:\r
+MSG_COMPILING = Compiling C:\r
+MSG_COMPILING_CPP = Compiling C++:\r
+MSG_ASSEMBLING = Assembling:\r
+MSG_CLEANING = Cleaning project:\r
+MSG_CREATING_LIBRARY = Creating library:\r
+\r
+\r
+\r
+\r
+# Define all object files.\r
+OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) \r
+\r
+# Define all listing files.\r
+LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) \r
+\r
+\r
+# Compiler flags to generate dependency files.\r
+GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d\r
+\r
+\r
+# Combine all necessary flags and optional flags.\r
+# Add target processor to flags.\r
+ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)\r
+ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)\r
+ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)\r
+\r
+\r
+\r
+\r
+\r
+# Default target.\r
+all: begin gccversion sizebefore build sizeafter end\r
+\r
+# Change the build target to build a HEX file or a library.\r
+build: elf hex eep lss sym\r
+#build: lib\r
+\r
+\r
+elf: $(TARGET).elf\r
+hex: $(TARGET).hex\r
+eep: $(TARGET).eep\r
+lss: $(TARGET).lss\r
+sym: $(TARGET).sym\r
+LIBNAME=lib$(TARGET).a\r
+lib: $(LIBNAME)\r
+\r
+keyboard-patterns.h: keyboard-patterns.c\r
+\r
+keyboard-patterns.c: keyboard-patterns.txt keyboard-patterns.py\r
+       $(PY) keyboard-patterns.py keyboard-patterns.txt keyboard-patterns.h keyboard-patterns.c\r
+\r
+\r
+# Eye candy.\r
+# AVR Studio 3.x does not check make's exit code but relies on\r
+# the following magic strings to be generated by the compile job.\r
+begin:\r
+       @echo\r
+       @echo $(MSG_BEGIN)\r
+\r
+end:\r
+       @echo $(MSG_END)\r
+       @echo\r
+\r
+\r
+# Display size of file.\r
+HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex\r
+ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf\r
+\r
+sizebefore:\r
+       @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \\r
+       2>/dev/null; echo; fi\r
+\r
+sizeafter:\r
+       @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \\r
+       2>/dev/null; echo; fi\r
+\r
+\r
+\r
+# Display compiler version information.\r
+gccversion : \r
+       @$(CC) --version\r
+\r
+\r
+\r
+# Program the device.  \r
+program: $(TARGET).hex $(TARGET).eep $(TARGET).elf\r
+       $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)\r
+\r
+program-fuse: $(TARGET).hex $(TARGET).eep $(TARGET).elf\r
+       $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_FUSE) $(AVRDUDE_WRITE_EEPROM)\r
+\r
+\r
+# Generate avr-gdb config/init file which does the following:\r
+#     define the reset signal, load the target file, connect to target, and set \r
+#     a breakpoint at main().\r
+gdb-config: \r
+       @$(REMOVE) $(GDBINIT_FILE)\r
+       @echo define reset >> $(GDBINIT_FILE)\r
+       @echo SIGNAL SIGHUP >> $(GDBINIT_FILE)\r
+       @echo end >> $(GDBINIT_FILE)\r
+       @echo file $(TARGET).elf >> $(GDBINIT_FILE)\r
+       @echo target remote $(DEBUG_HOST):$(DEBUG_PORT)  >> $(GDBINIT_FILE)\r
+ifeq ($(DEBUG_BACKEND),simulavr)\r
+       @echo load  >> $(GDBINIT_FILE)\r
+endif\r
+       @echo break main >> $(GDBINIT_FILE)\r
+\r
+debug: gdb-config $(TARGET).elf\r
+ifeq ($(DEBUG_BACKEND), avarice)\r
+       @echo Starting AVaRICE - Press enter when "waiting to connect" message displays.\r
+       @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \\r
+       $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)\r
+       @$(WINSHELL) /c pause\r
+\r
+else\r
+       @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \\r
+       $(DEBUG_MFREQ) --port $(DEBUG_PORT)\r
+endif\r
+       @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)\r
+\r
+\r
+\r
+\r
+# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.\r
+COFFCONVERT = $(OBJCOPY) --debugging\r
+COFFCONVERT += --change-section-address .data-0x800000\r
+COFFCONVERT += --change-section-address .bss-0x800000\r
+COFFCONVERT += --change-section-address .noinit-0x800000\r
+COFFCONVERT += --change-section-address .eeprom-0x810000\r
+\r
+\r
+\r
+coff: $(TARGET).elf\r
+       @echo\r
+       @echo $(MSG_COFF) $(TARGET).cof\r
+       $(COFFCONVERT) -O coff-avr $< $(TARGET).cof\r
+\r
+\r
+extcoff: $(TARGET).elf\r
+       @echo\r
+       @echo $(MSG_EXTENDED_COFF) $(TARGET).cof\r
+       $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof\r
+\r
+\r
+\r
+# Create final output files (.hex, .eep) from ELF output file.\r
+%.hex: %.elf\r
+       @echo\r
+       @echo $(MSG_FLASH) $@\r
+       $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock $< $@\r
+\r
+%.eep: %.elf\r
+       @echo\r
+       @echo $(MSG_EEPROM) $@\r
+       -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \\r
+       --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0\r
+\r
+# Create extended listing file from ELF output file.\r
+%.lss: %.elf\r
+       @echo\r
+       @echo $(MSG_EXTENDED_LISTING) $@\r
+       $(OBJDUMP) -h -S -z $< > $@\r
+\r
+# Create a symbol table from ELF output file.\r
+%.sym: %.elf\r
+       @echo\r
+       @echo $(MSG_SYMBOL_TABLE) $@\r
+       $(NM) -n $< > $@\r
+\r
+\r
+\r
+# Create library from object files.\r
+.SECONDARY : $(TARGET).a\r
+.PRECIOUS : $(OBJ)\r
+%.a: $(OBJ)\r
+       @echo\r
+       @echo $(MSG_CREATING_LIBRARY) $@\r
+       $(AR) $@ $(OBJ)\r
+\r
+\r
+# Link: create ELF output file from object files.\r
+.SECONDARY : $(TARGET).elf\r
+.PRECIOUS : $(OBJ)\r
+%.elf: $(OBJ)\r
+       @echo\r
+       @echo $(MSG_LINKING) $@\r
+       $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)\r
+\r
+\r
+# Compile: create object files from C source files.\r
+$(OBJDIR)/%.o : %.c keyboard-patterns.h\r
+       @echo\r
+       @echo $(MSG_COMPILING) $<\r
+       $(CC) -c $(ALL_CFLAGS) $< -o $@ \r
+\r
+\r
+# Compile: create object files from C++ source files.\r
+$(OBJDIR)/%.o : %.cpp keyboard-patterns.h\r
+       @echo\r
+       @echo $(MSG_COMPILING_CPP) $<\r
+       $(CC) -c $(ALL_CPPFLAGS) $< -o $@ \r
+\r
+\r
+# Compile: create assembler files from C source files.\r
+%.s : %.c keyboard-patterns.h\r
+       $(CC) -S $(ALL_CFLAGS) $< -o $@\r
+\r
+\r
+# Compile: create assembler files from C++ source files.\r
+%.s : %.cpp keyboard-patterns.h\r
+       $(CC) -S $(ALL_CPPFLAGS) $< -o $@\r
+\r
+\r
+# Assemble: create object files from assembler source files.\r
+$(OBJDIR)/%.o : %.S keyboard-patterns.h\r
+       @echo\r
+       @echo $(MSG_ASSEMBLING) $<\r
+       $(CC) -c $(ALL_ASFLAGS) $< -o $@\r
+\r
+\r
+# Create preprocessed source for use in sending a bug report.\r
+%.i : %.c keyboard-patterns.h\r
+       $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ \r
+\r
+\r
+# Target: clean project.\r
+clean: begin clean_list end\r
+\r
+clean_list :\r
+       @echo\r
+       @echo $(MSG_CLEANING)\r
+       $(REMOVE) $(TARGET).hex\r
+       $(REMOVE) $(TARGET).eep\r
+       $(REMOVE) $(TARGET).cof\r
+       $(REMOVE) $(TARGET).elf\r
+       $(REMOVE) $(TARGET).map\r
+       $(REMOVE) $(TARGET).sym\r
+       $(REMOVE) $(TARGET).lss\r
+       $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)\r
+       $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)\r
+       $(REMOVE) $(SRC:.c=.s)\r
+       $(REMOVE) $(SRC:.c=.d)\r
+       $(REMOVE) $(SRC:.c=.i)\r
+       $(REMOVEDIR) .dep\r
+\r
+\r
+# Create object files directory\r
+$(shell mkdir $(OBJDIR) 2>/dev/null)\r
+\r
+\r
+# Include the dependency files.\r
+-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)\r
+\r
+\r
+# Listing of phony targets.\r
+.PHONY : all begin finish end sizebefore sizeafter gccversion \\r
+build elf hex eep lss sym coff extcoff \\r
+clean clean_list program debug gdb-config\r
+\r
+\r
diff --git a/avt2994-avrdude.txt b/avt2994-avrdude.txt
new file mode 100644 (file)
index 0000000..9070f19
--- /dev/null
@@ -0,0 +1,149 @@
+Install avrdude gcc-avr avr-libc
+
+Programator AVT2994
+FTDI232RL.
+
+MAP:
+
+232RL AVR
+ RxD  MOSI
+ TxD  MISO
+ DTR  RST
+ RTS  SCK
+         FT232RL: 
+         +------+    
+  TxD D0 |1*  28|    OSCO
+  DTR D4 |2   27|    OSCI
+  RTS D2 |3   26|    TEST
+VccIO    |4   25|    AGND
+  RxD D1 |5   24|    NC
+   DI D7 |6   23| C0 CBUS0 
+  GND    |7   22| C1 CBUS1
+   NC    |8   21|    GND
+  DSR D5 |9   20|    Vcc
+  DCD D6 |10  19|    RESET
+  CTS D3 |11  18|    GND
+CBUS4    |12  17|    3V3OUT
+CBUS2 C2 |13  16|    USBDM
+CBUS3 C3 |14  15|    USBDP
+         +------+
+
+
+/etc/avrdude.conf
+
+programmer
+  id    = "avt2994";
+  desc  = "UniProgUSB AVT kit 2994";
+  type  = "ftdi_syncbb";
+  connection_type = usb;
+  miso  = 0;  # TxD
+  sck   = 2;  # RTS
+  mosi  = 1;  # RxD
+  reset = 4;  # DTR
+;
+
+
+               328P
+             +--\/--+
+[DTR] RST C6 |1*  28| C5
+       RX D0 |2   27| C4
+       TX D1 |3   26| C3
+          D2 |4   25| C2
+          D3 |5   24| C1
+          D4 |6   23| C0
+  [+]    VCC |7   22| GND     [-]
+  [-]    GND |8   21| AREF
+       X1 B6 |9   20| AVCC    [+]
+       X2 B7 |10  19| B5 SCK  [RTS]
+          D5 |11  18| B4 MISO [TX]
+          D6 |12  17| B3 MOSI [RX]
+          D7 |13  16| B2
+          B0 |14  15| B1
+             +------+
+
+> sudo dmesg | tail
+[sudo] password for b: 
+[18049.452272] usb 4-2: USB disconnect, device number 7
+[18051.272131] usb 4-2: new full-speed USB device number 8 using uhci_hcd
+[18051.486223] usb 4-2: New USB device found, idVendor=0403, idProduct=6001, bcdDevice= 6.00
+[18051.486227] usb 4-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
+[18051.486229] usb 4-2: Product: FT232R USB UART
+[18051.486230] usb 4-2: Manufacturer: FTDI
+[18051.486232] usb 4-2: SerialNumber: AR0K62QF
+[18051.493294] ftdi_sio 4-2:1.0: FTDI USB Serial Device converter detected
+[18051.493330] usb 4-2: Detected FT232RL
+[18051.495373] usb 4-2: FTDI USB Serial Device converter now attached to ttyUSB0
+
+> avrdude -v -c avt2994 -p m328p -P usb:AR0K62QF -B 400
+
+avrdude: Version 6.3-20171130
+         Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
+         Copyright (c) 2007-2014 Joerg Wunsch
+
+         System wide configuration file is "/etc/avrdude.conf"
+         User configuration file is "/home/b/.avrduderc"
+         User configuration file does not exist or is not a regular file, skipping
+
+         Using Port                    : usb:AR0K62QF
+         Using Programmer              : avt2994
+         Setting bit clk period        : 400.0
+         AVR Part                      : ATmega328P
+         Chip Erase delay              : 9000 us
+         PAGEL                         : PD7
+         BS2                           : PC2
+         RESET disposition             : dedicated
+         RETRY pulse                   : SCK
+         serial program mode           : yes
+         parallel program mode         : yes
+         Timeout                       : 200
+         StabDelay                     : 100
+         CmdexeDelay                   : 25
+         SyncLoops                     : 32
+         ByteDelay                     : 0
+         PollIndex                     : 3
+         PollValue                     : 0x53
+         Memory Detail                 :
+
+                                  Block Poll               Page                       Polled
+           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
+           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
+           eeprom        65    20     4    0 no       1024    4      0  3600  3600 0xff 0xff
+           flash         65     6   128    0 yes     32768  128    256  4500  4500 0xff 0xff
+           lfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
+           hfuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
+           efuse          0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
+           lock           0     0     0    0 no          1    0      0  4500  4500 0x00 0x00
+           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
+           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00
+
+         Programmer Type : ftdi_syncbb
+         Description     : UniProgUSB AVT kit 2994
+         Pin assignment  : 0..7 = DBUS0..7
+           VCC     =  (not used)
+           BUFF    =  (not used)
+           RESET   =  4
+           SCK     =  2
+           MOSI    =  1
+           MISO    =  0
+           ERR LED =  (not used)
+           RDY LED =  (not used)
+           PGM LED =  (not used)
+           VFY LED =  (not used)
+
+avrdude: AVR device initialized and ready to accept instructions
+
+Reading | ################################################## | 100% 0.10s
+
+avrdude: Device signature = 0x1e950f (probably m328p)
+avrdude: safemode: lfuse reads as 62
+avrdude: safemode: hfuse reads as D9
+avrdude: safemode: efuse reads as FF
+
+avrdude: safemode: lfuse reads as 62
+avrdude: safemode: hfuse reads as D9
+avrdude: safemode: efuse reads as FF
+avrdude: safemode: Fuses OK (E:FF, H:D9, L:62)
+
+avrdude done.  Thank you.
+
diff --git a/code_page_template.py b/code_page_template.py
new file mode 100644 (file)
index 0000000..1bd5a1c
--- /dev/null
@@ -0,0 +1,32 @@
+encodings = [
+    'ascii',
+    'cp852',
+    'cp1250',
+    'iso8859-2'
+]
+
+B = [bytes([i]) for i in range (0, 0x100)]
+all_chars = []
+
+for enc in encodings:
+    print (enc + ':')
+    
+    offset = 0 if enc == 'ascii' else 0x80
+    
+    for i in range (offset, offset+0x80, 0x10):
+        l = ''
+        for j in range (0, 0x10):
+            t = B[i+j].decode(enc, errors='ignore')
+            if t == '':
+                t = '_'
+            c = ord(t)
+            l += ' %04x' % c
+            
+            if not (c in all_chars):
+                all_chars.append(c)
+        print (l)
+
+d = sorted(all_chars)
+
+for c in d:
+    print((' %04x: ' % c) + chr(c))
\ No newline at end of file
diff --git a/cp.txt b/cp.txt
new file mode 100644 (file)
index 0000000..8a2ec8a
--- /dev/null
+++ b/cp.txt
@@ -0,0 +1,16 @@
+ |0 1 2 3 4 5 6 7 8 9 A B C D E F \r
+-+--------------------------------\r
+2|  ! " # $ % & ' ( ) * + , - . / \r
+3|0 1 2 3 4 5 6 7 8 9 : ; < = > ? \r
+4|@ A B C D E F G H I J K L M N O \r
+5|P Q R S T U V W X Y Z [ \ ] ^ _ \r
+6|` a b c d e f g h i j k l m n o \r
+7|p q r s t u v w x y z { | } ~ \7f \r
+8|\80 \81 \82 \83 \84 \85 \86 \87 \88 \89 \8a \8b \8c \8d \8e \8f \r
+9|\90 \91 \92 \93 \94 \95 \96 \97 \98 \99 \9a \9b \9c \9d \9e \9f \r
+A|  ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ \r
+B|° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ \r
+C|À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï \r
+D|РѠҠӠԠՠ֠נؠ٠ڠ۠ܠݠޠߠ\r
+E|à á â ã ä å æ ç è é ê ë ì í î ï \r
+F|ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ \r
diff --git a/esc.txt b/esc.txt
new file mode 100644 (file)
index 0000000..fd436de
--- /dev/null
+++ b/esc.txt
@@ -0,0 +1,106 @@
+ESC (  C    7
+ESC (  c    9
+ESC C       3
+ESC C  NUL  4
+ESC N       3
+ESC O       2
+ESC Q       3
+ESC 1       3
+CR          1
+LF          1
+FF          1
+ESC $       4
+ESC \       4
+ESC (  V    7
+ESC (  v    7
+ESC J       3
+HT          1
+VT          1
+ESC f       4
+BS          1
+ESC (  U    6
+ESC 0       2
+ESC 2       2
+ESC 3       3
+ESC +       3
+ESC A       3
+ESC 1       2
+ESC D       TERM NUL 35
+ESC B       TERM NUL 19
+ESC b       TERM NUL 19
+ESC /       3
+ESC e       4
+ESC a       3
+ESC (  t    8
+ESC t       3
+ESC R       3
+ESC &  NUL  ???
+ESC :  NUL  5
+ESC %       3
+ESC x       3
+ESC k       3
+ESC X       5
+ESC c       4
+ESC P       2
+ESC M       2
+ESC g       2
+ESC p       3
+ESC SP      3
+ESC E       2
+ESC F       2
+ESC 4       2
+ESC 5       2
+ESC !       3
+ESC G       2
+ESC H       2
+ESC -       3
+ESC (  -    8
+ESC S       3
+ESC T       2
+ESC q       3
+SI          1
+ESC SI      2
+DC2         1
+DO          1
+ESC SO      2
+DC4         1
+ESC W       3
+ESC w       3
+ESC (  ^    ???
+ESC 6       2
+ESC 7       2
+ESC I       3
+ESC m       3
+ESC EM      3
+ESC U       3
+ESC <       2
+BEL         1
+ESC 8       2
+ESC 9       2
+ESC s       3
+ESC (  G    6
+ESC (  i    6
+ESC .       ???
+ESC . /2    8
+ESC *       ???
+ESC ?       4
+ESC K       ???
+ESC L       ???
+ESC Y       ???
+ESC Z       ???
+ESC ^       ???
+ESC r       3
+ESC (       ???
+ESC @       2
+CAN         1
+DEL         1
+DC1         1
+DC3         1
+ESC #       2
+ESC =       2
+ESC >       2
+ESC j       3
+ESC i       3
+
+
+
diff --git a/keyboard-patterns.c b/keyboard-patterns.c
new file mode 100644 (file)
index 0000000..596874e
--- /dev/null
@@ -0,0 +1,3748 @@
+/* file autogenerated from keyboard-patterns.txt. do not edit - will be overwritten */
+#include <stdint.h>
+#include "keyboard.h"
+#include "keyboard-patterns.h"
+
+const uint8_t ENC_C1[0x0B] = {
+       1,
+       1,
+       1,
+       1,
+       1,
+       1,
+       1,
+       1,
+       1,
+       0,
+       0,
+};
+
+uint8_t const * const * const CH_LIST[0x0B] = {
+       CH_ISO8859_1,
+       CH_ISO8859_2,
+       CH_ISO8859_3,
+       CH_ISO8859_4,
+       CH_ISO8859_9,
+       CH_ISO8859_10,
+       CH_ISO8859_13,
+       CH_ISO8859_15,
+       CH_ISO8859_16,
+       CH_CP1250,
+       CH_CP852,
+};
+
+uint8_t const * const KEYMAP_LIST[0x0B] = {
+       KEYMAP_ISO8859_1,
+       KEYMAP_ISO8859_2,
+       KEYMAP_ISO8859_3,
+       KEYMAP_ISO8859_4,
+       KEYMAP_ISO8859_9,
+       KEYMAP_ISO8859_10,
+       KEYMAP_ISO8859_13,
+       KEYMAP_ISO8859_15,
+       KEYMAP_ISO8859_16,
+       KEYMAP_CP1250,
+       KEYMAP_CP852,
+};
+
+uint8_t const * const CH_TABLE[0x0600] = {
+/* ASCII      00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 00 */ CH_0000, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL,
+/* 10 */ CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL,
+/* 20 */ CH_0020, CH_0021, CH_0022, CH_0023, CH_0024, CH_0025, CH_0026, CH_0027, CH_0028, CH_0029, CH_002A, CH_002B, CH_002C, CH_002D, CH_002E, CH_002F,
+/* 30 */ CH_0030, CH_0031, CH_0032, CH_0033, CH_0034, CH_0035, CH_0036, CH_0037, CH_0038, CH_0039, CH_003A, CH_003B, CH_003C, CH_003D, CH_003E, CH_003F,
+/* 40 */ CH_0040, CH_0041, CH_0042, CH_0043, CH_0044, CH_0045, CH_0046, CH_0047, CH_0048, CH_0049, CH_004A, CH_004B, CH_004C, CH_004D, CH_004E, CH_004F,
+/* 50 */ CH_0050, CH_0051, CH_0052, CH_0053, CH_0054, CH_0055, CH_0056, CH_0057, CH_0058, CH_0059, CH_005A, CH_005B, CH_005C, CH_005D, CH_005E, CH_005F,
+/* 60 */ CH_0060, CH_0061, CH_0062, CH_0063, CH_0064, CH_0065, CH_0066, CH_0067, CH_0068, CH_0069, CH_006A, CH_006B, CH_006C, CH_006D, CH_006E, CH_006F,
+/* 70 */ CH_0070, CH_0071, CH_0072, CH_0073, CH_0074, CH_0075, CH_0076, CH_0077, CH_0078, CH_0079, CH_007A, CH_007B, CH_007C, CH_007D, CH_007E, CH_UNKN,
+/* ISO8859_1  00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_00A1, CH_00A2, CH_00A3, CH_00A4, CH_00A5, CH_00A6, CH_00A7, CH_00A8, CH_00A9, CH_00AA, CH_00AB, CH_00AC, CH_00AD, CH_00AE, CH_00AF,
+/* B0 */ CH_00B0, CH_00B1, CH_00B2, CH_00B3, CH_00B4, CH_00B5, CH_00B6, CH_00B7, CH_00B8, CH_00B9, CH_00BA, CH_00BB, CH_00BC, CH_00BD, CH_00BE, CH_00BF,
+/* C0 */ CH_00C0, CH_00C1, CH_00C2, CH_00C3, CH_00C4, CH_00C5, CH_00C6, CH_00C7, CH_00C8, CH_00C9, CH_00CA, CH_00CB, CH_00CC, CH_00CD, CH_00CE, CH_00CF,
+/* D0 */ CH_00D0, CH_00D1, CH_00D2, CH_00D3, CH_00D4, CH_00D5, CH_00D6, CH_00D7, CH_00D8, CH_00D9, CH_00DA, CH_00DB, CH_00DC, CH_00DD, CH_00DE, CH_00DF,
+/* E0 */ CH_00E0, CH_00E1, CH_00E2, CH_00E3, CH_00E4, CH_00E5, CH_00E6, CH_00E7, CH_00E8, CH_00E9, CH_00EA, CH_00EB, CH_00EC, CH_00ED, CH_00EE, CH_00EF,
+/* F0 */ CH_00F0, CH_00F1, CH_00F2, CH_00F3, CH_00F4, CH_00F5, CH_00F6, CH_00F7, CH_00F8, CH_00F9, CH_00FA, CH_00FB, CH_00FC, CH_00FD, CH_00FE, CH_00FF,
+/* ISO8859_2  00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_0104, CH_02D8, CH_0141, CH_00A4, CH_013D, CH_015A, CH_00A7, CH_00A8, CH_0160, CH_015E, CH_0164, CH_0179, CH_00AD, CH_017D, CH_017B,
+/* B0 */ CH_00B0, CH_0105, CH_02DB, CH_0142, CH_00B4, CH_013E, CH_015B, CH_02C7, CH_00B8, CH_0161, CH_015F, CH_0165, CH_017A, CH_02DD, CH_017E, CH_017C,
+/* C0 */ CH_0154, CH_00C1, CH_00C2, CH_0102, CH_00C4, CH_0139, CH_0106, CH_00C7, CH_010C, CH_00C9, CH_0118, CH_00CB, CH_011A, CH_00CD, CH_00CE, CH_010E,
+/* D0 */ CH_0110, CH_0143, CH_0147, CH_00D3, CH_00D4, CH_0150, CH_00D6, CH_00D7, CH_0158, CH_016E, CH_00DA, CH_0170, CH_00DC, CH_00DD, CH_0162, CH_00DF,
+/* E0 */ CH_0155, CH_00E1, CH_00E2, CH_0103, CH_00E4, CH_013A, CH_0107, CH_00E7, CH_010D, CH_00E9, CH_0119, CH_00EB, CH_011B, CH_00ED, CH_00EE, CH_010F,
+/* F0 */ CH_0111, CH_0144, CH_0148, CH_00F3, CH_00F4, CH_0151, CH_00F6, CH_00F7, CH_0159, CH_016F, CH_00FA, CH_0171, CH_00FC, CH_00FD, CH_0163, CH_02D9,
+/* ISO8859_3  00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_0126, CH_02D8, CH_00A3, CH_00A4, CH_UNKN, CH_0124, CH_00A7, CH_00A8, CH_0130, CH_015E, CH_011E, CH_0134, CH_00AD, CH_UNKN, CH_017B,
+/* B0 */ CH_00B0, CH_0127, CH_00B2, CH_00B3, CH_00B4, CH_00B5, CH_0125, CH_00B7, CH_00B8, CH_0131, CH_015F, CH_011F, CH_0135, CH_00BD, CH_UNKN, CH_017C,
+/* C0 */ CH_00C0, CH_00C1, CH_00C2, CH_UNKN, CH_00C4, CH_010A, CH_0108, CH_00C7, CH_00C8, CH_00C9, CH_00CA, CH_00CB, CH_00CC, CH_00CD, CH_00CE, CH_00CF,
+/* D0 */ CH_UNKN, CH_00D1, CH_00D2, CH_00D3, CH_00D4, CH_0120, CH_00D6, CH_00D7, CH_011C, CH_00D9, CH_00DA, CH_00DB, CH_00DC, CH_016C, CH_015C, CH_00DF,
+/* E0 */ CH_00E0, CH_00E1, CH_00E2, CH_UNKN, CH_00E4, CH_010B, CH_0109, CH_00E7, CH_00E8, CH_00E9, CH_00EA, CH_00EB, CH_00EC, CH_00ED, CH_00EE, CH_00EF,
+/* F0 */ CH_UNKN, CH_00F1, CH_00F2, CH_00F3, CH_00F4, CH_0121, CH_00F6, CH_00F7, CH_011D, CH_00F9, CH_00FA, CH_00FB, CH_00FC, CH_016D, CH_015D, CH_02D9,
+/* ISO8859_4  00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_0104, CH_0138, CH_0156, CH_00A4, CH_0128, CH_013B, CH_00A7, CH_00A8, CH_0160, CH_0112, CH_0122, CH_0166, CH_00AD, CH_017D, CH_00AF,
+/* B0 */ CH_00B0, CH_0105, CH_02DB, CH_0157, CH_00B4, CH_0129, CH_013C, CH_02C7, CH_00B8, CH_0161, CH_0113, CH_0123, CH_0167, CH_014A, CH_017E, CH_014B,
+/* C0 */ CH_0100, CH_00C1, CH_00C2, CH_00C3, CH_00C4, CH_00C5, CH_00C6, CH_012E, CH_010C, CH_00C9, CH_0118, CH_00CB, CH_0116, CH_00CD, CH_00CE, CH_012A,
+/* D0 */ CH_0110, CH_0145, CH_014C, CH_0136, CH_00D4, CH_00D5, CH_00D6, CH_00D7, CH_00D8, CH_0172, CH_00DA, CH_00DB, CH_00DC, CH_0168, CH_016A, CH_00DF,
+/* E0 */ CH_0101, CH_00E1, CH_00E2, CH_00E3, CH_00E4, CH_00E5, CH_00E6, CH_012F, CH_010D, CH_00E9, CH_0119, CH_00EB, CH_0117, CH_00ED, CH_00EE, CH_012B,
+/* F0 */ CH_0111, CH_0146, CH_014D, CH_0137, CH_00F4, CH_00F5, CH_00F6, CH_00F7, CH_00F8, CH_0173, CH_00FA, CH_00FB, CH_00FC, CH_0169, CH_016B, CH_02D9,
+/* ISO8859_9  00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_00A1, CH_00A2, CH_00A3, CH_00A4, CH_00A5, CH_00A6, CH_00A7, CH_00A8, CH_00A9, CH_00AA, CH_00AB, CH_00AC, CH_00AD, CH_00AE, CH_00AF,
+/* B0 */ CH_00B0, CH_00B1, CH_00B2, CH_00B3, CH_00B4, CH_00B5, CH_00B6, CH_00B7, CH_00B8, CH_00B9, CH_00BA, CH_00BB, CH_00BC, CH_00BD, CH_00BE, CH_00BF,
+/* C0 */ CH_00C0, CH_00C1, CH_00C2, CH_00C3, CH_00C4, CH_00C5, CH_00C6, CH_00C7, CH_00C8, CH_00C9, CH_00CA, CH_00CB, CH_00CC, CH_00CD, CH_00CE, CH_00CF,
+/* D0 */ CH_011E, CH_00D1, CH_00D2, CH_00D3, CH_00D4, CH_00D5, CH_00D6, CH_00D7, CH_00D8, CH_00D9, CH_00DA, CH_00DB, CH_00DC, CH_0130, CH_015E, CH_00DF,
+/* E0 */ CH_00E0, CH_00E1, CH_00E2, CH_00E3, CH_00E4, CH_00E5, CH_00E6, CH_00E7, CH_00E8, CH_00E9, CH_00EA, CH_00EB, CH_00EC, CH_00ED, CH_00EE, CH_00EF,
+/* F0 */ CH_011F, CH_00F1, CH_00F2, CH_00F3, CH_00F4, CH_00F5, CH_00F6, CH_00F7, CH_00F8, CH_00F9, CH_00FA, CH_00FB, CH_00FC, CH_0131, CH_015F, CH_00FF,
+/* ISO8859_10 00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_0104, CH_0112, CH_0122, CH_012A, CH_0128, CH_0136, CH_00A7, CH_013B, CH_0110, CH_0160, CH_0166, CH_017D, CH_00AD, CH_016A, CH_014A,
+/* B0 */ CH_00B0, CH_0105, CH_0113, CH_0123, CH_012B, CH_0129, CH_0137, CH_00B7, CH_013C, CH_0111, CH_0161, CH_0167, CH_017E, CH_UNKN, CH_016B, CH_014B,
+/* C0 */ CH_0100, CH_00C1, CH_00C2, CH_00C3, CH_00C4, CH_00C5, CH_00C6, CH_012E, CH_010C, CH_00C9, CH_0118, CH_00CB, CH_0116, CH_00CD, CH_00CE, CH_00CF,
+/* D0 */ CH_00D0, CH_0145, CH_014C, CH_00D3, CH_00D4, CH_00D5, CH_00D6, CH_0168, CH_00D8, CH_0172, CH_00DA, CH_00DB, CH_00DC, CH_00DD, CH_00DE, CH_00DF,
+/* E0 */ CH_0101, CH_00E1, CH_00E2, CH_00E3, CH_00E4, CH_00E5, CH_00E6, CH_012F, CH_010D, CH_00E9, CH_0119, CH_00EB, CH_0117, CH_00ED, CH_00EE, CH_00EF,
+/* F0 */ CH_00F0, CH_0146, CH_014D, CH_00F3, CH_00F4, CH_00F5, CH_00F6, CH_0169, CH_00F8, CH_0173, CH_00FA, CH_00FB, CH_00FC, CH_00FD, CH_00FE, CH_0138,
+/* ISO8859_13 00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_UNKN, CH_00A2, CH_00A3, CH_00A4, CH_UNKN, CH_00A6, CH_00A7, CH_00D8, CH_00A9, CH_0156, CH_00AB, CH_00AC, CH_00AD, CH_00AE, CH_00C6,
+/* B0 */ CH_00B0, CH_00B1, CH_00B2, CH_00B3, CH_UNKN, CH_00B5, CH_00B6, CH_00B7, CH_00F8, CH_00B9, CH_0157, CH_00BB, CH_00BC, CH_00BD, CH_00BE, CH_00E6,
+/* C0 */ CH_0104, CH_012E, CH_0100, CH_0106, CH_00C4, CH_00C5, CH_0118, CH_0112, CH_010C, CH_00C9, CH_0179, CH_0116, CH_0122, CH_0136, CH_012A, CH_013B,
+/* D0 */ CH_0160, CH_0143, CH_0145, CH_00D3, CH_014C, CH_00D5, CH_00D6, CH_00D7, CH_0172, CH_0141, CH_015A, CH_016A, CH_00DC, CH_017B, CH_017D, CH_00DF,
+/* E0 */ CH_0105, CH_012F, CH_0101, CH_0107, CH_00E4, CH_00E5, CH_0119, CH_0113, CH_010D, CH_00E9, CH_017A, CH_0117, CH_0123, CH_0137, CH_012B, CH_013C,
+/* F0 */ CH_0161, CH_0144, CH_0146, CH_00F3, CH_014D, CH_00F5, CH_00F6, CH_00F7, CH_0173, CH_0142, CH_015B, CH_016B, CH_00FC, CH_017C, CH_017E, CH_UNKN,
+/* ISO8859_15 00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_00A1, CH_00A2, CH_00A3, CH_UNKN, CH_00A5, CH_0160, CH_00A7, CH_0161, CH_00A9, CH_00AA, CH_00AB, CH_00AC, CH_00AD, CH_00AE, CH_00AF,
+/* B0 */ CH_00B0, CH_00B1, CH_00B2, CH_00B3, CH_017D, CH_00B5, CH_00B6, CH_00B7, CH_017E, CH_00B9, CH_00BA, CH_00BB, CH_0152, CH_0153, CH_0178, CH_00BF,
+/* C0 */ CH_00C0, CH_00C1, CH_00C2, CH_00C3, CH_00C4, CH_00C5, CH_00C6, CH_00C7, CH_00C8, CH_00C9, CH_00CA, CH_00CB, CH_00CC, CH_00CD, CH_00CE, CH_00CF,
+/* D0 */ CH_00D0, CH_00D1, CH_00D2, CH_00D3, CH_00D4, CH_00D5, CH_00D6, CH_00D7, CH_00D8, CH_00D9, CH_00DA, CH_00DB, CH_00DC, CH_00DD, CH_00DE, CH_00DF,
+/* E0 */ CH_00E0, CH_00E1, CH_00E2, CH_00E3, CH_00E4, CH_00E5, CH_00E6, CH_00E7, CH_00E8, CH_00E9, CH_00EA, CH_00EB, CH_00EC, CH_00ED, CH_00EE, CH_00EF,
+/* F0 */ CH_00F0, CH_00F1, CH_00F2, CH_00F3, CH_00F4, CH_00F5, CH_00F6, CH_00F7, CH_00F8, CH_00F9, CH_00FA, CH_00FB, CH_00FC, CH_00FD, CH_00FE, CH_00FF,
+/* ISO8859_16 00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* A0 */ CH_00A0, CH_0104, CH_0105, CH_0141, CH_UNKN, CH_UNKN, CH_0160, CH_00A7, CH_0161, CH_00A9, CH_UNKN, CH_00AB, CH_0179, CH_00AD, CH_017A, CH_017B,
+/* B0 */ CH_00B0, CH_00B1, CH_010C, CH_0142, CH_017D, CH_UNKN, CH_00B6, CH_00B7, CH_017E, CH_010D, CH_UNKN, CH_00BB, CH_0152, CH_0153, CH_0178, CH_017C,
+/* C0 */ CH_00C0, CH_00C1, CH_00C2, CH_0102, CH_00C4, CH_0106, CH_00C6, CH_00C7, CH_00C8, CH_00C9, CH_00CA, CH_00CB, CH_00CC, CH_00CD, CH_00CE, CH_00CF,
+/* D0 */ CH_0110, CH_0143, CH_00D2, CH_00D3, CH_00D4, CH_0150, CH_00D6, CH_015A, CH_0170, CH_00D9, CH_00DA, CH_00DB, CH_00DC, CH_0118, CH_UNKN, CH_00DF,
+/* E0 */ CH_00E0, CH_00E1, CH_00E2, CH_0103, CH_00E4, CH_0107, CH_00E6, CH_00E7, CH_00E8, CH_00E9, CH_00EA, CH_00EB, CH_00EC, CH_00ED, CH_00EE, CH_00EF,
+/* F0 */ CH_0111, CH_0144, CH_00F2, CH_00F3, CH_00F4, CH_0151, CH_00F6, CH_015B, CH_0171, CH_00F9, CH_00FA, CH_00FB, CH_00FC, CH_0119, CH_UNKN, CH_00FF,
+/* CP1250     00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_0160, CH_UNKN, CH_015A, CH_0164, CH_017D, CH_0179,
+/* 90 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_0161, CH_UNKN, CH_015B, CH_0165, CH_017E, CH_017A,
+/* A0 */ CH_00A0, CH_02C7, CH_02D8, CH_0141, CH_00A4, CH_0104, CH_00A6, CH_00A7, CH_00A8, CH_00A9, CH_015E, CH_00AB, CH_00AC, CH_00AD, CH_00AE, CH_017B,
+/* B0 */ CH_00B0, CH_00B1, CH_02DB, CH_0142, CH_00B4, CH_00B5, CH_00B6, CH_00B7, CH_00B8, CH_0105, CH_015F, CH_00BB, CH_013D, CH_02DD, CH_013E, CH_017C,
+/* C0 */ CH_0154, CH_00C1, CH_00C2, CH_0102, CH_00C4, CH_0139, CH_0106, CH_00C7, CH_010C, CH_00C9, CH_0118, CH_00CB, CH_011A, CH_00CD, CH_00CE, CH_010E,
+/* D0 */ CH_0110, CH_0143, CH_0147, CH_00D3, CH_00D4, CH_0150, CH_00D6, CH_00D7, CH_0158, CH_016E, CH_00DA, CH_0170, CH_00DC, CH_00DD, CH_0162, CH_00DF,
+/* E0 */ CH_0155, CH_00E1, CH_00E2, CH_0103, CH_00E4, CH_013A, CH_0107, CH_00E7, CH_010D, CH_00E9, CH_0119, CH_00EB, CH_011B, CH_00ED, CH_00EE, CH_010F,
+/* F0 */ CH_0111, CH_0144, CH_0148, CH_00F3, CH_00F4, CH_0151, CH_00F6, CH_00F7, CH_0159, CH_016F, CH_00FA, CH_0171, CH_00FC, CH_00FD, CH_0163, CH_02D9,
+/* CP852      00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 80 */ CH_00C7, CH_00FC, CH_00E9, CH_00E2, CH_00E4, CH_016F, CH_0107, CH_00E7, CH_0142, CH_00EB, CH_0150, CH_0151, CH_00EE, CH_0179, CH_00C4, CH_0106,
+/* 90 */ CH_00C9, CH_0139, CH_013A, CH_00F4, CH_00F6, CH_013D, CH_013E, CH_015A, CH_015B, CH_00D6, CH_00DC, CH_0164, CH_0165, CH_0141, CH_00D7, CH_010D,
+/* A0 */ CH_00E1, CH_00ED, CH_00F3, CH_00FA, CH_0104, CH_0105, CH_017D, CH_017E, CH_0118, CH_0119, CH_00AC, CH_017A, CH_010C, CH_015F, CH_00AB, CH_00BB,
+/* B0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_00C1, CH_00C2, CH_011A, CH_015E, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_017B, CH_017C, CH_UNKN,
+/* C0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_0102, CH_0103, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_00A4,
+/* D0 */ CH_0111, CH_0110, CH_010E, CH_00CB, CH_010F, CH_0147, CH_00CD, CH_00CE, CH_011B, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_0162, CH_016E, CH_UNKN,
+/* E0 */ CH_00D3, CH_00DF, CH_00D4, CH_0143, CH_0144, CH_0148, CH_0160, CH_0161, CH_0154, CH_00DA, CH_0155, CH_0170, CH_00FD, CH_00DD, CH_0163, CH_00B4,
+/* F0 */ CH_00AD, CH_02DD, CH_02DB, CH_02C7, CH_02D8, CH_00A7, CH_00F7, CH_00B8, CH_00B0, CH_00A8, CH_02D9, CH_0171, CH_0158, CH_0159, CH_UNKN, CH_00A0,
+};
+
+uint8_t const * const UNI_TABLE[0x02DE] = {
+/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 0000 */ CH_0000, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL,
+/* 0010 */ CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL,
+/* 0020 */ CH_0020, CH_0021, CH_0022, CH_0023, CH_0024, CH_0025, CH_0026, CH_0027, CH_0028, CH_0029, CH_002A, CH_002B, CH_002C, CH_002D, CH_002E, CH_002F,
+/* 0030 */ CH_0030, CH_0031, CH_0032, CH_0033, CH_0034, CH_0035, CH_0036, CH_0037, CH_0038, CH_0039, CH_003A, CH_003B, CH_003C, CH_003D, CH_003E, CH_003F,
+/* 0040 */ CH_0040, CH_0041, CH_0042, CH_0043, CH_0044, CH_0045, CH_0046, CH_0047, CH_0048, CH_0049, CH_004A, CH_004B, CH_004C, CH_004D, CH_004E, CH_004F,
+/* 0050 */ CH_0050, CH_0051, CH_0052, CH_0053, CH_0054, CH_0055, CH_0056, CH_0057, CH_0058, CH_0059, CH_005A, CH_005B, CH_005C, CH_005D, CH_005E, CH_005F,
+/* 0060 */ CH_0060, CH_0061, CH_0062, CH_0063, CH_0064, CH_0065, CH_0066, CH_0067, CH_0068, CH_0069, CH_006A, CH_006B, CH_006C, CH_006D, CH_006E, CH_006F,
+/* 0070 */ CH_0070, CH_0071, CH_0072, CH_0073, CH_0074, CH_0075, CH_0076, CH_0077, CH_0078, CH_0079, CH_007A, CH_007B, CH_007C, CH_007D, CH_007E, CH_NULL,
+/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 0080 */ CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL,
+/* 0090 */ CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL, CH_NULL,
+/* 00A0 */ CH_00A0, CH_00A1, CH_00A2, CH_00A3, CH_00A4, CH_00A5, CH_00A6, CH_00A7, CH_00A8, CH_00A9, CH_00AA, CH_00AB, CH_00AC, CH_00AD, CH_00AE, CH_00AF,
+/* 00B0 */ CH_00B0, CH_00B1, CH_00B2, CH_00B3, CH_00B4, CH_00B5, CH_00B6, CH_00B7, CH_00B8, CH_00B9, CH_00BA, CH_00BB, CH_00BC, CH_00BD, CH_00BE, CH_00BF,
+/* 00C0 */ CH_00C0, CH_00C1, CH_00C2, CH_00C3, CH_00C4, CH_00C5, CH_00C6, CH_00C7, CH_00C8, CH_00C9, CH_00CA, CH_00CB, CH_00CC, CH_00CD, CH_00CE, CH_00CF,
+/* 00D0 */ CH_00D0, CH_00D1, CH_00D2, CH_00D3, CH_00D4, CH_00D5, CH_00D6, CH_00D7, CH_00D8, CH_00D9, CH_00DA, CH_00DB, CH_00DC, CH_00DD, CH_00DE, CH_00DF,
+/* 00E0 */ CH_00E0, CH_00E1, CH_00E2, CH_00E3, CH_00E4, CH_00E5, CH_00E6, CH_00E7, CH_00E8, CH_00E9, CH_00EA, CH_00EB, CH_00EC, CH_00ED, CH_00EE, CH_00EF,
+/* 00F0 */ CH_00F0, CH_00F1, CH_00F2, CH_00F3, CH_00F4, CH_00F5, CH_00F6, CH_00F7, CH_00F8, CH_00F9, CH_00FA, CH_00FB, CH_00FC, CH_00FD, CH_00FE, CH_00FF,
+/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 0100 */ CH_0100, CH_0101, CH_0102, CH_0103, CH_0104, CH_0105, CH_0106, CH_0107, CH_0108, CH_0109, CH_010A, CH_010B, CH_010C, CH_010D, CH_010E, CH_010F,
+/* 0110 */ CH_0110, CH_0111, CH_0112, CH_0113, CH_0114, CH_0115, CH_0116, CH_0117, CH_0118, CH_0119, CH_011A, CH_011B, CH_011C, CH_011D, CH_011E, CH_011F,
+/* 0120 */ CH_0120, CH_0121, CH_0122, CH_0123, CH_0124, CH_0125, CH_0126, CH_0127, CH_0128, CH_0129, CH_012A, CH_012B, CH_012C, CH_012D, CH_012E, CH_012F,
+/* 0130 */ CH_0130, CH_0131, CH_0132, CH_0133, CH_0134, CH_0135, CH_0136, CH_0137, CH_0138, CH_0139, CH_013A, CH_013B, CH_013C, CH_013D, CH_013E, CH_013F,
+/* 0140 */ CH_0140, CH_0141, CH_0142, CH_0143, CH_0144, CH_0145, CH_0146, CH_0147, CH_0148, CH_UNKN, CH_014A, CH_014B, CH_014C, CH_014D, CH_014E, CH_014F,
+/* 0150 */ CH_0150, CH_0151, CH_0152, CH_0153, CH_0154, CH_0155, CH_0156, CH_0157, CH_0158, CH_0159, CH_015A, CH_015B, CH_015C, CH_015D, CH_015E, CH_015F,
+/* 0160 */ CH_0160, CH_0161, CH_0162, CH_0163, CH_0164, CH_0165, CH_0166, CH_0167, CH_0168, CH_0169, CH_016A, CH_016B, CH_016C, CH_016D, CH_016E, CH_016F,
+/* 0170 */ CH_0170, CH_0171, CH_0172, CH_0173, CH_0174, CH_0175, CH_0176, CH_0177, CH_0178, CH_0179, CH_017A, CH_017B, CH_017C, CH_017D, CH_017E, CH_UNKN,
+/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 0180 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0190 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 01A0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 01B0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 01C0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 01D0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 01E0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 01F0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 0200 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0210 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0220 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0230 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0240 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0250 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0260 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0270 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */
+/* 0280 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 0290 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 02A0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 02B0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 02C0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_02C7, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN,
+/* 02D0 */ CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_UNKN, CH_02D8, CH_02D9, CH_UNKN, CH_02DB, CH_UNKN, CH_02DD,
+};
+
+const uint8_t KEYBOARD_PATTERN[0x05EC] = {
+/* 0000 */
+       0,
+/* 0020: ' ' */
+/* 00A0: ' ' */
+       1,
+       KEY_SPACE,
+/* 0021: '!' */
+/* 00A1: '¡' */
+       1,
+       SKEY_EXCL,
+/* 0022: '"' */
+       1,
+       SKEY_QUOT,
+/* 0023: '#' */
+       2,
+       CODE_ALT,
+       XKEY_HASH,
+/* 0024: '$' */
+       2,
+       CODE_ALT,
+       XKEY_DOLLAR,
+/* 0025: '%' */
+       1,
+       SKEY_PERCENT,
+/* 0026: '&' */
+       1,
+       SKEY_AMP,
+/* 0027: ''' */
+       2,
+       CODE_ALT,
+       XKEY_QUOT,
+/* 0028: '(' */
+       1,
+       SKEY_LPAREN,
+/* 0029: ')' */
+       1,
+       SKEY_RPAREN,
+/* 002A: '*' */
+       2,
+       CODE_ALT,
+       XKEY_STAR,
+/* 002B: '+' */
+       1,
+       SKEY_PLUS,
+/* 002C: ',' */
+/* 00B8: '¸' */
+       1,
+       KEY_COMA,
+/* 002D: '-' */
+/* 00AD: '­' */
+       1,
+       KEY_MINUS,
+/* 002E: '.' */
+       1,
+       KEY_DOT,
+/* 002F: '/' */
+       1,
+       SKEY_SLASH,
+/* 0030: '0' */
+       1,
+       KEY_0,
+/* 0031: '1' */
+       1,
+       KEY_1,
+/* 0032: '2' */
+       1,
+       KEY_2,
+/* 0033: '3' */
+       1,
+       KEY_3,
+/* 0034: '4' */
+       1,
+       KEY_4,
+/* 0035: '5' */
+       1,
+       KEY_5,
+/* 0036: '6' */
+       1,
+       KEY_6,
+/* 0037: '7' */
+       1,
+       KEY_7,
+/* 0038: '8' */
+       1,
+       KEY_8,
+/* 0039: '9' */
+       1,
+       KEY_9,
+/* 003A: ':' */
+       1,
+       SKEY_COLON,
+/* 003B: ';' */
+       1,
+       SKEY_SEMI,
+/* 003C: '<' */
+       2,
+       CODE_ALT,
+       XKEY_LT,
+/* 003D: '=' */
+       1,
+       SKEY_EQ,
+/* 003E: '>' */
+       2,
+       CODE_ALT,
+       XKEY_GT,
+/* 003F: '?' */
+/* 00BF: '¿' */
+       1,
+       SKEY_QUEST,
+/* 0040: '@' */
+       17,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       SKEY_LPAREN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_A,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_RPAREN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+/* 0041: 'A' */
+       1,
+       SKEY_A,
+/* 0042: 'B' */
+       1,
+       SKEY_B,
+/* 0043: 'C' */
+       1,
+       SKEY_C,
+/* 0044: 'D' */
+       1,
+       SKEY_D,
+/* 0045: 'E' */
+       1,
+       SKEY_E,
+/* 0046: 'F' */
+       1,
+       SKEY_F,
+/* 0047: 'G' */
+       1,
+       SKEY_G,
+/* 0048: 'H' */
+       1,
+       SKEY_H,
+/* 0049: 'I' */
+       1,
+       SKEY_I,
+/* 004A: 'J' */
+       1,
+       SKEY_J,
+/* 004B: 'K' */
+/* 0138: 'ĸ' */
+       1,
+       SKEY_K,
+/* 004C: 'L' */
+       1,
+       SKEY_L,
+/* 004D: 'M' */
+       1,
+       SKEY_M,
+/* 004E: 'N' */
+       1,
+       SKEY_N,
+/* 004F: 'O' */
+       1,
+       SKEY_O,
+/* 0050: 'P' */
+       1,
+       SKEY_P,
+/* 0051: 'Q' */
+       1,
+       SKEY_Q,
+/* 0052: 'R' */
+       1,
+       SKEY_R,
+/* 0053: 'S' */
+       1,
+       SKEY_S,
+/* 0054: 'T' */
+       1,
+       SKEY_T,
+/* 0055: 'U' */
+       1,
+       SKEY_U,
+/* 0056: 'V' */
+       1,
+       SKEY_V,
+/* 0057: 'W' */
+       1,
+       SKEY_W,
+/* 0058: 'X' */
+       1,
+       SKEY_X,
+/* 0059: 'Y' */
+       1,
+       SKEY_Y,
+/* 005A: 'Z' */
+       1,
+       SKEY_Z,
+/* 005B: '[' */
+       9,
+       SKEY_LPAREN,
+       CODE_HALFUP,
+       KEY_BACK,
+       KEY_MINUS,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       CODE_HALFDOWN,
+       KEY_MINUS,
+       CODE_HALFUP,
+/* 005C: '\' */
+       14,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       SKEY_GRAVE,
+       KEY_SPACE,
+       CODE_HALFDOWN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_GRAVE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_HALFUP,
+/* 005D: ']' */
+       9,
+       SKEY_RPAREN,
+       CODE_HALFUP,
+       KEY_BACK,
+       KEY_MINUS,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       CODE_HALFDOWN,
+       KEY_MINUS,
+       CODE_HALFUP,
+/* 005E: '^' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+/* 005F: '_' */
+       1,
+       SKEY_UNDER,
+/* 0060: '`' */
+       2,
+       SKEY_GRAVE,
+       KEY_SPACE,
+/* 0061: 'a' */
+       1,
+       KEY_A,
+/* 0062: 'b' */
+       1,
+       KEY_B,
+/* 0063: 'c' */
+       1,
+       KEY_C,
+/* 0064: 'd' */
+       1,
+       KEY_D,
+/* 0065: 'e' */
+       1,
+       KEY_E,
+/* 0066: 'f' */
+       1,
+       KEY_F,
+/* 0067: 'g' */
+       1,
+       KEY_G,
+/* 0068: 'h' */
+       1,
+       KEY_H,
+/* 0069: 'i' */
+/* 0131: 'ı' */
+       1,
+       KEY_I,
+/* 006A: 'j' */
+       1,
+       KEY_J,
+/* 006B: 'k' */
+       1,
+       KEY_K,
+/* 006C: 'l' */
+       1,
+       KEY_L,
+/* 006D: 'm' */
+       1,
+       KEY_M,
+/* 006E: 'n' */
+       1,
+       KEY_N,
+/* 006F: 'o' */
+       1,
+       KEY_O,
+/* 0070: 'p' */
+       1,
+       KEY_P,
+/* 0071: 'q' */
+       1,
+       KEY_Q,
+/* 0072: 'r' */
+       1,
+       KEY_R,
+/* 0073: 's' */
+       1,
+       KEY_S,
+/* 0074: 't' */
+       1,
+       KEY_T,
+/* 0075: 'u' */
+       1,
+       KEY_U,
+/* 0076: 'v' */
+       1,
+       KEY_V,
+/* 0077: 'w' */
+       1,
+       KEY_W,
+/* 0078: 'x' */
+/* 00D7: '×' */
+       1,
+       KEY_X,
+/* 0079: 'y' */
+       1,
+       KEY_Y,
+/* 007A: 'z' */
+       1,
+       KEY_Z,
+/* 007B: '{' */
+       4,
+       SKEY_LPAREN,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_LT,
+/* 007C: '|' */
+/* 00A6: '¦' */
+       7,
+       CODE_ALT,
+       XKEY_QUOT,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       CODE_ALT,
+       XKEY_QUOT,
+       CODE_HALFUP,
+/* 007D: '}' */
+       4,
+       SKEY_RPAREN,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_GT,
+/* 007E: '~' */
+       12,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* 00A2: '¢' */
+       9,
+       KEY_C,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_QUOT,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       CODE_ALT,
+       XKEY_QUOT,
+       CODE_HALFUP,
+/* 00A3: '£' */
+       2,
+       CODE_ALT,
+       XKEY_POUND,
+/* 00A4: '¤' */
+       3,
+       KEY_O,
+       KEY_BACK,
+       KEY_X,
+/* 00A5: '¥' */
+       3,
+       SKEY_Y,
+       KEY_BACK,
+       SKEY_EQ,
+/* 00A7: '§' */
+       1,
+       SKEY_PARAG,
+/* 00A8: '¨' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       KEY_SPACE,
+/* 00A9: '©' */
+       17,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       SKEY_LPAREN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       SKEY_C,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_RPAREN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+/* 00AA: 'ª' */
+       5,
+       CODE_HALFUP,
+       KEY_A,
+       CODE_HALFDOWN,
+       KEY_BACK,
+       KEY_MINUS,
+/* 00AB: '«' */
+       11,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_ALT,
+       XKEY_LT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       KEY_MARGIN,
+       CODE_ALT,
+       XKEY_LT,
+       CODE_STEPLEFT,
+/* 00AC: '¬' */
+       12,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       CODE_ALT,
+       XKEY_QUOT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_HALFUP,
+/* 00AE: '®' */
+       17,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       SKEY_LPAREN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       SKEY_R,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_RPAREN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+/* 00AF: '¯' */
+       3,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 00B0: '°' */
+       2,
+       CODE_ALT,
+       XKEY_DEGREE,
+/* 00B1: '±' */
+       3,
+       SKEY_PLUS,
+       KEY_BACK,
+       SKEY_UNDER,
+/* 00B2: '²' */
+       3,
+       CODE_HALFUP,
+       KEY_2,
+       CODE_HALFDOWN,
+/* 00B3: '³' */
+       3,
+       CODE_HALFUP,
+       KEY_3,
+       CODE_HALFDOWN,
+/* 00B4: '´' */
+       2,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 00B5: 'µ' */
+       14,
+       KEY_U,
+       CODE_HALFDOWN,
+       KEY_BACK,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_ALT,
+       XKEY_QUOT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_SPACE,
+       CODE_HALFUP,
+/* 00B6: '¶' */
+       3,
+       SKEY_P,
+       KEY_BACK,
+       SKEY_I,
+/* 00B7: '·' */
+/* 02D9: '˙' */
+       3,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 00B9: '¹' */
+       3,
+       CODE_HALFUP,
+       KEY_1,
+       CODE_HALFDOWN,
+/* 00BA: 'º' */
+       4,
+       CODE_ALT,
+       XKEY_DEGREE,
+       KEY_BACK,
+       KEY_MINUS,
+/* 00BB: '»' */
+       12,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_ALT,
+       XKEY_GT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       CODE_ALT,
+       XKEY_GT,
+       CODE_STEPLEFT,
+/* 00BC: '¼' */
+       9,
+       CODE_HALFUP,
+       KEY_1,
+       CODE_HALFDOWN,
+       KEY_BACK,
+       KEY_MINUS,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       KEY_4,
+       CODE_HALFUP,
+/* 00BD: '½' */
+       9,
+       CODE_HALFUP,
+       KEY_1,
+       CODE_HALFDOWN,
+       KEY_BACK,
+       KEY_MINUS,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       KEY_2,
+       CODE_HALFUP,
+/* 00BE: '¾' */
+       9,
+       CODE_HALFUP,
+       KEY_3,
+       CODE_HALFDOWN,
+       KEY_BACK,
+       KEY_MINUS,
+       KEY_BACK,
+       CODE_HALFDOWN,
+       KEY_4,
+       CODE_HALFUP,
+/* 00C0: 'À' */
+       2,
+       SKEY_GRAVE,
+       SKEY_A,
+/* 00C1: 'Á' */
+       2,
+       KEY_ACUTE,
+       SKEY_A,
+/* 00C2: 'Â' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_A,
+/* 00C3: 'Ã' */
+/* 0100: 'Ā' */
+       5,
+       SKEY_A,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 00C4: 'Ä' */
+       1,
+       SKEY_AE,
+/* 00C5: 'Å' */
+       5,
+       SKEY_A,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 00C6: 'Æ' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       SKEY_A,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_E,
+       CODE_STEPLEFT,
+/* 00C7: 'Ç' */
+       3,
+       SKEY_C,
+       KEY_BACK,
+       KEY_COMA,
+/* 00C8: 'È' */
+       2,
+       SKEY_GRAVE,
+       SKEY_E,
+/* 00C9: 'É' */
+       2,
+       KEY_ACUTE,
+       SKEY_E,
+/* 00CA: 'Ê' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_E,
+/* 00CB: 'Ë' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       SKEY_E,
+/* 00CC: 'Ì' */
+       2,
+       SKEY_GRAVE,
+       SKEY_I,
+/* 00CD: 'Í' */
+       2,
+       KEY_ACUTE,
+       SKEY_I,
+/* 00CE: 'Î' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_I,
+/* 00CF: 'Ï' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       SKEY_I,
+/* 00D0: 'Ð' */
+/* 0110: 'Đ' */
+       9,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_MINUS,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       SKEY_D,
+/* 00D1: 'Ñ' */
+       5,
+       SKEY_N,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 00D2: 'Ò' */
+       2,
+       SKEY_GRAVE,
+       SKEY_O,
+/* 00D3: 'Ó' */
+       2,
+       KEY_ACUTE,
+       SKEY_O,
+/* 00D4: 'Ô' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_O,
+/* 00D5: 'Õ' */
+/* 014C: 'Ō' */
+       5,
+       SKEY_O,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 00D6: 'Ö' */
+       1,
+       SKEY_OE,
+/* 00D8: 'Ø' */
+       3,
+       SKEY_O,
+       KEY_BACK,
+       SKEY_SLASH,
+/* 00D9: 'Ù' */
+       2,
+       SKEY_GRAVE,
+       SKEY_U,
+/* 00DA: 'Ú' */
+       2,
+       KEY_ACUTE,
+       SKEY_U,
+/* 00DB: 'Û' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_U,
+/* 00DC: 'Ü' */
+       1,
+       SKEY_UE,
+/* 00DD: 'Ý' */
+       2,
+       KEY_ACUTE,
+       SKEY_Y,
+/* 00DE: 'Þ' */
+/* 00FE: 'þ' */
+       3,
+       KEY_P,
+       KEY_BACK,
+       KEY_B,
+/* 00DF: 'ß' */
+       1,
+       KEY_SS,
+/* 00E0: 'à' */
+       2,
+       SKEY_GRAVE,
+       KEY_A,
+/* 00E1: 'á' */
+       2,
+       KEY_ACUTE,
+       KEY_A,
+/* 00E2: 'â' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_A,
+/* 00E3: 'ã' */
+       14,
+       KEY_A,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* 00E4: 'ä' */
+       1,
+       KEY_AE,
+/* 00E5: 'å' */
+       4,
+       KEY_A,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_DEGREE,
+/* 00E6: 'æ' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_A,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_E,
+       CODE_STEPLEFT,
+/* 00E7: 'ç' */
+       3,
+       KEY_C,
+       KEY_BACK,
+       KEY_COMA,
+/* 00E8: 'è' */
+       2,
+       SKEY_GRAVE,
+       KEY_E,
+/* 00E9: 'é' */
+       2,
+       KEY_ACUTE,
+       KEY_E,
+/* 00EA: 'ê' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_E,
+/* 00EB: 'ë' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       KEY_E,
+/* 00EC: 'ì' */
+       2,
+       SKEY_GRAVE,
+       KEY_I,
+/* 00ED: 'í' */
+       2,
+       KEY_ACUTE,
+       KEY_I,
+/* 00EE: 'î' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_I,
+/* 00EF: 'ï' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       KEY_I,
+/* 00F0: 'ð' */
+/* 0111: 'đ' */
+       5,
+       KEY_D,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 00F1: 'ñ' */
+       14,
+       KEY_N,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* 00F2: 'ò' */
+       2,
+       SKEY_GRAVE,
+       KEY_O,
+/* 00F3: 'ó' */
+       2,
+       KEY_ACUTE,
+       KEY_O,
+/* 00F4: 'ô' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_O,
+/* 00F5: 'õ' */
+       14,
+       KEY_O,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* 00F6: 'ö' */
+       1,
+       KEY_OE,
+/* 00F7: '÷' */
+       3,
+       SKEY_COLON,
+       KEY_BACK,
+       KEY_MINUS,
+/* 00F8: 'ø' */
+       3,
+       KEY_O,
+       KEY_BACK,
+       SKEY_SLASH,
+/* 00F9: 'ù' */
+       2,
+       SKEY_GRAVE,
+       KEY_U,
+/* 00FA: 'ú' */
+       2,
+       KEY_ACUTE,
+       KEY_U,
+/* 00FB: 'û' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_U,
+/* 00FC: 'ü' */
+       1,
+       KEY_UE,
+/* 00FD: 'ý' */
+       2,
+       KEY_ACUTE,
+       KEY_Y,
+/* 00FF: 'ÿ' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       KEY_Y,
+/* 0101: 'ā' */
+       5,
+       KEY_A,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0102: 'Ă' */
+       5,
+       SKEY_GRAVE,
+       SKEY_A,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0103: 'ă' */
+       5,
+       SKEY_GRAVE,
+       KEY_A,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0104: 'Ą' */
+       9,
+       SKEY_A,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 0105: 'ą' */
+       9,
+       KEY_A,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 0106: 'Ć' */
+       2,
+       KEY_ACUTE,
+       SKEY_C,
+/* 0107: 'ć' */
+       2,
+       KEY_ACUTE,
+       KEY_C,
+/* 0108: 'Ĉ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_C,
+/* 0109: 'ĉ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_C,
+/* 010A: 'Ċ' */
+       5,
+       SKEY_C,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 010B: 'ċ' */
+       5,
+       KEY_C,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 010C: 'Č' */
+       5,
+       SKEY_GRAVE,
+       SKEY_C,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 010D: 'č' */
+       5,
+       SKEY_GRAVE,
+       KEY_C,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 010E: 'Ď' */
+       5,
+       SKEY_GRAVE,
+       SKEY_D,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 010F: 'ď' */
+       5,
+       SKEY_GRAVE,
+       KEY_D,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0112: 'Ē' */
+       5,
+       SKEY_E,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0113: 'ē' */
+       5,
+       KEY_E,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0114: 'Ĕ' */
+/* 011A: 'Ě' */
+       5,
+       SKEY_GRAVE,
+       SKEY_E,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0115: 'ĕ' */
+/* 011B: 'ě' */
+       5,
+       SKEY_GRAVE,
+       KEY_E,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0116: 'Ė' */
+       5,
+       SKEY_E,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0117: 'ė' */
+       5,
+       KEY_E,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0118: 'Ę' */
+       9,
+       SKEY_E,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 0119: 'ę' */
+       9,
+       KEY_E,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 011C: 'Ĝ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_G,
+/* 011D: 'ĝ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_G,
+/* 011E: 'Ğ' */
+       5,
+       SKEY_GRAVE,
+       SKEY_G,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 011F: 'ğ' */
+       5,
+       SKEY_GRAVE,
+       KEY_G,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0120: 'Ġ' */
+       5,
+       SKEY_G,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0121: 'ġ' */
+       5,
+       KEY_G,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0122: 'Ģ' */
+       3,
+       SKEY_G,
+       KEY_BACK,
+       KEY_COMA,
+/* 0123: 'ģ' */
+       3,
+       KEY_G,
+       KEY_BACK,
+       KEY_COMA,
+/* 0124: 'Ĥ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_H,
+/* 0125: 'ĥ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_H,
+/* 0126: 'Ħ' */
+       5,
+       SKEY_H,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0127: 'ħ' */
+       5,
+       KEY_H,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0128: 'Ĩ' */
+/* 012A: 'Ī' */
+       5,
+       SKEY_I,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0129: 'ĩ' */
+       14,
+       KEY_I,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* 012B: 'ī' */
+       5,
+       KEY_I,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 012C: 'Ĭ' */
+       5,
+       SKEY_GRAVE,
+       SKEY_I,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 012D: 'ĭ' */
+       5,
+       SKEY_GRAVE,
+       KEY_I,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 012E: 'Į' */
+       9,
+       SKEY_I,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 012F: 'į' */
+       9,
+       KEY_I,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 0130: 'İ' */
+       5,
+       SKEY_I,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0132: 'IJ' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       SKEY_I,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_J,
+       CODE_STEPLEFT,
+/* 0133: 'ij' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_I,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_J,
+       CODE_STEPLEFT,
+/* 0134: 'Ĵ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_J,
+/* 0135: 'ĵ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_J,
+/* 0136: 'Ķ' */
+       3,
+       SKEY_K,
+       KEY_BACK,
+       KEY_COMA,
+/* 0137: 'ķ' */
+       3,
+       KEY_K,
+       KEY_BACK,
+       KEY_COMA,
+/* 0139: 'Ĺ' */
+       2,
+       KEY_ACUTE,
+       SKEY_L,
+/* 013A: 'ĺ' */
+       2,
+       KEY_ACUTE,
+       KEY_L,
+/* 013B: 'Ļ' */
+       3,
+       SKEY_L,
+       KEY_BACK,
+       KEY_COMA,
+/* 013C: 'ļ' */
+       3,
+       KEY_L,
+       KEY_BACK,
+       KEY_COMA,
+/* 013D: 'Ľ' */
+       5,
+       SKEY_L,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_COMA,
+       CODE_HALFDOWN,
+/* 013E: 'ľ' */
+       11,
+       KEY_L,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       CODE_HALFUP,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_HALFDOWN,
+       CODE_STEPLEFT,
+/* 013F: 'Ŀ' */
+       5,
+       SKEY_L,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0140: 'ŀ' */
+       11,
+       KEY_L,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       CODE_HALFUP,
+       KEY_MARGIN,
+       KEY_DOT,
+       CODE_HALFDOWN,
+       CODE_STEPLEFT,
+/* 0141: 'Ł' */
+       3,
+       SKEY_L,
+       KEY_BACK,
+       KEY_MINUS,
+/* 0142: 'ł' */
+       3,
+       KEY_L,
+       KEY_BACK,
+       KEY_MINUS,
+/* 0143: 'Ń' */
+       2,
+       KEY_ACUTE,
+       SKEY_N,
+/* 0144: 'ń' */
+       2,
+       KEY_ACUTE,
+       KEY_N,
+/* 0145: 'Ņ' */
+       3,
+       SKEY_N,
+       KEY_BACK,
+       KEY_COMA,
+/* 0146: 'ņ' */
+       3,
+       KEY_N,
+       KEY_BACK,
+       KEY_COMA,
+/* 0147: 'Ň' */
+       5,
+       SKEY_GRAVE,
+       SKEY_N,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0148: 'ň' */
+       5,
+       SKEY_GRAVE,
+       KEY_N,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 014A: 'Ŋ' */
+       9,
+       SKEY_N,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 014B: 'ŋ' */
+       9,
+       KEY_N,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 014D: 'ō' */
+       5,
+       KEY_O,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 014E: 'Ŏ' */
+       5,
+       SKEY_GRAVE,
+       SKEY_O,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 014F: 'ŏ' */
+       5,
+       SKEY_GRAVE,
+       KEY_O,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0150: 'Ő' */
+       14,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       KEY_BACK,
+       SKEY_O,
+/* 0151: 'ő' */
+       14,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       KEY_BACK,
+       KEY_O,
+/* 0152: 'Œ' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       SKEY_O,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       SKEY_E,
+       CODE_STEPLEFT,
+/* 0153: 'œ' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_O,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_E,
+       CODE_STEPLEFT,
+/* 0154: 'Ŕ' */
+       2,
+       KEY_ACUTE,
+       SKEY_R,
+/* 0155: 'ŕ' */
+       2,
+       KEY_ACUTE,
+       KEY_R,
+/* 0156: 'Ŗ' */
+       3,
+       SKEY_R,
+       KEY_BACK,
+       KEY_COMA,
+/* 0157: 'ŗ' */
+       3,
+       KEY_R,
+       KEY_BACK,
+       KEY_COMA,
+/* 0158: 'Ř' */
+       5,
+       SKEY_GRAVE,
+       SKEY_R,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0159: 'ř' */
+       5,
+       SKEY_GRAVE,
+       KEY_R,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 015A: 'Ś' */
+       2,
+       KEY_ACUTE,
+       SKEY_S,
+/* 015B: 'ś' */
+       2,
+       KEY_ACUTE,
+       KEY_S,
+/* 015C: 'Ŝ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_S,
+/* 015D: 'ŝ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_S,
+/* 015E: 'Ş' */
+       3,
+       SKEY_S,
+       KEY_BACK,
+       KEY_COMA,
+/* 015F: 'ş' */
+       3,
+       KEY_S,
+       KEY_BACK,
+       KEY_COMA,
+/* 0160: 'Š' */
+       5,
+       SKEY_GRAVE,
+       SKEY_S,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0161: 'š' */
+       5,
+       SKEY_GRAVE,
+       KEY_S,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0162: 'Ţ' */
+       3,
+       SKEY_T,
+       KEY_BACK,
+       KEY_COMA,
+/* 0163: 'ţ' */
+       3,
+       KEY_T,
+       KEY_BACK,
+       KEY_COMA,
+/* 0164: 'Ť' */
+       5,
+       SKEY_GRAVE,
+       SKEY_T,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 0165: 'ť' */
+       11,
+       KEY_T,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       CODE_HALFUP,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_HALFDOWN,
+       CODE_STEPLEFT,
+/* 0166: 'Ŧ' */
+       3,
+       SKEY_T,
+       KEY_BACK,
+       KEY_MINUS,
+/* 0167: 'ŧ' */
+       3,
+       KEY_T,
+       KEY_BACK,
+       KEY_MINUS,
+/* 0168: 'Ũ' */
+/* 016A: 'Ū' */
+       5,
+       SKEY_U,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 0169: 'ũ' */
+       14,
+       KEY_U,
+       KEY_BACK,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* 016B: 'ū' */
+       5,
+       KEY_U,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_MINUS,
+       CODE_HALFDOWN,
+/* 016C: 'Ŭ' */
+       5,
+       SKEY_GRAVE,
+       SKEY_U,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 016D: 'ŭ' */
+       5,
+       SKEY_GRAVE,
+       KEY_U,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 016E: 'Ů' */
+       5,
+       SKEY_U,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 016F: 'ů' */
+       5,
+       KEY_U,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 0170: 'Ű' */
+       14,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       KEY_BACK,
+       SKEY_U,
+/* 0171: 'ű' */
+       14,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       KEY_BACK,
+       KEY_U,
+/* 0172: 'Ų' */
+       9,
+       SKEY_U,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 0173: 'ų' */
+       9,
+       KEY_U,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 0174: 'Ŵ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_W,
+/* 0175: 'ŵ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_W,
+/* 0176: 'Ŷ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       SKEY_Y,
+/* 0177: 'ŷ' */
+       3,
+       CODE_ALT,
+       XKEY_CARET,
+       KEY_Y,
+/* 0178: 'Ÿ' */
+       3,
+       CODE_ALT,
+       XKEY_UMLAUT,
+       SKEY_Y,
+/* 0179: 'Ź' */
+       10,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       SKEY_Z,
+/* 017A: 'ź' */
+       2,
+       KEY_ACUTE,
+       KEY_Z,
+/* 017B: 'Ż' */
+       3,
+       SKEY_Z,
+       KEY_BACK,
+       KEY_MINUS,
+/* 017C: 'ż' */
+       5,
+       KEY_Z,
+       KEY_BACK,
+       CODE_HALFUP,
+       KEY_DOT,
+       CODE_HALFDOWN,
+/* 017D: 'Ž' */
+       5,
+       SKEY_GRAVE,
+       SKEY_Z,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 017E: 'ž' */
+       5,
+       SKEY_GRAVE,
+       KEY_Z,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 02C7: 'ˇ' */
+/* 02D8: '˘' */
+       5,
+       SKEY_GRAVE,
+       KEY_SPACE,
+       KEY_BACK,
+       KEY_ACUTE,
+       KEY_SPACE,
+/* 02DB: '˛' */
+       9,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_COMA,
+       CODE_STEPLEFT,
+/* 02DD: '˝' */
+       12,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       KEY_ACUTE,
+       KEY_SPACE,
+       CODE_STEPLEFT,
+/* FFFD: '�' */
+       19,
+       KEY_MARGIN,
+       CODE_STEPLEFT,
+       CODE_ALT,
+       XKEY_LT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       SKEY_QUEST,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT,
+       CODE_STEPLEFT_EXTRA,
+       KEY_MARGIN,
+       CODE_ALT,
+       XKEY_GT,
+       CODE_STEPLEFT,
+};
+
+const uint8_t KEYMAP_ISO8859_1[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0xA3,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0xB4,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xA8,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0x00,
+       /* Ę */ [TCODE_E_] = 0x00,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0x00,
+       /* Ż */ [TCODE_Z_] = 0x00,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0x00,
+       /* Ą */ [TCODE_A_] = 0x00,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x00,
+       /* Ś */ [TCODE_S_] = 0x00,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x00,
+       /* Ś */ [TCODE_D_] = 0x00,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x00,
+       /* Ł */ [TCODE_L_] = 0x00,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x00,
+       /* Ź */ [TCODE_Y_] = 0x00,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x00,
+       /* Ć */ [TCODE_C_] = 0x00,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0x00,
+       /* Ń */ [TCODE_N_] = 0x00,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_2[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0x00,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0xB4,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xA8,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xEA,
+       /* Ę */ [TCODE_E_] = 0xCA,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0xBF,
+       /* Ż */ [TCODE_Z_] = 0xAF,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xB1,
+       /* Ą */ [TCODE_A_] = 0xA1,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0xB6,
+       /* Ś */ [TCODE_S_] = 0xA6,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0xB6,
+       /* Ś */ [TCODE_D_] = 0xA6,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0xB3,
+       /* Ł */ [TCODE_L_] = 0xA3,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0xBC,
+       /* Ź */ [TCODE_Y_] = 0xAC,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0xE6,
+       /* Ć */ [TCODE_C_] = 0xC6,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0xF1,
+       /* Ń */ [TCODE_N_] = 0xD1,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_3[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0xA3,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0xB4,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xA8,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0x00,
+       /* Ę */ [TCODE_E_] = 0x00,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0xBF,
+       /* Ż */ [TCODE_Z_] = 0xAF,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0x00,
+       /* Ą */ [TCODE_A_] = 0x00,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x00,
+       /* Ś */ [TCODE_S_] = 0x00,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x00,
+       /* Ś */ [TCODE_D_] = 0x00,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x00,
+       /* Ł */ [TCODE_L_] = 0x00,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x00,
+       /* Ź */ [TCODE_Y_] = 0x00,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x00,
+       /* Ć */ [TCODE_C_] = 0x00,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0x00,
+       /* Ń */ [TCODE_N_] = 0x00,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_4[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0x00,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0xB4,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xA8,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xEA,
+       /* Ę */ [TCODE_E_] = 0xCA,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0x00,
+       /* Ż */ [TCODE_Z_] = 0x00,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0x00,
+       /* Ó */ [TCODE_O_] = 0x00,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xB1,
+       /* Ą */ [TCODE_A_] = 0xA1,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x00,
+       /* Ś */ [TCODE_S_] = 0x00,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x00,
+       /* Ś */ [TCODE_D_] = 0x00,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x00,
+       /* Ł */ [TCODE_L_] = 0x00,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x00,
+       /* Ź */ [TCODE_Y_] = 0x00,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x00,
+       /* Ć */ [TCODE_C_] = 0x00,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0x00,
+       /* Ń */ [TCODE_N_] = 0x00,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_9[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0xA3,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0xB4,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xA8,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0x00,
+       /* Ę */ [TCODE_E_] = 0x00,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0x00,
+       /* Ż */ [TCODE_Z_] = 0x00,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0x00,
+       /* Ą */ [TCODE_A_] = 0x00,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x00,
+       /* Ś */ [TCODE_S_] = 0x00,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x00,
+       /* Ś */ [TCODE_D_] = 0x00,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x00,
+       /* Ł */ [TCODE_L_] = 0x00,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x00,
+       /* Ź */ [TCODE_Y_] = 0x00,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x00,
+       /* Ć */ [TCODE_C_] = 0x00,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0x00,
+       /* Ń */ [TCODE_N_] = 0x00,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_10[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0x00,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0x00,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0x00,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xEA,
+       /* Ę */ [TCODE_E_] = 0xCA,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0x00,
+       /* Ż */ [TCODE_Z_] = 0x00,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xB1,
+       /* Ą */ [TCODE_A_] = 0xA1,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x00,
+       /* Ś */ [TCODE_S_] = 0x00,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x00,
+       /* Ś */ [TCODE_D_] = 0x00,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x00,
+       /* Ł */ [TCODE_L_] = 0x00,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x00,
+       /* Ź */ [TCODE_Y_] = 0x00,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x00,
+       /* Ć */ [TCODE_C_] = 0x00,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0x00,
+       /* Ń */ [TCODE_N_] = 0x00,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_13[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0xA3,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0x00,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0x00,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xE6,
+       /* Ę */ [TCODE_E_] = 0xC6,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0xFD,
+       /* Ż */ [TCODE_Z_] = 0xDD,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xE0,
+       /* Ą */ [TCODE_A_] = 0xC0,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0xFA,
+       /* Ś */ [TCODE_S_] = 0xDA,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0xFA,
+       /* Ś */ [TCODE_D_] = 0xDA,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0xF9,
+       /* Ł */ [TCODE_L_] = 0xD9,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0xEA,
+       /* Ź */ [TCODE_Y_] = 0xCA,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0xE3,
+       /* Ć */ [TCODE_C_] = 0xC3,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0xF1,
+       /* Ń */ [TCODE_N_] = 0xD1,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_15[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0xA3,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0x00,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0x00,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0x00,
+       /* Ę */ [TCODE_E_] = 0x00,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0x00,
+       /* Ż */ [TCODE_Z_] = 0x00,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0x00,
+       /* Ą */ [TCODE_A_] = 0x00,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x00,
+       /* Ś */ [TCODE_S_] = 0x00,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x00,
+       /* Ś */ [TCODE_D_] = 0x00,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x00,
+       /* Ł */ [TCODE_L_] = 0x00,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x00,
+       /* Ź */ [TCODE_Y_] = 0x00,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x00,
+       /* Ć */ [TCODE_C_] = 0x00,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0x00,
+       /* Ń */ [TCODE_N_] = 0x00,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_ISO8859_16[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0x00,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0x00,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0x00,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xFD,
+       /* Ę */ [TCODE_E_] = 0xDD,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0xBF,
+       /* Ż */ [TCODE_Z_] = 0xAF,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xA2,
+       /* Ą */ [TCODE_A_] = 0xA1,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0xF7,
+       /* Ś */ [TCODE_S_] = 0xD7,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0xF7,
+       /* Ś */ [TCODE_D_] = 0xD7,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0xB3,
+       /* Ł */ [TCODE_L_] = 0xA3,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0xAE,
+       /* Ź */ [TCODE_Y_] = 0xAC,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0xE5,
+       /* Ć */ [TCODE_C_] = 0xC5,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0xF1,
+       /* Ń */ [TCODE_N_] = 0xD1,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_CP1250[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xA7,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xDF,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0x00,
+       /* ° */ [TCODE_DEGREE] = 0xB0,
+       /* ´ */ [KEY_ACUTE] = 0xB4,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xA8,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xEA,
+       /* Ę */ [TCODE_E_] = 0xCA,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0xBF,
+       /* Ż */ [TCODE_Z_] = 0xAF,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xF3,
+       /* Ó */ [TCODE_O_] = 0xD3,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0xFC,
+       /* Ü */ [SKEY_UE] = 0xDC,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xB9,
+       /* Ą */ [TCODE_A_] = 0xA5,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x9C,
+       /* Ś */ [TCODE_S_] = 0x8C,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x9C,
+       /* Ś */ [TCODE_D_] = 0x8C,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0xB3,
+       /* Ł */ [TCODE_L_] = 0xA3,
+       /* ö */ [KEY_OE] = 0xF6,
+       /* Ö */ [SKEY_OE] = 0xD6,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0xE4,
+       /* Ä */ [SKEY_AE] = 0xC4,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0x9F,
+       /* Ź */ [TCODE_Y_] = 0x8F,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0xE6,
+       /* Ć */ [TCODE_C_] = 0xC6,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0xF1,
+       /* Ń */ [TCODE_N_] = 0xD1,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint8_t KEYMAP_CP852[0x0100] = {
+       [0 ... 0xff] = 0x00,
+       /* @ */ [TKEY_AT] = 0x40,
+       /* ~ */ [TKEY_TILDE] = 0x7E,
+               [TCODE_ESC] = 0x1B,
+       /* 1 */ [KEY_1] = 0x31,
+       /* ! */ [SKEY_EXCL] = 0x21,
+       /* < */ [TCODE_LT] = 0x3C,
+       /* < */ [TCODE_LT_] = 0x3C,
+       /* 2 */ [KEY_2] = 0x32,
+       /* " */ [SKEY_QUOT] = 0x22,
+       /* > */ [TCODE_GT] = 0x3E,
+       /* > */ [TCODE_GT_] = 0x3E,
+       /* 3 */ [KEY_3] = 0x33,
+       /* § */ [SKEY_PARAG] = 0xF5,
+       /* ' */ [TCODE_QUOT] = 0x27,
+       /* ' */ [TCODE_QUOT_] = 0x27,
+       /* 4 */ [KEY_4] = 0x34,
+       /* + */ [SKEY_PLUS] = 0x2B,
+       /* 5 */ [KEY_5] = 0x35,
+       /* % */ [SKEY_PERCENT] = 0x25,
+       /* 6 */ [KEY_6] = 0x36,
+       /* & */ [SKEY_AMP] = 0x26,
+       /* 7 */ [KEY_7] = 0x37,
+       /* / */ [SKEY_SLASH] = 0x2F,
+       /* 8 */ [KEY_8] = 0x38,
+       /* ( */ [SKEY_LPAREN] = 0x28,
+       /* 9 */ [KEY_9] = 0x39,
+       /* ) */ [SKEY_RPAREN] = 0x29,
+       /* 0 */ [KEY_0] = 0x30,
+       /* = */ [SKEY_EQ] = 0x3D,
+       /* # */ [TCODE_HASH] = 0x23,
+       /* $ */ [TCODE_DOLLAR] = 0x24,
+       /* ß */ [KEY_SS] = 0xE1,
+       /* ? */ [SKEY_QUEST] = 0x3F,
+       /* £ */ [TCODE_POUND] = 0x00,
+       /* ° */ [TCODE_DEGREE] = 0xF8,
+       /* ´ */ [KEY_ACUTE] = 0xEF,
+       /* ` */ [SKEY_GRAVE] = 0x60,
+       /* ^ */ [TCODE_DASH] = 0x5E,
+       /* ¨ */ [TCODE_UMLAUT] = 0xF9,
+               [KEY_BACK] = 0x08,
+               [KEY_TAB] = 0x09,
+       /* q */ [KEY_Q] = 0x71,
+       /* Q */ [SKEY_Q] = 0x51,
+       /* w */ [KEY_W] = 0x77,
+       /* W */ [SKEY_W] = 0x57,
+       /* e */ [KEY_E] = 0x65,
+       /* E */ [SKEY_E] = 0x45,
+       /* ę */ [TCODE_E] = 0xA9,
+       /* Ę */ [TCODE_E_] = 0xA8,
+       /* r */ [KEY_R] = 0x72,
+       /* R */ [SKEY_R] = 0x52,
+       /* t */ [KEY_T] = 0x74,
+       /* T */ [SKEY_T] = 0x54,
+       /* z */ [KEY_Z] = 0x7A,
+       /* Z */ [SKEY_Z] = 0x5A,
+       /* ż */ [TCODE_Z] = 0xBE,
+       /* Ż */ [TCODE_Z_] = 0xBD,
+       /* u */ [KEY_U] = 0x75,
+       /* U */ [SKEY_U] = 0x55,
+       /* i */ [KEY_I] = 0x69,
+       /* I */ [SKEY_I] = 0x49,
+       /* o */ [KEY_O] = 0x6F,
+       /* O */ [SKEY_O] = 0x4F,
+       /* ó */ [TCODE_O] = 0xA2,
+       /* Ó */ [TCODE_O_] = 0xE0,
+       /* p */ [KEY_P] = 0x70,
+       /* P */ [SKEY_P] = 0x50,
+       /* ü */ [KEY_UE] = 0x81,
+       /* Ü */ [SKEY_UE] = 0x9A,
+       /* \ */ [TCODE_BSLASH] = 0x5C,
+       /* | */ [TCODE_WALL] = 0x7C,
+               [KEY_RETURN] = 0x0D,
+               [SKEY_RETURN] = 0x0D,
+       /* a */ [KEY_A] = 0x61,
+       /* A */ [SKEY_A] = 0x41,
+       /* ą */ [TCODE_A] = 0xA5,
+       /* Ą */ [TCODE_A_] = 0xA4,
+       /* s */ [KEY_S] = 0x73,
+       /* S */ [SKEY_S] = 0x53,
+       /* ś */ [TCODE_S] = 0x98,
+       /* Ś */ [TCODE_S_] = 0x97,
+       /* d */ [KEY_D] = 0x64,
+       /* D */ [SKEY_D] = 0x44,
+       /* ś */ [TCODE_D] = 0x98,
+       /* Ś */ [TCODE_D_] = 0x97,
+       /* f */ [KEY_F] = 0x66,
+       /* F */ [SKEY_F] = 0x46,
+       /* g */ [KEY_G] = 0x67,
+       /* G */ [SKEY_G] = 0x47,
+       /* h */ [KEY_H] = 0x68,
+       /* H */ [SKEY_H] = 0x48,
+       /* j */ [KEY_J] = 0x6A,
+       /* J */ [SKEY_J] = 0x4A,
+       /* k */ [KEY_K] = 0x6B,
+       /* K */ [SKEY_K] = 0x4B,
+       /* l */ [KEY_L] = 0x6C,
+       /* L */ [SKEY_L] = 0x4C,
+       /* ł */ [TCODE_L] = 0x88,
+       /* Ł */ [TCODE_L_] = 0x9D,
+       /* ö */ [KEY_OE] = 0x94,
+       /* Ö */ [SKEY_OE] = 0x99,
+       /* [ */ [TCODE_LSQBR] = 0x5B,
+       /* { */ [TCODE_LCURL] = 0x7B,
+       /* ä */ [KEY_AE] = 0x84,
+       /* Ä */ [SKEY_AE] = 0x8E,
+       /* ] */ [TCODE_RSQBR] = 0x5D,
+       /* } */ [TCODE_RCURL] = 0x7D,
+       /* y */ [KEY_Y] = 0x79,
+       /* Y */ [SKEY_Y] = 0x59,
+       /* ź */ [TCODE_Y] = 0xAB,
+       /* Ź */ [TCODE_Y_] = 0x8D,
+       /* x */ [KEY_X] = 0x78,
+       /* X */ [SKEY_X] = 0x58,
+       /* c */ [KEY_C] = 0x63,
+       /* C */ [SKEY_C] = 0x43,
+       /* ć */ [TCODE_C] = 0x86,
+       /* Ć */ [TCODE_C_] = 0x8F,
+       /* v */ [KEY_V] = 0x76,
+       /* V */ [SKEY_V] = 0x56,
+       /* b */ [KEY_B] = 0x62,
+       /* B */ [SKEY_B] = 0x42,
+       /* n */ [KEY_N] = 0x6E,
+       /* N */ [SKEY_N] = 0x4E,
+       /* ń */ [TCODE_N] = 0xE4,
+       /* Ń */ [TCODE_N_] = 0xE3,
+       /* m */ [KEY_M] = 0x6D,
+       /* M */ [SKEY_M] = 0x4D,
+       /* , */ [KEY_COMA] = 0x2C,
+       /* ; */ [SKEY_SEMI] = 0x3B,
+       /* . */ [KEY_DOT] = 0x2E,
+       /* : */ [SKEY_COLON] = 0x3A,
+       /* - */ [KEY_MINUS] = 0x2D,
+       /* _ */ [SKEY_UNDER] = 0x5F,
+       /* * */ [TCODE_STAR] = 0x2A,
+       /*   */ [KEY_SPACE] = 0x20,
+       /*   */ [SKEY_SPACE] = 0x20,
+               [KEY_ERASE1] = 0x7F,
+               [KEY_ERASEW] = 0x7F,
+};
+const uint16_t KEYMAP_UNI[0x0100] = {
+       [0 ... 0xff] = 0x0000,
+       /* @ */ [TKEY_AT] = 0x0040,
+       /* ~ */ [TKEY_TILDE] = 0x007E,
+               [TCODE_ESC] = 0x001B,
+       /* 1 */ [KEY_1] = 0x0031,
+       /* ! */ [SKEY_EXCL] = 0x0021,
+       /* < */ [TCODE_LT] = 0x003C,
+       /* < */ [TCODE_LT_] = 0x003C,
+       /* 2 */ [KEY_2] = 0x0032,
+       /* " */ [SKEY_QUOT] = 0x0022,
+       /* > */ [TCODE_GT] = 0x003E,
+       /* > */ [TCODE_GT_] = 0x003E,
+       /* 3 */ [KEY_3] = 0x0033,
+       /* § */ [SKEY_PARAG] = 0x00A7,
+       /* ' */ [TCODE_QUOT] = 0x0027,
+       /* ' */ [TCODE_QUOT_] = 0x0027,
+       /* 4 */ [KEY_4] = 0x0034,
+       /* + */ [SKEY_PLUS] = 0x002B,
+       /* 5 */ [KEY_5] = 0x0035,
+       /* % */ [SKEY_PERCENT] = 0x0025,
+       /* 6 */ [KEY_6] = 0x0036,
+       /* & */ [SKEY_AMP] = 0x0026,
+       /* 7 */ [KEY_7] = 0x0037,
+       /* / */ [SKEY_SLASH] = 0x002F,
+       /* 8 */ [KEY_8] = 0x0038,
+       /* ( */ [SKEY_LPAREN] = 0x0028,
+       /* 9 */ [KEY_9] = 0x0039,
+       /* ) */ [SKEY_RPAREN] = 0x0029,
+       /* 0 */ [KEY_0] = 0x0030,
+       /* = */ [SKEY_EQ] = 0x003D,
+       /* # */ [TCODE_HASH] = 0x0023,
+       /* $ */ [TCODE_DOLLAR] = 0x0024,
+       /* ß */ [KEY_SS] = 0x00DF,
+       /* ? */ [SKEY_QUEST] = 0x003F,
+       /* £ */ [TCODE_POUND] = 0x00A3,
+       /* ° */ [TCODE_DEGREE] = 0x00B0,
+       /* ´ */ [KEY_ACUTE] = 0x00B4,
+       /* ` */ [SKEY_GRAVE] = 0x0060,
+       /* ^ */ [TCODE_DASH] = 0x005E,
+       /* ¨ */ [TCODE_UMLAUT] = 0x00A8,
+               [KEY_BACK] = 0x0008,
+               [KEY_TAB] = 0x0009,
+       /* q */ [KEY_Q] = 0x0071,
+       /* Q */ [SKEY_Q] = 0x0051,
+       /* w */ [KEY_W] = 0x0077,
+       /* W */ [SKEY_W] = 0x0057,
+       /* e */ [KEY_E] = 0x0065,
+       /* E */ [SKEY_E] = 0x0045,
+       /* ę */ [TCODE_E] = 0x0119,
+       /* Ę */ [TCODE_E_] = 0x0118,
+       /* r */ [KEY_R] = 0x0072,
+       /* R */ [SKEY_R] = 0x0052,
+       /* t */ [KEY_T] = 0x0074,
+       /* T */ [SKEY_T] = 0x0054,
+       /* z */ [KEY_Z] = 0x007A,
+       /* Z */ [SKEY_Z] = 0x005A,
+       /* ż */ [TCODE_Z] = 0x017C,
+       /* Ż */ [TCODE_Z_] = 0x017B,
+       /* u */ [KEY_U] = 0x0075,
+       /* U */ [SKEY_U] = 0x0055,
+       /* i */ [KEY_I] = 0x0069,
+       /* I */ [SKEY_I] = 0x0049,
+       /* o */ [KEY_O] = 0x006F,
+       /* O */ [SKEY_O] = 0x004F,
+       /* ó */ [TCODE_O] = 0x00F3,
+       /* Ó */ [TCODE_O_] = 0x00D3,
+       /* p */ [KEY_P] = 0x0070,
+       /* P */ [SKEY_P] = 0x0050,
+       /* ü */ [KEY_UE] = 0x00FC,
+       /* Ü */ [SKEY_UE] = 0x00DC,
+       /* \ */ [TCODE_BSLASH] = 0x005C,
+       /* | */ [TCODE_WALL] = 0x007C,
+               [KEY_RETURN] = 0x000D,
+               [SKEY_RETURN] = 0x000D,
+       /* a */ [KEY_A] = 0x0061,
+       /* A */ [SKEY_A] = 0x0041,
+       /* ą */ [TCODE_A] = 0x0105,
+       /* Ą */ [TCODE_A_] = 0x0104,
+       /* s */ [KEY_S] = 0x0073,
+       /* S */ [SKEY_S] = 0x0053,
+       /* ś */ [TCODE_S] = 0x015B,
+       /* Ś */ [TCODE_S_] = 0x015A,
+       /* d */ [KEY_D] = 0x0064,
+       /* D */ [SKEY_D] = 0x0044,
+       /* ś */ [TCODE_D] = 0x015B,
+       /* Ś */ [TCODE_D_] = 0x015A,
+       /* f */ [KEY_F] = 0x0066,
+       /* F */ [SKEY_F] = 0x0046,
+       /* g */ [KEY_G] = 0x0067,
+       /* G */ [SKEY_G] = 0x0047,
+       /* h */ [KEY_H] = 0x0068,
+       /* H */ [SKEY_H] = 0x0048,
+       /* j */ [KEY_J] = 0x006A,
+       /* J */ [SKEY_J] = 0x004A,
+       /* k */ [KEY_K] = 0x006B,
+       /* K */ [SKEY_K] = 0x004B,
+       /* l */ [KEY_L] = 0x006C,
+       /* L */ [SKEY_L] = 0x004C,
+       /* ł */ [TCODE_L] = 0x0142,
+       /* Ł */ [TCODE_L_] = 0x0141,
+       /* ö */ [KEY_OE] = 0x00F6,
+       /* Ö */ [SKEY_OE] = 0x00D6,
+       /* [ */ [TCODE_LSQBR] = 0x005B,
+       /* { */ [TCODE_LCURL] = 0x007B,
+       /* ä */ [KEY_AE] = 0x00E4,
+       /* Ä */ [SKEY_AE] = 0x00C4,
+       /* ] */ [TCODE_RSQBR] = 0x005D,
+       /* } */ [TCODE_RCURL] = 0x007D,
+       /* y */ [KEY_Y] = 0x0079,
+       /* Y */ [SKEY_Y] = 0x0059,
+       /* ź */ [TCODE_Y] = 0x017A,
+       /* Ź */ [TCODE_Y_] = 0x0179,
+       /* x */ [KEY_X] = 0x0078,
+       /* X */ [SKEY_X] = 0x0058,
+       /* c */ [KEY_C] = 0x0063,
+       /* C */ [SKEY_C] = 0x0043,
+       /* ć */ [TCODE_C] = 0x0107,
+       /* Ć */ [TCODE_C_] = 0x0106,
+       /* v */ [KEY_V] = 0x0076,
+       /* V */ [SKEY_V] = 0x0056,
+       /* b */ [KEY_B] = 0x0062,
+       /* B */ [SKEY_B] = 0x0042,
+       /* n */ [KEY_N] = 0x006E,
+       /* N */ [SKEY_N] = 0x004E,
+       /* ń */ [TCODE_N] = 0x0144,
+       /* Ń */ [TCODE_N_] = 0x0143,
+       /* m */ [KEY_M] = 0x006D,
+       /* M */ [SKEY_M] = 0x004D,
+       /* , */ [KEY_COMA] = 0x002C,
+       /* ; */ [SKEY_SEMI] = 0x003B,
+       /* . */ [KEY_DOT] = 0x002E,
+       /* : */ [SKEY_COLON] = 0x003A,
+       /* - */ [KEY_MINUS] = 0x002D,
+       /* _ */ [SKEY_UNDER] = 0x005F,
+       /* * */ [TCODE_STAR] = 0x002A,
+       /*   */ [KEY_SPACE] = 0x0020,
+       /*   */ [SKEY_SPACE] = 0x0020,
+               [KEY_ERASE1] = 0x007F,
+               [KEY_ERASEW] = 0x007F,
+};
diff --git a/keyboard-patterns.h b/keyboard-patterns.h
new file mode 100644 (file)
index 0000000..38a0940
--- /dev/null
@@ -0,0 +1,380 @@
+/* file autogenerated from keyboard-patterns.txt. do not edit - will be overwritten */
+
+#include <stdint.h>
+#include "keyboard.h"
+
+extern const uint8_t ENC_C1[0x0B];
+extern uint8_t const * const CH_TABLE[0x0600];
+extern uint8_t const * const UNI_TABLE[0x02DE];
+extern const uint8_t KEYBOARD_PATTERN[0x05EC];
+extern const uint8_t KEYMAP_ISO8859_1[0x0100];
+extern const uint8_t KEYMAP_ISO8859_2[0x0100];
+extern const uint8_t KEYMAP_ISO8859_3[0x0100];
+extern const uint8_t KEYMAP_ISO8859_4[0x0100];
+extern const uint8_t KEYMAP_ISO8859_9[0x0100];
+extern const uint8_t KEYMAP_ISO8859_10[0x0100];
+extern const uint8_t KEYMAP_ISO8859_13[0x0100];
+extern const uint8_t KEYMAP_ISO8859_15[0x0100];
+extern const uint8_t KEYMAP_ISO8859_16[0x0100];
+extern const uint8_t KEYMAP_CP1250[0x0100];
+extern const uint8_t KEYMAP_CP852[0x0100];
+extern const uint16_t KEYMAP_UNI[0x0100];
+extern uint8_t const * const * const CH_LIST[0x0B];
+extern uint8_t const * const KEYMAP_LIST[0x0B];
+
+#define ENC_ISO8859_1 0x00
+#define ENC_ISO8859_2 0x01
+#define ENC_ISO8859_3 0x02
+#define ENC_ISO8859_4 0x03
+#define ENC_ISO8859_9 0x04
+#define ENC_ISO8859_10 0x05
+#define ENC_ISO8859_13 0x06
+#define ENC_ISO8859_15 0x07
+#define ENC_ISO8859_16 0x08
+#define ENC_CP1250 0x09
+#define ENC_CP852 0x0A
+#define N_ENC 0x0B
+#define ENC_UNI 0x80
+
+#define CH_ASCII CH_TABLE
+#define CH_ISO8859_1 ((uint8_t const * const *)(&(CH_TABLE[0x0000])))
+#define CH_ISO8859_2 ((uint8_t const * const *)(&(CH_TABLE[0x0080])))
+#define CH_ISO8859_3 ((uint8_t const * const *)(&(CH_TABLE[0x0100])))
+#define CH_ISO8859_4 ((uint8_t const * const *)(&(CH_TABLE[0x0180])))
+#define CH_ISO8859_9 ((uint8_t const * const *)(&(CH_TABLE[0x0200])))
+#define CH_ISO8859_10 ((uint8_t const * const *)(&(CH_TABLE[0x0280])))
+#define CH_ISO8859_13 ((uint8_t const * const *)(&(CH_TABLE[0x0300])))
+#define CH_ISO8859_15 ((uint8_t const * const *)(&(CH_TABLE[0x0380])))
+#define CH_ISO8859_16 ((uint8_t const * const *)(&(CH_TABLE[0x0400])))
+#define CH_CP1250 ((uint8_t const * const *)(&(CH_TABLE[0x0480])))
+#define CH_CP852 ((uint8_t const * const *)(&(CH_TABLE[0x0500])))
+
+#define CH_LIMIT 0x2DE
+
+#define CH_0000 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0000])))
+#define CH_0020 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0001]))) /*   */
+#define CH_0021 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0003]))) /* ! */
+#define CH_0022 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0005]))) /* " */
+#define CH_0023 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0007]))) /* # */
+#define CH_0024 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x000A]))) /* $ */
+#define CH_0025 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x000D]))) /* % */
+#define CH_0026 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x000F]))) /* & */
+#define CH_0027 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0011]))) /* ' */
+#define CH_0028 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0014]))) /* ( */
+#define CH_0029 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0016]))) /* ) */
+#define CH_002A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0018]))) /* * */
+#define CH_002B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x001B]))) /* + */
+#define CH_002C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x001D]))) /* , */
+#define CH_002D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x001F]))) /* - */
+#define CH_002E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0021]))) /* . */
+#define CH_002F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0023]))) /* / */
+#define CH_0030 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0025]))) /* 0 */
+#define CH_0031 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0027]))) /* 1 */
+#define CH_0032 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0029]))) /* 2 */
+#define CH_0033 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x002B]))) /* 3 */
+#define CH_0034 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x002D]))) /* 4 */
+#define CH_0035 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x002F]))) /* 5 */
+#define CH_0036 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0031]))) /* 6 */
+#define CH_0037 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0033]))) /* 7 */
+#define CH_0038 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0035]))) /* 8 */
+#define CH_0039 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0037]))) /* 9 */
+#define CH_003A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0039]))) /* : */
+#define CH_003B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x003B]))) /* ; */
+#define CH_003C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x003D]))) /* < */
+#define CH_003D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0040]))) /* = */
+#define CH_003E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0042]))) /* > */
+#define CH_003F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0045]))) /* ? */
+#define CH_0040 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0047]))) /* @ */
+#define CH_0041 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0059]))) /* A */
+#define CH_0042 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x005B]))) /* B */
+#define CH_0043 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x005D]))) /* C */
+#define CH_0044 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x005F]))) /* D */
+#define CH_0045 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0061]))) /* E */
+#define CH_0046 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0063]))) /* F */
+#define CH_0047 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0065]))) /* G */
+#define CH_0048 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0067]))) /* H */
+#define CH_0049 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0069]))) /* I */
+#define CH_004A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x006B]))) /* J */
+#define CH_004B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x006D]))) /* K */
+#define CH_004C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x006F]))) /* L */
+#define CH_004D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0071]))) /* M */
+#define CH_004E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0073]))) /* N */
+#define CH_004F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0075]))) /* O */
+#define CH_0050 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0077]))) /* P */
+#define CH_0051 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0079]))) /* Q */
+#define CH_0052 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x007B]))) /* R */
+#define CH_0053 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x007D]))) /* S */
+#define CH_0054 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x007F]))) /* T */
+#define CH_0055 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0081]))) /* U */
+#define CH_0056 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0083]))) /* V */
+#define CH_0057 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0085]))) /* W */
+#define CH_0058 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0087]))) /* X */
+#define CH_0059 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0089]))) /* Y */
+#define CH_005A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x008B]))) /* Z */
+#define CH_005B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x008D]))) /* [ */
+#define CH_005C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0097]))) /* \ */
+#define CH_005D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00A6]))) /* ] */
+#define CH_005E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00B0]))) /* ^ */
+#define CH_005F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00B4]))) /* _ */
+#define CH_0060 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00B6]))) /* ` */
+#define CH_0061 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00B9]))) /* a */
+#define CH_0062 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00BB]))) /* b */
+#define CH_0063 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00BD]))) /* c */
+#define CH_0064 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00BF]))) /* d */
+#define CH_0065 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00C1]))) /* e */
+#define CH_0066 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00C3]))) /* f */
+#define CH_0067 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00C5]))) /* g */
+#define CH_0068 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00C7]))) /* h */
+#define CH_0069 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00C9]))) /* i */
+#define CH_006A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00CB]))) /* j */
+#define CH_006B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00CD]))) /* k */
+#define CH_006C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00CF]))) /* l */
+#define CH_006D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00D1]))) /* m */
+#define CH_006E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00D3]))) /* n */
+#define CH_006F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00D5]))) /* o */
+#define CH_0070 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00D7]))) /* p */
+#define CH_0071 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00D9]))) /* q */
+#define CH_0072 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00DB]))) /* r */
+#define CH_0073 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00DD]))) /* s */
+#define CH_0074 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00DF]))) /* t */
+#define CH_0075 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00E1]))) /* u */
+#define CH_0076 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00E3]))) /* v */
+#define CH_0077 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00E5]))) /* w */
+#define CH_0078 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00E7]))) /* x */
+#define CH_0079 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00E9]))) /* y */
+#define CH_007A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00EB]))) /* z */
+#define CH_007B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00ED]))) /* { */
+#define CH_007C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00F2]))) /* | */
+#define CH_007D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00FA]))) /* } */
+#define CH_007E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00FF]))) /* ~ */
+#define CH_00A0 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0001]))) /*   */
+#define CH_00A1 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0003]))) /* ¡ */
+#define CH_00A2 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x010C]))) /* ¢ */
+#define CH_00A3 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0116]))) /* £ */
+#define CH_00A4 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0119]))) /* ¤ */
+#define CH_00A5 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x011D]))) /* ¥ */
+#define CH_00A6 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00F2]))) /* ¦ */
+#define CH_00A7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0121]))) /* § */
+#define CH_00A8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0123]))) /* ¨ */
+#define CH_00A9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0127]))) /* © */
+#define CH_00AA ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0139]))) /* ª */
+#define CH_00AB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x013F]))) /* « */
+#define CH_00AC ((uint8_t const *) (&(KEYBOARD_PATTERN[0x014B]))) /* ¬ */
+#define CH_00AD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x001F]))) /* ­ */
+#define CH_00AE ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0158]))) /* ® */
+#define CH_00AF ((uint8_t const *) (&(KEYBOARD_PATTERN[0x016A]))) /* ¯ */
+#define CH_00B0 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x016E]))) /* ° */
+#define CH_00B1 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0171]))) /* ± */
+#define CH_00B2 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0175]))) /* ² */
+#define CH_00B3 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0179]))) /* ³ */
+#define CH_00B4 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x017D]))) /* ´ */
+#define CH_00B5 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0180]))) /* µ */
+#define CH_00B6 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x018F]))) /* ¶ */
+#define CH_00B7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0193]))) /* · */
+#define CH_00B8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x001D]))) /* ¸ */
+#define CH_00B9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0197]))) /* ¹ */
+#define CH_00BA ((uint8_t const *) (&(KEYBOARD_PATTERN[0x019B]))) /* º */
+#define CH_00BB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01A0]))) /* » */
+#define CH_00BC ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01AD]))) /* ¼ */
+#define CH_00BD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01B7]))) /* ½ */
+#define CH_00BE ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01C1]))) /* ¾ */
+#define CH_00BF ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0045]))) /* ¿ */
+#define CH_00C0 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01CB]))) /* À */
+#define CH_00C1 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01CE]))) /* Á */
+#define CH_00C2 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01D1]))) /* Â */
+#define CH_00C3 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01D5]))) /* Ã */
+#define CH_00C4 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01DB]))) /* Ä */
+#define CH_00C5 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01DD]))) /* Å */
+#define CH_00C6 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01E3]))) /* Æ */
+#define CH_00C7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01EE]))) /* Ç */
+#define CH_00C8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01F2]))) /* È */
+#define CH_00C9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01F5]))) /* É */
+#define CH_00CA ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01F8]))) /* Ê */
+#define CH_00CB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01FC]))) /* Ë */
+#define CH_00CC ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0200]))) /* Ì */
+#define CH_00CD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0203]))) /* Í */
+#define CH_00CE ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0206]))) /* Î */
+#define CH_00CF ((uint8_t const *) (&(KEYBOARD_PATTERN[0x020A]))) /* Ï */
+#define CH_00D0 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x020E]))) /* Ð */
+#define CH_00D1 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0218]))) /* Ñ */
+#define CH_00D2 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x021E]))) /* Ò */
+#define CH_00D3 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0221]))) /* Ó */
+#define CH_00D4 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0224]))) /* Ô */
+#define CH_00D5 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0228]))) /* Õ */
+#define CH_00D6 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x022E]))) /* Ö */
+#define CH_00D7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00E7]))) /* × */
+#define CH_00D8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0230]))) /* Ø */
+#define CH_00D9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0234]))) /* Ù */
+#define CH_00DA ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0237]))) /* Ú */
+#define CH_00DB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x023A]))) /* Û */
+#define CH_00DC ((uint8_t const *) (&(KEYBOARD_PATTERN[0x023E]))) /* Ü */
+#define CH_00DD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0240]))) /* Ý */
+#define CH_00DE ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0243]))) /* Þ */
+#define CH_00DF ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0247]))) /* ß */
+#define CH_00E0 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0249]))) /* à */
+#define CH_00E1 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x024C]))) /* á */
+#define CH_00E2 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x024F]))) /* â */
+#define CH_00E3 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0253]))) /* ã */
+#define CH_00E4 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0262]))) /* ä */
+#define CH_00E5 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0264]))) /* å */
+#define CH_00E6 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0269]))) /* æ */
+#define CH_00E7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0274]))) /* ç */
+#define CH_00E8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0278]))) /* è */
+#define CH_00E9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x027B]))) /* é */
+#define CH_00EA ((uint8_t const *) (&(KEYBOARD_PATTERN[0x027E]))) /* ê */
+#define CH_00EB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0282]))) /* ë */
+#define CH_00EC ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0286]))) /* ì */
+#define CH_00ED ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0289]))) /* í */
+#define CH_00EE ((uint8_t const *) (&(KEYBOARD_PATTERN[0x028C]))) /* î */
+#define CH_00EF ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0290]))) /* ï */
+#define CH_00F0 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0294]))) /* ð */
+#define CH_00F1 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x029A]))) /* ñ */
+#define CH_00F2 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02A9]))) /* ò */
+#define CH_00F3 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02AC]))) /* ó */
+#define CH_00F4 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02AF]))) /* ô */
+#define CH_00F5 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02B3]))) /* õ */
+#define CH_00F6 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02C2]))) /* ö */
+#define CH_00F7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02C4]))) /* ÷ */
+#define CH_00F8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02C8]))) /* ø */
+#define CH_00F9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02CC]))) /* ù */
+#define CH_00FA ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02CF]))) /* ú */
+#define CH_00FB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02D2]))) /* û */
+#define CH_00FC ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02D6]))) /* ü */
+#define CH_00FD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02D8]))) /* ý */
+#define CH_00FE ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0243]))) /* þ */
+#define CH_00FF ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02DB]))) /* ÿ */
+#define CH_0100 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x01D5]))) /* Ā */
+#define CH_0101 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02DF]))) /* ā */
+#define CH_0102 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02E5]))) /* Ă */
+#define CH_0103 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02EB]))) /* ă */
+#define CH_0104 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02F1]))) /* Ą */
+#define CH_0105 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x02FB]))) /* ą */
+#define CH_0106 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0305]))) /* Ć */
+#define CH_0107 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0308]))) /* ć */
+#define CH_0108 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x030B]))) /* Ĉ */
+#define CH_0109 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x030F]))) /* ĉ */
+#define CH_010A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0313]))) /* Ċ */
+#define CH_010B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0319]))) /* ċ */
+#define CH_010C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x031F]))) /* Č */
+#define CH_010D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0325]))) /* č */
+#define CH_010E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x032B]))) /* Ď */
+#define CH_010F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0331]))) /* ď */
+#define CH_0110 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x020E]))) /* Đ */
+#define CH_0111 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0294]))) /* đ */
+#define CH_0112 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0337]))) /* Ē */
+#define CH_0113 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x033D]))) /* ē */
+#define CH_0114 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0343]))) /* Ĕ */
+#define CH_0115 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0349]))) /* ĕ */
+#define CH_0116 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x034F]))) /* Ė */
+#define CH_0117 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0355]))) /* ė */
+#define CH_0118 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x035B]))) /* Ę */
+#define CH_0119 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0365]))) /* ę */
+#define CH_011A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0343]))) /* Ě */
+#define CH_011B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0349]))) /* ě */
+#define CH_011C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x036F]))) /* Ĝ */
+#define CH_011D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0373]))) /* ĝ */
+#define CH_011E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0377]))) /* Ğ */
+#define CH_011F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x037D]))) /* ğ */
+#define CH_0120 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0383]))) /* Ġ */
+#define CH_0121 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0389]))) /* ġ */
+#define CH_0122 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x038F]))) /* Ģ */
+#define CH_0123 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0393]))) /* ģ */
+#define CH_0124 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0397]))) /* Ĥ */
+#define CH_0125 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x039B]))) /* ĥ */
+#define CH_0126 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x039F]))) /* Ħ */
+#define CH_0127 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03A5]))) /* ħ */
+#define CH_0128 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03AB]))) /* Ĩ */
+#define CH_0129 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03B1]))) /* ĩ */
+#define CH_012A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03AB]))) /* Ī */
+#define CH_012B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03C0]))) /* ī */
+#define CH_012C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03C6]))) /* Ĭ */
+#define CH_012D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03CC]))) /* ĭ */
+#define CH_012E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03D2]))) /* Į */
+#define CH_012F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03DC]))) /* į */
+#define CH_0130 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03E6]))) /* İ */
+#define CH_0131 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x00C9]))) /* ı */
+#define CH_0132 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03EC]))) /* IJ */
+#define CH_0133 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x03F7]))) /* ij */
+#define CH_0134 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0402]))) /* Ĵ */
+#define CH_0135 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0406]))) /* ĵ */
+#define CH_0136 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x040A]))) /* Ķ */
+#define CH_0137 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x040E]))) /* ķ */
+#define CH_0138 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x006D]))) /* ĸ */
+#define CH_0139 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0412]))) /* Ĺ */
+#define CH_013A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0415]))) /* ĺ */
+#define CH_013B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0418]))) /* Ļ */
+#define CH_013C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x041C]))) /* ļ */
+#define CH_013D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0420]))) /* Ľ */
+#define CH_013E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0426]))) /* ľ */
+#define CH_013F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0432]))) /* Ŀ */
+#define CH_0140 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0438]))) /* ŀ */
+#define CH_0141 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0444]))) /* Ł */
+#define CH_0142 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0448]))) /* ł */
+#define CH_0143 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x044C]))) /* Ń */
+#define CH_0144 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x044F]))) /* ń */
+#define CH_0145 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0452]))) /* Ņ */
+#define CH_0146 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0456]))) /* ņ */
+#define CH_0147 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x045A]))) /* Ň */
+#define CH_0148 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0460]))) /* ň */
+#define CH_014A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0466]))) /* Ŋ */
+#define CH_014B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0470]))) /* ŋ */
+#define CH_014C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0228]))) /* Ō */
+#define CH_014D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x047A]))) /* ō */
+#define CH_014E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0480]))) /* Ŏ */
+#define CH_014F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0486]))) /* ŏ */
+#define CH_0150 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x048C]))) /* Ő */
+#define CH_0151 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x049B]))) /* ő */
+#define CH_0152 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04AA]))) /* Œ */
+#define CH_0153 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04B5]))) /* œ */
+#define CH_0154 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04C0]))) /* Ŕ */
+#define CH_0155 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04C3]))) /* ŕ */
+#define CH_0156 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04C6]))) /* Ŗ */
+#define CH_0157 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04CA]))) /* ŗ */
+#define CH_0158 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04CE]))) /* Ř */
+#define CH_0159 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04D4]))) /* ř */
+#define CH_015A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04DA]))) /* Ś */
+#define CH_015B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04DD]))) /* ś */
+#define CH_015C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04E0]))) /* Ŝ */
+#define CH_015D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04E4]))) /* ŝ */
+#define CH_015E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04E8]))) /* Ş */
+#define CH_015F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04EC]))) /* ş */
+#define CH_0160 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04F0]))) /* Š */
+#define CH_0161 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04F6]))) /* š */
+#define CH_0162 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x04FC]))) /* Ţ */
+#define CH_0163 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0500]))) /* ţ */
+#define CH_0164 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0504]))) /* Ť */
+#define CH_0165 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x050A]))) /* ť */
+#define CH_0166 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0516]))) /* Ŧ */
+#define CH_0167 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x051A]))) /* ŧ */
+#define CH_0168 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x051E]))) /* Ũ */
+#define CH_0169 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0524]))) /* ũ */
+#define CH_016A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x051E]))) /* Ū */
+#define CH_016B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0533]))) /* ū */
+#define CH_016C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0539]))) /* Ŭ */
+#define CH_016D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x053F]))) /* ŭ */
+#define CH_016E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0545]))) /* Ů */
+#define CH_016F ((uint8_t const *) (&(KEYBOARD_PATTERN[0x054B]))) /* ů */
+#define CH_0170 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0551]))) /* Ű */
+#define CH_0171 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0560]))) /* ű */
+#define CH_0172 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x056F]))) /* Ų */
+#define CH_0173 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0579]))) /* ų */
+#define CH_0174 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0583]))) /* Ŵ */
+#define CH_0175 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0587]))) /* ŵ */
+#define CH_0176 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x058B]))) /* Ŷ */
+#define CH_0177 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x058F]))) /* ŷ */
+#define CH_0178 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0593]))) /* Ÿ */
+#define CH_0179 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0597]))) /* Ź */
+#define CH_017A ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05A2]))) /* ź */
+#define CH_017B ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05A5]))) /* Ż */
+#define CH_017C ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05A9]))) /* ż */
+#define CH_017D ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05AF]))) /* Ž */
+#define CH_017E ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05B5]))) /* ž */
+#define CH_02C7 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05BB]))) /* ˇ */
+#define CH_02D8 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05BB]))) /* ˘ */
+#define CH_02D9 ((uint8_t const *) (&(KEYBOARD_PATTERN[0x0193]))) /* ˙ */
+#define CH_02DB ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05C1]))) /* ˛ */
+#define CH_02DD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05CB]))) /* ˝ */
+#define CH_FFFD ((uint8_t const *) (&(KEYBOARD_PATTERN[0x05D8]))) /* � */
+
+#define CH_NULL CH_0000
+#define CH_UNKN CH_FFFD
diff --git a/keyboard-patterns.py b/keyboard-patterns.py
new file mode 100755 (executable)
index 0000000..012b33f
--- /dev/null
@@ -0,0 +1,254 @@
+#!/usr/bin/python3
+
+import sys
+import re
+
+KEYB_DEF = 'keyboard.h'
+REPLACEMENT = 0xFFFD
+
+mode = ''
+encodings = ['ascii']
+sequences = {}
+ch = 0
+sequence = []
+offsets = {}
+reverse_offsets={}
+max_ch = 0
+total_pattern=[]
+encodings_upper = ['ASCII']
+key = ''
+keyvalue = -1
+keymap = {}
+
+def add_sequence():
+    global ch, max_ch, sequence
+    global offsets, reverse_offsets, sequences
+    global total_pattern
+    global key, keyvalue, keymap
+    
+    if len(sequence) != 0:
+        if (ch > max_ch) and (ch != REPLACEMENT):
+            max_ch = ch
+        for c in sequences:
+            if sequence == sequences[c]:
+                offsets[ch] = offsets[c]
+                reverse_offsets[offsets[c]].append(ch)
+                sequence = []
+                return
+        sequences[ch] = sequence
+        offsets[ch] = len(total_pattern)
+        reverse_offsets[offsets[ch]] = [ch]
+        total_pattern.append(str(len(sequence)))
+        for p in sequence:
+            total_pattern.append(p)
+        sequence = []
+    
+    if keyvalue >= 0:
+        keymap[key] = keyvalue
+        keyvalue = -1
+
+sequences[0]=[]
+offsets[0]=0
+reverse_offsets[0]=[0]
+total_pattern.append('0')
+
+l = len(sys.argv)
+if l>=4:
+    file_in = sys.argv[1]
+    file_h = sys.argv[2]
+    file_c = sys.argv[3]
+else:
+    print('missing arguments.', file=sys.stderr)
+
+with open(file_in, 'rt', encoding='utf-8') as file:
+    for line in file:
+        i = line.find('#')
+        if i >= 0:
+            line = line[0:i]
+        line = line.strip()
+        
+        m = re.search('^([A-Za-z0-9_]+):$', line)
+        if m:
+            add_sequence()
+            t = m.group(1)
+            if t == 'encoding':
+                mode = 'encoding'
+            elif re.search('^[0-9A-Fa-f]+$', t):
+                mode = 'sequence'
+                ch = int(t, 16)
+                sequence = []
+            elif re.search('^[0-9A-Z_]+$', t):
+                mode = 'key'
+                key = t
+                keyvalue = -1
+            else:
+                mode = ''
+        elif line != '':
+            if mode == 'encoding':
+                encodings.append(line)
+                encodings_upper.append(line.upper().replace('-', '_'))
+            elif mode == 'sequence':
+                sequence.append(line)
+            elif mode == 'key':
+                if re.search('^([0-9A-Fa-f]){2,4}$', line):
+                    keyvalue = int(line, 16)
+                elif len(line) == 1:
+                    keyvalue = ord(line)
+
+add_sequence()
+max_ch += 1
+B = [bytes([i]) for i in range (0x0, 0x100)]
+
+with open(file_h, 'wt', encoding='utf-8') as file:
+    print('/* file autogenerated from ' + file_in + '. do not edit - will be overwritten */', file=file)
+    print('', file=file)
+    print('#include <stdint.h>', file=file)
+    print('#include "'+KEYB_DEF+'"', file=file)
+    print('', file=file)
+    print('extern const uint8_t ENC_C1[0x%02X];' % (len(encodings)-1), file=file)
+    print('extern uint8_t const * const CH_TABLE[0x%04X];' % (len(encodings)*0x80), file=file)
+    print('extern uint8_t const * const UNI_TABLE[0x%04X];' % max_ch, file=file)
+    print(('extern const uint8_t KEYBOARD_PATTERN[0x%04X];' % len(total_pattern)), file=file)
+    for i, enc in enumerate(encodings):
+        if enc == 'ascii':
+            continue
+        print('extern const uint8_t KEYMAP_' + encodings_upper[i] + '[0x0100];', file=file)
+    print('extern const uint16_t KEYMAP_UNI[0x0100];', file=file)
+    print('extern uint8_t const * const * const CH_LIST[0x%02X];' % (len(encodings)-1), file=file)
+    print('extern uint8_t const * const KEYMAP_LIST[0x%02X];' % (len(encodings)-1), file=file)
+
+
+    print('', file=file)
+    
+    for i, enc in enumerate(encodings):
+        if enc == 'ascii':
+            continue
+        print('#define ENC_' + encodings_upper[i] + (' 0x%02X' % (i - 1)), file=file)
+    print('#define N_ENC 0x%02X' % (len(encodings)-1), file=file)
+    print('#define ENC_UNI 0x80', file=file)
+    print('', file=file)
+    
+    for i, enc in enumerate(encodings):
+        if i==0:
+            print ('#define CH_' + encodings_upper[i] + ' CH_TABLE', file=file)
+        else:
+            print ('#define CH_' + encodings_upper[i] + ' ((uint8_t const * const *)(&(CH_TABLE[0x%04X])))' % ((i-1) * 0x80), file=file) 
+    
+    print('', file=file)
+    print('#define CH_LIMIT 0x%02X' % (max_ch), file=file)
+    print('', file=file)
+    
+    for off in sorted(offsets):
+        print(('#define CH_%04X ((uint8_t const *) (&(KEYBOARD_PATTERN[0x%04X])))' % (off, offsets[off])) + ((' /* ' + chr(off) + ' */') if ((off >= 0x20) and not  (0x7f <= off <= 0x9f)) else ''), file=file)
+    
+    print('', file=file)
+    print('#define CH_NULL CH_0000', file=file)
+    print('#define CH_UNKN CH_%04X' % REPLACEMENT, file=file)
+
+with open(file_c, 'wt', encoding='utf-8') as file:
+    print('/* file autogenerated from ' + file_in + '. do not edit - will be overwritten */', file=file)
+    print('#include <stdint.h>', file=file)
+    print('#include "'+KEYB_DEF+'"', file=file)
+    print('#include "'+file_h+'"', file=file)
+    
+    print('', file=file)
+    
+    print('const uint8_t ENC_C1[0x%02X] = {' % (len(encodings)-1), file=file)
+    for enc in encodings:
+        if enc == 'ascii':
+            continue
+        print ('\t%d,' % int ('iso8859-' in enc), file=file)
+    print('};', file=file)
+    print('', file=file)
+    
+    print('uint8_t const * const * const CH_LIST[0x%02X] = {' % (len(encodings)-1), file=file)
+    for i, enc in enumerate(encodings):
+        if enc == 'ascii':
+            continue
+        print('\tCH_' + encodings_upper[i] + ',', file=file)
+    print('};', file=file)
+    print('', file=file)
+    
+    print('uint8_t const * const KEYMAP_LIST[0x%02X] = {' % (len(encodings)-1), file=file)
+    for i, enc in enumerate(encodings):
+        if enc == 'ascii':
+            continue
+        print('\tKEYMAP_' + encodings_upper[i] + ',', file=file)
+    print('};', file=file)
+    print('', file=file)
+    
+    print ('uint8_t const * const CH_TABLE[0x%04X] = {' % (len(encodings)*0x80), file=file)
+    for n, enc in enumerate(encodings):
+        enc_text = encodings_upper[n]
+        if len(enc_text) > 10:
+            enc_text = enc_text[0:10]
+        else:
+            enc_text += ' ' * (10 - len(enc_text))
+        print('/* ' + enc_text + ' 00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */', file=file)
+        for i in (range(0, 0x80, 0x10) if enc == 'ascii' else range(0x80, 0x100, 0x10)):
+            line = '/* %02X */' % i
+            for j in range(0, 0x10, 1):
+                c = i+j
+                t = B[c].decode(enc, errors='ignore')
+                if t == '':
+                    line += ' CH_UNKN,'
+                else:
+                    c = ord(t)
+                    if c in offsets:
+                        line += ' CH_%04X,' % c
+                    else:
+                        if (c < 0x20): #or (0x7f <= c <= 0x9f):
+                            line += ' CH_NULL,'
+                        else:
+                            line += ' CH_UNKN,'
+            print(line, file=file)
+    print('};', file=file)
+    print('', file=file)
+    print ('uint8_t const * const UNI_TABLE[0x%04X] = {' % max_ch, file=file)
+    for i in range(0, max_ch, 0x10):
+        if i & 0x7f == 0:
+            print('/*              00       01       02       03       04       05       06       07       08       09       0A       0B       0C       0D       0E       0F */', file=file)
+        line =  '/* %04X */' % i
+        for c in range (i, min(max_ch, i+0x10), 1):
+            if c in offsets:
+                line += ' CH_%04X,' % c
+            else:
+                if (c < 0x20) or (0x7f <= c <= 0x9f):
+                    line += ' CH_NULL,'
+                else:
+                    line += ' CH_UNKN,'
+        print(line, file=file)
+    print('};', file=file)
+    
+    print('', file=file)
+    
+    print(('const uint8_t KEYBOARD_PATTERN[0x%04X] = {' % len(total_pattern)), file=file)
+    for i, line in enumerate(total_pattern):
+        if i in reverse_offsets:
+            for c in reverse_offsets[i]:
+                print(('/* %04X' % c) + ((": '" + chr(c) + "'") if ((c >= 0x20) and not  (0x7f <= c <= 0x9f)) else '') + ' */', file=file)
+        print('\t' + line + ',', file=file)
+    print('};', file=file)
+    
+    print('', file=file)
+    
+    for n, enc in enumerate(encodings):
+        if enc == 'ascii':
+            continue
+        print('const uint8_t KEYMAP_' + encodings_upper[n] + '[0x0100] = {', file=file)
+        print('\t[0 ... 0xff] = 0x00,', file=file)
+        for k in keymap:
+            c = keymap[k]
+            ch = chr(c)
+            ck = ch.encode(enc, errors='ignore')
+            ci = int.from_bytes(ck, 'little')
+            print ('\t' + (('/* ' + ch + ' */ ') if ((c >= 0x20) and not  (0x7f <= c <= 0x9f)) else '        ') + '[' + k + ('] = 0x%02X,' % ci), file=file)
+        print('};', file=file)
+    print('const uint16_t KEYMAP_UNI[0x0100] = {', file=file)
+    print('\t[0 ... 0xff] = 0x0000,', file=file)
+    for k in keymap:
+        c = keymap[k]
+        ch = chr(c)
+        print ('\t' + (('/* ' + ch + ' */ ') if ((c >= 0x20) and not  (0x7f <= c <= 0x9f)) else '        ') + '[' + k + ('] = 0x%04X,' % c), file=file)
+    print('};', file=file)
+    
\ No newline at end of file
diff --git a/keyboard-patterns.txt b/keyboard-patterns.txt
new file mode 100644 (file)
index 0000000..7dd2349
--- /dev/null
@@ -0,0 +1,1979 @@
+encoding:
+       iso8859-1
+       iso8859-2
+       iso8859-3
+       iso8859-4
+       iso8859-9
+       iso8859-10
+       iso8859-13
+       iso8859-15
+       iso8859-16
+       cp1250
+       cp852
+
+0020: # ' '
+       KEY_SPACE
+0021: # '!'
+       SKEY_EXCL
+0022: # '"'
+       SKEY_QUOT
+0023: # '#'
+       CODE_ALT
+       XKEY_HASH
+0024: # '$'
+       CODE_ALT
+       XKEY_DOLLAR
+0025: # '%'
+       SKEY_PERCENT
+0026: # '&'
+       SKEY_AMP
+0027: # '''
+       CODE_ALT
+       XKEY_QUOT
+0028: # '('
+       SKEY_LPAREN
+0029: # ')'
+       SKEY_RPAREN
+002A: # '*'
+       CODE_ALT
+       XKEY_STAR
+002B: # '+'
+       SKEY_PLUS
+002C: # ','
+       KEY_COMA
+002D: # '-'
+       KEY_MINUS
+002E: # '.'
+       KEY_DOT
+002F: # '/'
+       SKEY_SLASH
+0030: # '0'
+       KEY_0
+0031: # '1'
+       KEY_1
+0032: # '2'
+       KEY_2
+0033: # '3'
+       KEY_3
+0034: # '4'
+       KEY_4
+0035: # '5'
+       KEY_5
+0036: # '6'
+       KEY_6
+0037: # '7'
+       KEY_7
+0038: # '8'
+       KEY_8
+0039: # '9'
+       KEY_9
+003A: # ':'
+       SKEY_COLON
+003B: # ';'
+       SKEY_SEMI
+003C: # '<'
+       CODE_ALT
+       XKEY_LT
+003D: # '='
+       SKEY_EQ
+003E: # '>'
+       CODE_ALT
+       XKEY_GT
+003F: # '?'
+       SKEY_QUEST
+0040: # '@'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       SKEY_LPAREN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_A
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_RPAREN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+0041: # 'A'
+       SKEY_A
+0042: # 'B'
+       SKEY_B
+0043: # 'C'
+       SKEY_C
+0044: # 'D'
+       SKEY_D
+0045: # 'E'
+       SKEY_E
+0046: # 'F'
+       SKEY_F
+0047: # 'G'
+       SKEY_G
+0048: # 'H'
+       SKEY_H
+0049: # 'I'
+       SKEY_I
+004A: # 'J'
+       SKEY_J
+004B: # 'K'
+       SKEY_K
+004C: # 'L'
+       SKEY_L
+004D: # 'M'
+       SKEY_M
+004E: # 'N'
+       SKEY_N
+004F: # 'O'
+       SKEY_O
+0050: # 'P'
+       SKEY_P
+0051: # 'Q'
+       SKEY_Q
+0052: # 'R'
+       SKEY_R
+0053: # 'S'
+       SKEY_S
+0054: # 'T'
+       SKEY_T
+0055: # 'U'
+       SKEY_U
+0056: # 'V'
+       SKEY_V
+0057: # 'W'
+       SKEY_W
+0058: # 'X'
+       SKEY_X
+0059: # 'Y'
+       SKEY_Y
+005A: # 'Z'
+       SKEY_Z
+005B: # '['
+       SKEY_LPAREN
+       CODE_HALFUP
+       KEY_BACK
+       KEY_MINUS
+       KEY_BACK
+       CODE_HALFDOWN
+       CODE_HALFDOWN
+       KEY_MINUS
+       CODE_HALFUP
+005C: # '\'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       SKEY_GRAVE
+       KEY_SPACE
+       CODE_HALFDOWN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_GRAVE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_HALFUP
+005D: # ']'
+       SKEY_RPAREN
+       CODE_HALFUP
+       KEY_BACK
+       KEY_MINUS
+       KEY_BACK
+       CODE_HALFDOWN
+       CODE_HALFDOWN
+       KEY_MINUS
+       CODE_HALFUP
+005E: # '^'
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+005F: # '_'
+       SKEY_UNDER
+0060: # '`'
+       SKEY_GRAVE
+       KEY_SPACE
+0061: # 'a'
+       KEY_A
+0062: # 'b'
+       KEY_B
+0063: # 'c'
+       KEY_C
+0064: # 'd'
+       KEY_D
+0065: # 'e'
+       KEY_E
+0066: # 'f'
+       KEY_F
+0067: # 'g'
+       KEY_G
+0068: # 'h'
+       KEY_H
+0069: # 'i'
+       KEY_I
+006A: # 'j'
+       KEY_J
+006B: # 'k'
+       KEY_K
+006C: # 'l'
+       KEY_L
+006D: # 'm'
+       KEY_M
+006E: # 'n'
+       KEY_N
+006F: # 'o'
+       KEY_O
+0070: # 'p'
+       KEY_P
+0071: # 'q'
+       KEY_Q
+0072: # 'r'
+       KEY_R
+0073: # 's'
+       KEY_S
+0074: # 't'
+       KEY_T
+0075: # 'u'
+       KEY_U
+0076: # 'v'
+       KEY_V
+0077: # 'w'
+       KEY_W
+0078: # 'x'
+       KEY_X
+0079: # 'y'
+       KEY_Y
+007A: # 'z'
+       KEY_Z
+007B: # '{'
+       SKEY_LPAREN
+       KEY_BACK
+       CODE_ALT
+       XKEY_LT
+007C: # '|'
+       CODE_ALT
+       XKEY_QUOT
+       KEY_BACK
+       CODE_HALFDOWN
+       CODE_ALT
+       XKEY_QUOT
+       CODE_HALFUP
+007D: # '}'
+       SKEY_RPAREN
+       KEY_BACK
+       CODE_ALT
+       XKEY_GT
+007E: # '~'
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+007F:
+0080:
+0081:
+0082:
+0083:
+0084:
+0085:
+0086:
+0087:
+0088:
+0089:
+008A:
+008B:
+008C:
+008D:
+008E:
+008F:
+0090:
+0091:
+0092:
+0093:
+0094:
+0095:
+0096:
+0097:
+0098:
+0099:
+009A:
+009B:
+009C:
+009D:
+009E:
+009F:
+00A0: # ' '
+       KEY_SPACE
+00A1: # '¡'
+       SKEY_EXCL
+00A2: # '¢'
+       KEY_C
+       KEY_BACK
+       CODE_ALT
+       XKEY_QUOT
+       KEY_BACK
+       CODE_HALFDOWN
+       CODE_ALT
+       XKEY_QUOT
+       CODE_HALFUP
+00A3: # '£'
+       CODE_ALT
+       XKEY_POUND
+00A4: # '¤'
+       KEY_O
+       KEY_BACK
+       KEY_X
+00A5: # '¥'
+       SKEY_Y
+       KEY_BACK
+       SKEY_EQ
+00A6: # '¦'
+       CODE_ALT
+       XKEY_QUOT
+       KEY_BACK
+       CODE_HALFDOWN
+       CODE_ALT
+       XKEY_QUOT
+       CODE_HALFUP
+00A7: # '§'
+       SKEY_PARAG
+00A8: # '¨'
+       CODE_ALT
+       XKEY_UMLAUT
+       KEY_SPACE
+00A9: # '©'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       SKEY_LPAREN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       SKEY_C
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_RPAREN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+00AA: # 'ª'
+       CODE_HALFUP
+       KEY_A
+       CODE_HALFDOWN
+       KEY_BACK
+       KEY_MINUS
+00AB: # '«'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_ALT
+       XKEY_LT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       KEY_MARGIN
+       CODE_ALT
+       XKEY_LT
+       CODE_STEPLEFT
+00AC: # '¬'
+       KEY_MINUS
+       CODE_HALFDOWN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       CODE_ALT
+       XKEY_QUOT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_HALFUP
+00AD: # '­'
+       KEY_MINUS
+00AE: # '®'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       SKEY_LPAREN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       SKEY_R
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_RPAREN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+00AF: # '¯'
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+00B0: # '°'
+       CODE_ALT
+       XKEY_DEGREE
+00B1: # '±'
+       SKEY_PLUS
+       KEY_BACK
+       SKEY_UNDER
+00B2: # '²'
+       CODE_HALFUP
+       KEY_2
+       CODE_HALFDOWN
+00B3: # '³'
+       CODE_HALFUP
+       KEY_3
+       CODE_HALFDOWN
+00B4: # '´'
+       KEY_ACUTE
+       KEY_SPACE
+00B5: # 'µ'
+       KEY_U
+       CODE_HALFDOWN
+       KEY_BACK
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_ALT
+       XKEY_QUOT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_SPACE
+       CODE_HALFUP
+00B6: # '¶'
+       SKEY_P
+       KEY_BACK
+       SKEY_I
+00B7: # '·'
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+00B8: # '¸'
+       KEY_COMA
+00B9: # '¹'
+       CODE_HALFUP
+       KEY_1
+       CODE_HALFDOWN
+00BA: # 'º'
+       CODE_ALT
+       XKEY_DEGREE
+       KEY_BACK
+       KEY_MINUS
+00BB: # '»'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_ALT
+       XKEY_GT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       CODE_ALT
+       XKEY_GT
+       CODE_STEPLEFT
+00BC: # '¼'
+       CODE_HALFUP
+       KEY_1
+       CODE_HALFDOWN
+       KEY_BACK
+       KEY_MINUS
+       KEY_BACK
+       CODE_HALFDOWN
+       KEY_4
+       CODE_HALFUP
+00BD: # '½'
+       CODE_HALFUP
+       KEY_1
+       CODE_HALFDOWN
+       KEY_BACK
+       KEY_MINUS
+       KEY_BACK
+       CODE_HALFDOWN
+       KEY_2
+       CODE_HALFUP
+00BE: # '¾'
+       CODE_HALFUP
+       KEY_3
+       CODE_HALFDOWN
+       KEY_BACK
+       KEY_MINUS
+       KEY_BACK
+       CODE_HALFDOWN
+       KEY_4
+       CODE_HALFUP
+00BF: # '¿'
+       SKEY_QUEST
+00C0: # 'À'
+       SKEY_GRAVE
+       SKEY_A
+00C1: # 'Á'
+       KEY_ACUTE
+       SKEY_A
+00C2: # 'Â'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_A
+00C3: # 'Ã'
+       SKEY_A
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+00C4: # 'Ä'
+       SKEY_AE
+00C5: # 'Å'
+       SKEY_A
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+00C6: # 'Æ'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       SKEY_A
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_E
+       CODE_STEPLEFT
+00C7: # 'Ç'
+       SKEY_C
+       KEY_BACK
+       KEY_COMA
+00C8: # 'È'
+       SKEY_GRAVE
+       SKEY_E
+00C9: # 'É'
+       KEY_ACUTE
+       SKEY_E
+00CA: # 'Ê'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_E
+00CB: # 'Ë'
+       CODE_ALT
+       XKEY_UMLAUT
+       SKEY_E
+00CC: # 'Ì'
+       SKEY_GRAVE
+       SKEY_I
+00CD: # 'Í'
+       KEY_ACUTE
+       SKEY_I
+00CE: # 'Î'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_I
+00CF: # 'Ï'
+       CODE_ALT
+       XKEY_UMLAUT
+       SKEY_I
+00D0: # 'Ð'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_MINUS
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       SKEY_D
+00D1: # 'Ñ'
+       SKEY_N
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+00D2: # 'Ò'
+       SKEY_GRAVE
+       SKEY_O
+00D3: # 'Ó'
+       KEY_ACUTE
+       SKEY_O
+00D4: # 'Ô'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_O
+00D5: # 'Õ'
+       SKEY_O
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+00D6: # 'Ö'
+       SKEY_OE
+00D7: # '×'
+       KEY_X
+00D8: # 'Ø'
+       SKEY_O
+       KEY_BACK
+       SKEY_SLASH
+00D9: # 'Ù'
+       SKEY_GRAVE
+       SKEY_U
+00DA: # 'Ú'
+       KEY_ACUTE
+       SKEY_U
+00DB: # 'Û'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_U
+00DC: # 'Ü'
+       SKEY_UE
+00DD: # 'Ý'
+       KEY_ACUTE
+       SKEY_Y
+00DE: # 'Þ'
+       KEY_P
+       KEY_BACK
+       KEY_B
+00DF: # 'ß'
+       KEY_SS
+00E0: # 'à'
+       SKEY_GRAVE
+       KEY_A
+00E1: # 'á'
+       KEY_ACUTE
+       KEY_A
+00E2: # 'â'
+       CODE_ALT
+       XKEY_CARET
+       KEY_A
+00E3: # 'ã'
+       KEY_A
+       KEY_BACK
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+00E4: # 'ä'
+       KEY_AE
+00E5: # 'å'
+       KEY_A
+       KEY_BACK
+       CODE_ALT
+       XKEY_DEGREE
+00E6: # 'æ'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_A
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_E
+       CODE_STEPLEFT
+00E7: # 'ç'
+       KEY_C
+       KEY_BACK
+       KEY_COMA
+00E8: # 'è'
+       SKEY_GRAVE
+       KEY_E
+00E9: # 'é'
+       KEY_ACUTE
+       KEY_E
+00EA: # 'ê'
+       CODE_ALT
+       XKEY_CARET
+       KEY_E
+00EB: # 'ë'
+       CODE_ALT
+       XKEY_UMLAUT
+       KEY_E
+00EC: # 'ì'
+       SKEY_GRAVE
+       KEY_I
+00ED: # 'í'
+       KEY_ACUTE
+       KEY_I
+00EE: # 'î'
+       CODE_ALT
+       XKEY_CARET
+       KEY_I
+00EF: # 'ï'
+       CODE_ALT
+       XKEY_UMLAUT
+       KEY_I
+00F0: # 'ð'
+       KEY_D
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+00F1: # 'ñ'
+       KEY_N
+       KEY_BACK
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+00F2: # 'ò'
+       SKEY_GRAVE
+       KEY_O
+00F3: # 'ó'
+       KEY_ACUTE
+       KEY_O
+00F4: # 'ô'
+       CODE_ALT
+       XKEY_CARET
+       KEY_O
+00F5: # 'õ'
+       KEY_O
+       KEY_BACK
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+00F6: # 'ö'
+       KEY_OE
+00F7: # '÷'
+       SKEY_COLON
+       KEY_BACK
+       KEY_MINUS
+00F8: # 'ø'
+       KEY_O
+       KEY_BACK
+       SKEY_SLASH
+00F9: # 'ù'
+       SKEY_GRAVE
+       KEY_U
+00FA: # 'ú'
+       KEY_ACUTE
+       KEY_U
+00FB: # 'û'
+       CODE_ALT
+       XKEY_CARET
+       KEY_U
+00FC: # 'ü'
+       KEY_UE
+00FD: # 'ý'
+       KEY_ACUTE
+       KEY_Y
+00FE: # 'þ'
+       KEY_P
+       KEY_BACK
+       KEY_B
+00FF: # 'ÿ'
+       CODE_ALT
+       XKEY_UMLAUT
+       KEY_Y
+0100: # 'Ā'
+       SKEY_A
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0101: # 'ā'
+       KEY_A
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0102: # 'Ă'
+       SKEY_GRAVE
+       SKEY_A
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0103: # 'ă'
+       SKEY_GRAVE
+       KEY_A
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0104: # 'Ą'
+       SKEY_A
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+0105: # 'ą'
+       KEY_A
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+0106: # 'Ć'
+       KEY_ACUTE
+       SKEY_C
+0107: # 'ć'
+       KEY_ACUTE
+       KEY_C
+0108: # 'Ĉ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_C
+0109: # 'ĉ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_C
+010A: # 'Ċ'
+       SKEY_C
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+010B: # 'ċ'
+       KEY_C
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+010C: # 'Č'
+       SKEY_GRAVE
+       SKEY_C
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+010D: # 'č'
+       SKEY_GRAVE
+       KEY_C
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+010E: # 'Ď'
+       SKEY_GRAVE
+       SKEY_D
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+010F: # 'ď'
+       SKEY_GRAVE
+       KEY_D
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0110: # 'Đ'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_MINUS
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       SKEY_D
+0111: # 'đ'
+       KEY_D
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0112: # 'Ē'
+       SKEY_E
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0113: # 'ē'
+       KEY_E
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0114: # 'Ĕ'
+       SKEY_GRAVE
+       SKEY_E
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0115: # 'ĕ'
+       SKEY_GRAVE
+       KEY_E
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0116: # 'Ė'
+       SKEY_E
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0117: # 'ė'
+       KEY_E
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0118: # 'Ę'
+       SKEY_E
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+0119: # 'ę'
+       KEY_E
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+011A: # 'Ě'
+       SKEY_GRAVE
+       SKEY_E
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+011B: # 'ě'
+       SKEY_GRAVE
+       KEY_E
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+011C: # 'Ĝ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_G
+011D: # 'ĝ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_G
+011E: # 'Ğ'
+       SKEY_GRAVE
+       SKEY_G
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+011F: # 'ğ'
+       SKEY_GRAVE
+       KEY_G
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0120: # 'Ġ'
+       SKEY_G
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0121: # 'ġ'
+       KEY_G
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0122: # 'Ģ'
+       SKEY_G
+       KEY_BACK
+       KEY_COMA
+0123: # 'ģ'
+       KEY_G
+       KEY_BACK
+       KEY_COMA
+0124: # 'Ĥ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_H
+0125: # 'ĥ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_H
+0126: # 'Ħ'
+       SKEY_H
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0127: # 'ħ'
+       KEY_H
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0128: # 'Ĩ'
+       SKEY_I
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0129: # 'ĩ'
+       KEY_I
+       KEY_BACK
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+012A: # 'Ī'
+       SKEY_I
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+012B: # 'ī'
+       KEY_I
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+012C: # 'Ĭ'
+       SKEY_GRAVE
+       SKEY_I
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+012D: # 'ĭ'
+       SKEY_GRAVE
+       KEY_I
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+012E: # 'Į'
+       SKEY_I
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+012F: # 'į'
+       KEY_I
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+0130: # 'İ'
+       SKEY_I
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0131: # 'ı'
+       KEY_I
+0132: # 'IJ'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       SKEY_I
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_J
+       CODE_STEPLEFT
+0133: # 'ij'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_I
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_J
+       CODE_STEPLEFT
+0134: # 'Ĵ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_J
+0135: # 'ĵ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_J
+0136: # 'Ķ'
+       SKEY_K
+       KEY_BACK
+       KEY_COMA
+0137: # 'ķ'
+       KEY_K
+       KEY_BACK
+       KEY_COMA
+0138: # 'ĸ'
+       SKEY_K
+0139: # 'Ĺ'
+       KEY_ACUTE
+       SKEY_L
+013A: # 'ĺ'
+       KEY_ACUTE
+       KEY_L
+013B: # 'Ļ'
+       SKEY_L
+       KEY_BACK
+       KEY_COMA
+013C: # 'ļ'
+       KEY_L
+       KEY_BACK
+       KEY_COMA
+013D: # 'Ľ'
+       SKEY_L
+       KEY_BACK
+       CODE_HALFUP
+       KEY_COMA
+       CODE_HALFDOWN
+013E: # 'ľ'
+       KEY_L
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       CODE_HALFUP
+       KEY_MARGIN
+       KEY_COMA
+       CODE_HALFDOWN
+       CODE_STEPLEFT
+013F: # 'Ŀ'
+       SKEY_L
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0140: # 'ŀ'
+       KEY_L
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       CODE_HALFUP
+       KEY_MARGIN
+       KEY_DOT
+       CODE_HALFDOWN
+       CODE_STEPLEFT
+0141: # 'Ł'
+       SKEY_L
+       KEY_BACK
+       KEY_MINUS
+0142: # 'ł'
+       KEY_L
+       KEY_BACK
+       KEY_MINUS
+0143: # 'Ń'
+       KEY_ACUTE
+       SKEY_N
+0144: # 'ń'
+       KEY_ACUTE
+       KEY_N
+0145: # 'Ņ'
+       SKEY_N
+       KEY_BACK
+       KEY_COMA
+0146: # 'ņ'
+       KEY_N
+       KEY_BACK
+       KEY_COMA
+0147: # 'Ň'
+       SKEY_GRAVE
+       SKEY_N
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0148: # 'ň'
+       SKEY_GRAVE
+       KEY_N
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+014A: # 'Ŋ'
+       SKEY_N
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+014B: # 'ŋ'
+       KEY_N
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+014C: # 'Ō'
+       SKEY_O
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+014D: # 'ō'
+       KEY_O
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+014E: # 'Ŏ'
+       SKEY_GRAVE
+       SKEY_O
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+014F: # 'ŏ'
+       SKEY_GRAVE
+       KEY_O
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0150: # 'Ő'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       KEY_BACK
+       SKEY_O
+0151: # 'ő'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       KEY_BACK
+       KEY_O
+0152: # 'Œ'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       SKEY_O
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       SKEY_E
+       CODE_STEPLEFT
+0153: # 'œ'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_O
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_E
+       CODE_STEPLEFT
+0154: # 'Ŕ'
+       KEY_ACUTE
+       SKEY_R
+0155: # 'ŕ'
+       KEY_ACUTE
+       KEY_R
+0156: # 'Ŗ'
+       SKEY_R
+       KEY_BACK
+       KEY_COMA
+0157: # 'ŗ'
+       KEY_R
+       KEY_BACK
+       KEY_COMA
+0158: # 'Ř'
+       SKEY_GRAVE
+       SKEY_R
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0159: # 'ř'
+       SKEY_GRAVE
+       KEY_R
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+015A: # 'Ś'
+       KEY_ACUTE
+       SKEY_S
+015B: # 'ś'
+       KEY_ACUTE
+       KEY_S
+015C: # 'Ŝ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_S
+015D: # 'ŝ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_S
+015E: # 'Ş'
+       SKEY_S
+       KEY_BACK
+       KEY_COMA
+015F: # 'ş'
+       KEY_S
+       KEY_BACK
+       KEY_COMA
+0160: # 'Š'
+       SKEY_GRAVE
+       SKEY_S
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0161: # 'š'
+       SKEY_GRAVE
+       KEY_S
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0162: # 'Ţ'
+       SKEY_T
+       KEY_BACK
+       KEY_COMA
+0163: # 'ţ'
+       KEY_T
+       KEY_BACK
+       KEY_COMA
+0164: # 'Ť'
+       SKEY_GRAVE
+       SKEY_T
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0165: # 'ť'
+       KEY_T
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       CODE_HALFUP
+       KEY_MARGIN
+       KEY_COMA
+       CODE_HALFDOWN
+       CODE_STEPLEFT
+0166: # 'Ŧ'
+       SKEY_T
+       KEY_BACK
+       KEY_MINUS
+0167: # 'ŧ'
+       KEY_T
+       KEY_BACK
+       KEY_MINUS
+0168: # 'Ũ'
+       SKEY_U
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+0169: # 'ũ'
+       KEY_U
+       KEY_BACK
+       CODE_ALT
+       XKEY_CARET
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+016A: # 'Ū'
+       SKEY_U
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+016B: # 'ū'
+       KEY_U
+       KEY_BACK
+       CODE_HALFUP
+       KEY_MINUS
+       CODE_HALFDOWN
+016C: # 'Ŭ'
+       SKEY_GRAVE
+       SKEY_U
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+016D: # 'ŭ'
+       SKEY_GRAVE
+       KEY_U
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+016E: # 'Ů'
+       SKEY_U
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+016F: # 'ů'
+       KEY_U
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+0170: # 'Ű'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       KEY_BACK
+       SKEY_U
+0171: # 'ű'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       KEY_BACK
+       KEY_U
+0172: # 'Ų'
+       SKEY_U
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+0173: # 'ų'
+       KEY_U
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+0174: # 'Ŵ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_W
+0175: # 'ŵ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_W
+0176: # 'Ŷ'
+       CODE_ALT
+       XKEY_CARET
+       SKEY_Y
+0177: # 'ŷ'
+       CODE_ALT
+       XKEY_CARET
+       KEY_Y
+0178: # 'Ÿ'
+       CODE_ALT
+       XKEY_UMLAUT
+       SKEY_Y
+0179: # 'Ź'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       SKEY_Z
+017A: # 'ź'
+       KEY_ACUTE
+       KEY_Z
+017B: # 'Ż'
+       SKEY_Z
+       KEY_BACK
+       KEY_MINUS
+017C: # 'ż'
+       KEY_Z
+       KEY_BACK
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+017D: # 'Ž'
+       SKEY_GRAVE
+       SKEY_Z
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+017E: # 'ž'
+       SKEY_GRAVE
+       KEY_Z
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+0218: # 'Ș'
+0219: # 'ș'
+021A: # 'Ț'
+021B: # 'ț'
+02C7: # 'ˇ'
+       SKEY_GRAVE
+       KEY_SPACE
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+02D8: # '˘'
+       SKEY_GRAVE
+       KEY_SPACE
+       KEY_BACK
+       KEY_ACUTE
+       KEY_SPACE
+02D9: # '˙'
+       CODE_HALFUP
+       KEY_DOT
+       CODE_HALFDOWN
+02DB: # '˛'
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_COMA
+       CODE_STEPLEFT
+02DD: # '˝'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       KEY_ACUTE
+       KEY_SPACE
+       CODE_STEPLEFT
+2013: # '–'
+2014: # '—'
+2015: # '―'
+2018: # '‘'
+2019: # '’'
+201A: # '‚'
+201C: # '“'
+201D: # '”'
+201E: # '„'
+2020: # '†'
+2021: # '‡'
+2022: # '•'
+2026: # '…'
+2030: # '‰'
+2039: # '‹'
+203A: # '›'
+20AC: # '€'
+2122: # '™'
+2500: # '─'
+2502: # '│'
+250C: # '┌'
+2510: # '┐'
+2514: # '└'
+2518: # '┘'
+251C: # '├'
+2524: # '┤'
+252C: # '┬'
+2534: # '┴'
+253C: # '┼'
+2550: # '═'
+2551: # '║'
+2554: # '╔'
+2557: # '╗'
+255A: # '╚'
+255D: # '╝'
+2560: # '╠'
+2563: # '╣'
+2566: # '╦'
+2569: # '╩'
+256C: # '╬'
+2580: # '▀'
+2584: # '▄'
+2588: # '█'
+2591: # '░'
+2592: # '▒'
+2593: # '▓'
+25A0: # '■'
+FFFD: # '�'
+       KEY_MARGIN
+       CODE_STEPLEFT
+       CODE_ALT
+       XKEY_LT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       SKEY_QUEST
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT
+       CODE_STEPLEFT_EXTRA
+       KEY_MARGIN
+       CODE_ALT
+       XKEY_GT
+       CODE_STEPLEFT
+
+TKEY_AT:
+       0040 # '@'
+TKEY_TILDE:
+       007E # '~'
+TCODE_ESC:
+       001B
+KEY_1:
+       0031 # '1'
+SKEY_EXCL:
+       0021 # '!'
+TCODE_LT:
+       003C # '<'
+TCODE_LT_:
+       003C # '<'
+KEY_2:
+       0032 # '2'
+SKEY_QUOT:
+       0022 # '"'
+TCODE_GT:
+       003E # '>'
+TCODE_GT_:
+       003E # '>'
+KEY_3:
+       0033 # '3'
+SKEY_PARAG:
+       00A7 # '§'
+TCODE_QUOT:
+       0027 # '''
+TCODE_QUOT_:
+       0027 # '''
+KEY_4:
+       0034 # '4'
+SKEY_PLUS:
+       002B # '+'
+KEY_5:
+       0035 # '5'
+SKEY_PERCENT:
+       0025 # '%'
+KEY_6:
+       0036 # '6'
+SKEY_AMP:
+       0026 # '&'
+KEY_7:
+       0037 # '7'
+SKEY_SLASH:
+       002F # '/'
+KEY_8:
+       0038 # '8'
+SKEY_LPAREN:
+       0028 # '('
+KEY_9:
+       0039 # '9'
+SKEY_RPAREN:
+       0029 # ')'
+KEY_0:
+       0030 # '0'
+SKEY_EQ:
+       003D # '='
+TCODE_HASH:
+       0023 # '#'
+TCODE_DOLLAR:
+       0024 # '$'
+KEY_SS:
+       00DF # 'ß'
+SKEY_QUEST:
+       003F # '?'
+TCODE_POUND:
+       00A3 # '£'
+TCODE_DEGREE:
+       00B0 # '°'
+KEY_ACUTE:
+       00B4 # '´'
+SKEY_GRAVE:
+       0060 # '`'
+TCODE_DASH:
+       005E # '^'
+TCODE_UMLAUT:
+       00A8 # '¨'
+KEY_BACK:
+       0008
+KEY_TAB:
+       0009
+KEY_Q:
+       0071 # 'q'
+SKEY_Q:
+       0051 # 'Q'
+KEY_W:
+       0077 # 'w'
+SKEY_W:
+       0057 # 'W'
+KEY_E:
+       0065 # 'e'
+SKEY_E:
+       0045 # 'E'
+TCODE_E:
+       0119 # 'ę'
+TCODE_E_:
+       0118 # 'Ę'
+KEY_R:
+       0072 # 'r'
+SKEY_R:
+       0052 # 'R'
+KEY_T:
+       0074 # 't'
+SKEY_T:
+       0054 # 'T'
+KEY_Z:
+       007A # 'z'
+SKEY_Z:
+       005A # 'Z'
+TCODE_Z:
+       017C # 'ż'
+TCODE_Z_:
+       017B # 'Ż'
+KEY_U:
+       0075 # 'u'
+SKEY_U:
+       0055 # 'U'
+KEY_I:
+       0069 # 'i'
+SKEY_I:
+       0049 # 'I'
+KEY_O:
+       006F # 'o'
+SKEY_O:
+       004F # 'O'
+TCODE_O:
+       00F3 # 'ó'
+TCODE_O_:
+       00D3 # 'Ó'
+KEY_P:
+       0070 # 'p'
+SKEY_P:
+       0050 # 'P'
+KEY_UE:
+       00FC # 'ü'
+SKEY_UE:
+       00DC # 'Ü'
+TCODE_BSLASH:
+       005C # '\'
+TCODE_WALL:
+       007C # '|'
+KEY_RETURN:
+       000D
+SKEY_RETURN:
+       000D
+KEY_A:
+       0061 # 'a'
+SKEY_A:
+       0041 # 'A'
+TCODE_A:
+       0105 # 'ą'
+TCODE_A_:
+       0104 # 'Ą'
+KEY_S:
+       0073 # 's'
+SKEY_S:
+       0053 # 'S'
+TCODE_S:
+       015B # 'ś'
+TCODE_S_:
+       015A # 'Ś'
+KEY_D:
+       0064 # 'd'
+SKEY_D:
+       0044 # 'D'
+TCODE_D:
+       015B # 'ś'
+TCODE_D_:
+       015A # 'Ś'
+KEY_F:
+       0066 # 'f'
+SKEY_F:
+       0046 # 'F'
+KEY_G:
+       0067 # 'g'
+SKEY_G:
+       0047 # 'G'
+KEY_H:
+       0068 # 'h'
+SKEY_H:
+       0048 # 'H'
+KEY_J:
+       006A # 'j'
+SKEY_J:
+       004A # 'J'
+KEY_K:
+       006B # 'k'
+SKEY_K:
+       004B # 'K'
+KEY_L:
+       006C # 'l'
+SKEY_L:
+       004C # 'L'
+TCODE_L:
+       0142 # 'ł'
+TCODE_L_:
+       0141 # 'Ł'
+KEY_OE:
+       00F6 # 'ö'
+SKEY_OE:
+       00D6 # 'Ö'
+TCODE_LSQBR:
+       005B # '['
+TCODE_LCURL:
+       007B # '{'
+KEY_AE:
+       00E4 # 'ä'
+SKEY_AE:
+       00C4 # 'Ä'
+TCODE_RSQBR:
+       005D # ']'
+TCODE_RCURL:
+       007D # '}'
+KEY_Y:
+       0079 # 'y'
+SKEY_Y:
+       0059 # 'Y'
+TCODE_Y:
+       017A # 'ź'
+TCODE_Y_:
+       0179 # 'Ź'
+KEY_X:
+       0078 # 'x'
+SKEY_X:
+       0058 # 'X'
+KEY_C:
+       0063 # 'c'
+SKEY_C:
+       0043 # 'C'
+TCODE_C:
+       0107 # 'ć'
+TCODE_C_:
+       0106 # 'Ć'
+KEY_V:
+       0076 # 'v'
+SKEY_V:
+       0056 # 'V'
+KEY_B:
+       0062 # 'b'
+SKEY_B:
+       0042 # 'B'
+KEY_N:
+       006E # 'n'
+SKEY_N:
+       004E # 'N'
+TCODE_N:
+       0144 # 'ń'
+TCODE_N_:
+       0143 # 'Ń'
+KEY_M:
+       006D # 'm'
+SKEY_M:
+       004D # 'M'
+KEY_COMA:
+       002C # ','
+SKEY_SEMI:
+       003B # ';'
+KEY_DOT:
+       002E # '.'
+SKEY_COLON:
+       003A # ':'
+KEY_MINUS:
+       002D # '-'
+SKEY_UNDER:
+       005F # '_'
+TCODE_STAR:
+       002A # '*'
+KEY_SPACE:
+       0020 # ' '
+SKEY_SPACE:
+       0020 # ' '
+KEY_ERASE1:
+       007F
+KEY_ERASEW:
+       007F
diff --git a/keyboard.h b/keyboard.h
new file mode 100644 (file)
index 0000000..6760d5f
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+Actual kezboard layout
+all numbers in octal
+
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+|mar|! <|" >|§ '| + | % | & | / | ( | ) |= $|? °|` ¨|bac|
+|gin|1  |2  |3  | 4 | 5 | 6 | 7 | 8 | 9 |0 #|ß £|´ ^|ksp|
++---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     |   |   |   |   |   |   |   |   |   |   |   |     |
+| tab | Q | W | E | R | T | Z | U | I | O | P | Ü | ret |
++-+---++--++--++--++--++--++--++--++--++--++--++--++urn |
+| |caps|   |   |   |   |   |   |   |   |   |   |   |    |
+| |lock| A | S | D | F | G | H | J | K | L | Ö | Ä |    |
++-+----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+----+
+|        |   |   |   |   |   |   |   | ; | : |_  |      |
+| shift  | Y | X | C | V | B | N | M | , | . |- *| shift|
++--------+---+---+---+---+---+---+---+---+---+---+------+
+         |co |                           |   |   |
+         |de |           space           |<XX|<X |
+         +---+---------------------------+---+---+
+
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+| 10| 00| 01| 05| 07| 17| 16| 06| 03| 02| 04| 14| 12| 22|
++---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|  30 | 20| 21| 25| 27| 37| 36| 26| 23| 52| 34| 24|     |
++-+---++--++--++--++--++--++--++--++--++--++--++--++ 35 |
+| | 50 | 40| 41| 45| 47| 77| 76| 46| 43| 42| 44| 54|    |
++-+----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+----+
+|   53   | 60| 61| 65| 67| 57| 56| 66| 63| 62| 64|  53  |
++--------+---+---+---+---+---+---+---+---+---+---+------+
+         | 51|             70            | 72| 74|
+         +---+---------------------------+---+---+
+
+  | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
+--+----+----+----+----+----+----+----+----+
+  | !< | "> | )  | (  | =$ | §' | /  | +  |
+00| 1  | 2  | 9  | 8  | 0# | 3  | 7  | 4  |
+--+----+----+----+----+----+----+----+----+
+  |mar |    | `¨ |    | ?° |    | &  | %  |
+10|gin |    | ´^ |    | ß£ |    | 6  | 5  |
+--+----+----+----+----+----+----+----+----+
+  |    |    |back|    |    |    |    |    |
+20| Q  | W  |spac| i  | Ü  | E  | U  | R  |
+--+----+----+----+----+----+----+----+----+
+  |    |    |    |    |    | re |    |    |
+30|tab |    |    |    | P  |turn| Z  | T  |
+--+----+----+----+----+----+----+----+----+
+  |    |    |    |    |    |    |    |    |
+40| A  | S  | L  | K  | Ö  | D  | J  | F  |
+--+----+----+----+----+----+----+----+----+
+  |caps| co |    | shi|    |    |    |    |
+50|lock| de | O  | ft | Ä  |    | N  | B  |
+--+----+----+----+----+----+----+----+----+
+  |    |    | :  | ;  | _  |    |    |    |
+60| Y  | X  | .  | ,  | -* | C  | M  | V  |
+--+----+----+----+----+----+----+----+----+
+  | spa|    |    |    |    |    |    |    |
+70| ce |    |<XXX|    | <X |    | H  | G  |
+--+----+----+----+----+----+----+----+----+
+
+special functions
+
+10 <+> ALLOW CROSSING MARGIN
+72 <XX ERASE LAST WORD
+74 <X  ERASE LAST CHARACTER
++CODE:
+10 <+> SET LEFT MARGIN
+00  1  SET RIGHT MARGIN
+01  2  SET TAB STOP
+05  3  CLEAR TAB STOP
+07  4  6 LPI
+17  5  4 LPI
+16  6  3 LPI
+06  7  10 CPI
+03  8  12 CPI
+02  9  STEP DOWN
+04  0  STEP UP
+22 |<- STEP LEFT
+20  Q  RETURN TO LEFT MARGIN
+27  R  AUTORETURN
+26  U  UNDERLINE
+23  I  INDEX
+35 ret CLEAR INDEX
+45  D  CLEAR ALL TAB STOPS
+43  K  WEAK STRIKE
+42  L  STRONG STRIKE
+60  Y  ALTERNATIVE SYMBOL
+65  C  CENTER
+57  B  BOLD
+72 <XX GOTO WORD START
+74 <X  SELECT ERASE CHARACTER
++SHIFT+CODE:
+34  P  PRINT ALL SYMBOLS
+76  H  PRINT ENTIRE LINE H
+56  N  PRINT ALL SYMBOLS FOREVER
+
+
+Created keyboard layout
+top - with shift,
+right - with code
+
++---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+|~  |! <|" >|§ '|+  |%  |&  |/  |(  |)  |= $|? °|` ¨|bac|
+|@\e|1 <|2 >|3 '|4  |5  |6  |7  |8  |9  |0 #|ß £|´ ^|ksp|
++---+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+|     |Q  |W  |E Ę|R  |T  |Z Ż|U  |I  |O Ó|P  |Ü ||     |
+| tab |q  |w  |e ę|r  |t  |z ż|u  |i  |o ó|p  |ü \| ret |
++-+---++--++--++--++--++--++--++--++--++--++--++--++urn |
+| |next|A Ą|S  |D Ś|F  |G  |H  |J  |K  |L Ł|Ö {|Ä }|    |
+| |page|a ą|s ś|d  |f  |g  |h  |j  |k  |l ł|ö [|ä ]|    |
++-+----+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+----+
+|        |Y Ź|X  |C Ć|V  |B  |N Ń|M  |;  |:  |_  |      |
+| shift  |y ź|x  |c ć|v  |b  |n ń|m  |,  |.  |- *| shift|
++--------+---+---+---+---+---+---+---+---+---+---+------+
+         |co |                           |con|   |
+         |de |           space           |trl|del|
+         +---+---------------------------+---+---+
+*/
+
+#define KEYB_ROW    070
+#define KEYB_COL    007
+
+#define KEYB_ROW_0  000
+#define KEYB_ROW_1  010
+#define KEYB_ROW_2  020
+#define KEYB_ROW_3  030
+#define KEYB_ROW_4  040
+#define KEYB_ROW_5  050
+#define KEYB_ROW_6  060
+#define KEYB_ROW_7  070
+
+#define KEYB_COL_0  000
+#define KEYB_COL_1  001
+#define KEYB_COL_2  002
+#define KEYB_COL_3  003
+#define KEYB_COL_4  004
+#define KEYB_COL_5  005
+#define KEYB_COL_6  006
+#define KEYB_COL_7  007
+
+#define KEYB_0 0b00000001
+#define KEYB_1 0b00000010
+#define KEYB_2 0b00000100
+#define KEYB_3 0b00001000
+#define KEYB_4 0b00010000
+#define KEYB_5 0b00100000
+#define KEYB_6 0b01000000
+#define KEYB_7 0b10000000
+
+#define KEYB_SHIFT 0100
+#define KEYB_CODE  0200
+
+#define KEYB_MOD_IND   5
+#define KEYB_SHIFT_BIT 0b00001000
+#define KEYB_CODE_BIT  0b00000010
+
+
+#define KEY_MARGIN 010
+#define KEY_1      000
+#define KEY_2      001
+#define KEY_3      005
+#define KEY_4      007
+#define KEY_5      017
+#define KEY_6      016
+#define KEY_7      006
+#define KEY_8      003
+#define KEY_9      002
+#define KEY_0      004
+#define KEY_SS     014
+#define KEY_ACUTE  012
+#define KEY_BACK   022
+
+#define KEY_TAB    030
+#define KEY_Q      020
+#define KEY_W      021
+#define KEY_E      025
+#define KEY_R      027
+#define KEY_T      037
+#define KEY_Z      036
+#define KEY_U      026
+#define KEY_I      023
+#define KEY_O      052
+#define KEY_P      034
+#define KEY_UE     024
+
+#define KEY_RETURN 035
+
+#define KEY_CAPS   050
+#define KEY_A      040
+#define KEY_S      041
+#define KEY_D      045
+#define KEY_F      047
+#define KEY_G      077
+#define KEY_H      076
+#define KEY_J      046
+#define KEY_K      043
+#define KEY_L      042
+#define KEY_OE     044
+#define KEY_AE     054
+
+#define KEY_SHIFT  053
+#define KEY_Y      060
+#define KEY_X      061
+#define KEY_C      065
+#define KEY_V      067
+#define KEY_B      057
+#define KEY_N      056
+#define KEY_M      066
+#define KEY_COMA   063
+#define KEY_DOT    062
+#define KEY_MINUS  064
+
+#define KEY_CODE   051
+#define KEY_SPACE  070
+#define KEY_ERASEW 072
+#define KEY_ERASE1 074
+
+
+#define SKEY_EXCL    (KEY_1    | KEYB_SHIFT)
+#define SKEY_QUOT    (KEY_2    | KEYB_SHIFT)
+#define SKEY_PARAG   (KEY_3    | KEYB_SHIFT)
+#define SKEY_PLUS    (KEY_4    | KEYB_SHIFT)
+#define SKEY_PERCENT (KEY_5    | KEYB_SHIFT)
+#define SKEY_AMP     (KEY_6    | KEYB_SHIFT)
+#define SKEY_SLASH   (KEY_7    | KEYB_SHIFT)
+#define SKEY_LPAREN  (KEY_8    | KEYB_SHIFT)
+#define SKEY_RPAREN  (KEY_9    | KEYB_SHIFT)
+#define SKEY_EQ      (KEY_0    | KEYB_SHIFT)
+#define SKEY_QUEST   (KEY_SS   | KEYB_SHIFT)
+#define SKEY_GRAVE   (KEY_ACUTE| KEYB_SHIFT)
+
+#define SKEY_Q       (KEY_Q    | KEYB_SHIFT)
+#define SKEY_W       (KEY_W    | KEYB_SHIFT)
+#define SKEY_E       (KEY_E    | KEYB_SHIFT)
+#define SKEY_R       (KEY_R    | KEYB_SHIFT)
+#define SKEY_T       (KEY_T    | KEYB_SHIFT)
+#define SKEY_Z       (KEY_Z    | KEYB_SHIFT)
+#define SKEY_U       (KEY_U    | KEYB_SHIFT)
+#define SKEY_I       (KEY_I    | KEYB_SHIFT)
+#define SKEY_O       (KEY_O    | KEYB_SHIFT)
+#define SKEY_P       (KEY_P    | KEYB_SHIFT)
+#define SKEY_UE      (KEY_UE   | KEYB_SHIFT)
+
+#define SKEY_RETURN  (KEY_RETURN|KEYB_SHIFT)
+
+#define SKEY_CAPS    (KEY_CAPS | KEYB_SHIFT)
+#define SKEY_A       (KEY_A    | KEYB_SHIFT)
+#define SKEY_S       (KEY_S    | KEYB_SHIFT)
+#define SKEY_D       (KEY_D    | KEYB_SHIFT)
+#define SKEY_F       (KEY_F    | KEYB_SHIFT)
+#define SKEY_G       (KEY_G    | KEYB_SHIFT)
+#define SKEY_H       (KEY_H    | KEYB_SHIFT)
+#define SKEY_J       (KEY_J    | KEYB_SHIFT)
+#define SKEY_K       (KEY_K    | KEYB_SHIFT)
+#define SKEY_L       (KEY_L    | KEYB_SHIFT)
+#define SKEY_OE      (KEY_OE   | KEYB_SHIFT)
+#define SKEY_AE      (KEY_AE   | KEYB_SHIFT)
+
+#define SKEY_Y       (KEY_Y    | KEYB_SHIFT)
+#define SKEY_X       (KEY_X    | KEYB_SHIFT)
+#define SKEY_C       (KEY_C    | KEYB_SHIFT)
+#define SKEY_V       (KEY_V    | KEYB_SHIFT)
+#define SKEY_B       (KEY_B    | KEYB_SHIFT)
+#define SKEY_N       (KEY_N    | KEYB_SHIFT)
+#define SKEY_M       (KEY_M    | KEYB_SHIFT)
+#define SKEY_SEMI    (KEY_COMA | KEYB_SHIFT)
+#define SKEY_COLON   (KEY_DOT  | KEYB_SHIFT)
+#define SKEY_UNDER   (KEY_MINUS| KEYB_SHIFT)
+
+#define SKEY_SPACE   (KEY_SPACE| KEYB_SHIFT)
+
+#define XKEY_LT      (KEY_1    | KEYB_SHIFT)
+#define XKEY_GT      (KEY_2    | KEYB_SHIFT)
+#define XKEY_QUOT    (KEY_3    | KEYB_SHIFT)
+#define XKEY_HASH    (KEY_0                )
+#define XKEY_DOLLAR  (KEY_0    | KEYB_SHIFT)
+#define XKEY_POUND   (KEY_SS               )
+#define XKEY_DEGREE  (KEY_SS   | KEYB_SHIFT)
+#define XKEY_CARET   (KEY_ACUTE            )
+#define XKEY_UMLAUT  (KEY_ACUTE| KEYB_SHIFT)
+#define XKEY_STAR    (KEY_MINUS            )
+
+
+#define CODE_LMARGIN    (KEYB_CODE | KEY_MARGIN)
+#define CODE_RMARGIN    (KEYB_CODE | KEY_1     )
+#define CODE_TABPLUS    (KEYB_CODE | KEY_2     )
+#define CODE_TABMINUS   (KEYB_CODE | KEY_3     )
+#define CODE_LINE1      (KEYB_CODE | KEY_4     )
+#define CODE_LINE1_5    (KEYB_CODE | KEY_5     )
+#define CODE_LINE2      (KEYB_CODE | KEY_6     )
+#define CODE_PITCH10    (KEYB_CODE | KEY_7     )
+#define CODE_PITCH12    (KEYB_CODE | KEY_8     )
+#define CODE_HALFDOWN   (KEYB_CODE | KEY_9     )
+#define CODE_HALFUP     (KEYB_CODE | KEY_0     )
+#define CODE_STEPLEFT   (KEYB_CODE | KEY_BACK  )
+#define CODE_TABBACK    (KEYB_CODE | KEY_TAB   )
+#define CODE_RETURN     (KEYB_CODE | KEY_Q     )
+#define CODE_AUTORETURN (KEYB_CODE | KEY_R     )
+#define CODE_UNDER      (KEYB_CODE | KEY_U     )
+#define CODE_IND        (KEYB_CODE | KEY_I     )
+#define CODE_NOTAB      (KEYB_CODE | KEY_D     )
+#define CODE_WEAK       (KEYB_CODE | KEY_K     )
+#define CODE_STRONG     (KEYB_CODE | KEY_L     )
+#define CODE_ALT        (KEYB_CODE | KEY_Y     )
+#define CODE_CENTER     (KEYB_CODE | KEY_C     )
+#define CODE_BOLD       (KEYB_CODE | KEY_B     )
+
+#define CODE_BELL       (KEYB_CODE | KEY_ACUTE )
+#define CODE_STEPLEFT_EXTRA (CODE_STEPLEFT | KEYB_SHIFT)
+
+#define TKEY_AT      KEY_MARGIN
+#define TKEY_TILDE  (KEY_MARGIN | KEYB_SHIFT)
+
+#define TCODE_ESC     (KEYB_CODE | KEY_MARGIN  )
+#define TCODE_LT      (KEYB_CODE | KEY_1       )
+#define TCODE_LT_     (KEYB_SHIFT| TCODE_LT    )
+#define TCODE_GT      (KEYB_CODE | KEY_2       )
+#define TCODE_GT_     (KEYB_SHIFT| TCODE_GT    )
+#define TCODE_QUOT    (KEYB_CODE | KEY_3       )
+#define TCODE_QUOT_   (KEYB_SHIFT| TCODE_QUOT  )
+#define TCODE_HASH    (KEYB_CODE | KEY_0       )
+#define TCODE_DOLLAR  (KEYB_SHIFT| TCODE_HASH  )
+#define TCODE_POUND   (KEYB_CODE | KEY_SS      )
+#define TCODE_DEGREE  (KEYB_SHIFT| TCODE_POUND )
+#define TCODE_DASH    (KEYB_CODE | KEY_ACUTE   )
+#define TCODE_UMLAUT  (KEYB_SHIFT| TCODE_DASH  )
+#define TCODE_E       (KEYB_CODE | KEY_E       )
+#define TCODE_E_      (KEYB_SHIFT| TCODE_E     )
+#define TCODE_Z       (KEYB_CODE | KEY_Z       )
+#define TCODE_Z_      (KEYB_SHIFT| TCODE_Z     )
+#define TCODE_O       (KEYB_CODE | KEY_O       )
+#define TCODE_O_      (KEYB_SHIFT| TCODE_O     )
+#define TCODE_BSLASH  (KEYB_CODE | KEY_UE      )
+#define TCODE_WALL    (KEYB_SHIFT| TCODE_BSLASH)
+#define TCODE_A       (KEYB_CODE | KEY_A       )
+#define TCODE_A_      (KEYB_SHIFT| TCODE_A     )
+#define TCODE_S       (KEYB_CODE | KEY_S       )
+#define TCODE_S_      (KEYB_SHIFT| TCODE_S     )
+#define TCODE_D       (KEYB_CODE | KEY_D       )
+#define TCODE_D_      (KEYB_SHIFT| TCODE_D     )
+#define TCODE_L       (KEYB_CODE | KEY_L       )
+#define TCODE_L_      (KEYB_SHIFT| TCODE_L     )
+#define TCODE_LSQBR   (KEYB_CODE | KEY_OE      )
+#define TCODE_LCURL   (KEYB_SHIFT| TCODE_LSQBR )
+#define TCODE_RSQBR   (KEYB_CODE | KEY_AE      )
+#define TCODE_RCURL   (KEYB_SHIFT| TCODE_RSQBR )
+#define TCODE_Y       (KEYB_CODE | KEY_Y       )
+#define TCODE_Y_      (KEYB_SHIFT| TCODE_Y     )
+#define TCODE_X       (KEYB_CODE | KEY_X       )
+#define TCODE_X_      (KEYB_SHIFT| TCODE_X     )
+#define TCODE_C       (KEYB_CODE | KEY_C       )
+#define TCODE_C_      (KEYB_SHIFT| TCODE_C     )
+#define TCODE_N       (KEYB_CODE | KEY_N       )
+#define TCODE_N_      (KEYB_SHIFT| TCODE_N     )
+#define TCODE_STAR    (KEYB_CODE | KEY_MINUS   )
diff --git a/license.txt b/license.txt
new file mode 100644 (file)
index 0000000..6988639
--- /dev/null
@@ -0,0 +1,5 @@
+This my software is released under the 2-clause BSD license.
+
+It includes the makefile (copied from WinAVR) which is in the public domain.
+
+TODO: include license information in all relevant files.
diff --git a/maszyna.c b/maszyna.c
new file mode 100644 (file)
index 0000000..d8857cc
--- /dev/null
+++ b/maszyna.c
@@ -0,0 +1,6072 @@
+/*
+Copyright 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "keyboard.h"
+#include "keyboard-patterns.h"
+
+
+// hex mode command
+
+#define HEX_NOTHING   0b00000000
+#define HEX_AVAILABLE 0b00000001
+#define HEX_FORCE     0b00000010
+#define HEX_RESET     0b00000100
+#define HEX_FINISH    0b00001000
+
+// menu buttons
+
+#define MENU_NONE     0355 // choose something not present on kezboard
+#define MENU_ENTER   (KEY_ERASEW | KEYB_CODE)
+#define MENU_OUTPUT   KEY_ERASEW
+#define MENU_EXIT     KEY_MARGIN
+#define MENU_CONFIRM  KEY_RETURN
+#define MENU_BAUD     KEY_1
+#define MENU_BITS     KEY_2
+#define MENU_FLOW     KEY_3
+#define MENU_ECHO     KEY_4
+#define MENU_NEWLINE  KEY_5
+#define MENU_DELETE   KEY_6
+#define MENU_REPLACE  KEY_7
+#define MENU_ENCODING KEY_8
+#define MENU_PWIDTH   KEY_Q
+#define MENU_LMARGIN  KEY_W
+#define MENU_RMARGIN  KEY_E
+#define MENU_TWIDTH   KEY_R
+#define MENU_PHEIGHT  KEY_T
+#define MENU_TMARGIN  KEY_Z
+#define MENU_BMARGIN  KEY_U
+#define MENU_THEIGHT  KEY_I
+#define MENU_HTAB     KEY_O
+#define MENU_VTAB     KEY_P
+#define MENU_CWIDTH   KEY_A
+#define MENU_LHEIGHT  KEY_S
+#define MENU_PAPER    KEY_D
+
+#define QMENU_PAGE    KEY_CAPS
+#define QMENU_FPAGE   SKEY_CAPS
+#define QMENU_BOLD    CODE_BOLD
+#define QMENU_UNDER   CODE_UNDER
+#define QMENU_UNDER2 (CODE_UNDER             | KEYB_SHIFT)
+#define QMENU_CROSS  (KEY_P      | KEYB_CODE)
+#define QMENU_OVER   (KEY_P      | KEYB_CODE | KEYB_SHIFT)
+#define QMENU_WEAK    CODE_WEAK
+#define QMENU_STRONG (CODE_WEAK              | KEYB_SHIFT)
+#define QMENU_6LPI    CODE_LINE1
+#define QMENU_4LPI    CODE_LINE1_5
+#define QMENU_3LPI    CODE_LINE2
+#define QMENU_10CPI   CODE_PITCH10
+#define QMENU_12CPI   CODE_PITCH12
+#define QMENU_ECHO    CODE_AUTORETURN
+#define QMENU_PAPER  (KEY_RETURN | KEYB_CODE)
+#define QMENU_EXIT   (KEY_MARGIN | KEYB_CODE | KEYB_SHIFT)
+#define QMENU_HEX    (KEY_TAB    | KEYB_CODE)
+
+// menu text
+
+#define TEXT_MENU_LIST ((uint8_t *) \
+        "MENU\r\n" \
+        "1:baud 2:bits 3:flowctrl 4:echo 5:CR/LF 6:BS/DEL 7:replace 8:encoding\r\n" \
+        "Q:width W:left E:right R:Twidth T:height Z:top U:bottom I:Theight\r\n" \
+        "O:Htab P: Vtab A:Cwidth S:Lheight D:paper DEL: help ESC: exit\r\n> ")
+#define TEXT_MENU_EXIT ((uint8_t *) \
+        "EXIT\r\n")
+#define TEXT_MENU_BAUD ((uint8_t *) \
+        "SET BAUD RATE\r\n" \
+        "134,150,200,300,600,1200,1800,2400,4800,7200,9600,14400,\r\n" \
+        "19200,28800,31520,57600,76800,115200,125000,250000,\r\n" \
+        "> ")
+#define TEXT_MENU_BITS ((uint8_t *) \
+        "SET SERIAL MODE\r\n" \
+        "1:8n1 2:8e1 3:8o1 4:8n2 5:8e2 6:8o2\r\n" \
+        "7:7n1 8:7e1 9:7o1 10:7n2 11:7e2 12:7o2\r\n" \
+        "> ")
+#define TEXT_MENU_FLOW ((uint8_t *) \
+        "SET FLOW CONTROPL\r\n" \
+        "HW: 1:FD(RTR/CTS) 2:HD,DTE(RTS/CTS) 3:HD,DCE(CTS/RTS) 4:none\r\n" \
+        "SW: 5:XON/XOFF  6:none\r\n> ")
+#define TEXT_MENU_NEWLINE ((uint8_t *) \
+        "SET NEWLINE HANDLING\r\n" \
+        "RECEIVE: 1:CR->CRLF 2:LF->CRLF 3:any->CRLF 4:no change\r\n" \
+        "SEND: 5:CR 6:LF 7:CRLF\r\n> ")
+#define TEXT_MENU_ECHO ((uint8_t *) \
+        "SET LOCAL ECHO\r\n" \
+        "1:ON 2:OFF\r\n> ")
+#define TEXT_MENU_DELETE ((uint8_t *) \
+        "SET BACKSPACE/DELETE KEY CODE\r\n" \
+        "1:BS=08 2:BS=7F 3:DEL=7F 4:DEL=08\r\n> ")
+#define TEXT_MENU_REPLACE ((uint8_t *) \
+        "SET UNKNOWN CHARACTER HANDLING\r\n" \
+        "1:<?> 2:? 3:_ 4:SPACE 5:ignore\r\n> ")
+#define TEXT_MENU_ENCODING ((uint8_t *) \
+        "SET CHARACTER ENCODING\r\n" \
+        "1,2,3,4,9,10,13,15,16:ISO8859 1250,852:codepage 8:UTF-8\r\n> ")
+#define TEXT_MENU_PWIDTH ((uint8_t *) \
+        "SET PAGE WIDTH (in columns)\r\n> ")
+#define TEXT_MENU_LMARGIN ((uint8_t *) \
+        "SET LEFT MARGIN (in columns)\r\n> ")
+#define TEXT_MENU_RMARGIN ((uint8_t *) \
+        "SET RIGHT MARGIN (in columns)\r\n> ")
+#define TEXT_MENU_TWIDTH ((uint8_t *) \
+        "SET TEXT WIDTH (in columns)\r\n> ")
+#define TEXT_MENU_PHEIGHT ((uint8_t *) \
+        "SET PAGE HEIGHT (in lines)\r\n> ")
+#define TEXT_MENU_TMARGIN ((uint8_t *) \
+        "SET TOP MARGIN (in lines)\r\n> ")
+#define TEXT_MENU_BMARGIN ((uint8_t *) \
+        "SET BOTTOM MARGIN (in lines)\r\n> ")
+#define TEXT_MENU_THEIGHT ((uint8_t *) \
+        "SET TEXT HEIGHT (in lines)\r\n> ")
+#define TEXT_MENU_HTAB ((uint8_t *) \
+        "SET TAB WIDTH (in columns)\r\n> ")
+#define TEXT_MENU_VTAB ((uint8_t *) \
+        "SET TAB HEIGHT (in lines)\r\n> ")
+#define TEXT_MENU_CWIDTH ((uint8_t *) \
+        "SET CHARACTER WIDTH\r\n" \
+        "15, 12, 10, 6, 4, 3 CPI\r\n> ")
+#define TEXT_MENU_LHEIGHT ((uint8_t *) \
+        "SET LINE HEIGHT\r\n" \
+        "6, 4, 3, 2 LPI\r\n> ")
+#define TEXT_MENU_PAPER ((uint8_t *) \
+        "SET_PAPER_TYPE\r\n" \
+        "1:continuous 2:single pages\r\n> ")
+#define TEXT_MENU_CANCEL ((uint8_t *) \
+        " CANCEL\r\n> ")
+#define TEXT_MENU_OK ((uint8_t *) \
+        " OK\r\n> ")
+#define TEXT_MENU_FAIL ((uint8_t *) \
+        " FAIL\r\n> ")
+
+// setting ID in EEPROM
+
+#define ID_BAUD     1
+#define ID_MODE     2
+#define ID_NL_MODE  3
+#define ID_BS_MODE  4
+#define ID_ENCODING 5
+#define ID_REPLACE  6
+#define ID_BITS     7
+#define ID_LWIDTH   8
+#define ID_LMARGIN  9
+#define ID_RMARGIN 10
+#define ID_PHEIGHT 11
+#define ID_TMARGIN 12
+#define ID_BMARGIN 13
+#define ID_CWIDTH  14
+#define ID_LHEIGHT 15
+#define ID_HTAB    16
+#define ID_VTAB    17
+#define ID_PAPER   18
+#define ID_STYLE   19
+#define ID_FLOW    20
+
+//              <=25000  <=8192                              <=1.500%
+// #define UART_DIV_50    20000 // 20000             50.0000   0.000%  +
+// #define UART_DIV_75    13333 // 13333 1/3         75.0019  +0.010%  +
+// #define UART_DIV_110    9091 //  9090 10/11      109.9989  -0.001%  +
+   #define UART_DIV_134_5  7435 //  7434.944238     134.4990  -0.001%  +
+   #define UART_DIV_150    6667 //  6666 2/3        149.9925  -0.005%  +
+   #define UART_DIV_200    5000 //  5000            200.0000   0.000%  +
+   #define UART_DIV_300    3333 //  3333 1/3        300.0300  +0.010%  +
+   #define UART_DIV_600    1667 //  1666 2/3        599.8800  -0.020%  +
+   #define UART_DIV_1200    833 //   833 1/3       1200.4802  +0.040%  +
+   #define UART_DIV_1800    556 //   555 5/9       1798.5612  -0.080%  +
+   #define UART_DIV_2400    417 //   416 2/3       2398.0815  -0.080%  +
+   #define UART_DIV_4800    208 //   208 1/3       4807.6923  +0.160%  +
+   #define UART_DIV_7200    139 //   138 8/9       7194.2446  -0.080%  +
+   #define UART_DIV_9600    104 //   104 1/6       9615.3846  +0.160%  +
+   #define UART_DIV_14400    69 //    69 4/9      14492.7536  +0.644%  +
+   #define UART_DIV_19200    52 //    52 1/12     19230.7692  +0.160%  +
+   #define UART_DIV_28800    35 //    34 13/18    28571.4286  -0.794%  +
+   #define UART_DIV_31250    32 //    32          31250.0000   0.000%  +
+   #define UART_DIV_38400    26 //    26 1/24     38461.5384  +0.160%  +
+   #define UART_DIV_57600    17 //    17 17/36    58823.5294  +2.124%  -
+   #define UART_DIV_76800    13 //    13 1/48     76923.0769  +0,160%  +
+   #define UART_DIV_115200    9 //     8 49/72   111111.1111  -3.549%  -
+   #define UART_DIV_125000    8 //     8         125000.0000   0.000%  +
+// #define UART_DIV_128000    8 //     7 13/16   125000.0000  -2.344%  -
+// #define UART_DIV_230400    4 //     4 49/144  250000.0000  +8.507%  -
+   #define UART_DIV_250000    4 //     4         250000.0000   0.000%  +
+// #define UART_DIV_256000    4 //     3 29/32   250000.0000  +2.344%  -
+// #define UART_DIV_460800    2 //     2 49/284  500000.0000  +8.507%  -
+// #define UART_DIV_500000    2 //     2         500000.0000   0.000%  +
+// #define UART_DIV_576000    2 //     1 53/72   500000.0000 -13.194%  -
+// #define UART_DIV_921600    1 //     1 49/576 1000000.0000  +8.507%  -
+// #define UART_DIV_1000000   1 //     1        1000000.0000   0.000%  +
+
+#define UART_BAUD_134_5    0
+#define UART_BAUD_150      1
+#define UART_BAUD_200      2
+#define UART_BAUD_300      3
+#define UART_BAUD_600      4
+#define UART_BAUD_1200     5
+#define UART_BAUD_1800     6
+#define UART_BAUD_2400     7
+#define UART_BAUD_4800     8
+#define UART_BAUD_7200     9
+#define UART_BAUD_9600    10
+#define UART_BAUD_14400   11
+#define UART_BAUD_19200   12
+#define UART_BAUD_28800   13
+#define UART_BAUD_31250   14
+#define UART_BAUD_38400   15
+#define UART_BAUD_57600   16
+#define UART_BAUD_76800   17
+#define UART_BAUD_115200  18
+#define UART_BAUD_125000  19
+#define UART_BAUD_250000  20
+#define N_UART_BAUD       21
+
+#define UM16_134_5     134
+#define UM16_150       150
+#define UM16_200       200
+#define UM16_300       300
+#define UM16_600       600
+#define UM16_1200     1200
+#define UM16_1800     1800
+#define UM16_2400     2400
+#define UM16_4800     4800
+#define UM16_7200     7200
+#define UM16_9600     9600
+#define UM16_14400   14400
+#define UM16_19200   19200
+#define UM16_28800   28800
+#define UM16_31250   31250
+#define UM16_38400   38400
+#define UM16_57600   57600
+#define UM16_76800   11264
+#define UM16_115200  49664
+#define UM16_125000  59464
+#define UM16_250000  53392
+
+#define UART_DATA     (7<<UCSZ00)
+#define UART_DATA_8   (3<<UCSZ00)
+#define UART_DATA_7   (2<<UCSZ00)
+#define UART_STOP     (1<<USBS0)
+#define UART_STOP_1   (0<<USBS0)
+#define UART_STOP_2   (1<<USBS0)
+#define UART_PARITY   (3<<UPM00)
+#define UART_PARITY_N (0<<UPM00)
+#define UART_PARITY_E (2<<UPM00)
+#define UART_PARITY_O (3<<UPM00)
+
+#define UART_8N1 (UART_DATA_8 | UART_STOP_1 | UART_PARITY_N)
+#define UART_8E1 (UART_DATA_8 | UART_STOP_1 | UART_PARITY_E)
+#define UART_8O1 (UART_DATA_8 | UART_STOP_1 | UART_PARITY_O)
+#define UART_8N2 (UART_DATA_8 | UART_STOP_2 | UART_PARITY_N)
+#define UART_8E2 (UART_DATA_8 | UART_STOP_2 | UART_PARITY_E)
+#define UART_8O2 (UART_DATA_8 | UART_STOP_2 | UART_PARITY_O)
+#define UART_7N1 (UART_DATA_7 | UART_STOP_1 | UART_PARITY_N)
+#define UART_7E1 (UART_DATA_7 | UART_STOP_1 | UART_PARITY_E)
+#define UART_7O1 (UART_DATA_7 | UART_STOP_1 | UART_PARITY_O)
+#define UART_7N2 (UART_DATA_7 | UART_STOP_2 | UART_PARITY_N)
+#define UART_7E2 (UART_DATA_7 | UART_STOP_2 | UART_PARITY_E)
+#define UART_7O2 (UART_DATA_7 | UART_STOP_2 | UART_PARITY_N)
+
+#define FLOW_HW     0b00000111
+#define FLOW_FD     0b00000001
+#define FLOW_HD_DTE 0b00000010
+#define FLOW_HD_DCE 0b00000100
+#define FLOW_SW     0b00001000
+#define FLOW_XONOFF 0b00001000
+#define FLOW_NONE   0b00000000
+
+#define XON  0x11
+#define XOFF 0x13
+
+
+#define MODE_WAIT  0b00000000
+#define MODE_TYPE  0b00000001
+#define MODE_TERM  0b00000010
+#define MODE_ECHO  0b00000100
+#define MODE_HEX   0b00001000
+
+
+#define NL_IMPLICIT_CR 0b00000001
+#define NL_IMPLICIT_LF 0b00000010
+#define NL_SEND_CR     0b00000100
+#define NL_SEND_LF     0b00001000
+#define NL_SEND_CRLF   (NL_SEND_CR | NL_SEND_LF)
+#define NL_CATCH_ALL   (NL_IMPLICIT_CR | NL_IMPLICIT_LF)
+
+
+#define BS_BS  0b00000001
+#define BS_DEL 0b00000010
+
+
+#define ESC_NONE    0
+// #define ESC_P_POS   1 // rejected
+#define ESC_ECMA_48 2
+
+
+#define REPLACE_SYMBOL 0
+#define REPLACE_QUEST  1
+#define REPLACE_UNDER  2
+#define REPLACE_SPACE  3
+#define REPLACE_IGNORE 4
+#define N_REPLACE      5
+
+#define R_SYMBOL CH_UNKN // '<?>'
+#define R_QUEST  CH_003F // '?'
+#define R_UNDER  CH_005F // '_'
+#define R_SPACE  CH_0020 // ' '
+#define R_IGNORE CH_NULL // ''
+
+
+#define PAPER_SINGLE     0
+#define PAPER_CONTINUOUS 1
+
+
+#define STYLE_NORMAL  0b00000000
+#define STYLE_BOLD    0b00000001
+#define STYLE_UNDER   0b00000010
+#define STYLE_UNDER2  0b00000100
+#define STYLE_OVER    0b00001000
+#define STYLE_CROSS   0b00010000
+#define STYLE_STRONG  0b10000000
+
+
+// some of the fractions were obtained using RIES by Robert Munafo https://mrob.com/pub/ries/
+#define HUNIT_MUL_CH    0 // CHARACTER
+#define HUNIT_DIV_CH    0 
+#define HUNIT_MUL_MM  300 // MILLIMETRE
+#define HUNIT_DIV_MM  127 //   1mm   300/127
+#define HUNIT_MUL_CDP   1 // COMPUTER DECIPOINT
+#define HUNIT_DIV_CDP  12 //   1"/720   1/12
+#define HUNIT_MUL_DD    4 // DECIDIDOT
+#define HUNIT_DIV_DD   45 //   10mm/266   1500/16891 ~ 4/45
+#define HUNIT_MUL_MIL   3 // MIL
+#define HUNIT_DIV_MIL  50 //   1"/1000   3/50
+#define HUNIT_MUL_BMU   1 // BASIC MEASURING UNIT
+#define HUNIT_DIV_BMU  20 //   1"/1200   1/20
+#define HUNIT_MUL_UM    3 // MICROMETRE
+#define HUNIT_DIV_UM 1270 //   1mm/1000   3/1270
+#define HUNIT_MUL_DP    1 // DECIPOINT
+#define HUNIT_DIV_DP   12 //   35mm/996   875/10541 ~ 1/12
+
+#define VUNIT_MUL_CH    1 // CHARACTER
+#define VUNIT_DIV_CH    0
+#define VUNIT_MUL_MM   60 // MILLIMETRE
+#define VUNIT_DIV_MM  127 //   1mm   60/127
+#define VUNIT_MUL_CDP   1 // COMPUTER DECIPOINT
+#define VUNIT_DIV_CDP  60 //   1"720   1/60
+#define VUNIT_MUL_DD    4 // DECIDIDOT
+#define VUNIT_DIV_DD  225 //   10mm/266 - 300/16891 ~ 4/225
+#define VUNIT_MUL_MIL   3 // MIL
+#define VUNIT_DIV_MIL 250 //   1"/1000   3/250
+#define VUNIT_MUL_BMU   1 // BASIC MEASURING UNIT
+#define VUNIT_DIV_BMU 100 //   1"/1200   1/100
+#define VUNIT_MUL_UM    3 // MICROMETRE
+#define VUNIT_DIV_UM 6350 //   1mm/1000   3/6350
+#define VUNIT_MUL_DP    1 // DECIPOINT
+#define VUNIT_DIV_DP   60 //   35mm/996   175/10541 ~ 1/60
+
+
+// for PFS - PAGE FORMAT SELECTION
+// table E.1 in ECMA-48
+// all columns merged into single value
+
+#define PF_TCOMM_BASIC_TALL 0
+#define PF_TCOMM_BASIC_WIDE 1
+#define PF_A4_BASIC_TALL    2
+#define PF_A4_BASIC_WIDE    3
+#define PF_LETTER_TALL      4
+#define PF_LETTER_WIDE      5
+#define PF_A4_EXT_TALL      6
+#define PF_A4_EXT_WIDE      7
+#define PF_LEGAL_TALL       8
+#define PF_LEGAL_WIDE       9
+#define PF_A4_SHORT        10
+#define PF_A4_LONG         11
+#define PF_B5_SHORT        12
+#define PF_B5_LONG         13
+#define PF_B4_SHORT        14
+#define PF_B4_LONG         15
+#define N_PF               16
+
+#define LWIDTH_TCOMM_BASIC_TALL 462 //  92.4  7.7"
+#define LWIDTH_TCOMM_BASIC_WIDE 625 // 125    10 5/12"
+#define LWIDTH_A4_BASIC_TALL    462 //  92.4  7.7"
+#define LWIDTH_A4_BASIC_WIDE    660 // 132    11"
+#define LWIDTH_LETTER_TALL      480 //  96    8"
+#define LWIDTH_LETTER_WIDE      625 // 125    10 5/12"
+#define LWIDTH_A4_EXT_TALL      462 //  92.4  7.7"
+#define LWIDTH_A4_EXT_WIDE      660 // 132    11"
+#define LWIDTH_LEGAL_TALL       480 //  96    8"
+#define LWIDTH_LEGAL_WIDE       810 // 162    13.5"
+#define LWIDTH_A4_SHORT         450 //  90    7.5"
+#define LWIDTH_A4_LONG          655 // 131    10 11/12"
+#define LWIDTH_B5_SHORT         375 //  75    6.25"
+#define LWIDTH_B5_LONG          555 // 111    9.25"
+#define LWIDTH_B4_SHORT         555 // 111    9.25"
+#define LWIDTH_B4_LONG          785 // 157    13 1/12"
+
+#define PHEIGHT_TCOMM_BASIC_TALL 110 // 55   9 1/6"
+#define PHEIGHT_TCOMM_BASIC_WIDE  76 // 38   6 1/3"
+#define PHEIGHT_A4_BASIC_TALL    118 // 59   9 5/6"
+#define PHEIGHT_A4_BASIC_WIDE     76 // 38   6 1/3"
+#define PHEIGHT_LETTER_TALL      112 // 56   9 1/3"
+#define PHEIGHT_LETTER_WIDE       80 // 40   6 2/3"
+#define PHEIGHT_A4_EXT_TALL      132 // 63   11"
+#define PHEIGHT_A4_EXT_WIDE       88 // 44   7 1/3" 
+#define PHEIGHT_LEGAL_TALL       148 // 74   12 1/3"
+#define PHEIGHT_LEGAL_WIDE        80 // 40   6 2/3"
+#define PHEIGHT_A4_SHORT         118 // 59   9 5/6"
+#define PHEIGHT_A4_LONG           76 // 38   6 1/3"
+#define PHEIGHT_B5_SHORT          98 // 49   8 1/6"
+#define PHEIGHT_B5_LONG           64 // 32   5 1/13"
+#define PHEIGHT_B4_SHORT         114 // 59   9.5"  
+#define PHEIGHT_B4_LONG           98 // 49   8 1/6"
+
+
+#define WIDTH_15   4 // 1/15 "
+#define WIDTH_12   5 // 1/12 "
+#define WIDTH_10   6 // 1/10 "
+#define WIDTH_6   10 // 1/6 "
+#define WIDTH_4_5 13 // 2/9 "  13 1/3
+#define WIDTH_4   15 // 1/4 "
+#define WIDTH_3   20 // 1/3 "
+#define N_CWIDTH   7
+
+#define HEIGHT_6     2 // 1/6 "  2
+#define HEIGHT_4     3 // 1/4 "  3 
+#define HEIGHT_3     4 // 1/3 "  4
+#define HEIGHT_12    1 // 1/12 " 1
+#define HEIGHT_8     2 // 3.75mm 1.5
+#define HEIGHT_6M    2 // 5mm    2 46/127
+#define HEIGHT_4M    4 // 7.5mm  3 69/127
+#define HEIGHT_3M    5 // 10mm   4 92/127
+#define HEIGHT_12M   1 // 2.5mm  1 23/127
+#define HEIGHT_2     6 // 1/2 "  6
+#define N_LHEIGHT   10
+
+#define WIDTH_NARROW  WIDTH_15
+#define WIDTH_NORMAL  WIDTH_12
+#define WIDTH_WIDE    WIDTH_10
+
+#define HEIGHT_NORMAL HEIGHT_6
+
+/*
+Text positions and default margins on machine
+
+12CPI:
+0         1         2         3         4         5         6         7         8         9         10      
+012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
+XXXXXXXXXXXX                                                                              XXXXXXXXXXXXXXXXXX
+
+10CPI:
+0         1         2         3         4         5         6         7         8         
+012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+XXXXXXXXXX                                                                 XXXXXXXXXXXXXXX
+
+unit is 1/60", width is 10". Default left margin is 1", right is 1.5".
+I'm keeping out of first and last 12CPI columns, denying their existence
+*/
+
+#define HPOS_LIMIT         ((108-2) * WIDTH_NORMAL)
+#define VPOS_LIMIT             (144 * HEIGHT_NORMAL)
+#define DEFAULT_LWIDTH          (92 * WIDTH_NORMAL)
+#define DEFAULT_PHEIGHT         (72 * HEIGHT_NORMAL)
+#define DEFAULT_LMARGIN     ((12-1) * WIDTH_NORMAL)
+#define DEFAULT_LMARGIN_AIM      (0 * WIDTH_NORMAL)
+#define DEFAULT_RMARGIN     ((90-1) * WIDTH_NORMAL)
+#define DEFAULT_RMARGIN_AIM    ((80 * WIDTH_NORMAL)+DEFAULT_LMARGIN_AIM)
+#define DEFAULT_TMARGIN          (0 * HEIGHT_NORMAL)
+#define DEFAULT_BMARGIN        ((56 * HEIGHT_NORMAL)+DEFAULT_TMARGIN)
+#define DEFAULT_TWIDTH_CH         4
+#define DEFAULT_THEIGHT_CH        4
+
+// for PFS - PAGE FORMAT SELECTION again
+#define LMARGIN_PRESET          (12 * WIDTH_NORMAL)
+#define RMARGIN_PRESET           (2 * WIDTH_NORMAL)
+
+// size in bytes of table to keep track of TAB positions.
+#define N_HTAB (((HPOS_LIMIT-1)/8)+1)
+#define N_VTAB (((VPOS_LIMIT-1)/8)+1)
+
+
+// timing stuff
+
+// Frequency of main interrupt, values for prescaler and counter
+#define INT_PRE 2   // 8MHz / 8 = 1MHz
+#define INT_DIV 167 // 1MHz / 167 = 5.988kHz
+// Based on that derive frequency for triggers of LED and printing action
+// Printing 1 character takes 4+ cycles
+#define PRINT_DIV 176 // 1MHz / 167 / 176 = 34.0228Hz = 4 * 8.5057Hz
+#define LED_DIV   599 // 1MHz / 167/ 599  =  9.9967Hz
+// how many cycles of delay (wait for Carriage Return) 1 character introduces:
+#define PRINT_DELAY 1 // 2?
+
+#define TIME_1MS     6
+#define TIME_10MS   60
+#define TIME_100MS 600
+#define TIME_1S   6000
+
+#define SCAN_HOLD 3 // how long state must be stable
+#define SCAN_DEBOUNCE  3 //   3 * 10ms =  30ms
+#define SCAN_DELAY    70 //  70 * 10ms = 700ms
+#define SCAN_REPEAT   12 //  12 * 10ms = 120ms
+// ~10ms is the total period coming from the typewriter
+
+
+// buffer sizes
+#define N_INCOME_BUFFER  256 // incoming characters
+#define N_OUTCOME_BUFFER  64 // outcoming characters
+#define N_PRINT_BUFFER   128 // outcoming key presses
+#define N_SCAN_BUFFER     64 // incoming key presses
+#define N_ESC_BUFFER      64 // control string / sequence
+
+#define INCOME_BUFFER_LOW    8  // for XON / CTS
+#define INCOME_BUFFER_HIGH 208  // for XOFF / ~CTS
+
+
+// control for allowing / disallowing sleep mode
+#define WAKEUP_INCOME  0b00000001
+#define WAKEUP_OUTCOME 0b00000010
+#define WAKEUP_SCAN    0b00000100
+
+
+#define EEPROM_SIZE (4 * 1024)
+
+
+/*
+IO
+                ATmega1284
+            +-------\/-------+
+   /----- 0 |*1 B0      A0 40| 70   /-----
+  <COLUMN 1 | 2 B1      A1 39| 60  /
+   \----- 2 | 3 B2      A2 38| 50 /
+   /----- 0 | 4 B3      A3 37| 40/KEYBOARD
+  <  ROW  1 | 5 B4      A4 36| 30\   ROW
+   \----- 2 | 6 B5      A5 35| 20 \
+   <- SHIFT | 7 B6      A6 34| 10  \
+    <- CODE | 8 B7      A7 33| 00   \-----
+            | 9 RESET AREF 32|
+            |10 VCC    GND 31| 
+            |11 GND   AVCC 30| 
+            |12 X2      C7 29| 07   /-----
+            |13 X1      C6 28| 06  /
+      -> RX |14 D0      C5 27| 05 /
+      <- TX |15 D1      C4 26| 04/KEYBOARD
+    <- FLOW |16 D2      C3 25| 03\ COLUMN
+    -> FLOW |17 D3      C2 24| 02 \
+    <- /LED |18 D4      C1 23| 01  \
+    <- /KEY |19 D5      C0 22| 00   \-----
+<- /EN_KEYB |20 D6      C7 21| /EN_PRINT ->
+            +----------------+
+*/
+
+// port A, keyboard row
+#define PORT_ROW PORTA
+#define DDR_ROW  DDRA
+#define PIN_ROW  PINA
+
+// port C, keyboard column
+#define PORT_COL PORTC
+#define DDR_COL  DDRC
+#define PIN_COL  PINC
+
+// port B, key output select
+#define PORT_KEY PORTB
+#define DDR_KEY  DDRB
+
+// port D, control of state, active low
+#define PORT_CTRL PORTD
+#define DDR_CTRL  DDRD
+
+#define LED      0b00010000 // out
+#define KEY      0b00100000 // out
+#define EN_PRINT 0b01000000 // out
+#define EN_KEYB  0b10000000 // out
+
+#define MASK_CTRL (LED|KEY|EN_PRINT|EN_KEYB)
+
+// port D, communication
+#define PORT_COMM PORTD
+#define DDR_COMM  DDRD
+#define PIN_COMM  PIND
+
+#define RX       0b00000001 // in
+#define TX       0b00000010 // out
+#define SYNC_IN  0b00000100 // in
+#define SYNC_OUT 0b00001000 // out
+
+#define MASK_COMM (RX|TX|SYNC_IN|SYNC_OUT)
+
+
+// to simplify keeping track of buffer indexing
+#define CTRL_IND (buffer+1), &buffer_pos, &p_ind, &sp_ind
+
+// common actions on buffer pointers
+// W  write pointer
+// R  read pointer
+// P  any pointer
+// N  buffer size
+#define ADVANCE_BP(P, N)      ((P<(N-1)) ? (++P) : (P=0))
+#define DIFF_BP(W, R, N)      ((W<R) ? (N + W - R) : W - R)
+#define FULL_BP(W, R, N)      (DIFF_BP(W, R, N) == (N-1))
+#define NOT_FULL_BP(W, R, N)  (DIFF_BP(W, R, N) != (N-1))
+#define EMPTY_BP(W, R, N)     (R == W)
+#define NOT_EMPTY_BP(W, R, N) (R != W)
+
+// useful macro for horizontal and vertical unit conversion
+#define HUNIT(X) unit(X, hunit_mul, hunit_div)
+#define VUNIT(Y) unit(Y, vunit_mul, vunit_div)
+
+// FUSE bits modified from default value
+// reprogram FUSE at least once for correct operation
+// make fuse
+FUSES = 
+{
+.low =
+       FUSE_SUT_CKSEL0 & FUSE_SUT_CKSEL2 & FUSE_SUT_CKSEL3 & // internal 8MHz
+       FUSE_SUT_CKSEL4 & FUSE_SUT_CKSEL5, // BOD
+       // no clk out
+       // no clk div
+.high =
+       // BOOTRST = 1
+       FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & // BOOTSZ = 0
+       FUSE_EESAVE & // preserve EEPROM
+       // WDT off
+       // FUSE_SPIEN & FUSE_JTAGEN, // enable prog.
+       FUSE_SPIEN, // enable spi prog, disable jtag
+       // no enable ocd
+.extended = FUSE_BODLEVEL1, // BOD 2.5 - 2.9
+};
+
+/* look up tables fot option selection */
+
+const uint16_t UART_DIV[N_UART_BAUD] = {
+       UART_DIV_134_5,
+       UART_DIV_150,
+       UART_DIV_200,
+       UART_DIV_300,
+       UART_DIV_600,
+       UART_DIV_1200,
+       UART_DIV_1800,
+       UART_DIV_2400,
+       UART_DIV_4800,
+       UART_DIV_7200,
+       UART_DIV_9600,
+       UART_DIV_14400,
+       UART_DIV_19200,
+       UART_DIV_28800,
+       UART_DIV_31250,
+       UART_DIV_38400,
+       UART_DIV_57600,
+       UART_DIV_76800,
+       UART_DIV_115200,
+       UART_DIV_125000,
+       UART_DIV_250000,
+};
+
+uint8_t const * const REPLACE[N_REPLACE] = {
+       R_SYMBOL,
+       R_QUEST,
+       R_UNDER,
+       R_SPACE,
+       R_IGNORE
+};
+
+const uint16_t LWIDTH_PRESET[N_PF] = {
+       LWIDTH_TCOMM_BASIC_TALL,
+       LWIDTH_TCOMM_BASIC_WIDE,
+       LWIDTH_A4_BASIC_TALL,
+       LWIDTH_A4_BASIC_WIDE,
+       LWIDTH_LETTER_TALL,
+       LWIDTH_LETTER_WIDE,
+       LWIDTH_A4_EXT_TALL,
+       LWIDTH_A4_EXT_WIDE,
+       LWIDTH_LEGAL_TALL,
+       LWIDTH_LEGAL_WIDE,
+       LWIDTH_A4_SHORT,
+       LWIDTH_A4_LONG,
+       LWIDTH_B5_SHORT,
+       LWIDTH_B5_LONG,
+       LWIDTH_B4_SHORT,
+       LWIDTH_B4_LONG
+};
+
+const uint16_t PHEIGHT_PRESET[N_PF] = {
+       PHEIGHT_TCOMM_BASIC_TALL,
+       PHEIGHT_TCOMM_BASIC_WIDE,
+       PHEIGHT_A4_BASIC_TALL,
+       PHEIGHT_A4_BASIC_WIDE,
+       PHEIGHT_LETTER_TALL,
+       PHEIGHT_LETTER_WIDE,
+       PHEIGHT_A4_EXT_TALL,
+       PHEIGHT_A4_EXT_WIDE,
+       PHEIGHT_LEGAL_TALL,
+       PHEIGHT_LEGAL_WIDE,
+       PHEIGHT_A4_SHORT,
+       PHEIGHT_A4_LONG,
+       PHEIGHT_B5_SHORT,
+       PHEIGHT_B5_LONG,
+       PHEIGHT_B4_SHORT,
+       PHEIGHT_B4_LONG,
+};
+
+const uint8_t CWIDTH_PRESET[N_CWIDTH] = {
+       WIDTH_10,
+       WIDTH_12,
+       WIDTH_15,
+       WIDTH_6,
+       WIDTH_3,
+       WIDTH_4_5,
+       WIDTH_4
+};
+
+const uint8_t LHEIGHT_PRESET[N_LHEIGHT] = {
+       HEIGHT_6,
+       HEIGHT_4,
+       HEIGHT_3,
+       HEIGHT_12,
+       HEIGHT_8,
+       HEIGHT_6M,
+       HEIGHT_4M,
+       HEIGHT_3M,
+       HEIGHT_12M,
+       HEIGHT_2
+};
+
+/* time stuff */
+
+volatile uint32_t main_timer = 0;
+volatile uint32_t last_print_time = 0;
+
+/* buffers & pointers */
+
+// incoming characters
+volatile uint8_t income_buffer[N_INCOME_BUFFER];
+volatile uint8_t income_r = 0;
+volatile uint8_t income_w = 0;
+
+// outcoming characters
+volatile uint8_t outcome_buffer[N_OUTCOME_BUFFER];
+volatile uint8_t outcome_r = 0;
+volatile uint8_t outcome_w = 0;
+
+// incoming key press actions
+volatile uint8_t scan_buffer[N_SCAN_BUFFER];
+volatile uint8_t scan_r = 0;
+volatile uint8_t scan_w = 0;
+
+// outcoming key press actions
+volatile uint8_t print_buffer[N_PRINT_BUFFER];
+volatile uint8_t print_r = 0;
+volatile uint8_t print_w = 0;
+
+
+/* flags to keep from sleep mode*/
+volatile uint8_t keep_active=0;
+
+/* options */
+
+// operation mode of machine, flags
+uint8_t loaded_mode =    MODE_TERM; // loaded from config
+uint8_t mode =           MODE_WAIT; // actual current value
+// handling of newlines CR LF ...
+uint8_t nl_mode =        NL_CATCH_ALL | NL_SEND_CRLF;
+// handling of backspace / delete keys 0x08 or 0x7F
+uint8_t bs_mode =        BS_BS | BS_DEL;
+// escape sequence handling
+uint8_t esc_mode =       ESC_ECMA_48;
+// text print style
+volatile uint8_t style = STYLE_NORMAL; // actual current value
+uint8_t   loaded_style = STYLE_NORMAL; // loaded from config
+// how to replace unknown/invalid characters
+uint8_t replace =        REPLACE_SYMBOL;
+// continuous paper or single pages
+uint8_t paper =          PAPER_SINGLE;
+// serial interface settings
+uint8_t baud =           UART_BAUD_115200;
+uint8_t serial_mode =    UART_8N1;
+
+/* flow control */
+volatile uint8_t flow =        FLOW_FD; // flow control mode
+volatile uint8_t outcome_requested = 0; // want to send
+volatile uint8_t income_accepted =   0; // allow to receive
+volatile uint8_t send_xonoff =       0; // request to send XON / XOFF
+volatile uint8_t remote_xonoff =   XON; // state of XON/XOFF on remote machine
+volatile uint8_t local_xonoff =      0; // local state of XON/XOFF
+
+/*character encoding */
+// active encoding
+uint8_t encoding =              ENC_ISO8859_2;
+// "codepage" for converting bytes to characters
+uint8_t const * const * CH_CP = CH_ISO8859_2;
+// "keymap" for converting keys to bytes
+uint8_t const * KEYMAP_CP =     KEYMAP_ISO8859_2;
+// ECMA-35 stuff 
+uint8_t C1 = 1;         // If encoding has C1 control characters
+uint8_t GR_index = 1;   // status of "locking shift N right"
+uint8_t GR_table[4] = { // assignments to GR1, GR2, GR3
+       0,
+       ENC_ISO8859_1,
+       ENC_ISO8859_2,
+       ENC_ISO8859_2
+};
+
+/* page, line, character;
+   size, spacing, margin;
+   actual and requested position */
+
+// page size
+uint16_t pheight =     DEFAULT_PHEIGHT;
+uint16_t lwidth =      DEFAULT_LWIDTH;
+// margins
+int16_t  tmargin =     DEFAULT_TMARGIN;
+int16_t  bmargin =     DEFAULT_BMARGIN;
+int16_t  lmargin =     DEFAULT_LMARGIN;
+int16_t  lmargin_aim = DEFAULT_LMARGIN_AIM;
+int16_t  rmargin =     DEFAULT_RMARGIN;
+int16_t  rmargin_aim = DEFAULT_RMARGIN_AIM;
+// character & line spacing
+uint8_t  lheight =     HEIGHT_NORMAL;
+uint8_t  cwidth =      WIDTH_NORMAL;
+uint8_t  cwidth_aim =  WIDTH_NORMAL;
+uint8_t  cwidth_todo = 0; // reminder to update setting at next left margin
+// TAB size
+int8_t   theight_ch =  DEFAULT_THEIGHT_CH;
+int8_t   twidth_ch =   DEFAULT_TWIDTH_CH;
+// cursor position tracking
+int16_t  ppos =        0;
+int16_t  vpos =        DEFAULT_TMARGIN;
+int16_t  vpos_aim =    DEFAULT_TMARGIN;
+int16_t  hpos =        DEFAULT_LMARGIN;
+int16_t  hpos_aim =    DEFAULT_LMARGIN_AIM;
+uint8_t  out_margin =  0;
+
+// wait until next page inserted
+uint8_t wait_page =    0;
+
+// TAB positions
+uint8_t HTAB[N_HTAB];
+uint8_t VTAB[N_VTAB];
+
+// unit conversion
+uint16_t hunit_mul =   HUNIT_MUL_CH;
+uint16_t hunit_div =   HUNIT_DIV_CH;
+uint16_t vunit_mul =   VUNIT_MUL_CH;
+uint16_t vunit_div =   VUNIT_DIV_CH;
+
+// request for event
+volatile uint8_t set_led = 0;   // turn on LED
+volatile uint8_t set_alarm = 0; // make buzzer sound
+
+// EEPROM pointer
+uint16_t ee_address = 0;
+
+
+/* main interrupt */
+ISR(TIMER2_COMPA_vect);
+
+/* kezboard input */
+static inline void scan_keyboard (void);
+              void add_scan      (const uint8_t key);
+              void handle_scan   (void);
+
+/* menu */
+uint8_t handle_menu (const uint8_t key);
+
+/* keyboard output */
+              void add_print_key      (const uint8_t key);
+              void add_print_ch       (uint8_t const * const ch);
+static inline void add_print_ch_ASCII (const uint8_t ch);
+static inline void add_print_ch_CP    (const uint8_t ch);
+static inline void add_print_ch_UNI   (const uint32_t ch);
+              void add_print_str_ASCII(uint8_t const * str);
+              void add_print_str_CP   (uint8_t const * str);
+              void add_print_dec      (const uint32_t value, const uint8_t min_digits);
+              void add_print_hex      (const uint32_t value, const uint8_t min_digits);
+static inline void handle_print       (void);
+
+/* incoming characters */
+ISR(USART0_RX_vect);
+void add_income     (const uint8_t in, const uint8_t blocking);
+void add_income_str (uint8_t const * in, const uint8_t blocking);
+void add_income_dec (
+       const uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t blocking
+);
+void add_income_hex (
+       const uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t blocking
+);
+void handle_income  (void);
+
+/* hex */
+
+void handle_hex (const uint8_t cmd, const uint8_t value);
+
+/* control characters / sequences */
+uint8_t  handle_ctrl        (uint8_t in);
+uint32_t get_ctrl_parameter (
+       uint8_t * buffer,
+       uint8_t * * pos,
+       uint8_t * ind,
+       uint8_t * subind,
+       uint8_t id,
+       uint8_t subid,
+       uint32_t def
+);
+static inline void send_DSR_ok (void);
+static inline void send_CPR    (void);
+
+/* outcoming characters */
+void add_outcome     (const uint8_t out);
+void add_outcome_str (uint8_t const * out);
+void add_outcome_dec (const uint32_t value, const uint8_t min_digits);
+void add_outcome_hex (const uint32_t value, const uint8_t min_digits);
+void handle_outcome  (void);
+
+/* both way */
+static inline void add_ch (uint8_t io);
+
+/* cursor movement */
+static inline void goto_prev_page           (void);
+static inline void goto_prev_page_tmargin   (void);
+static inline void goto_next_page           (void);
+static inline void goto_next_page_tmargin   (void);
+              void move_back_page           (const uint8_t n);
+              void move_back_page_tmargin   (const uint8_t n);
+              void move_forward_page        (const uint8_t n);
+              void move_forward_page_tmargin(const uint8_t n);
+              void goto_page                (const int16_t p);
+
+              uint8_t goto_prev_line    (const uint8_t ignore_margin);
+              uint8_t goto_next_line    (const uint8_t ignore_margin);
+              void    move_back_line    (const uint8_t n, const uint8_t ignore_margin);
+              void    move_forward_line (const uint8_t n, const uint8_t ignore_margin);
+              void    goto_line         (uint8_t y);
+              void    goto_line_rel     (uint8_t y);
+static inline void    goto_prev_vstep   (void);
+static inline void    goto_next_vstep   (void);
+
+              uint8_t goto_prev_col    (const uint8_t ignore_margin);
+              uint8_t goto_next_col    (const uint8_t ignore_margin);
+              void    move_back_col    (const uint8_t n, const uint8_t ignore_margin);
+              void    move_forward_col (const uint8_t n, const uint8_t ignore_margin);
+              void    goto_col         (uint8_t x);
+              void    goto_col_rel     (uint8_t x);
+static inline void    goto_lmargin     (void);
+static inline void    goto_col0        (void);
+
+              uint8_t goto_prev_vtab    (const uint8_t ignore_margin);
+              uint8_t goto_next_vtab    (const uint8_t ignore_margin);
+              void    move_back_vtab    (const uint8_t n, const uint8_t ignore_margin);
+              void    move_forward_vtab (const uint8_t n, const uint8_t ignore_margin);
+              uint8_t is_vtab           (const int16_t y);
+              void    set_vtab          (const int16_t y);
+              void    clear_vtab        (const int16_t y);
+static inline void clear_vtab_all       (void);
+
+              uint8_t goto_prev_htab    (const uint8_t ignore_margin);
+              uint8_t goto_next_htab    (const uint8_t ignore_margin);
+              void    move_back_htab    (const uint8_t n, const uint8_t ignore_margin);
+              void    move_forward_htab (const uint8_t n, const uint8_t ignore_margin);
+              void    goto_htab         (const int8_t x, const uint8_t ignore_margin);
+              uint8_t is_htab           (const int16_t x);
+              void    set_htab          (const int16_t x);
+              void    clear_htab        (const int16_t x);
+static inline void    clear_htab_ch     (uint8_t x);
+static inline void    clear_htab_all    (void);
+
+void adjust_print_pos (void);
+
+/* size, margin, spacing */
+              void set_pheight     (const uint16_t y);
+              void set_lheight     (const uint8_t y);
+              void set_tmargin     (int16_t y);
+              void set_bmargin     (int16_t y);
+              void set_bmargin_rel (const int16_t y);
+static inline void set_tmargin_ch  (uint8_t y);
+static inline void set_bmargin_ch  (uint8_t y);
+
+              void set_lwidth      (const uint16_t x);
+              void set_cwidth      (const uint8_t x);
+              void set_lmargin     (int16_t x);
+              void set_rmargin     (int16_t x);
+              void set_rmargin_rel (const int16_t x);
+static inline void set_lmargin_ch  (uint8_t x);
+static inline void set_rmargin_ch  (uint8_t x);
+
+              void set_theight     (const uint8_t y);
+              void set_twidth      (const uint8_t x);
+static inline void set_theight_ch  (const uint8_t y);
+static inline void set_twidth_ch   (const uint8_t x);
+
+/* operating mode */
+              void set_mode          (uint8_t new_mode);
+              void become_typewriter (void);
+              void become_terminal   (void);
+
+static inline void set_baudrate      (const uint8_t setting);
+static inline void set_serial_mode   (const uint8_t setting);
+static inline void set_encoding      (const uint8_t setting);
+static inline void set_encoding_GR   (const uint8_t setting);
+              void set_flowcontrol   (uint8_t setting);
+
+              void set_style         (const uint8_t new_style);
+static inline void set_style_normal  (void);
+static inline void set_style_bold    (void);
+static inline void set_style_nobold  (void);
+static inline void toggle_bold       (void);
+static inline void set_style_under   (void);
+static inline void set_style_under2  (void);
+static inline void set_style_nounder (void);
+static inline void toggle_under      (void);
+static inline void toggle_under2     (void);
+static inline void set_style_cross   (void);
+static inline void set_style_nocross (void);
+static inline void toggle_cross      (void);
+static inline void set_style_over    (void);
+static inline void set_style_noover  (void);
+static inline void toggle_over       (void);
+static inline void set_style_strong  (void);
+static inline void set_style_weak    (void);
+
+/* flow control */
+              void    update_flowcontrol_hw (void);
+              void    update_flowcontrol_sw (void);
+static inline void    request_outcome       (void);
+static inline void    unrequest_outcome     (void);
+static inline void    accept_income         (void);
+static inline void    reject_income         (void);
+              uint8_t income_requested      (void);
+              uint8_t outcome_accepted      (void);
+
+
+/* eeprom settings storage */
+static inline uint8_t eeprom_read  (const uint16_t address);
+static inline void    eeprom_write (const uint16_t address, const uint8_t data);
+              uint8_t eeprom_read_record (
+       const uint16_t address,
+       uint8_t * const id,
+       uint16_t * const data
+);
+              void    eeprom_write_record (
+       const uint16_t address,
+       const uint8_t  id,
+       const uint16_t data
+);
+              void    eeprom_erase_record (const uint16_t address);
+              void    store_all_config    (void);
+              void    store_single_config (const uint8_t id);
+static inline void    load_config         (void);
+
+/* sleep mode */
+static inline void cancel_sleep (const uint8_t flag);
+static inline void allow_sleep  (const uint8_t flag);
+static inline void goto_sleep   (void);
+
+/* support util. */
+uint8_t make_dec_string (
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits
+);
+uint8_t make_hex_string (
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits,
+       const uint8_t uppercase
+);
+uint32_t unit (uint32_t x, const uint16_t mul, const uint16_t div);
+
+
+
+int main (void)
+{
+       /* IO */
+       
+       MCUCR |= 0b00010000; //DISABLE PULLUP
+       
+       // keyboard scan input
+       PORT_ROW = 0b00000000;
+       PORT_COL = 0b00000000;
+       DDR_ROW  = 0b00000000;
+       DDR_COL  = 0b00000000;
+       
+       // print key output
+       PORT_KEY = 0b00000000;
+       DDR_KEY  = 0b11111111;
+       
+       // ctrl state
+       PORT_CTRL = (PORT_CTRL | MASK_CTRL) & ~EN_KEYB;
+       DDR_CTRL =  (DDR_CTRL | MASK_CTRL);
+       
+       //communication
+       PORT_COMM = (PORT_COMM | MASK_COMM) & ~RX & ~SYNC_IN;
+       DDR_COMM =  (DDR_COMM & ~MASK_COMM) | TX | SYNC_OUT;
+       
+       /* UART */
+       
+       // UBRR0H = (uint8_t) ((UART_DIV[baud]-1) >> 8);
+       // UBRR0L = (uint8_t) ((UART_DIV[baud]-1) & 0xff);
+       UBRR0 = UART_DIV[baud]-1;
+       UCSR0A = (1<<U2X0); // 2x speed mode
+       UCSR0B = 
+               (1<<RXCIE0) | // enable RX int
+               // (1<<TXCIE0) | // enable TX int (complete)
+               // (1<<UDRIE0) | // enable TX int (buf free)
+               (1<<RXEN0) | (1<<TXEN0); //enable RX, enable TX
+       // UCSR0C = (3<<UCSZ00); //8n1 mode;
+       set_serial_mode(serial_mode);
+       
+       /* TIMER */
+       
+       TCCR2A = 0;
+       TCCR2B = 0;
+       TCNT2 = 0;
+       OCR2A = INT_DIV - 1;
+       TCCR2A = (1 << WGM21);  //CTC mode
+       TCCR2B = INT_PRE; // prescaler
+       TIMSK2 |= (1<<OCIE2A); //enable timer compare interrupt
+       
+       /* RESTORE SETTINGS */
+       
+       load_config(); // might enable int!
+       vpos = tmargin;
+       vpos_aim = tmargin;
+       hpos_aim = lmargin_aim;
+       
+       /* ENABLE INT */
+       
+       sei();
+       
+       /* DO THE */
+       
+       accept_income();
+       
+       goto_sleep();
+       
+       while(5)
+       {
+               handle_scan();
+               handle_income();
+               handle_outcome();
+       }
+}
+
+
+/* main interrupt */
+
+ISR(TIMER2_COMPA_vect)
+{
+       scan_keyboard();
+       
+       static uint8_t  print_timer = 0;
+       static uint16_t led_timer = 0;
+       static uint8_t  led_on = 0;
+       
+        // printing action
+       if (print_timer >= PRINT_DIV-1)
+       {
+               print_timer = 0;
+               handle_print();
+       }
+       else
+               ++print_timer;
+       
+       // LED control
+       if (led_timer >= LED_DIV-1)
+       {
+               led_timer = 0;
+               if (set_led) // there was request
+               {
+                       PORT_CTRL &= ~LED;
+                       if (set_led > led_on)
+                               led_on = set_led;
+                       set_led = 0;
+               }
+               else if(led_on) // keep until out of time
+               {
+                       --led_on;
+                       if (!led_on)
+                               PORT_CTRL |= LED;
+               }
+       }
+       ++led_timer;
+       
+       // as DCE, constant update is needed,
+       // CTS depents on buffer state and RTS
+       if ((flow & FLOW_HW) == FLOW_HD_DCE)
+               update_flowcontrol_hw();
+       
+       ++main_timer;
+       // TODO 
+       // goto_sleep();
+}
+
+
+/* kezboard input */
+
+static inline void scan_keyboard (void)
+{
+       static uint8_t base_state [8] = {0,0,0,0,0,0,0,0};
+       static uint8_t last_state [8] = {0,0,0,0,0,0,0,0};
+       
+       static uint8_t shift_state = 0;
+       static uint8_t code_state  = 0;
+       
+       static uint8_t last_row = 0b00000000;
+       static uint8_t last_col = 0b00000000;
+       static uint8_t hold_count = 0;
+       static uint8_t key_debounce[8] = {0,0,0,0,0,0,0,0};
+       static uint8_t key_repeat[8] =   {0,0,0,0,0,0,0,0};
+       
+       uint8_t row, col;
+       uint8_t ind, ind_base, ind_off;
+       uint8_t filtered_state;
+       
+       uint8_t send_event = 0;
+       
+       // get keyboard state
+       col = PIN_COL;
+       row = PIN_ROW;
+       
+       if (row == last_row) // keep measuring pulse length
+               ++hold_count;
+       else // state changed; react
+       {
+               if (hold_count >= SCAN_HOLD) // pulse was long enough;
+               {
+                       // now handle state from previous iteration, before change
+                       
+                       // get row number, accept only single row selected, prepare base value
+                       switch(last_row)
+                       {
+                       case KEYB_0:
+                               ind = 0;
+                               ind_base = KEYB_ROW_0;
+                               break;
+                       case KEYB_1:
+                               ind = 1;
+                               ind_base = KEYB_ROW_1;
+                               break;
+                       case KEYB_2:
+                               ind = 2;
+                               ind_base = KEYB_ROW_2;
+                               break;
+                       case KEYB_3:
+                               ind = 3;
+                               ind_base = KEYB_ROW_3;
+                               break;
+                       case KEYB_4:
+                               ind = 4;
+                               ind_base = KEYB_ROW_4;
+                               break;
+                       case KEYB_5:
+                               ind = 5;
+                               ind_base = KEYB_ROW_5;
+                               break;
+                       case KEYB_6:
+                               ind = 6;
+                               ind_base = KEYB_ROW_6;
+                               break;
+                       case KEYB_7:
+                               ind = 7;
+                               ind_base = KEYB_ROW_7;
+                               break;
+                       default:
+                               ind = 0xff;
+                       }
+                       
+                       // there was single row selected, signal is valid
+                       if (ind < 8)
+                       {
+                               // do some debouncing
+                               if (last_col != last_state[ind])
+                                       key_debounce[ind] = 0;
+                               else 
+                               {
+                                       if(key_debounce[ind] < SCAN_DEBOUNCE)
+                                       {
+                                               ++key_debounce[ind];
+                                               // ok, debouncing finished, key change detected
+                                               if(key_debounce[ind] == SCAN_DEBOUNCE)
+                                               {
+                                                       // prepare state, prepare repeat counter
+                                                       base_state[ind] = last_col;
+                                                       key_repeat[ind] = SCAN_DEBOUNCE - 1;
+                                                       send_event = 1;
+                                               }
+                                       }
+                               }
+                               
+                               // handle repeated event after long press
+                               if (key_repeat[ind] >= SCAN_DELAY)
+                               {
+                                       key_repeat[ind] -= SCAN_REPEAT;
+                                       send_event = 1;
+                               }
+                                       ++key_repeat[ind];
+                               
+                               // ok, now prepare and send a key press event
+                               if (send_event)
+                               {
+                                       send_event=0;
+                                       filtered_state = base_state[ind];
+                                       // special handling for SHIFT and CODE keys
+                                       if (ind==KEYB_MOD_IND)
+                                       {
+                                               shift_state = (filtered_state & KEYB_SHIFT_BIT) ? KEYB_SHIFT : 0;
+                                               code_state = (filtered_state & KEYB_CODE_BIT) ? KEYB_CODE : 0;
+                                               filtered_state &= ~(KEYB_SHIFT_BIT | KEYB_CODE_BIT);
+                                       }
+                                       // get column number, accept single row only, prepare offset value
+                                       switch (filtered_state)
+                                       {
+                                       case KEYB_0:
+                                               ind_off = KEYB_COL_0;
+                                               break;
+                                       case KEYB_1:
+                                               ind_off = KEYB_COL_1;
+                                               break;
+                                       case KEYB_2:
+                                               ind_off = KEYB_COL_2;
+                                               break;
+                                       case KEYB_3:
+                                               ind_off = KEYB_COL_3;
+                                               break;
+                                       case KEYB_4:
+                                               ind_off = KEYB_COL_4;
+                                               break;
+                                       case KEYB_5:
+                                               ind_off = KEYB_COL_5;
+                                               break;
+                                       case KEYB_6:
+                                               ind_off = KEYB_COL_6;
+                                               break;
+                                       case KEYB_7:
+                                               ind_off = KEYB_COL_7;
+                                               break;
+                                       default:
+                                               ind_off = 0xff;
+                                               break;
+                                       }
+                                       // single column, signal still valid
+                                       if (ind_off <= KEYB_COL_7)
+                                       {
+                                               // generate the correct event
+                                               add_scan(ind_base | ind_off | shift_state | code_state);
+                                       }
+                               }
+                               last_state[ind] = last_col;
+                       }
+               }
+               hold_count=0;
+       }
+       last_row = row;
+       last_col = col;
+}
+
+void add_scan (const uint8_t key)
+{
+       // buffer is full, keyboard event will be lost
+       if (FULL_BP(scan_w, scan_r, N_SCAN_BUFFER))
+       {
+               set_led = 10;
+               set_alarm = 1;
+               return;
+       }
+       
+       scan_buffer[scan_w] = key;
+       ADVANCE_BP(scan_w, N_SCAN_BUFFER);
+       
+       // can't sleep when there are keys to handle
+       cancel_sleep(WAKEUP_SCAN);
+}
+
+void handle_scan (void)
+{
+       uint8_t key;
+       uint8_t ch;
+       uint16_t uni_ch;
+       uint8_t  uni_bytes;
+       uint8_t  uni_buffer[3];
+       
+       static uint8_t ctrl = 0;
+       
+       cli();
+       if (EMPTY_BP(scan_w, scan_r, N_SCAN_BUFFER))
+       {
+               sei();
+               allow_sleep(WAKEUP_SCAN);
+       }
+       else
+       {
+               sei();
+               
+               key = scan_buffer[scan_r];
+               ADVANCE_BP(scan_r, N_SCAN_BUFFER);
+               
+               // first event since startup is a key press
+               // start working as a normal typewriter
+               // (unless special combination, then be terminal instead)
+               if (mode == MODE_WAIT)
+               {
+                       if (key & (KEYB_SHIFT|KEYB_CODE))
+                               become_terminal();
+                       else
+                               become_typewriter();
+               }
+               
+               // only handle keyboard input if in terminal mode 
+               if (mode & MODE_TERM)
+               {
+                       switch (key)
+                       {
+                       // new page
+                       case QMENU_PAGE: // new page inserted
+                               if (!wait_page)
+                                       break;
+                       case QMENU_FPAGE: // force reset to page top
+                               vpos = tmargin;
+                               vpos_aim = tmargin;
+                               wait_page = 0;
+                               set_alarm = 1;
+                               break;
+                       // some style change
+                       case QMENU_BOLD:
+                               toggle_bold();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_UNDER:
+                               toggle_under();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_UNDER2:
+                               toggle_under2();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_CROSS:
+                               toggle_cross();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_OVER:
+                               toggle_over();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_STRONG:
+                               set_style_strong();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_WEAK:
+                               set_style_weak();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       // line & char. spacing
+                       case QMENU_6LPI:
+                               set_lheight(HEIGHT_6);
+                               store_single_config(ID_LHEIGHT);
+                               set_alarm=1;
+                               break;
+                       case QMENU_4LPI:
+                               set_lheight(HEIGHT_4);
+                               store_single_config(ID_LHEIGHT);
+                               set_alarm=1;
+                               break;
+                       case QMENU_3LPI:
+                               set_lheight(HEIGHT_3);
+                               store_single_config(ID_LHEIGHT);
+                               set_alarm=1;
+                               break;
+                       case QMENU_10CPI:
+                               set_cwidth(WIDTH_10);
+                               store_single_config(ID_CWIDTH);
+                               set_alarm=1;
+                               break;
+                       case QMENU_12CPI:
+                               set_cwidth(WIDTH_12);
+                               store_single_config(ID_CWIDTH);
+                               set_alarm=1;
+                               break;
+                       // hex
+                       case QMENU_HEX:
+                               set_mode(mode ^ MODE_HEX);
+                               store_single_config(ID_MODE);
+                               set_alarm=1;
+                               break;
+                       // local echo
+                       case QMENU_ECHO:
+                               set_mode(mode ^ MODE_ECHO);
+                               store_single_config(ID_MODE);
+                               set_alarm=1;
+                               break;
+                       // paper type
+                       case QMENU_PAPER:
+                               if (paper == PAPER_SINGLE)
+                                       paper = PAPER_CONTINUOUS;
+                               else
+                                       paper = PAPER_SINGLE;
+                               store_single_config(ID_PAPER);
+                               set_alarm=1;
+                               break;
+                       // exit terminal mode, be a normal typewriter now
+                       case QMENU_EXIT:
+                               become_typewriter();
+                               break;
+                       // not a function key
+                       default:
+                               // First, perform menu handling, if relevant
+                               if (handle_menu(key))
+                                       ctrl = 0;
+                               else
+                               {
+                                       switch(key)
+                                       {
+                                       case KEY_BACK: // backspace
+                                               add_ch((bs_mode & BS_BS) ? 0x08 : 0x7f);
+                                               break;
+                                       case KEY_ERASE1: // delete
+                                               add_ch((bs_mode & BS_DEL)  ? 0x7f : 0x08);
+                                               break;
+                                       case KEY_ERASEW: // ctrl
+                                               ctrl = 1;
+                                               break;
+                                       case KEY_RETURN: // newline
+                                       case SKEY_RETURN:
+                                               if (nl_mode & NL_SEND_CR)
+                                                       add_ch('\r');
+                                               if (nl_mode & NL_SEND_LF)
+                                                       add_ch('\n');
+                                               break;
+                                       default: // "normal" key; just consult keymap
+                                               if (encoding & ENC_UNI) // UTF-8
+                                               {
+                                                       uni_ch = KEYMAP_UNI[key];
+                                                       
+                                                       if (uni_ch >= 0x0080) // multi-byte code point
+                                                       {
+                                                               uni_buffer[0] = 0b10000000;
+                                                               if (uni_ch >= 0x0800)
+                                                               {
+                                                                       uni_bytes = 3;
+                                                                       uni_buffer[1] = 0b10000000;
+                                                                       uni_buffer[2] = 0b11100000;
+                                                               }
+                                                               else
+                                                               {
+                                                                       uni_bytes = 2;
+                                                                       uni_buffer[1] = 0b11000000;
+                                                               }
+                                                               uni_buffer[0] |= uni_ch & 0b00111111;
+                                                               uni_ch >>= 6;
+                                                               uni_buffer[1] |= uni_ch & 0b00111111;
+                                                               uni_ch >>= 6;
+                                                               uni_buffer[2] |= uni_ch;
+                                                               while (uni_bytes)
+                                                               {
+                                                                       --uni_bytes;
+                                                                       add_ch(uni_buffer[uni_bytes]);
+                                                               }
+                                                       }
+                                                       else if (uni_ch)
+                                                       {
+                                                               if (ctrl) // CTRL + key
+                                                               {
+                                                                       uni_ch &= 0x1f;
+                                                                       ctrl = 0;
+                                                               }
+                                                               add_ch(uni_ch);
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       ch = KEYMAP_CP[key];
+                                                       if (ch)
+                                                       {
+                                                               if (ctrl) // CTRL + key
+                                                               {
+                                                                       ch &= 0x1f;
+                                                                       ctrl = 0;
+                                                               }
+                                                               add_ch(ch);
+                                                       }
+                                               }
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+
+/* menu */
+
+uint8_t handle_menu (const uint8_t key)
+{
+       static uint8_t  menu_active = 0;
+       static uint8_t  function = MENU_NONE;
+       static uint8_t  allow_output = 0;
+       static uint16_t value=0;
+       uint8_t x;
+       
+       if (!menu_active) // we're not in menu yet
+       {
+               if (key == MENU_ENTER) // let's enter menu
+               {
+                       menu_active = 1;
+                       function = MENU_NONE;
+                       allow_output = 0;
+                       set_alarm = 1;
+               }
+       }
+       else if (function == MENU_NONE) // in menu, no function chosen
+       {
+               function = key;
+               value = 0;
+               switch (key)
+               {
+               case MENU_ENTER: // enable printing in menu
+               case MENU_OUTPUT:
+                       function = MENU_NONE;
+                       allow_output = 1;
+                       add_income_str(TEXT_MENU_LIST, 1);
+                       set_alarm = 1;
+                       break;
+               case MENU_EXIT: // leave the menu
+               case MENU_CONFIRM:
+                       menu_active = 0;
+                       if (allow_output) add_income_str(TEXT_MENU_EXIT, 1);
+                       set_alarm = 3;
+                       // we don't want to return actual status this time
+                       // it would treat the menu exit key as normal terminal action
+                       return 1;
+               case MENU_BAUD:
+                       if (allow_output) add_income_str(TEXT_MENU_BAUD, 1);
+                       break;
+               case MENU_BITS:
+                       if (allow_output) add_income_str(TEXT_MENU_BITS, 1);
+                       break;
+               case MENU_FLOW:
+                       if (allow_output) add_income_str(TEXT_MENU_FLOW, 1);
+                       break;
+               case MENU_ECHO:
+                       if (allow_output) add_income_str(TEXT_MENU_ECHO, 1);
+                       break;
+               case MENU_DELETE:
+                       if (allow_output) add_income_str(TEXT_MENU_DELETE, 1);
+                       break;
+               case MENU_NEWLINE:
+                       if (allow_output) add_income_str(TEXT_MENU_NEWLINE, 1);
+                       break;
+               case MENU_REPLACE:
+                       if (allow_output) add_income_str(TEXT_MENU_REPLACE, 1);
+                       break;
+               case MENU_ENCODING:
+                       if (allow_output) add_income_str(TEXT_MENU_ENCODING, 1);
+                       break;
+               case MENU_PWIDTH:
+                       if (allow_output) add_income_str(TEXT_MENU_PWIDTH, 1);
+                       break;
+               case MENU_LMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_LMARGIN, 1);
+                       break;
+               case MENU_RMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_RMARGIN, 1);
+                       break;
+               case MENU_TWIDTH:
+                       if (allow_output) add_income_str(TEXT_MENU_TWIDTH, 1);
+                       break;
+               case MENU_PHEIGHT:
+                       if (allow_output) add_income_str(TEXT_MENU_PHEIGHT, 1);
+                       break;
+               case MENU_TMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_TMARGIN, 1);
+                       break;
+               case MENU_BMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_BMARGIN, 1);
+                       break;
+               case MENU_THEIGHT:
+                       if (allow_output) add_income_str(TEXT_MENU_THEIGHT, 1);
+                       break;
+               case MENU_HTAB:
+                       if (allow_output) add_income_str(TEXT_MENU_HTAB, 1);
+                       break;
+               case MENU_VTAB:
+                       if (allow_output) add_income_str(TEXT_MENU_VTAB, 1);
+                       break;
+               case MENU_CWIDTH:
+                       if (allow_output) add_income_str(TEXT_MENU_CWIDTH, 1);
+                       break;
+               case MENU_LHEIGHT:
+                       if (allow_output) add_income_str(TEXT_MENU_LHEIGHT, 1);
+                       break;
+               case MENU_PAPER:
+                       if (allow_output) add_income_str(TEXT_MENU_PAPER, 1);
+                       break;
+               default:
+                       function = MENU_NONE;
+               }
+               if (function != MENU_NONE)
+                       set_alarm = 2;
+       }
+       else // in menu, function already chosen
+       {
+               switch(key)
+               {
+               case KEY_0: // digit; update value
+               case KEY_1:
+               case KEY_2:
+               case KEY_3:
+               case KEY_4:
+               case KEY_5:
+               case KEY_6:
+               case KEY_7:
+               case KEY_8:
+               case KEY_9:
+                       x=KEYMAP_LIST[0][key];
+                       if(allow_output)
+                               add_income(x, 1);
+                       value *= 10;
+                       value += x-0x30;
+                       set_alarm = 1;
+                       break;
+               case MENU_EXIT: // cancel input
+                       function = MENU_NONE;
+                       if(allow_output)
+                               add_income_str(TEXT_MENU_CANCEL, 1);
+                       set_alarm = 2;
+                       break;
+               case MENU_ENTER: // enable printing, cancel input
+               case MENU_OUTPUT:
+                       function = MENU_NONE;
+                       if(allow_output)
+                               add_income_str(TEXT_MENU_LIST, 1);
+                       set_alarm = 2;
+               case MENU_CONFIRM: // confirm value
+                       switch (function)
+                       {
+                       case MENU_BAUD:
+                               switch (value)
+                               {
+                               case UM16_134_5:
+                                       value = UART_BAUD_134_5;
+                                       break;
+                               case UM16_150:
+                                       value = UART_BAUD_150;
+                                       break;
+                               case UM16_200:
+                                       value = UART_BAUD_200;
+                                       break;
+                               case UM16_300:
+                                       value = UART_BAUD_300;
+                                       break;
+                               case UM16_600:
+                                       value = UART_BAUD_600;
+                                       break;
+                               case UM16_1200:
+                                       value = UART_BAUD_1200;
+                                       break;
+                               case UM16_1800:
+                                       value = UART_BAUD_1800;
+                                       break;
+                               case UM16_2400:
+                                       value = UART_BAUD_2400;
+                                       break;
+                               case UM16_4800:
+                                       value = UART_BAUD_4800;
+                                       break;
+                               case UM16_7200:
+                                       value = UART_BAUD_7200;
+                                       break;
+                               case UM16_9600:
+                                       value = UART_BAUD_9600;
+                                       break;
+                               case UM16_14400:
+                                       value = UART_BAUD_14400;
+                                       break;
+                               case UM16_19200:
+                                       value = UART_BAUD_19200;
+                                       break;
+                               case UM16_28800:
+                                       value = UART_BAUD_28800;
+                                       break;
+                               case UM16_31250:
+                                       value = UART_BAUD_31250;
+                                       break;
+                               case UM16_38400:
+                                       value = UART_BAUD_38400;
+                                       break;
+                               case UM16_57600:
+                                       value = UART_BAUD_57600;
+                                       break;
+                               case UM16_76800:
+                                       value = UART_BAUD_76800;
+                                       break;
+                               case UM16_115200:
+                                       value = UART_BAUD_115200;
+                                       break;
+                               case UM16_125000:
+                                       value = UART_BAUD_125000;
+                                       break;
+                               case UM16_250000:
+                                       value = UART_BAUD_250000;
+                                       break;
+                               case UART_BAUD_134_5:
+                               case UART_BAUD_150:
+                               case UART_BAUD_200:
+                               case UART_BAUD_300:
+                               case UART_BAUD_600:
+                               case UART_BAUD_1200:
+                               case UART_BAUD_1800:
+                               case UART_BAUD_2400:
+                               case UART_BAUD_4800:
+                               case UART_BAUD_7200:
+                               case UART_BAUD_9600:
+                               case UART_BAUD_14400:
+                               case UART_BAUD_19200:
+                               case UART_BAUD_28800:
+                               case UART_BAUD_31250:
+                               case UART_BAUD_38400:
+                               case UART_BAUD_57600:
+                               case UART_BAUD_76800:
+                               case UART_BAUD_115200:
+                               case UART_BAUD_125000:
+                               case UART_BAUD_250000:
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_baudrate(value);
+                                       store_single_config(ID_BAUD);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_BITS:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = UART_8N1;
+                                       break;
+                               case 2:
+                                       value = UART_8E1;
+                                       break;
+                               case 3:
+                                       value = UART_8O1;
+                                       break;
+                               case 4:
+                                       value = UART_8N2;
+                                       break;
+                               case 5:
+                                       value = UART_8E2;
+                                       break;
+                               case 6:
+                                       value = UART_8O2;
+                                       break;
+                               case 7:
+                                       value = UART_7N1;
+                                       break;
+                               case 8:
+                                       value = UART_7E1;
+                                       break;
+                               case 9:
+                                       value = UART_7O1;
+                                       break;
+                               case 10:
+                                       value = UART_7N2;
+                                       break;
+                               case 11:
+                                       value = UART_7E2;
+                                       break;
+                               case 12:
+                                       value = UART_7O2;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_serial_mode(value);
+                                       store_single_config(ID_BITS);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_FLOW:
+                               switch (value)
+                               {
+                               case 1: // RTR/CTS
+                                       value = (flow & ~FLOW_HW) | FLOW_FD;
+                                       break;
+                               case 2: // RTS/CTS, we're the DTE
+                                       value = (flow & ~FLOW_HW) | FLOW_HD_DTE;
+                                       break;
+                               case 3: // RTS/CTS, we're the DCE
+                                       value = (flow & ~FLOW_HW) | FLOW_HD_DCE;
+                                       break;
+                               case 4:
+                                       value = (flow & ~FLOW_HW) | FLOW_NONE;
+                                       break;
+                               case 5:
+                                       value = (flow & ~FLOW_SW) | FLOW_XONOFF;
+                                       break;
+                               case 6:
+                                       value = (flow & ~FLOW_SW) | FLOW_NONE;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_flowcontrol(value);
+                                       store_single_config(ID_FLOW);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_ECHO:
+                               switch (value)
+                               {
+                               case 1:
+                                       set_mode(mode | MODE_ECHO);
+                                       break;
+                               case 2:
+                                       set_mode(mode & ~MODE_ECHO);
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_MODE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_NEWLINE:
+                               switch (value)
+                               {
+                               case 1: // receive CR -> CR LF
+                                       nl_mode = (nl_mode & ~NL_IMPLICIT_CR) | NL_IMPLICIT_LF;
+                                       break;
+                               case 2: // receive LF -> CR LF
+                                       nl_mode = (nl_mode & ~NL_IMPLICIT_LF) | NL_IMPLICIT_CR;
+                                       break;
+                               case 3: // receive CR or LF -> CR LF
+                                       nl_mode |= NL_CATCH_ALL;
+                                       break;
+                               case 4: // no change
+                                       nl_mode &= ~NL_CATCH_ALL;
+                                       break;
+                               case 5: // send CR
+                                       nl_mode = (nl_mode & ~NL_SEND_LF) | NL_SEND_CR;
+                                       break;
+                               case 6: // send LF
+                                       nl_mode = (nl_mode & ~NL_SEND_CR) | NL_SEND_LF;
+                                       break;
+                               case 7: // send CR LF
+                                       nl_mode |= NL_SEND_CRLF;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_MODE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_DELETE:
+                               switch (value)
+                               {
+                               case 1: // BACKSPACE is 08
+                                       bs_mode |= BS_BS;
+                                       break;
+                               case 2: // BACKSPACE is 7F
+                                       bs_mode &= ~BS_BS;
+                                       break;
+                               case 3: // DELETE is 7F
+                                       bs_mode |= BS_DEL;
+                                       break;
+                               case 4: // DELETE is 08
+                                       bs_mode &= ~BS_DEL;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_BS_MODE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_REPLACE:
+                               switch (value)
+                               {
+                               case 1: // <?>
+                                       replace = REPLACE_SYMBOL;
+                                       break;
+                               case 2: // ?
+                                       replace = REPLACE_QUEST;
+                                       break;
+                               case 3: // _
+                                       replace = REPLACE_UNDER;
+                                       break;
+                               case 4: // SPACE
+                                       replace = REPLACE_SPACE;
+                                       break;
+                               case 5: // IGNORE
+                                       replace = REPLACE_IGNORE;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_REPLACE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_ENCODING:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = ENC_ISO8859_1;
+                                       break;
+                               case 2:
+                                       value = ENC_ISO8859_2;
+                                       break;
+                               case 3:
+                                       value = ENC_ISO8859_3;
+                                       break;
+                               case 4:
+                                       value = ENC_ISO8859_4;
+                                       break;
+                               case 9:
+                                       value = ENC_ISO8859_9;
+                                       break;
+                               case 10:
+                                       value = ENC_ISO8859_10;
+                                       break;
+                               case 13:
+                                       value = ENC_ISO8859_13;
+                                       break;
+                               case 15:
+                                       value = ENC_ISO8859_15;
+                                       break;
+                               case 16:
+                                       value = ENC_ISO8859_16;
+                                       break;
+                               case 1250:
+                                       value = ENC_CP1250;
+                                       break;
+                               case 852:
+                                       value = ENC_CP852;
+                                       break;
+                               case 8: // UTF-8
+                                       value = encoding | ENC_UNI;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                                       break;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_encoding(value);
+                                       store_single_config(ID_ENCODING);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_PWIDTH:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= cwidth_aim;
+                                       if (value > HPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_lwidth(value);
+                                               store_single_config(ID_LWIDTH);
+                                               store_single_config(ID_LMARGIN);
+                                               store_single_config(ID_RMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_LMARGIN:
+                               value *= cwidth_aim;
+                               if (value > (HPOS_LIMIT - cwidth_aim))
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_lmargin(value);
+                                       store_single_config(ID_LWIDTH);
+                                       store_single_config(ID_LMARGIN);
+                                       store_single_config(ID_RMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_RMARGIN:
+                               value *= cwidth_aim;
+                               if (value > (lwidth - cwidth_aim))
+                                       value = 0xffff;
+                               else
+                               {
+                                       value = lwidth - value;
+                                       set_rmargin(value);
+                                       store_single_config(ID_LWIDTH);
+                                       store_single_config(ID_LMARGIN);
+                                       store_single_config(ID_RMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_TWIDTH:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= cwidth_aim;
+                                       value += lmargin_aim;
+                                       if (value > HPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_rmargin(value);
+                                               store_single_config(ID_LWIDTH);
+                                               store_single_config(ID_LMARGIN);
+                                               store_single_config(ID_RMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_PHEIGHT:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= lheight;
+                                       if (value > VPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_pheight(value);
+                                               store_single_config(ID_PHEIGHT);
+                                               store_single_config(ID_TMARGIN);
+                                               store_single_config(ID_BMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_TMARGIN:
+                               value *= lheight;
+                               if (value > (VPOS_LIMIT - lheight))
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_tmargin(value);
+                                       store_single_config(ID_PHEIGHT);
+                                       store_single_config(ID_TMARGIN);
+                                       store_single_config(ID_BMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_BMARGIN:
+                               value *= lheight;
+                               if (value > (pheight - lheight))
+                                       value = 0xffff;
+                               else
+                               {
+                                       value = pheight - value;
+                                       set_bmargin(value);
+                                       store_single_config(ID_PHEIGHT);
+                                       store_single_config(ID_TMARGIN);
+                                       store_single_config(ID_BMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_THEIGHT:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= lheight;
+                                       value += tmargin;
+                                       if (value > VPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_bmargin(value);
+                                               store_single_config(ID_PHEIGHT);
+                                               store_single_config(ID_TMARGIN);
+                                               store_single_config(ID_BMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_HTAB:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_twidth_ch(value);
+                                       store_single_config(ID_HTAB);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_VTAB:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_theight_ch(value);
+                                       store_single_config(ID_VTAB);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_CWIDTH:
+                               switch (value) // CPI
+                               {
+                               case 15:
+                                       value = WIDTH_15;
+                                       break;
+                               case 12:
+                                       value = WIDTH_12;
+                                       break;
+                               case 10:
+                                       value = WIDTH_10;
+                                       break;
+                               case 6:
+                                       value = WIDTH_6;
+                                       break;
+                               case 4:
+                                       value = WIDTH_4;
+                                       break;
+                               case 3:
+                                       value = WIDTH_3;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_cwidth(value);
+                                       store_single_config(ID_CWIDTH);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_LHEIGHT:
+                               switch (value) // LPI
+                               {
+                               case 6:
+                                       value = HEIGHT_6;
+                                       break;
+                               case 4:
+                                       value = HEIGHT_4;
+                                       break;
+                               case 3:
+                                       value = HEIGHT_3;
+                                       break;
+                               case 2:
+                                       value = HEIGHT_2;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_lheight(value);
+                                       store_single_config(ID_CWIDTH);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_PAPER:
+                               switch (value)
+                               {
+                                       case 1:
+                                               value = PAPER_CONTINUOUS;
+                                               break;
+                                       case 2:
+                                               value = PAPER_SINGLE;
+                                               break;
+                                       default:
+                                               value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       paper = value;
+                                       store_single_config(ID_PAPER);
+                                       value = 0;
+                               }
+                               break;
+                       default:
+                               value = 1;
+                       }
+                       function = MENU_NONE;
+                       if (!value)
+                       {
+                               if(allow_output)
+                                       add_income_str(TEXT_MENU_OK, 1);
+                               set_alarm = 2;
+                       }
+                       else
+                       {
+                               if(allow_output)
+                                       add_income_str(TEXT_MENU_FAIL, 1);
+                               set_alarm = 5;
+                       }
+                       break;
+               }
+       }
+       
+       return menu_active;
+}
+
+
+/* keyboard output */
+
+void add_print_key (const uint8_t key)
+{
+       while (FULL_BP(print_w, print_r, N_PRINT_BUFFER))
+       {
+               // wait for space in buffer
+               // interrupt will do it
+       }
+       print_buffer[print_w] = key;
+       ADVANCE_BP(print_w, N_PRINT_BUFFER);
+       
+       last_print_time = main_timer;
+}
+
+void add_print_ch (uint8_t const * const ch)
+{
+       uint8_t const * p; 
+       uint8_t count;
+       
+       // prepare position before
+       // often redundant but not always
+       adjust_print_pos();
+       
+       p = ch;
+       
+       // replacement symbol for unknown char
+       if (p == CH_UNKN)
+               p = REPLACE[replace];
+       
+       // nothing to print
+       if (*p == 0)
+               return;
+       
+       // add key sequence to buffer
+       for (count = *p; count!=0; --count)
+       {
+               ++p;
+               add_print_key(*p);
+       }
+       
+       // manually apply styles not handled automatically
+       if (style & STYLE_UNDER)
+       {
+               add_print_key(KEY_BACK);
+               add_print_key(SKEY_UNDER);
+       }
+       if (style & (STYLE_CROSS|STYLE_OVER))
+       {
+               add_print_key(CODE_HALFUP);
+               if (style & STYLE_CROSS)
+               {
+                       add_print_key(KEY_BACK);
+                       add_print_key(SKEY_UNDER);
+               }
+               if (style & STYLE_OVER)
+               {
+                       add_print_key(CODE_HALFUP);
+                       add_print_key(KEY_BACK);
+                       add_print_key(SKEY_UNDER);
+                       add_print_key(CODE_HALFDOWN);
+               }
+               add_print_key(CODE_HALFDOWN);
+       }
+       if (style & STYLE_UNDER2)
+       {
+               add_print_key(CODE_HALFDOWN);
+               add_print_key(KEY_BACK);
+               add_print_key(SKEY_EQ);
+               add_print_key(CODE_HALFUP);
+       }
+       
+       // adjust position
+       hpos += cwidth;
+       hpos_aim += cwidth_aim;
+       
+       // moved out of line; adjust again
+       if ((hpos_aim + cwidth_aim) > rmargin_aim)
+               adjust_print_pos();
+}
+
+// low level; no newlines & stuff
+
+static inline void add_print_ch_ASCII (const uint8_t ch)
+{
+       add_print_ch(CH_ASCII[ch & 0b01111111]);
+}
+
+static inline void add_print_ch_CP (const uint8_t ch)
+{
+       if (ch & 0b10000000)
+               add_print_ch(CH_CP[ch]);
+       else
+               add_print_ch(CH_ASCII[ch]);
+}
+
+static inline void add_print_ch_UNI (const uint32_t ch)
+{
+       if (ch < CH_LIMIT)
+               add_print_ch(UNI_TABLE[ch]);
+       else
+               add_print_ch(CH_UNKN);
+}
+
+void add_print_str_ASCII (uint8_t const * str)
+{
+       uint8_t const * p;
+       
+       for (p = str; *p != 0x00; ++p)
+               add_print_ch_ASCII(*p);
+}
+
+void add_print_str_CP (uint8_t const * str)
+{
+       uint8_t const * p;
+       
+       for (p = str; *p != 0x00; ++p)
+               add_print_ch_CP(*p);
+}
+
+void add_print_dec (
+       const uint32_t value,
+       const uint8_t min_digits
+)
+{
+       uint8_t text[11];
+       uint8_t x;
+       
+       x = make_dec_string(
+               text,
+               value,
+               min_digits,
+               10
+       );
+       text[x] = 0x00;
+       add_print_str_ASCII(text);
+}
+
+void add_print_hex (
+       const uint32_t value,
+       const uint8_t min_digits
+)
+{
+       uint8_t text[9];
+       uint8_t x;
+       
+       x = make_hex_string(
+               text,
+               value,
+               min_digits,
+               8,
+               1
+       );
+       text[x] = 0x00;
+       add_print_str_ASCII(text);
+}
+
+static inline void handle_print (void)
+{
+       static uint8_t phase=0;
+       static uint8_t count=0;
+       static uint8_t delay=255;
+       static uint8_t alarm=0;
+       
+       uint8_t key;
+       static uint8_t prev = CODE_BELL;
+       
+       if (set_alarm) // there was request for buzzer
+       {
+               if (set_alarm > alarm)
+                       alarm = set_alarm;
+               set_alarm = 0;
+       }
+       
+       if (!phase) // free to print next key
+       {
+               if (delay || alarm)
+               {
+                       last_print_time = main_timer;
+                       
+                       if (alarm) // insert buzzer action
+                       {
+                               PORT_KEY = CODE_BELL;
+                               phase = 3;
+                               --alarm;
+                       }
+                       if (delay) // wait for Carriage Return
+                               --delay;
+               }
+               else if (!(mode & MODE_TERM)) // we're not in terminal mode
+               {
+               }
+               else if (NOT_EMPTY_BP(print_w, print_r, N_PRINT_BUFFER)) // key press available in buffer
+               {
+                       key = print_buffer[print_r];
+                       ADVANCE_BP(print_r, N_PRINT_BUFFER);
+                       
+                       if ((key == CODE_STEPLEFT_EXTRA) && (cwidth == WIDTH_NORMAL))
+                       {
+                               // 10 CPI has 6 microspaces in char, 12 CPI has 5
+                               // 6th microspace must be ignored for 12 CPI
+                       }
+                       else
+                       {
+                               last_print_time = main_timer;
+                               
+                               PORT_KEY = key; // select key, press SHIFT, CODE
+                               phase = 3;
+                               
+                               switch (key)
+                               {
+                               case CODE_RETURN: // carriage return; activate the delay
+                               case KEY_RETURN:
+                                       delay = count;
+                                       count = 0;
+                                       break;
+                               case KEY_BACK: // going left; reduce CR delay
+                                       if (count >= PRINT_DELAY)
+                                               count -= PRINT_DELAY;
+                                       else
+                                               count = 0;
+                                       break;
+                               case CODE_STEPLEFT: // minimally going left
+                               case CODE_HALFUP:  // staying in place; don't change CR delay
+                               case CODE_HALFDOWN:
+                                       break;
+                               default: // going right (???); increase CR delay
+                                       if (count < 0xff - PRINT_DELAY)
+                                               count += PRINT_DELAY;
+                                       else
+                                               count = 0xff;
+                                       if (style & STYLE_BOLD) // multi-strike takes more time
+                                               phase += 2;
+                               }
+                               switch(prev) // movement back takes extra time
+                               {
+                               case CODE_STEPLEFT:
+                               case CODE_STEPLEFT_EXTRA:
+                               case CODE_HALFUP:
+                                       phase += 2; // slightly increase wait before key
+                               }
+                               prev = key;
+                       }
+               }
+               else // no key waiting
+               {
+                       PORT_KEY &= ~(KEYB_SHIFT | KEYB_CODE); // release SHIFT and CODE
+               }
+       }
+       else // continue ongoing key action
+       {
+               last_print_time = main_timer;
+               
+               if (phase == 3) // key down
+                       PORT_CTRL &= ~KEY;
+               else if (phase == 1) // key up
+                       PORT_CTRL |= KEY;
+               --phase;
+       }
+}
+
+
+/* incoming characters */
+
+ISR(USART0_RX_vect)
+{
+       uint8_t in, err;
+       
+       err = UCSR0A & ((1 << FE0) | (1 << UPE0)); // check error
+       in = UDR0; // get the byte
+       
+       if (err) // reject error
+               return;
+       
+       if ((flow & FLOW_SW) == FLOW_XONOFF)
+       {
+               // XON, XOFF received, update status
+               if ((in == XON) || (in == XOFF))
+               {
+                       remote_xonoff = in;
+                       return;
+               }
+       }
+       
+       // reject byte if DTE didn't assert RTS
+       // (only effective if we're DCE in RTS/CTS mode)
+       if (!income_requested())
+               return;
+       
+       // accept byte
+       add_income(in, 0);
+}
+
+void add_income (
+       const uint8_t in,
+       const uint8_t blocking
+)
+{
+       while (FULL_BP(income_w, income_r, N_INCOME_BUFFER)) // no place in buffer
+       {
+               if (blocking) // we must wait
+                       handle_income(); // perform input handling to free space in buffer
+               else // we cannot wait, input is lost!
+               {
+                       set_led = 10;
+                       set_alarm = 1;
+                       reject_income();
+                       return;
+               }
+       }
+       
+       set_led = 2; // show that something is happening
+       
+       income_buffer[income_w] = in;
+       ADVANCE_BP(income_w, N_INCOME_BUFFER);
+       
+       if (DIFF_BP(income_w, income_r, N_INCOME_BUFFER) >= INCOME_BUFFER_HIGH)
+       {
+               // buffer getting full, don't accept new input (flow control)
+               reject_income();
+       }
+       
+       // can't go to sleep when there is unhandled data in buffer
+       cancel_sleep(WAKEUP_INCOME);
+}
+
+void add_income_str (
+       uint8_t const * in,
+       const uint8_t blocking
+)
+{
+       uint8_t const * p;
+       
+       for (p = in; *p != 0x00; ++p)
+               add_income(*p, blocking);
+}
+
+void add_income_dec (
+       const uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t blocking
+)
+{
+       uint8_t text[11];
+       uint8_t x;
+       
+       x = make_dec_string(
+               text,
+               value,
+               min_digits,
+               10
+       );
+       text[x] = 0x00;
+       add_income_str(text, blocking);
+}
+
+void add_income_hex (
+       const uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t blocking
+)
+{
+       uint8_t text[9];
+       uint8_t x;
+       
+       x = make_hex_string(
+               text,
+               value,
+               min_digits,
+               8,
+               1
+       );
+       text[x] = 0x00;
+       add_income_str(text, blocking);
+}
+
+void handle_income (void)
+{
+       uint8_t in;
+       
+       static uint8_t  uni_bytes = 0;
+       static uint32_t uni_ch = 0; 
+       
+       uint8_t uni_ctrl;
+       
+       // wait until next page is inserted
+       if (wait_page)
+       {
+               if (paper == PAPER_CONTINUOUS)
+                       wait_page = 0;
+               else
+               {
+                       set_led = 2;
+                       return;
+               }
+       }
+       
+       cli();
+       if (EMPTY_BP(income_w, income_r, N_BUFER_INCOME))
+       {
+               sei();
+               // nothing left in buffer
+               if (mode & MODE_HEX)
+                       handle_hex(HEX_NOTHING, 0);
+               
+               accept_income(); // allow remote machine to send data (flow control)
+               allow_sleep(WAKEUP_INCOME);
+       }
+       else
+       {
+               sei();
+               
+               in = income_buffer[income_r];
+               ADVANCE_BP(income_r, N_INCOME_BUFFER);
+               
+               if (DIFF_BP(income_w, income_r, N_INCOME_BUFFER) < INCOME_BUFFER_LOW) // buffer getting free
+                       accept_income(); // allow remote machine to send data (flow control)
+               
+               // first event was received data; goto terminal mode
+               if (mode == MODE_WAIT)
+                       become_terminal();
+               
+               if (mode & MODE_TERM) // only if we are in terminal mode
+               {
+                       if (mode & MODE_HEX) // HEX
+                               handle_hex(HEX_AVAILABLE, in);
+                       else if (encoding & ENC_UNI) // UTF-8
+                       {
+                               if ((in & 0b11000000) == 0b10000000) // continuation of sequence
+                               {
+                                       if (uni_bytes) // byte was expected. handle it
+                                       {
+                                               uni_ch <<= 6;
+                                               uni_ch |= in & 0b00111111;
+                                               --uni_bytes;
+                                               if (!uni_bytes) // finished
+                                               {
+                                                       /* nothing else to do here */
+                                               }
+                                       }
+                                       else // unexpected continuation byte
+                                               uni_ch = -1;
+                               }
+                               else // new
+                               {
+                                       if (uni_bytes) // continuation was expected
+                                       {
+                                               handle_ctrl(0xFF);
+                                               add_print_ch(CH_UNKN);
+                                       }
+                                       if ((in & 0b10000000) == 0b00000000) // 1 byte
+                                       {
+                                               uni_ch = in;
+                                               uni_bytes = 0;
+                                       }
+                                       else if ((in & 0b11100000) == 0b11000000) // 2 byte
+                                       {
+                                               uni_ch = in & 0b00011111;
+                                               uni_bytes = 1;
+                                       }
+                                       else if ((in & 0b11110000) == 0b11100000) // 3 byte
+                                       {
+                                               uni_ch = in & 0b00001111;
+                                               uni_bytes = 2;
+                                       }
+                                       else if ((in & 0b11111000) == 0b11110000) // 4 byte
+                                       {
+                                               uni_ch = in & 0b00000111;
+                                               uni_bytes = 3;
+                                       }
+                                       else if ((in & 0b11111100) == 0b11111000) // 5 byte [???]
+                                       {
+                                               uni_ch = in & 0b00000011;
+                                               uni_bytes = 4;
+                                       }
+                                       else if ((in & 0b11111110) == 0b11111100) // 6 byte [???]
+                                       {
+                                               uni_ch = in & 0b00000001;
+                                               uni_bytes = 5;
+                                       }
+                                       else if (in == 0b11111110) // 7 byte [???]
+                                       {
+                                               uni_ch = 0;
+                                               uni_bytes = 6;
+                                       }
+                                       else // ???
+                                       {
+                                               uni_ch = -1;
+                                               uni_bytes = 0;
+                                       }
+                               }
+                               
+                               if (!uni_bytes) // no unfinished sequence
+                               {
+                                       if (uni_ch < 0x100)
+                                               uni_ctrl = uni_ch;
+                                       else
+                                               uni_ctrl = 0xFF;
+                                       
+                                       if (handle_ctrl(uni_ctrl)) // check if control char / function / sequence
+                                       {
+                                       }
+                                       else // no; normal character to print
+                                       {
+                                               add_print_ch_UNI(uni_ch);
+                                               // if (uni_ch < CH_LIMIT)
+                                                       // add_print_ch(UNI_TABLE[uni_ch]);
+                                               // else
+                                                       // add_print_ch(CH_UNKN);
+                                       }
+                               }
+                       }
+                       else // 8 bit encoding
+                       {
+                               if (uni_bytes)
+                               {
+                                       uni_bytes = 0;
+                                       handle_ctrl(0xFF);
+                                       add_print_ch(CH_UNKN);
+                               }
+                               if (handle_ctrl(in)) // check if control char / function / sequence
+                               {
+                               }
+                               else // no; normal character to print
+                               {
+                                       add_print_ch_CP(in);
+                                       // if (in & 0b10000000)
+                                               // add_print_ch(CH_CP[in]);
+                                       // else
+                                               // add_print_ch(CH_ASCII[in]);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* hex */
+
+void handle_hex (
+       const uint8_t cmd,
+       const uint8_t value
+)
+{
+       static int16_t r_lmargin = 0;
+       static int16_t r_rmargin = 0;
+       static uint8_t r_cwidth = 0;
+       static uint8_t columns = 0;
+       uint8_t new_columns;
+       
+       static uint8_t buffer[16];
+       static uint8_t rl = 0;
+       static uint8_t rr = 0;
+       static uint8_t wr = 0;
+       static uint8_t side = 0;
+       static uint8_t rel = 0;
+       
+       static uint16_t address = 0x0000;
+       
+       uint8_t force_output = 0;
+       uint8_t write_later = 0;
+       
+       if (cmd & HEX_RESET)
+       {
+               address = 0x0000;
+               rl = 0;
+               rr = 0;
+               wr = 0;
+               side = 0;
+               force_output = 1;
+               if (hpos_aim != lmargin_aim)
+               {
+                       goto_lmargin();
+                       goto_next_line(0);
+               }
+       }
+       if (cmd & (HEX_FORCE | HEX_FINISH))
+               force_output = 1;
+       if (
+               (!(cmd & HEX_AVAILABLE)) &&
+               (((int32_t)(main_timer - last_print_time)) >= (119 * TIME_10MS))
+       )
+               force_output = 1;
+       
+       if (
+               (lmargin_aim != r_lmargin) ||
+               (rmargin_aim != r_rmargin) ||
+               (cwidth_aim != r_cwidth)
+       )
+       {
+               r_lmargin = lmargin_aim;
+               r_rmargin = rmargin_aim;
+               r_cwidth = cwidth_aim;
+               
+/*
+0001 00  0
+0002 00 11  01
+0004 00 11 22 33  0123
+0008 00 11 22 33 44 55 55 77  01234567
+0010 00 11 22 33 44 55 66 77 88 88 AA BB CC DD EE FF  0123456789ABCDEF
+*/
+               
+               if ((r_rmargin - r_lmargin) >= (r_cwidth * (uint16_t)70))
+               {
+                       new_columns = 16;
+                       rel = 54;
+               }
+               else if ((r_rmargin - r_lmargin) >= (r_cwidth * (uint16_t)38))
+               {
+                       new_columns = 8;
+                       rel = 30;
+               }
+               else if ((r_rmargin - r_lmargin) >= (r_cwidth * (uint16_t)22))
+               {
+                       new_columns = 4;
+                       rel = 18;
+               }
+               else if ((r_rmargin - r_lmargin) >= (r_cwidth * (uint16_t)14))
+               {
+                       new_columns = 2;
+                       rel = 12;
+               }
+               else if ((r_rmargin - r_lmargin) >= (r_cwidth * (uint16_t)10))
+               {
+                       new_columns = 1;
+                       rel = 9;
+               }
+               else
+               {
+                       new_columns = 0;
+                       rel = 0;
+               }
+               
+               if (new_columns != columns)
+                       force_output = 1;
+       }
+       else
+               new_columns = columns;
+       
+       if (cmd & HEX_AVAILABLE)
+       {
+               if (wr < columns) // will fit in line
+               {
+                       buffer[wr] = value;
+                       ++wr;
+               }
+               else
+                       write_later = 1;
+       }
+       
+       if (wr >= columns)
+               force_output = 1;
+       
+       if (columns)
+       {
+               while ((rl < wr) || (rr < wr))
+               {
+                       if (!side) // left part
+                       {
+                               if (rl<wr)
+                               {
+                                       if (rl == 0) // start of line; print address
+                                       {
+                                               goto_lmargin();
+                                               add_print_hex(address, 4);
+                                       }
+                                       
+                                       // print hex value
+                                       
+                                       goto_col_rel(5 + 3 * rl);
+                                       add_print_hex(buffer[rl], 2);
+                                       ++rl;
+                               }
+                               else // out of available data
+                               {
+                                       if (force_output)
+                                               side = 1;
+                                       else
+                                               break;
+                               }
+                       }
+                       else // right part
+                       {
+                               if (rr<wr)
+                               {
+                                       goto_col_rel(rel + rr);
+                                       if ((buffer[rr] >= 0x20) && (buffer[rr] <= 0x7E))
+                                               add_print_ch_ASCII(buffer[rr]);
+                                       else
+                                               add_print_ch_ASCII('.');
+                                       ++rr;
+                               }
+                               else // out of available data
+                               {
+                                       if (force_output)
+                                               side = 0;
+                                       else
+                                               break;
+                               }
+                       }
+               }
+               if(
+                       (rl >= columns) &&
+                       (rr >= columns) &&
+                       (rl >= wr) &&
+                       (rr >= wr)
+               )
+               {
+                       address += wr;
+                       wr = 0;
+                       rl = 0;
+                       rr = 0;
+                       side = 0;
+                       goto_lmargin();
+                       goto_next_line(0);
+               }
+       }
+       else
+       {
+               for(rr=0; rr<wr; ++rr)
+               {
+                       add_print_hex(buffer[rr], 2);
+                       if ((hpos_aim + 3*cwidth_aim) <= rmargin_aim)
+                               goto_next_col(0);
+                       else
+                       {
+                               goto_lmargin();
+                               goto_next_line(0);
+                       }
+                       ++address;
+               }
+               wr = 0;
+       }
+       
+       if (write_later)
+       {
+               buffer[wr] = value;
+                       ++wr;
+       }
+       
+       columns = new_columns;
+       
+       if (cmd & HEX_FINISH)
+       {
+               rl = 0;
+               rr = 0;
+               wr = 0;
+               if (hpos_aim != lmargin_aim)
+               {
+                       goto_lmargin();
+                       goto_next_line(0);
+               }
+       }
+}
+
+
+/* control characters / sequences */
+
+uint8_t handle_ctrl (uint8_t in)
+{
+       static uint8_t ind = 0;
+       static uint8_t buffer[N_ESC_BUFFER];
+       static uint8_t prev = 0;
+       static uint8_t ib = 0; // intermediate byte count
+       
+       uint16_t long_id;
+       uint8_t c1_allowed = C1;
+       uint8_t handled = 0;
+       
+       uint8_t * buffer_pos = buffer;
+       uint8_t p_ind = 0;
+       uint8_t sp_ind = 0;
+       
+       // temporary for storing parameters
+       uint8_t  u0;
+       
+       if (esc_mode == ESC_ECMA_48)
+       {
+               if (prev == 0x1B) // there was ESC - ESCAPE
+               {
+                       if ((in >= 0x40) && (in <= 0x5F)) // C1 recode
+                       {
+                               in += 0x40;
+                               c1_allowed = 1; // even if originally unavailable, escape makes it possible
+                               if (ind) // overwrite the ESC
+                                       --ind;
+                       }
+                       else // delayed reaction; interrupt previous sequence, start new
+                       {
+                               if (buffer[0] != 0x98) // SOS can contain ESC
+                               {
+                                       buffer[0] = 0x1B;
+                                       ib = 0;
+                                       ind = 1;
+                               }
+                       }
+               }
+               
+               // C0, C1, GR not allowed inside sequences unless in control string
+               if (
+                       ((in < 0x20) || (in > 0x7E)) && // char out of GL
+                       (in != 0x1B) && // but not ESC (deal with it in next iteration)
+                       ind // in sequence already
+               )
+               {
+                       switch(buffer[0])
+                       {
+                       case 0x98: // SOS
+                               break;
+                       case 0x90: // DCS
+                       case 0x9A: // SCI
+                       case 0x9D: // OSC
+                       case 0x9E: // PM
+                       case 0x9F: // APC
+                               if (((in >= 0x08) && (in <= 0x0C)) || (in == 0x9C)) // allowed; do nothing 
+                                       break;
+                       default:
+                               ind = 0;
+                               break;
+                       }
+               }
+       }
+       
+       if (ind < N_ESC_BUFFER)
+               buffer[ind] = in;
+       
+       if (!ind) // single character or new sequence
+       {
+               if ((in <= 0x1F) || (in == 0x7F)) // C0
+               {
+                       handled = 1;
+                       switch (in)
+                       {
+                       case 0x00: // NUL - NULL
+                               break;
+                       // case 0x01: // SOH - START OF HEADING
+                       // case 0x02: // STX - START OF TEXT
+                       // case 0x03: // ETX - END OF TEXT
+                       // case 0x04: // EOT - END OF TRANSMISSION
+                       // case 0x05: // ENQ - ENQUIRY
+                       // case 0x06: // ACK - ACKNOWLEDGE
+                       case 0x07: // BEL - BELL
+                               add_print_key (CODE_BELL);
+                               break;
+                       case 0x08: // BS - BACKSPACE
+                       case 0x7F: // DEL - DELETE // TODO: should I accept this here?
+                               goto_prev_col(0);
+                               break;
+                       case 0x09: // HT - CHARACTER TABULATION
+                               goto_next_htab(0);
+                               break;
+                       case 0x0A: // LF - LINE FEED
+                               if (nl_mode & NL_IMPLICIT_CR)
+                                       goto_lmargin();
+                               if (!((nl_mode & NL_IMPLICIT_LF) && (prev==0x0D))) // already handled in last step?
+                                       goto_next_line(0);
+                               break;
+                       case 0x0B: // VT - LINE TABULATION
+                               goto_next_vtab(0);
+                               break;
+                       case 0x0C: // FF - FORM FEED
+                               goto_next_page_tmargin();
+                               break;
+                       case 0x0D: // CR - CARRIAGE RETURN
+                               goto_lmargin();
+                               if (nl_mode & NL_IMPLICIT_LF)
+                                       goto_next_line(0);
+                               break;
+                       // case 0x0E: // SO - SHIFT-OUT
+                       // case 0x0F: // SI - SHIFT-IN
+                       // case 0x10: // DLE - DATA LINK ESCAPE
+                       // case 0x11: // DC1 - DEVICE CONTROL ONE
+                       // case 0x12: // DC2 - DEVICE CONTROL TWO
+                       // case 0x13: // DC3 - DEVICE CONTROL THREE
+                       // case 0x14: // DC4 - DEVICE CONTROL FOUR
+                       // case 0x15: // NAK - NEGATIVE ACKNOWLEDGE
+                       // case 0x16: // SYN - SYNCHRONOUS IDLE
+                       // case 0x17: // ETB - END OF TRANSMISSION BLOCK
+                       // case 0x18: // CAN - CANCEL
+                       // case 0x19: // EM - END OF MEDIUM
+                       // case 0x1A: // SUB - SUBSTITUTE
+                       case 0x1B: // ESC - ESCAPE
+                               if (esc_mode == ESC_ECMA_48)
+                               {
+                                       ++ind;  // start sequence
+                                       ib = 0; // reset intermediate byte count
+                               }
+                               // else if (esc_mode == ESC_P_POS)
+                                       // ++ind;
+                               break;
+                       // case 0x1C: // IS4 - INFORMATION SEPARATOR FOUR
+                       // case 0x1D: // IS3 - INFORMATION SEPARATOR THREE
+                       // case 0x1E: // IS2 - INFORMATION SEPARATOR TWO
+                       // case 0x1F: // IS1 - INFORMATION SEPARATOR ONE
+                       default:
+                               if (esc_mode == ESC_NONE)
+                               {
+                                       add_print_ch(CH_ASCII['^']);
+                                       add_print_ch(CH_ASCII['@'+in]);
+                               }
+                               break;
+                       }
+               }
+               else if ((in >= 0x80) && (in <= 0x9F) && c1_allowed) // C1
+               {
+                       if (esc_mode == ESC_ECMA_48)
+                       {
+                               handled = 1;
+                               switch (in)
+                               {
+                               //case 0x80: // 1B 40  reserved
+                               //case 0x81: // 1B 41  reserved
+                               //case 0x82: // 1B 42  BPH - BREAK PERMITTED HERE
+                               //case 0x83: // 1B 43  NBH - NO BREAK HERE
+                               //case 0x84: // 1B 44  reserved
+                               case 0x85: // 1B 45  NEL - NEXT LINE
+                                       goto_lmargin();
+                                       goto_next_line(0);
+                                       break;
+                               //case 0x86: // 1B 46  SSA - START OF SELECTED AREA
+                               //case 0x87: // 1B 47  ESA - END OF SELECTED AREA
+                               case 0x88: // 1B 48  HTS - CHARACTER TABULATION SET
+                                       set_htab(hpos_aim);
+                                       break;
+                               case 0x89: // 1B 49  HTJ - CHARACTER TABULATION WITH JUSTIFICATION
+                                       goto_next_htab(0);
+                                       break;
+                               case 0x8A: // 1B 4A  VTS - LINE TABULATION SET
+                                       set_vtab(vpos_aim);
+                                       break;
+                               case 0x8B: // 1B 4B  PLD - PARTIAL LINE FORWARD
+                                       goto_next_vstep();
+                                       break;
+                               case 0x8C: // 1B 4C  PLU - PARTIAL LINE BACKWARD
+                                       goto_prev_vstep();
+                                       break;
+                               case 0x8D: // 1B 4D  RI - REVERSE LINE FEED
+                                       goto_prev_line(0);
+                                       break;
+                               //case 0x8E: // 1B 4E  SS2 - SINGLE-SHIFT TWO
+                               //case 0x8F: // 1B 4F  SS3 - SINGLE-SHIFT THREE
+                               //case 0x91: // 1B 51  PU1 - PRIVATE USE ONE
+                               //case 0x92: // 1B 52  PU2 - PRIVATE USE TWO
+                               //case 0x93: // 1B 53  STS - SET TRANSMIT STATE
+                               //case 0x94: // 1B 54  CCH - CANCEL CHARACTER
+                               case 0x95: // 1B 55  MW - MESSAGE WAITING
+                                       send_DSR_ok();
+                                       break;
+                               //case 0x96: // 1B 56  SPA - START OF GUARDED AREA
+                               //case 0x97: // 1B 57  EPA - END OF GUARDED AREA
+                               //case 0x99: // 1B 59  reserved
+                               //case 0x9C: // 1B 5C  ST - STRING TERMINATOR
+                               
+                               // control string / control sequence:
+                               
+                               case 0x90: // 1B 50  DCS  08-0C,20-7E - DEVICE CONTROL STRING
+                               case 0x98: // 1B 58  SOS  any         - START OF STRING
+                               case 0x9A: // 1B 5A  SCI  08-0C,20-7E - SINGLE CHARACTER INTRODUCER
+                               case 0x9D: // 1B 5D  OSC  08-0C,20-7E - OPERATING SYSTEM COMMAND
+                               case 0x9E: // 1B 5E  PM   08-0C,20-7E - PRIVACY MESSAGE
+                               case 0x9F: // 1B 5F  APC  08-0C,20-7E - APPLICATION PROGRAM COMMAND
+                               case 0x9B: // 1B 5B  CSI - CONTROL SEQUENCE INTRODUCER
+                                       ++ind;
+                                       ib = 0;
+                                       break;
+                               }
+                               
+                       }
+                       else
+                               handled = 0;
+               }
+               else // normal text
+                       handled = 0;
+       }
+       else // continued sequence
+       {
+               if (esc_mode == ESC_ECMA_48)
+               {
+                       handled = 1;
+                       
+                       if (in == 0x1B) // ESC - ESCAPE
+                       {
+                               // allow to go through. We'll deal with it next iteration.
+                               if (ind < N_ESC_BUFFER-1)
+                                       ++ind;
+                       }
+                       else
+                       {
+                               switch (buffer[0])
+                               {
+                               case 0x1B: // ESC - ESCAPE
+                                       if ((buffer[1] >= 0x20) && (buffer[1] <= 0x2F)) // nF
+                                       {
+                                               if ((in >= 0x20) && (in <= 0x2F)) // intermediate byte
+                                               {
+                                                       ++ib; // count intermediate bytes
+                                                       if (ind < N_ESC_BUFFER-1)
+                                                               ++ind;
+                                               }
+                                               else if ((in >= 0x30) && (in <= 0x7E)) // final byte
+                                               {
+                                                       switch (buffer[1])
+                                                       {
+                                                       // case 0x20: // ANNOUNCE CODE STRUCTURE
+                                                       // case 0x21: // C0-DESIGNATE
+                                                       // case 0x22: // C1-DESIGNATE
+                                                       // case 0x23: // Single control functions
+                                                       // case 0x24: // Designation of multiple-byte graphic character sets
+                                                       case 0x25: // DESIGNATE OTHER CODING SYSTEM
+                                                               if (ib == 1) // single intermediate byte
+                                                                       long_id = buffer[2];
+                                                               else if (ib == 2) // 2 intermediate bytes
+                                                                       long_id = (((uint16_t)buffer[2])<<8) | buffer[3];
+                                                               else  // invalid
+                                                                       break;
+                                                               switch (long_id)
+                                                               {
+                                                               case   0x47: // goto UTF-8
+                                                               case 0x2f47:
+                                                               case 0x2f48:
+                                                               case 0x2f49:
+                                                                       set_encoding(encoding | ENC_UNI);
+                                                                       break;
+                                                               case   0x40: // return to ECMA-35
+                                                                       set_encoding_GR(GR_index);
+                                                                       break;
+                                                               }
+                                                               break;
+                                                       // case 0x26: // IDENTIFY REVISED REGISTRATION
+                                                       // case 0x27: // (reserved for future standardisation)
+                                                       // case 0x28: // G0-DESIGNATE 94-SET
+                                                       // case 0x29: // G1-DESIGNATE 94-SET
+                                                       // case 0x2A: // G2-DESIGNATE 94-SET
+                                                       // case 0x2B: // G3-DESIGNATE 94-SET
+                                                       // case 0x2C: // (reserved for future standardisation)
+                                                       case 0x2D: // G1-DESIGNATE 96-SET
+                                                       case 0x2E: // G2-DESIGNATE 96-SET
+                                                       case 0x2F: // G3-DESIGNATE 96-SET
+                                                               u0 = buffer[1] - 0x2D + 1;
+                                                               if (ib == 1) // single intermediate byte
+                                                               {
+                                                                       switch (buffer[2]) // final byte
+                                                                       {
+                                                                       case 0x41:
+                                                                       case 0x63:
+                                                                               GR_table[u0] = ENC_ISO8859_1;
+                                                                               break;
+                                                                       case 0x42:
+                                                                               GR_table[u0] = ENC_ISO8859_2;
+                                                                               break;
+                                                                       case 0x43:
+                                                                               GR_table[u0] = ENC_ISO8859_3;
+                                                                               break;
+                                                                       case 0x44:
+                                                                       case 0x64:
+                                                                               GR_table[u0] = ENC_ISO8859_4;
+                                                                               break;
+                                                                       case 0x4D:
+                                                                               GR_table[u0] = ENC_ISO8859_9;
+                                                                               break;
+                                                                       case 0x56:
+                                                                               GR_table[u0] = ENC_ISO8859_10;
+                                                                               break;
+                                                                       case 0x65:
+                                                                               GR_table[u0] = ENC_ISO8859_13;
+                                                                               break;
+                                                                       case 0x62:
+                                                                               GR_table[u0] = ENC_ISO8859_15;
+                                                                               break;
+                                                                       default:
+                                                                               u0 = 0xff;
+                                                                       }
+                                                                       if (u0 == GR_index) // reassigned already selected encoding; update
+                                                                               set_encoding_GR(GR_index);
+                                                               }
+                                                               break;
+                                                       }
+                                                       ind = 0;
+                                               }
+                                               else // invalid value
+                                               {
+                                                       ind = 0;
+                                                       handled = 0;
+                                               }
+                                       }
+                                       else if ((buffer[1] >= 0x30) && (buffer[1] <= 0x7E)) // Fp, Fs, control function 
+                                       {
+                                               switch(buffer[1])
+                                               {
+                                               // case 0x60: // DMI - DISABLE MANUAL INPUT
+                                               // case 0x61: // INT - INTERRUPT
+                                               // case 0x62: // EMI - ENABLE MANUAL INPUT
+                                               case 0x63: // RIS - RESET TO INITIAL STATE
+                                                       out_margin =  0;
+                                                       
+                                                       pheight =     DEFAULT_PHEIGHT;
+                                                       tmargin =     DEFAULT_TMARGIN;
+                                                       bmargin =     DEFAULT_BMARGIN;
+                                                       lheight =     HEIGHT_NORMAL;
+                                                       theight_ch =  DEFAULT_THEIGHT_CH;
+                                                       
+                                                       lwidth =      DEFAULT_LWIDTH;
+                                                       lmargin_aim = DEFAULT_LMARGIN_AIM;
+                                                       rmargin_aim = DEFAULT_RMARGIN_AIM;
+                                                       cwidth_aim =  WIDTH_NORMAL;
+                                                       cwidth_todo = 1;
+                                                       twidth_ch =   DEFAULT_TWIDTH_CH;
+                                                       
+                                                       set_style_normal();
+                                                       
+                                                       load_config();
+                                                       
+                                                       ppos = -1;
+                                                       vpos_aim = pheight + tmargin;
+                                                       hpos_aim = lmargin_aim;
+                                                       adjust_print_pos();
+                                                       break;
+                                               // case 0x64: // CMD - CODING METHOD DELIMITER
+                                               // case 0x6E: // LS2 - LOCKING-SHIFT TWO
+                                               // case 0x6F: // LS3 - LOCKING-SHIFT THREE
+                                               case 0x7C: // LS3R - LOCKING-SHIFT THREE RIGHT
+                                                       set_encoding_GR(3);
+                                                       break;
+                                               case 0x7D: // LS2R - LOCKING-SHIFT TWO RIGHT
+                                                       set_encoding_GR(2);
+                                                       break;
+                                               case 0x7E: // LS1R - LOCKING-SHIFT ONE RIGHT
+                                                       set_encoding_GR(1);
+                                                       break;
+                                               default:
+                                                       break;
+                                               }
+                                               ind = 0;
+                                       }
+                                       else // invalid value
+                                       {
+                                               ind = 0;
+                                               handled = 0;
+                                       }
+                                       break;
+                               case 0x9B: // 1B 5B  CSI - CONTROL SEQUENCE INTRODUCER
+                                       if ((in >= 0x30) && (in <= 0x3F)) // parameter byte
+                                       {
+                                               if (prev < 0x30)  // I before P
+                                               {
+                                                       ind = 0;
+                                                       handled = 0;
+                                               }
+                                               else // ok
+                                               {
+                                                       if (ind < N_ESC_BUFFER-1)
+                                                               ++ind;
+                                               }
+                                       }
+                                       else if ((in >= 0x20) && (in <= 0x2F)) // intermediate byte
+                                       {
+                                               ++ib; // count intermediate bytes
+                                               if (ind < N_ESC_BUFFER-1)
+                                                       ++ind;
+                                       }
+                                       else if ((in >= 0x40) && (in <= 0x7E)) // final byte
+                                       {
+                                               buffer_pos = buffer + 1;
+                                               if (ib == 0) // just 1 final byte
+                                                       long_id = in;
+                                               else if (ib == 1) // 1 intermediate & 1 final byte
+                                                       long_id = (((uint16_t)prev)<<8)|in;
+                                               else // invalid
+                                                       long_id =0;
+                                               switch (long_id)
+                                               {
+                                               // case 0x40: // ICH - INSERT CHARACTER
+                                               case 0x41: // CUU - CURSOR UP
+                                               case 0x6B: // VPB - LINE POSITION BACKWARD
+                                                       move_back_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x42: // CUD - CURSOR DOWN
+                                               case 0x65: // VPR - LINE POSITION FORWARD
+                                                       move_forward_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x43: // CUF - CURSOR RIGHT
+                                               case 0x61: // HPR - CHARACTER POSITION FORWARD
+                                                       move_forward_col((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x44: // CUB - CURSOR LEFT
+                                               case 0x6A: // HPB - CHARACTER POSITION BACKWARD
+                                                       move_back_col((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x45: // CNL - CURSOR NEXT LINE
+                                                       goto_col0();
+                                                       move_forward_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x46: // CPL - CURSOR PRECEDING LINE
+                                                       goto_col0();
+                                                       move_back_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x47: // CHA - CURSOR CHARACTER ABSOLUTE
+                                               case 0x60: // HPA - CHARACTER POSITION ABSOLUTE
+                                                       goto_col(((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1))-1);
+                                                       break;
+                                               case 0x48: // CUP - CURSOR POSITION
+                                               case 0x66: // HVP - CHARACTER AND LINE POSITION
+                                                       goto_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       goto_col((uint8_t)get_ctrl_parameter(CTRL_IND, 1, 0, 1)-1);
+                                                       break;
+                                               case 0x49: // CHT - CURSOR FORWARD TABULATION
+                                                       move_forward_htab ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               // case 0x4A: // ED - ERASE IN PAGE
+                                               // case 0x4B: // EL - ERASE IN LINE
+                                               // case 0x4C: // IL - INSERT LINE
+                                               // case 0x4D: // DL - DELETE LINE
+                                               // case 0x4E: // EF - ERASE IN FIELD
+                                               // case 0x4F: // EA - ERASE IN AREA
+                                               // case 0x50: // DCH - DELETE CHARACTER
+                                               // case 0x51: // SEE - SELECT EDITING EXTENT
+                                               // case 0x52: // CPR - ACTIVE POSITION REPORT
+                                               // case 0x53: // SU - SCROLL UP
+                                               // case 0x54: // SD - SCROLL DOWN
+                                               case 0x55: // NP - NEXT PAGE
+                                                       move_forward_page_tmargin((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               case 0x56: // PP - PRECEDING PAGE
+                                                       move_back_page_tmargin((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               case 0x57: // CTC - CURSOR TABULATION CONTROL
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                               set_htab(hpos_aim);
+                                                               break;
+                                                       case 1:
+                                                               set_vtab(vpos_aim);
+                                                               break;
+                                                       case 2:
+                                                               clear_htab(hpos_aim);
+                                                               break;
+                                                       case 3:
+                                                               clear_vtab(hpos_aim);
+                                                               break;
+                                                       case 4:
+                                                       case 5:
+                                                               clear_htab_all();
+                                                               break;
+                                                       case 6:
+                                                               clear_vtab_all();
+                                                               break;
+                                                       }
+                                                       break;
+                                               // case 0x58: // ECH - ERASE CHARACTER
+                                               case 0x59: // CVT - CURSOR LINE TABULATION
+                                                       move_forward_vtab((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x5A: // CBT - CURSOR BACKWARD TABULATION
+                                                       move_back_htab ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               // case 0x5B: // SRS - START REVERSED STRING
+                                               // case 0x5C: // PTX - PARALLEL TEXTS
+                                               // case 0x5D: // SDS - START DIRECTED STRING
+                                               // case 0x5E: // SIMD - SELECT IMPLICIT MOVEMENT DIRECTION
+                                               // case 0x62: // REP - REPEAT // TODO:???
+                                               // case 0x63: // DA - DEVICE ATTRIBUTES
+                                               case 0x64: // VPA - LINE POSITION ABSOLUTE
+                                                       goto_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x67: // TBC - TABULATION CLEAR
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                               clear_htab(hpos_aim);
+                                                               break;
+                                                       case 1:
+                                                               clear_vtab(vpos_aim);
+                                                               break;
+                                                       case 2:
+                                                       case 3:
+                                                               clear_htab_all();
+                                                               break;
+                                                       case 5:
+                                                               clear_htab_all();
+                                                       case 4:
+                                                               clear_vtab_all();
+                                                               break;
+                                                       }
+                                                       break;
+                                               // case 0x68: // SM - SET MODE
+                                               // case 0x69: // MC - MEDIA COPY
+                                               // case 0x6C: // RM - RESET MODE
+                                               case 0x6D: // SGR - SELECT GRAPHIC RENDITION
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                       case 65:
+                                                               set_style_normal();
+                                                               break;
+                                                       case 1:
+                                                               set_style_bold();
+                                                               break;
+                                                       case 4:
+                                                               set_style_under();
+                                                               break;
+                                                       case 9:
+                                                               set_style_cross();
+                                                               break;
+                                                       case 21:
+                                                               set_style_under2();
+                                                               break;
+                                                       case 22:
+                                                               set_style_nobold();
+                                                               break;
+                                                       case 24:
+                                                               set_style_nounder();
+                                                               break;
+                                                       case 29:
+                                                               set_style_nocross();
+                                                               break;
+                                                       case 53:
+                                                               set_style_over();
+                                                               break;
+                                                       case 55:
+                                                               set_style_noover();
+                                                               break;
+                                                       }
+                                                       break;
+                                               case 0x6E: // DSR - DEVICE STATUS REPORT
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       //case 0:
+                                                       //case 1:
+                                                       //case 2:
+                                                       //case 3:
+                                                       //case 4:
+                                                       case 5:
+                                                               send_DSR_ok();
+                                                               break;
+                                                       case 6:
+                                                        send_CPR();
+                                                        break;
+                                                       }
+                                                       break;
+                                               // case 0x6F: // DAQ - DEFINE AREA QUALIFICATION
+                                               
+                                               // case 0x2040: // SL - SCROLL LEFT
+                                               // case 0x2041: // SR - SCROLL RIGHT
+                                               // case 0x2043: // GSS - GRAPHIC SIZE SELECTION
+                                                       // set_lheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       // // width is implicit, but I don't change it here
+                                                       // break;
+                                               // case 0x2044: // FNT - FONT SELECTION
+                                               // case 0x2045: // TSS - THIN SPACE SPECIFICATION
+                                               // case 0x2046: // JFY - JUSTIFY
+                                               case 0x2047: // SPI - SPACING INCREMENT
+                                                       set_lheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       set_cwidth(HUNIT(get_ctrl_parameter(CTRL_IND, 1, 0, 0)));
+                                                       break;
+                                               // case 0x2048: // QUAD - QUAD
+                                               case 0x2049: // SSU - SELECT SIZE UNIT
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0: // CHARACTER
+                                                               hunit_mul = HUNIT_MUL_CH;
+                                                               hunit_div = HUNIT_DIV_CH;
+                                                               vunit_mul = VUNIT_MUL_CH;
+                                                               vunit_div = VUNIT_DIV_CH;
+                                                               break;
+                                                       case 1: // MILLIMETRE
+                                                               hunit_mul = HUNIT_MUL_MM;
+                                                               hunit_div = HUNIT_DIV_MM;
+                                                               vunit_mul = VUNIT_MUL_MM;
+                                                               vunit_div = VUNIT_DIV_MM;
+                                                               break;
+                                                       case 2: // COMPUTER DECIPOINT
+                                                               hunit_mul = HUNIT_MUL_CDP;
+                                                               hunit_div = HUNIT_DIV_CDP;
+                                                               vunit_mul = VUNIT_MUL_CDP;
+                                                               vunit_div = VUNIT_DIV_CDP;
+                                                               break;
+                                                       case 3: // DECIDIDOT
+                                                               hunit_mul = HUNIT_MUL_DD;
+                                                               hunit_div = HUNIT_DIV_DD;
+                                                               vunit_mul = VUNIT_MUL_DD;
+                                                               vunit_div = VUNIT_DIV_DD;
+                                                               break;
+                                                       case 4: // MIL
+                                                               hunit_mul = HUNIT_MUL_MIL;
+                                                               hunit_div = HUNIT_DIV_MIL;
+                                                               vunit_mul = VUNIT_MUL_MIL;
+                                                               vunit_div = VUNIT_DIV_MIL;
+                                                               break;
+                                                       case 5: // BASIC MEASURING UNIT
+                                                               hunit_mul = HUNIT_MUL_BMU;
+                                                               hunit_div = HUNIT_DIV_BMU;
+                                                               vunit_mul = VUNIT_MUL_BMU;
+                                                               vunit_div = VUNIT_DIV_BMU;
+                                                               break;
+                                                       case 6: // MICROMETRE
+                                                               hunit_mul = HUNIT_MUL_UM;
+                                                               hunit_div = HUNIT_DIV_UM;
+                                                               vunit_mul = VUNIT_MUL_UM;
+                                                               vunit_div = VUNIT_DIV_UM;
+                                                               break;
+                                                       case 7: // PIXEL
+                                                               hunit_mul = 1;
+                                                               hunit_div = 1;
+                                                               vunit_mul = 1;
+                                                               vunit_div = 1;
+                                                               break;
+                                                       case 8: // DECIPOINT
+                                                               hunit_mul = HUNIT_MUL_DP;
+                                                               hunit_div = HUNIT_DIV_DP;
+                                                               vunit_mul = VUNIT_MUL_DP;
+                                                               vunit_div = VUNIT_DIV_DP;
+                                                               break;
+                                                       }
+                                                       break;
+                                               case 0x204A: // PFS - PAGE FORMAT SELECTION
+                                                       u0 = (uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0);
+                                                       if (u0 < N_PF)
+                                                       {
+                                                               set_pheight(PHEIGHT_PRESET[u0]);
+                                                               set_tmargin(0);
+                                                               set_bmargin_rel(0);
+                                                               set_theight_ch(theight_ch);
+                                                               set_lwidth(LWIDTH_PRESET[u0]);
+                                                               set_lmargin(LMARGIN_PRESET);
+                                                               set_rmargin_rel(0-RMARGIN_PRESET);
+                                                               set_twidth_ch(twidth_ch);
+                                                               adjust_print_pos();
+                                                               // TODO: new page?
+                                                       }
+                                                       break;
+                                               case 0x204B: // SHS - SELECT CHARACTER SPACING
+                                                       u0 = (uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0);
+                                                       if (u0 < N_CWIDTH)
+                                                               set_cwidth(CWIDTH_PRESET[u0]);
+                                                       break;
+                                               case 0x204C: // SVS - SELECT LINE SPACING
+                                                       u0 = (uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0);
+                                                       if (u0 < N_LHEIGHT)
+                                                               set_lheight(LHEIGHT_PRESET[u0]);
+                                                       break;
+                                               // case 0x204D: // IGS - IDENTIFY GRAPHIC SUBREPERTOIRE
+                                               // case 0x204F: // IDCS - IDENTIFY DEVICE CONTROL STRING
+                                               case 0x2050: // PPA - PAGE POSITION ABSOLUTE
+                                                       goto_page((int16_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x2051: // PPR - PAGE POSITION FORWARD
+                                                       move_forward_page((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               case 0x2052: // PPB - PAGE POSITION BACKWARD
+                                                       move_back_page((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               // case 0x2053: // SPD - SELECT PRESENTATION DIRECTIONS
+                                               case 0x2054: // DTA - DIMENSION TEXT AREA
+                                                       set_pheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       set_lwidth(HUNIT(get_ctrl_parameter(CTRL_IND, 1, 0, 0)));
+                                                       adjust_print_pos();
+                                                       // TODO: set new margins?
+                                                       break;
+                                               case 0x2055: // SLH - SET LINE HOME
+                                                       set_lmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x2056: // SLL - SET LINE LIMIT
+                                                       set_rmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               // case 0x2057: // FNK - FUNCTION KEY
+                                               // case 0x2058: // SPQR - SELECT PRINT QUALITY AND RAPIDITY
+                                               case 0x2059: // SEF - SHEET EJECT AND FEED
+                                                       // partial implementation: move out of page
+                                                       goto_next_page_tmargin();
+                                                       break;
+                                               case 0x205A: // PEC - PRESENTATION EXPAND OR CONTRACT
+                                                       switch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                               set_cwidth(WIDTH_NORMAL);
+                                                               break;
+                                                       case 1:
+                                                               set_cwidth(WIDTH_WIDE);
+                                                               break;
+                                                       case 2:
+                                                               set_cwidth(WIDTH_NARROW);
+                                                               break;
+                                                       }
+                                                       break;
+                                               // case 0x205B: // SSW - SET SPACE WIDTH
+                                               // case 0x205C: // SACS - SET ADDITIONAL CHARACTER SEPARATION
+                                               // case 0x205D: // SAPV - SELECT ALTERNATIVE PRESENTATION VARIANTS
+                                               case 0x205E: // STAB - SELECTIVE TABULATION
+                                                       // arbitrary choice
+                                                       goto_htab((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               // case 0x205F: // GCC - GRAPHIC CHARACTER COMBINATION
+                                               // case 0x2060: // TATE - TABULATION ALIGNED TRAILING EDGE
+                                               // case 0x2061: // TALE - TABULATION ALIGNED LEADING EDGE
+                                               // case 0x2062: // TAC - TABULATION ALIGNED CENTRED
+                                               // case 0x2063: // TAC - TABULATION ALIGNED CENTRED
+                                               case 0x2064: // TSR - TABULATION STOP REMOVE
+                                                       clear_htab_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               // case 0x2065: // SCO - SELECT CHARACTER ORIENTATION
+                                               // case 0x2066: // SRCS - SET REDUCED CHARACTER SEPARATION
+                                               case 0x2067: // SCS - SET CHARACTER SPACING
+                                                       set_cwidth(HUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       break;
+                                               case 0x2068: // SLS - SET LINE SPACING
+                                                       set_lheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       break;
+                                               case 0x2069: // SPH - SET PAGE HOME
+                                                       set_tmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x206A: // SPL - SET PAGE LIMIT
+                                                       set_bmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0));
+                                                       break;
+                                               // case 0x206B: // SCP - SELECT CHARACTER PATH
+                                               }
+                                               ind = 0;
+                                       }
+                                       else // invalid value
+                                       {
+                                               ind = 0;
+                                               handled = 0;
+                                       }
+                                       break;
+                               case 0x90: // 1B 50  DCS - DEVICE CONTROL STRING
+                               case 0x98: // 1B 58  SOS - START OF STRING
+                               case 0x9A: // 1B 5A  SCI - SINGLE CHARACTER INTRODUCER
+                               case 0x9D: // 1B 5D  OSC - OPERATING SYSTEM COMMAND
+                               case 0x9E: // 1B 5E  PM  - PRIVACY MESSAGE
+                               case 0x9F: // 1B 5F  APC - APPLICATION PROGRAM COMMAND
+                                       if (in == 0x9C) // 1B 5C  ST - STRING TERMINATOR
+                                       {
+                                               /* control string would be handled here if implemented */
+                                               ind = 0;
+                                       }
+                                       else if (ind < N_ESC_BUFFER-1)
+                                               ++ind;
+                                       break;
+                               default:
+                                       // how did we get here?
+                                       ind = 0;
+                                       handled = 0;
+                               }
+                       }
+               }
+               else
+               {
+                       ind = 0;
+                       handled = 0;
+               }
+       }
+       prev = in;
+       return handled;
+}
+
+uint32_t get_ctrl_parameter (
+       uint8_t * buffer,
+       uint8_t * * pos,
+       uint8_t * ind,
+       uint8_t * subind,
+       uint8_t id,
+       uint8_t subid,
+       uint32_t def
+)
+{
+       uint32_t val = 0;
+       uint8_t ch;
+       uint8_t return_now = 0;
+       uint8_t return_default = 1;
+       
+       // too far, move to start.
+       if ((id < *ind) || ((id == *ind) && (subid < *subind)))
+       {
+               *pos = buffer;
+               *ind = 0;
+               *subind = 0;
+       }
+       
+       if (*pos == buffer) // at start
+       {
+               if ((*buffer < 0x30) || (*buffer > 0x3B)) // not a parameter string
+               {
+                       return def;
+               }
+       }
+       
+       while (1)
+       {
+               ch = **pos;
+               switch (ch)
+               {
+               case 0x30: // digit
+               case 0x31:
+               case 0x32:
+               case 0x33:
+               case 0x34:
+               case 0x35:
+               case 0x36:
+               case 0x37:
+               case 0x38:
+               case 0x39:
+                       if ((*ind == id) && (*subind == subid))
+                       {
+                               return_default = 0;
+                               val *= 10;
+                               val += ch - 0x30;
+                       }
+                       ++(*pos);
+                       break;
+               case 0x3A: // : substring separator
+                       if ((*ind == id) && (*subind == subid))
+                       {
+                               return_now = 1;
+                       }
+                       ++(*subind);
+                       ++(*pos);
+                       break;
+               case 0x3B: // ; string separator
+                       if ((*ind == id) && (*subind == subid))
+                       {
+                               return_now = 1;
+                       }
+                       ++(*ind);
+                       *subind = 0;
+                       ++(*pos);
+                       break;
+               default: // end of parameter strings
+                       return_now = 1;
+               }
+               
+               if (return_now)
+               {
+                       return return_default ? def : val;
+               }
+       }
+}
+
+static inline void send_DSR_ok (void)
+{
+       add_outcome_str((uint8_t *)"\x1B\x5B\x30\x6E");
+}
+
+static inline void send_CPR (void)
+{
+       add_outcome(0x1B); // ESC
+       add_outcome(0x5B); // CSI
+       add_outcome_dec((vpos_aim/lheight)+1, 1); // Pn1 - line number
+       add_outcome(0x3B); // separator
+       add_outcome_dec((hpos_aim/cwidth_aim)+1, 1); // Pn2 - column number
+       add_outcome(0x52); // CPR - ACTIVE POSITION REPORT
+}
+
+
+/* outcoming characters */
+
+void add_outcome (const uint8_t out)
+{
+       if (
+               (out & 0x80) && // high bit set
+               ((serial_mode & UART_DATA) == UART_DATA_7) // serial set to 7 bits
+       )
+               return; // refuse to send such value in this mode
+       
+       while (FULL_BP(outcome_w, outcome_r, N_OUTCOME_BUFFER)) // buffer is full
+       {
+               // try handling the outcoming data to make some place
+               handle_outcome();
+       }
+       
+       outcome_buffer[outcome_w] = out;
+       ADVANCE_BP(outcome_w, N_OUTCOME_BUFFER);
+       
+       // cannot sleep when there are bytes to send out
+       cancel_sleep(WAKEUP_OUTCOME);
+}
+
+void add_outcome_str (uint8_t const * out)
+{
+       uint8_t const * p;
+       
+       for (p = out; *p != 0x00; ++p)
+               add_outcome(*p);
+}
+
+void add_outcome_dec (
+       const uint32_t value,
+       const uint8_t min_digits
+)
+{
+       uint8_t text[11];
+       uint8_t x;
+       
+       x = make_dec_string(
+               text,
+               value,
+               min_digits,
+               10
+       );
+       text[x] = 0x00;
+       add_outcome_str(text);
+}
+
+void add_outcome_hex (
+       const uint32_t value,
+       const uint8_t min_digits
+)
+{
+       uint8_t text[9];
+       uint8_t x;
+       
+       x = make_hex_string(
+               text,
+               value,
+               min_digits,
+               8,
+               1
+       );
+       text[x] = 0x00;
+       add_outcome_str(text);
+}
+
+void handle_outcome (void)
+{
+       if (send_xonoff) // requested to send XON or XOFF
+       {
+               if (UCSR0A & (1<<UDRE0))
+               {
+                       UDR0 = send_xonoff;
+                       send_xonoff = 0;
+                       set_led = 2;
+               }
+               return;
+       }
+       
+       cli();
+       if (EMPTY_BP(outcome_w, outcome_r, N_BUFFER_OUTCOME)) // buffer is empty
+       {
+               sei();
+               if (UCSR0A & (1<<UDRE0)) // and last byte was already sent
+               {
+                       // no longer request to send out (flow control)
+                       // (only effective if we are the DTE)
+                       unrequest_outcome();
+                       allow_sleep(WAKEUP_OUTCOME);
+               }
+       }
+       else // there is something to send
+       {
+               sei();
+               
+               // request to send out (flow control)
+               // (only effective if we are the DTE)
+               request_outcome();
+               if (
+                       outcome_accepted() && // flow control
+                       (UCSR0A & (1<<UDRE0))
+               )
+               {
+                       UDR0 = outcome_buffer[outcome_r];
+                       ADVANCE_BP(outcome_r, N_OUTCOME_BUFFER);
+                       
+                       set_led = 2; // show that something is happening
+               }
+       }
+}
+
+
+/* both way */
+
+static inline void add_ch (const uint8_t io)
+{
+       if (mode & MODE_ECHO)
+               add_income(io, 1);
+       add_outcome(io);
+}
+
+
+/* cursor movement */
+
+static inline void goto_prev_page (void)
+{
+       out_margin = 1; // will be cancelled anyway [???]
+       vpos_aim -= pheight; // the world is not ready for this
+       adjust_print_pos();
+}
+
+static inline void goto_prev_page_tmargin (void)
+{
+       out_margin = 1; // will be cancelled anyway [???]
+       vpos_aim = tmargin - pheight; // the world is not ready for this
+       adjust_print_pos();
+}
+
+static inline void goto_next_page (void)
+{
+       out_margin = 1; // will be cancelled anyway
+       vpos_aim += pheight;
+       adjust_print_pos();
+}
+
+static inline void goto_next_page_tmargin (void)
+{
+       out_margin = 1; // will be cancelled anyway
+       vpos_aim = tmargin + pheight;
+       adjust_print_pos();
+}
+
+void move_back_page (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_prev_page();
+}
+
+void move_back_page_tmargin (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_prev_page_tmargin();
+}
+
+void move_forward_page (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_next_page();
+}
+
+void move_forward_page_tmargin (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_next_page_tmargin();
+}
+
+void goto_page (const int16_t y)
+{
+       int16_t diff;
+       
+       diff = y - ppos;
+       
+       if (diff > 0)
+       {
+               if (diff > 255) // sorry, too far
+                       return;
+               move_forward_page(diff);
+       }
+       else if (diff < 0)
+       {
+               if (diff < -255) // sorry, too far
+                       return;
+               move_back_page(0-diff);
+       }
+}
+
+
+uint8_t goto_prev_line (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       vpos_aim -= lheight;
+       
+       if ((vpos_aim < tmargin ) && (!out_margin))// don't apply -1 offset
+       {
+               stop = 1;
+               if (vpos >= tmargin)
+                       vpos_aim = tmargin;
+               else
+                       vpos_aim = vpos;
+       }
+       else if (vpos_aim < 0)
+       {
+               stop = 1;
+               if (vpos >= 0)
+                       vpos_aim = 0;
+               else
+                       vpos_aim = vpos;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_next_line (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       vpos_aim += lheight;
+       
+       if (((vpos_aim + lheight) > bmargin ) && (!out_margin)) // don't apply +1 offset
+       {
+               stop = 1;
+       }
+       else if ((vpos_aim + lheight) > pheight) // don't apply +1 offset
+       {
+               stop = 1;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+void move_back_line (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_line(ignore_margin))
+                       break;
+       }
+}
+
+void move_forward_line (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_line(ignore_margin))
+               {
+                       if (paper != PAPER_CONTINUOUS)
+                               break;
+               }
+       }
+}
+
+void goto_line (uint8_t y)
+{
+       if (y == 0xff) //-1
+               y = 0;
+       
+       out_margin = 1;
+       vpos_aim = y * lheight;
+       
+       if ((vpos_aim + lheight) > pheight) // don't apply +1 offset
+       {
+               if(vpos <= (pheight - lheight))
+                       vpos_aim = pheight - lheight;
+               else
+                       vpos_aim = vpos;
+       }
+       adjust_print_pos();
+}
+
+void goto_line_rel (uint8_t y)
+{
+       if (y == 0xff) //-1
+               y = 0;
+       
+       vpos_aim = tmargin + y * lheight;
+       
+       if ((vpos_aim + lheight) > bmargin) // don't apply +1 offset
+       {
+               if(vpos <= (bmargin - lheight))
+                       vpos_aim = bmargin - lheight;
+               else
+                       vpos_aim = vpos;
+       }
+       adjust_print_pos();
+}
+
+static inline void goto_prev_vstep (void)
+{
+       --vpos_aim;
+       adjust_print_pos();
+}
+
+static inline void goto_next_vstep (void)
+{
+       ++vpos_aim;
+       adjust_print_pos();
+}
+
+
+uint8_t goto_prev_col (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin; 
+       hpos_aim -= cwidth_aim;
+       
+       if ((hpos_aim < lmargin_aim) && (!out_margin))
+       {
+               hpos_aim = lmargin_aim;
+               stop = 1;
+       }
+       else if (hpos_aim < 0)
+       {
+               hpos_aim = 0;
+               stop = 1;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_next_col (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin; 
+       hpos_aim += cwidth_aim;
+       
+       if (((hpos_aim + cwidth_aim) > rmargin_aim) && (!out_margin))
+       {
+               stop = 1;
+       }
+       else if ((hpos_aim + cwidth_aim) > lwidth)
+       {
+               stop = 1;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+void move_back_col (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_col(ignore_margin))
+                       break;
+       }
+}
+
+void move_forward_col (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_col(ignore_margin))
+                       break;
+       }
+}
+
+void goto_col (uint8_t x)
+{
+       if (x == 0xff) //-1
+               x = 0;
+       
+       out_margin = 1;
+       hpos_aim = x * cwidth_aim;
+       
+       if ((hpos_aim + cwidth_aim) > lwidth)
+               hpos_aim = lwidth - cwidth_aim;
+       adjust_print_pos();
+}
+
+void goto_col_rel (uint8_t x)
+{
+       if (x == 0xff) //-1
+               x = 0;
+       
+       hpos_aim = lmargin_aim + x * cwidth_aim;
+       
+       if ((hpos_aim + cwidth_aim) > rmargin_aim)
+               hpos_aim = rmargin_aim - cwidth_aim;
+       adjust_print_pos();
+}
+
+static inline void goto_lmargin (void)
+{
+       hpos_aim = lmargin_aim;
+       adjust_print_pos();
+}
+
+static inline void goto_col0 (void)
+{
+       out_margin = 1;
+       hpos_aim = 0;
+       adjust_print_pos();
+}
+
+
+uint8_t goto_prev_vtab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       
+       do
+       {
+               --vpos_aim;
+               
+               if ((vpos_aim < tmargin) && (!out_margin)) // don't apply -1 offset
+               {
+                       stop = 1;
+                       if (vpos >= tmargin)
+                               vpos_aim = tmargin;
+                       else
+                               vpos_aim = vpos;
+               }
+               else if (vpos_aim < 0) // don't apply -1 offset
+               {
+                       stop = -1;
+                       if (vpos >= 0)
+                               vpos_aim = 0;
+                       else
+                               vpos_aim = vpos;
+               }
+       } while (!is_vtab(vpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_next_vtab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       
+       do
+       {
+               ++vpos_aim;
+               
+               if (((vpos_aim + lheight) > bmargin ) && (!out_margin)) // don't apply +1 offset
+               {
+                       stop = 1;
+                       break;
+               }
+               else if ((vpos_aim + lheight) > pheight) // don't apply +1 offset
+               {
+                       stop = 1;
+                       break;
+               }
+       } while (!is_vtab(vpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+void move_back_vtab (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_vtab(ignore_margin))
+                       break;
+       }
+}
+
+void move_forward_vtab (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_vtab(ignore_margin))
+               {
+                       if (paper != PAPER_CONTINUOUS)
+                               break;
+               }
+       }
+}
+
+uint8_t is_vtab (const int16_t y)
+{
+       uint8_t p, q;
+       
+       if ((y < 0) || (y >= VPOS_LIMIT))
+               return 0;
+       
+       p = (uint8_t)(y >> 3);
+       q = ((uint8_t)y) & 7;
+       
+       return VTAB[p] & (1<<q);
+}
+
+void set_vtab (const int16_t y)
+{
+       uint8_t p, q;
+       
+       if ((y < 0) || (y >= VPOS_LIMIT))
+               return;
+       
+       p = (uint8_t)(y >> 3);
+       q = ((uint8_t)y) & 7;
+       
+       VTAB[p] |= (1<<q);
+}
+
+void clear_vtab (const int16_t y)
+{
+       uint8_t p, q;
+       
+       if ((y < 0) || (y >= VPOS_LIMIT))
+               return;
+       
+       p = (uint8_t)(y >> 3);
+       q = ((uint8_t)y) & 7;
+       
+       VTAB[p] &= ~(1<<q);
+}
+
+static inline void clear_vtab_all (void)
+{
+       memset(VTAB, 0, N_VTAB);
+}
+
+
+uint8_t goto_prev_htab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       
+       do
+       {
+               --hpos_aim;
+               
+               if ((hpos_aim < lmargin_aim) && (!out_margin))
+               {
+                       hpos_aim = lmargin_aim;
+                       stop = 1;
+                       break;
+               }
+               else if (hpos_aim < 0)
+               {
+                       hpos_aim = 0;
+                       stop=1;
+                       break;
+               }
+       } while (!is_htab(hpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_next_htab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       
+       do
+       {
+               ++hpos_aim;
+               
+               if (((hpos_aim + cwidth_aim) > rmargin_aim) && (!out_margin))
+               {
+                       stop = 1;
+                       break;
+               }
+               else if ((hpos_aim + cwidth_aim) > lwidth)
+               {
+                       stop = 1;
+                       break;
+               }
+       } while (!is_htab(hpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+void move_back_htab (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_htab(ignore_margin))
+                       break;
+       }
+}
+
+void move_forward_htab (
+       const uint8_t n,
+       const uint8_t ignore_margin
+)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_htab(ignore_margin))
+                       break;
+       }
+}
+
+void goto_htab (
+       const int8_t x,
+       const uint8_t ignore_margin
+)
+{
+       int8_t dir;
+       int8_t i = 0;
+       
+       hpos_aim = lmargin_aim;
+       if (x>0)
+               dir = 1;
+       else if (x<0)
+               dir = -1;
+       else
+       {
+               adjust_print_pos();
+               return;
+       }
+       
+       do
+       {
+               hpos_aim += dir;
+               if (is_htab(hpos_aim))
+                       i += dir;
+               
+               if (((hpos_aim + cwidth_aim) > rmargin_aim) && (!out_margin))
+               {
+                       hpos_aim = rmargin_aim - cwidth_aim;
+                       break;
+               }
+               else if ((hpos_aim + cwidth_aim) > lwidth)
+               {
+                       hpos_aim = lwidth - cwidth_aim;
+                       break;
+               }
+               else if ((hpos_aim < lmargin_aim) && (!out_margin))
+               {
+                       hpos_aim = lmargin;
+                       break;
+               }
+               else if (hpos_aim < 0)
+               {
+                       hpos_aim = 0;
+                       break;
+               }
+               
+       } while (i != x);
+       
+       adjust_print_pos();
+}
+
+uint8_t is_htab (const int16_t x)
+{
+       uint8_t p, q;
+       
+       if ((x < 0) || (x >= HPOS_LIMIT))
+               return 0;
+       
+       p = (uint8_t)(x >> 3);
+       q = ((uint8_t)x) & 7;
+       
+       return HTAB[p] & (1<<q);
+}
+
+void set_htab (const int16_t x)
+{
+       uint8_t p, q;
+       
+       if ((x < 0) || (x >= HPOS_LIMIT))
+               return;
+       
+       p = (uint8_t)(x >> 3);
+       q = ((uint8_t)x) & 7;
+       
+       HTAB[p] |= (1<<q);
+}
+
+void clear_htab (const int16_t x)
+{
+       uint8_t p, q;
+       
+       if ((x < 0) || (x >= HPOS_LIMIT))
+               return;
+       
+       p = (uint8_t)(x >> 3);
+       q = ((uint8_t)x) & 7;
+       
+       HTAB[p] &= ~(1<<q);
+}
+
+static inline void clear_htab_ch (uint8_t x)
+{
+       if (x==0xff)
+               x = 0;
+       clear_htab(cwidth_aim * (int16_t)x);
+}
+
+static inline void clear_htab_all (void)
+{
+       memset(HTAB, 0, N_HTAB);
+}
+
+void adjust_print_pos (void)
+{
+       uint8_t margin_requested = 0;
+       
+       // dest. inside margins; cancel the privilege
+       if (
+               (hpos_aim >= lmargin_aim) &&
+               ((hpos_aim + cwidth_aim) <= rmargin_aim) &&
+               (vpos_aim >= tmargin - 1) &&
+               ((vpos_aim + lheight) <= (bmargin + 1))
+       )
+               out_margin = 0;
+       
+       // outside current margins; adjust margins
+       if ((hpos > rmargin)/* && (hpos <= rmargin_aim)*/)
+       {
+               add_print_key(CODE_RMARGIN);
+               rmargin = hpos;
+       }
+       if ((hpos < lmargin) && (hpos >= lmargin_aim))
+       {
+               add_print_key(CODE_LMARGIN);
+               lmargin = hpos;
+       }
+       else if ((hpos == lmargin_aim) && (lmargin != lmargin_aim))
+       {
+               add_print_key(CODE_LMARGIN);
+               lmargin = hpos;
+       }
+       
+       // requested move outside right margin
+       if ((hpos_aim + cwidth_aim) > rmargin_aim)
+       {
+               // not allowed to leave; goto next line
+               if (!out_margin)
+               {
+                       hpos_aim = lmargin_aim;
+                       vpos_aim += lheight;
+               }
+               // requested move outside right edge; stay at edge
+               else if ((hpos_aim + cwidth_aim) > lwidth)
+               {
+                       hpos_aim = lwidth - cwidth_aim;
+               }
+       }
+       
+       // requested move outside left margin
+       if (hpos_aim < lmargin_aim)
+       {
+               // not allowed to leave; stay at margin
+               if (!out_margin)
+                       hpos_aim = lmargin_aim;
+               // requested move outside left edge; stay at edge
+               else if (hpos_aim < 0) 
+                       hpos_aim = 0;
+       }
+       
+       // requested move outside bottom margin; wait for new page
+       if ((vpos_aim + lheight) > (bmargin + 1))
+       {
+               if (!out_margin ) // not allowed to leave
+               {
+                       if (vpos_aim < pheight + tmargin)
+                               vpos_aim = pheight + tmargin; // skip to next page top margin
+                       set_alarm = 1;
+                       set_led = 10;
+                       wait_page = 1;
+               }
+               else if ((vpos_aim + lheight) > (pheight + 1)) // requested move outside bottom edge
+               {
+                       set_alarm = 1;
+                       set_led = 10;
+                       wait_page = 1;
+               }
+       }
+       
+       // requested move outside top margin
+       if (vpos_aim < (tmargin - 1))
+       {
+               // not allowed to leave; stay at top margin
+               if (!out_margin)
+               {
+                       if (vpos >= tmargin)
+                               vpos_aim = tmargin;
+                       else
+                               vpos_aim = vpos;
+               }
+               // requested move outside top edge; stay at edge
+               else if (vpos_aim < -1)
+               {
+                       if (vpos >= 0)
+                               vpos_aim = 0;
+                       else
+                               vpos_aim = vpos;
+               }
+       }
+       
+       // left from goal; move right
+       while (hpos < hpos_aim)
+       {
+               // move outside margin
+               if ((hpos + cwidth > rmargin) && (!margin_requested))
+               {
+                       add_print_key(KEY_MARGIN);
+                       margin_requested = 1;
+               }
+               
+               // move right by 1 space
+               add_print_key(KEY_SPACE);
+               hpos += cwidth;
+       }
+       margin_requested = 0;
+       // outside margin; adjust margin
+       if (hpos > rmargin)
+       {
+               add_print_key(CODE_RMARGIN);
+               rmargin = hpos;
+       }
+       
+       // right from goal & from left margin; move to left margin
+       if ((hpos_aim <= lmargin) && (hpos > lmargin))
+       {
+               add_print_key(CODE_RETURN);
+               hpos = lmargin;
+       }
+       
+       // right from goal; move left
+       while (hpos > hpos_aim)
+       {
+               // away by at least 1 space
+               if (hpos >= hpos_aim + cwidth) 
+               {
+                       // move outside margin
+                       if ((hpos < lmargin + cwidth) && (!margin_requested))
+                       {
+                               add_print_key(KEY_MARGIN);
+                               margin_requested = 1;
+                       }
+                       
+                       // move left by 1 space
+                       add_print_key(KEY_BACK);
+                       hpos -= cwidth;
+               }
+               // away by less than 1 space
+               else
+               {
+                       // move outside margin
+                       if ((hpos < lmargin + 1) && (!margin_requested))
+                       {
+                               add_print_key(KEY_MARGIN);
+                               margin_requested = 1;
+                       }
+                       
+                       // move left by 1 unit
+                       add_print_key(CODE_STEPLEFT);
+                       --hpos;
+               }
+       }
+       margin_requested = 0;
+       // outside margin; adjust margin
+       if((hpos < lmargin) && (hpos >= lmargin_aim))
+       {
+               add_print_key(CODE_LMARGIN);
+               lmargin = hpos;
+       }
+       
+       // above goal; move down
+       while (vpos < vpos_aim)
+       {
+               add_print_key(CODE_HALFDOWN);
+               ++vpos;
+       }
+       
+       // below goal; move up
+       while (vpos > vpos_aim)
+       {
+               add_print_key(CODE_HALFUP);
+               --vpos;
+       }
+       
+       // next char will be out of margin
+       if (hpos + cwidth > rmargin)
+       {
+               add_print_key(KEY_MARGIN);
+               // margin_requested = 1;
+       }
+       
+       // out of page; renormalise coordinates
+       while (vpos_aim < -1)
+       {
+               vpos_aim += pheight;
+               vpos += pheight;
+               --ppos;
+       }
+       while ((vpos_aim + lheight) > (pheight + 1))
+       {
+               vpos_aim -= pheight;
+               vpos -= pheight;
+               ++ppos;
+       }
+       
+       // opportunity to adjust char width
+       if (cwidth_todo & (hpos == lmargin))
+               set_cwidth(cwidth_aim);
+}
+
+
+/* size, margin, spacing */
+
+void set_pheight (const uint16_t y)
+{
+       pheight = y;
+       
+       // ensure at least 1 line in page & don't exceed limits
+       if (pheight < lheight)
+               pheight = lheight;
+       if (pheight > VPOS_LIMIT)
+               pheight = VPOS_LIMIT;
+       if (bmargin > pheight)
+               bmargin = pheight;
+       if(tmargin > bmargin - lheight)
+               tmargin = bmargin - lheight;
+}
+
+void set_lheight (const uint8_t y)
+{
+       lheight = y;
+       
+       // ensure at least 1 line in page
+       if (pheight < lheight)
+               pheight = lheight;
+       if (tmargin + lheight > pheight)
+               tmargin = pheight - lheight;
+       if (tmargin + lheight > bmargin)
+               bmargin = tmargin + lheight;
+}
+
+void set_tmargin (int16_t y)
+{
+       if (y<0)
+               y = 0;
+       
+       tmargin = y;
+       
+       if ((tmargin + lheight) > VPOS_LIMIT)
+               tmargin = VPOS_LIMIT - lheight;
+       if ((tmargin + lheight) > pheight)
+               pheight = tmargin + lheight;
+       if ((tmargin + lheight) > bmargin)
+               bmargin = tmargin + lheight;
+}
+
+void set_bmargin (int16_t y)
+{
+       if (y<0)
+               y = 0;
+       
+       bmargin = y;
+       
+       if (bmargin < lheight)
+               bmargin = lheight;
+       if (bmargin > VPOS_LIMIT)
+               bmargin = VPOS_LIMIT;
+       if (bmargin > pheight)
+               pheight = bmargin;
+       if ((tmargin + lheight) > bmargin)
+       {
+               tmargin = bmargin - lheight;
+       }
+}
+
+void set_bmargin_rel (const int16_t y)
+{
+       if (y>0)
+               set_bmargin(tmargin + y); // relative to top margin
+       else
+               set_bmargin(pheight + y); // relative to bottom edge
+}
+
+static inline void set_tmargin_ch (uint8_t y)
+{
+       if(y==0xFF)
+               y = 0;
+       set_tmargin(lheight * (int16_t)y);
+}
+
+static inline void set_bmargin_ch (uint8_t y)
+{
+       if(y==0xFF)
+               y = 0;
+       set_bmargin(lheight * (int16_t)y);
+}
+
+
+void set_lwidth (const uint16_t x)
+{
+       lwidth = + x;
+       
+       // ensure at least 1 character in line & don't exceed limits
+       if (lwidth < cwidth_aim)
+               lwidth = cwidth_aim;
+       if (lwidth > HPOS_LIMIT)
+               lwidth = HPOS_LIMIT;
+       if(rmargin_aim > lwidth)
+               rmargin_aim = lwidth;
+       if(lmargin_aim > (rmargin_aim - cwidth_aim))
+               lmargin_aim = rmargin_aim - cwidth_aim;
+}
+
+void set_cwidth (const uint8_t x)
+{
+       cwidth_aim = x;
+       
+       // ensure at least 1 character in line
+       if (lwidth < cwidth_aim)
+               lwidth = cwidth_aim;
+       if (lmargin + cwidth_aim > lwidth)
+               lmargin = lwidth - cwidth_aim;
+       if (lmargin + cwidth_aim > rmargin_aim)
+               rmargin_aim = lmargin_aim + cwidth_aim;
+       
+       if(hpos == lmargin) // opportunity to adjust at machine
+       {
+               if (x == WIDTH_10)
+               {
+                       if (cwidth != WIDTH_10)
+                               add_print_key(CODE_PITCH10);
+                       cwidth = WIDTH_10;
+               }
+               else
+               {
+                       if (cwidth != WIDTH_12)
+                               add_print_key(CODE_PITCH12);
+                       cwidth = WIDTH_12;
+               }
+               cwidth_todo = 0;
+       }
+       else
+               cwidth_todo = 1;
+}
+
+void set_lmargin (int16_t x)
+{
+       if (x<0)
+               x = 0;
+       
+       lmargin_aim = x;
+       
+       if ((lmargin_aim + cwidth_aim) > HPOS_LIMIT)
+               lmargin_aim = HPOS_LIMIT - cwidth_aim;
+       if ((lmargin_aim + cwidth_aim) > lwidth)
+               lwidth = lmargin_aim + cwidth_aim;
+       if ((lmargin_aim + cwidth_aim) > rmargin_aim)
+               rmargin_aim = lmargin_aim + cwidth_aim;
+}
+
+void set_rmargin (int16_t x)
+{
+       if (x<0)
+               x = 0;
+       
+       rmargin_aim = x;
+       
+       if (rmargin_aim < cwidth_aim)
+               rmargin_aim = cwidth_aim;
+       if (rmargin_aim > HPOS_LIMIT)
+               rmargin_aim = HPOS_LIMIT;
+       if (rmargin_aim > lwidth)
+               lwidth = rmargin_aim;
+       if((lmargin_aim + cwidth_aim) > rmargin_aim)
+               lmargin_aim = rmargin_aim - cwidth_aim;
+}
+
+void set_rmargin_rel (const int16_t x)
+{
+       if (x>0)
+               set_rmargin(lmargin_aim + x); // relative to left margin
+       else
+               set_rmargin(lwidth + x); // relative to rigth edge
+}
+
+static inline void set_lmargin_ch (uint8_t x)
+{
+       if(x==0xFF)
+               x = 0;
+       set_lmargin(cwidth_aim * (int16_t)x);
+}
+
+static inline void set_rmargin_ch (uint8_t x)
+{
+       if(x==0xFF)
+               x = 0;
+       set_rmargin(cwidth_aim * (int16_t)x);
+}
+
+
+void set_theight (const uint8_t y)
+{
+       int16_t i;
+       
+       clear_vtab_all();
+       
+       if (y==0)
+               return;
+       
+       set_vtab(0);
+       for (i=tmargin; i>0; i-=y)
+               set_vtab(i);
+       for (i=tmargin; i<bmargin; i+=y)
+               set_vtab(i);
+       for (i=bmargin; i<VPOS_LIMIT; i+=y)
+               set_vtab(i);
+}
+
+void set_twidth (const uint8_t x)
+{
+       int16_t i;
+       
+       clear_htab_all();
+       
+       if (x==0)
+               return;
+       
+       set_htab(0);
+       for (i=lmargin_aim; i>0; i-=x)
+               set_htab(i);
+       for (i=lmargin_aim; i<rmargin_aim; i+=x)
+               set_htab(i);
+       for (i=rmargin_aim; i<HPOS_LIMIT; i+=x)
+               set_htab(i);
+}
+
+static inline void set_theight_ch (const uint8_t y)
+{
+       theight_ch = y;
+       set_theight(y * lheight);
+}
+
+static inline void set_twidth_ch (const uint8_t x)
+{
+       twidth_ch = x;
+       set_twidth(x * cwidth_aim);
+}
+
+
+/* operating mode */
+
+void set_mode (uint8_t new_mode)
+{
+       if (
+               (new_mode & MODE_HEX) &&
+               (!(mode & MODE_HEX))
+       )
+               handle_hex(HEX_RESET, 0);
+       else if (
+               (!(new_mode & MODE_HEX)) &&
+               (mode & MODE_HEX)
+       )
+               handle_hex(HEX_FORCE | HEX_FINISH, 0);
+       
+       mode = new_mode;
+}
+
+void become_typewriter (void)
+{
+       set_mode(MODE_TYPE);
+       
+       // ok, prepare for total stop
+       // no more int.
+       
+       cli();
+       
+       // block injected keyboard
+       PORT_CTRL |= EN_PRINT;
+       
+       
+       // don't accept any input more
+       reject_income();
+       
+       // wait to make sure that XOFF (if relevant) was sent
+       while (send_xonoff)
+               handle_outcome();
+       
+       // don't request any output more
+       unrequest_outcome();
+       
+       // clean up IO, most importanlty, LED must be off.
+       PORT_CTRL |= LED | KEY;
+       PORT_KEY &= ~(KEYB_CODE | KEYB_SHIFT);
+       
+       // allow real keyboard
+       PORT_CTRL &= ~EN_KEYB;
+       
+       // stop performing actions
+       while (1)
+       {
+               allow_sleep(0xff);
+               goto_sleep();
+       }
+}
+
+void become_terminal (void)
+{
+       set_mode(loaded_mode | MODE_TERM);
+       
+       // block real keyboard, allow injected keyboard
+       PORT_CTRL |= EN_KEYB;
+       PORT_CTRL &= ~EN_PRINT;
+       
+       accept_income();
+       
+       add_print_key(CODE_AUTORETURN); // disable auto-return
+       set_style(loaded_style);
+       
+       vpos = tmargin;
+       vpos_aim = tmargin;
+       hpos_aim = lmargin_aim;
+       
+       adjust_print_pos();
+}
+
+
+static inline void set_baudrate (const uint8_t setting)
+{
+       if (setting < N_UART_BAUD)
+       {
+               baud = setting;
+               if (UART_DIV[setting] <= 0x1000)
+               {
+                       UCSR0A = (1<<U2X0); // 2x speed mode
+                       UBRR0 = UART_DIV[setting]-1;
+               }
+               else
+               {
+                       UCSR0A = 0; // 1x speed mode
+                       UBRR0 = (UART_DIV[setting]>>1)-1;
+               }
+       }
+}
+
+static inline void set_serial_mode (const uint8_t setting)
+{
+       serial_mode = setting;
+       UCSR0C = setting; // the flags in SW and in register are the same :)
+}
+
+static inline void set_encoding (const uint8_t setting)
+{
+       if (setting & ENC_UNI)
+               encoding = setting;
+       else if (setting < N_ENC)
+       {
+               CH_CP = CH_LIST[setting];
+               KEYMAP_CP = KEYMAP_LIST[setting];
+               C1 = ENC_C1[setting];
+               encoding = setting;
+               if (C1)
+                       GR_table[GR_index] = setting;
+       }
+}
+
+static inline void set_encoding_GR (const uint8_t setting)
+{
+       if ((setting>=1) && (setting<=3))
+       {
+               GR_index = setting;
+               set_encoding(GR_table[GR_index]);
+       }
+}
+
+void set_flowcontrol (uint8_t setting)
+{
+       flow = setting & (FLOW_HW | FLOW_SW);
+       local_xonoff = 0;
+       remote_xonoff = XON;
+       unrequest_outcome();
+       if (DIFF_BP(income_w, income_r, N_INCOME_BUFFER) < INCOME_BUFFER_HIGH)
+               accept_income();
+       else
+               reject_income();
+}
+
+
+void set_style (const uint8_t new_style)
+{
+       if ( // set bold
+               (new_style & STYLE_BOLD) &&
+               (!(style & STYLE_BOLD))
+       )
+               add_print_key(CODE_BOLD);
+       else if ( // clear bold
+               (!(new_style & STYLE_BOLD)) &&
+               (style & STYLE_BOLD)
+       )
+               add_print_key(CODE_BOLD);
+       
+       if ( // set strong
+               (new_style & STYLE_STRONG) &&
+               (!(style & STYLE_STRONG))
+       )
+               add_print_key(CODE_STRONG);
+       else if ( // clear strong
+               (!(new_style & STYLE_STRONG)) &&
+               (style & STYLE_STRONG)
+       )
+               add_print_key(CODE_WEAK);
+       
+       style = new_style;
+}
+
+static inline void set_style_normal (void)
+{
+       set_style((style & STYLE_STRONG) | STYLE_NORMAL);
+}
+
+static inline void set_style_bold (void)
+{
+       set_style(style | STYLE_BOLD);
+}
+
+static inline void set_style_nobold (void)
+{
+       set_style(style & ~STYLE_BOLD);
+}
+
+static inline void toggle_bold (void)
+{
+       set_style(style ^ STYLE_BOLD);
+}
+
+static inline void set_style_under (void)
+{
+       set_style((style & ~STYLE_UNDER2) | STYLE_UNDER);
+}
+
+static inline void set_style_under2 (void)
+{
+       set_style((style & ~STYLE_UNDER) | STYLE_UNDER2);
+}
+
+static inline void set_style_nounder (void)
+{
+       set_style(style & ~(STYLE_UNDER | STYLE_UNDER2));
+}
+
+static void inline toggle_under (void)
+{
+       if (style & (STYLE_UNDER | STYLE_UNDER2))
+               set_style_nounder();
+       else
+               set_style_under();
+}
+
+static void inline toggle_under2 (void)
+{
+       if (style & (STYLE_UNDER | STYLE_UNDER2))
+               set_style_nounder();
+       else
+               set_style_under2();
+}
+
+static inline void set_style_cross (void)
+{
+       set_style(style | STYLE_CROSS);
+}
+
+static inline void set_style_nocross (void)
+{
+       set_style(style & ~STYLE_CROSS);
+}
+
+static inline void toggle_cross (void)
+{
+       set_style(style ^ STYLE_CROSS);
+}
+
+static inline void set_style_over (void)
+{
+       set_style(style | STYLE_OVER);
+}
+
+static inline void set_style_noover (void)
+{
+       set_style(style & ~STYLE_OVER);
+}
+
+static inline void toggle_over (void)
+{
+       set_style(style ^ STYLE_OVER);
+}
+
+static inline void set_style_strong (void)
+{
+       set_style(style | STYLE_STRONG);
+}
+
+static inline void set_style_weak (void)
+{
+       set_style(style & ~STYLE_STRONG);
+}
+
+
+/* flow control */
+
+void update_flowcontrol_hw (void)
+{
+       uint8_t out = 0;
+       
+       switch (flow & FLOW_HW)
+       {
+       case FLOW_HD_DCE: // we are the DCE; RTS/CTS
+               if (!income_requested()) // only assert CTS if there was RTS
+                       break;
+       case FLOW_FD: // RTR/CTS
+               out = income_accepted; // assert RTR/CTS if we can accept incoming data
+               break;
+       case FLOW_HD_DTE: // we are the DTE; RTS/CTS
+               out = outcome_requested; // assert RTS if we want to send outcoming data
+               break;
+       default: // no flow control
+               out = 1; // always assert
+       }
+       if (out)
+               PORT_COMM &= ~SYNC_OUT; // assert RTR/RTS/CTS
+       else
+               PORT_COMM |= SYNC_OUT; // deassert RTR/RTS/CTS
+}
+
+void update_flowcontrol_sw (void)
+{
+       if ((flow & FLOW_SW) == FLOW_XONOFF)
+       {
+               if (income_accepted)
+               {
+                       if (local_xonoff != XON)
+                       {
+                               local_xonoff = XON;
+                               send_xonoff = XON;
+                               cancel_sleep(WAKEUP_OUTCOME);
+                       }
+               }
+               else
+               {
+                       if (local_xonoff != XOFF)
+                       {
+                               local_xonoff = XOFF;
+                               send_xonoff = XOFF;
+                               cancel_sleep(WAKEUP_OUTCOME);
+                       }
+               }
+       }
+}
+
+static inline void request_outcome (void)
+{
+       // we want to send outcoming data
+       outcome_requested = 1;
+       // this will only have an effect if we are the DTE in RTS/CTS mode
+       update_flowcontrol_hw();
+}
+
+static inline void unrequest_outcome (void)
+{
+       // we don't want to send outcoming data
+       outcome_requested = 0;
+       // this will only have an effect if we are the DTE in RTS/CTS mode
+       update_flowcontrol_hw();
+}
+
+static inline void accept_income (void)
+{
+       // we want to accept incoming data
+       income_accepted = 1;
+       // this will have effect in RTR/CTS mode or if we are the DCE in RTS/CTS mode
+       update_flowcontrol_hw();
+       // this will have effect in XON/XOFF mode
+       update_flowcontrol_sw();
+}
+
+static inline void reject_income (void)
+{
+       // we don't want to accept incoming data
+       income_accepted = 0;
+       // this will have effect in RTR/CTS mode or if we are the DCE in RTS/CTS mode
+       update_flowcontrol_hw();
+       // this will have effect in XON/XOFF mode
+       update_flowcontrol_sw();
+}
+
+uint8_t income_requested (void)
+{
+       // does remote machine want to send incoming data?
+       if ((flow & FLOW_HW) == FLOW_HD_DCE) // we are the DCE in RTS/CTS mode
+       {
+               if (PORT_COMM & SYNC_IN); // only if DTE asserted RTS
+                       return 0;
+       }
+       return 0xFF; // all other cases, arrumed always true
+}
+
+uint8_t outcome_accepted (void)
+{
+       // does remote machine accept outcoming data?
+       
+       // at first we assume YES, then we look for reasons for NO.
+       uint8_t accepted = 0xFF;
+       
+       switch (flow & FLOW_HW)
+       {
+       case FLOW_FD: // RTR/CTS
+       case FLOW_HD_DTE: // we are the DTE; RTS/CTS
+               if (PORT_COMM & SYNC_IN) // sorry, remote didn't assert RTR/CTS
+                       accepted = 0;
+               break;
+       case FLOW_HD_DCE: // we are the DCE; RTS/CTS
+               if (!(PORT_COMM & SYNC_IN)) // sorry, remote wants to send now, not to receive
+                       accepted = 0;
+       }
+       if ((flow & FLOW_SW) == FLOW_XONOFF) // XON/XOFF
+       {
+               if (remote_xonoff != XON) // sorry, remote said XOFF
+                       accepted = 0;
+       }
+       return accepted;
+}
+
+
+/* eeprom settings storage */
+
+static inline uint8_t eeprom_read (const uint16_t address)
+{
+       uint8_t data;
+       
+       while (EECR & (1<<EEPE))
+               ;
+       EEAR = address;
+       EECR |= (1<<EERE);
+       data = EEDR;
+       
+       return data;
+}
+
+static inline void eeprom_write (
+       const uint16_t address,
+       const uint8_t  data
+)
+{
+       while (EECR & (1<<EEPE))
+               ;
+       EEAR = address;
+       EEDR = data;
+       cli();
+       EECR |= (1<<EEMPE);
+       EECR |= (1<<EEPE);
+       sei();
+}
+
+
+uint8_t eeprom_read_record (
+       const uint16_t address,
+       uint8_t * const id,
+       uint16_t * const data
+)
+{
+       uint8_t block[4];
+       uint8_t checksum=0;
+       uint8_t i;
+       
+       for(i=0; i<4; ++i)
+       {
+               block[i] = eeprom_read(address + i);
+               checksum += block[i];
+       }
+       
+       *id = block[0];
+       *data = (((uint16_t)block[3])<<8)|block[2];
+       return checksum;
+}
+
+void eeprom_write_record (
+       const uint16_t address,
+       const uint8_t id,
+       const uint16_t data
+)
+{
+       uint8_t block[4];
+       uint8_t checksum=0;
+       uint8_t i;
+       
+       EECR &= ~(1<<EEPM0);
+       EECR |= (1<<EEPM1);
+       
+       block[0] = id;
+       checksum -= block[0];
+       
+       block[2] = data & 0xff;
+       checksum -= block[2];
+       
+       block[3] = data >> 8;
+       checksum -= block[3];
+       
+       block[1] = checksum;
+       
+       for(i=0; i<4; ++i)
+       {
+               eeprom_write(address + i, block[i]);
+       }
+}
+
+void eeprom_erase_record (const uint16_t address)
+{
+       uint8_t i;
+       uint8_t io;
+       
+       EECR |= (1<<EEPM0);
+       EECR &= ~(1<<EEPM1);
+       
+       for(i=0; i<4; ++i)
+       {
+               io = eeprom_read(address + i);
+               if (io != 0xff)
+                       eeprom_write(address + i, 0xff);
+       }
+}
+
+void store_all_config (void)
+{
+       ee_address = 0;
+       eeprom_write_record(ee_address, ID_BAUD, baud);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_BITS, serial_mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_MODE, mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_NL_MODE, nl_mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_BS_MODE, bs_mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_ENCODING, encoding);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_REPLACE, replace);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_LWIDTH, lwidth);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_LMARGIN, lmargin_aim);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_RMARGIN, rmargin_aim);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_PHEIGHT, pheight);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_TMARGIN, tmargin);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_BMARGIN, bmargin);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_HTAB, twidth_ch);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_VTAB, theight_ch);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_CWIDTH, cwidth_aim);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_LHEIGHT, lheight);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_FLOW, flow);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_PAPER, paper);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_STYLE, style);
+       ee_address+=4;
+       eeprom_erase_record(ee_address);
+}
+
+void store_single_config (const uint8_t id)
+{
+       if (ee_address >= EEPROM_SIZE - 4)
+               store_all_config();
+       else
+       {
+               switch(id)
+               {
+               case ID_BAUD:
+                       eeprom_write_record(ee_address, ID_BAUD, baud);
+                       break;
+               case ID_BITS:
+                       eeprom_write_record(ee_address, ID_BITS, serial_mode);
+                       break;
+               case ID_MODE:
+                       eeprom_write_record(ee_address, ID_MODE, mode);
+                       break;
+               case ID_NL_MODE:
+                       eeprom_write_record(ee_address, ID_NL_MODE, nl_mode);
+                       break;
+               case ID_BS_MODE:
+                       eeprom_write_record(ee_address, ID_BS_MODE, bs_mode);
+                       break;
+               case ID_ENCODING:
+                       eeprom_write_record(ee_address, ID_ENCODING, encoding);
+                       break;
+               case ID_REPLACE:
+                       eeprom_write_record(ee_address, ID_REPLACE, replace);
+                       break;
+               case ID_LWIDTH:
+                       eeprom_write_record(ee_address, ID_LWIDTH, lwidth);
+                       break;
+               case ID_LMARGIN:
+                       eeprom_write_record(ee_address, ID_LMARGIN, lmargin_aim);
+                       break;
+               case ID_RMARGIN:
+                       eeprom_write_record(ee_address, ID_RMARGIN, rmargin_aim);
+                       break;
+               case ID_PHEIGHT:
+                       eeprom_write_record(ee_address, ID_PHEIGHT, pheight);
+                       break;
+               case ID_TMARGIN:
+                       eeprom_write_record(ee_address, ID_TMARGIN, tmargin);
+                       break;
+               case ID_BMARGIN:
+                       eeprom_write_record(ee_address, ID_BMARGIN, bmargin);
+                       break;
+               case ID_HTAB:
+                       eeprom_write_record(ee_address, ID_HTAB, twidth_ch);
+                       break;
+               case ID_VTAB:
+                       eeprom_write_record(ee_address, ID_VTAB, theight_ch);
+                       break;
+               case ID_CWIDTH:
+                       eeprom_write_record(ee_address, ID_CWIDTH, cwidth_aim);
+                       break;
+               case ID_LHEIGHT:
+                       eeprom_write_record(ee_address, ID_LHEIGHT, lheight);
+                       break;
+               case ID_FLOW:
+                       eeprom_write_record(ee_address, ID_FLOW, flow);
+                       break;
+               case ID_PAPER:
+                       eeprom_write_record(ee_address, ID_PAPER, paper);
+                       break;
+               case ID_STYLE:
+                       eeprom_write_record(ee_address, ID_STYLE, style);
+                       break;
+               default:
+                       return;
+               }
+               ee_address += 4;
+               eeprom_erase_record(ee_address);
+       }
+}
+
+void load_config (void)
+{
+       uint8_t  id;
+       uint16_t value;
+       
+       uint8_t  ld_baud = baud;
+       uint8_t  ld_serial_mode = serial_mode;
+       uint8_t  ld_flow = flow;
+       uint8_t  ld_encoding = encoding;
+       uint16_t ld_lwidth = lwidth;
+       uint16_t ld_lmargin = lmargin_aim;
+       uint16_t ld_rmargin = lmargin_aim;
+       uint16_t ld_pheight = pheight;
+       uint16_t ld_tmargin = tmargin;
+       uint16_t ld_bmargin = bmargin;
+       uint8_t  ld_twidth = twidth_ch;
+       uint8_t  ld_theight = theight_ch;
+       uint8_t  ld_cwidth = cwidth_aim;
+       uint8_t  ld_lheight = lheight;
+       
+       ee_address = 0;
+       while(1)
+       {
+               if (eeprom_read_record(ee_address, &id, &value))
+               {
+                       eeprom_erase_record(ee_address);
+                       break;
+               }
+               switch (id)
+               {
+               case ID_BAUD:
+                       ld_baud = (uint8_t)value;
+                       break;
+               case ID_BITS:
+                       ld_serial_mode = (uint8_t)value;
+                       break;
+               case ID_MODE:
+                       loaded_mode = (uint8_t)value;
+                       break;
+               case ID_NL_MODE:
+                       nl_mode = (uint8_t)value;
+                       break;
+               case ID_BS_MODE:
+                       bs_mode = (uint8_t)value;
+                       break;
+               case ID_ENCODING:
+                       ld_encoding = (uint8_t)value;
+                       break;
+               case ID_REPLACE:
+                       replace = (uint8_t)value;
+                       break;
+               case ID_LWIDTH:
+                       ld_lwidth = value;
+                       break;
+               case ID_LMARGIN:
+                       ld_lmargin = value;
+                       break;
+               case ID_RMARGIN:
+                       ld_rmargin = value;
+                       break;
+               case ID_PHEIGHT:
+                       ld_pheight = value;
+                       break;
+               case ID_TMARGIN:
+                       ld_tmargin =value;
+                       break;
+               case ID_BMARGIN:
+                       ld_bmargin =value;
+                       break;
+               case ID_HTAB:
+                       ld_twidth = value;
+                       break;
+               case ID_VTAB:
+                       ld_theight = (uint8_t)value;
+                       break;
+               case ID_CWIDTH:
+                       ld_cwidth = (uint8_t)value;
+                       break;
+               case ID_LHEIGHT:
+                       ld_lheight = value;
+                       break;
+               case ID_FLOW:
+                       ld_flow = (uint8_t)value;
+                       break;
+               case ID_PAPER:
+                       paper = (uint8_t)value;
+                       break;
+               case ID_STYLE:
+                       loaded_style = (uint8_t)value;
+                       break;
+               default:
+                       break;
+               }
+               ee_address +=4;
+               if (ee_address >= EEPROM_SIZE)
+                       break;
+       }
+       
+       set_baudrate(ld_baud);
+       set_serial_mode(ld_serial_mode);
+       set_flowcontrol(ld_flow);
+       set_encoding(ld_encoding);
+       
+       set_pheight(ld_pheight);
+       set_lwidth(ld_lwidth);
+       set_lheight(ld_lheight);
+       set_cwidth(ld_cwidth);
+       set_tmargin(ld_tmargin);
+       set_bmargin(ld_bmargin);
+       set_lmargin(ld_lmargin);
+       set_rmargin(ld_rmargin);
+       set_theight_ch(ld_theight);
+       set_twidth_ch(ld_twidth);
+}
+
+
+/* sleep mode */
+
+static inline void cancel_sleep (const uint8_t flag)
+{
+       SMCR &= ~(1 << SE); //disable sleep
+       keep_active |= flag;
+}
+
+static inline void allow_sleep (const uint8_t flag)
+{
+       keep_active &= ~flag;
+}
+
+static inline void goto_sleep (void)
+{
+       if (!keep_active)
+       {
+               SMCR =
+                       (1 << SE) | // enable sleep
+                       (0 << SM0); // idle
+               sleep_cpu();
+       }
+}
+
+
+/* support util. */
+
+uint8_t make_dec_string ( // create decimal text representation of number
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits
+)
+{
+       int8_t i, j;
+       uint8_t text[10];
+       uint8_t digit;
+       uint8_t first_digit = 9;
+       
+       for(i=9; i>=0; --i)
+       {
+               digit = value % 10;
+               value /= 10;
+               
+               if (digit != 0)
+                       first_digit = i;
+               
+               text[i] = digit + 0x30;
+       }
+       if ((10 - min_digits) < first_digit)
+               first_digit = 10 - min_digits;
+       if ((10 - first_digit) > max_digits)
+               first_digit = 10 - max_digits;
+       
+       for (i=first_digit, j=0; i<10; ++i, ++j)
+               string[j] = text[i];
+       
+       return 10 - first_digit; // return actual number of digits
+}
+
+uint8_t make_hex_string ( // create hexadecimal text representation of number
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits,
+       const uint8_t uppercase
+)
+{
+       int8_t i, j;
+       uint8_t text[8];
+       uint8_t digit;
+       uint8_t first_digit = 7;
+       
+       for(i=7; i>=0; --i)
+       {
+               digit = value & 0x0f;
+               value >>=4;
+               
+               if (digit != 0)
+                       first_digit = i;
+               
+               if (digit < 10)
+                       text[i] = digit + 0x30;
+               else if (uppercase)
+                       text[i] = digit + 0x41 - 10;
+               else
+                       text[i] = digit + 0x61 - 10;
+       }
+       if ((8 - min_digits) < first_digit)
+               first_digit = 8 - min_digits;
+       if ((8 - first_digit) > max_digits)
+               first_digit = 8 - max_digits;
+       
+       for (i=first_digit, j=0; i<8; ++i, ++j)
+               string[j] = text[i];
+       
+       return 8 - first_digit; // return actual number of digits
+}
+
+uint32_t unit (uint32_t x, const uint16_t mul, const uint16_t div)
+{
+       if (div) // normal operation
+       {
+               if (mul != 1)
+                       x *= mul;
+               if (div>1)
+                       x /= div;
+       }
+       else if (mul)
+               x *= lheight;
+       else
+               x *= cwidth_aim;
+       return x;
+}
diff --git a/maszyna_.c b/maszyna_.c
new file mode 100644 (file)
index 0000000..e749c98
--- /dev/null
@@ -0,0 +1,5228 @@
+/*
+Copyright 2022 Balthasar Szczepański
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <avr/sleep.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "keyboard.h"
+#include "keyboard-patterns.h"
+
+
+// #define UART_DIV_75    13333 // 13333 1/3         75.0019  +0.010%  +
+   #define UART_DIV_150    6667 //  6666 2/3        149.9925  -0.005%  +
+   #define UART_DIV_300    3333 //  3333 1/3        300.0300  +0.010%  +
+   #define UART_DIV_600    1667 //  1666 2/3        599.8800  -0.020%  +
+   #define UART_DIV_1200    833 //   833 1/3       1200.4802  +0.040%  +
+   #define UART_DIV_2400    417 //   416 2/3       2398.0815  -0.080%  +
+   #define UART_DIV_4800    208 //   208 1/3       4807.6923  +0.160%  +
+   #define UART_DIV_9600    104 //   104 1/6       9615.3846  +0.160%  +
+   #define UART_DIV_19200    52 //    52 1/12     19230.7692  +0.160%  +
+   #define UART_DIV_38400    26 //    26 1/24     38461.5384  +0.160%  +
+// #define UART_DIV_57600    17 //    17 17/36    58823.5294  +2.124%  -
+   #define UART_DIV_115200    9 //     8 49/72   111111.1111  -3.549%  -
+// #define UART_DIV_230400    4 //     4 49/144  250000.0000  +8.507%  -
+// #define UART_DIV_460800    2 //     2 49/284  500000.0000  +8.507%  -
+// #define UART_DIV_500000    2 //     2         500000.0000   0.000%  +
+// #define UART_DIV_576000    2 //     1 53/72   500000.0000 -13.194%  -
+// #define UART_DIV_921600    1 //     1 49/576 1000000.0000  +8.507%  +
+// #define UART_DIV_1000000   1 //     1        1000000.0000   0.000%  -
+
+#define UART_BAUD_150    0
+#define UART_BAUD_300    1
+#define UART_BAUD_600    2
+#define UART_BAUD_1200   3
+#define UART_BAUD_2400   4
+#define UART_BAUD_4800   5
+#define UART_BAUD_9600   6
+#define UART_BAUD_19200  7
+#define UART_BAUD_38400  8
+#define UART_BAUD_115200 9
+#define N_UART_BAUD     10
+
+#define UART_DATA     (7<<UCSZ00)
+#define UART_DATA_8   (3<<UCSZ00)
+#define UART_DATA_7   (2<<UCSZ00)
+#define UART_STOP     (1<<USBS0)
+#define UART_STOP_1   (0<<USBS0)
+#define UART_STOP_2   (1<<USBS0)
+#define UART_PARITY   (3<<UPM00)
+#define UART_PARITY_N (0<<UPM00)
+#define UART_PARITY_E (2<<UPM00)
+#define UART_PARITY_O (3<<UPM00)
+
+#define UART_8N1 (UART_DATA_8 | UART_STOP_1 | UART_PARITY_N)
+#define UART_8E1 (UART_DATA_8 | UART_STOP_1 | UART_PARITY_E)
+#define UART_8O1 (UART_DATA_8 | UART_STOP_1 | UART_PARITY_O)
+#define UART_8N2 (UART_DATA_8 | UART_STOP_2 | UART_PARITY_N)
+#define UART_8E2 (UART_DATA_8 | UART_STOP_2 | UART_PARITY_E)
+#define UART_8O2 (UART_DATA_8 | UART_STOP_2 | UART_PARITY_O)
+#define UART_7N1 (UART_DATA_7 | UART_STOP_1 | UART_PARITY_N)
+#define UART_7E1 (UART_DATA_7 | UART_STOP_1 | UART_PARITY_E)
+#define UART_7O1 (UART_DATA_7 | UART_STOP_1 | UART_PARITY_O)
+#define UART_7N2 (UART_DATA_7 | UART_STOP_2 | UART_PARITY_N)
+#define UART_7E2 (UART_DATA_7 | UART_STOP_2 | UART_PARITY_E)
+#define UART_7O2 (UART_DATA_7 | UART_STOP_2 | UART_PARITY_N)
+
+
+#define FLOW_HW     0b00000111
+#define FLOW_FD     0b00000001
+#define FLOW_HD_DTE 0b00000010
+#define FLOW_HD_DCE 0b00000100
+#define FLOW_SW     0b00001000
+#define FLOW_XONOFF 0b00001000
+#define FLOW_NONE   0b00000000
+
+#define XON  0x11
+#define XOFF 0x13
+
+
+#define INT_PRE 2   // 8MHz / 8 = 1MHz
+#define INT_DIV 167 // 1MHz / 167 = 5.988kHz
+
+// #define PRINT_DIV 136 // 1MHz / 167 / 136 = 44.0296Hz = 4 * 11.0074Hz
+#define PRINT_DIV 176 // 1MHz / 167 / 176 = 34.0228Hz = 4 * 8.5057Hz
+#define LED_DIV   599 // 1MHz / 167/ 599  =  9.9967Hz
+
+
+#define REPLACE_SYMBOL 0
+#define REPLACE_QUEST  1
+#define REPLACE_UNDER  2
+#define REPLACE_SPACE  3
+#define REPLACE_IGNORE 4
+#define N_REPLACE      5
+
+#define R_SYMBOL CH_UNKN // '<?>'
+#define R_QUEST  CH_003F // '?'
+#define R_UNDER  CH_005F // '_'
+#define R_SPACE  CH_0020 // ' '
+#define R_IGNORE CH_NULL // ''
+
+
+#define ESC_NONE    0
+#define ESC_P_POS   1
+#define ESC_ECMA_48 2
+
+
+#define ID_BAUD     1
+#define ID_MODE     2
+#define ID_NL_MODE  3
+#define ID_BS_MODE  4
+#define ID_ENCODING 5
+#define ID_REPLACE  6
+#define ID_BITS     7
+#define ID_LWIDTH   8
+#define ID_LMARGIN  9
+#define ID_RMARGIN 10
+#define ID_PHEIGHT 11
+#define ID_TMARGIN 12
+#define ID_BMARGIN 13
+#define ID_CWIDTH  14
+#define ID_LHEIGHT 15
+#define ID_HTAB    16
+#define ID_VTAB    17
+#define ID_PAPER   18
+#define ID_STYLE   19
+#define ID_FLOW    20
+
+
+#define MENU_NONE     0355 // choose something not present on kezboard
+#define MENU_ENTER   (KEY_ERASEW | KEYB_CODE)
+#define MENU_OUTPUT   KEY_ERASEW
+#define MENU_EXIT     KEY_MARGIN
+#define MENU_CONFIRM  KEY_RETURN
+#define MENU_BAUD     KEY_1
+#define MENU_BITS     KEY_2
+#define MENU_FLOW     KEY_3
+#define MENU_ECHO     KEY_4
+#define MENU_NEWLINE  KEY_5
+#define MENU_DELETE   KEY_6
+#define MENU_REPLACE  KEY_7
+#define MENU_ENCODING KEY_8
+#define MENU_PWIDTH   KEY_Q
+#define MENU_LMARGIN  KEY_W
+#define MENU_RMARGIN  KEY_E
+#define MENU_TWIDTH   KEY_R
+#define MENU_PHEIGHT  KEY_T
+#define MENU_TMARGIN  KEY_Z
+#define MENU_BMARGIN  KEY_U
+#define MENU_THEIGHT  KEY_I
+#define MENU_HTAB     KEY_O
+#define MENU_VTAB     KEY_P
+#define MENU_CWIDTH   KEY_A
+#define MENU_LHEIGHT  KEY_S
+#define MENU_PAPER    KEY_D
+
+#define QMENU_ECHO    CODE_AUTORETURN
+#define QMENU_PAPER  (KEY_RETURN | KEYB_CODE)
+#define QMENU_EXIT   (KEY_MARGIN | KEYB_CODE | KEYB_SHIFT)
+
+
+#define TEXT_MENU_LIST ((uint8_t *)"MENU\r\n" \
+       "1:baud 2:bits 3:flowctrl 4:echo 5:CR/LF 6:BS/DEL 7:replace 8:encoding\r\n" \
+       "Q:width W:left E:right R:Twidth T:height Z:top U:bottom I:Theight\r\n" \
+       "O:Htab P: Vtab A:Cwidth S:Lheight D:paper DEL: help ESC: exit\r\n> ")
+#define TEXT_MENU_EXIT ((uint8_t *)"EXIT\r\n")
+#define TEXT_MENU_BAUD ((uint8_t *)"SET BAUD RATE\r\n" \
+       "1:150 2:300 3:600 4:1200 5:2400 6:4800 7:9600 8:19200 9:38400 0:115200\r\n" \
+       "> ")
+#define TEXT_MENU_BITS ((uint8_t *)"SET SERIAL MODE\r\n" \
+       "1:8n1 2:8e1 3:8o1 4:8n2 5:8e2 6:8o2\r\n" \
+       "7:7n1 8:7e1 9:7o1 10:7n2 11:7e2 12:7o2\r\n" \
+       "> ")
+#define TEXT_MENU_FLOW ((uint8_t *)"SET FLOW CONTROPL\r\n" \
+       "HW: 1:FD(RTR/CTS) 2:HD,DTE(RTS/CTS) 3:HD,DCE(CTS/RTS) 4:none\r\n" \
+       "SW: 5:XON/XOFF  6:none\r\n> ")
+#define TEXT_MENU_NEWLINE ((uint8_t *)"SET NEWLINE HANDLING\r\n" \
+       "RECEIVE: 1:CR->CRLF 2:LF->CRLF 3:any->CRLF 4:no change\r\n" \
+       "SEND: 5:CR 6:LF 7:CRLF\r\n> ")
+#define TEXT_MENU_ECHO ((uint8_t *)"SET LOCAL ECHO\r\n" \
+       "1:ON 2:OFF\r\n> ")
+#define TEXT_MENU_DELETE ((uint8_t *)"SET BACKSPACE/DELETE KEY CODE\r\n" \
+       "1:BS=08 2:BS=7F 3:DEL=7F 4:DEL=08\r\n> ")
+#define TEXT_MENU_REPLACE ((uint8_t *)"SET UNKNOWN CHARACTER HANDLING\r\n" \
+       "1:<?> 2:? 3:_ 4:SPACE 5:ignore\r\n> ")
+#define TEXT_MENU_ENCODING ((uint8_t *)"SET CHARACTER ENCODING\r\n" \
+       "1,2,3,4,9,10,13,15,16:ISO8859 1250,852:codepage 8:UTF-8\r\n> ")
+#define TEXT_MENU_PWIDTH ((uint8_t *)"SET PAGE WIDTH (in columns)\r\n> ")
+#define TEXT_MENU_LMARGIN ((uint8_t *)"SET LEFT MARGIN (in columns)\r\n> ")
+#define TEXT_MENU_RMARGIN ((uint8_t *)"SET RIGHT MARGIN (in columns)\r\n> ")
+#define TEXT_MENU_TWIDTH ((uint8_t *)"SET TEXT WIDTH (in columns)\r\n> ")
+#define TEXT_MENU_PHEIGHT ((uint8_t *)"SET PAGE HEIGHT (in lines)\r\n> ")
+#define TEXT_MENU_TMARGIN ((uint8_t *)"SET TOP MARGIN (in lines)\r\n> ")
+#define TEXT_MENU_BMARGIN ((uint8_t *)"SET BOTTOM MARGIN (in lines)\r\n> ")
+#define TEXT_MENU_THEIGHT ((uint8_t *)"SET TEXT HEIGHT (in lines)\r\n> ")
+#define TEXT_MENU_HTAB ((uint8_t *)"SET TAB WIDTH (in columns)\r\n> ")
+#define TEXT_MENU_VTAB ((uint8_t *)"SET TAB HEIGHT (in lines)\r\n> ")
+#define TEXT_MENU_CWIDTH ((uint8_t *)"SET CHARACTER WIDTH\r\n" \
+       "1:15CPI 2:12CPI 3:10CPI 4:6CPI 5:4CPI 6:3CPI\r\n> ")
+#define TEXT_MENU_LHEIGHT ((uint8_t *)"SET LINE HEIGHT\r\n" \
+       "1:6LPI 2:4LPI 3:3LPI 4:2LPI\r\n> ")
+#define TEXT_MENU_PAPER ((uint8_t *)"SET_PAPER_TYPE\r\n" \
+       "1:continuous 2:single pages\r\n> ")
+#define TEXT_MENU_CANCEL ((uint8_t *)" CANCEL\r\n> ")
+#define TEXT_MENU_OK ((uint8_t *)" OK\r\n> ")
+#define TEXT_MENU_FAIL ((uint8_t *)" FAIL\r\n> ")
+
+
+#define PRINT_DELAY 1 // 2?
+
+#define SCAN_HOLD 3
+#define SCAN_DEBOUNCE  3 //   3 * 10ms =  30ms
+#define SCAN_DELAY    70 //  70 * 10ms = 700ms
+#define SCAN_REPEAT   10 //  10 * 10ms = 100ms
+
+#define N_INCOME_BUFFER  256
+#define N_OUTCOME_BUFFER  64
+#define N_PRINT_BUFFER   128
+#define N_SCAN_BUFFER     64
+#define N_ESC_BUFFER      64
+
+#define INCOME_BUFFER_LOW    8
+#define INCOME_BUFFER_HIGH 208
+
+
+#define MODE_WAIT  0b00000000
+#define MODE_TYPE  0b00000001
+#define MODE_TERM  0b00000010
+#define MODE_ECHO  0b00000100
+
+#define NL_IMPLICIT_CR 0b00000001
+#define NL_IMPLICIT_LF 0b00000010
+#define NL_SEND_CR     0b00000100
+#define NL_SEND_LF     0b00001000
+#define NL_SEND_CRLF   (NL_SEND_CR | NL_SEND_LF)
+#define NL_CATCH_ALL   (NL_IMPLICIT_CR | NL_IMPLICIT_LF)
+
+#define BS_BS  0b00000001
+#define BS_DEL 0b00000010
+
+#define WAKEUP_INCOME  0b00000001
+#define WAKEUP_OUTCOME 0b00000010
+#define WAKEUP_SCAN    0b00000100
+
+#define WIDTH_15   4
+#define WIDTH_12   5
+#define WIDTH_10   6
+#define WIDTH_6   10
+#define WIDTH_4_5 13
+#define WIDTH_4   15
+#define WIDTH_3   20
+#define N_CWIDTH   7
+
+#define WIDTH_NARROW  WIDTH_15
+#define WIDTH_NORMAL  WIDTH_12
+#define WIDTH_WIDE    WIDTH_10
+
+#define HEIGHT_6     2 // 2
+#define HEIGHT_4     3 // 3 
+#define HEIGHT_3     4 // 4
+#define HEIGHT_12    1 // 1
+#define HEIGHT_8     2 // 1.5
+#define HEIGHT_6M    2 // 2 46/127
+#define HEIGHT_4M    4 // 3 69/127
+#define HEIGHT_3M    5 // 4 92/127
+#define HEIGHT_12M   1 // 1 23/127
+#define HEIGHT_2     6 // 6
+#define N_LHEIGHT   10
+
+#define HEIGHT_NORMAL HEIGHT_6
+
+#define HPOS_LIMIT         ((108-2) * WIDTH_NORMAL)
+#define VPOS_LIMIT             (144 * HEIGHT_NORMAL)
+#define DEFAULT_LWIDTH          (92 * WIDTH_NORMAL)
+#define DEFAULT_PHEIGHT         (72 * HEIGHT_NORMAL)
+#define DEFAULT_LMARGIN     ((12-1) * WIDTH_NORMAL)
+#define DEFAULT_LMARGIN_AIM      (0 * WIDTH_NORMAL)
+#define DEFAULT_RMARGIN     ((90-1) * WIDTH_NORMAL)
+#define DEFAULT_RMARGIN_AIM    ((80 * WIDTH_NORMAL)+DEFAULT_LMARGIN_AIM)
+#define DEFAULT_TMARGIN          (0 * HEIGHT_NORMAL)
+#define DEFAULT_BMARGIN        ((56 * HEIGHT_NORMAL)+DEFAULT_TMARGIN)
+#define DEFAULT_TWIDTH_CH         4
+#define DEFAULT_THEIGHT_CH        4
+
+#define LMARGIN_PRESET          (12 * WIDTH_NORMAL)
+#define RMARGIN_PRESET           (2 * WIDTH_NORMAL)
+
+
+#define HTAB_SIZE (((HPOS_LIMIT-1)/8)+1)
+#define VTAB_SIZE (((VPOS_LIMIT-1)/8)+1)
+
+
+#define HUNIT_MUL_CH    0
+#define HUNIT_DIV_CH    0
+#define HUNIT_MUL_MM  300
+#define HUNIT_DIV_MM  127
+#define HUNIT_MUL_CDP   1
+#define HUNIT_DIV_CDP  12
+#define HUNIT_MUL_DD    4
+#define HUNIT_DIV_DD   45
+#define HUNIT_MUL_MIL   3
+#define HUNIT_DIV_MIL  50
+#define HUNIT_MUL_BMU   1
+#define HUNIT_DIV_BMU  20
+#define HUNIT_MUL_UM    3
+#define HUNIT_DIV_UM 1270
+#define HUNIT_MUL_DP    1
+#define HUNIT_DIV_DP   12
+
+#define VUNIT_MUL_CH    1
+#define VUNIT_DIV_CH    0
+#define VUNIT_MUL_MM   60
+#define VUNIT_DIV_MM  127
+#define VUNIT_MUL_CDP   1
+#define VUNIT_DIV_CDP  60
+#define VUNIT_MUL_DD    4
+#define VUNIT_DIV_DD  225
+#define VUNIT_MUL_MIL   3
+#define VUNIT_DIV_MIL 250
+#define VUNIT_MUL_BMU   1
+#define VUNIT_DIV_BMU 100
+#define VUNIT_MUL_UM    3
+#define VUNIT_DIV_UM 6350
+#define VUNIT_MUL_DP    1
+#define VUNIT_DIV_DP   60
+
+
+#define PF_TCOMM_BASIC_TALL 0
+#define PF_TCOMM_BASIC_WIDE 1
+#define PF_A4_BASIC_TALL    2
+#define PF_A4_BASIC_WIDE    3
+#define PF_LETTER_TALL      4
+#define PF_LETTER_WIDE      5
+#define PF_A4_EXT_TALL      6
+#define PF_A4_EXT_WIDE      7
+#define PF_LEGAL_TALL       8
+#define PF_LEGAL_WIDE       9
+#define PF_A4_SHORT        10
+#define PF_A4_LONG         11
+#define PF_B5_SHORT        12
+#define PF_B5_LONG         13
+#define PF_B4_SHORT        14
+#define PF_B4_LONG         15
+#define N_PF               16
+
+#define LWIDTH_TCOMM_BASIC_TALL 462 //  92.4  7.7"
+#define LWIDTH_TCOMM_BASIC_WIDE 625 // 125    10 5/12"
+#define LWIDTH_A4_BASIC_TALL    462 //  92.4  7.7"
+#define LWIDTH_A4_BASIC_WIDE    660 // 132    11"
+#define LWIDTH_LETTER_TALL      480 //  96    8"
+#define LWIDTH_LETTER_WIDE      625 // 125    10 5/12"
+#define LWIDTH_A4_EXT_TALL      462 //  92.4  7.7"
+#define LWIDTH_A4_EXT_WIDE      660 // 132    11"
+#define LWIDTH_LEGAL_TALL       480 //  96    8"
+#define LWIDTH_LEGAL_WIDE       810 // 162    13.5"
+#define LWIDTH_A4_SHORT         450 //  90    7.5"
+#define LWIDTH_A4_LONG          655 // 131    10 11/12"
+#define LWIDTH_B5_SHORT         375 //  75    6.25"
+#define LWIDTH_B5_LONG          555 // 111    9.25"
+#define LWIDTH_B4_SHORT         555 // 111    9.25"
+#define LWIDTH_B4_LONG          785 // 157    13 1/12"
+
+#define PHEIGHT_TCOMM_BASIC_TALL 110 // 55   9 1/6"
+#define PHEIGHT_TCOMM_BASIC_WIDE  76 // 38   6 1/3"
+#define PHEIGHT_A4_BASIC_TALL    118 // 59   9 5/6"
+#define PHEIGHT_A4_BASIC_WIDE     76 // 38   6 1/3"
+#define PHEIGHT_LETTER_TALL      112 // 56   9 1/3"
+#define PHEIGHT_LETTER_WIDE       80 // 40   6 2/3"
+#define PHEIGHT_A4_EXT_TALL      132 // 63   11"
+#define PHEIGHT_A4_EXT_WIDE       88 // 44   7 1/3" 
+#define PHEIGHT_LEGAL_TALL       148 // 74   12 1/3"
+#define PHEIGHT_LEGAL_WIDE        80 // 40   6 2/3"
+#define PHEIGHT_A4_SHORT         118 // 59   9 5/6"
+#define PHEIGHT_A4_LONG           76 // 38   6 1/3"
+#define PHEIGHT_B5_SHORT          98 // 49   8 1/6"
+#define PHEIGHT_B5_LONG           64 // 32   5 1/13"
+#define PHEIGHT_B4_SHORT         114 // 59   9.5"  
+#define PHEIGHT_B4_LONG           98 // 49   8 1/6"
+
+
+#define STYLE_NORMAL  0b00000000
+#define STYLE_BOLD    0b00000001
+#define STYLE_UNDER   0b00000010
+#define STYLE_UNDER2  0b00000100
+#define STYLE_OVER    0b00001000
+#define STYLE_CROSS   0b00010000
+#define STYLE_STRONG  0b10000000
+
+
+#define PAPER_SINGLE     0
+#define PAPER_CONTINUOUS 1
+
+
+#define EEPROM_SIZE (4 * 1024)
+
+
+#define CTRL_IND (buffer+1), &buffer_pos, &p_ind, &sp_ind
+
+
+// port A, keyboard row
+#define PORT_ROW PORTA
+#define DDR_ROW  DDRA
+#define PIN_ROW  PINA
+
+// port C, keyboard column
+#define PORT_COL PORTC
+#define DDR_COL  DDRC
+#define PIN_COL  PINC
+
+// port B, key output select
+#define PORT_KEY PORTB
+#define DDR_KEY  DDRB
+
+// port D, control of state, active low
+#define PORT_CTRL PORTD
+#define DDR_CTRL  DDRD
+
+#define LED      0b00010000 // out
+#define KEY      0b00100000 // out
+#define EN_PRINT 0b01000000 // out
+#define EN_KEYB  0b10000000 // out
+
+#define MASK_CTRL (LED|KEY|EN_PRINT|EN_KEYB)
+
+// port D, communication
+#define PORT_COMM PORTD
+#define DDR_COMM  DDRD
+#define PIN_COMM  PIND
+
+#define RX       0b00000001 // in
+#define TX       0b00000010 // out
+#define SYNC_IN  0b00000100 // in
+#define SYNC_OUT 0b00001000 // out
+
+#define MASK_COMM (RX|TX|SYNC_IN|SYNC_OUT)
+
+#define ADVANCE_BP(P, N)      ((P<(N-1)) ? (++P) : (P=0))
+#define DIFF_BP(W, R, N)      ((W<R) ? (N + W - R) : W - R)
+#define FULL_BP(W, R, N)      (DIFF_BP(W, R, N) == (N-1))
+#define NOT_FULL_BP(W, R, N)  (DIFF_BP(W, R, N) != (N-1))
+#define EMPTY_BP(W, R, N)     (R == W)
+#define NOT_EMPTY_BP(W, R, N) (R != W)
+
+#define HUNIT(X) unit(X, hunit_mul, hunit_div)
+#define VUNIT(Y) unit(Y, vunit_mul, vunit_div)
+
+
+FUSES = 
+{
+.low =
+       FUSE_SUT_CKSEL0 & FUSE_SUT_CKSEL2 & FUSE_SUT_CKSEL3 & // internal 8MHz
+       FUSE_SUT_CKSEL4 & FUSE_SUT_CKSEL5, // BOD
+       // no clk out
+       // no clk div
+.high =
+       // BOOTRST = 1
+       FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & // BOOTSZ = 0
+       FUSE_EESAVE & // preserve EEPROM
+       // WDT off
+       // FUSE_SPIEN & FUSE_JTAGEN, // enable prog.
+       FUSE_SPIEN, // enable spi prog, disable jtag
+       // no enable ocd
+.extended = FUSE_BODLEVEL1, // BOD 2.5 - 2.9
+};
+
+const uint16_t UART_DIV[N_UART_BAUD] = {
+       UART_DIV_150,
+       UART_DIV_300,
+       UART_DIV_600,
+       UART_DIV_1200,
+       UART_DIV_2400,
+       UART_DIV_4800,
+       UART_DIV_9600,
+       UART_DIV_19200,
+       UART_DIV_38400,
+       UART_DIV_115200
+};
+
+uint8_t const * const REPLACE[N_REPLACE] = {
+       R_SYMBOL,
+       R_QUEST,
+       R_UNDER,
+       R_SPACE,
+       R_IGNORE
+};
+
+const uint16_t LWIDTH_PRESET[N_PF] = {
+       LWIDTH_TCOMM_BASIC_TALL,
+       LWIDTH_TCOMM_BASIC_WIDE,
+       LWIDTH_A4_BASIC_TALL,
+       LWIDTH_A4_BASIC_WIDE,
+       LWIDTH_LETTER_TALL,
+       LWIDTH_LETTER_WIDE,
+       LWIDTH_A4_EXT_TALL,
+       LWIDTH_A4_EXT_WIDE,
+       LWIDTH_LEGAL_TALL,
+       LWIDTH_LEGAL_WIDE,
+       LWIDTH_A4_SHORT,
+       LWIDTH_A4_LONG,
+       LWIDTH_B5_SHORT,
+       LWIDTH_B5_LONG,
+       LWIDTH_B4_SHORT,
+       LWIDTH_B4_LONG
+};
+
+const uint16_t PHEIGHT_PRESET[N_PF] = {
+       PHEIGHT_TCOMM_BASIC_TALL,
+       PHEIGHT_TCOMM_BASIC_WIDE,
+       PHEIGHT_A4_BASIC_TALL,
+       PHEIGHT_A4_BASIC_WIDE,
+       PHEIGHT_LETTER_TALL,
+       PHEIGHT_LETTER_WIDE,
+       PHEIGHT_A4_EXT_TALL,
+       PHEIGHT_A4_EXT_WIDE,
+       PHEIGHT_LEGAL_TALL,
+       PHEIGHT_LEGAL_WIDE,
+       PHEIGHT_A4_SHORT,
+       PHEIGHT_A4_LONG,
+       PHEIGHT_B5_SHORT,
+       PHEIGHT_B5_LONG,
+       PHEIGHT_B4_SHORT,
+       PHEIGHT_B4_LONG,
+};
+
+const uint8_t CWIDTH_PRESET[N_CWIDTH] = {
+       WIDTH_10,
+       WIDTH_12,
+       WIDTH_15,
+       WIDTH_6,
+       WIDTH_3,
+       WIDTH_4_5,
+       WIDTH_4
+};
+
+const uint8_t LHEIGHT_PRESET[N_LHEIGHT] = {
+       HEIGHT_6,
+       HEIGHT_4,
+       HEIGHT_3,
+       HEIGHT_12,
+       HEIGHT_8,
+       HEIGHT_6M,
+       HEIGHT_4M,
+       HEIGHT_3M,
+       HEIGHT_12M,
+       HEIGHT_2
+};
+
+volatile uint8_t income_buffer[N_INCOME_BUFFER];
+volatile uint8_t income_r = 0;
+volatile uint8_t income_w = 0;
+
+volatile uint8_t outcome_buffer[N_OUTCOME_BUFFER];
+volatile uint8_t outcome_r = 0;
+volatile uint8_t outcome_w = 0;
+
+volatile uint8_t scan_buffer[N_SCAN_BUFFER];
+volatile uint8_t scan_r = 0;
+volatile uint8_t scan_w = 0;
+
+volatile uint8_t print_buffer[N_PRINT_BUFFER];
+volatile uint8_t print_r = 0;
+volatile uint8_t print_w = 0;
+
+volatile uint8_t keep_active=0;
+
+volatile uint8_t set_led = 0;
+volatile uint8_t set_alarm = 0;
+
+volatile uint8_t flow = FLOW_FD;
+volatile uint8_t outcome_requested = 0;
+volatile uint8_t income_accepted = 0;
+volatile uint8_t send_xonoff = 0;
+volatile uint8_t remote_xonoff = XON;
+volatile uint8_t local_xonoff = 0;
+
+uint8_t loaded_mode =    MODE_TERM;
+uint8_t mode =           MODE_WAIT;
+uint8_t nl_mode =        NL_CATCH_ALL | NL_SEND_CRLF;
+uint8_t bs_mode =        BS_BS | BS_DEL;
+uint8_t baud =           UART_BAUD_115200;
+uint8_t serial_mode =    UART_8N1;
+uint8_t esc_mode =       ESC_ECMA_48;
+volatile uint8_t style = STYLE_NORMAL;
+uint8_t loaded_style   = STYLE_NORMAL;
+
+uint8_t const * const * CH_CP = CH_ISO8859_2;
+uint8_t const * KEYMAP_CP =     KEYMAP_ISO8859_2;
+uint8_t encoding =              ENC_ISO8859_2;
+uint8_t replace =               REPLACE_SYMBOL;
+uint8_t paper =                 PAPER_SINGLE;
+uint8_t c1 = 1;
+
+uint8_t GR_index = 1;
+uint8_t GR_table[4] = {
+       0,
+       ENC_ISO8859_1,
+       ENC_ISO8859_2,
+       ENC_ISO8859_2
+};
+
+int16_t  lmargin =     DEFAULT_LMARGIN;
+int16_t  lmargin_aim = DEFAULT_LMARGIN_AIM;
+int16_t  rmargin =     DEFAULT_RMARGIN;
+int16_t  rmargin_aim = DEFAULT_RMARGIN_AIM;
+int16_t  tmargin =     DEFAULT_TMARGIN;
+int16_t  bmargin =     DEFAULT_BMARGIN;
+uint16_t lwidth =      DEFAULT_LWIDTH;
+uint16_t pheight =     DEFAULT_PHEIGHT;
+int8_t   twidth_ch =   DEFAULT_TWIDTH_CH;
+int8_t   theight_ch =  DEFAULT_THEIGHT_CH;
+
+int16_t  hpos =        DEFAULT_LMARGIN;
+int16_t  hpos_aim =    DEFAULT_LMARGIN_AIM;
+int16_t  vpos =        DEFAULT_TMARGIN;
+int16_t  vpos_aim =    DEFAULT_TMARGIN;
+int16_t  ppos =        0;
+uint8_t  cwidth =      WIDTH_NORMAL;
+uint8_t  cwidth_aim =  WIDTH_NORMAL;
+uint8_t  cwidth_todo = 0;
+uint8_t  lheight =     HEIGHT_NORMAL;
+uint8_t  out_margin =  0;
+
+uint16_t hunit_mul =   HUNIT_MUL_CH;
+uint16_t hunit_div =   HUNIT_DIV_CH;
+uint16_t vunit_mul =   VUNIT_MUL_CH;
+uint16_t vunit_div =   VUNIT_DIV_CH;
+
+
+uint8_t HTAB[HTAB_SIZE];
+uint8_t VTAB[VTAB_SIZE];
+
+uint8_t wait_page = 0;
+
+uint16_t ee_address = 0;
+
+void become_typewriter (void);
+void become_terminal (void);
+void set_flowcontrol (uint8_t setting);
+void update_flowcontrol_hw (void);
+void update_flowcontrol_sw (void);
+static inline void request_outcome (void);
+static inline void unrequest_outcome (void);
+static inline void accept_income (void);
+static inline void reject_income (void);
+uint8_t income_requested (void);
+uint8_t outcome_accepted (void);
+static inline void set_baudrate (const uint8_t setting);
+static inline void set_serial_mode (const uint8_t setting);
+static inline void set_encoding (const uint8_t setting);
+static inline void set_encoding_GR (const uint8_t setting);
+static inline uint8_t eeprom_read (const uint16_t address);
+static inline void eeprom_write (const uint16_t address, const uint8_t data);
+void eeprom_write_record (
+       const uint16_t address,
+       const uint8_t id,
+       const uint16_t data
+);
+void eeprom_erase_record (const uint16_t address);
+void store_all_config (void);
+void store_single_config (const uint8_t id);
+static inline void load_config (void);
+static inline void scan_keyboard (void);
+void add_scan (const uint8_t key);
+void handle_scan (void);
+static inline void goto_sleep (void);
+static inline void cancel_sleep (const uint8_t flag);
+static inline void allow_sleep (const uint8_t flag);
+void add_income (const uint8_t in, const uint8_t blocking);
+void handle_income (void);
+void add_outcome (const uint8_t out);
+void handle_outcome (void);
+static inline void add_ch (uint8_t io);
+void add_income_str (uint8_t const * in, const uint8_t blocking);
+void add_outcome_str (uint8_t const * out);
+uint8_t make_dec_string (
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits
+);
+uint8_t make_hex_string (
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits,
+       const uint8_t uppercase
+);
+void add_outcome_dec (const uint32_t value, const uint8_t min_digits);
+void add_outcome_hex (const uint32_t value, const uint8_t min_digits);
+uint8_t goto_next_col (const uint8_t ignore_margin);
+uint8_t goto_prev_col (const uint8_t ignore_margin);
+void move_forward_col (const uint8_t n, const uint8_t ignore_margin);
+void move_back_col (const uint8_t n, const uint8_t ignore_margin);
+void goto_col (uint8_t x);
+static inline void goto_lmargin (void);
+static inline void goto_col0 (void);
+uint8_t goto_next_line (const uint8_t ignore_margin);
+uint8_t goto_prev_line (const uint8_t ignore_margin);
+static inline void goto_next_vstep (void);
+static inline void goto_prev_vstep (void);
+void move_forward_line (const uint8_t n, const uint8_t ignore_margin);
+void move_back_line (const uint8_t n, const uint8_t ignore_margin);
+void goto_line (uint8_t y);
+static inline void goto_next_page (void);
+static inline void goto_next_page_tmargin (void);
+static inline void goto_prev_page (void);
+static inline void goto_prev_page_tmargin (void);
+void move_forward_page (const uint8_t n);
+void move_forward_page_tmargin (const uint8_t n);
+void move_back_page (const uint8_t n);
+void move_back_page_tmargin (const uint8_t n);
+void goto_page (const int16_t y);
+uint8_t is_htab (const int16_t x);
+uint8_t is_vtab (const int16_t y);
+uint8_t goto_next_htab (const uint8_t ignore_margin);
+uint8_t goto_prev_htab (const uint8_t ignore_margin);
+uint8_t goto_next_vtab (const uint8_t ignore_margin);
+uint8_t goto_prev_vtab (const uint8_t ignore_margin);
+void move_forward_htab (const uint8_t n, const uint8_t ignore_margin);
+void move_back_htab (const uint8_t n, const uint8_t ignore_margin);
+void move_forward_vtab (const uint8_t n, const uint8_t ignore_margin);
+void move_back_vtab (const uint8_t n, const uint8_t ignore_margin);
+void goto_htab (const int8_t x, const uint8_t ignore_margin);
+void set_htab (const int16_t x);
+void clear_htab (const int16_t x);
+static inline void clear_htab_ch (uint8_t x);
+void set_vtab (const int16_t y);
+void clear_vtab (const int16_t y);
+static inline void clear_htab_all (void);
+static inline void clear_vtab_all (void);
+void set_twidth (const uint8_t x);
+static inline void set_twidth_ch (const uint8_t x);
+void set_theight (const uint8_t y);
+static inline void set_theight_ch (const uint8_t y);
+uint32_t unit (uint32_t x, const uint16_t mul, const uint16_t div);
+void set_lwidth (const uint16_t x);
+void set_pheight (const uint16_t y);
+void set_cwidth (const uint8_t x);
+void set_lheight (const uint8_t y);
+void set_lmargin (int16_t x);
+void set_rmargin (int16_t x);
+static inline void set_lmargin_ch (uint8_t x);
+static inline void set_rmargin_ch (uint8_t x);
+void set_rmargin_rel (const int16_t x);
+void set_tmargin (int16_t y);
+void set_bmargin (int16_t y);
+static inline void set_tmargin_ch (uint8_t y);
+static inline void set_bmargin_ch (uint8_t y);
+void set_bmargin_rel (const int16_t y);
+void set_style (const uint8_t new_style);
+static inline void set_style_normal (void);
+static inline void set_style_bold (void);
+static inline void set_style_nobold (void);
+static inline void toggle_bold (void);
+static inline void set_style_under (void);
+static inline void set_style_under2 (void);
+static inline void set_style_nounder (void);
+static inline void toggle_under (void);
+static inline void set_style_cross (void);
+static inline void set_style_nocross (void);
+static inline void set_style_over (void);
+static inline void set_style_noover (void);
+static inline void set_style_strong (void);
+static inline void set_style_weak (void);
+void add_print_key (const uint8_t key);
+void adjust_print_pos (void);
+void add_print_ch (uint8_t const * const ch);
+static inline void handle_print (void);
+uint8_t handle_ctrl (uint8_t in);
+uint32_t get_ctrl_parameter (
+       uint8_t * buffer,
+       uint8_t * * pos,
+       uint8_t * ind,
+       uint8_t * subind,
+       uint8_t id,
+       uint8_t subid,
+       uint32_t def
+);
+uint8_t handle_menu (const uint8_t key);
+
+int main (void)
+{
+       /* IO */
+       
+       MCUCR |= 0b00010000; //DISABLE PULLUP
+       
+       // keyboard scan input
+       PORT_ROW = 0b00000000;
+       PORT_COL = 0b00000000;
+       DDR_ROW  = 0b00000000;
+       DDR_COL  = 0b00000000;
+       
+       // print key output
+       PORT_KEY = 0b00000000;
+       DDR_KEY  = 0b11111111;
+       
+       // ctrl state
+       PORT_CTRL = (PORT_CTRL | MASK_CTRL) & ~EN_KEYB;
+       DDR_CTRL = (DDR_CTRL | MASK_CTRL);
+       
+       //communication
+       PORT_COMM = (PORT_COMM | MASK_COMM) & ~RX & ~SYNC_IN;
+       DDR_COMM = (DDR_COMM & ~MASK_COMM) | TX | SYNC_OUT;
+       
+       /* UART */
+       
+       // UBRR0H = (uint8_t) ((UART_DIV[baud]-1) >> 8);
+       // UBRR0L = (uint8_t) ((UART_DIV[baud]-1) & 0xff);
+       UBRR0 = UART_DIV[baud]-1;
+       UCSR0A = (1<<U2X0); // 2x speed mode
+       UCSR0B = 
+               (1<<RXCIE0) | // enable RX int
+               // (1<<TXCIE0) | // enable TX int (complete)
+               // (1<<UDRIE0) | // enable TX int (buf free)
+               (1<<RXEN0) | (1<<TXEN0); //enable RX, enable TX
+       // UCSR0C = (3<<UCSZ00); //8n1 mode;
+       set_serial_mode(serial_mode);
+       
+       /* TIMER */
+       
+       TCCR2A = 0;
+       TCCR2B = 0;
+       TCNT2 = 0;
+       OCR2A = INT_DIV - 1;
+       TCCR2A = (1 << WGM21);  //CTC mode
+       TCCR2B = INT_PRE; // prescaler
+       TIMSK2 |= (1<<OCIE2A); //enable timer compare interrupt
+       
+       /* RESTORE SETTINGS */
+       
+       load_config(); // might enable int!
+       vpos = tmargin;
+       vpos_aim = tmargin;
+       hpos_aim = lmargin_aim;
+       
+       /* ENABLE INT */
+       
+       sei();
+       
+       /* DO THE */
+       
+       accept_income();
+       
+       goto_sleep();
+       
+       while(5)
+       {
+               handle_scan();
+               handle_income();
+               handle_outcome();
+       }
+}
+
+void become_typewriter (void)
+{
+       mode = MODE_TYPE;
+       
+       // ok, prepare for total stop
+       // no more int.
+       
+       cli();
+       
+       // allow real keyboard, block injected keyboard
+       PORT_CTRL |= EN_PRINT;
+       PORT_CTRL &= ~EN_KEYB;
+       
+       // don't accept any input more
+       reject_income();
+       
+       // wait to make sure that XOFF (if relevant) was sent
+       while (send_xonoff)
+               handle_outcome();
+       
+       // clean up IO, most importanlty, LED must be off.
+       PORT_CTRL |= LED | KEY;
+       PORT_KEY &= ~(KEYB_CODE | KEYB_SHIFT);
+       
+       // stop performing actions
+       while (1)
+       {
+               allow_sleep(0xff);
+               goto_sleep();
+       }
+}
+
+void become_terminal (void)
+{
+       mode = loaded_mode | MODE_TERM;
+       
+       PORT_CTRL |= EN_KEYB;
+       PORT_CTRL &= ~EN_PRINT;
+       
+       accept_income();
+       
+       add_print_key(CODE_AUTORETURN); // disable auto-return
+       set_style(loaded_style);
+       
+       vpos = tmargin;
+       vpos_aim = tmargin;
+       hpos_aim = lmargin_aim;
+       
+       adjust_print_pos();
+}
+
+void set_flowcontrol (uint8_t setting)
+{
+       flow = setting & (FLOW_HW | FLOW_SW);
+       local_xonoff = 0;
+       remote_xonoff = XON;
+       unrequest_outcome();
+       if (DIFF_BP(income_w, income_r, N_INCOME_BUFFER) < INCOME_BUFFER_HIGH)
+               accept_income();
+       else
+               reject_income();
+}
+
+void update_flowcontrol_hw (void)
+{
+       uint8_t out = 0;
+       
+       switch (flow & FLOW_HW)
+       {
+       case FLOW_HD_DCE:
+               if (!income_requested())
+                       break;
+       case FLOW_FD:
+               out = income_accepted;
+               break;
+       case FLOW_HD_DTE:
+               out = outcome_requested;
+               break;
+       default:
+               out = 1;
+       }
+       if (out)
+               PORT_COMM &= ~SYNC_OUT;
+       else
+               PORT_COMM |= SYNC_OUT;
+}
+
+void update_flowcontrol_sw (void)
+{
+       if ((flow & FLOW_SW) == FLOW_XONOFF)
+       {
+               if (income_accepted)
+               {
+                       if (local_xonoff != XON)
+                       {
+                               local_xonoff = XON;
+                               send_xonoff = XON;
+                       }
+               }
+               else
+               {
+                       if (local_xonoff != XOFF)
+                       {
+                               local_xonoff = XOFF;
+                               send_xonoff = XOFF;
+                       }
+               }
+       }
+}
+
+static inline void request_outcome (void)
+{
+       outcome_requested = 1;
+       update_flowcontrol_hw();
+}
+
+static inline void unrequest_outcome (void)
+{
+       outcome_requested = 0;
+       update_flowcontrol_hw();
+}
+
+static inline void accept_income (void)
+{
+       income_accepted = 1;
+       update_flowcontrol_hw();
+       update_flowcontrol_sw();
+}
+
+static inline void reject_income (void)
+{
+       income_accepted = 0;
+       update_flowcontrol_hw();
+       update_flowcontrol_sw();
+}
+
+uint8_t income_requested (void)
+{
+       if ((flow & FLOW_HW) == FLOW_HD_DCE)
+       {
+               if (PORT_COMM & SYNC_IN);
+                       return 0;
+       }
+       return 0xFF;
+}
+
+uint8_t outcome_accepted (void)
+{
+       uint8_t accepted = 0xFF;
+       
+       switch (flow & FLOW_HW)
+       {
+       case FLOW_FD:
+       case FLOW_HD_DTE:
+               if (PORT_COMM & SYNC_IN)
+                       accepted = 0;
+               break;
+       case FLOW_HD_DCE:
+               if (!(PORT_COMM & SYNC_IN))
+                       accepted = 0;
+       }
+       if ((flow & FLOW_SW) == FLOW_XONOFF)
+       {
+               if (remote_xonoff != XON)
+                       accepted = 0;
+       }
+       return accepted;
+}
+
+static inline void set_baudrate (const uint8_t setting)
+{
+       if (setting < N_UART_BAUD)
+       {
+               baud = setting;
+               UBRR0 = UART_DIV[setting]-1;
+       }
+}
+
+static inline void set_serial_mode (const uint8_t setting)
+{
+       serial_mode = setting;
+       UCSR0C = setting;
+}
+
+static inline void set_encoding (const uint8_t setting)
+{
+       if (setting & ENC_UNI)
+               encoding = setting;
+       else if (setting < ENC_MAX)
+       {
+               CH_CP = CH_LIST[setting];
+               KEYMAP_CP = KEYMAP_LIST[setting];
+               c1 = ENC_C1[setting];
+               encoding = setting;
+               if (c1)
+                       GR_table[GR_index] = setting;
+       }
+}
+
+static inline void set_encoding_GR (const uint8_t setting)
+{
+       if ((setting>=0) && (setting<=3))
+       {
+               GR_index = setting;
+               set_encoding(GR_table[GR_index]);
+       }
+}
+
+static inline uint8_t eeprom_read (const uint16_t address)
+{
+       uint8_t data;
+       // add_income('R');
+       // add_income(' ');
+       // add_income((address>>12)+'0');
+       // add_income(((address>>8)&0xf)+'0');
+       // add_income(((address>>4)&0xf)+'0');
+       // add_income((address&0xf)+'0');
+       // add_income(' ');
+       
+       while (EECR & (1<<EEPE))
+               ;
+       EEAR = address;
+       EECR |= (1<<EERE);
+       data = EEDR;
+       
+       // add_income((data>>4)+'0');
+       // add_income((data&0xf)+'0');
+       // add_income('\r');
+       // add_income('\n');
+       
+       return data;
+}
+
+static inline void eeprom_write (const uint16_t address, const uint8_t data)
+{
+       // add_income('W');
+       // add_income(' ');
+       // add_income((address>>12)+'0');
+       // add_income(((address>>8)&0xf)+'0');
+       // add_income(((address>>4)&0xf)+'0');
+       // add_income((address&0xf)+'0');
+       // add_income(' ');
+       // add_income((data>>4)+'0');
+       // add_income((data&0xf)+'0');
+       // add_income('\r');
+       // add_income('\n');
+       
+       while (EECR & (1<<EEPE))
+               ;
+       EEAR = address;
+       EEDR = data;
+       cli();
+       EECR |= (1<<EEMPE);
+       EECR |= (1<<EEPE);
+       sei();
+}
+
+void eeprom_write_record (
+       const uint16_t address,
+       const uint8_t id,
+       const uint16_t data
+)
+{
+       uint8_t block[4];
+       uint8_t checksum=0;
+       uint8_t i;
+       
+       EECR &= ~(1<<EEPM0);
+       EECR |= (1<<EEPM1);
+       
+       block[0] = id;
+       checksum -= block[0];
+       
+       block[2] = data & 0xff;
+       checksum -= block[2];
+       
+       block[3] = data >> 8;
+       checksum -= block[3];
+       
+       block[1] = checksum;
+       
+       // add_outcome_str("STORE ");
+       // add_outcome_hex(address,4);
+       // add_outcome(' ');
+       // add_outcome_hex(block[0],2);
+       // add_outcome(' ');
+       // add_outcome_hex(block[1],2);
+       // add_outcome(' ');
+       // add_outcome_hex(block[2],2);
+       // add_outcome(' ');
+       // add_outcome_hex(block[3],2);
+       // add_outcome_str("\r\n");
+       
+       for(i=0; i<4; ++i)
+       {
+               eeprom_write(address + i, block[i]);
+       }
+}
+
+void eeprom_erase_record (const uint16_t address)
+{
+       uint8_t i;
+       uint8_t io;
+       
+       EECR |= (1<<EEPM0);
+       EECR &= ~(1<<EEPM1);
+       
+       // add_outcome_str("ERASE ");
+       // add_outcome_hex(address,4);
+       // add_outcome_str("\r\n");
+       
+       for(i=0; i<4; ++i)
+       {
+               io = eeprom_read(address + i);
+               if (io != 0xff)
+                       eeprom_write(address + i, 0xff);
+       }
+}
+
+void store_all_config (void)
+{
+       ee_address = 0;
+       eeprom_write_record(ee_address, ID_BAUD, baud);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_BITS, baud);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_MODE, mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_NL_MODE, nl_mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_BS_MODE, bs_mode);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_ENCODING, encoding);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_REPLACE, replace);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_LWIDTH, lwidth);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_LMARGIN, lmargin_aim);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_RMARGIN, rmargin_aim);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_PHEIGHT, pheight);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_TMARGIN, tmargin);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_BMARGIN, bmargin);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_HTAB, twidth_ch);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_VTAB, theight_ch);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_CWIDTH, cwidth_aim);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_LHEIGHT, lheight);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_FLOW, flow);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_PAPER, paper);
+       ee_address+=4;
+       eeprom_write_record(ee_address, ID_STYLE, style);
+       ee_address+=4;
+       eeprom_erase_record(ee_address);
+}
+
+void store_single_config (const uint8_t id)
+{
+       if (ee_address >= EEPROM_SIZE - 4)
+               store_all_config();
+       else
+       {
+               switch(id)
+               {
+               case ID_BAUD:
+                       eeprom_write_record(ee_address, ID_BAUD, baud);
+                       break;
+               case ID_BITS:
+                       eeprom_write_record(ee_address, ID_BITS, serial_mode);
+                       break;
+               case ID_MODE:
+                       eeprom_write_record(ee_address, ID_MODE, mode);
+                       break;
+               case ID_NL_MODE:
+                       eeprom_write_record(ee_address, ID_NL_MODE, nl_mode);
+                       break;
+               case ID_BS_MODE:
+                       eeprom_write_record(ee_address, ID_BS_MODE, bs_mode);
+                       break;
+               case ID_ENCODING:
+                       eeprom_write_record(ee_address, ID_ENCODING, encoding);
+                       break;
+               case ID_REPLACE:
+                       eeprom_write_record(ee_address, ID_REPLACE, replace);
+                       break;
+               case ID_LWIDTH:
+                       eeprom_write_record(ee_address, ID_LWIDTH, lwidth);
+                       break;
+               case ID_LMARGIN:
+                       eeprom_write_record(ee_address, ID_LMARGIN, lmargin_aim);
+                       break;
+               case ID_RMARGIN:
+                       eeprom_write_record(ee_address, ID_RMARGIN, rmargin_aim);
+                       break;
+               case ID_PHEIGHT:
+                       eeprom_write_record(ee_address, ID_PHEIGHT, pheight);
+                       break;
+               case ID_TMARGIN:
+                       eeprom_write_record(ee_address, ID_TMARGIN, tmargin);
+                       break;
+               case ID_BMARGIN:
+                       eeprom_write_record(ee_address, ID_BMARGIN, bmargin);
+                       break;
+               case ID_HTAB:
+                       eeprom_write_record(ee_address, ID_HTAB, twidth_ch);
+                       break;
+               case ID_VTAB:
+                       eeprom_write_record(ee_address, ID_VTAB, theight_ch);
+                       break;
+               case ID_CWIDTH:
+                       eeprom_write_record(ee_address, ID_CWIDTH, cwidth_aim);
+                       break;
+               case ID_LHEIGHT:
+                       eeprom_write_record(ee_address, ID_LHEIGHT, lheight);
+                       break;
+               case ID_FLOW:
+                       eeprom_write_record(ee_address, ID_FLOW, flow);
+                       break;
+               case ID_PAPER:
+                       eeprom_write_record(ee_address, ID_PAPER, paper);
+                       break;
+               case ID_STYLE:
+                       eeprom_write_record(ee_address, ID_STYLE, style);
+                       break;
+               default:
+                       return;
+               }
+               ee_address += 4;
+               eeprom_erase_record(ee_address);
+       }
+}
+
+void load_config (void)
+{
+       uint8_t  block[4];
+       uint8_t  i;
+       uint8_t  checksum;
+       uint8_t  ld_baud = baud;
+       uint8_t  ld_serial_mode = serial_mode;
+       uint8_t  ld_flow = flow;
+       uint8_t  ld_encoding = encoding;
+       uint16_t ld_lwidth = lwidth;
+       uint16_t ld_lmargin = lmargin_aim;
+       uint16_t ld_rmargin = lmargin_aim;
+       uint16_t ld_pheight = pheight;
+       uint16_t ld_tmargin = tmargin;
+       uint16_t ld_bmargin = bmargin;
+       uint8_t  ld_twidth = twidth_ch;
+       uint8_t  ld_theight = theight_ch;
+       uint8_t  ld_cwidth = cwidth_aim;
+       uint8_t  ld_lheight = lheight;
+       
+       ee_address = 0;
+       while(1)
+       {
+               // add_outcome_str("LOAD ");
+               // add_outcome_hex(ee_address,4);
+               // add_outcome(' ');
+               checksum = 0;
+               for (i=0; i<4; ++i)
+               {
+                       block[i] = eeprom_read(ee_address + i);
+                       checksum += block[i];
+               }
+               // add_outcome_hex(block[0],2);
+               // add_outcome(' ');
+               // add_outcome_hex(block[1],2);
+               // add_outcome(' ');
+               // add_outcome_hex(block[2],2);
+               // add_outcome(' ');
+               // add_outcome_hex(block[3],2);
+               // add_outcome(' ');
+               if (checksum!=0)
+               {
+                       eeprom_erase_record(ee_address);
+                       break;
+                       // add_outcome_str("BAD CHECKSUM\r\n");
+               }
+               switch (block[0])
+               {
+               case ID_BAUD:
+                       ld_baud = block[2];
+                       // add_outcome_str("BAUD ");
+                       // add_outcome_dec(ld_baud, 1);
+                       break;
+               case ID_BITS:
+                       ld_serial_mode = block[2];
+                       // add_outcome_str("BITS ");
+                       // add_outcome_dec(ld_serial_mode, 1);
+                       break;
+               case ID_MODE:
+                       loaded_mode = block[2];
+                       // add_outcome_str("mode ");
+                       // add_outcome_dec(loaded_mode, 1);
+                       break;
+               case ID_NL_MODE:
+                       nl_mode = block[2];
+                       // add_outcome_str("NL ");
+                       // add_outcome_dec(nl_mode, 1);
+                       break;
+               case ID_BS_MODE:
+                       bs_mode = block[2];
+                       // add_outcome_str("BS ");
+                       // add_outcome_dec(bs_mode, 1);
+                       break;
+               case ID_ENCODING:
+                       ld_encoding = block[2];
+                       // add_outcome_str("ENCODING ");
+                       // add_outcome_dec(ld_encoding, 1);
+                       break;
+               case ID_REPLACE:
+                       replace = block[2];
+                       // add_outcome_str("REPLACE ");
+                       // add_outcome_dec(replace, 1);
+                       break;
+               case ID_LWIDTH:
+                       ld_lwidth = (((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("LWIDTH ");
+                       // add_outcome_dec(ld_lwidth, 1);
+                       break;
+               case ID_LMARGIN:
+                       ld_lmargin = (((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("LMARGIN ");
+                       // add_outcome_dec(ld_lmargin, 1);
+                       break;
+               case ID_RMARGIN:
+                       ld_rmargin = (((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("RMARGIN ");
+                       // add_outcome_dec(ld_rmargin, 1);
+                       break;
+               case ID_PHEIGHT:
+                       ld_pheight = (((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("PHEIGHT ");
+                       // add_outcome_dec(ld_pheight, 1);
+                       break;
+               case ID_TMARGIN:
+                       ld_tmargin =(((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("TMARGIN ");
+                       // add_outcome_dec(ld_tmargin, 1);
+                       break;
+               case ID_BMARGIN:
+                       ld_bmargin =(((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("BMARGIN ");
+                       // add_outcome_dec(ld_bmargin, 1);
+                       break;
+               case ID_HTAB:
+                       ld_twidth = (((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("HTAB ");
+                       // add_outcome_dec(ld_twidth, 1);
+                       break;
+               case ID_VTAB:
+                       ld_theight = block[2];
+                       // add_outcome_str("VTAB ");
+                       // add_outcome_dec(ld_theight, 1);
+                       break;
+               case ID_CWIDTH:
+                       ld_cwidth = block[2];
+                       // add_outcome_str("CWIDTH ");
+                       // add_outcome_dec(ld_cwidth, 1);
+                       break;
+               case ID_LHEIGHT:
+                       ld_lheight = (((uint16_t)block[3])<<8)|block[2];
+                       // add_outcome_str("LHEIGHT ");
+                       // add_outcome_dec(ld_lheight, 1);
+                       break;
+               case ID_FLOW:
+                       ld_flow = block[2];
+                       // add_outcome_str("FLOW ");
+                       // add_outcome_dec(ld_flow, 1);
+                       break;
+               case ID_PAPER:
+                       paper = block[2];
+                       // add_outcome_str("PAPER ");
+                       // add_outcome_dec(paper, 1);
+                       break;
+               case ID_STYLE:
+                       loaded_style = block[2];
+                       // add_outcome_str("STYLE ");
+                       // add_outcome_dec(loaded_style, 1);
+                       break;
+               default:
+                       break;
+               }
+               // add_outcome_str("\r\n");
+               ee_address +=4;
+               if (ee_address >= EEPROM_SIZE)
+                       break;
+       }
+       set_baudrate(ld_baud);
+       set_serial_mode(ld_serial_mode);
+       set_flowcontrol(ld_flow);
+       set_encoding(ld_encoding);
+       
+       set_pheight(ld_pheight);
+       set_lwidth(ld_lwidth);
+       set_lheight(ld_lheight);
+       set_cwidth(ld_cwidth);
+       set_tmargin(ld_tmargin);
+       set_bmargin(ld_bmargin);
+       set_lmargin(ld_lmargin);
+       set_rmargin(ld_rmargin);
+       set_theight_ch(ld_theight);
+       set_twidth_ch(ld_twidth);
+}
+
+static inline void scan_keyboard (void)
+{
+       static uint8_t base_state [8] = {0,0,0,0,0,0,0,0};
+       static uint8_t last_state [8] = {0,0,0,0,0,0,0,0};
+       
+       static uint8_t shift_state = 0;
+       static uint8_t code_state  = 0;
+       
+       static uint8_t last_row = 0b00000000;
+       static uint8_t last_col = 0b00000000;
+       static uint8_t hold_count = 0;
+       static uint8_t key_debounce[8] = {0,0,0,0,0,0,0,0};
+       static uint8_t key_repeat[8] = {0,0,0,0,0,0,0,0};
+       
+       uint8_t row, col;
+       uint8_t ind, ind_base, ind_off;
+       uint8_t filtered_state;
+       
+       uint8_t send_event = 0;
+       
+       col = PIN_COL;
+       row = PIN_ROW;
+       
+       if (row == last_row)
+               ++hold_count;
+       else
+       {
+               if (hold_count >= SCAN_HOLD)
+               {
+                       switch(last_row)
+                       {
+                       case KEYB_0:
+                               ind = 0;
+                               ind_base = KEYB_ROW_0;
+                               break;
+                       case KEYB_1:
+                               ind = 1;
+                               ind_base = KEYB_ROW_1;
+                               break;
+                       case KEYB_2:
+                               ind = 2;
+                               ind_base = KEYB_ROW_2;
+                               break;
+                       case KEYB_3:
+                               ind = 3;
+                               ind_base = KEYB_ROW_3;
+                               break;
+                       case KEYB_4:
+                               ind = 4;
+                               ind_base = KEYB_ROW_4;
+                               break;
+                       case KEYB_5:
+                               ind = 5;
+                               ind_base = KEYB_ROW_5;
+                               break;
+                       case KEYB_6:
+                               ind = 6;
+                               ind_base = KEYB_ROW_6;
+                               break;
+                       case KEYB_7:
+                               ind = 7;
+                               ind_base = KEYB_ROW_7;
+                               break;
+                       default:
+                               ind = 0xff;
+                       }
+                       if (ind < 8)
+                       {
+                               if (last_col != last_state[ind])
+                                       key_debounce[ind] = 0;
+                               else 
+                               {
+                                       if(key_debounce[ind] < SCAN_DEBOUNCE)
+                                       {
+                                               ++key_debounce[ind];
+                                               if(key_debounce[ind] == SCAN_DEBOUNCE)
+                                               {
+                                                       base_state[ind] = last_col;
+                                                       key_repeat[ind] = SCAN_DEBOUNCE - 1;
+                                                       send_event = 1;
+                                               }
+                                       }
+                               }
+                               
+                               if (key_repeat[ind] >= SCAN_DELAY)
+                               {
+                                       key_repeat[ind] -= SCAN_REPEAT;
+                                       send_event = 1;
+                               }
+                                       ++key_repeat[ind];
+                               
+                               if (send_event)
+                               {
+                                       send_event=0;
+                                       filtered_state = base_state[ind];
+                                       if (ind==KEYB_MOD_IND)
+                                       {
+                                               shift_state = (filtered_state & KEYB_SHIFT_BIT) ? KEYB_SHIFT : 0;
+                                               code_state = (filtered_state & KEYB_CODE_BIT) ? KEYB_CODE : 0;
+                                               filtered_state &= ~(KEYB_SHIFT_BIT | KEYB_CODE_BIT);
+                                       }
+                                       switch (filtered_state)
+                                       {
+                                       case KEYB_0:
+                                               ind_off = KEYB_COL_0;
+                                               break;
+                                       case KEYB_1:
+                                               ind_off = KEYB_COL_1;
+                                               break;
+                                       case KEYB_2:
+                                               ind_off = KEYB_COL_2;
+                                               break;
+                                       case KEYB_3:
+                                               ind_off = KEYB_COL_3;
+                                               break;
+                                       case KEYB_4:
+                                               ind_off = KEYB_COL_4;
+                                               break;
+                                       case KEYB_5:
+                                               ind_off = KEYB_COL_5;
+                                               break;
+                                       case KEYB_6:
+                                               ind_off = KEYB_COL_6;
+                                               break;
+                                       case KEYB_7:
+                                               ind_off = KEYB_COL_7;
+                                               break;
+                                       default:
+                                               ind_off = 0xff;
+                                               break;
+                                       }
+                                       if (ind_off <= KEYB_COL_7)
+                                       {
+                                               add_scan(ind_base | ind_off | shift_state | code_state);
+                                       }
+                               }
+                               last_state[ind] = last_col;
+                       }
+               }
+               hold_count=0;
+       }
+       last_row = row;
+       last_col = col;
+}
+
+void add_scan (const uint8_t key)
+{
+       if (FULL_BP(scan_w, scan_r, N_SCAN_BUFFER))
+       {
+               set_led = 10;
+               set_alarm = 1;
+               return;
+       }
+       
+       scan_buffer[scan_w] = key;
+       ADVANCE_BP(scan_w, N_SCAN_BUFFER);
+       
+       cancel_sleep(WAKEUP_SCAN);
+}
+
+void handle_scan (void)
+{
+       uint8_t key;
+       uint8_t ch;
+       uint16_t uni_ch;
+       uint8_t  uni_bytes;
+       uint8_t  uni_buffer[3];
+       
+       static uint8_t ctrl = 0;
+       
+       
+       cli();
+       if (EMPTY_BP(scan_w, scan_r, N_SCAN_BUFFER))
+       {
+               allow_sleep(WAKEUP_SCAN);
+               sei();
+       }
+       else
+       {
+               sei();
+               
+               key = scan_buffer[scan_r];
+               ADVANCE_BP(scan_r, N_SCAN_BUFFER);
+               
+               if (mode == MODE_WAIT)
+               {
+                       if (key & (KEYB_SHIFT|KEYB_CODE))
+                               become_terminal();
+                       else
+                               become_typewriter();
+               }
+               
+               if (mode & MODE_TERM)
+               {
+                       switch (key)
+                       {
+                       case KEY_CAPS:
+                               if(!wait_page)
+                                       break;
+                       case SKEY_CAPS:
+                               vpos = tmargin;
+                               vpos_aim = tmargin;
+                               wait_page = 0;
+                               set_alarm = 1;
+                               break;
+                       case CODE_BOLD:
+                               toggle_bold();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case CODE_UNDER:
+                               toggle_under();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case CODE_STRONG:
+                               set_style_strong();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case CODE_WEAK:
+                               set_style_weak();
+                               store_single_config(ID_STYLE);
+                               set_alarm=1;
+                               break;
+                       case CODE_LINE1:
+                               set_lheight(HEIGHT_6);
+                               store_single_config(ID_LHEIGHT);
+                               set_alarm=1;
+                               break;
+                       case CODE_LINE1_5:
+                               set_lheight(HEIGHT_4);
+                               store_single_config(ID_LHEIGHT);
+                               set_alarm=1;
+                               break;
+                       case CODE_LINE2:
+                               set_lheight(HEIGHT_3);
+                               store_single_config(ID_LHEIGHT);
+                               set_alarm=1;
+                               break;
+                       case CODE_PITCH10:
+                               set_cwidth(WIDTH_10);
+                               store_single_config(ID_CWIDTH);
+                               set_alarm=1;
+                               break;
+                       case CODE_PITCH12:
+                               set_cwidth(WIDTH_12);
+                               store_single_config(ID_CWIDTH);
+                               set_alarm=1;
+                               break;
+                       case QMENU_ECHO:
+                               mode ^= MODE_ECHO;
+                               store_single_config(ID_MODE);
+                               set_alarm=1;
+                               break;
+                       case QMENU_PAPER:
+                               if (paper == PAPER_SINGLE)
+                                       paper = PAPER_CONTINUOUS;
+                               else
+                                       paper = PAPER_SINGLE;
+                               store_single_config(ID_PAPER);
+                               set_alarm=1;
+                               break;
+                       case QMENU_EXIT:
+                               become_typewriter();
+                               break;
+                       default:
+                               if (handle_menu(key))
+                                       ctrl = 0;
+                               else
+                               {
+                                       switch(key)
+                                       {
+                                       case KEY_BACK:
+                                               add_ch((bs_mode & BS_BS) ? 0x08 : 0x7f);
+                                               break;
+                                       case KEY_ERASE1:
+                                               add_ch((bs_mode & BS_DEL)  ? 0x7f : 0x08);
+                                               break;
+                                       case KEY_ERASEW:
+                                               ctrl = 1;
+                                               break;
+                                       case KEY_RETURN:
+                                       case SKEY_RETURN:
+                                               if (nl_mode & NL_SEND_CR)
+                                                       add_ch('\r');
+                                               if (nl_mode & NL_SEND_LF)
+                                                       add_ch('\n');
+                                               break;
+                                       default:
+                                               if (encoding & ENC_UNI)
+                                               {
+                                                       uni_ch = KEYMAP_UNI[key];
+                                                       if (uni_ch >= 0x0080)
+                                                       {
+                                                               uni_buffer[0] = 0b10000000;
+                                                               if (uni_ch >= 0x0800)
+                                                               {
+                                                                       uni_bytes = 3;
+                                                                       uni_buffer[1] = 0b10000000;
+                                                                       uni_buffer[2] = 0b11100000;
+                                                               }
+                                                               else
+                                                               {
+                                                                       uni_bytes = 2;
+                                                                       uni_buffer[1] = 0b11000000;
+                                                               }
+                                                               uni_buffer[0] |= uni_ch & 0b00111111;
+                                                               uni_ch >>= 6;
+                                                               uni_buffer[1] |= uni_ch & 0b00111111;
+                                                               uni_ch >>= 6;
+                                                               uni_buffer[2] |= uni_ch;
+                                                               while (uni_bytes)
+                                                               {
+                                                                       --uni_bytes;
+                                                                       add_ch(uni_buffer[uni_bytes]);
+                                                               }
+                                                       }
+                                                       else if (uni_ch)
+                                                       {
+                                                               if (ctrl)
+                                                               {
+                                                                       uni_ch &= 0x1f;
+                                                                       ctrl = 0;
+                                                               }
+                                                               add_ch(uni_ch);
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       ch = KEYMAP_CP[key];
+                                                       if (ch)
+                                                       {
+                                                               if (ctrl)
+                                                               {
+                                                                       ch &= 0x1f;
+                                                                       ctrl = 0;
+                                                               }
+                                                               add_ch(ch);
+                                                       }
+                                               }
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+static inline void goto_sleep (void)
+{
+       if (!keep_active)
+       {
+               SMCR =
+                       (1 << SE) | // enable sleep
+                       (0 << SM0); // idle
+               sleep_cpu();
+       }
+}
+
+static inline void cancel_sleep (const uint8_t flag)
+{
+       SMCR &= ~(1 << SE); //disable sleep
+       keep_active |= flag;
+}
+
+static inline void allow_sleep (const uint8_t flag)
+{
+       keep_active &= ~flag;
+}
+
+
+ISR(TIMER2_COMPA_vect)
+{
+       scan_keyboard();
+       
+       static uint8_t  print_timer = 0;
+       static uint16_t led_timer = 0;
+       static uint8_t  led_on = 0;
+       
+       if (print_timer >= PRINT_DIV-1)
+       {
+               print_timer = 0;
+               handle_print();
+               if ((flow & FLOW_HW) == FLOW_HD_DCE)
+                       update_flowcontrol_hw();
+       }
+       else
+               ++print_timer;
+       
+       if (led_timer >= LED_DIV-1)
+       {
+               led_timer = 0;
+               if (set_led)
+               {
+                       PORT_CTRL &= ~LED;
+                       if (set_led > led_on)
+                               led_on = set_led;
+                       set_led = 0;
+               }
+               else if(led_on)
+               {
+                       --led_on;
+                       if (!led_on)
+                               PORT_CTRL |= LED;
+               }
+       }
+       ++led_timer;
+       
+       // goto_sleep();
+}
+
+void add_income (const uint8_t in, const uint8_t blocking)
+{
+       while (FULL_BP(income_w, income_r, N_INCOME_BUFFER))
+       {
+               if (blocking)
+                       handle_income();
+               else
+               {
+                       set_led = 10;
+                       set_alarm = 1;
+                       reject_income();
+                       return;
+               }
+       }
+       
+       set_led = 2;
+       
+       income_buffer[income_w] = in;
+       ADVANCE_BP(income_w, N_INCOME_BUFFER);
+       
+       if (DIFF_BP(income_w, income_r, N_INCOME_BUFFER) >= INCOME_BUFFER_HIGH) // buffer getting full
+               reject_income();
+       
+       cancel_sleep(WAKEUP_INCOME);
+}
+
+void handle_income (void)
+{
+       uint8_t in;
+       
+       static uint8_t  uni_bytes = 0;
+       static uint32_t uni_ch = 0; 
+       
+       if (wait_page)
+       {
+               if (paper == PAPER_CONTINUOUS)
+                       wait_page = 0;
+               else
+               {
+                       set_led = 2;
+                       return;
+               }
+       }
+       
+       cli();
+       if (EMPTY_BP(income_w, income_r, N_BUFER_INCOME))
+       {
+               allow_sleep(WAKEUP_INCOME);
+               sei();
+               accept_income(); 
+       }
+       else
+       {
+               sei();
+               
+               in = income_buffer[income_r];
+               ADVANCE_BP(income_r, N_INCOME_BUFFER);
+               
+               if (DIFF_BP(income_w, income_r, N_INCOME_BUFFER) < INCOME_BUFFER_LOW) // buffer getting free
+                       accept_income(); // resume communication please
+               
+               if (mode == MODE_WAIT)
+                       become_terminal();
+               
+               if (mode & MODE_TERM)
+               {
+                       if (encoding && ENC_UNI) // UTF-8
+                       {
+                               if (uni_bytes && (in < 0x80)) // interrupted utf-8 sequence
+                               {
+                                       add_print_ch(CH_UNKN);
+                                       uni_bytes = 0;
+                               }
+                               
+                               if ((in & 0b11000000) == 0b10000000) // continuation of sequence
+                               {
+                                       if (uni_bytes) // byte was expected. handle it
+                                       {
+                                               uni_ch <<= 6;
+                                               uni_ch |= in & 0b00111111;
+                                               --uni_bytes;
+                                               if (!uni_bytes) // finished
+                                               {
+                                                       if (uni_ch < CH_LIMIT)
+                       
+                       
+                       
+                       
+                       
+                       
+                       
+                       
+                       
+                       if (uni_bytes && (in < 0x80)) // interrupted utf-8 sequence
+                       {
+                               add_print_ch(CH_UNKN);
+                               uni_bytes = 0;
+                       }
+                       
+                       if (handle_ctrl(in))
+                       {
+                       }
+                       else if (in < 0x80) // ascii
+                       {
+                               add_print_ch(CH_ASCII[in]);
+                       }
+                       else if (encoding & ENC_UNI) // utf-8
+                       {
+                               if ((in & 0b11000000) == 0b10000000) // continuation
+                               {
+                                       if (uni_bytes)
+                                       {
+                                               uni_ch <<= 6;
+                                               uni_ch |= in & 0b00111111;
+                                               --uni_bytes;
+                                               if (!uni_bytes) // finished
+                                               {
+                                                       if (uni_ch < CH_LIMIT)
+                                                               add_print_ch(UNI_TABLE[uni_ch]);
+                                                       else
+                                                               add_print_ch(CH_UNKN);
+                                               }
+                                       }
+                                       else
+                                               add_print_ch(CH_UNKN);
+                               }
+                               else // new char
+                               {
+                                       if (uni_bytes)
+                                               add_print_ch(CH_UNKN);
+                                       if ((in & 0b11100000) == 0b11000000) // 2 byte
+                                       {
+                                               uni_ch = in & 0b00011111;
+                                               uni_bytes = 1;
+                                       }
+                                       else if ((in & 0b11110000) == 0b11100000) // 3 byte
+                                       {
+                                               uni_ch = in & 0b00001111;
+                                               uni_bytes = 2;
+                                       }
+                                       else if ((in & 0b11111000) == 0b11110000) // 4 byte
+                                       {
+                                               uni_ch = in & 0b00000111;
+                                               uni_bytes = 3;
+                                       }
+                                       else if ((in & 0b11111100) == 0b11111000) // 5 byte [!]
+                                       {
+                                               uni_ch = in & 0b00000011;
+                                               uni_bytes = 4;
+                                       }
+                                       else if ((in & 0b11111110) == 0b11111100) // 6 byte [!]
+                                       {
+                                               uni_ch = in & 0b00000001;
+                                               uni_bytes = 5;
+                                       }
+                                       else if (in == 0b11111110) // 7 byte [!]
+                                       {
+                                               uni_ch = 0;
+                                               uni_bytes = 6;
+                                       }
+                                       else // ???
+                                       {
+                                               uni_bytes = 0;
+                                               add_print_ch(CH_UNKN);
+                                       }
+                               }
+                       }
+                       else // codepage
+                       {
+                               if (uni_bytes) // leftover
+                               {
+                                       uni_bytes = 0;
+                                       add_print_ch(CH_UNKN);
+                               }
+                               add_print_ch(CH_CP[in]);
+                       }
+               }
+       }
+}
+
+void add_outcome (const uint8_t out)
+{
+       if (
+               (out & 0x80) && // high bit set
+               ((serial_mode & UART_DATA) == UART_DATA_7) // serial set to 7 bits
+       )
+               return; // refuse to send such value in this mode
+       
+       while (FULL_BP(outcome_w, outcome_r, N_OUTCOME_BUFFER))
+       {
+               handle_outcome();
+       }
+       
+       outcome_buffer[outcome_w] = out;
+       ADVANCE_BP(outcome_w, N_OUTCOME_BUFFER);
+       
+       cancel_sleep(WAKEUP_OUTCOME);
+}
+
+void handle_outcome (void)
+{
+       if (send_xonoff) // requested to send XON or XOFF
+       {
+               if (UCSR0A & (1<<UDRE0))
+               {
+                       UDR0 = send_xonoff;
+                       send_xonoff = 0;
+                       set_led = 2;
+               }
+               return;
+       }
+       cli();
+       if (EMPTY_BP(outcome_w, outcome_r, N_BUFFER_OUTCOME))
+       {
+               allow_sleep(WAKEUP_OUTCOME);
+               sei();
+               unrequest_outcome();
+       }
+       else
+       {
+               sei();
+               request_outcome();
+               if (
+                       outcome_accepted() &&
+                       (UCSR0A & (1<<UDRE0))
+               )
+               {
+                       UDR0 = outcome_buffer[outcome_r];
+                       ADVANCE_BP(outcome_r, N_OUTCOME_BUFFER);
+                       set_led = 2;
+               }
+       }
+}
+
+static inline void add_ch (const uint8_t io)
+{
+       if (mode & MODE_ECHO)
+               add_income(io, 1);
+       add_outcome(io);
+}
+
+void add_income_str (uint8_t const * in, const uint8_t blocking)
+{
+       uint8_t const * p;
+       
+       for (p = in; *p != 0x00; ++p)
+               add_income(*p, 1);
+}
+
+void add_outcome_str (uint8_t const * out)
+{
+       uint8_t const * p;
+       
+       for (p = out; *p != 0x00; ++p)
+               add_outcome(*p);
+}
+
+uint8_t make_dec_string ( // create decimal text representation of number
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits
+)
+{
+       int8_t i, j;
+       uint8_t text[10];
+       uint8_t digit;
+       uint8_t first_digit = 9;
+       
+       for(i=9; i>=0; --i)
+       {
+               digit = value % 10;
+               value /= 10;
+               
+               if (digit != 0)
+                       first_digit = i;
+               
+               text[i] = digit + '0';
+       }
+       if ((10 - min_digits) < first_digit)
+               first_digit = 10 - min_digits;
+       if ((10 - first_digit) > max_digits)
+               first_digit = 10 - max_digits;
+       
+       for (i=first_digit, j=0; i<10; ++i, ++j)
+               string[j] = text[i];
+       
+       return 10 - first_digit; // return actual number of digits
+}
+
+uint8_t make_hex_string ( // create hexadecimal text representation of number
+       uint8_t * const string,
+       uint32_t value,
+       const uint8_t min_digits,
+       const uint8_t max_digits,
+       const uint8_t uppercase
+)
+{
+       int8_t i, j;
+       uint8_t text[8];
+       uint8_t digit;
+       uint8_t first_digit = 7;
+       
+       for(i=7; i>=0; --i)
+       {
+               digit = value & 0x0f;
+               value >>=4;
+               
+               if (digit != 0)
+                       first_digit = i;
+               
+               if (digit < 10)
+                       text[i] = digit + '0';
+               else if (uppercase)
+                       text[i] = digit + 'A' - 10;
+               else
+                       text[i] = digit + 'a' - 10;
+       }
+       if ((8 - min_digits) < first_digit)
+               first_digit = 8 - min_digits;
+       if ((8 - first_digit) > max_digits)
+               first_digit = 8 - max_digits;
+       
+       for (i=first_digit, j=0; i<8; ++i, ++j)
+               string[j] = text[i];
+       
+       return 8 - first_digit; // return actual number of digits
+}
+
+void add_outcome_dec (const uint32_t value, const uint8_t min_digits)
+{
+       uint8_t text[11];
+       uint8_t x;
+       
+       x = make_dec_string(
+               text,
+               value,
+               min_digits,
+               10
+       );
+       text[x] = 0x00;
+       add_outcome_str(text);
+}
+
+void add_outcome_hex (const uint32_t value, const uint8_t min_digits)
+{
+       uint8_t text[9];
+       uint8_t x;
+       
+       x = make_hex_string(
+               text,
+               value,
+               min_digits,
+               8,
+               1
+       );
+       text[x] = 0x00;
+       add_outcome_str(text);
+}
+
+uint8_t goto_next_col (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       out_margin |= ignore_margin; 
+       
+       hpos_aim += cwidth_aim;
+       if (((hpos_aim + cwidth_aim) > rmargin_aim) && (!out_margin))
+       {
+               stop = 1;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_prev_col (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       out_margin |= ignore_margin; 
+       
+       hpos_aim -= cwidth_aim;
+       if ((hpos_aim <= lmargin_aim) && (!out_margin))
+       {
+               hpos_aim = lmargin_aim;
+               stop = 1;
+       }
+       adjust_print_pos();
+       return stop;
+}
+
+void move_forward_col (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_col(ignore_margin))
+                       break;
+       }
+}
+
+void move_back_col (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_col(ignore_margin))
+                       break;
+       }
+}
+
+void goto_col (uint8_t x)
+{
+       if (x == 0xff) //-1
+               x = 0;
+       
+       out_margin = 1;
+       
+       hpos_aim = x * cwidth_aim;
+       if ((hpos_aim + cwidth_aim) > lwidth)
+               hpos_aim = lwidth - cwidth_aim;
+       adjust_print_pos();
+}
+
+static inline void goto_lmargin (void)
+{
+       hpos_aim = lmargin_aim;
+       adjust_print_pos();
+}
+
+static inline void goto_col0 (void)
+{
+       out_margin = 1;
+       hpos_aim = 0;
+       adjust_print_pos();
+}
+
+uint8_t goto_next_line (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       vpos_aim += lheight;
+       
+       if (
+               (((vpos_aim + cwidth) > bmargin) && (!out_margin)) ||
+               ((vpos_aim + cwidth) > pheight)
+       ) // don't apply +1 offset
+               stop = 1;
+       
+       if (((vpos_aim + lheight) > bmargin ) && (!out_margin)) // don't apply +1 offset
+       {
+               // if (vpos <= bmargin)
+                       // vpos_aim = bmargin; // will send us to next page anyways
+               // else
+                       // vpos_aim = vpos
+               stop = 1;
+       }
+       else if ((vpos_aim + lheight) > pheight) // don't apply +1 offset
+       {
+               // if (vpos <= pheight)
+                       // vpos_aim = pheight;
+               // else
+                       // vpos_aim = pheight
+               stop = 1;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_prev_line (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       vpos_aim -= lheight;
+       if ((vpos_aim < tmargin ) && (!out_margin))// don't apply -1 offset
+       {
+               stop = 1;
+               if (vpos >= tmargin)
+                       vpos_aim = tmargin;
+               else
+                       vpos_aim = vpos;
+       }
+       else if (vpos_aim < 1)
+       {
+               stop = 1;
+               if (vpos >= 0)
+                       vpos_aim = 0;
+               else
+                       vpos_aim = vpos;
+       }
+       
+       adjust_print_pos();
+       return stop;
+}
+
+static inline void goto_next_vstep (void)
+{
+       ++vpos_aim;
+       adjust_print_pos();
+}
+
+static inline void goto_prev_vstep (void)
+{
+       --vpos_aim;
+       adjust_print_pos();
+}
+
+void move_forward_line (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_line(ignore_margin))
+                       break;
+       }
+}
+
+void move_back_line (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_line(ignore_margin))
+                       break;
+       }
+}
+
+void goto_line (uint8_t y)
+{
+       if (y == 0xff) //-1
+               y = 0;
+       
+       out_margin = 1;
+       
+       vpos_aim = y * lheight;
+       if ((vpos_aim + lheight) > pheight) // don't apply +1 offset
+       {
+               if(vpos <= (pheight - lheight))
+                       vpos_aim = pheight - lheight;
+               else
+                       vpos_aim = 0;
+       }
+       adjust_print_pos();
+}
+
+static inline void goto_next_page (void)
+{
+       out_margin = 1; // will be cancelled anyway
+       vpos_aim += pheight;
+       adjust_print_pos();
+}
+
+static inline void goto_next_page_tmargin (void)
+{
+       out_margin = 1; // will be cancelled anyway
+       vpos_aim = tmargin + pheight;
+       adjust_print_pos();
+}
+
+static inline void goto_prev_page (void)
+{
+       out_margin = 1; // will be cancelled anyway [???]
+       vpos_aim -= pheight; // the world is not ready for this
+       adjust_print_pos();
+}
+
+static inline void goto_prev_page_tmargin (void)
+{
+       out_margin = 1; // will be cancelled anyway [???]
+       vpos_aim = tmargin - pheight; // the world is not ready for this
+       adjust_print_pos();
+}
+
+void move_forward_page (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_next_page();
+}
+
+void move_forward_page_tmargin (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_next_page_tmargin();
+}
+
+void move_back_page (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_prev_page();
+}
+
+void move_back_page_tmargin (const uint8_t n)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+               goto_prev_page_tmargin();
+}
+
+void goto_page (const int16_t y)
+{
+       int16_t diff;
+       
+       diff = y - ppos;
+       
+       if (diff > 0)
+       {
+               if (diff > 255) // sorry, too far
+                       return;
+               move_forward_page(diff);
+       }
+       else if (diff < 0)
+       {
+               if (diff < -255) // sorry, too far
+                       return;
+               move_back_page(0-diff);
+       }
+}
+
+uint8_t is_htab (const int16_t x)
+{
+       uint8_t i, j;
+       
+       if ((x < 0) || (x >= HPOS_LIMIT))
+               return 0;
+       
+       i = (uint8_t)(x >> 3);
+       j = ((uint8_t)x) & 7;
+       
+       return HTAB[i] & (1<<j);
+}
+
+uint8_t is_vtab (const int16_t y)
+{
+       uint8_t i, j;
+       
+       if ((y < 0) || (y >= VPOS_LIMIT))
+               return 0;
+       
+       i = (uint8_t)(y >> 3);
+       j = ((uint8_t)y) & 7;
+       
+       return VTAB[i] & (1<<j);
+}
+
+uint8_t goto_next_htab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       do
+       {
+               ++hpos_aim;
+               if (((hpos_aim + cwidth) > rmargin_aim) && (!out_margin))
+               {
+                       hpos_aim = rmargin_aim; // will send us to next line anyways
+                       stop = 1;
+                       break;
+               }
+               else if ((hpos_aim + cwidth) > lwidth)
+               {
+                       hpos_aim = lwidth - cwidth;
+                       stop = 1;
+                       break;
+               }
+       } while (!is_htab(hpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_prev_htab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       do
+       {
+               --hpos_aim;
+               if ((hpos_aim < lmargin_aim) && (!out_margin))
+               {
+                       hpos_aim = lmargin_aim;
+                       stop = 1;
+                       break;
+               }
+               else if (hpos_aim < 0)
+               {
+                       hpos_aim = 0;
+                       stop=1;
+                       break;
+               }
+       } while (!is_htab(hpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_next_vtab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       do
+       {
+               ++vpos_aim;
+               if (((vpos_aim + lheight) > bmargin ) && (!out_margin)) // don't apply +1 offset
+               {
+                       if (vpos <= bmargin)
+                               vpos_aim = bmargin; // will send us to next page anyways
+                       else
+                               vpos_aim = vpos;
+                       stop = 1;
+                       break;
+               }
+               else if ((vpos_aim + lheight) > pheight) // don't apply +1 offset
+               {
+                       if (vpos <= pheight)
+                               vpos_aim = pheight;
+                       else
+                               vpos_aim = pheight;
+                       stop = 1;
+                       break;
+               }
+       } while (!is_vtab(vpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+uint8_t goto_prev_vtab (const uint8_t ignore_margin)
+{
+       uint8_t stop = 0;
+       
+       out_margin |= ignore_margin;
+       do
+       {
+               --vpos_aim;
+               if ((vpos_aim < tmargin) && (!out_margin)) // don't apply -1 offset
+               {
+                       stop = 1;
+                       if (vpos >= tmargin)
+                               vpos_aim = tmargin;
+                       else
+                               vpos_aim = vpos;
+               }
+               else if (vpos_aim < 0) // don't apply -1 offset
+               {
+                       stop = -1;
+                       if (vpos >= 0)
+                               vpos_aim = 0;
+                       else
+                               vpos_aim = vpos;
+               }
+       } while (!is_vtab(vpos_aim));
+       
+       adjust_print_pos();
+       return stop;
+}
+
+void move_forward_htab (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_htab(ignore_margin))
+                       break;
+       }
+}
+
+void move_back_htab (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_htab(ignore_margin))
+                       break;
+       }
+}
+
+void move_forward_vtab (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_next_vtab(ignore_margin))
+                       break;
+       }
+}
+
+void move_back_vtab (const uint8_t n, const uint8_t ignore_margin)
+{
+       uint8_t i;
+       
+       if (n<1)
+               return;
+       
+       for (i=0; i<n; ++i)
+       {
+               if (goto_prev_vtab(ignore_margin))
+                       break;
+       }
+}
+
+// better implementation needed
+void goto_htab (const int8_t x, const uint8_t ignore_margin)
+{
+       hpos_aim = lmargin_aim;
+       adjust_print_pos();
+       if (x>0)
+               move_forward_htab(x, ignore_margin);
+       else if (x<0)
+               move_back_htab(0-x, ignore_margin);
+}
+
+void set_htab (const int16_t x)
+{
+       uint8_t i, j;
+       
+       if ((x < 0) || (x >= HPOS_LIMIT))
+               return;
+       
+       i = (uint8_t)(x >> 3);
+       j = ((uint8_t)x) & 7;
+       
+       HTAB[i] |= (1<<j);
+}
+
+void clear_htab (const int16_t x)
+{
+       uint8_t i, j;
+       
+       if ((x < 0) || (x >= HPOS_LIMIT))
+               return;
+       
+       i = (uint8_t)(x >> 3);
+       j = ((uint8_t)x) & 7;
+       
+       HTAB[i] &= ~(1<<j);
+}
+
+static inline void clear_htab_ch (uint8_t x)
+{
+       if (x==0xff)
+               x = 0;
+       clear_htab(cwidth_aim * (int16_t)x);
+}
+
+void set_vtab (const int16_t y)
+{
+       uint8_t i, j;
+       
+       if ((y < 0) || (y >= VPOS_LIMIT))
+               return;
+       
+       i = (uint8_t)(y >> 3);
+       j = ((uint8_t)y) & 7;
+       
+       VTAB[i] |= (1<<j);
+}
+
+void clear_vtab (const int16_t y)
+{
+       uint8_t i, j;
+       
+       if ((y < 0) || (y >= VPOS_LIMIT))
+               return;
+       
+       i = (uint8_t)(y >> 3);
+       j = ((uint8_t)y) & 7;
+       
+       VTAB[i] &= ~(1<<j);
+}
+
+static inline void clear_htab_all (void)
+{
+       memset(HTAB, 0, HTAB_SIZE);
+}
+
+static inline void clear_vtab_all (void)
+{
+       memset(VTAB, 0, VTAB_SIZE);
+}
+
+void set_twidth (const uint8_t x)
+{
+       int16_t i;
+       
+       clear_htab_all();
+       if (x==0)
+               return;
+       set_htab(0);
+       for (i=lmargin_aim; i>0; i-=x)
+               set_htab(i);
+       for (i=lmargin_aim; i<rmargin_aim; i+=x)
+               set_htab(i);
+       for (i=rmargin_aim; i<HPOS_LIMIT; i+=x)
+               set_htab(i);
+}
+
+static inline void set_twidth_ch (const uint8_t x)
+{
+       twidth_ch = x;
+       set_twidth(x * cwidth_aim);
+}
+
+void set_theight (const uint8_t y)
+{
+       int16_t i;
+       
+       clear_vtab_all();
+       if (y==0)
+               return;
+       set_vtab(0);
+       for (i=tmargin; i>0; i-=y)
+               set_vtab(i);
+       for (i=tmargin; i<bmargin; i+=y)
+               set_vtab(i);
+       for (i=bmargin; i<VPOS_LIMIT; i+=y)
+               set_vtab(i);
+}
+
+static inline void set_theight_ch (const uint8_t y)
+{
+       theight_ch = y;
+       set_theight(y * lheight);
+}
+
+uint32_t unit (uint32_t x, const uint16_t mul, const uint16_t div)
+{
+       if (div) // normal operation
+       {
+               if (mul != 1)
+                       x *= mul;
+               if (div>1)
+                       x /= div;
+       }
+       else if (mul)
+               x *= lheight;
+       else
+               x *= cwidth_aim;
+       return x;
+}
+
+void set_lwidth (const uint16_t x)
+{
+       lwidth = + x;
+       
+       // ensure at least 1 character in line & don't exceed limits
+       if (lwidth < cwidth_aim)
+               lwidth = cwidth_aim;
+       if (lwidth > HPOS_LIMIT)
+               lwidth = HPOS_LIMIT;
+       if(rmargin_aim > lwidth)
+               rmargin_aim = lwidth;
+       if(lmargin_aim > (rmargin_aim - cwidth_aim))
+               lmargin_aim = rmargin_aim - cwidth_aim;
+}
+
+void set_pheight (const uint16_t y)
+{
+       pheight = y;
+       
+       // ensure at least 1 line in page & don't exceed limits
+       if (pheight < lheight)
+               pheight = lheight;
+       if (pheight > VPOS_LIMIT)
+               pheight = VPOS_LIMIT;
+       if (bmargin > pheight)
+               bmargin = pheight;
+       if(tmargin > bmargin - lheight)
+               tmargin = bmargin - lheight;
+}
+
+void set_cwidth (const uint8_t x)
+{
+       cwidth_aim = x;
+       
+       // ensure at least 1 character in line
+       if (lwidth < cwidth_aim)
+               lwidth = cwidth_aim;
+       if (lmargin + cwidth_aim > lwidth)
+               lmargin = lwidth - cwidth_aim;
+       if (lmargin + cwidth_aim > rmargin_aim)
+               rmargin_aim = lmargin_aim + cwidth_aim;
+       
+       if(hpos == lmargin) // opportunity to adjust at machine
+       {
+               if (x == WIDTH_10)
+               {
+                       if (cwidth != WIDTH_10)
+                               add_print_key(CODE_PITCH10);
+                       cwidth = WIDTH_10;
+               }
+               else
+               {
+                       if (cwidth != WIDTH_12)
+                               add_print_key(CODE_PITCH12);
+                       cwidth = WIDTH_12;
+               }
+               cwidth_todo = 0;
+       }
+       else
+               cwidth_todo = 1;
+}
+
+void set_lheight (const uint8_t y)
+{
+       lheight = y;
+       
+       // ensure at least 1 line in page
+       if (pheight < lheight)
+               pheight = lheight;
+       if (tmargin + lheight > pheight)
+               tmargin = pheight - lheight;
+       if (tmargin + lheight > bmargin)
+               bmargin = tmargin + lheight;
+}
+
+void set_lmargin (int16_t x)
+{
+       if (x<0)
+               x = 0;
+       lmargin_aim = x;
+       if ((lmargin_aim + cwidth_aim) > HPOS_LIMIT)
+               lmargin_aim = HPOS_LIMIT - cwidth_aim;
+       if ((lmargin_aim + cwidth_aim) > lwidth)
+               lwidth = lmargin_aim + cwidth_aim;
+       if ((lmargin_aim + cwidth_aim) > rmargin_aim)
+               rmargin_aim = lmargin_aim + cwidth_aim;
+}
+
+void set_rmargin (int16_t x)
+{
+       if (x<0)
+               x = 0;
+       rmargin_aim = x;
+       if (rmargin_aim < cwidth_aim)
+               rmargin_aim = cwidth_aim;
+       if (rmargin_aim > HPOS_LIMIT)
+               rmargin_aim = HPOS_LIMIT;
+       if (rmargin_aim > lwidth)
+               lwidth = rmargin_aim;
+       if((lmargin_aim + cwidth_aim) > rmargin_aim)
+               lmargin_aim = rmargin_aim - cwidth_aim;
+}
+
+static inline void set_lmargin_ch (uint8_t x)
+{
+       if(x==0xFF)
+               x = 0;
+       set_lmargin(cwidth_aim * (int16_t)x);
+}
+
+static inline void set_rmargin_ch (uint8_t x)
+{
+       if(x==0xFF)
+               x = 0;
+       set_rmargin(cwidth_aim * (int16_t)x);
+}
+
+void set_rmargin_rel (const int16_t x)
+{
+       if (x>0)
+               set_rmargin(lmargin_aim + x); // relative to left margin
+       else
+               set_rmargin(lwidth + x); // relative to rigth edge
+}
+
+void set_tmargin (int16_t y)
+{
+       if (y<0)
+               y = 0;
+       tmargin = y;
+       if ((tmargin + lheight) > VPOS_LIMIT)
+               tmargin = VPOS_LIMIT - lheight;
+       if ((tmargin + lheight) > pheight)
+               pheight = tmargin + lheight;
+       if ((tmargin + lheight) > bmargin)
+               bmargin = tmargin + lheight;
+}
+
+void set_bmargin (int16_t y)
+{
+       if (y<0)
+               y = 0;
+       bmargin = y;
+       if (bmargin < lheight)
+               bmargin = lheight;
+       if (bmargin > VPOS_LIMIT)
+               bmargin = VPOS_LIMIT;
+       if (bmargin > pheight)
+               pheight = bmargin;
+       if ((tmargin + lheight) > bmargin)
+       {
+               tmargin = bmargin - lheight;
+       }
+}
+
+static inline void set_tmargin_ch (uint8_t y)
+{
+       if(y==0xFF)
+               y = 0;
+       set_tmargin(lheight * (int16_t)y);
+}
+
+static inline void set_bmargin_ch (uint8_t y)
+{
+       if(y==0xFF)
+               y = 0;
+       set_bmargin(lheight * (int16_t)y);
+}
+
+void set_bmargin_rel (const int16_t y)
+{
+       if (y>0)
+               set_bmargin(tmargin + y); // relative to top margin
+       else
+               set_bmargin(pheight + y); // relative to bottom edge
+}
+
+void set_style (const uint8_t new_style)
+{
+       if ( // set bold
+               (new_style & STYLE_BOLD) &&
+               (!(style & STYLE_BOLD))
+       )
+               add_print_key(CODE_BOLD);
+       else if ( // clear bold
+               (!(new_style & STYLE_BOLD)) &&
+               (style & STYLE_BOLD)
+       )
+               add_print_key(CODE_BOLD);
+       
+       // if ( // set underline
+               // (new_style & STYLE_UNDER) &&
+               // (!(style & STYLE_UNDER))
+       // )
+               // add_print_key(CODE_UNDER);
+       // else if ( // clear underline
+               // (!(new_style & STYLE_UNDER)) &&
+               // (style & STYLE_UNDER)
+       // )
+               // add_print_key(CODE_UNDER);
+       
+       if ( // set strong
+               (new_style & STYLE_STRONG) &&
+               (!(style & STYLE_STRONG))
+       )
+               add_print_key(CODE_STRONG);
+       else if ( // clear strong
+               (!(new_style & STYLE_STRONG)) &&
+               (style & STYLE_STRONG)
+       )
+               add_print_key(CODE_WEAK);
+       
+       style = new_style;
+}
+
+static inline void set_style_normal (void)
+{
+       set_style((style & ~STYLE_STRONG) | STYLE_NORMAL);
+}
+
+static inline void set_style_bold (void)
+{
+       set_style(style | STYLE_BOLD);
+}
+
+static inline void set_style_nobold (void)
+{
+       set_style(style & ~STYLE_BOLD);
+}
+
+static inline void toggle_bold (void)
+{
+       set_style(style ^ STYLE_BOLD);
+}
+
+static inline void set_style_under (void)
+{
+       set_style((style & ~STYLE_UNDER2) | STYLE_UNDER);
+}
+
+static inline void set_style_under2 (void)
+{
+       set_style((style & ~STYLE_UNDER) | STYLE_UNDER2);
+}
+
+static inline void set_style_nounder (void)
+{
+       set_style(style & ~(STYLE_UNDER | STYLE_UNDER2));
+}
+
+static void inline toggle_under (void)
+{
+       if (style & (STYLE_UNDER | STYLE_UNDER2))
+               set_style_nounder();
+       else
+               set_style_under();
+}
+
+static inline void set_style_cross (void)
+{
+       set_style(style | STYLE_CROSS);
+}
+
+static inline void set_style_nocross (void)
+{
+       set_style(style & ~STYLE_CROSS);
+}
+
+static inline void set_style_over (void)
+{
+       set_style(style | STYLE_OVER);
+}
+
+static inline void set_style_noover (void)
+{
+       set_style(style & ~STYLE_OVER);
+}
+
+static inline void set_style_strong (void)
+{
+       set_style(style | STYLE_STRONG);
+}
+
+static inline void set_style_weak (void)
+{
+       set_style(style & ~STYLE_STRONG);
+}
+
+void add_print_key (const uint8_t key)
+{
+       while (FULL_BP(print_w, print_r, N_PRINT_BUFFER))
+       {
+       }
+       print_buffer[print_w] = key;
+       ADVANCE_BP(print_w, N_PRINT_BUFFER);
+}
+
+void adjust_print_pos (void)
+{
+       // dest. inside margins; cancel the privilege
+       if (
+               (hpos_aim >= lmargin_aim) &&
+               ((hpos_aim + cwidth_aim) <= rmargin_aim) &&
+               (vpos_aim >= tmargin - 1) &&
+               ((vpos_aim + lheight) <= (bmargin + 1))
+       )
+               out_margin = 0;
+       
+       // outside current margins; adjust margins
+       if ((hpos > rmargin) && (hpos <= rmargin_aim))
+       {
+               add_print_key(CODE_RMARGIN);
+               rmargin = hpos;
+       }
+       if ((hpos < lmargin) && (hpos >= lmargin_aim))
+       {
+               add_print_key(CODE_LMARGIN);
+               lmargin = hpos;
+       }
+       else if ((hpos == lmargin_aim) && (lmargin != lmargin_aim))
+       {
+               add_print_key(CODE_LMARGIN);
+               lmargin = hpos;
+       }
+       
+       // requested move outside right margin
+       if ((hpos_aim + cwidth_aim) > rmargin_aim)
+       {
+               // not allowed to leave; goto next line
+               if (!out_margin)
+               {
+                       hpos_aim = lmargin_aim;
+                       vpos_aim += lheight;
+               }
+               // requested move outside right edge; stay at edge
+               else if ((hpos_aim + cwidth_aim) > lwidth)
+               {
+                       hpos_aim = lwidth - cwidth_aim;
+               }
+       }
+       
+       // requested move outside left margin
+       if (hpos_aim < lmargin_aim)
+       {
+               // not allowed to leave; stay at margin
+               if (!out_margin)
+                       hpos_aim = lmargin_aim;
+               // requested move outside left edge; stay at edge
+               else if (hpos_aim < 0) 
+                       hpos_aim = 0;
+       }
+       
+       // requested move outside bottom margin; wait for new page
+       if ((vpos_aim + lheight) > (bmargin + 1))
+       {
+               if (!out_margin ) // not allowed to leave
+               {
+                       if (vpos_aim < pheight + tmargin)
+                               vpos_aim = pheight + tmargin; // skip to next page top margin
+                       set_alarm = 1;
+                       set_led = 10;
+                       wait_page = 1;
+               }
+               else if ((vpos_aim + lheight) > (pheight + 1)) // requested move outside bottom edge
+               {
+                       set_alarm = 1;
+                       set_led = 10;
+                       wait_page = 1;
+               }
+       }
+       
+       // requested move outside top margin
+       if (vpos_aim < (tmargin - 1))
+       {
+               // not allowed to leave; stay at top margin
+               if (!out_margin)
+               {
+                       if (vpos >= tmargin)
+                               vpos_aim = tmargin;
+                       else
+                               vpos_aim = vpos;
+               }
+               // requested move outside top edge; stay at edge
+               else if (vpos_aim < -1)
+               {
+                       if (vpos >= 0)
+                               vpos_aim = 0;
+                       else
+                               vpos_aim = vpos;
+               }
+       }
+       
+       // left from goal; move right
+       while (hpos < hpos_aim)
+       {
+               // move outside margin
+               if (hpos + cwidth > rmargin)
+                       add_print_key(KEY_MARGIN);
+               
+               // move right by 1 space
+               add_print_key(KEY_SPACE);
+               hpos += cwidth;
+               
+               // outside margin; adjust margin
+               if (hpos > rmargin)
+               {
+                       add_print_key(CODE_RMARGIN);
+                       rmargin = hpos;
+               }
+       }
+       
+       // right from goal & from left margin; move to left margin
+       if ((hpos_aim <= lmargin) && (hpos > lmargin))
+       {
+               add_print_key(CODE_RETURN);
+               hpos = lmargin;
+       }
+       
+       // right from goal; move left
+       while (hpos > hpos_aim)
+       {
+               // away by at least 1 space
+               if (hpos >= hpos_aim + cwidth) 
+               {
+                       // move outside margin
+                       if (hpos < lmargin + cwidth)
+                               add_print_key(KEY_MARGIN);
+                       
+                       // move left by 1 space
+                       add_print_key(KEY_BACK);
+                       hpos -= cwidth;
+               }
+               // away by less than 1 space
+               else
+               {
+                       // move outside margin
+                       if (hpos < lmargin + 1)
+                               add_print_key(KEY_MARGIN);
+                       
+                       // move left by 1 unit
+                       add_print_key(CODE_STEPLEFT);
+                       --hpos;
+               }
+               
+               // outside margin; adjust margin
+               if(hpos < lmargin)
+               {
+                       add_print_key(CODE_LMARGIN);
+                       lmargin = hpos;
+               }
+       }
+       
+       // above goal; move down
+       while (vpos < vpos_aim)
+       {
+               add_print_key(CODE_HALFDOWN);
+               ++vpos;
+       }
+       
+       // below goal; move up
+       while (vpos > vpos_aim)
+       {
+               add_print_key(CODE_HALFUP);
+               --vpos;
+       }
+       
+       // next char will be out of margin
+       if (hpos + cwidth > rmargin)
+               add_print_key(KEY_MARGIN);
+       
+       // out of page; renormalise coordinates
+       while (vpos_aim < -1)
+       {
+               vpos_aim += pheight;
+               vpos += pheight;
+               --ppos;
+       }
+       while ((vpos_aim + lheight) > (pheight + 1))
+       {
+               vpos_aim -= pheight;
+               vpos -= pheight;
+               ++ppos;
+       }
+       
+       // opportunity to adjust char width
+       if (cwidth_todo & (hpos == lmargin))
+               set_cwidth(cwidth_aim);
+}
+
+void add_print_ch (uint8_t const * const ch)
+{
+       uint8_t const * p; 
+       uint8_t count;
+       
+       // prepare position before
+       // often redundant but not always
+       adjust_print_pos();
+       
+       p = ch;
+       
+       // replacement symbol for unknown char
+       if (p == CH_UNKN)
+               p = REPLACE[replace];
+       
+       // nothing to print
+       if (*p == 0)
+               return;
+       
+       // add key sequence to buffer
+       for (count = *p; count!=0; --count)
+       {
+               ++p;
+               add_print_key(*p);
+       }
+       
+       // manually apply styles not handled automatically
+       if (style & STYLE_UNDER)
+       {
+               add_print_key(KEY_BACK);
+               add_print_key(SKEY_UNDER);
+       }
+       if (style & (STYLE_CROSS|STYLE_OVER))
+       {
+               add_print_key(CODE_HALFUP);
+               if (style & STYLE_CROSS)
+               {
+                       add_print_key(KEY_BACK);
+                       add_print_key(SKEY_UNDER);
+               }
+               if (style & STYLE_OVER)
+               {
+                       add_print_key(CODE_HALFUP);
+                       add_print_key(KEY_BACK);
+                       add_print_key(SKEY_UNDER);
+                       add_print_key(CODE_HALFDOWN);
+               }
+               add_print_key(CODE_HALFDOWN);
+       }
+       if (style & STYLE_UNDER2)
+       {
+               add_print_key(CODE_HALFDOWN);
+               add_print_key(KEY_BACK);
+               add_print_key(SKEY_EQ);
+               add_print_key(CODE_HALFUP);
+       }
+       
+       // adjust position
+       hpos += cwidth;
+       hpos_aim += cwidth_aim;
+       
+       // moved out of line; adjust again
+       if ((hpos_aim + cwidth_aim) > rmargin_aim)
+               adjust_print_pos();
+}
+
+static inline void handle_print (void)
+{
+       static uint8_t phase=0;
+       static uint8_t count=0;
+       static uint8_t delay=255;
+       static uint8_t alarm=0;
+       
+       uint8_t key;
+       
+       if (set_alarm)
+       {
+               if (set_alarm > alarm)
+                       alarm = set_alarm;
+               set_alarm = 0;
+       }
+       
+       if (!phase) // free to print next key
+       {
+               if (delay || alarm)
+               {
+                       if (alarm)
+                       {
+                               PORT_KEY = CODE_BELL;
+                               phase = 3;
+                               --alarm;
+                       }
+                       if (delay)
+                               --delay;
+               }
+               else if (!(mode & MODE_TERM))
+               {
+               }
+               else if (NOT_EMPTY_BP(print_w, print_r, N_PRINT_BUFFER))
+               {
+                       key = print_buffer[print_r];
+                       ADVANCE_BP(print_r, N_PRINT_BUFFER);
+                       
+                       if ((key == CODE_STEPLEFT_EXTRA) && (cwidth == WIDTH_NORMAL))
+                       {
+                       }
+                       else
+                       {
+                               PORT_KEY = key;
+                               phase = 3;
+                               
+                               switch (key)
+                               {
+                               case CODE_RETURN:
+                               case KEY_RETURN:
+                                       delay = count;
+                                       count = 0;
+                                       break;
+                               case KEY_BACK:
+                                       if (count >= PRINT_DELAY)
+                                               count -= PRINT_DELAY;
+                                       else
+                                               count = 0;
+                                       break;
+                               default:
+                                       if (count < 0xff - PRINT_DELAY)
+                                               count += PRINT_DELAY;
+                                       else
+                                               count = 0xff;
+                                       switch(key)
+                                       {
+                                       case CODE_STEPLEFT:
+                                       case CODE_STEPLEFT_EXTRA:
+                                       // case KEY_SPACE:
+                                       // case KEY_BACK:
+                                       case CODE_HALFUP:
+                                       // case CODE_HALFDOWN:
+                                               phase += 2;
+                                       }
+                                       
+                                       // if (style & STYLE_UNDER)
+                                               // ++phase;
+                                       if (style & STYLE_BOLD)
+                                               ++phase;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               if (phase == 3) // key down
+                       PORT_CTRL &= ~KEY;
+               else if (phase == 1) // key up
+                       PORT_CTRL |= KEY;
+               --phase;
+       }
+}
+
+ISR(USART0_RX_vect)
+{
+       uint8_t in, err;
+       
+       err = UCSR0A & ((1 << FE0) | (1 << UPE0));
+       in = UDR0; // get the byte
+       
+       if (err)
+               return;
+       
+       if ((flow & FLOW_SW) == FLOW_XONOFF)
+       {
+               if ((in == XON) || (in == XOFF))
+               {
+                       remote_xonoff = in;
+                       return;
+               }
+       }
+       
+       if (!income_requested())
+               return;
+       
+       
+       add_income(in, 0);
+}
+
+uint8_t handle_ctrl (uint8_t in)
+{
+       static uint8_t ind = 0;
+       static uint8_t buffer[N_ESC_BUFFER];
+       static uint8_t prev = 0;
+       static uint8_t ib = 0;
+       
+       uint16_t long_id;
+       
+       uint8_t c1_allowed = c1;
+       
+       uint8_t handled = 0;
+       
+       uint8_t * buffer_pos = buffer;
+       uint8_t p_ind = 0;
+       uint8_t sp_ind = 0;
+       
+       // temporary for storing parameters
+       uint8_t  u0;
+       
+       if (esc_mode == ESC_ECMA_48)
+       {
+               if (prev == 0x1B) // ESC - ESCAPE
+               {
+                       if ((in >= 0x40) && (in <= 0x5F)) // C1 recode
+                       {
+                               in += 0x40;
+                               c1_allowed = 1;
+                               if (ind)
+                                       --ind;
+                       }
+                       else // delayed reaction; interrupt previous sequence, start new
+                       {
+                               if (buffer[0] != 0x98) // SOS
+                               {
+                                       buffer[0] = 0x1B;
+                                       ib = 0;
+                                       ind = 1;
+                               }
+                       }
+               }
+               
+               // C0, C1, GR not allowed inside sequences unless in control string
+               if (
+                       ((in < 0x20) || (in > 0x7E)) && // char out of GL
+                       (ind != 0x1B) && // but not ESC (deal with it in next iteration)
+                       ind // in sequence already
+               )
+               {
+                       switch(buffer[0])
+                       {
+                       case 0x98: // SOS
+                               break;
+                       case 0x90: // DCS
+                       case 0x9A: // SCI
+                       case 0x9D: // OSC
+                       case 0x9E: // PM
+                       case 0x9F: // APC
+                               if (((in >= 0x08) && (in <= 0x0C)) || (in == 0x9C)) // allowed; do nothing 
+                                       break;
+                       default:
+                               ind = 0;
+                               break;
+                       }
+               }
+       }
+       
+       if (ind < N_ESC_BUFFER)
+               buffer[ind] = in;
+       
+       if (!ind) // single character or new sequence
+       {
+               if ((in <= 0x1F) || (in == 0x7F)) // C0
+               {
+                       switch (in)
+                       {
+                       case 0x00: // NUL - NULL
+                               break;
+                       // case 0x01: // SOH - START OF HEADING
+                       // case 0x02: // STX - START OF TEXT
+                       // case 0x03: // ETX - END OF TEXT
+                       // case 0x04: // EOT - END OF TRANSMISSION
+                       // case 0x05: // ENQ - ENQUIRY
+                       // case 0x06: // ACK - ACKNOWLEDGE
+                       case 0x07: // BEL - BELL
+                               add_print_key (CODE_BELL);
+                               break;
+                       case 0x08: // BS - BACKSPACE
+                       case 0x7F: // DEL - DELETE // TODO: should I accept this here?
+                               goto_prev_col(0);
+                               break;
+                       case 0x09: // HT - CHARACTER TABULATION
+                               goto_next_htab(0);
+                               break;
+                       case 0x0A: // LF - LINE FEED
+                               if (nl_mode & NL_IMPLICIT_CR)
+                                       goto_lmargin();
+                               if (!((nl_mode & NL_IMPLICIT_LF) && (prev==0x0D))) // already handled in last step?
+                                       goto_next_line(0);
+                               break;
+                       case 0x0B: // VT - LINE TABULATION
+                               goto_next_vtab(0);
+                               break;
+                       case 0x0C: // FF - FORM FEED
+                               goto_next_page_tmargin();
+                               break;
+                       case 0x0D: // CR - CARRIAGE RETURN
+                               goto_lmargin();
+                               if (nl_mode & NL_IMPLICIT_LF)
+                                       goto_next_line(0);
+                               break;
+                       // case 0x0E: // SO - SHIFT-OUT
+                       // case 0x0F: // SI - SHIFT-IN
+                       // case 0x10: // DLE - DATA LINK ESCAPE
+                       // case 0x11: // DC1 - DEVICE CONTROL ONE
+                       // case 0x12: // DC2 - DEVICE CONTROL TWO
+                       // case 0x13: // DC3 - DEVICE CONTROL THREE
+                       // case 0x14: // DC4 - DEVICE CONTROL FOUR
+                       // case 0x15: // NAK - NEGATIVE ACKNOWLEDGE
+                       // case 0x16: // SYN - SYNCHRONOUS IDLE
+                       // case 0x17: // ETB - END OF TRANSMISSION BLOCK
+                       // case 0x18: // CAN - CANCEL
+                       // case 0x19: // EM - END OF MEDIUM
+                       // case 0x1A: // SUB - SUBSTITUTE
+                       case 0x1B: // ESC - ESCAPE
+                               if (esc_mode == ESC_ECMA_48)
+                               {
+                                       ++ind;  // start sequence
+                                       ib = 0; // reset intermediate byte count
+                               }
+                               // else if (esc_mode == ESC_P_POS)
+                                       // ++ind;
+                               break;
+                       // case 0x1C: // IS4 - INFORMATION SEPARATOR FOUR
+                       // case 0x1D: // IS3 - INFORMATION SEPARATOR THREE
+                       // case 0x1E: // IS2 - INFORMATION SEPARATOR TWO
+                       // case 0x1F: // IS1 - INFORMATION SEPARATOR ONE
+                       default:
+                               if (esc_mode == ESC_NONE)
+                               {
+                                       add_print_ch(CH_ASCII['^']);
+                                       add_print_ch(CH_ASCII['@'+in]);
+                               }
+                               break;
+                       }
+                       handled = 1;
+               }
+               else if ((in >= 0x80) && (in <= 0x9F) && c1_allowed) // C1
+               {
+                       if (esc_mode == ESC_ECMA_48)
+                       {
+                               switch (in)
+                               {
+                               //case 0x80: // 1B 40  reserved
+                               //case 0x81: // 1B 41  reserved
+                               //case 0x82: // 1B 42  BPH - BREAK PERMITTED HERE
+                               //case 0x83: // 1B 43  NBH - NO BREAK HERE
+                               //case 0x84: // 1B 44  reserved
+                               case 0x85: // 1B 45  NEL - NEXT LINE
+                                       goto_lmargin();
+                                       goto_next_line(0);
+                                       break;
+                               //case 0x86: // 1B 46  SSA - START OF SELECTED AREA
+                               //case 0x87: // 1B 47  ESA - END OF SELECTED AREA
+                               case 0x88: // 1B 48  HTS - CHARACTER TABULATION SET
+                                       set_htab(hpos_aim);
+                                       break;
+                               case 0x89: // 1B 49  HTJ - CHARACTER TABULATION WITH JUSTIFICATION
+                                       goto_next_htab(0);
+                                       break;
+                               case 0x8A: // 1B 4A  VTS - LINE TABULATION SET
+                                       set_vtab(vpos_aim);
+                                       break;
+                               case 0x8B: // 1B 4B  PLD - PARTIAL LINE FORWARD
+                                       goto_next_vstep();
+                                       break;
+                               case 0x8C: // 1B 4C  PLU - PARTIAL LINE BACKWARD
+                                       goto_prev_vstep();
+                                       break;
+                               case 0x8D: // 1B 4D  RI - REVERSE LINE FEED
+                                       goto_prev_line(0);
+                                       break;
+                               //case 0x8E: // 1B 4E  SS2 - SINGLE-SHIFT TWO
+                               //case 0x8F: // 1B 4F  SS3 - SINGLE-SHIFT THREE
+                               //case 0x91: // 1B 51  PU1 - PRIVATE USE ONE
+                               //case 0x92: // 1B 52  PU2 - PRIVATE USE TWO
+                               //case 0x93: // 1B 53  STS - SET TRANSMIT STATE
+                               //case 0x94: // 1B 54  CCH - CANCEL CHARACTER
+                               //case 0x95: // 1B 55  MW - MESSAGE WAITING  (TODO: ->DSR)
+                               //case 0x96: // 1B 56  SPA - START OF GUARDED AREA
+                               //case 0x97: // 1B 57  EPA - END OF GUARDED AREA
+                               //case 0x99: // 1B 59  reserved
+                               //case 0x9C: // 1B 5C  ST - STRING TERMINATOR
+                               
+                               // control string / control sequence:
+                               
+                               case 0x90: // 1B 50  DCS  08-0C,20-7E - DEVICE CONTROL STRING
+                               case 0x98: // 1B 58  SOS  any         - START OF STRING
+                               case 0x9A: // 1B 5A  SCI  08-0C,20-7E - SINGLE CHARACTER INTRODUCER
+                               case 0x9D: // 1B 5D  OSC  08-0C,20-7E - OPERATING SYSTEM COMMAND
+                               case 0x9E: // 1B 5E  PM   08-0C,20-7E - PRIVACY MESSAGE
+                               case 0x9F: // 1B 5F  APC  08-0C,20-7E - APPLICATION PROGRAM COMMAND
+                               case 0x9B: // 1B 5B  CSI - CONTROL SEQUENCE INTRODUCER
+                                       ++ind;
+                                       ib = 0;
+                                       break;
+                               }
+                               handled = 1;
+                       }
+                       else
+                               handled = 0;
+               }
+               else // normal text
+                       handled = 0;
+       }
+       else // continued sequence
+       {
+               if (esc_mode == ESC_ECMA_48)
+               {
+                       handled = 1;
+                       
+                       if (in == 0x1B) // ESC - ESCAPE
+                       {
+                               // allow to go through. We'll deal with it next iteration.
+                               if (ind < N_ESC_BUFFER-1)
+                                       ++ind;
+                       }
+                       else
+                       {
+                               switch (buffer[0])
+                               {
+                               case 0x1B: // ESC - ESCAPE
+                                       if ((buffer[1] >= 0x20) && (buffer[1] <= 0x2F)) // nF
+                                       {
+                                               if ((in >= 0x20) && (in <= 0x2F)) // intermediate byte
+                                               {
+                                                       ++ib; // count intermediate bytes
+                                                       if (ind < N_ESC_BUFFER-1)
+                                                               ++ind;
+                                               }
+                                               else if ((in >= 0x30) && (in <= 0x7E)) // final byte
+                                               {
+                                                       switch (buffer[1])
+                                                       {
+                                                       // case 0x20: // ANNOUNCE CODE STRUCTURE
+                                                       // case 0x21: // C0-DESIGNATE
+                                                       // case 0x22: // C1-DESIGNATE
+                                                       // case 0x23: // Single control functions
+                                                       // case 0x24: // Designation of multiple-byte graphic character sets
+                                                       case 0x25: // DESIGNATE OTHER CODING SYSTEM
+                                                               if (ib == 1)
+                                                                       long_id = buffer[1];
+                                                               else if (ib == 2)
+                                                                       long_id = (((uint16_t)buffer[1])<<8) | buffer[2];
+                                                               else
+                                                                       break;
+                                                               switch (long_id)
+                                                               {
+                                                               case   0x47:
+                                                               case 0x2f47:
+                                                               case 0x2f48:
+                                                               case 0x2f49:
+                                                                       set_encoding(encoding | ENC_UNI);
+                                                                       break;
+                                                               case   0x40:
+                                                                       set_encoding_GR(GR_index);
+                                                                       break;
+                                                               }
+                                                               break;
+                                                       // case 0x26: // IDENTIFY REVISED REGISTRATION
+                                                       // case 0x27: // (reserved for future standardisation)
+                                                       // case 0x28: // G0-DESIGNATE 94-SET
+                                                       // case 0x29: // G1-DESIGNATE 94-SET
+                                                       // case 0x2A: // G2-DESIGNATE 94-SET
+                                                       // case 0x2B: // G3-DESIGNATE 94-SET
+                                                       // case 0x2C: // (reserved for future standardisation)
+                                                       case 0x2D: // G1-DESIGNATE 96-SET
+                                                       case 0x2E: // G2-DESIGNATE 96-SET
+                                                       case 0x2F: // G3-DESIGNATE 96-SET
+                                                               u0 = buffer[1] - 0x2D + 1;
+                                                               if (ib == 1) // single intermediate byte
+                                                               {
+                                                                       switch (buffer[2]) // final byte
+                                                                       {
+                                                                       case 0x41:
+                                                                       case 0x63:
+                                                                               GR_table[u0] = ENC_ISO8859_1;
+                                                                               break;
+                                                                       case 0x42:
+                                                                               GR_table[u0] = ENC_ISO8859_2;
+                                                                               break;
+                                                                       // case 0x43:
+                                                                               // GR_table[u0] = ENC_ISO8859_3;
+                                                                               // break;
+                                                                       // case 0x44:
+                                                                       // case 0x64:
+                                                                               // GR_table[u0] = ENC_ISO8859_4;
+                                                                               // break;
+                                                                       // case 0x4D:
+                                                                               // GR_table[u0] = ENC_ISO8859_9;
+                                                                               // break;
+                                                                       // case 0x56:
+                                                                               // GR_table[u0] = ENC_ISO8859_10;
+                                                                               // break;
+                                                                       // case 0x65:
+                                                                               // GR_table[u0] = ENC_ISO8859_13;
+                                                                               // break;
+                                                                       // case 0x62:
+                                                                               // GR_table[u0] = ENC_ISO8859_15;
+                                                                               // break;
+                                                                       default:
+                                                                               u0 = 0xff;
+                                                                       }
+                                                                       if (u0 == GR_index)
+                                                                               set_encoding_GR(GR_index);
+                                                               }
+                                                               break;
+                                                       }
+                                                       ind = 0;
+                                               }
+                                               else // invalid value
+                                               {
+                                                       ind = 0;
+                                                       handled = 0;
+                                               }
+                                       }
+                                       else if ((buffer[1] >= 0x30) && (buffer[1] <= 0x7E)) // Fp, Fs, control function 
+                                       {
+                                               switch(buffer[1])
+                                               {
+                                               // case 0x60: // DMI - DISABLE MANUAL INPUT
+                                               // case 0x61: // INT - INTERRUPT
+                                               // case 0x62: // EMI - ENABLE MANUAL INPUT
+                                               case 0x63: // RIS - RESET TO INITIAL STATE
+                                                       out_margin =  0;
+                                                       
+                                                       pheight =     DEFAULT_PHEIGHT;
+                                                       tmargin =     DEFAULT_TMARGIN;
+                                                       bmargin =     DEFAULT_BMARGIN;
+                                                       lheight =     HEIGHT_NORMAL;
+                                                       theight_ch =  DEFAULT_THEIGHT_CH;
+                                                       
+                                                       lwidth =      DEFAULT_LWIDTH;
+                                                       lmargin_aim = DEFAULT_LMARGIN_AIM;
+                                                       rmargin_aim = DEFAULT_RMARGIN_AIM;
+                                                       cwidth_aim =  WIDTH_NORMAL;
+                                                       twidth_ch =   DEFAULT_TWIDTH_CH;
+                                                       
+                                                       set_style_normal();
+                                                       
+                                                       load_config();
+                                                       
+                                                       ppos = -1;
+                                                       vpos_aim = pheight + tmargin;
+                                                       hpos_aim = lmargin_aim;
+                                                       adjust_print_pos();
+                                                       break;
+                                               // case 0x64: // CMD - CODING METHOD DELIMITER
+                                               // case 0x6E: // LS2 - LOCKING-SHIFT TWO
+                                               // case 0x6F: // LS3 - LOCKING-SHIFT THREE
+                                               case 0x7C: // LS3R - LOCKING-SHIFT THREE RIGHT
+                                                       set_encoding_GR(3);
+                                                       break;
+                                               case 0x7D: // LS2R - LOCKING-SHIFT TWO RIGHT
+                                                       set_encoding_GR(2);
+                                                       break;
+                                               case 0x7E: // LS1R - LOCKING-SHIFT ONE RIGHT
+                                                       set_encoding_GR(1);
+                                                       break;
+                                               default:
+                                                       break;
+                                               }
+                                               ind = 0;
+                                       }
+                                       else // invalid value
+                                       {
+                                               ind = 0;
+                                               handled = 0;
+                                       }
+                                       break;
+                               case 0x9B: // 1B 5B  CSI - CONTROL SEQUENCE INTRODUCER
+                                       if ((in >= 0x30) && (in <= 0x3F)) // parameter byte
+                                       {
+                                               if (prev < 0x30)  // I before P
+                                               {
+                                                       ind = 0;
+                                                       handled = 0;
+                                               }
+                                               else // ok
+                                               {
+                                                       if (ind < N_ESC_BUFFER-1)
+                                                               ++ind;
+                                               }
+                                       }
+                                       else if ((in >= 0x20) && (in <= 0x2F)) // intermediate byte
+                                       {
+                                               ++ib; // count intermediate bytes
+                                               if (ind < N_ESC_BUFFER-1)
+                                                       ++ind;
+                                       }
+                                       else if ((in >= 0x40) && (in <= 0x7E)) // final byte
+                                       {
+                                               buffer_pos = buffer + 1;
+                                               if (ib == 0) // just 1 final byte
+                                                       long_id = in;
+                                               else if (ib == 1) // 1 intermediate & 1 final byte
+                                                       long_id = (((uint16_t)prev)<<8)|in;
+                                               else
+                                                       long_id =0;
+                                               switch (long_id)
+                                               {
+                                               // case 0x40: // ICH - INSERT CHARACTER
+                                               case 0x41: // CUU - CURSOR UP
+                                               case 0x6B: // VPB - LINE POSITION BACKWARD
+                                                       move_back_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x42: // CUD - CURSOR DOWN
+                                               case 0x65: // VPR - LINE POSITION FORWARD
+                                                       move_forward_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x43: // CUF - CURSOR RIGHT
+                                               case 0x61: // HPR - CHARACTER POSITION FORWARD
+                                                       move_forward_col((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x44: // CUB - CURSOR LEFT
+                                               case 0x6A: // HPB - CHARACTER POSITION BACKWARD
+                                                       move_back_col((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x45: // CNL - CURSOR NEXT LINE
+                                                       goto_col0();
+                                                       move_forward_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x46: // CPL - CURSOR PRECEDING LINE
+                                                       goto_col0();
+                                                       move_back_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x47: // CHA - CURSOR CHARACTER ABSOLUTE
+                                               case 0x60: // HPA - CHARACTER POSITION ABSOLUTE
+                                                       goto_col(((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1))-1);
+                                                       break;
+                                               case 0x48: // CUP - CURSOR POSITION
+                                               case 0x66: // HVP - CHARACTER AND LINE POSITION
+                                                       goto_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       goto_col((uint8_t)get_ctrl_parameter(CTRL_IND, 1, 0, 1)-1);
+                                                       break;
+                                               case 0x49: // CHT - CURSOR FORWARD TABULATION
+                                                       move_forward_htab ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               // case 0x4A: // ED - ERASE IN PAGE
+                                               // case 0x4B: // EL - ERASE IN LINE
+                                               // case 0x4C: // IL - INSERT LINE
+                                               // case 0x4D: // DL - DELETE LINE
+                                               // case 0x4E: // EF - ERASE IN FIELD
+                                               // case 0x4F: // EA - ERASE IN AREA
+                                               // case 0x50: // DCH - DELETE CHARACTER
+                                               // case 0x51: // SEE - SELECT EDITING EXTENT
+                                               // case 0x52: // CPR - ACTIVE POSITION REPORT
+                                               // case 0x53: // SU - SCROLL UP
+                                               // case 0x54: // SD - SCROLL DOWN
+                                               case 0x55: // NP - NEXT PAGE
+                                                       move_forward_page_tmargin((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               case 0x56: // PP - PRECEDING PAGE
+                                                       move_back_page_tmargin((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               case 0x57: // CTC - CURSOR TABULATION CONTROL
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                               set_htab(hpos_aim);
+                                                               break;
+                                                       case 1:
+                                                               set_vtab(vpos_aim);
+                                                               break;
+                                                       case 2:
+                                                               clear_htab(hpos_aim);
+                                                               break;
+                                                       case 3:
+                                                               clear_vtab(hpos_aim);
+                                                               break;
+                                                       case 4:
+                                                       case 5:
+                                                               clear_htab_all();
+                                                               break;
+                                                       case 6:
+                                                               clear_vtab_all();
+                                                               break;
+                                                       }
+                                                       break;
+                                               // case 0x58: // ECH - ERASE CHARACTER
+                                               case 0x59: // CVT - CURSOR LINE TABULATION
+                                                       move_forward_vtab((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               case 0x5A: // CBT - CURSOR BACKWARD TABULATION
+                                                       move_back_htab ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               // case 0x5B: // SRS - START REVERSED STRING
+                                               // case 0x5C: // PTX - PARALLEL TEXTS
+                                               // case 0x5D: // SDS - START DIRECTED STRING
+                                               // case 0x5E: // SIMD - SELECT IMPLICIT MOVEMENT DIRECTION
+                                               // case 0x62: // REP - REPEAT // TODO:???
+                                               // case 0x63: // DA - DEVICE ATTRIBUTES
+                                               case 0x64: // VPA - LINE POSITION ABSOLUTE
+                                                       goto_line((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x67: // TBC - TABULATION CLEAR
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                               clear_htab(hpos_aim);
+                                                               break;
+                                                       case 1:
+                                                               clear_vtab(vpos_aim);
+                                                               break;
+                                                       case 2:
+                                                       case 3:
+                                                               clear_htab_all();
+                                                               break;
+                                                       case 5:
+                                                               clear_htab_all();
+                                                       case 4:
+                                                               clear_vtab_all();
+                                                               break;
+                                                       }
+                                                       break;
+                                               // case 0x68: // SM - SET MODE
+                                               // case 0x69: // MC - MEDIA COPY
+                                               // case 0x6C: // RM - RESET MODE
+                                               case 0x6D: // SGR - SELECT GRAPHIC RENDITION
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                       case 65:
+                                                               set_style_normal();
+                                                               break;
+                                                       case 1:
+                                                               set_style_bold();
+                                                               break;
+                                                       case 4:
+                                                               set_style_under();
+                                                               break;
+                                                       case 9:
+                                                               set_style_cross();
+                                                               break;
+                                                       case 21:
+                                                               set_style_under2();
+                                                               break;
+                                                       case 22:
+                                                               set_style_nobold();
+                                                               break;
+                                                       case 24:
+                                                               set_style_nounder();
+                                                               break;
+                                                       case 29:
+                                                               set_style_nocross();
+                                                               break;
+                                                       case 53:
+                                                               set_style_over();
+                                                               break;
+                                                       case 55:
+                                                               set_style_noover();
+                                                               break;
+                                                       }
+                                                       break;
+                                               case 0x6E: // DSR - DEVICE STATUS REPORT
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       //case 0:
+                                                       //case 1:
+                                                       //case 2:
+                                                       //case 3:
+                                                       //case 4:
+                                                       case 5:
+                                                               //TODO: send DSR here
+                                                               break;
+                                                       case 6:
+                                                        //TODO: send CPR here
+                                                        break;
+                                                       }
+                                                       break;
+                                               // case 0x6F: // DAQ - DEFINE AREA QUALIFICATION
+                                               
+                                               // case 0x2040: // SL - SCROLL LEFT
+                                               // case 0x2041: // SR - SCROLL RIGHT
+                                               // case 0x2043: // GSS - GRAPHIC SIZE SELECTION
+                                                       // set_lheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       // // width is implicit, but I don't change it here
+                                                       // break;
+                                               // case 0x2044: // FNT - FONT SELECTION
+                                               // case 0x2045: // TSS - THIN SPACE SPECIFICATION
+                                               // case 0x2046: // JFY - JUSTIFY
+                                               case 0x2047: // SPI - SPACING INCREMENT
+                                                       set_lheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       set_cwidth(HUNIT(get_ctrl_parameter(CTRL_IND, 1, 0, 0)));
+                                                       break;
+                                               // case 0x2048: // QUAD - QUAD
+                                               case 0x2049: // SSU - SELECT SIZE UNIT
+                                                       switch ((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0: // CHARACTER
+                                                               hunit_mul = HUNIT_MUL_CH;
+                                                               hunit_div = HUNIT_DIV_CH;
+                                                               vunit_mul = VUNIT_MUL_CH;
+                                                               vunit_div = VUNIT_DIV_CH;
+                                                               break;
+                                                       case 1: // MILLIMETRE
+                                                               hunit_mul = HUNIT_MUL_MM;
+                                                               hunit_div = HUNIT_DIV_MM;
+                                                               vunit_mul = VUNIT_MUL_MM;
+                                                               vunit_div = VUNIT_DIV_MM;
+                                                               break;
+                                                       case 2: // COMPUTER DECIPOINT
+                                                               hunit_mul = HUNIT_MUL_CDP;
+                                                               hunit_div = HUNIT_DIV_CDP;
+                                                               vunit_mul = VUNIT_MUL_CDP;
+                                                               vunit_div = VUNIT_DIV_CDP;
+                                                               break;
+                                                       case 3: // DECIDIDOT
+                                                               hunit_mul = HUNIT_MUL_DD;
+                                                               hunit_div = HUNIT_DIV_DD;
+                                                               vunit_mul = VUNIT_MUL_DD;
+                                                               vunit_div = VUNIT_DIV_DD;
+                                                               break;
+                                                       case 4: // MIL
+                                                               hunit_mul = HUNIT_MUL_MIL;
+                                                               hunit_div = HUNIT_DIV_MIL;
+                                                               vunit_mul = VUNIT_MUL_MIL;
+                                                               vunit_div = VUNIT_DIV_MIL;
+                                                               break;
+                                                       case 5: // BASIC MEASURING UNIT
+                                                               hunit_mul = HUNIT_MUL_BMU;
+                                                               hunit_div = HUNIT_DIV_BMU;
+                                                               vunit_mul = VUNIT_MUL_BMU;
+                                                               vunit_div = VUNIT_DIV_BMU;
+                                                               break;
+                                                       case 6: // MICROMETRE
+                                                               hunit_mul = HUNIT_MUL_UM;
+                                                               hunit_div = HUNIT_DIV_UM;
+                                                               vunit_mul = VUNIT_MUL_UM;
+                                                               vunit_div = VUNIT_DIV_UM;
+                                                               break;
+                                                       case 7: // PIXEL
+                                                               hunit_mul = 1;
+                                                               hunit_div = 1;
+                                                               vunit_mul = 1;
+                                                               vunit_div = 1;
+                                                               break;
+                                                       case 8: // DECIPOINT
+                                                               hunit_mul = HUNIT_MUL_DP;
+                                                               hunit_div = HUNIT_DIV_DP;
+                                                               vunit_mul = VUNIT_MUL_DP;
+                                                               vunit_div = VUNIT_DIV_DP;
+                                                               break;
+                                                       }
+                                                       break;
+                                               case 0x204A: // PFS - PAGE FORMAT SELECTION
+                                                       u0 = (uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0);
+                                                       if (u0 < N_PF)
+                                                       {
+                                                               set_pheight(PHEIGHT_PRESET[u0]);
+                                                               set_tmargin(0);
+                                                               set_bmargin_rel(0);
+                                                               set_theight_ch(theight_ch);
+                                                               set_lwidth(LWIDTH_PRESET[u0]);
+                                                               set_lmargin(LMARGIN_PRESET);
+                                                               set_rmargin_rel(0-RMARGIN_PRESET);
+                                                               set_twidth_ch(twidth_ch);
+                                                               adjust_print_pos();
+                                                               // TODO: new page?
+                                                       }
+                                                       break;
+                                               case 0x204B: // SHS - SELECT CHARACTER SPACING
+                                                       u0 = (uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0);
+                                                       if (u0 < N_CWIDTH)
+                                                               set_cwidth(CWIDTH_PRESET[u0]);
+                                                       break;
+                                               case 0x204C: // SVS - SELECT LINE SPACING
+                                                       u0 = (uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0);
+                                                       if (u0 < N_LHEIGHT)
+                                                               set_lheight(LHEIGHT_PRESET[u0]);
+                                                       break;
+                                               // case 0x204D: // IGS - IDENTIFY GRAPHIC SUBREPERTOIRE
+                                               // case 0x204F: // IDCS - IDENTIFY DEVICE CONTROL STRING
+                                               case 0x2050: // PPA - PAGE POSITION ABSOLUTE
+                                                       goto_page((int16_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x2051: // PPR - PAGE POSITION FORWARD
+                                                       move_forward_page((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               case 0x2052: // PPB - PAGE POSITION BACKWARD
+                                                       move_back_page((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               // case 0x2053: // SPD - SELECT PRESENTATION DIRECTIONS
+                                               case 0x2054: // DTA - DIMENSION TEXT AREA
+                                                       set_pheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       set_lwidth(HUNIT(get_ctrl_parameter(CTRL_IND, 1, 0, 0)));
+                                                       adjust_print_pos();
+                                                       // TODO: set new margins?
+                                                       break;
+                                               case 0x2055: // SLH - SET LINE HOME
+                                                       set_lmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x2056: // SLL - SET LINE LIMIT
+                                                       set_rmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1));
+                                                       break;
+                                               // case 0x2057: // FNK - FUNCTION KEY
+                                               // case 0x2058: // SPQR - SELECT PRINT QUALITY AND RAPIDITY
+                                               case 0x2059: // SEF - SHEET EJECT AND FEED
+                                                       // partial implementation: move out of page
+                                                       goto_next_page_tmargin();
+                                                       break;
+                                               case 0x205A: // PEC - PRESENTATION EXPAND OR CONTRACT
+                                                       switch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0))
+                                                       {
+                                                       case 0:
+                                                               set_cwidth(WIDTH_NORMAL);
+                                                               break;
+                                                       case 1:
+                                                               set_cwidth(WIDTH_WIDE);
+                                                               break;
+                                                       case 2:
+                                                               set_cwidth(WIDTH_NARROW);
+                                                               break;
+                                                       }
+                                                       break;
+                                               // case 0x205B: // SSW - SET SPACE WIDTH
+                                               // case 0x205C: // SACS - SET ADDITIONAL CHARACTER SEPARATION
+                                               // case 0x205D: // SAPV - SELECT ALTERNATIVE PRESENTATION VARIANTS
+                                               case 0x205E: // STAB - SELECTIVE TABULATION
+                                                       // arbitrary choice
+                                                       goto_htab((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1), 1);
+                                                       break;
+                                               // case 0x205F: // GCC - GRAPHIC CHARACTER COMBINATION
+                                               // case 0x2060: // TATE - TABULATION ALIGNED TRAILING EDGE
+                                               // case 0x2061: // TALE - TABULATION ALIGNED LEADING EDGE
+                                               // case 0x2062: // TAC - TABULATION ALIGNED CENTRED
+                                               // case 0x2063: // TAC - TABULATION ALIGNED CENTRED
+                                               case 0x2064: // TSR - TABULATION STOP REMOVE
+                                                       clear_htab_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               // case 0x2065: // SCO - SELECT CHARACTER ORIENTATION
+                                               // case 0x2066: // SRCS - SET REDUCED CHARACTER SEPARATION
+                                               case 0x2067: // SCS - SET CHARACTER SPACING
+                                                       set_cwidth(HUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       break;
+                                               case 0x2068: // SLS - SET LINE SPACING
+                                                       set_lheight(VUNIT(get_ctrl_parameter(CTRL_IND, 0, 0, 0)));
+                                                       break;
+                                               case 0x2069: // SPH - SET PAGE HOME
+                                                       set_tmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 1)-1);
+                                                       break;
+                                               case 0x206A: // SPL - SET PAGE LIMIT
+                                                       set_bmargin_ch((uint8_t)get_ctrl_parameter(CTRL_IND, 0, 0, 0));
+                                                       break;
+                                               // case 0x206B: // SCP - SELECT CHARACTER PATH
+                                               }
+                                               ind = 0;
+                                       }
+                                       else // invalid value
+                                       {
+                                               ind = 0;
+                                               hanled = 0;
+                                       }
+                                       break;
+                               case 0x90: // 1B 50  DCS - DEVICE CONTROL STRING
+                               case 0x98: // 1B 58  SOS - START OF STRING
+                               case 0x9A: // 1B 5A  SCI - SINGLE CHARACTER INTRODUCER
+                               case 0x9D: // 1B 5D  OSC - OPERATING SYSTEM COMMAND
+                               case 0x9E: // 1B 5E  PM  - PRIVACY MESSAGE
+                               case 0x9F: // 1B 5F  APC - APPLICATION PROGRAM COMMAND
+                                       if (in == 0x9C) // 1B 5C  ST - STRING TERMINATOR
+                                       {
+                                               /* control string would be handled here if implemented */
+                                               ind = 0;
+                                       }
+                                       else if (ind < N_ESC_BUFFER-1)
+                                               ++ind;
+                                       break;
+                               default:
+                                       // how did we get here?
+                                       ind = 0;
+                                       handled = 0;
+                               }
+                       }
+               }
+               else
+               {
+                       ind = 0;
+                       handled = 0;
+               }
+       }
+       prev = in;
+       return handled;
+}
+
+uint32_t get_ctrl_parameter (
+       uint8_t * buffer,
+       uint8_t * * pos,
+       uint8_t * ind,
+       uint8_t * subind,
+       uint8_t id,
+       uint8_t subid,
+       uint32_t def
+)
+{
+       uint32_t val = 0;
+       uint8_t ch;
+       uint8_t return_now = 0;
+       uint8_t return_default = 1;
+       
+       // add_outcome_str("get_ctrl_parameter()\r\n");
+       // add_outcome_str("buffer == ");
+       // add_outcome_hex((uint16_t)buffer, 4);
+       // add_outcome_str("\r\n");
+       // add_outcome_str("*buffer == ");
+       // add_outcome_hex(*buffer, 2);
+       // if ((*buffer >= 20) && (*buffer <= 0x7E))
+       // {
+               // add_outcome_str(" /* ");
+               // add_outcome(*buffer);
+               // add_outcome_str(" */ ");
+       // }
+       // add_outcome_str("\r\n");
+       // add_outcome_str("*pos == ");
+       // add_outcome_hex((uint16_t)(*pos), 4);
+       // add_outcome_str("\r\n");
+       // add_outcome_str("**pos == ");
+       // add_outcome_hex(**pos, 2);
+       // if ((**pos >= 20) && (**pos <= 0x7E))
+       // {
+               // add_outcome_str(" /* ");
+               // add_outcome(**pos);
+               // add_outcome_str(" */ ");
+       // }
+       // add_outcome_str("\r\n");
+       // add_outcome_str("*ind == ");
+       // add_outcome_dec(*ind, 1);
+       // add_outcome_str("\r\n");
+       // add_outcome_str("*subind == ");
+       // add_outcome_dec(*ind, 1);
+       // add_outcome_str("\r\n");
+       // add_outcome_str("id == ");
+       // add_outcome_dec(id, 1);
+       // add_outcome_str("\r\n");
+       // add_outcome_str("subid == ");
+       // add_outcome_dec(subid, 1);
+       // add_outcome_str("\r\n");
+       // add_outcome_str("def == ");
+       // add_outcome_dec(def, 1);
+       // add_outcome_str("\r\n");
+       
+       // too far, move to start.
+       if ((id < *ind) || ((id == *ind) && (subid < *subind)))
+       {
+               *pos = buffer;
+               *ind = 0;
+               *subind = 0;
+               // add_outcome_str("// too far, move to start.\r\n");
+               // add_outcome_str("*pos == ");
+               // add_outcome_hex((uint16_t)(*pos), 8);
+               // add_outcome_str("\r\n");
+               // add_outcome_str("**pos == ");
+               // add_outcome_hex(**pos, 2);
+               // if ((**pos >= 20) && (**pos <= 0x7E))
+               // {
+                       // add_outcome_str(" /* ");
+                       // add_outcome(**pos);
+                       // add_outcome_str(" */ ");
+               // }
+               // add_outcome_str("\r\n");
+               // add_outcome_str("*ind == ");
+               // add_outcome_dec(*ind, 1);
+               // add_outcome_str("\r\n");
+               // add_outcome_str("*subind == ");
+               // add_outcome_dec(*subind, 1);
+               // add_outcome_str("\r\n");
+       }
+       
+       if (*pos == buffer) // at start
+       {
+               // add_outcome_str("// at start\r\n");
+               if ((*buffer < 0x30) || (*buffer > 0x3B)) // not a parameter string
+               {
+                       // add_outcome_str("// not a parameter string\r\n");
+                       // add_outcome_str("return ");
+                       // add_outcome_dec(def, 1);
+                       // add_outcome_str("\r\n");
+                       return def;
+               }
+       }
+       
+       while (1)
+       {
+               ch = **pos;
+               // add_outcome_str("ch == ");
+               // add_outcome_hex(ch, 2);
+               // if ((ch >= 20) && (ch <= 0x7E))
+               // {
+                       // add_outcome_str(" /* ");
+                       // add_outcome(ch);
+                       // add_outcome_str(" */ ");
+               // }
+               // add_outcome_str("\r\n");
+               switch (ch)
+               {
+               case 0x30: // digit
+               case 0x31:
+               case 0x32:
+               case 0x33:
+               case 0x34:
+               case 0x35:
+               case 0x36:
+               case 0x37:
+               case 0x38:
+               case 0x39:
+                       // add_outcome_str("// digit\r\n");
+                       if ((*ind == id) && (*subind == subid))
+                       {
+                               return_default = 0;
+                               val *= 10;
+                               val += ch - 0x30;
+                               // add_outcome_str("return_default = 0//\r\n");
+                               // add_outcome_str("val == ");
+                               // add_outcome_dec(val, 1);
+                               // add_outcome_str("\r\n");
+                       }
+                       ++(*pos);
+                       // add_outcome_str("*pos == ");
+                       // add_outcome_hex((uint16_t)(*pos), 8);
+                       // add_outcome_str("\r\n");
+                       // add_outcome_str("**pos == ");
+                       // add_outcome_hex(**pos, 2);
+                       // if ((**pos >= 20) && (**pos <= 0x7E))
+                       // {
+                               // add_outcome_str(" /* ");
+                               // add_outcome(**pos);
+                               // add_outcome_str(" */ ");
+                       // }
+                       // add_outcome_str("\r\n");
+                       break;
+               case 0x3A: // : substring separator
+                       // add_outcome_str("// : substring separator\r\n");
+                       if ((*ind == id) && (*subind == subid))
+                       {
+                               return_now = 1;
+                               // add_outcome_str("return_now = 1//\r\n");
+                       }
+                       ++(*subind);
+                       ++(*pos);
+                       // add_outcome_str("*subind == ");
+                       // add_outcome_dec(*subind, 1);
+                       // add_outcome_str("\r\n");
+                       // add_outcome_str("*pos == ");
+                       // add_outcome_hex((uint16_t)(*pos), 8);
+                       // add_outcome_str("\r\n");
+                       // add_outcome_str("**pos == ");
+                       // add_outcome_hex(**pos, 2);
+                       // if ((**pos >= 20) && (**pos <= 0x7E))
+                       // {
+                               // add_outcome_str(" /* ");
+                               // add_outcome(**pos);
+                               // add_outcome_str(" */ ");
+                       // }
+                       // add_outcome_str("\r\n");
+                       break;
+               case 0x3B: // ; string separator
+                       // add_outcome_str("// ; string separator\r\n");
+                       if ((*ind == id) && (*subind == subid))
+                       {
+                               return_now = 1;
+                               // add_outcome_str("return_now = 1//\r\n");
+                       }
+                       ++(*ind);
+                       *subind = 0;
+                       ++(*pos);
+                       // add_outcome_str("*ind == ");
+                       // add_outcome_dec(*ind, 1);
+                       // add_outcome_str("\r\n");
+                       // add_outcome_str("*subind == ");
+                       // add_outcome_dec(*subind, 1);
+                       // add_outcome_str("\r\n");
+                       // add_outcome_str("*pos == ");
+                       // add_outcome_hex((uint16_t)(*pos), 8);
+                       // add_outcome_str("\r\n");
+                       // add_outcome_str("**pos == ");
+                       // add_outcome_hex(**pos, 2);
+                       // if ((**pos >= 20) && (**pos <= 0x7E))
+                       // {
+                               // add_outcome_str(" /* ");
+                               // add_outcome(**pos);
+                               // add_outcome_str(" */ ");
+                       // }
+                       // add_outcome_str("\r\n");
+                       break;
+               default: // end of parameter strings
+                       // add_outcome_str("// end of parameter strings\r\n");
+                       // add_outcome_str("return_now = 1//\r\n");
+                       return_now = 1;
+               }
+               
+               if (return_now)
+               {
+                       // add_outcome_str("return ");
+                       // add_outcome_dec(return_default ? def : val, 1);
+                       // add_outcome_str("\r\n");
+                       return return_default ? def : val;
+               }
+       }
+}
+
+uint8_t handle_menu (const uint8_t key)
+{
+       static uint8_t menu_active = 0;
+       static uint8_t function = MENU_NONE;
+       static uint8_t allow_output = 0;
+       static uint16_t value=0;
+       uint8_t x;
+       
+       if (!menu_active)
+       {
+               if (key == MENU_ENTER)
+               {
+                       menu_active = 1;
+                       function = MENU_NONE;
+                       allow_output = 0;
+                       set_alarm = 1;
+               }
+       }
+       else if (function == MENU_NONE)
+       {
+               function = key;
+               value = 0;
+               switch (key)
+               {
+               case MENU_ENTER:
+               case MENU_OUTPUT:
+                       function = MENU_NONE;
+                       allow_output = 1;
+                       add_income_str(TEXT_MENU_LIST, 1);
+                       set_alarm = 1;
+                       break;
+               case MENU_EXIT:
+               case MENU_CONFIRM:
+                       menu_active = 0;
+                       if (allow_output) add_income_str(TEXT_MENU_EXIT, 1);
+                       set_alarm = 3;
+                       break;
+               case MENU_BAUD:
+                       if (allow_output) add_income_str(TEXT_MENU_BAUD, 1);
+                       break;
+               case MENU_BITS:
+                       if (allow_output) add_income_str(TEXT_MENU_BITS, 1);
+                       break;
+               case MENU_FLOW:
+                       if (allow_output) add_income_str(TEXT_MENU_FLOW, 1);
+                       break;
+               case MENU_ECHO:
+                       if (allow_output) add_income_str(TEXT_MENU_ECHO, 1);
+                       break;
+               case MENU_DELETE:
+                       if (allow_output) add_income_str(TEXT_MENU_DELETE, 1);
+                       break;
+               case MENU_NEWLINE:
+                       if (allow_output) add_income_str(TEXT_MENU_NEWLINE, 1);
+                       break;
+               case MENU_REPLACE:
+                       if (allow_output) add_income_str(TEXT_MENU_REPLACE, 1);
+                       break;
+               case MENU_ENCODING:
+                       if (allow_output) add_income_str(TEXT_MENU_ENCODING, 1);
+                       break;
+               case MENU_PWIDTH:
+                       if (allow_output) add_income_str(TEXT_MENU_PWIDTH, 1);
+                       break;
+               case MENU_LMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_LMARGIN, 1);
+                       break;
+               case MENU_RMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_RMARGIN, 1);
+                       break;
+               case MENU_TWIDTH:
+                       if (allow_output) add_income_str(TEXT_MENU_TWIDTH, 1);
+                       break;
+               case MENU_PHEIGHT:
+                       if (allow_output) add_income_str(TEXT_MENU_PHEIGHT, 1);
+                       break;
+               case MENU_TMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_TMARGIN, 1);
+                       break;
+               case MENU_BMARGIN:
+                       if (allow_output) add_income_str(TEXT_MENU_BMARGIN, 1);
+                       break;
+               case MENU_THEIGHT:
+                       if (allow_output) add_income_str(TEXT_MENU_THEIGHT, 1);
+                       break;
+               case MENU_HTAB:
+                       if (allow_output) add_income_str(TEXT_MENU_HTAB, 1);
+                       break;
+               case MENU_VTAB:
+                       if (allow_output) add_income_str(TEXT_MENU_VTAB, 1);
+                       break;
+               case MENU_CWIDTH:
+                       if (allow_output) add_income_str(TEXT_MENU_CWIDTH, 1);
+                       break;
+               case MENU_LHEIGHT:
+                       if (allow_output) add_income_str(TEXT_MENU_LHEIGHT, 1);
+                       break;
+               case MENU_PAPER:
+                       if (allow_output) add_income_str(TEXT_MENU_PAPER, 1);
+                       break;
+               default:
+                       function = MENU_NONE;
+               }
+               if (function != MENU_NONE)
+                       set_alarm = 2;
+       }
+       else
+       {
+               switch(key)
+               {
+               case KEY_0:
+               case KEY_1:
+               case KEY_2:
+               case KEY_3:
+               case KEY_4:
+               case KEY_5:
+               case KEY_6:
+               case KEY_7:
+               case KEY_8:
+               case KEY_9:
+                       x=KEYMAP_LIST[0][key];
+                       if(allow_output)
+                               add_income(x, 1);
+                       value *= 10;
+                       value += x-'0';
+                       set_alarm = 1;
+                       break;
+               case MENU_EXIT:
+                       function = MENU_NONE;
+                       if(allow_output)
+                               add_income_str(TEXT_MENU_CANCEL, 1);
+                       set_alarm = 2;
+                       break;
+               case MENU_ENTER:
+               case MENU_OUTPUT:
+                       function = MENU_NONE;
+                       if(allow_output)
+                               add_income_str(TEXT_MENU_LIST, 1);
+                       set_alarm = 2;
+               case MENU_CONFIRM:
+                       switch (function)
+                       {
+                       case MENU_BAUD:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = UART_BAUD_150;
+                                       break;
+                               case 2:
+                                       value = UART_BAUD_300;
+                                       break;
+                               case 3:
+                                       value = UART_BAUD_600;
+                                       break;
+                               case 4:
+                                       value = UART_BAUD_1200;
+                                       break;
+                               case 5:
+                                       value = UART_BAUD_2400;
+                                       break;
+                               case 6:
+                                       value = UART_BAUD_4800;
+                                       break;
+                               case 7:
+                                       value = UART_BAUD_9600;
+                                       break;
+                               case 8:
+                                       value = UART_BAUD_19200;
+                                       break;
+                               case 9:
+                                       value = UART_BAUD_38400;
+                                       break;
+                               case 0:
+                                       value = UART_BAUD_115200;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_baudrate(value);
+                                       store_single_config(ID_BAUD);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_BITS:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = UART_8N1;
+                                       break;
+                               case 2:
+                                       value = UART_8E1;
+                                       break;
+                               case 3:
+                                       value = UART_8O1;
+                                       break;
+                               case 4:
+                                       value = UART_8N2;
+                                       break;
+                               case 5:
+                                       value = UART_8E2;
+                                       break;
+                               case 6:
+                                       value = UART_8O2;
+                                       break;
+                               case 7:
+                                       value = UART_7N1;
+                                       break;
+                               case 8:
+                                       value = UART_7E1;
+                                       break;
+                               case 9:
+                                       value = UART_7O1;
+                                       break;
+                               case 10:
+                                       value = UART_7N2;
+                                       break;
+                               case 11:
+                                       value = UART_7E2;
+                                       break;
+                               case 12:
+                                       value = UART_7O2;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_serial_mode(value);
+                                       store_single_config(ID_BITS);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_FLOW:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = (flow & ~FLOW_HW) | FLOW_FD;
+                                       break;
+                               case 2:
+                                       value = (flow & ~FLOW_HW) | FLOW_HD_DTE;
+                                       break;
+                               case 3:
+                                       value = (flow & ~FLOW_HW) | FLOW_HD_DCE;
+                                       break;
+                               case 4:
+                                       value = (flow & ~FLOW_HW) | FLOW_NONE;
+                                       break;
+                               case 5:
+                                       value = (flow & ~FLOW_SW) | FLOW_XONOFF;
+                                       break;
+                               case 6:
+                                       value = (flow & ~FLOW_SW) | FLOW_NONE;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_flowcontrol(value);
+                                       store_single_config(ID_FLOW);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_ECHO:
+                               switch (value)
+                               {
+                               case 1:
+                                       mode |= MODE_ECHO;
+                                       break;
+                               case 2:
+                                       mode &= ~MODE_ECHO;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_MODE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_NEWLINE:
+                               switch (value)
+                               {
+                               case 1:
+                                       nl_mode = (nl_mode & ~NL_IMPLICIT_CR) | NL_IMPLICIT_LF;
+                                       break;
+                               case 2:
+                                       nl_mode = (nl_mode & ~NL_IMPLICIT_LF) | NL_IMPLICIT_CR;
+                                       break;
+                               case 3:
+                                       nl_mode |= NL_CATCH_ALL;
+                                       break;
+                               case 4:
+                                       nl_mode &= ~NL_CATCH_ALL;
+                                       break;
+                               case 5:
+                                       nl_mode = (nl_mode & ~NL_SEND_LF) | NL_SEND_CR;
+                                       break;
+                               case 6:
+                                       nl_mode = (nl_mode & ~NL_SEND_CR) | NL_SEND_LF;
+                                       break;
+                               case 7:
+                                       nl_mode |= NL_SEND_CRLF;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_MODE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_DELETE:
+                               switch (value)
+                               {
+                               case 1:
+                                       bs_mode |= BS_BS;
+                                       break;
+                               case 2:
+                                       bs_mode &= ~BS_BS;
+                                       break;
+                               case 3:
+                                       bs_mode |= BS_DEL;
+                                       break;
+                               case 4:
+                                       bs_mode &= ~BS_DEL;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_BS_MODE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_REPLACE:
+                               switch (value)
+                               {
+                               case 1:
+                                       replace = REPLACE_SYMBOL;
+                                       break;
+                               case 2:
+                                       replace = REPLACE_QUEST;
+                                       break;
+                               case 3:
+                                       replace = REPLACE_UNDER;
+                                       break;
+                               case 4:
+                                       replace = REPLACE_SPACE;
+                                       break;
+                               case 5:
+                                       replace = REPLACE_IGNORE;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       store_single_config(ID_REPLACE);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_ENCODING:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = ENC_ISO8859_1;
+                                       break;
+                               case 2:
+                                       value = ENC_ISO8859_2;
+                                       break;
+                               // case 3:
+                                       // value = ENC_ISO8859_3;
+                                       // break;
+                               // case 4:
+                                       // value = ENC_ISO8859_4;
+                                       // break;
+                               // case 9:
+                                       // value = ENC_ISO8859_9;
+                                       // break;
+                               // case 10:
+                                       // value = ENC_ISO8859_10;
+                                       // break;
+                               // case 13:
+                                       // value = ENC_ISO8859_13;
+                                       // break;
+                               // case 15:
+                                       // value = ENC_ISO8859_15;
+                                       // break;
+                               // case 16:
+                                       // value = ENC_ISO8859_16;
+                                       // break;
+                               case 1250:
+                                       value = ENC_CP1250;
+                                       break;
+                               case 852:
+                                       value = ENC_CP852;
+                                       break;
+                               case 8:
+                                       value = encoding | ENC_UNI;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                                       break;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_encoding(value);
+                                       store_single_config(ID_ENCODING);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_PWIDTH:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= cwidth_aim;
+                                       if (value > HPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_lwidth(value);
+                                               store_single_config(ID_LWIDTH);
+                                               store_single_config(ID_LMARGIN);
+                                               store_single_config(ID_RMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_LMARGIN:
+                               value *= cwidth_aim;
+                               if (value > (HPOS_LIMIT - cwidth_aim))
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_lmargin(value);
+                                       store_single_config(ID_LWIDTH);
+                                       store_single_config(ID_LMARGIN);
+                                       store_single_config(ID_RMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_RMARGIN:
+                               value *= cwidth_aim;
+                               if (value > (lwidth - cwidth_aim))
+                                       value = 0xffff;
+                               else
+                               {
+                                       value = lwidth - value;
+                                       set_rmargin(value);
+                                       store_single_config(ID_LWIDTH);
+                                       store_single_config(ID_LMARGIN);
+                                       store_single_config(ID_RMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_TWIDTH:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= cwidth_aim;
+                                       value += lmargin_aim;
+                                       if (value > HPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_rmargin(value);
+                                               store_single_config(ID_LWIDTH);
+                                               store_single_config(ID_LMARGIN);
+                                               store_single_config(ID_RMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_PHEIGHT:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= lheight;
+                                       if (value > VPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_pheight(value);
+                                               store_single_config(ID_PHEIGHT);
+                                               store_single_config(ID_TMARGIN);
+                                               store_single_config(ID_BMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_TMARGIN:
+                               value *= lheight;
+                               if (value > (VPOS_LIMIT - lheight))
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_tmargin(value);
+                                       store_single_config(ID_PHEIGHT);
+                                       store_single_config(ID_TMARGIN);
+                                       store_single_config(ID_BMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_BMARGIN:
+                               value *= lheight;
+                               if (value > (pheight - lheight))
+                                       value = 0xffff;
+                               else
+                               {
+                                       value = pheight - value;
+                                       set_bmargin(value);
+                                       store_single_config(ID_PHEIGHT);
+                                       store_single_config(ID_TMARGIN);
+                                       store_single_config(ID_BMARGIN);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_THEIGHT:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       value *= lheight;
+                                       value += tmargin;
+                                       if (value > VPOS_LIMIT)
+                                               value = 0xffff;
+                                       else
+                                       {
+                                               set_bmargin(value);
+                                               store_single_config(ID_PHEIGHT);
+                                               store_single_config(ID_TMARGIN);
+                                               store_single_config(ID_BMARGIN);
+                                               value = 0;
+                                       }
+                               }
+                               break;
+                       case MENU_HTAB:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_twidth_ch(value);
+                                       store_single_config(ID_HTAB);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_VTAB:
+                               if (value == 0)
+                                       value = 0xffff;
+                               else
+                               {
+                                       set_theight_ch(value);
+                                       store_single_config(ID_VTAB);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_CWIDTH:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = WIDTH_15;
+                                       break;
+                               case 2:
+                                       value = WIDTH_12;
+                                       break;
+                               case 3:
+                                       value = WIDTH_10;
+                                       break;
+                               case 4:
+                                       value = WIDTH_6;
+                                       break;
+                               case 5:
+                                       value = WIDTH_4;
+                                       break;
+                               case 6:
+                                       value = WIDTH_3;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_cwidth(value);
+                                       store_single_config(ID_CWIDTH);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_LHEIGHT:
+                               switch (value)
+                               {
+                               case 1:
+                                       value = HEIGHT_6;
+                                       break;
+                               case 2:
+                                       value = HEIGHT_4;
+                                       break;
+                               case 3:
+                                       value = HEIGHT_3;
+                                       break;
+                               case 4:
+                                       value = HEIGHT_2;
+                                       break;
+                               default:
+                                       value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       set_lheight(value);
+                                       store_single_config(ID_CWIDTH);
+                                       value = 0;
+                               }
+                               break;
+                       case MENU_PAPER:
+                               switch (value)
+                               {
+                                       case 1:
+                                               value = PAPER_CONTINUOUS;
+                                               break;
+                                       case 2:
+                                               value = PAPER_SINGLE;
+                                               break;
+                                       default:
+                                               value = 0xffff;
+                               }
+                               if (value != 0xffff)
+                               {
+                                       paper = value;
+                                       store_single_config(ID_PAPER);
+                                       value = 0;
+                               }
+                               break;
+                       default:
+                               value = 1;
+                       }
+                       function = MENU_NONE;
+                       if (!value)
+                       {
+                               if(allow_output)
+                                       add_income_str(TEXT_MENU_OK, 1);
+                               set_alarm = 2;
+                       }
+                       else
+                       {
+                               if(allow_output)
+                                       add_income_str(TEXT_MENU_FAIL, 1);
+                               set_alarm = 5;
+                       }
+                       break;
+               }
+       }
+       
+       
+       
+       return menu_active;
+}
+
diff --git a/uni.py b/uni.py
new file mode 100755 (executable)
index 0000000..6e2b239
--- /dev/null
+++ b/uni.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python3
+
+N = 0x0300
+
+def single_line(n):
+    line = '%04X|' % n
+    if (n != 0x00) and (n != 0x80):
+        for i in range (n, min(N, n + 0x20)):
+            line += chr(i) + ' '
+    print (line)
+
+print ('    |                                1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ')
+print ('    |0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F ')
+print ('----+----------------------------------------------------------------')
+for i in range (0x00, N, 0x20):
+    single_line(i)
+
diff --git a/uni.txt b/uni.txt
new file mode 100644 (file)
index 0000000..903886f
--- /dev/null
+++ b/uni.txt
@@ -0,0 +1,27 @@
+    |                                1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
+    |0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F 
+----+----------------------------------------------------------------
+0000|
+0020|  ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 
+0040|@ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ 
+0060|` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ \7f 
+0080|
+00A0|  ¡ ¢ £ ¤ ¥ ¦ § ¨ © ª « ¬ ­ ® ¯ ° ± ² ³ ´ µ ¶ · ¸ ¹ º » ¼ ½ ¾ ¿ 
+00C0|À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß 
+00E0|à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ 
+0100|Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď Đ đ Ē ē Ĕ ĕ Ė ė Ę ę Ě ě Ĝ ĝ Ğ ğ 
+0120|Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĩ ĩ Ī ī Ĭ ĭ Į į İ ı IJ ij Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ 
+0140|ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ō ō Ŏ ŏ Ő ő Œ œ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş ş 
+0160|Š š Ţ ţ Ť ť Ŧ ŧ Ũ ũ Ū ū Ŭ ŭ Ů ů Ű ű Ų ų Ŵ ŵ Ŷ ŷ Ÿ Ź ź Ż ż Ž ž ſ 
+0180|ƀ Ɓ Ƃ ƃ Ƅ ƅ Ɔ Ƈ ƈ Ɖ Ɗ Ƌ ƌ ƍ Ǝ Ə Ɛ Ƒ ƒ Ɠ Ɣ ƕ Ɩ Ɨ Ƙ ƙ ƚ ƛ Ɯ Ɲ ƞ Ɵ 
+01A0|Ơ ơ Ƣ ƣ Ƥ ƥ Ʀ Ƨ ƨ Ʃ ƪ ƫ Ƭ ƭ Ʈ Ư ư Ʊ Ʋ Ƴ ƴ Ƶ ƶ Ʒ Ƹ ƹ ƺ ƻ Ƽ ƽ ƾ ƿ 
+01C0|ǀ ǁ ǂ ǃ DŽ Dž dž LJ Lj lj NJ Nj nj Ǎ ǎ Ǐ ǐ Ǒ ǒ Ǔ ǔ Ǖ ǖ Ǘ ǘ Ǚ ǚ Ǜ ǜ ǝ Ǟ ǟ 
+01E0|Ǡ ǡ Ǣ ǣ Ǥ ǥ Ǧ ǧ Ǩ ǩ Ǫ ǫ Ǭ ǭ Ǯ ǯ ǰ DZ Dz dz Ǵ ǵ Ƕ Ƿ Ǹ ǹ Ǻ ǻ Ǽ ǽ Ǿ ǿ 
+0200|Ȁ ȁ Ȃ ȃ Ȅ ȅ Ȇ ȇ Ȉ ȉ Ȋ ȋ Ȍ ȍ Ȏ ȏ Ȑ ȑ Ȓ ȓ Ȕ ȕ Ȗ ȗ Ș ș Ț ț Ȝ ȝ Ȟ ȟ 
+0220|Ƞ ȡ Ȣ ȣ Ȥ ȥ Ȧ ȧ Ȩ ȩ Ȫ ȫ Ȭ ȭ Ȯ ȯ Ȱ ȱ Ȳ ȳ ȴ ȵ ȶ ȷ ȸ ȹ Ⱥ Ȼ ȼ Ƚ Ⱦ ȿ 
+0240|ɀ Ɂ ɂ Ƀ Ʉ Ʌ Ɇ ɇ Ɉ ɉ Ɋ ɋ Ɍ ɍ Ɏ ɏ ɐ ɑ ɒ ɓ ɔ ɕ ɖ ɗ ɘ ə ɚ ɛ ɜ ɝ ɞ ɟ 
+0260|ɠ ɡ ɢ ɣ ɤ ɥ ɦ ɧ ɨ ɩ ɪ ɫ ɬ ɭ ɮ ɯ ɰ ɱ ɲ ɳ ɴ ɵ ɶ ɷ ɸ ɹ ɺ ɻ ɼ ɽ ɾ ɿ 
+0280|ʀ ʁ ʂ ʃ ʄ ʅ ʆ ʇ ʈ ʉ ʊ ʋ ʌ ʍ ʎ ʏ ʐ ʑ ʒ ʓ ʔ ʕ ʖ ʗ ʘ ʙ ʚ ʛ ʜ ʝ ʞ ʟ 
+02A0|ʠ ʡ ʢ ʣ ʤ ʥ ʦ ʧ ʨ ʩ ʪ ʫ ʬ ʭ ʮ ʯ ʰ ʱ ʲ ʳ ʴ ʵ ʶ ʷ ʸ ʹ ʺ ʻ ʼ ʽ ʾ ʿ 
+02C0|ˀ ˁ ˂ ˃ ˄ ˅ ˆ ˇ ˈ ˉ ˊ ˋ ˌ ˍ ˎ ˏ ː ˑ ˒ ˓ ˔ ˕ ˖ ˗ ˘ ˙ ˚ ˛ ˜ ˝ ˞ ˟ 
+02E0|ˠ ˡ ˢ ˣ ˤ ˥ ˦ ˧ ˨ ˩ ˪ ˫ ˬ ˭ ˮ ˯ ˰ ˱ ˲ ˳ ˴ ˵ ˶ ˷ ˸ ˹ ˺ ˻ ˼ ˽ ˾ ˿ 
diff --git a/update-template.py b/update-template.py
new file mode 100755 (executable)
index 0000000..803fce0
--- /dev/null
@@ -0,0 +1,110 @@
+#!/usr/bin/python3
+
+import sys
+import re
+
+mode = ''
+encodings = []
+sequences = {}
+ch = 0
+sequence = []
+key = ''
+keyvalue = -1
+keymap = {}
+
+l = len(sys.argv)
+if l >= 2:
+    file_in = sys.argv[1]
+    if l >= 3:
+        file_out = sys.argv[2]
+    else:
+        file_out = file_in
+else:
+    file_in=''
+    file_out=''
+
+
+with (open(file_in, 'rt', encoding='utf-8') if file_in else sys.stdin) as file:
+    for line in file:
+        i = line.find('#')
+        if i >= 0:
+            line = line[0:i]
+        line = line.strip()
+        
+        m = re.search('^([A-Za-z0-9_]+):$', line)
+        if m:
+            if len(sequence) != 0:
+                sequences[ch] = sequence
+                sequence = []
+            if keyvalue >= 0:
+                keymap[key] = keyvalue
+                keyvalue = -1
+            t = m.group(1)
+            if t == 'encoding':
+                mode = 'encoding'
+            elif re.search('^[0-9A-Fa-f]+$', t):
+                mode = 'sequence'
+                ch = int(t, 16)
+                sequence = []
+            elif re.search('^[0-9A-Z_]+$', t):
+                mode = 'key'
+                key = t
+                keyvalue = -1
+            else:
+                mode = ''
+        elif line != '':
+            if mode == 'encoding':
+                encodings.append(line)
+            elif mode == 'sequence':
+                sequence.append(line)
+            elif mode == 'key':
+                if re.search('^([0-9A-Fa-f]){2,4}$', line):
+                    keyvalue = int(line, 16)
+                elif len(line) == 1:
+                    keyvalue = ord(line)
+
+if len(sequence) != 0:
+    sequences[ch] = sequence
+    sequence = []
+
+if keyvalue >= 0:
+    keymap[key] = keyvalue
+    keyvalue = -1
+
+char_list = list(range(0x20, 0x80))
+B = [bytes([i]) for i in range (0x80, 0x100)]
+
+for e in encodings:
+    for b in B:
+        t = b.decode(e, errors='ignore')
+        if t == '':
+            t = ' '
+        c = ord(t)
+        if not (c in char_list):
+            char_list.append(c)
+
+for c in sequences:
+    if not (c in char_list):
+        char_list.append(c)
+char_list = sorted(char_list)
+
+with (open(file_out, 'wt', encoding='utf-8') if file_out else sys.stdout) as file:
+    print('encoding:', file=file)
+    for e in encodings:
+        print('\t' + e, file=file)
+    
+    print('', file=file)
+    
+    for c in char_list:
+        print(('%04X:' % c) + ('' if (0x7f <= c <= 0x9f) else (" # '" + chr(c) + "'")), file=file)
+        if c in sequences:
+            for k in sequences[c]:
+                print('\t' + k, file=file)
+    
+    print('', file=file)
+    
+    for k in keymap:
+        print (k + ':', file=file)
+        c = keymap[k]
+        print (('\t%04X' % c) + ('' if ((0x7f <= c <= 0x9f) or (c < 0x20)) else (" # '" + chr(c) + "'")), file=file)
+