This is an archive of the original site, preserved as a historical reference. Some of the content is outdated. Please consult our other sites for more current information:, ScriptSource, FDBP, and silfontdev


Contact Us


Initiative B@bel

WSI Guidelines


















Type Design


Design Tools



Font Downloads










Font FAQ



Computers & Writing Systems


You are here: Input > Tutorials
Short URL:

Building Keyboards with Keyman 6.0

Lorna Priest, 2003-02-20


This page is now obsolete. It is provided for historical information. For using the Keyman program, please go to the  Keyman site.

We will be creating a keyboard which will allow us to type IPA text. Our goal will be to learn how to develop a Keyman keyboard, not to create a complete keyboard. In this tutorial we are going to begin creating a mnemonic keyboard for IPA.

Before beginning the tutorial you should have installed Keyman 6 Developer.


Keyman Installation

Follow the Instructions for installation in: Keyboard Installation and Use

In order to test the keyboard you will also need a Unicode-based font. Either Doulos SIL or  Code2000 (which is a shareware Unicode font you can use) will work fine.

Choosing the characters and designing the layout

Before we begin, we need to look at which characters we want in our keyboard. In order to save time, I have chosen to use just a few of the characters used for IPA. These are listed in the following charts.




A keyboard file is divided up into a header (which contains such things as the name of the keyboard, copyright information, etc.) and the rules. The rules give Keyman information it needs for converting keystrokes into something else.

Writing the header

Let’s begin by opening TIKE (Start / Programs / Tavultesoft Keyman Developer / TIKE) and writing the header. When you open TIKE you get a welcome screen. Select Keyboard or Start a Keyboard Source File and  OK 

Type in the information you want for your header or select Keyboard / Insert Standard Header. You can choose to use a traditional header or use the newer stores options:

c IPA keyboard
MESSAGE "This is a keyboard developed as a tutorial for learning to develop
Keyman keyboards and uses as many Keyman commands as possible"
COPYRIGHT "2002 SIL International"


c IPA keyboard
store(&NAME) "SIL IPA test"
store(&BITMAP) "IPA"
store(&VERSION) "6.0"
c store(&HOTKEY) "^+I"     c This statement does not currently work in Keyman 6.0.158.
store(&MESSAGE) "This is a keyboard developed as a tutorial for learning to 
develop Keyman keyboards and uses as many Keyman commands as 
store(&COPYRIGHT) "2002 SIL International"

Each of the above rules must all be typed on one line. You will get an error message if any of the rules/lines go onto the next line.

Let’s go ahead and save this file as ipa.kmn (File / Save As).


The “c” with a space after it, is a comment, and everything after it will be ignored.

NAME is the name you will see when you install the keyboard and go to select the keyboard you want to use.

BITMAP is the bitmap shown on the tray when it is active. (You don’t need the .bmp extension in the Keyman file, although the actual filename does.)

VERSION is for the version of Keyman this keyboard was written for.

HOTKEY is whatever keys you want to type to activate the keyboard (rather than using your mouse).

MESSAGE is if you want other people using this keyboard to read something as they install the keyboard.

COPYRIGHT is, of course, what copyright you want to place the keyboard under.

Creating a bitmap

You will need to create a new bitmap or you can just use ipa.bmp found in the following zip file.

Bitmap for IPA Keyman tutorial
Lorna Priest, 2003-02-21
Download "", ZIP archive, 1KB [3287 downloads]

To edit the bitmap (or create a new one), right-click anywhere on the BITMAP line and click on Edit bitmap… If you already have a bitmap by that name it will bring that one up, if not it will ask if you want to create a new one. Editing is simple so we won’t cover how to create a bitmap. When you are finished, close the bitmap and save it.


It is important to realize that if you create a bitmap outside of TIKE it should be 16x16 pixels and no larger.

Also, remember that the bitmap must be in the same directory as the .kmn file, but when you distribute the keyboard you no longer need to send the .bmp file along with the compiled keyboard.

The begin statement

Keyman uses various groups for processing the keys which are pressed on the keyboard. Keyman 5.0 added a new keyword which identifies whether your keyboard is ANSI or Unicode. You can write a keyboard which will work for both ANSI and Unicode applications, but that would be unusual You would only want to do this if the encoding was exactly the same for both.

Keyman needs to know what group to begin with and so you’ll need to add a statement like the following:

begin UNICODE > use(MainU) 

The Keyboard body

The body of the keyboard is what determines the behaviour of the keyboard. It contains rules which are part of literal and stores.


A group begins with a Group statement, and ends either at the start of another group, or at the end of the keyboard file. There are two types of groups: one that processes the keys pressed and the context, and one that processes the context only. If you want to tell Keyman to process keystrokes you must use the using keys statement, otherwise it will process context only.

Since the begin statement calls for the MainU group, let’s create that group. We want to process keystrokes so we’ll use the using keys statement. After the begin statement type the following:

group(MainU) using keys

Basic rules

A rule is the most basic part of a Keyman keyboard. Each rule defines what a keystroke will output when certain characters are already displayed on the screen. A rule is also used to pre-process and post-process the characters being inserted in the file.

A rule is made up of three parts:

context + keystroke > output

The context refers to what is already displayed on the screen. A rule will only be fired if the context and the keystroke both match. The output will replace the context matched on the left hand side of the rule and the keystroke and is now considered context for the next rule processed.

Let’s create a simple rule for typing the schwa.

+    "e"            > U+0259

Since there is no context and I want U+0259 to be output every time I type  e , we don’t need anything on the context side.

We could just use this type of rule for all of the characters we need.

+    "n"            > U+0272
+    "a"            > U+0251

But that would mean an awful lot of rules.


When we have a lot of 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 statements. Let’s create two stores for the IPA base characters. These can appear anywhere in the Keyman file, but to provide some structure let’s put all stores after the begin line and before group(MainU):

store(equalD) "a"    "b"    "c"    "d"    "e"    "f"    "g"    "h"    "i" 
              "j"    "l"    "n"    "o"    "p"    "r"    "s"    "t" 
              "u"    "v"    "w"    
store(equalU) U+0251 U+03B2 U+00E7 U+00F0 U+0259 U+0278 U+0263 U+0265 U+026A 
              U+025F U+026C U+0272 U+0252 U+0298 U+0279 U+0283 U+03B8 
              U+026F U+028B U+028D 

In the first store are the keystrokes we want to use and the second store contains what we want to output when we type something on the keyboard.


We could have typed everything in one store on the same long line, but because I wanted to see it all without scrolling I typed a "" which told Keyman that this store continues on the next line. Notice that the last line of a store does not have the backslash. We also could have made the first store with just a beginning and ending double quote like the following:

store(equalD) "abcdefghijlnoprstuvwxyz"

I like to do it the way I did in the first line above so I can clearly compare the first and second stores to each other since it is important, in this case, to make sure the contents are the same length and in the correct order.

any() and index()

It might be better to just type  e  to output an “e” and a two keystroke sequence to output “special” characters. So let’s comment out the above rule you created (by adding a “c” at the beginning of the line):

c +    "e"            > U+0259

Now we can write a rule under group(MainU):

any(equalD)     + "="           > index(equalU,1)

The any statement is used to match any one character from a specific store. In this example, if  e  is typed, the any statement finds its position in the “equalD” store; the index statement then says use the same position of the first store referenced (which is equalD in this case) but output the character at the same position in the “equalU” store; in this case, if  e  followed by  =  was typed, “U+0259” or “schwa” would be output. We’ll use the index statement again which will help you understand it better.

Testing the keyboard

In order to test what we’ve done so far, let’s save the file again and compile it (Keyboard / Compile keyboard). Look in the messages frame to see if it compiled correctly or not. If there are errors, you will get a message telling you which line the problem is in. See if you can figure it out, fix it, save it and recompile.

To test the keyboard click on Keyboard / Start test. Make sure that “Keyboard active” and “Unicode” are selected. Then select View / Font and select Code2000 (or whatever Unicode font you are using). You can also change the point size so it’s big enough to see.


If you are using an unregistered version of Keyman the above steps will not work. Instead, to test a keyboard, click on Debug / Show debugger. Click in the Debug input pane. Right-click in the Debug input pane, choose "Custom font..." and select Code2000 (or whatever Unicode font you are using). You can also change the point size so it’s big enough to see.

Now try typing:

 e   =   f   =   g   = 

which should look like this:

From now on, when I say to test or type something, you’ll need to remember to save, then compile before you go to the test window. I won’t tell you every time.

Adding more stores and rules

Let’s go ahead and create some more stores for the combining marks and composite characters. Put these with the other stores (just cut and paste these lines in your Keyman file.)

store(ldiaK)    "+"    "_"    "%"    "$"    "{"
store(ldiaU)    U+031F U+0331 U+0325 U+0329 U+032A

store(udiaK)    '~'    '"'
store(udiaU)    U+0303 U+0308

store(tone_K)   "0"     "1"    "2"    "3"    "4"    "&"
store(toneU)     U+030F U+0300 U+0304 U+0301 U+030B U+0361

store(composite)   U+0061 U+0065 U+0069 U+006F U+0075 
store(compositeAc) U+00E1 U+00E9 U+00ED U+00F3 U+00FA

The “ldia” stores refer to diacritics underneath a character and the “udia” stores refer to diacritics above characters. The “tone” stores are obviously for tone markers and the “composite” stores for composites. Next we’ll create two rules similar to the “equal” rule above. Before looking at the next lines, try to create a rule for diacritics underneath and diacritics above on your own. Put them in the MainU group.

+ any(ldiaK)    > index(ldiaU,1)
+ any(udiaK)    > index(udiaU,1) 

Let’s save and compile the file again. Now, in the test window, try typing:

 e   =   +   g   =   o   ~   v   =   %   "   B 

which should look like this:

Watch the screen as you type. You’ll notice that when you type a key that is not part of any of our rules (B), it will just output the character as it would if our IPA keyboard wasn’t selected.


You can also have multiple “index” statements in the output, which can reference the same or different “any”. We won’t use this line, but here’s an example:

any(equalU) + any(equalD) > index(equalU,2) index(equalU,1)

In this example, if I had typed “au”, a previous rule would have converted the “a” to U+0251. Then this rule would take U+0251 + “u” and output U+026F U+0251 (turned m / alpha). I don’t want to do this reordering for IPA but this would be useful if you wanted to type diacritics before the base character (remember that in Unicode combining marks must come after the character it is combining with) or for many non-Roman scripts.

Context / beep

Another statement which is useful is context. The context statement simply reproduces the context stored from the rule match into the output. Use the context statement as much as possible as it is significantly faster than using the index statement. Let’s use context by adding the following rule. Put it with your other rules in group MainU:

any(ldiaU)      + any(ldiaK)    > context beep

This rule outputs the context (some Unicode value from your “ldiaU” store) then it outputs beep which is an audible beep. This can be useful if you want to assure that certain keystrokes are never used. In this example it prohibits the typist from ever typing two below diacritics in a row. “ldiaK” is never output, just a beep to let the typist know something’s wrong.

Test by typing:

 a   =   +   _   v   =   %   + 

You should see something similar to this and you should have heard two beeps:

instead of:

nul statement

nul is another useful statement. “Nul” can be used on the context or the output side. When you use “nul” in the output side, nothing is output. For instance, it could be that you never want to allow the computer operator to type  B ” Let’s add a rule which prohibits typing  B .You can choose to add a “beep” or not, depending on whether you want the audible reminder that nothing was done with the keystroke.

+ "B"    > nul beep


A deadkey is a keystroke that is used but never appears on the screen. Deadkeys can now have descriptive names rather than just numbers. Let’s put all deadkeys at the beginning of the MainU group before the other rules. Type:

+ "@"           > deadkey(at)

This would mean that every time I typed  @ , nothing would appear on the screen. A shortcut to the deadkey() statement is dk(). Now we need to create a rule which will use this deadkey. You can put it anywhere in the MainUgroup:

dk(at)          + any(tone_K)   > index(toneU,2)        c typing tone

Let’s test again by typing:

 u   @   1   v   =   @   2   o   @   3   a   =   @   4 

This should be your output:

Did you notice that when you typed the deadkey you didn’t see any results on the screen? I find this useful but it could be disconcerting for new keyboard users.

use statement

The use statement tells Keyman to switch processing to a new group; after Keyman has gone through the new group, and any other nested groups, it will return to the original group from which the use statement was fired.

The current output is moved to the context before the new group is entered, so the new group will see the output from the fired rule as its context.


As a “cc” user it took me awhile to figure out the use statement. I was thinking it was taking me to a new group and we’d stay in that group until some rule pushed me to another group. I was less confused when I finally switched to thinking of the new group as a define, and the use to a do.

Groups which are accessed by the use statement can also utilize the using keys statement as mentioned earlier.

Now we’ll modify a rule which will take us to another group. Add:


to the end of your deadkey rule, like this:

dk(at)          + any(tone_K)   > index(toneU,2) use(composite)

This rule says that when any tone is output, it will next go to the composite group. Let’s create that group at the end of the file:

any(composite) U+0301 > index(compositeAc,1)


Notice that we are not “using keys”. This is because we will only process what is already in the context, no new keystrokes. This rule says that when Keyman comes across any vowel (aeiou) in the composite store followed by the acute accent (we would have to add other rules if we wanted to create composites for other tone marks), it should be replaced by the glyph found in the same position in the compositeAc store. If there is another character followed by an acute accent it will just stay as is and return to processing in the MainU group.

Test by typing:

 i   @   3   a   =   @   3 

You should see this:

Then use the left arrow key to step over the output. You should notice that you have to left arrow down twice to get through the last one and only once to get through the first. Until OpenType/Uniscribe have full roman support, it is best to use composite characters, so that diacritic placement will be more accurate and the “i” has no dot.

Virtual Keys

You may want to make it so that if you type  n   =  (left-hook n) and then change your mind and just want a regular “n” you can just hit  backspace  and the regular “n” shows up. To do this, add the following rule to the MainUgroup:

any(equal)     + [K_BKSP]      > index(equalD,1)

Next, save and compile. You should have gotten an error message saying the store referenced does not exist. Change any(equal) to any(equalU) and save and compile again. This rule means that if you’ve got a left-hooked n in context followed by  backspace , the left-hooked n will be replaced by whatever is in the equalD store in that position, which in this case happens to be “n.”


You can use many other virtual keys including  ALT ,  CTRL , etc. These are very useful. A sample rule:

+ [RALT K_e] > U+0259

This rule means that if you type  RIGHT-ALT  followed by  e , the schwa will be output.

We’re almost finished. Let’s test the keyboard again. Type  n   =  and then  backspace . You should see the left-hook n and then when you  backspace  you should see “n”.

After closing the test window, we can install the keyboard. There are a variety of ways to do this but the easiest is within TIKE (Keyboard / Install). As you install it, take a look at the Name, Hotkey, Copyright and Message. These are all things that you put in the header statement. Exit TIKE and if Keyman isn’t running already, load the keyboard driver (Start / Programs / Tavultesoft Keyman / Keyman). (You won’t be able to use the keyboard without the driver loaded.) Now in the tray (lower right side) you’ll see the Keyman icon . When you left-click on the icon you can select your keyboard for the current application (or if you remember the hotkey you assigned you can use that).To install a new keyboard or uninstall your keyboard you can right-click on the icon, select Keyman Configuration and then install or uninstall. Once you have a keyboard which you use all the time, you may find you want to include the Keyman driver in your startup options so that it will automatically load and your keyboards will be immediately available for use. Remember that you may want to associate your new keyboard with a Microsoft input language.

You may have noticed we only wrote eight rules. The stores are a little more complicated than just writing one rule after another, but it does save us from writing rules. To accomplish all we’ve done here without stores, we would have had to write at least 72 rules. Enjoy writing keyboards!


There are a number of statements, rules, etc for which there is no time to cover. For information on the rules, check out TIKE’s help files. Among the things not covered in this tutorial are:



store(vowelkeys) "AEIOU"

store(allkeys) outs(conskeys) outs(vowelkeys)


match > use(AdjustVowels)

return: tells Keyman to stop processing rules and wait for the next keystroke to come

nomatch > return

My Final Keyboard


begin Unicode > use(MainU)

store( &Copyright ) "2002 SIL International"
store( &Message )   "This is a keyboard developed as a tutorial for learning
to develop Keyman keyboards and uses as many Keyman commands as 

store(equalD)   "a"    "b"    "c"    "d"    "e"    "f"    "g"    "h"    "i" 
                "j"    "l"    "n"    "o"    "p"    "r"    "s"    "t" 
                "u"    "v"    "w"        
store(equalU)   U+0251 U+03B2 U+00E7 U+00F0 U+0259 U+0278 U+0263 U+0265 U+026A 
                U+025F U+026C U+0272 U+0252 U+0298 U+0279 U+0283 U+03B8 
                U+026F U+028B U+028D 

store(ldiaK)    "+"    "_"    "%"    "$"    "{"
store(ldiaU)    U+031F U+0331 U+0325 U+0329 U+032A

store(udiaK)    '~'    '"'
store(udiaU)    U+0303 U+0308

store(tone_K)   "0"    "1"    "2"    "3"    "4"    "&"
store(toneU)    U+030F U+0300 U+0304 U+0301 U+030B U+0361

store(composite)   U+0061 U+0065 U+0069 U+006F U+0075 
store(compositeAc) U+00E1 U+00E9 U+00ED U+00F3 U+00FA

group(Mainu) using keys 

c deadkeys
                + "@"           > deadkey(at)

c General rules
dk(at)          + any(tone_K)   > index(toneU,2) use(composite)

any(equalD)     + "="           > index(equalU,1)
any(equalU)     + [K_BKSP]      > index(equalD,1)

c lower diacritic
any(ldiaU)      + any(ldiaK)    > context beep
                + any(ldiaK)    > index(ldiaU,1)
c upper diacritic
any(udiaU)      + any(udiaK)    > context beep
                + any(udiaK)    > index(udiaU,1) 

                + "B"          > nul beep


any(composite) U+0301 > index(compositeAc,1)


If you no longer wish to have Keyman 6 on your computer, you can uninstall it.

  • Right-click on the Keyman icon in the tray and click on Keyman Configuration.
  • Uninstall any keyboards you have installed. Close this dialog box.
  • Right-click on the Keyman icon in your systems tray and click on Exit Keyman.
  • Click on Start / Programs / Tavultesoft Keyman Developer / Uninstall Keyman Developer.
  • Click on Start / Programs / Tavultesoft Keyman / Uninstall Keyman.
  • You may need to go to C:Program Files and manually delete the Tavultesoft folder.

© 2003-2024 SIL International, all rights reserved, unless otherwise noted elsewhere on this page.
Provided by SIL's Writing Systems Technology team (formerly known as NRSI). Read our Privacy Policy. Contact us here.