|
Computers & Writing Systems
You are here: Input > Tutorials Building Keyboards with Keyman 6.0
Note: This page is now obsolete. It is provided for historical information. For using the Keyman program, please go to the 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. Contents Keyman InstallationFollow 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 Choosing the characters and designing the layoutBefore 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. CharactersDiacriticsOverviewA 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 headerLet’s begin by opening TIKE ( ) and writing the header. When you open TIKE you get a welcome screen. Select or andType in the information you want for your header or select . You can choose to use a traditional header or use the newer stores options:c IPA keyboard NAME "SIL IPA test" BITMAP IPA VERSION 6.0 HOTKEY "^+I" 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" or 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 possible" store(©RIGHT) "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 ( ). Note 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 bitmapYou will need to create a new bitmap or you can just use ipa.bmp found in the following zip file.
To edit the bitmap (or create a new one), right-click anywhere on the BITMAP line and click on 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. Note 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 statementKeyman 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 bodyThe body of the keyboard is what determines the behaviour of the keyboard. It contains rules which are part of stores. andGroupsA 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 rulesA 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. store()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. Note 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 keyboardIn order to test what we’ve done so far, let’s save the file again and compile it ( ). 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 . Make sure that “Keyboard active” and “Unicode” are selected. Then select and select Code2000 (or whatever Unicode font you are using). You can also change the point size so it’s big enough to see.Note If you are using an unregistered version of Keyman the above steps will not work. Instead, to test a keyboard, click on . Click in the pane. Right-click in the 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 , then compile before you go to the test window. I won’t tell you every time.Adding more stores and rulesLet’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. Note 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 / beepAnother 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 statementnul 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 DeadkeysA 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 statementThe 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. Note 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: use(composite) 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: group(composite) any(composite) U+0301 > index(compositeAc,1) Note 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 KeysYou 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.” Note 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 (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 ( ). (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 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! Note 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(conskeys) "BCDFGHJKLMNPQRSTVWXYZ" store(vowelkeys) "AEIOU" store(allkeys) outs(conskeys) outs(vowelkeys)
match > use(AdjustVowels) : tells Keyman to stop processing rules and wait for the next keystroke to come
My Final KeyboardNAME "SIL IPA test" VERSION 6.0 BITMAP IPA HOTKEY "+I" 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 possible" 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 group(composite) any(composite) U+0301 > index(compositeAc,1) CleanupIf you no longer wish to have Keyman 6 on your computer, you can uninstall it.
© 2003-2024 SIL International, all rights reserved, unless otherwise noted elsewhere on this page. |