./ 755 0 0 0 7417636236 4160 5./lib/ 755 0 0 0 7417634633 4725 5./lib/azerty 644 0 0 1337 7417634633 6172 0 0x02 0x26 0 0x03 0xE9 0 0x04 0x22 0 0x05 0x27 0 0x06 0x28 0 0x07 0x2D 0 0x08 0xE8 0 0x09 0x5F 0 0x0A 0xE7 0 0x0B 0xE0 0 0x0C 0x29 0 0x10 0x61 0 0x11 0x7A 0 0x1A 0x5E 0 0x1B 0x24 0 0x1E 0x71 0 0x27 0x6D 0 0x29 0x2072 0 0x2B 0x2A 0 0x2C 0x77 0 0x32 0x2C 0 0x33 0x3B 0 0x34 0x3A 0 0x35 0x21 0 0x56 0x3C 1 0x02 0x31 1 0x03 0x32 1 0x04 0x33 1 0x05 0x34 1 0x06 0x35 1 0x07 0x36 1 0x08 0x37 1 0x09 0x38 1 0x0A 0x39 1 0x0B 0x30 1 0x0C 0xB0 1 0x10 0x41 1 0x11 0x5A 1 0x1B 0xA3 1 0x1E 0x51 1 0x27 0x4D 1 0x28 0x25 1 0x29 0x00 1 0x2B 0x3BC 1 0x2C 0x57 1 0x32 0x3F 1 0x33 0x2E 1 0x34 0x2F 1 0x35 0xA7 1 0x56 0x3E 3 0x03 0x7E 3 0x04 0x23 3 0x05 0x7B 3 0x06 0x5B 3 0x07 0x7c 3 0x08 0x60 3 0x09 0x5C 3 0x0A 0x5E 3 0x0B 0x40 3 0x0C 0x5D 3 0x0D 0x7D B 0x2A 0 0x2C 0x77 0 0x32 0x2C 0 0x33 0x3B 0 0x34 0x3A 0 0x35 0x21 0 0x56 0x3C 1 0x02 0x31 1 0x03 0x32 1 0x04 0x33 1 0x05 0x34 1 0x06 0x35 1 0x07 0x36 1 0x08 0x37 1 0x09 0x38 1 0x0A 0x39 1 0x0B 0x30 1 0x0C 0xB0 1 0x10 0x41 1 0x11 0x5A 1 0x1B 0xA3 1 0x1E 0x51 1 0x27 0x4D 1 0x28 0x25 1 0x29./rc/ 755 0 0 0 7417635231 4556 5./rc/termrc 755 0 0 3772 7417635231 6011 #!/bin/rc -x # replace FILESERVER with the name of your file server # here we start with kfs, your local disk file system fileserver=kfs # replace CPU with the name of your cpu server cpu=coma # replace FACEDOM with the local domain to be used in the faces database facedom=strakt.com # keyboard mapping kbmap=/lib/azerty # cs sets sysname ndb/cs sysname=`{cat /dev/sysname} # mount mail uncached mount -c /srv/boot /n/termrc.tmp bind -c /n/termrc.tmp/mail /mail unmount /n/termrc.tmp # start ethernet if any; ignore errors ip/ipconfig >/dev/null >[2=1] ndb/dns -r aux/timesync -rL switch($terminal){ case carrera* bind -a '#t' /dev case *' ss'* /bin/bind -a '#w' /dev >/dev/null >[2=1] /bin/bind -a '#t' /dev >/dev/null >[2=1] case *' magnum'* /bin/bind -a '#m' /dev >/dev/null >[2=1] /bin/bind -a '#t' /dev >/dev/null >[2=1] aux/mouse -dC 0 case *' indigo'* /bin/bind -a '#L' /dev >/dev/null >[2=1] /bin/bind -a '#w1' /dev >/dev/null >[2=1] /bin/bind -a '#t' /dev >/dev/null >[2=1] /bin/bind -a '#A' /dev >/dev/null >[2=1] case NCR* 'AT&TNSX'* generic* _MP_* 'alpha apc'* for(i in f t m L S κ) /bin/bind -a '#'^$i /dev >/dev/null >[2=1] for(disk in /dev/sd??) { if(test -f $disk/data && test -f $disk/ctl) disk/fdisk -p $disk/data >$disk/ctl for(part in $disk/plan9*) if(test -f $part) disk/prep -p $part >$disk/ctl >[2]/dev/null } if(test -f /dev/mousectl){ switch($mouseport){ case ps2 ps2intellimouse 0 1 2 aux/mouse $mouseport # parse vgasize into fields vgasize=`{echo $vgasize} if(! ~ $monitor '' && ! ~ `{cat /dev/user} none){ aux/vga -l $vgasize # turn off hardware acceleration until you know it's ok. echo -n 'hwaccel off' >'#v/vgactl' >[2]/dev/null } } } if(test -f /dev/sd*/swap){ x=(`{echo /dev/sd*/swap}) swap $x(1) >/dev/null >[2=1] } if(test -f /dev/sd*/dos*){ dossrv c: } } if (! ~ $kbmap '' && test -f $kbmap) cat $kbmap > /dev/kbmap switch ($fileserver) { case kfs fn k { disk/kfscmd $* } fn halt { k halt } fn sync { k sync } } gasize./pc/ 755 0 0 0 7417634607 4562 5./pc/kbd.c 644 0 0 23225 7417634537 5514 #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" enum { Data= 0x60, /* data port */ Status= 0x64, /* status port */ Inready= 0x01, /* input character ready */ Outbusy= 0x02, /* output busy */ Sysflag= 0x04, /* system flag */ Cmddata= 0x08, /* cmd==0, data==1 */ Inhibit= 0x10, /* keyboard/mouse inhibited */ Minready= 0x20, /* mouse character ready */ Rtimeout= 0x40, /* general timeout */ Parity= 0x80, Cmd= 0x64, /* command port (write only) */ Spec= 0xF800, /* Unicode private space */ PF= Spec|0x20, /* num pad function key */ View= Spec|0x00, /* view (shift window up) */ KF= 0xF000, /* function key (begin Unicode private space) */ Shift= Spec|0x60, Break= Spec|0x61, Ctrl= Spec|0x62, Latin= Spec|0x63, Caps= Spec|0x64, Num= Spec|0x65, Middle= Spec|0x66, Altgr= Spec|0x67, No= 0x00, /* peter */ Home= KF|13, Up= KF|14, Pgup= KF|15, Print= KF|16, Left= KF|17, Right= KF|18, End= '\r', Down= View, Pgdown= KF|19, Ins= KF|20, Del= 0x7F, Scroll= KF|21, Nscan= 130, }; /* * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard. * A 'standard' keyboard doesn't produce anything above 0x58. */ Rune kbtab[Nscan] = { [0x00] No, 0x1b, '1', '2', '3', '4', '5', '6', [0x08] '7', '8', '9', '0', '-', '=', '\b', '\t', [0x10] 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', [0x18] 'o', 'p', '[', ']', '\n', Ctrl, 'a', 's', [0x20] 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', [0x28] '\'', '`', Shift, '\\', 'z', 'x', 'c', 'v', [0x30] 'b', 'n', 'm', ',', '.', '/', Shift, '*', [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7', [0x48] '8', '9', '-', '4', '5', '6', '+', '1', [0x50] '2', '3', '0', '.', No, No, No, KF|11, [0x58] KF|12, No, No, No, No, No, No, No, [0x60] No, No, No, No, No, No, No, No, [0x68] No, No, No, No, No, No, No, No, [0x70] No, No, No, No, No, No, No, No, [0x78] No, View, No, Up, No, No, No, No, }; Rune kbtabshift[Nscan] = { [0x00] No, 0x1b, '!', '@', '#', '$', '%', '^', [0x08] '&', '*', '(', ')', '_', '+', '\b', '\t', [0x10] 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', [0x18] 'O', 'P', '{', '}', '\n', Ctrl, 'A', 'S', [0x20] 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', [0x28] '"', '~', Shift, '|', 'Z', 'X', 'C', 'V', [0x30] 'B', 'N', 'M', '<', '>', '?', Shift, '*', [0x38] Latin, ' ', Ctrl, KF|1, KF|2, KF|3, KF|4, KF|5, [0x40] KF|6, KF|7, KF|8, KF|9, KF|10, Num, Scroll, '7', [0x48] '8', '9', '-', '4', '5', '6', '+', '1', [0x50] '2', '3', '0', '.', No, No, No, KF|11, [0x58] KF|12, No, No, No, No, No, No, No, [0x60] No, No, No, No, No, No, No, No, [0x68] No, No, No, No, No, No, No, No, [0x70] No, No, No, No, No, No, No, No, [0x78] No, Up, No, Up, No, No, No, No, }; Rune kbtabesc1[Nscan] = { [0x00] No, No, No, No, No, No, No, No, [0x08] No, No, No, No, No, No, No, No, [0x10] No, No, No, No, No, No, No, No, [0x18] No, No, No, No, '\n', Ctrl, No, No, [0x20] No, No, No, No, No, No, No, No, [0x28] No, No, Shift, No, No, No, No, No, [0x30] No, No, No, No, No, '/', No, Print, [0x38] Altgr, No, No, No, No, No, No, No, [0x40] No, No, No, No, No, No, Break, Home, [0x48] Up, Pgup, No, Left, No, Right, No, End, [0x50] Down, Pgdown, Ins, Del, No, No, No, No, [0x58] No, No, No, No, No, No, No, No, [0x60] No, No, No, No, No, No, No, No, [0x68] No, No, No, No, No, No, No, No, [0x70] No, No, No, No, No, No, No, No, [0x78] No, Up, No, No, No, No, No, No, }; Rune kbtabaltgr[Nscan] = { [0x00] No, No, No, No, No, No, No, No, [0x08] No, No, No, No, No, No, No, No, [0x10] No, No, No, No, No, No, No, No, [0x18] No, No, No, No, No, No, No, No, [0x20] No, No, No, No, No, No, No, No, [0x28] No, No, No, No, No, No, No, No, [0x30] No, No, No, No, No, No, No, No, [0x38] No, No, No, No, No, No, No, No, [0x40] No, No, No, No, No, No, No, No, [0x48] No, No, No, No, No, No, No, No, [0x50] No, No, No, No, No, No, No, No, [0x58] No, No, No, No, No, No, No, No, [0x60] No, No, No, No, No, No, No, No, [0x68] No, No, No, No, No, No, No, No, [0x70] No, No, No, No, No, No, No, No, [0x78] No, Up, No, No, No, No, No, No, }; enum { /* controller command byte */ Cscs1= (1<<6), /* scan code set 1 */ Cauxdis= (1<<5), /* mouse disable */ Ckbddis= (1<<4), /* kbd disable */ Csf= (1<<2), /* system flag */ Cauxint= (1<<1), /* mouse interrupt enable */ Ckbdint= (1<<0), /* kbd interrupt enable */ }; static Lock i8042lock; static uchar ccc; static void (*auxputc)(int, int); /* * wait for output no longer busy */ static int outready(void) { int tries; for(tries = 0; (inb(Status) & Outbusy); tries++){ if(tries > 500) return -1; delay(2); } return 0; } /* * wait for input */ static int inready(void) { int tries; for(tries = 0; !(inb(Status) & Inready); tries++){ if(tries > 500) return -1; delay(2); } return 0; } /* * ask 8042 to reset the machine */ void i8042reset(void) { ushort *s = KADDR(0x472); int i, x; *s = 0x1234; /* BIOS warm-boot flag */ /* * newer reset the machine command */ outready(); outb(Cmd, 0xFE); outready(); /* * Pulse it by hand (old somewhat reliable) */ x = 0xDF; for(i = 0; i < 5; i++){ x ^= 1; outready(); outb(Cmd, 0xD1); outready(); outb(Data, x); /* toggle reset */ delay(100); } } int i8042auxcmd(int cmd) { unsigned int c; int tries; c = 0; tries = 0; ilock(&i8042lock); do{ if(tries++ > 2) break; if(outready() < 0) break; outb(Cmd, 0xD4); if(outready() < 0) break; outb(Data, cmd); if(outready() < 0) break; if(inready() < 0) break; c = inb(Data); } while(c == 0xFE || c == 0); iunlock(&i8042lock); if(c != 0xFA){ print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd); return -1; } return 0; } /* * keyboard interrupt */ static void i8042intr(Ureg*, void*) { int s, c, i; static int esc1; static int alt, altgr, caps, ctl, num, shift; static int collecting, nk; static Rune kc[5]; int keyup; /* * get status */ lock(&i8042lock); s = inb(Status); if(!(s&Inready)){ unlock(&i8042lock); return; } /* * get the character */ c = inb(Data); unlock(&i8042lock); /* * if it's the aux port... */ if(s & Minready){ if(auxputc != nil) auxputc(c, shift); return; } /* * e0's is the first of a 2 character sequence */ if(c == 0xe0){ esc1 = 1; return; } keyup = c&0x80; c &= 0x7f; if(c > sizeof kbtab){ c |= keyup; if(c != 0xFF) /* these come fairly often: CAPSLOCK U Y */ print("unknown key %ux\n", c); return; } if(esc1){ c = kbtabesc1[c]; esc1 = 0; } else if(shift) c = kbtabshift[c]; else if (altgr) c = kbtabaltgr[c]; else c = kbtab[c]; if(caps && c<='z' && c>='a') c += 'A' - 'a'; /* * keyup only important for shifts */ if(keyup){ switch(c){ case Latin: alt = 0; break; case Shift: shift = 0; break; case Ctrl: ctl = 0; break; case Altgr: /*print("ag- e %d a %d c %d\n", esc1, alt, collecting);*/ altgr = 0; break; } return; } /* * normal character */ if(!(c & (Spec|KF))){ if(ctl){ if(alt && c == Del) exit(0); c &= 0x1f; } if(!collecting){ kbdputc(kbdq, c); return; } kc[nk++] = c; c = latin1(kc, nk); if(c < -1) /* need more keystrokes */ return; if(c != -1) /* valid sequence */ kbdputc(kbdq, c); else /* dump characters */ for(i=0; i= Nscan) error(Ebadarg); switch(m) { default: error(Ebadarg); case 0: kbtab[scanc] = r; break; case 1: kbtabshift[scanc] = r; break; case 2: kbtabesc1[scanc] = r; break; case 3: kbtabaltgr[scanc] = r; break; } } int kbdgetmap(int offset, int *t, int *sc, Rune *r) { *t = offset/Nscan; *sc = offset%Nscan; if(*t < 0 || *sc < 0) error(Ebadarg); switch(*t) { default: return 0; case 0: *r = kbtab[*sc]; return 1; case 1: *r = kbtabshift[*sc]; return 1; case 2: *r = kbtabesc1[*sc]; return 1; case 3: *r = kbtabaltgr[*sc]; return 1; } } fault: error(Ebadarg); case 0: kbtab[scanc] = r; break; case 1: kbtabshift[scanc] = r; break; case 2: kbtabesc1[scanc] = r; break; case 3: kbtabaltgr[scanc] = r; break; } } int kbdgetmap(int offset, int *t, int *sc, Rune *r) { *t = offset/Nscan; *sc = offset%Nscan; if(*t < 0 || *sc < 0) error(Ebadarg); switch(*t) { default: return 0; case 0: *r = ./pc/pcdisk 644 0 0 2012 7417634607 5755 dev root cons arch env pipe proc mnt srv dup rtc ssl bridge loopback kprof kbmap ether netif ip arp chandial ip ipaux iproute netlog nullmedium pktmedium ptclbsum386 inferno draw screen vga vgax mouse mouse vga sd floppy dma audio dma i82365 cis lpt ns16552 link apm apmjump ether2000 ether8390 ether2114x pci ether589 etherelnk3 ether79c970 pci ether8003 ether8390 ether82557 pci etherec2t ether8390 etherelnk3 pci etherwavelan ethermedium loopbackmedium pcmciamodem misc archmp mp apic cfs.root kfs.root ppp.root ipconfig.root sdata pci sdscsi sd53c8xx pci sdscsi sdmylex pci sdscsi vga3dfx +cur vgaark2000pv +cur vgabt485 =cur vgaclgd542x +cur vgaclgd546x +cur vgact65545 +cur vgacyber938x +cur vgahiqvideo +cur vgamach64xx +cur vgamga2164w +cur vganeomagic +cur vgargb524 =cur vgas3 +cur vgasavage vgat2r4 +cur vgatvp3020 =cur vgatvp3026 =cur ip il tcp udp rudp ipifc icmp gre ipmux port int cpuserver = 0; boot boot #S/sdC0/ il local archmp mp apic cfs.root kfs.root ppp.root ipconfig.root sdata pci sdscsi sd53c8xx pci sdscsi sdmylex pci sdscsi vga3dfx +cur vgaark2000pv +cur vgabt485 =cur vgaclgd542x +cur vgaclgd546x +cur vgact65545 +cur vgacyber938x +cur vgahiqvideo +cur vgamach64xx +cur vgamga2164w +cur vganeomagic +cur vgargb524 =cur vgas3 +cur vgasavage vgat2r4 +cur vgatvp3020 =cur vgatvp3026 =cur ip il tcp udp rudp ipifc icmp gre ipmux port int cpuserver = 0; boot boot #S/sdC0/ ./port/ 755 0 0 0 7417635067 5145 5./port/devkbmap.c 644 0 0 4467 7417634556 7117 /* * keyboard map */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" enum{ Qdir, Qdata, }; Dirtab kbmaptab[]={ "kbmap", {Qdata, 0}, 0, 0600, }; #define NKBFILE sizeof(kbmaptab)/sizeof(kbmaptab[0]) #define KBLINELEN (3*NUMSIZE+1) /* t code val\n */ extern int kbdgetmap(int, int*, int*, Rune*); extern void kbdputmap(ushort, ushort, Rune); static Chan * kbmapattach(char *spec) { return devattach(L'κ', spec); } static int kbmapwalk(Chan *c, char *name) { return devwalk(c, name, kbmaptab, NKBFILE, devgen); } static void kbmapstat(Chan *c, char *db) { devstat(c, db, kbmaptab, NKBFILE, devgen); } static Chan * kbmapopen(Chan *c, int omode) { return devopen(c, omode, kbmaptab, NKBFILE, devgen); } static void kbmapclose(Chan*) { } static long kbmapread(Chan *c, void *a, long n, vlong offset) { char *bp; char tmp[KBLINELEN+1]; int t, sc; Rune r; switch(c->qid.path & ~CHDIR){ case Qdir: return devdirread(c, a, n, kbmaptab, NKBFILE, devgen); case Qdata: if(kbdgetmap(offset/KBLINELEN, &t, &sc, &r)) { bp = tmp; bp += readnum(0, bp, NUMSIZE, t, NUMSIZE); bp += readnum(0, bp, NUMSIZE, sc, NUMSIZE); bp += readnum(0, bp, NUMSIZE, r, NUMSIZE); *bp++ = '\n'; *bp = 0; n = readstr(offset%KBLINELEN, a, n, tmp); } else n = 0; break; default: n=0; break; } return n; } static long kbmapwrite(Chan *c, void *a, long n, vlong) { char line[100], *lp, *b; int key, m, l; Rune r; switch(c->qid.path & ~CHDIR){ case Qdata: b = a; l = n; for(lp = line; --l >= 0;) { *lp++ = *b++; if(lp[-1] == '\n' || l == 0 || lp == &line[sizeof(line)-1]) { *lp = 0; if(*line == 0) error(Ebadarg); m = strtoul(line, &lp, 0); key = strtoul(lp, &lp, 0); while(*lp == ' ' || *lp == '\t') lp++; r = 0; if(*lp == '\'' && lp[1]) chartorune(&r, lp+1); else if(*lp>='0' && *lp<='9') /* includes 0x... */ r = strtoul(lp, &lp, 0); else error(Ebadarg); kbdputmap(m, key, r); lp = line; } } break; default: error(Ebadusefd); } return n; } Dev kbmapdevtab = { L'κ', "kbmap", devreset, devinit, kbmapattach, devclone, kbmapwalk, kbmapstat, kbmapopen, devcreate, kbmapclose, kbmapread, devbread, kbmapwrite, devbwrite, devremove, devwstat, }; ++; r = 0; if(*lp == '\'' && lp[1]) chartorune(&r, lp+1); else if(*lp>='0' && *lp<='9') /* includes 0x... */ r = strtoul(lp, &lp, 0); else error(Ebadarg); kbdputmap(m./port/master 644 0 0 532 7417635067 6343 root / audio A bridge B sac C ssl D sdp E tinyfs F astar G ip I lpt L mnt M arch P cdrom R sd S lm78 T kprof T usb U lml V loopback X intrts Z cons c dup d env e floppy f draw i ether l lance l midi m mouse m proc p rtc r srv s ns16552 t z8530 t duart t vga v pcmcia y i82365 y mntstats z pipe | kbmap κ & lp[1]) chartorune(&r, lp+1); else if(*lp>='0' && *lp<='9') /* includes 0x... */ r = strtoul(lp, &lp, 0); else error(Ebadarg); kbdputmap(m./man/ 755 0 0 0 7417635742 4734 5./man/kbmap.man 644 0 0 2675 7417635742 6535 .TH KBMAP 3 .SH NAME kbmap \- keyboard map .SH SYNOPSIS .nf .B bind -a #κ /dev .B /dev/kbmap .fi .SH DESCRIPTION .PP The .I kbmap device serves a one-level directory containing a single file, .BR kbmap , representing the kernel's mapping of keyboard scan codes to Unicode characters (see .IR cons (3) and .IR keyboard (6)). .PP Reads return the current contents of the map. Each entry is one line containing three 11 character numeric fields, each followed by a space: a table number, an index into the table (scan code), and the decimal value of the corresponding Unicode character (0 if none). The table numbers are platform dependent; they typically distinguish between unshifted and shifted keys. The scan code values are hardware dependent and can vary from keyboard to keyboard. .PP Writes to the file change the map. Lines written to the file must contain three space-separated numeric fields, representing the table number, scan code index, and Unicode character. Values are taken to be decimal unless they start with .B 0x (hexadecimal) or .B 0 (octal). The Unicode character can also be represented as .BI ' x where .I x gives the UTF-8 representation of the character (see .IR utf (6)). Entries in the Unicode `private use' area from +U'FD80' to +U'FDFF' might have special meaning to some keyboard drivers and should not be mapped (or remapped) lightly. .SH "SEE ALSO" .IR cons (3), .IR keyboard (6), .IR utf (6) .SH SOURCE .B /sys/src/9/port/devkbmap.c nicode character. Values are taken to be decimal unless they start ./readme 644 0 0 3550 7417636236 5343 This implements /dev/kbmap, to allow the keyboard map to be changed. Based on C H Forsyth's work [see end]. Latin-1 support added by: Boyd Roberts RESTRICTIONS i've currently modified only the /sys/src/9/pc/kbd.c driver to support kbmap's interface. partly because of that, the declarations for the interface routines are in /sys/src/9/pc/fns.h instead of /sys/src/9/port/portfns.h. my use of values in the Unicode private use area to encode certain `Special' keys in the driver might not be the best approach. arguably kbmap might become a kbdctl device in devcons.c INSTALLATION cp port/devkbmap.c /sys/src/9/port cp man/kbmap /sys/man/3 cp pc/kbd.c /sys/src/9/pc add the following lines to /sys/src/9/pc/fns.h: int kbdgetmap(int, int*, int*, Rune*); void kbdputmap(ushort, ushort, Rune); put them after: void kbdinit(void); CONFIGURATION add the line kbmap κ to /sys/src/9/port/master for kernels in which you'd like to configure the driver. The device character is 03BA *k κ greek small letter kappa by the way. Rebuild and install the kernels (be sensible and save the previous copy). USE To configure a UK keyboard, I run the following script: echo 0 43 ''''^'#' echo 1 43 ''''^'~' echo 1 3 ''''^'"' echo 1 4 ''''^£ echo 1 40 ''''^'@' echo 0 86 ''''\ echo 1 86 ''''^'|' with output redirected to #κ/kbmap . Note that a write must send complete records, so cp '#κ/kbmap' /tmp/kbmap cp /tmp/kbmap 'κ/kbmap' won't work because one of the lines is split across writes. Tables: 0 unshifted 1 shifted 2 e0 x or e0 e1 x it's possible the latter table should be split in two. if you haven't a table of scan codes to hand, you can try cat /dev/klog& and then type keys. the hex value of any unrecognised code (one mapped to 0) will be printed in /dev/klog. C H Forsyth forsyth@plan9.cs.york.ac.uk Mon Sep 23 14:57:41 BST 1996 a write must send complete records, so cp '#κ/kbmap' /tmp/kbmap cp /tmp/kbmap 'κ/kbmap' won't work because one of the lines is split across writes.