OLPC Brasil Keyboard/xkb
- !/usr/bin/python
- parsekbd.py
- Usage: python parsekbd.py OLPC_Nigeria_Keyboard
- Gets the wiki page (e.g.) http://wiki.laptop.org/go/OLPC_Nigeria_Keyboard
- Parses the keyboard table contained therein and converts it to a KA
- tag per http://wiki.laptop.org/go/Manufacturing_Data#Keyboard_ASCII_Map.
- The output is stored in a file named (e.g.) OLPC_Nigeria_Keyboard.ka
- Warnings on standard output tell you if duplicate entries are discarded
- or if some ASCII characters are not present.
- In a few cases, this program substitutes dead_{grave,circumflex,tilde}
- for {grave,asciicircumflex,asciitilde} because the ascii versions are
- in inaccessible locations (the firmware has only shift, unshift, AltGr
- 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 };
- 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
- This table converts from the IBM physical keystation number to
- 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)