Keyboard Mapping for Linux

KMFLCOMP

The Keyboard Compiler for KMFL

User's Guide

Version 1.0

November 2004

Table of Contents

Overview	1

Installing KMFLCOMP	1

Creating a new keyboard	1

Fundamental keyboard properties	2

Keyboard name	2

Encoding	2

Layout type	2

Icon file	3

Choosing the characters to output	3

Planning the keyboard layout	3

Context or input sequences?	3

Creating the keyboard source text file	4

File name conventions	4

Compiling a keyboard	4

Compiler options	4

Installing and testing the compiled keyboard	5

Installing a keyboard manually	5

Automatic keyboard loading	5

Testing the installed keyboard	5

Programming language reference	5

Overview	5

Language elements	5

Statements	5

String and character constants	6

Keystroke constants	7

Named constants	9

Keywords and keyword expressions	10

Symbolic names	10

Comments	10

Continuation lines	10

The keyboard header	11

Groups of processing rules	12

Rules	12

Simple rules	12

Rules with longer output	13

Rules with context	13

Stores, 'any', and 'index'	14

Deadkeys	15

Keyword reference	15

Keywords used in header statements	16

AUTHOR	16

begin	16

BITMAP	17

CAPS	17

COPYRIGHT	17

ETHNOLOGUECODE	18

HOTKEY	18

LANGUAGE	18

LAYOUT	19

MESSAGE	19

MNEMONIC LAYOUT	19

NAME	19

store	19

VERSION	20

Keywords used in rules	20

any	20

beep	21

context	21

deadkey	21

group	22

index	22

match	23

nomatch	23

nul	24

outs	24

return	24

use	24

Keyword Summary	25

Programming Tips	26

Using Groups	26

Using Stores	27

Sample keyboards	27

Simple French	27

Pig Latin	29

References	33

Appendix: Using KMFL	34

Installing KMFL	34

Using SCIM	35

Uninstalling SCIM	35

Overview

Keyboard mapping, pioneered for Windows by Tavultesoft with Tavultesoft Keyman, makes it possible to use a computer keyboard to input almost any language, by processing the keystrokes that are typed according to a set of rules provided by the keyboard designer, and outputting a sequence of characters that can be quite different from the typed input and may depend on the previously output characters.

The keyboard mapping rules are defined in a text file (the keyboard source file) using a set of keywords and a grammar that is described in this document. KMFL has been strongly influenced by the conventions developed for Tavultesoft Keyman, and the keywords and grammar follow those used by Tavultesoft Keyman. Early versions of Tavultesoft Keyman processed (interpreted) the keyboard source file directly, but later versions use a compiled binary version of the source file, reducing the processing that is required each time the keyboard is used and allowing all syntax checking to be carried out during compilation instead. KMFLCOMP is a Linux application to create the compiled keyboard files used by LIBKMFL (and indirectly by SCIM) from the keyboard source files specifying the rules for keyboard mapping.

In most cases, keyboard source files developed for Tavultesoft Keyman, and compiled with either Keyman 3.2 or with Keyman Developer (Version 5 or later) can be compiled with KMFLCOMP with few modifications. However, it should be remembered that many keyboards developed for use with Keyman and Windows-based applications are associated with the use of non-standard (True-Type) fonts, many of which will not behave the same way when used with Linux.

Like most Linux applications, KMFLCOMP is a command-line (console) application. It checks the syntax of the rules in the keyboard source file named on the command line and outputs any error or warning messages to the console. It also outputs a compiled version of the kyboard file, provided that no errors are detected that would prevent the keyboard from working.

Installing KMFLCOMP

The keyboard compiler may be installed from an rpm package, if one has been developed for the Linux distribution that you are using. Otherwise, it can be built from THE distributed archive file. If installing KMFLCOMP from the archive, it is important to build LIBKMFL first so that the required library files can be found when building KMFLCOMP.

Full instructions for installing LIBKMFL are provided with the separate documentation for KMFL users who do not need to build their own keyboards. To just install KMFLCOMP from the archive, proceed as follows:

Download the KMFLCOMP installation file:

kmflcomp-0.3.tar.gz

Copy the archive into an appropriate folder, e.g. ~/Projects/kmflcomp-0.3 and expand it into that folder:

tar –xzf kmflcomp-0.3

Build and install kmflcomp from the ~/Projects/kmflcomp-0.3 folder as follows:

./configure

make

su as root

make install

Creating a new keyboard

The steps for creating a simple keyboard are:

Define the fundamental keyboard properties

Choose the characters you want to be able to output

Plan the keyboard layout

Create the text source file with the rules for the keyboard

Compile and test the keyboard (see following sections)

Fundamental keyboard properties

The fundamental keyboard properties are keyboard name, encoding, layout type and associated icon file.

Keyboard name

Short, easy to remember names are generally better than long names, and are more easily seen in the list of available names displayed by SCIM. The name does not need to resemble the file name. Keyboard names should always use standard encoding and be able to be displayed with standard fonts.

Encoding

The two encoding conventions that may be used for the keyboard specification are known as Custom/codepage or Unicode. If the fonts you plan to use are encoded to make use of a codepage, and have all the visible characters in the first 256 codepoints, then you can use Custom/codepage encoding (referred to as ANSI in Keyman documentation for historical reasons). Otherwise, you will need to use Unicode encoding and observe the Unicode standard.

Layout type

There are two conceptually different ways of specifying a keyboard mapping, referred to as positional or mnemonic.

With a positional keyboard, keyboard mapping is in accordance with the actual key location on the keyboard, irrespective of the current locale. Positional keyboards are most useful for keyboard mappings that must follow a particular arrangement without regard for the keycap labelling of the keyboard being used, for example, for a non-roman script language where a standard typewriter layout is being implemented. Positional keyboards either refer to the keys by their "virtual key" code (roughly equivalent to Linux keysyms), or else interpret the characters in rules as referring to the keys with those labels on a US standard keyboard.

With a mnemonic keyboard, the key character that is output by the system according to the current locale will then be remapped according to the keyboard specification. Mnemonic keyboards are generally preferred where the input is based on a (latin) phonetic keyboard mapping, so that (for example) pressing "z" will produce the same output, even though the "z" key is in different positions when used on standard English, French or German (physical or system) keyboards. Mnemonic keyboards interpret the characters in rules as referring to keys with those labels on the currently active system-level keyboard.

For versions of Tavultesoft Keyman before Version 4, all keyboards were interpreted as being mnemonic. For Version 5, keyboards were generally interpreted as being positional, so that (for example) keyboards could be created to simulate typewriter layout for an Asian language without regard to the current system keyboard layout. Keyman 6 made the layout type explicit by use of an (optional) header command.

The keyboard type (positional or mnemonic) behaviour is somewhat different for KMFL than for Keyman (on Windows), since the way the locale is defined on Linux is not quite the same as the way the system keyboard and language are defined for Windows. For this reason, any complex Keyman keyboards that are recompiled for KMFL should always be carefully tested before distribution.

Note that keyboards are positional by default and positional keyboards are always based on a US English layout. A positional keyboard that tries to match keystrokes with characters or symbolic keys (except [K_oE2]) that are not present on a US English layout will probably not function correctly.

See Programming Language Reference – Language elements – Keystroke constants for further discussion.

Icon file

If an icon is to be associated with the keyboard (in the list of available keyboards), the icon file name must be specified in the header properties.

Choosing the characters to output

In most cases, you will already have a font with the characters you want to be able to output. Then, before creating keyboard mapping rules, it will be necessary to prepare a table indicating the code to be used for each character. If you are just remapping characters that already appear on the keyboard, then instead of specifying codes, you can specify the output character or strings as text. Otherwise, use the decimal, hexadecimal or Unicode codes for the characters in the font. For Custom/codepage (ANSI) keyboards, each output character code will be a value less than 256, while for Unicode keyboard it will be a 16-bit number, typically specified either as, for example, x1020 or U+1020. If a string must be output, it can be specified by either the separate characters or by the (quoted) string, if some means of entering the string can be found.

Planning the keyboard layout

To plan the keyboard layout, note the key sequence (or key combination) that you want to use by each output character (or string) in the table you have prepared, to create a rule for that mapping relationship. Most people are familiar with the idea of using the modifier keys (CTRL, SHIFT, ALT) to allow a different output for a particular key. What is probably less common, but is often a better approach for keyboard mapping, is to use a key sequence. Instead of holding the modifier keys then pressing a particular key, a sequence of input keystrokes can be interpreted to mean that a particular output is required.

Context or input sequences?

If the keyboard is just doing a straightforward one-to-one mapping of input keystrokes or key combinations to output characters or strings, the table that has been prepared can be used directly to create the keyboard. However, if key sequences are used, then the input for each rule must be specified, not as the sequence of keys pressed, but rather as the context followed by the last keystroke needed for the rule. The context is the characters (or dead keys) that have been output already before the keystroke triggering processing of the rule is pressed.

Why is context used rather than the more intuitive method of specifying a sequence of input keystrokes? There are two main reasons:

If input sequences are used, then the full sequence must be specified for each rule with the keystroke, but if the context is used, in most cases only the last output character (or deadkey) needs to be specified with the keystroke.

In principle, editing at a point in the will depend on the visible stored text, and not on keystrokes which may have been entered earlier. For Keyman 6, this functionality is supported when using applications (such as MS Word 2002 or later) that support Text Services Framework input. For Linux, such input processing that depends on the existing (rather than just remembered) text has yet to be implemented, but is an eventual design aim.

In practice, what this means is that it does not matter how a particular character came to be output when specifying a rule, which can significantly reduce the number of rules that must be defined.

Creating the keyboard source text file

Since the keyboard source files are written in plain text, any text file editor can be used to create or edit them. However, if you want to be able to display Unicode characters, it is necessary to use an editor that can save the file as UTF-8 coded text. (UTF-16 files are also supported by the compiler, but are probably somewhat less common in the Linux world.)

File name conventions

Keyboard source text files may be given any name, but it is recommended that the file extension .kmn be used, to maintain compatibility with source files developed for Tavultesoft Keyman. When using KMFLCOMP, if no file extension is specified, the compiler will first try to open a file with the name exactly as given, then if that file cannot be found, it will add the extension .kmn and look for a file with that extension. (It appends .kmn to the name specified on the command line, and does not replace any specified extension.)

Compiled keyboard files must use the file name extension .kmfl as only files with that extension will be loaded by LIBKMFL. The compiled output file created by KMFLCOMP is always given the same file name prefix as the input file, but any file name extension is replaced by .kmfl.

As with almost all Linux applications (and in contrast to Windows), file names are case dependent.

Compiling a keyboard

To compile the keyboard source file mykbd.kmn, simply type:

kmflcomp mykbd.kmn

or, since the file name extension in this case is .kmn,

kmflcomp mykbd

In either case, if the compilation succeeds, the compiled keyboard file will be named mykbd.kmfl. Descriptions of the first 10 warnings (or errors) detected are printed to the console, together with the coresponding line numbers in the source file, followed by the total numbers of compiler warnings and errors. If more than 10 errors or warnings are detected and details are required, the –v verbose option (see below) can be used to allow up to 1000 messages to be output.

Compiler options

The following compiler options are supported by KMFLCOMP:

-f	force: output a compiled keyboard file if possible, even if errors were detected.

-v	verbose: show up to 1000 warning and error messages.

-y	yacc debug: display a trace of the yacc parser. This option generates a lot of output, which is generally only of use for debugging suspected errors in the operation of KMFLCOMP, not for tracing errors in the keyboard source files.

Installing and testing the compiled keyboard

Both manual and automatic keyboard installation are supported. In most cases, manual installation is probably simpler and faster than automatic installation. Automatic installation is likely to be of most benefit when users need to frequently change which keyboards are installed and active. Brief instructions for installing SCIM and using KMFL keyboards are provided in the Appendix. See the separate KMFL User Instructions for further information.

Installing a keyboard manually

Any keyboard can be installed by simply copying the compiled keyboard file to the ~/.scim/kmfl folder, and any associated image (icon) files to the ~/.scim/kmfl/icons folder for the current user and restarting scim.

Automatic keyboard loading

If scim has been started, and an application started for which the scim (X11) input method has been selected, then keyboards may also be loaded or unloaded using the scim-setup utility. See the separate KMFL User Instructions for further information.

Testing the installed keyboard

(To be added.)

Programming language reference

Overview

The programming language used to write keyboard source files for KMFL consists of a series of statements organized as a header section followed by one or more groups of rules. The header section defines the name of the keyboard, its icon file (if any), and other general settings. The rules are used to define how the keyboard responds to keystrokes from the user. When more than group of rules is defined, control passes from one group of rules to another during keystroke mapping according to the result of processing each rule group.

Language elements

Statements

Statements may be either single lines of text, or else paragraphs where all lines of each paragraph except the last has a backslash character (preceded by at least one space) as the final character of the line.

There are three types of statement:

Header statements (or directives) are statements that establish general conditions for mapping the keystrokes. These include all header statements and statements defining stores (using the store keyword).

Rules (or processing commands) are the statements within each group that are applied in an appropriate order to each keystroke that is received in order to determine the output character sequence.

Comments are blank lines or starting with "c " inserted by the keyboard designer to clarify the mapping for future reference. Comments may also be added to the end of rules and directives as long as at least one space separates the rule or directive text from the comment ("c ") marker character.

Statements (other than comments) are written using string and character constants, keystroke and named constants, operators, keywords and keyword expressions, which should be separated from each other by inserting one or more spaces.

String and character constants

Keyboard mapping rules may specify strings and characters in a number of different ways. They may be written by enclosing them in single or double quotes, using the Unicode character code convention, or using a named constant (see below).

A string is a sequence of characters. Strings can be made up of multiple concatenated substrings. There is no general limit on the length of a string, although KMFL does impose limits on strings in some situations.

The following string formats are available:

Type	Description	Example
Quoted strings	A list of characters, enclosed either by single- or double-quote characters. For characters with codepage values above 127, the character code used will be the Unicode value (i.e. the relationship between the codepage codepoint and the Unicode value may be locale-dependent). To include quotes in a string, delimit with the alternate quote type.	store (vowels) "aeiou" store (squote) "'‘’"
Decimal character codes	Single character, in decimal format. Range d32 to d1114111.	+ d32 > 'space'
Hexadecimal character codes	Single character in hexadecimal format. Range x20 – x10FFFF.	+ x20 > 'space'
Octal character codes	Single character in octal format. Not recommended – included only for historical reasons. Range 40 – 4177777.	+ 40 > 'space'
Unicode character codes	Single character in U+xxxxxx format. Recommended for Unicode. Range U+0020 – U+10FFFF.	+ U+0020 > 'space'

Strings are concatenated by listing them together, separated by spaces. For example, the following two lines are equivalent:

U+0041 U+0042 d67 d68 "abc"

"ABCDabc"

A typical rule can thus be written in any of the following ways:

+ "a" > "ä"

+ 'a' > 'ä'

+ U+0061 > U+00E4

+ d97 > d244

+ x61 > xE4

+ 'a' > $ADIERESIS

While characters may be specified in terms of their decimal or hexadecimal code values (with d or x prefix), it is usually better if possible to use the Unicode convention (or the actual character) since that makes the mapping rules easier to follow.

The final syntax shown above assumes that the symbolic constant $ADIERESIS has been previously defined by an appropriate store() command in the keyboard header section:

store(ADIERESIS) 'ä'

Note that you must be careful to use the right code for the character you want: the Unicode standard has several characters with the same (or almost the same) shape as other characters, but a different meaning. One example of this is the Greek capital letter Sigma (Σ) and the mathematical summation symbol (∑) – although they look much the same (and were historically the same character), applications supporting Unicode would in many cases treat them differently. If in doubt whether a character is the right one, you can look up the reference tables at http://www.unicode.org

Keystroke constants

Keystrokes can be identified in one of two ways – by the default character generated without remapping, which usually (but not always) corresponds to the letter on the keycap, or by the 'virtual key', the position of the key in the keyboard, using the US standard layout as the primary reference. The following table shows some examples.

Character	'Virtual key'
'a'	[K_A]
'q'	[K_Q]
'A'	[SHIFT K_A]
(N/A)	[K_PAUSE]

Apart from the fact that 'function' keys (such as Pause) do not output a character, so cannot be specified using the character syntax, the two specifications are always equivalent for US standard layout (physical) keyboards (US English locale). However, when other system keyboards are in use, the two conventions are no longer equivalent, so, for example, with the Standard French AZERTY layout, the table becomes:

Character	'Virtual key'
'q'	[K_A]
'a'	[K_Q]
'Q'	[SHIFT K_A]
(N/A)	[K_PAUSE]

The virtual key convention is also important in another way when using non-US English keyboards. Many such keyboards have 'deadkeys' that do not output a character but instead modify the output of the following keystroke. When the keyboard is remapped, in most cases, the key will no longer be used for a deadkey. Using the virtual key syntax allows the keystroke to be recognized and processed as a normal (i.e. non-deadkey) key.

Keystroke combinations using modifier keys (such as CTRL, ALT, CAPS etc.) may also be specified using the virtual key syntax, e.g. [CTRL SHIFT K_A] or [ALT K_BKSP]. Since there is no standard output from such combinations from an unmapped, US standard layout keyboard, they cannot be specified using the character syntax. However, care needs to be taken when using modifier keys, as most applications reserve the ALT key combinations for menus, and many applications also use CTRL key combinations as 'hotkeys' to activate special functions. For new keyboards, it is recommended that key sequences are used rather than modifier key combinations as much as possible.

Note: The 'virtual character key' syntax (e.g. [CTRL 'a']) supported by Tavultesoft Keyman 6 for mnemonic layout keyboards is not (yet) supported by the KMFL compiler and interpreter.

The complete list of modifier keys recognized by the KMFL compiler is as follows:

SHIFT	Either Shift key	LSHIFT	Left Shift key	RSHIFT	Right Shift key
CTRL	Either Control key	LCTRL	Left Control key	RCTRL	Right Control key
ALT	Either Alt key	LALT	Left Alt key	RALT	Right Alt key
ALTGR	Right Alt key	CAPS	Caps lock on	NCAPS	Caps lock off

Note, however, that many keyboards do not have both left and right modifier keys, and some keyboards use the right Alt key (or the Right Alt/Right Ctrl combination) for special purposes, so the intended users of the keyboard layout should always be considered when designing a keyboard that makes use of any modifier keys.

The following table lists the keystroke constants that are recognized by the KMFL compiler, and the corresponding Linux keysym values, the numeric values of the codes that the keys actually generate. The key names shown in the table only correspond to the key caps for US English physical keyboards. (The modifier keys are listed for completeness, but cannot be recognized or used independently to generate output characters.)

Key Code	Key Name		Key Code	Key Name	
K_SPACE	Spacebar	0x20	K_oE2	102nd Key (European)	0x3C
K_A	A	0x41	K_BKSP	Backspace	0xFF08
K_B	B	0x42	K_TAB	Tab	0xFF09
K_C	C	0x43	K_ENTER	Enter	0xFF0D
K_D	D	0x44	K_ESC	Escape	0xFF1B
K_E	E	0x45	K_LEFT	Left Arrow	0xFF51
K_F	F	0x46	K_UP	Up Arrow	0xFF52
K_G	G	0x47	K_RIGHT	Right Arrow	0xFF53
K_H	H	0x48	K_DOWN	Down Arrow	0xFF54
K_I	I	0x49	K_PGUP	Page Up	0xFF55
K_J	J	0x4A	K_PGDN	Page Down	0xFF56
K_K	K	0x4B	K_HOME	Home	0xFF50
K_L	L	0x4C	K_END	End	0xFF57
K_M	M	0x4D	K_INS	Insert	0xFF63
K_N	N	0x4E	K_DEL	Delete	0xFFFF
K_O	O	0x4F	K_F1	F1	0xFFBE
K_P	P	0x50	K_F2	F2	0xFFBF
K_Q	Q	0x51	K_F3	F3	0xFFC0
K_R	R	0x52	K_F4	F4	0xFFC1
K_S	S	0x53	K_F5	F5	0xFFC2
K_T	T	0x54	K_F6	F6	0xFFC3
K_U	U	0x55	K_F7	F7	0xFFC4
K_V	V	0x56	K_F8	F8	0xFFC5
K_W	W	0x57	K_F9	F9	0xFFC6
K_X	X	0x58	K_F10	F10	0xFFC7
K_Y	Y	0x59	K_F11	F11	0xFFC8
K_Z	Z	0x5A	K_F12	F12	0xFFC9
K_1	1	0x31	K_NP0	Number Pad 0	0xFFB0
K_2	2	0x32	K_NP1	Number Pad 1	0xFFB1
K_3	3	0x33	K_NP2	Number Pad 2	0xFFB2
K_4	4	0x34	K_NP3	Number Pad 3	0xFFB3
K_5	5	0x35	K_NP4	Number Pad 4	0xFFB4
K_6	6	0x36	K_NP5	Number Pad 5	0xFFB5
K_7	7	0x37	K_NP6	Number Pad 6	0xFFB6
K_8	8	0x38	K_NP7	Number Pad 7	0xFFB7
K_9	9	0x39	K_NP8	Number Pad 8	0xFFB8
K_0	0	0x30	K_NP9	Number Pad 9	0xFFB9
K_BKQUOTE	`	0x60	K_NPSTAR	Number Pad *	0xFFAA
K_HYPHEN	-	0x2D	K_NPPLUS	Number Pad +	0xFFAB
K_EQUAL	=	0x3D	K_NPMINUS	Number Pad -	0xFFAD
K_LBRKT	[	0x5B	K_NPDOT	Number Pad .	0xFFAE
K_RBRKT	]	0x5D	K_NPSLASH	Number Pad /	0xFFAF
K_BKSLASH	\	0x5C	K_PAUSE	Pause	0xFF13
K_COLON	;	0x3A	K_SCROLL	Scroll Lock	0xFF14
K_QUOTE	'	0x27	K_SHIFT	Shift	0xFFE1
K_COMMA	,	0x2C	K_CONTROL	Control	0xFFE3
K_PERIOD	.	0x2E	K_CAPS	Caps	0xFFE5
K_SLASH	/	0x2F	K_ALT	Alt	0xFFE9

Named constants

Individual characters may also be given symbolic names, which can sometimes be helpful in making the function of mapping clearer. Typically named constants allow you to use a descriptive name for a character, instead of its code. To define a named constant, use store(name) code. When you wish to refer to the code, use $name. The dollar referencing can only be used with named constants. You cannot use it for stores that have more than one character in them. e.g.

store(CCedilla) U+00E7

...

+ [RALT K_C] > $CCedilla

Keywords and keyword expressions

Certain words, such as NAME, STORE, VERSION, INDEX, etc. have special meaning to the KMFL compiler when encountered in statements (other than a comment line). These keywords can always be written in either upper or lower case and to avoid confusion, should not be used for naming variables. A complete list of keywords can be found in the reference section.

Many keywords are used with variable arguments enclosed in parentheses. The keyword with its arguments is referred to here as a keyword expression. Some examples of keyword expressions are:

store(st1)

use(nextGroup)

index(ouputSet,3)

The arguments for keyword expressions are either symbolic names (the names of stores or groups) or constants (e.g. index position references).

Symbolic names

Symbolic names are used for three separate purposes in KMFL source code:

Names of sets (strings) of characters used in keyboard mapping and defined by store statements.

Names of groups of rules.

Names of deadkeys.

Symbolic names are alphanumeric, and may start with either a letter or a digit, but should generally avoid punctuation characters. Purely numeric names are permitted but are just treated as the equivalent string. In all cases, symbolic names are case insensitive, but careful use of mixed case can often help improve the readability of the source code.

Comments

It is often helpful to add comments to a keyboard file to explain what is being mapped or why a particular set of rules has been added. Any line that starts with the letter c (upper or lower case) followed by a space will be treated as a comment and ignored by the KMFL compiler. Similarly, comments may be added to the end of header or rule section command lines by following the command by one or more spaces, an (upper or lower case) letter c, another space, and the comment. Completely blank lines are also treated as comments and are ignored, but can be helpful for formatting the source of the keyboard and making it more readable. The only restriction is that comments may not be used on long (continuation) lines except on the final line of the continuation (see below).

Continuation lines

In both the header and the rules it is sometimes necessary to write quite lengthy specifications. While there is no actual limit to the line length that may be used, it is usually more convenient for display and editing if the rule is broken into parts using continuation lines. If you have a long line, you can wrap it to the next line by inserting a backslash (\) as the last character on the line. There are two limitations to remember when using continuation lines: (1) only the last line of a multi-line continuation can have a comment, and (2) the backslash must not be inside quotes.

The keyboard header

The keyboard header is the first part of a keyboard; it consists of statements that help identify the keyboard and set default options for it. Each statement in the header must be on a separate line and by convention is usually written with capital letters, although that is not required. Keeping the statements in the header in upper case helps you identify them easily, and keeps them consistent with keyboard programs other people might write.

An example of the start of a typical keyboard header is:

NAME "IPA Unicode 1.0"

VERSION 6.0

BITMAP IPA93

HOTKEY "^+P"

begin Unicode > use(Unicode)

store( &Copyright ) "Copyright © 2002 SIL International"

store( &Message ) "http://www.sil.org/computing/fonts"

c need to include international keyboards in this list also

store(nonK) "ACDFJKMPSTVWXYZ`|<>0123456789=^&*()';" "œ"

store(notrans) "abcdefghijklmnopqrstuvwxyz- /"

...

The above example shows the two equivalent but different conventions used for header statements, for example:

AUTHOR "John M. Durdin"

and

store( &Author ) "John M. Durdin"

have exactly the same meaning for KMFL.

The header will normally include at least a NAME statement, a VERSION statement, and a begin statement, and will usually be followed by one or more store() statements defining character or keystroke sets to be used in keyboard mapping. Other header statements that may be included are LANGUAGE, LAYOUT, COPYRIGHT, MESSAGE, CAPS, MNEMONIC LAYOUT, ETHNOLOGUE CODE, AUTHOR.

The NAME statement identifies the keyboard, while the VERSION statement indicates how rules should be interpreted. The main reason for a VERSION statement is to ensure that any future changes to KMFL do not result in existing keyboards being incorrectly interpreted. It also allows keyboards written for Tavultesoft Keyman to behave the same way as they when used with Keyman and Windows applications. The begin statement identifies the coding convention used and the first rule-processing group to be used as each keystroke is received.

A full description of each keyword that can be used in the header section is given below in the Programming language reference section. However, not all header keywords are currently implemented by KMFL.

Groups of processing rules

A rule-processing group consists of a group statement followed by a series of rules, and ends either at the start of another group, or at the end of the keyboard file.

There are two types of groups: those that process the keys pressed and the context, and those that process the context only. Most simple keyboards have a single group that processes each keystroke with the current context, but for more complex keyboard mapping, groups that process context only can be useful, for example, for selecting which group of rules to use according to the current context, or for combining or re-ordering output characters after mapping the keystroke to output characters.

The two group statements are simply written as:

group(main) using keys

for a standard group that has rules for processing both keystrokes and context, and

group(filter)

for a group that processes only the context.

Input processing passes from one group to another group in three situations. If a rule includes a command use(nextgroup) on the output (right hand) side of the rule, then control will be passed to the indicated group whenever that rule is used (see below). Similarly, if the match > use(group2) command is used at the end of a group, then control will be passed to the indicated group if any rule of the group has been matched. Finally, if the nomatch > use(group3) command is used at the end of a group (before or after any match rule), control will be passed to the indicated group if no rule of the group has been matched. If none of these conditions are satisfied, or if no rules contain use(nextgroup) commands, then processing of a keystroke will terminate when all rules of the group have been tested and processed if matched.

In most cases where multiple groups are used, only one group using keys will ever be processed for a given keystroke, but there are some situations when it is useful to include a second group to re-process the current keystroke according to the context resulting from processing the rules of the first group.

Rules

Each processing rule is a command line consisting of the input or match (left-hand) side, the operator > (indicating 'changes to') and the output (right-hand) side. The match side is a specification for a character string to match the context and the current keystroke using standard character strings, Unicode constants, integer constants, and keyword expressions. In all groups of rules that process the keystroke, the last character of the character string specification on the match side must be preceded by the + (plus) sign operator. (In early versions of Keyman, use of the + sign was optional. For this reason, if a VERSION statement is included in the keyboard header specifying a version less than 4.0, then KMFL will also treat the + sign as optional.)

In some cases, rules and that was every rule must include at least one character (as discussed previously under stores) consists of lefthadncomposed of a character string context and/or a (single) keystroke character preceded by the + (plus) operator, erthe operator > (indicating 'changes to') and the right-hadn side

Simple rules

The simplest rules for processing keystrokes consist of just a key and output, for example:

+ "a" > "ä"

In this rule, the key is "a", and the output is "ä". A simple rule begins with a plus sign, followed by the key, the greater-than symbol, and the output. As you might guess, this rule will (unconditionally) change a lowercase 'a' entered by the user into 'ä'.

The key and output can be written as a character in single or double quotes (as above), or as its Unicode character code, or using a named constant. The rule above could have been written in any of the following ways:

+ 'a' > 'ä'

+ U+0061 > U+00E4

+ 'a' > $ADIERESIS

The last syntax assumes that the symbolic constant $ADIERESIS has been previously defined by an appropriate store() command in the keyboard header section:

store(ADIERESIS) 'ä'

Other ways of writing this rule have been mentioned previously under String and character constants.

Rules with longer output

The output of a rule is not limited to a single character. You could, for example, write a rule such as the following:

+ "f" > "ph"

This would change any 'f' that is typed into 'ph'. If the output of a rule consists of more than one character, you can write the characters in different ways if necessary, with a space separating each part. You can specify multiple characters in quotes, but if you use the Unicode codes to write the characters, you must separate each with a space:

+ "f" > U+0070 U+0068

or, equivalently:

+ "f" > U+0070 "h"

Rules with context

Very often we want a keyboard to produce different output depending on more than just the last keystroke. For example, in a keyboard for typing accented characters, we may want the key "e" to produce one of "è", "é", "ë", "ê", or just "e", depending on what was typed immediately before it. To do this we must make our rules look at the context.

The context is the output from previous rules – that is, the characters that are displayed on the screen (and any deadkeys – see later discussion). We can make a rule apply with certain context by putting this context string before the plus sign in the rule, for example:

"^" + "e" > "ê"

With this rule, whenever an 'e' is typed, if it was preceded by a caret (^), the output will be 'ê'. It is important to understand that the context is the output from previous rules, and is not necessarily the same as the sequence of characters typed before the current keystroke. To emphasize this point, consider the four rules below:

+ "a" > "b"

+ "b" > "c"

"b" + "c" > "d"

"c" + "d" > "e"

With these rules, typing "bc" would produce the output "cc", and not "d", as you might at first expect. This is because the key "b" is converted by the second rule into the output "c", while the third rule expects a context of "b", and not "c". To output "d", you would have to type "ac".

However, if a key has no matching rule, the output will be the same as the key, so the output "e" will be produced for input sequences of either "cd" or "bd".

Stores, 'any', and 'index'

When we have many similar rules, we can group them together into one rule by using stores. A store is a set of characters that are grouped under a single name. Stores are used in rules with the any and index keywords. We create a store with a store statement, for example:

store(vowels) "aeiou"

This creates a store called "vowels", which contains the five lowercase vowels. Note that we could also have written the content of the store using ANSI or Unicode character codes, in the same way as output strings, as described previously. An important difference, however, is that while for a sequence of characters in an output string the entire sequence is always output, for a store, in most cases only a single character is selected and used.

The any keyword is used to match a character from a specific store. For example, the following rule will replace any vowel with a period, when used with the store above:

+ any(vowels) > "."

The any statement can be used both in the context and in the key part of a rule. It cannot be used in the output.

The second keyword that is used with stores is the index keyword. The purpose of the index keyword is to select a character from a particular store at the same position in the store as the character matched by a corresponding any statement. (It is usually only used in the output of a rule, although occasionally it is used in the context of a rule where an earlier character in the context is matched using the any keyword.)

An example will help to make this clear. The following rule converts all input to uppercase:

(in keyboard header)

store(lowercase) "abcdefghijklmnopqrstuvwxyz"

store(uppercase) "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

(in rule group)

+ any(lowercase) > index(uppercase,1)

When a letter such as "j" is typed, and the rule is being processed, the any expression looks for it and finds the position of the "j" in the "lowercase" store. The index expression then uses this position as an index into the "uppercase" store and outputs the character at that position from in that store, in this case "J".

The index expression has two parts: the store from which it takes the output character, and the number of the any statement that it gets the character position from. This number is found by counting the characters in the context and keystroke parts of the rule up to the any keyword. Again, a few examples may help to illustrate this:

"a" + any(store1) > index(store2,2)

"ab" any(store1) + "c" > index(store2,3)

In the first rule, the any expression is matching the second character, so the index expression must specify the position as "2". In the second rule, it is matching the third character, so index specifies "3".

d065 any(store1) "B" + any(store2) > index(store3,4)

In this slightly more complex (but artificial) example, the any keyword is used for matching both the context and keystroke, so the index expression specifies that it is the position of the keystroke in the matched store that must be used to select from the output string, not the position of the matched context.

You can have multiple index expressions in the output, which can reference the same or different any expressions on the input side, for example:

any(st1) + any(st2) > index(st1,2) index(st2,1) index(st3,2)

This example shows more clearly how a large number of rules may often be reduced significantly by using stores with any and index expressions in rules.

Deadkeys

Typical (system) keyboard layouts for French and other European languages use a two-key sequence for inputting accented vowels, but the first keystroke is a deadkey, that is the computer uses that keystroke to modify the result of the following keystroke, but nothing actually appears on the screen until the second key is typed. The deadkey keyword is recognized in KMFL for this purpose. If it appears on the output (right-hand) side of a rule, a hidden (deadkey) character is stored in the ouptut stream and can then be recognized as part of the context when processing subsequent keystrokes. KMFL deadkey expressions are identified by a symbolic name (in the same way as stores), and although it is unlikely to be necessary, up to 65,000 distinct deadkeys can be defined.

A typical example of using a deadkey would be the following two rules, to hanle acute accented vowels:

+ "'" > deadkey(quote)

deadkey(quote) + any(plainvowels) > index(acutevowels,2)

Outputting a single quote character is then most easily handled by adding the rule:

deadkey(quote) + "'" > "'"

Note that for the sake of convenience, a deadkey expression can also be written using the short form dk(quote).

Keyword reference

This section provides a more complete description of the syntax and use of each keyword and keyword expression recognized by the KMFL compiler in header and rule statements.

Note that all keywords and keyword expressions are case insensitive (except for arguments in quoted strings). By convention, however, keywords are usually written using lower case, except for (most) header keywords, which are often specified using upper case.

In the descriptions that follow, arguments (variables) used in specifying the syntax use a naming convention with a lower-case prefix that indicates the form of the argument:

the prefix n indicates a simple integer argument (e.g. nIndex)

the prefix s indicates a quoted string (using either single or double quotes), containing any normal printable characters (e.g. sMessage, sAuthor)

the prefix sn indicates a simple, unquoted alphanumeric strings, with no embedded spaces or punctuation except underscore (e.g. snStore, snGroup, snDeadkey)

the prefix sk indicates a (single) symbolic keystroke definition, specifying a keystroke combination (e.g. skHotkey)

the prefix es indicates an extended string consisting of the concatenation of (one or more) characters (specified in any of the ways recognized by the KMFL compiler), quoted strings and keyword expressions (e.g. esOutput)

the prefix v indicates a numeric argument such as 3.0 (e.g. vNumber)

The keyword descriptions that follow are grouped into keywords used in header statements and keywords used in rules. Note, however, that the rule keyword use can also be used in the begin header statement, and the outs and deadkey (or dk) rule keywords may also be used in store header statements.

Note that not all of the keywords listed below are fully implemented. Implementation limitations are listed under Notes. If a listed but unsupported keyword is encountered by the KMFL compiler in a keyboard file, a warning message will be issued, but no error will result, and the keyword (or the entire command) will simply be ignored during actual use of the keyboard.

Keywords used in header statements

Most header statements can be specified using either a keyword or the store(&…) syntax. For KMFL, the two forms are completely equivalent for all rules.

AUTHOR

Syntax	AUTHOR sName store(&Author) sName
Description	The indicated author's name will be displayed when the keyboard is installed or when keyboard information is displayed.
Example	AUTHOR "Brian J. Schmidt, Jr."
Notes	Implementation planned.

begin

Syntax	begin > use(snGroup) begin ANSI > use(snGroup) begin Unicode > use(snGroup)
Description	The begin statement tells KMFL which group should be processed first when it receives a keystroke. If neither ANSI nor Unicode is specified, the ANSI option is assumed. The difference between the two options is in the way characters specified as integer constants are interpreted by KMFL. If the ANSI option is set, then the output character will depend on the current locale for mapping character code to Unicode. If the Unicode option is used, the output will (in most cases) be locale independent, with the output characters being exactly as specified in the rules. New KMFL keyboards should in most cases use the Unicode option. The ANSI option is mainly allowed for compatibility with Keyman keyboards, for which the ANSI/Unicode has more significance for distinguishing between use with applications that can input 8-bit or 16-bit characters.
Example	begin > use(main) begin Unicode > use(main)
See also	group, use

BITMAP

Syntax	BITMAP sBitmap store(&Bitmap) sBitmap
Description	Specifies the bitmap to be used for the icon in the menu of installed KMFL keyboards. bmpFile should be specified as a filename (without a directory prefix). The bitmap file itself may be in one of a number of different formats – .bmp, .png, .xpm, .jpg/.jpeg or .ico, and should have an appropriate filename extension. The extension (and format) .bmp will be assumed if no extensionis specified. The image file itself is not built into the compiled keyboard (unlike Keyman) but must be provided to users with the compiled keyboard. During installation, it should be copied to the icons subdirectory of the installed keyboards folder, and will be loaded from that location (if found) when the keyboard is loaded by SCIM. In the first syntax, quotation marks are optional, but are recommended to avoid problems with any unusual characters or embedded spaces in file names.
Example	BITMAP "LgIcon.png"

CAPS

Syntax	CAPS ALWAYS OFF CAPS ON ONLY SHIFT FREES CAPS store(&CapsAlwaysOff) "1" store(&CapsOnOnly) "1" store(&ShiftFreesCaps) "1"
Description	These three header keyword expressions control the way use of the Caps Lock key is interpreted (following the conventions set for Keyman) and are recognized by the KMFL compiler, but are not currently supported. The following description applies to use in Keyman keyboards, and is a guide for intended use when supported by KMFL. The first statement, "Caps Always Off", makes sure that Caps Lock cannot be turned on while the keyboard is active, and it turns Caps Lock off when the keyboard is switched on. The other two statements, "Caps On Only", and "Shift Frees Caps" are usually used together. "Caps On Only" makes the Caps Lock key like a typewriter Caps Lock, where pressing it turns it on only. "Shift Frees Caps" allows the use of the Shift key to turn Caps Lock off. When both keyword expressions are used, Using these two together makes Keyman work like many European keyboards. These two statements each take a single line in the header.
See also	CAPS and NCAPS modifiers
Notes	Not currently implemented.

COPYRIGHT

Syntax	COPYRIGHT sCopyright store(&Copyright) sCopyright
Description	The specified copyright message will be displayed when the keyboard is installed.
Example	COPYRIGHT "Copyright ©2004 Fred Smith"
Notes	Implementation planned, but possibly not for initial release.

ETHNOLOGUECODE

Syntax	ETHNOLOGUECODE sEthcode store(&EthnologueCode) sEthcode
Description	The ETHNOLOGUECODE keyword specifies the language the keyboard is made for by use of an SIL Ethnologue three-letter language code. This information is intended to be used for integration with language selection by the operating system and applications. For a list of codes, or more information about Ethnologue, see http://www.ethnologue.com
Example	ETHNOLOGUECODE "ICE" c Icelandic
Notes	Not currently implemented.

HOTKEY

Syntax	HOTKEY skHotKey store(&HotKey) skHotKey
Description	The HOTKEY keyword is used to specify a key combination for enabling the keyboard for the current application. When the specified key combination is pressed, any active keyboard will be turned off and the new keyboard will be turned on. Older (Keyman) keyboards used a special syntax for key combinations when specifying the keyboard switching hotkey, but that syntax is not recognized by KMFL. The hotkey to be used should always be specified as a standard symbolic key expression.
Example	HOTKEY [CTRL ALT K_S]
Notes	Not currently implemented.

LANGUAGE

Syntax	LANGUAGE nLang, nSubLang store(&Language) nLang nSublang
Description	The LANGUAGE statement (for Keyman 6.0) specifies the Windows system language that a keyboard should be associated with. If the specified language is available on the user's system, Keyman will install it and associate it with the system shadow keyboard for the Keyman keyboard. The Keyman keyboard will then be activated whenever the language is selected using Windows' language selector in the taskbar. This is particularly relevant when writing a Keyman keyboard for a right-to-left language, as it then directs the system to use right-to-left behaviour with applications that support that. Similar functionality is planned for KMFL to specify locale.
Notes	Not currently implemented.

LAYOUT

Syntax	LAYOUT nID
Description	This header command was used in earlier versions of Keyman keyboards, and is recognized (but ignored) by the KMFL compiler only in order to allow old keyboards to be compiled without errors.
Notes	Not implemented.

MESSAGE

Syntax	MESSAGE sMessage store(&Message) sMessage
Description	The specified message will be displayed when the keyboard is installed or when keyboard information is displayed.
Example	MESSAGE "Use with SILDoulosIPA fonts"
Notes	Implementation planned.

MNEMONIC LAYOUT

Syntax	MNEMONIC LAYOUT nType store(&MnemonicLayout) sType
Description	Two different types of keyboards may be defined, referred to as positional and mnemonic. With a positional keyboard, keyboard mapping is in accordance with the actual key location on the keyboard, irrespective of the current locale. Positional keyboards are most useful for keyboard mappings that must follow a particular arrangement without regard for the keycap labelling of the keyboard being used, for example, for a non-roman script language where a standard typewriter layout is being implemented. See Creating a New Keyboard – Fundamental keyboard properties – Layout type and Language elements – Keystroke constants for a more detailed discussion.
Example	store(&MnemonicLayout) "1"

NAME

Syntax	NAME sKeyboardName
Description	The NAME statement lets you give a more descriptive name to your keyboard than just the file name. If NAME isn't specified in the keyboard file, the filename of the keyboard (excluding the extension) will be used. If a name is specified in the keyboard file, it is best to use an easily recognizable and unique name. For example, it is better to use a specific name, such as "My Dutch", rather than simply "Dutch" which may not be clearly distinguished from the standard keyboard (and locale) for a given language.

store

Syntax	store(snStore) esData
Description	The store keyword expression lets you store a string of characters and/or keystrokes in a buffer which can then be referenced usingthe keywords any and index. Use of stores can greatly simplify many keyboards, often down to just a few rules. A store definition is terminated at the end of the line unless continuation lines are used (see second example). Stores may also contain symbolic keystroke expressions and deadkeys. The outs keyword can sometimes be used to shorten the specification of a keyboard containing many complex stores with (partly) repeated contents, but the compiled result is exactly the same, as the expansion is carried out during compilation rather than when the compiled keyboard is used. Note: Tavultesoft Keyman allowed stores to be defined anywhere within the keyboard file before they are referenced. Since all store names are global, and not limited to within a single group, in order to avoid possible confusion or redefinition of similar stores it is strongly recommended that all stores be defined as part of the header.
Example	store(vowels) "aeiouy" store(acutes) U+00E1 U+00E9 U+00ED \ U+00F3 U+00FA U+00FD
See also	any, index, outs

VERSION

Syntax	VERSION vNumber store(&Version) sVersion
Description	The VERSION statement was defined for Tavultesoft Keyman to allow later versions to easily distinguish what version of Keyman the keyboard was written for and handle it as such. The KMFL interpreter tries to interpret the rules in the same way as the Keyman version specified by the VERSION statement. If no VERSION statement is included, a version of 3.2 is assumed. New keyboards should generally specify the version to be sure that the keyboard will be correctly remapped if future versions of KMFL modify the way any rules are interpreted.
Example	VERSION 6.0

Keywords used in rules

any

Syntax	any(snStore)
Description	The any keyword expression will match any character that is in the store snStore. This keyword can only be used on the left side of a rule. The index statement is used on the right hand side of the rule (or subsequently on the left hand side) to refer to or output the character matched by the any statement. When an any keyword is used, KMFL remembers the offset in the store where the match was found, for later use with the index statement.
Example	+ any(keys) > index(output,1)
See also	index, store

beep

Syntax	beep
Description	The beep keyword produces a sound with the system speaker when the rule is matched, useful for providing user feedback when an illegal typing sequence is used. When using the beep keyword, remember that it wil result in all that was matched on the left side of the rule being deleted unless you precede it with context or appropriate characters. The beep keyword is only valid in the output. The example given below shows how to use beep to leave the context unmodified but ignore an illegal keystroke character in a particular context.
Example	any(contextSet) + any(wrongKey) > context beep
Notes	Implementation of sound output is planned, but possibly for the initial release of the KMFL interpreter. However, rules that have the beep keyword as part of the output will still be correctly processed. Actual sound output when using this keyword is likely to be hardware and configuration dependent.

context

Syntax	context context(nIndex)
Description	The context keyword reproduces the context stored from the rule match, or a single character of it, into the output. Use the context statement as much as possible as it is significantly faster than using the index statement. The context keyword (without any argument) can only be used on the output side of the rule, but the context(nIndex) syntax may also be used as part of the match. A single character from the context can be output (on the right-hand side of a rule) or matched (on the left-hand side of a rule, following some valid context string) using context(i), which selects or matches the I-th character of the stored context.
Example	any(cons) "W" + any(key) > context index(keyout,3) "contex" + "t" > context(2) context(6) c outputs "ox"
See also	any

deadkey

Syntax	deadkey(snDeadkey) dk(snDeadkey)
Description	The deadkey or dk keyword expression lets you program a deadkey in your keyboard. Deadkeys are stored in the output and may be matched subsequently in the context, but are not output to the screen. A keyboard can have as many as 65,000 unique deadkeys if necessary. Any deadkeys inserted by another rule immediately before or after the character to the left of the insertion point will be deleted when backspace is pressed, unless backspace is overridden with a keyboard rule. Deadkeys are treated internally as other characters, and may be included in stores if necessary. In older keyboards, deadkeys were often numbered rather than named, but KMFL treats deadkey numbers as if they were names. For clarity, it is usually best to use names rather than numbers for stores, groups and deadkeys.
Example	+ '`' > dk(backquote) dk(backquote) + 'e' > 'è'
Notes	The deadkey keyword may also be used in store definitions in the header.

group

Syntax	group(snGroup) using keys group(snGroup)
Description	A line with the keyword expression group() must be the first command in each set of processing rules. The first syntax is used (in all keyboards) for a group of rules that processes the input keystrokes, with or without context checking. The second syntax is used in more complex keyboards in situations where it is necessary to check only the context (either before or after processing one or more groups that check the current keystrokes). When each keystroke is received, the KMFL interpreter starts by using the group specified in the begin statement, and then processes other groups according to the presence of use() keyword expressions in matched rules in the group being processed. The context is changed as each rule group is processed, but in keyboards where multiple key-processing groups may be invoked, the keystroke remains the same until all groups have been processed. For groups that process only the context, leave out the '+' operator and keystroke specification on the left-hand (match) side of each rule.
Example	group(main) using keys group(syllablecheck)
See also	use, match, nomatch, begin

index

Syntax	index(snStore,nOffset)
Description	The index keyword expression is used to select a particular character from a store, corresponding to the position of a matched character in a store matched by a corresponding any() keyword expression on the left hand side of the rule. The firsrt argument is the name of the store from which to select the character, and the second is an integer specifying the character position of the any() keyword in the left hand side of the rule (not the position of the character in the store, which can vary each time the rule is processed). The index keyword expression may also be used on the left hand side of rules (in the context, not for the keytroke), as long as the any() keyword it refers to is before it. The inherent flexibility of Keyman (and KMFL) keyboard mapping is largely due to the way index and any keywords are implemented.
Example	any© "W" + any(key) > index(keyout,3) "w" index(c,1)

match

Syntax	match
Description	The match keyword is used alone on the left hand side of a rule. If either or both match or nomatch are used, they must be the last rules of the group (in either order). In each group, if a match rule is found, the right hand side of the rule will be processed if any (preceding) rule in the group has been matched. The output side of a match rule is an extended string and may include use, return, beep keywords as well as characters to be output. The '+' operator is not used with the match or nomatch keywords.
Example	match > use(AdjustVowels) c further process the current keystroke and context
See also	use

nomatch

Syntax	nomatch
Description	The nomatch keyword is used alone on the left hand side of a rule. If either or both match or nomatch are used, they must be the last rules of the group (in either order). In each group, if a nomatch rule is found, the right hand side of the rule will be processed if no (preceding) rule in the group has been matched. The output side of a nomatch rule is an extended string and may include use, return, beep keywords as well as characters to be output. Note that an exception to the nomatch condition is that the nomatch condition will not be asserted, and the rule not used, in a group "using keys" if the current keystroke does not produce a displayable character. This is by design, and is intended to ensure that function keys, cursor movement keys, and shortcut keys (such as Ctrl+X) are passed through to the underlying application unless specifically matched in a rule.
Example	nomatch > beep c warn if input doesn't match any rule
See also	use

nul

Syntax	nul
Description	The nul keyword may be used alone on the output side of a rule to delete the matched context and keystroke specified in the rule, and is equivalent to having an empty output (which is not allowed). nul can also be used in the left hand side of a rule in the context in one special situation. It is used at the start of the context to force the interpreter to match the rule only if the context buffer starts with the matched context. This can occasionally be useful (for example) to test if the user is typing a character at the start of a paragraph, and use a different character in this situation.
Examples	any(cons) + any(key) > nul nul + 'a' > 'A' c match 'a' only if context buffer is empty
Notes	Currently supported only for the right hand side of rules.

outs

Syntax	outs(snStore)
Description	The outs keyword expression copies the contents of the store snStore into an extended string at the position at which the outs keyword occurs in the string. It is mainly used as a shorter way of defining large stores, but can also sometimes be useful for matching context or simplifying the output of long strings. Note that when using outs() in the context, the characters in the outs are included in index counts. (See last example below.)
Example	store(conskeys) "BCDFGHJKLMNPQRSTVWXYZ" store(vowelkeys) "AEIOU" store(allkeys) outs(conskeys) outs(vowelkeys) outs(vowelkeys) + any(conskeys) > index(conskeys, 6)
See also	store
Notes	This keyword may also be also used in the header in store definitions.

return

Syntax	return
Description	return on the right hand side of any rule instructs the KMFL interpreter to stop processing rules and wait for the next keystroke. No other groups will be processed, whether or not a match rule is included in the group.
Example	+ any(badChar) > beep return
See also	any, index, outs

use

Syntax	use(snGroup)
Description	The use keyword expression tells the interpreter to start processing with (or switch processing to) the specified group. Note that when all rules in the currently active group have been processed, the interpreter will return control to the calling group unless either a rule with return in the output was matched or the nomatch condition was met and a nomatch rule with return in the output was included. The use keyword is used in four distinct situations: in the header, as output for a begin command to specify the first group to be processed; in the output of any context and/or keystroke matching rule; or in the output of a match or nomatch rule.with a new group; after Keyman has gone through the new group, and any other nested groups, it will return to the previous one. The use statement can be used with the match and nomatch rules; it will work the same way. The current output is moved to the context before the new group is entered, so the new group will see the output from the matched rule as its context.
Example	any(Vowel) any(Diacritic) > context use(AdjustVowels)
See also	group, begin, match, nomatch, return
Notes	Also used in the header in the begin statement.

Keyword Summary

any	Matches on an array of characters
beep	Generates a beep on the speaker
begin	Defines the starting group for the keyboard layout
BITMAP	An image that appears in the language menu
BITMAPS	Obsolete (Keyman 3.2 keyboards, refers to two icons)
call	Calls an Input Method Extension DLL (Keyman only)
CAPS	Manages CAPS LOCK behaviour (Keyman only)
context	Outputs the context part of a rule
COPYRIGHT	A copyright message for the keyboard
deadkey	Matches and generates deadkeys
ETHNOLOGUE CODE	The SIL Ethnologue code for the language
group	Starts a new group of rules
HOTKEY	A default activation hotkey
index	Outputs from an array of characters
LANGUAGE	Specifies the system language to install
LAYOUT	Obsolete (was the Windows system layout for the keyboard)
match	A system rule that is fired when another rule is matched
MESSAGE	A message that appears when the keyboard is installed
MNEMONIC LAYOUT	Defines a keyboard to be mnemonic or positional
NAME	The name of the keyboard
nomatch	A rule that is used when no context/key rule is matched
nul	Forces no output from a matched rule
outs	Outputs an array of characters
return	Stops processing of the current keystroke
store	Defines an array of characters for use in rules
use	Starts processing in another group of rules
VERSION	The Keyman keyboard version

Programming Tips

Using Groups

Groups provide a facility for grouping related rules, similar to functions in other programming languages. When used effectively, groups can reduce the size and complexity of your keyboards significantly.

Groups can match on context only, or on context and keystroke. The context-only groups can be very useful for pre- and post-processing rules, such as re-ordering stacked diacritics.

The examples below show the two types of groups.

group(mygroup) c context only

'a' > 'b'

group(mygroup) using keys c context and keystroke

'a' + 'a' > 'c'

The use() keyword allows you move into another group when a rule is matched. All output from the matched rule (in the current group) preceding the use() keyword is processed into the context before the subsequent group is entered (although it is not sent to the application until processing finishes for the current keystroke).

For example:

begin > use(precheck) c This example stops two vowels in a row

group(precheck)

any(vowel) > context use(vowelstate)

nomatch > use(nostate)

group(vowelstate) using keys

+ any(vowel) > beep

nomatch > use(nostate)

group(nostate) using keys

+ any(cons) > index(cons, 1)

There are two important things to note from this example:

The first rule any(vowel) > context use(vowelstate) uses the context keyword to copy the matched context to the output, so that the interpreter can move it back into the context for use with the vowelstate group. If you do not do this, the context will be dropped before vowelstate is used, and the character will be deleted from the screen.

If the final group processed is a group() using keys matching both context and keystroke and there is no nomatch rule, then unless the keystroke is matched by another rule in the group, the keystroke will be output to the screen, regardless of whether or not it was matched in earlier groups.

The following table summarizes the special keywords used with groups:

begin	Defines the starting group for the keyboard layout
group	Starts a new group of rules
match	A system rule that is fired when another rule is matched
nomatch	A system rule that is fired when no rule is matched
return	Stops processing of the current keystroke
use	Starts processing in another group

Using Stores

Stores provide a facility to match a character or keystroke against an array of characters or keystrokes. They can also be used to give mnemonic names to strings.

The most common use of stores is to reduce the number of rules required in a keyboard by matching multiple characters rather than a single character in a rule. This is accomplished with the any and index keywords. The any keyword, on the left hand side of a rule, will match any character in the specified store, while the index keyword, on the right hand side of the same rule, will return the character at the corresponding position in the same or another store.

For example:

store(lowercase) "aeiou"

store(uppercase) "AEIOU"

+ any(lowercase) > index(uppercase,1) c vowels to upper case

deadkeys and symbolic key constants (virtual keys) are also permitted in store definitions.

A long store definition can sometimes be more conveniently expressed as a set of shorter definitions, using the outs keyword to concatenate strings. This is especially useful if several long store definitions use common substrings

Sample keyboards

The following keyboards are provided as worked examples, with notes explaining why a particular approach has been used in each case.

Simple French

The first sample keyboard allows users with a standard English physical keyboard to enter the accented vowels used in French in a fairly intuitive way. The first step is to plan the keyboard. Since French uses the same alphabet as English, but with the addition of accented vowels, c-cedilla, and a slightly different conventions for punctuation, the characters we shall need to be able to output are shown in the following table:

Character	Unicode	Character	Unicode
Á	U+00C1	á	U+00E1
É	U+00C9	é	U+00E9
Í	U+00CD	í	U+00ED
Ó	U+00D3	ó	U+00F3
Ú	U+00DA	ú	U+00FA
À	U+00C0	à	U+00E0
È	U+00C8	è	U+00E8
Ì	U+00CC	ì	U+00EC
Ò	U+00D2	ò	U+00F2
Ù	U+00D9	ù	U+00F9
Ä	U+00C4	ä	U+00E4
Ë	U+00CB	ë	U+00EB
Ï	U+00CF	ï	U+00EF
Ö	U+00D6	ö	U+00F6
Ü	U+00DC	ü	U+00FC
Â	U+00C2	â	U+00E2
Ê	U+00CA	ê	U+00EA
Î	U+00CE	î	U+00EE
Ô	U+00D4	ô	U+00F4
Û	U+00DB	û	U+00FB
Ç	U+00C7	ç	U+00E7
«	U+00AB	»	U+00BB

All we need is an easy way of entering the modified characters. For some languages, you might replace each letter on the English keyboard with a letter from the language. In this case, however, most of the letters are accented vowels, so we will use two keystrokes for each: one for the vowel, and one for the accent. Whether to enter the modifier key (for the accent) before or after the vowel being modified is a matter of choice: for this example, we'll use the latter approach.

The most intuitive way of keying an accented vowel is to type the vowel plus a key for which the keycap character resembles the wanted accent. For grave-accented vowels, it is easy, as there is a grave key on standard keyboards, and it is rarely used in other situations. For acute, we can use the single-quote – and perhaps provide a way to type the quote if is actually needed following a vowel. For circumflex, the obvious choice is the circumflex accent key (shift 6). For dieresis, the double-quote, colon or the equals sign could all be used – we'll opt for the equals sign, since it doesn't need to be shifted.

For c-cedilla, using a comma would probably be the most intuitive way, but since a c is likely to be quite often followed by a comma in normal use, it is better to use something else, such as the grave accent.

Keying the European style quotation marks is obvious: just press the angle brackets twice.

The header section for this keyboard is very simple – all that is really needed is the name, the version, and a begin statement indicating the encoding convention and the first rule group to execute. (There is only one rule group, which we'll call main.) To simplify the keyboard, we'll also define a few stores, grouping together keystrokes and characters that can be treated together in a similar way.

So here is the keyboard:

NAME "Simple French"

VERSION 6.0

begin Unicode > use(main)

store(vowel) 'aeiouAEIOU'

store(acute) U+00E1 U+00E9 U+00ED U+00F3 \

U+00FA U+00C1 U+00C9 U+00CD U+00D3 U+00DA

store(grave) U+00E0 U+00E8 U+00EC U+00F2 \

U+00F9 U+00C0 U+00C8 U+00CC U+00D2 U+00D9

store(circumflex) U+00E2 U+00EA U+00EE U+00F4 \

U+00FB U+00C2 U+00CA U+00CE U+00D4 U+00DB

store(dieresis) U+00E4 U+00EB U+00EF U+00F6 \

U+00FC U+00C4 U+00CB U+00CF U+00D6 U+00DC

group(main) using keys

any(vowel) + "'" > index(acute,1)

any(vowel) + "`" > index(grave,1)

any(vowel) + "^" > index(circumflex,1)

any(vowel) + "=" > index(dieresis,1)

'c' + "`" > U+00E7

'C' + "`" > U+00C7

'>' + '>' > U+00BB

'<' + '<' > U+00AB

By defining the stores for vowel keystrokes and characters, the entire keyboard can be written in these eight rules.

To make it easier to enter a single quote or equals sign after a vowel, we would add the following two additional rules:

any(acute) + "'" > index(vowel,1) "'"

any(dieresis) + "=" > index(vowel,1) "="

Pig Latin

This keyboard is provided mainly for fun, but shows how KMFL remapping can be used to manipulate text in quite complex ways. The spelling rules of "Pig Latin" are that words starting with a consonant have the initial consonant moved to the end of the word, and followed by 'ay', while words starting with a vowel simply add 'hay' to the end of the word.

Using one group to identify the end of a word, and another group to re-order words using any() and index() keyword expressions, it is quite easy to create a keyboard that outputs "Pig Latin" as normal English is typed.

NAME "Pig Latin"

VERSION 6.0

begin ansi > use(1)

store(v) 'aeiouAEIOU'

store(lc) 'abcdefghijklmnopqrstuvwxyz'

store(uc) 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

store(x) ' 0123456789~~!@#$%^&*()_+-={}[]:;",./<>?|\' "'"

group(1) using keys

+ any(x) > use(2)

group(2) using keys

any(v) + any(x) > index(v,1) 'hay' index(x,2)

any(lc) + any(x) > index(lc,1) 'ay' index(x,2)

any(uc) + any(x) > index(uc,1) 'ay' index(x,2)

any(v) any(lc) + any(x) > index(v,1) index(lc,2) 'hay'	\
index(x,3)

any(lc) any(lc) + any(x) > index(lc,2) index(lc,1) 'ay'	\
index(x,3)

any(uc) any(lc) + any(x) > index(uc,2) index(lc,1) 'ay'	\
index(x,3)

any(v) any(lc) any(lc) + any(x) > index(v,1) index(lc,2)	\
index(lc,3) 'hay' index(x,4)

any(lc) 'h' any(lc) + any(x) > index(lc,3) index(lc,1) 'hay'	\
index(x,4)

any(uc) 'h' any(lc) + any(x) > index(uc,3) index(lc,1) 'hay'	\
index(x,4)

any(lc) any(lc) any(lc) + any(x) > index(lc,2) index(lc,3)	\
index(lc,1) 'ay' index(x,4)

any(uc) any(lc) any(lc) + any(x) > index(uc,2) index(lc,3)	\
index(lc,1) 'ay' index(x,4)

any(v) any(lc) any(lc) any(lc) + any(x) > index(v,1)	\
index(lc,2) index(lc,3) index(lc,4) 'hay' index(x,5)

any(lc) 'h' any(lc) any(lc) + any(x) > index(lc,3)	\
index(lc,4) index(lc,1) 'hay' index(x,5)

any(uc) 'h' any(lc) any(lc) + any(x) > index(uc,3)	\
index(lc,4) index(lc,1) 'hay' index(x,5)

any(lc) any(lc) any(lc) any(lc) + any(x) > index(lc,2)	\
index(lc,3) index(lc,4) index(lc,1) 'ay' index(x,5)

any(uc) any(lc) any(lc) any(lc) + any(x) > index(uc,2)	\
index(lc,3) index(lc,4) index(lc,1) 'ay' index(x,5)

any(v) any(lc) any(lc) any(lc) any(lc) + any(x) > index(v,1)	\
index(lc,2) index(lc,3) index(lc,4) index(lc,5) 'hay'	\
index(x,6)

any(lc) 'h' any(lc) any(lc) any(lc) + any(x) > index(lc,3)	\
index(lc,4) index(lc,5) index(lc,1) 'hay' index(x,6)

any(uc) 'h' any(lc) any(lc) any(lc) + any(x) > index(uc,3)	\
index(lc,4) index(lc,5) index(lc,1) 'hay' index(x,6)

any(lc) any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(lc,2) index(lc,3) index(lc,4) index(lc,5)	\
index(lc,1) 'ay' index(x,6)

any(uc) any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(uc,2) index(lc,3) index(lc,4) index(lc,5)	\
index(lc,1) 'ay' index(x,6)

any(v) any(lc) any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(v,1) index(lc,2) index(lc,3) index(lc,4)	\
index(lc,5) index(lc,6) 'hay' index(x,7)

any(lc) 'h' any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(lc,3) index(lc,4) index(lc,5) index(lc,6)	\
index(lc,1) 'hay' index(x,7)

any(uc) 'h' any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(uc,3) index(lc,4) index(lc,5) index(lc,6)	\
index(lc,1) 'hay' index(x,7)

any(lc) any(lc) any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(lc,2) index(lc,3) index(lc,4) index(lc,5)	\
index(lc,6) index(lc,1) 'ay' index(x,7)

any(uc) any(lc) any(lc) any(lc) any(lc) any(lc) + any(x) >	\
index(uc,2) index(lc,3) index(lc,4) index(lc,5)	\
index(lc,6) index(lc,1) 'ay' index(x,7)

any(v) any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(v,1) index(lc,2) index(lc,3)	\
index(lc,4) index(lc,5) index(lc,6) index(lc,7)	\
'hay' index(x,8)

any(lc) 'h' any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(lc,3) index(lc,4) index(lc,5)	\
index(lc,6) index(lc,7) index(lc,1) 'hay' index(x,8)

any(uc) 'h' any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(uc,3) index(lc,4) index(lc,5)	\
index(lc,6) index(lc,7) index(lc,1) 'hay' index(x,8)

any(lc) any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(lc,2) index(lc,3) index(lc,4)	\
index(lc,5) index(lc,6) index(lc,7) index(lc,1) 'ay'	\
index(x,8)

any(uc) any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(uc,2) index(lc,3) index(lc,4)	\
index(lc,5) index(lc,6) index(lc,7) index(lc,1) 'ay'	\
index(x,8)

any(v) any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
any(lc) + any(x) > index(v,1) index(lc,2) index(lc,3)	\
index(lc,4) index(lc,5) index(lc,6) index(lc,7)	\
index(lc,8) 'hay' index(x,9)

any(lc) 'h' any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(lc,3) index(lc,4) index(lc,5)	\
index(lc,6) index(lc,7) index(lc,8) index(lc,1) 'hay'	\
index(x,9)

any(uc) 'h' any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
+ any(x) > index(uc,3) index(lc,4) index(lc,5)	\
index(lc,6) index(lc,7) index(lc,8) index(lc,1) 'hay'	\
index(x,9)

any(lc) any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
any(lc) + any(x) > index(lc,2) index(lc,3) index(lc,4)	\
index(lc,5) index(lc,6) index(lc,7) index(lc,8)	\
index(lc,1) 'ay' index(x,9)

any(uc) any(lc) any(lc) any(lc) any(lc) any(lc) any(lc)	\
any(lc) + any(x) > index(uc,2) index(lc,3) index(lc,4)	\
index(lc,5) index(lc,6) index(lc,7) index(lc,8)	\
index(lc,1) 'ay' index(x,9)

+ any(x) > index(x,1)

c End of Pig Latin keyboard

References

For further information, users are referred to the Tavultesoft Keyman Developer documentation, available in PDF format by download from Tavultesoft at http://www.tavultesoft.com/keymandev/documentation/, from which this manual has been adapted.

Manual written by Dr. John M. Durdin, who may be contacted using the contact form at http://www.tavultesoft.com/contact.php

November 2004

Appendix: Using KMFL

The following notes are a brief summary. Please see the separate manual for details of using KMFL.

KMFL Installation Instructions

Install SCIM. Files can be downloaded from .http://sourceforge.net/projects/scim The current version at the time of this writing is 1.0.1. For RPM based systems, the only rpm required for kmfl is scim-1.0.1-1.i586.rpm (or whatever is appropriate for your distro). If you are compiling scim_kmfl_imengine, then you will also need scim-devel-0.99.7-1.i586.rpm. If you are not running an RPM based system, then you will have to install from source until a package appropriate to your system is produced (see below for install from source). Note, kmfl requires scim version 0.99 or later. SCIM 0.9.1 is currently shipping with SuSE 9.1 which is not compatible with the KMFL SuSE rpms.

Install libkmfl.

Install kmflcomp if you are going to create kmfl keyboards.

Install scim_kmfl_imengine. If you are installing from source, make sure you use the same prefix that you used to install scim.

(For SuSE 9.x ignore steps 5-8 and do step 9)

Edit .bash_profile in your home directory and add the following lines:

GTK_IM_MODULE=xim-kmfl

XMODIFIERS=@im=SCIM

export GTK_IM_MODULE XMODIFIERS

Notes:

that xim-kmfl is a special GTK2 input method module based on the GTK2 xim module. The difference between this module and the default is the handling of the backspace when dealing with composite characters. The default xim module will delete the whole composite character when a backspace is press. With the modified module, individual componants of a composite character are deleted when the backspace is pressed.

The GTK2 SCIM input module is not compatible with kmfl. Use the xim-kmfl instead.

The above lines are case sensitive.

Use the “locale” command to check your current locale settings.

Change you locale to a UTF-8 locale if you are not currently using a UTF-8 locale. Fedora Core 2 (1 too?) and SuSE 9.1 (others?) already use UTF-8 encodings so nothing additional should be required with these distro.

On Debian or Gentoo systems, add the following line to the top of .bash_profile in your home directory:

LANG=en_US.UTF-8

On Mandrake systems, edit or modify .i18n in your home directory The follow is a sample .i18n for the en_US.UTF-8 locale:

LANG=en_US.UTF-8

LC_ADDRESS=en_US.UTF-8

LC_TELEPHONE=en_US.UTF-8

LC_PAPER=en_US.UTF-8

LC_CTYPE=en_US.UTF-8

LC_MONETARY=en_US.UTF-8

LC_NUMERIC=en_US.UTF-8

LC_MEASUREMENT=en_US.UTF-8

LC_IDENTIFICATION=en_US.UTF-8

LC_TIME=en_US.UTF-8

LC_NAME=en_US.UTF-8

LC_MESSAGES=en_US.UTF-8

LC_COLLATE=en_US.UTF-8

You will have to logout and login again for the changes to take affect.

For other distros, check the documentation for instructions on setting up a UTF-8 locale.

If you are not running under the en_US.UTF-8 locale, then the scim configuration needs to be modified to support your locale.

Edit /etc/scim/global and add or modify the following line

/SupportedUnicodeLocales = en_US.UTF-8,en_CA.UTF-8

en_CA.UTF-8 should be replaced with the locale under which you are running.

Setup scim to autostart when starting X as follows:

create a file called “startscim” somewhere in your home directory (I would recommend ~/bin) with the following contents:

#!/bin/sh

export SCIM_PANEL_SOCKET_ADDRESS=local:/tmp/scim-panel-socket-$DISPLAY

/usr/bin/scim -d

Make the file executable with the following command (for example):

chmod 700 ~/bin/startscim

***Note the SCIM_PANEL_SOCKET_ADDRESS setting allows more than one X session to be run by a same user on a system. For example I often run a regular X session as well as a VNC session. Without the about setting, scim-panel-gtk will not run on the second session.

KDE

Create a link in ~/.kde/Autostart to the file you created above. For example:

ln -s ~/bin/startscim ~/.kde/Autostart/

Gnome

Bring up the Sessions options.

Mandrake:

Click on “Foot/System/Configuration/Gnome/Advanced/Sessions” menu item.

Fedora:

Click on “Redhat/Preferences/Sessions” menu item.

Gentoo:

Click on “Applications/Desktop Preferences/Advanced/Sessions” menu item.

Click on the “Startup Programs” tab and then click on the “Add” button.

Browse to the location where you created “startscim”, click on “startscim”, click on “Ok”, and click on “Ok” again.

For SuSE 9.1, ignore steps 5-8. Instead, create a .xim file in your home directory with the following contents:

#!/bin/sh
export GTK_IM_MODULE=xim-kmfl
export XMODIFIERS=@im=SCIM
export SCIM_PANEL_SOCKET_ADDRESS=local:/tmp/scim-panel-socket-$DISPLAY
/usr/bin/scim -d

Log out and log back in again for the above settings to take affect.

For kmfl to work with KDE/QT apps, the QT XIM input style needs to be set to "On The Spot". You can set this up with qtconfig. Run qtconfig, select the "Interface" tab, and change the XIM input style to "On The Spot".

At this point, you should be able to bring up an application, for example gedit, hit ctrl-space to turn on scim and select a keyboard.

Compiled keyboards can be installed by copying a compile keyboard to the ~/.scim/kmfl directory (you may have to create this directory). The icon for the keyboard should be copy to ~/.scim/kmfl/icons/. There is also a kmfl keyboard management section in the scim-setup utility. Right-click on the scim tray icon and select setup. Then select the kmfl entry under the imengine section. This will list the currently installed keyboards and allow you to add and delete keyboards. Be aware that deleting a keyboard will delete the compiled keyboard file and the icon. When adding a keyboard, the compiled keyboard file and the keyboard icon must be in the same source directory. The kmfl imengine setup will copy the files to ~/.scim/kmfl/ and ~/.scim/kmfl/icons/.

Some keywords implemented by different versions of Tavultsoft Keyman but not supported by KMFL are also mentioned here for reference.

Keyboard Mapping for Linux - KMFLCOMP	36

John Durdin

2004-11-12T23:17:00