OLPC Brasil Keyboard/xkb

From OLPC
< OLPC Brasil Keyboard
Revision as of 02:14, 18 April 2008 by 116.228.2.130 (talk) (python parsexkb.py OPLC_Rwanda_Keyboard)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
  1. !/usr/bin/python
  2. parsekbd.py
  3. Usage: python parsekbd.py OLPC_Nigeria_Keyboard
  4. Gets the wiki page (e.g.) http://wiki.laptop.org/go/OLPC_Nigeria_Keyboard
  5. Parses the keyboard table contained therein and converts it to a KA
  6. tag per http://wiki.laptop.org/go/Manufacturing_Data#Keyboard_ASCII_Map.
  7. The output is stored in a file named (e.g.) OLPC_Nigeria_Keyboard.ka
  8. Warnings on standard output tell you if duplicate entries are discarded
  9. or if some ASCII characters are not present.
  10. In a few cases, this program substitutes dead_{grave,circumflex,tilde}
  11. for {grave,asciicircumflex,asciitilde} because the ascii versions are
  12. in inaccessible locations (the firmware has only shift, unshift, AltGr
  13. maps, so a Shift-AltGr symbol is inaccessible).

from sys import * from urllib import * from re import *

saved_keyname = 128*[0] keys = 128*[0] modifiers = 128*[0]

keynames = { 'AB01':44, 'AB02':45, 'AB03':46, 'AB04':47, 'AB05':48, 'AB06':49, 'AB07':50, 'AB08':51, 'AB09':52, 'AB10':53, 'AB11':115, 'AC01':30, 'AC02':31, 'AC03':32, 'AC04':33, 'AC05':34, 'AC06':35, 'AC07':36, 'AC08':37, 'AC09':38, 'AC10':39, 'AC11':40, 'BKSL':43, 'AD01':16, 'AD02':17, 'AD03':18, 'AD04':19, 'AD05':20, 'AD06':21, 'AD07':22, 'AD08':23, 'AD09':24, 'AD10':25, 'AD11':26, 'AD12':27, 'TLDE':41, 'AE01':2, 'AE02':3, 'AE03':4, 'AE04':5, 'AE05':6, 'AE06':7, 'AE07':8, 'AE08':9, 'AE09':10, 'AE10':11, 'AE11':12, 'AE12':13 };

  1. Convert from textual names of punctuation characters to the ASCII character

punctuation = {

 'exclam':ord('!'),
 'at':ord('@'),
 'numbersign':ord('#'),
 'dollar':ord('$'),
 'percent':ord('%'),
 'asciicircum':ord('^'),
 'dead_circumflex':ord('^'),
 'ampersand':ord('&'),
 'asterisk':ord('*'),
 'parenleft':ord('('),
 'parenright':ord(')'),
 'underscore':ord('_'),
 'plus':ord('+'),
 'minus':ord('-'),
 'equal':ord('='),
 'semicolon':ord(';'),
 'colon':ord(':'),
 'apostrophe':ord('\),
 'grave':ord('`'),
 'dead_grave':ord('`'),
 'quotedbl':ord('"'),
 'dblquote':ord('"'),
 'bar':ord('|'),
 'less':ord('<'),
 'greater':ord('>'),
 'period':ord('.'),
 'slash':ord('/'),
 'backslash':ord('\\'),
 'question':ord('?'),
 'comma':ord(','),
 'bracketleft':ord('['),
 'bracketright':ord(']'),
 'braceleft':ord('{'),
 'braceright':ord('}'),
 'asciitilde':ord('~') ,
 'dead_tilde':ord('~') ,
 'backspace':8,
 'space':32,
 'tab':9,
 'linefeed':10,
 'enter':13,
 'esc':27,
 'escape':27,
 'del':127,
 'delete':127,
 '&':ord('&'),
 '<':ord('<'),
 '>':ord('>'),

}

def string_to_ascii(s):

       if len(s) == 0:
               return -1
       if len(s) == 1:
               return ord(s)
       try:
               i = punctuation[s]
               return i
       except:
               pass
       return -1

def modname(modifier):

       if modifier & 4:
               return "AltGr"
       if modifier & 1:
               return "Shift"
       return "plain"

def handle_key(modifier, s, keyname, keyid):

       ascii = string_to_ascii(s)
       if ascii == -1:
               return
       if keys[ascii] != 0:
               # We already have an entry for this character
               # Keep the most accessible version
               # unshifted beats shifted beats altgr
               if modifier < modifiers[ascii]:
                       if keys[ascii] != keyid:
                               print "  Replacing ", chr(ascii), "on", modname(modifiers[ascii]), saved_keyname[ascii], "with", modname(modifier), keyname
                               keys[ascii] = keyid
                               saved_keyname[ascii] = keyname
                       modifiers[ascii] = modifier;
               else:
                       if keys[ascii] != keyid:
                               print "  Discarding", chr(ascii), "on", modname(modifier), keyname, "already have", modname(modifiers[ascii]), saved_keyname[ascii]
       else:
               # First time we've seen this character
               saved_keyname[ascii] = keyname
               keys[ascii] = keyid
               modifiers[ascii] = modifier

seenlines = {};

def collect_line(line):

       global seenlines
       try:
               s = split("\W+",sub("\t|{|}|\[|]|\,|<|>|;", "", line))
       except:
               return
       if s[1] != 'key':
               return
       seenlines[s[2]] = s[3:6]

def process_keys():

       global seenlines
       if len(seenlines) == 0:
               print "Didn't find any key definitions"
               raise ValueError
       for k in seenlines:
               try:
                       keyid = keynames[k]
               except:
                       print "Bad key name",k
               handle_key(0,seenlines[k][0], k, keyid) # Unshift
               handle_key(1,seenlines[k][1], k, keyid) # Shift
               handle_key(4,seenlines[k][2], k, keyid) # AltGr
  1. This table converts from the IBM physical keystation number to
  2. the corresponding scancode value in scan set 1.

def put_ka_format(outfile):

       global keys, modifiers
       # a-z - output scancode only; unshifted map is implied
       # and shifted map is derived automatically
       for i in range(ord('a'),ord('a')+26):
               if (keys[i] == 0):
                       print "Missing",chr(i)
               if modifiers[i] != 0:
                       print chr(i),"is modified"
               outfile.write(chr(keys[i]))
       # Numbers and punctuation - output scancode and keymap number
       for i in '0123456789!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~':
               ascii = ord(i)
               if (keys[ascii] == 0):
                       print "Missing",i
               if (modifiers[ascii] & 0xa) != 0:
                       print i,"is Ctrl or Fn"
               outfile.write(chr(keys[ascii]))
               
               if (modifiers[ascii] & 0x4) != 0:
                       # modifier & 4 implies AltGr map
                       outfile.write(chr(2))
               else:
                       # otherwise it's either the shift (1) or unshift (0) map
                       outfile.write(chr(modifiers[ascii] & 1))
       
       outfile.write(chr(0))   # Null terminator
       
       outfile.write(chr(111 ^ 0xff))
       outfile.write(chr(111))
       outfile.write('KA')

def wiki_to_ka(argv):

       try:
               try:
                       print  "Getting",'http://wiki.laptop.org/go/' + argv[1]
                       infile = urlopen('http://wiki.laptop.org/go/' + argv[1])
               except IOError:
                       print "Can't open that URL"
               for line in infile:
                       collect_line(line)
               infile.close()
               process_keys()
               try:
                       outfile = open(argv[1] + '.ka', 'w')
               except IOError:
                       print "Can't open output file",argv[1] + '.ka'
                       raise
               put_ka_format(outfile)
               outfile.close()
               print "Output at",argv[1] + '.ka'
       except:
               print "Failed"

if len(argv) != 2:

       print "Usage: python parsekbd.py PageName"

else:

       wiki_to_ka(argv)