]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/aux/kbdfs/kbdfs.c
kbdfs: add shift+altgr table 7 for polish keymaps
[plan9front.git] / sys / src / cmd / aux / kbdfs / kbdfs.c
index 55e3270a1c6f8630b302e2ae80748586e50e14d9..c4dd3362a9ad30c5d3dd7e335c708e120f96297f 100644 (file)
@@ -11,6 +11,7 @@ enum {
 
        Qroot=  0,
        Qkbd,
+       Qkbdin,
        Qkbin,
        Qkbmap,
        Qcons,
@@ -28,9 +29,8 @@ typedef struct Scan Scan;
 
 struct Key {
        int     down;
-       int     c;
-       Rune    r;
-       Rune    b;
+       Rune    b;      /* button, unshifted key */
+       Rune    r;      /* rune, shifted key */
 };
 
 struct Scan {
@@ -58,6 +58,10 @@ struct Qtab {
                0600,
                0,
 
+       "kbdin",
+               0200,
+               0,
+
        "kbin",
                0200,   
                0,
@@ -85,14 +89,20 @@ char Ewalk[] = "walk in non directory";
 char Ephase[] = "the front fell off";
 char Eintr[] = "interrupted";
 
-int scanfd;
-int ledsfd;
-int consfd;
-int mctlfd;
+int kbdifd = -1;
+int scanfd = -1;
+int ledsfd = -1;
+int consfd = -1;
+int mctlfd = -1;
+int msinfd = -1;
+int notefd = -1;
+int killfd = -1;
 
 int kbdopen;
 int consctlopen;
 int quiet = 0;
+char *sname = nil;
+char *mntpt = "/dev";
 
 int debug;
 
@@ -108,6 +118,7 @@ Channel *runechan;  /* chan(Rune) */
 
 Channel *conschan;     /* chan(char*) */
 Channel *kbdchan;      /* chan(char*) */
+Channel *intchan;      /* chan(int) */
 
 /*
  * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard.
@@ -123,7 +134,7 @@ Rune kbtab[Nscan] =
 [0x28] '\'',   '`',    Kshift, '\\',   'z',    'x',    'c',    'v',
 [0x30] 'b',    'n',    'm',    ',',    '.',    '/',    Kshift, '*',
 [0x38] Kalt,   ' ',    Kctl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
-[0x40] KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,        '7',
+[0x40] KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,'7',
 [0x48] '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
 [0x50] '2',    '3',    '0',    '.',    0,      0,      0,      KF|11,
 [0x58] KF|12,  0,      0,      0,      0,      0,      0,      0,
@@ -143,14 +154,14 @@ Rune kbtabshift[Nscan] =
 [0x28] '"',    '~',    Kshift, '|',    'Z',    'X',    'C',    'V',
 [0x30] 'B',    'N',    'M',    '<',    '>',    '?',    Kshift, '*',
 [0x38] Kalt,   ' ',    Kctl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
-[0x40] KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,        '7',
+[0x40] KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Knum,   Kscroll,'7',
 [0x48] '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
 [0x50] '2',    '3',    '0',    '.',    0,      0,      0,      KF|11,
 [0x58] KF|12,  0,      0,      0,      0,      0,      0,      0,
 [0x60] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x68] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x70] 0,      0,      0,      0,      0,      0,      0,      0,
-[0x78] 0,      Kup,    0,      Kup,    0,      0,      0,      0,
+[0x78] 0,      Kdown,  0,      Kup,    0,      0,      0,      0,
 };
 
 Rune kbtabesc1[Nscan] =
@@ -160,12 +171,52 @@ Rune kbtabesc1[Nscan] =
 [0x10] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x18] 0,      0,      0,      0,      '\n',   Kctl,   0,      0,
 [0x20] 0,      0,      0,      0,      0,      0,      0,      0,
-[0x28] 0,      0,      Kshift, 0,      0,      0,      0,      0,
+[0x28] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x30] 0,      0,      0,      0,      0,      '/',    0,      Kprint,
 [0x38] Kaltgr, 0,      0,      0,      0,      0,      0,      0,
 [0x40] 0,      0,      0,      0,      0,      0,      Kbreak, Khome,
 [0x48] Kup,    Kpgup,  0,      Kleft,  0,      Kright, 0,      Kend,
-[0x50] Kdown,  Kpgdown,        Kins,   Kdel,   0,      0,      0,      0,
+[0x50] Kdown,  Kpgdown,Kins,   Kdel,   0,      0,      0,      0,
+[0x58] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x60] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x68] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x70] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x78] 0,      Kup,    0,      0,      0,      0,      0,      0,
+};
+
+Rune kbtabshiftesc1[Nscan] =
+{
+[0x00] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x08] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x10] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x18] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x20] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x28] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x30] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x38] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x40] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x48] Kup,    0,      0,      0,      0,      0,      0,      0,
+[0x50] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x58] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x60] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x68] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x70] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x78] 0,      Kup,    0,      0,      0,      0,      0,      0,
+};
+
+Rune kbtabctrlesc1[Nscan] =
+{
+[0x00] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x08] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x10] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x18] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x20] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x28] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x30] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x38] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x40] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x48] Kup,    0,      0,      0,      0,      0,      0,      0,
+[0x50] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x58] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x60] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x68] 0,      0,      0,      0,      0,      0,      0,      0,
@@ -185,7 +236,7 @@ Rune kbtabaltgr[Nscan] =
 [0x38] Kaltgr, 0,      0,      0,      0,      0,      0,      0,
 [0x40] 0,      0,      0,      0,      0,      0,      Kbreak, Khome,
 [0x48] Kup,    Kpgup,  0,      Kleft,  0,      Kright, 0,      Kend,
-[0x50] Kdown,  Kpgdown,        Kins,   Kdel,   0,      0,      0,      0,
+[0x50] Kdown,  Kpgdown,Kins,   Kdel,   0,      0,      0,      0,
 [0x58] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x60] 0,      0,      0,      0,      0,      0,      0,      0,
 [0x68] 0,      0,      0,      0,      0,      0,      0,      0,
@@ -213,7 +264,69 @@ Rune kbtabctl[Nscan] =
 [0x78] 0,      '\a',    0,      '\b',   0,      0,      0,      0,
 };
 
-void reboot(void);
+Rune kbtabshiftaltgr[Nscan] =
+{
+[0x00] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x08] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x10] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x18] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x20] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x28] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x30] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x38] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x40] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x48] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x50] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x58] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x60] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x68] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x70] 0,      0,      0,      0,      0,      0,      0,      0,
+[0x78] 0,      0,      0,      0,      0,      0,      0,      0,
+};
+
+char*
+dev(char *file)
+{
+       static char *buf = nil;
+       free(buf);
+       buf = smprint("%s/%s", mntpt, file);
+       return buf;
+}
+
+int
+eopen(char *name, int mode)
+{
+       int fd;
+
+       fd = open(name, mode);
+       if(fd < 0 && !quiet)
+               fprint(2, "%s: warning: can't open %s: %r\n", argv0, name);
+       return fd;
+}
+
+void
+reboot(void)
+{
+       int fd;
+
+       if(debug)
+               return;
+
+       if((fd = eopen(dev("reboot"), OWRITE)) < 0)
+               return;
+       fprint(fd, "reboot\n");
+       close(fd);
+}
+
+void
+shutdown(void)
+{
+       if(notefd >= 0)
+               write(notefd, "hangup", 6);
+       if(killfd >= 0)
+               write(killfd, "hangup", 6);
+       threadexitsall(nil);
+}
 
 /*
  * Scan code processing
@@ -224,50 +337,51 @@ kbdputsc(Scan *scan, int c)
        Key key;
 
        /*
-        *  e0's is the first of a 2 character sequence, e1 the first
+        *  e0's is the first of a 2 character sequence, e1 and e2 the first
         *  of a 3 character sequence (on the safari)
         */
-       if(c == 0xe0){
-               scan->esc1 = 1;
+       if(scan->esc2){
+               scan->esc2--;
                return;
-       } else if(c == 0xe1){
+       } else if(c == 0xe1 || c == 0xe2){
                scan->esc2 = 2;
                return;
+       } else if(c == 0xe0){
+               scan->esc1 = 1;
+               return;
        }
 
        key.down = (c & 0x80) == 0;
-       key.c = c & 0x7f;
+       c &= 0x7f;
 
-       if(key.c >= Nscan)
+       if(c >= Nscan)
                return;
 
-       if(scan->esc1)
-               key.r = kbtabesc1[key.c];
+       /* qemu workarround: emulate e0 for numpad */
+       if(c != 0 && strchr("GHIKMOPQRS", c) != nil)
+               scan->esc1 |= !scan->num;
+
+       if(scan->esc1 && scan->ctl && kbtabctrlesc1[c] != 0)
+               key.r = kbtabctrlesc1[c];
+       else if(scan->esc1 && scan->shift && kbtabshiftesc1[c] != 0)
+               key.r = kbtabshiftesc1[c];
+       else if(scan->esc1)
+               key.r = kbtabesc1[c];
+       else if(scan->shift && scan->altgr && kbtabshiftaltgr[c] != 0)
+               key.r = kbtabshiftaltgr[c];
        else if(scan->shift)
-               key.r = kbtabshift[key.c];
+               key.r = kbtabshift[c];
        else if(scan->altgr)
-               key.r = kbtabaltgr[key.c];
+               key.r = kbtabaltgr[c];
        else if(scan->ctl)
-               key.r = kbtabctl[key.c];
+               key.r = kbtabctl[c];
        else
-               key.r = kbtab[key.c];
+               key.r = kbtab[c];
 
-       switch(key.r){
-       case Spec|0x60:
-               key.r = Kshift;
-               break;
-       case Spec|0x62:
-               key.r = Kctl;
-               break;
-       case Spec|0x63:
-               key.r = Kalt;
-               break;
-       }
-
-       if(scan->esc1)
+       if(scan->esc1 || kbtab[c] == 0)
                key.b = key.r;
        else
-               key.b = kbtab[key.c];
+               key.b = kbtab[c];
 
        if(scan->caps && key.r<='z' && key.r>='a')
                key.r += 'A' - 'a';
@@ -275,12 +389,8 @@ kbdputsc(Scan *scan, int c)
        if(scan->ctl && scan->alt && key.r == Kdel)
                reboot();
 
-       send(keychan, &key);
-
-       if(scan->esc1)
-               scan->esc1 = 0;
-       else if(scan->esc2)
-               scan->esc2--;
+       if(key.b)
+               send(keychan, &key);
 
        switch(key.r){
        case Kshift:
@@ -302,6 +412,82 @@ kbdputsc(Scan *scan, int c)
                scan->caps ^= key.down;
                break;
        }
+       scan->esc1 = 0;
+}
+
+static void
+kbdin(Scan *a, char *p, int n)
+{
+       char *s;
+       Key k;
+       int i;
+
+       if(n > 0 && p[n-1] != 0){
+               /*
+                * old format as used by bitsy keyboard:
+                * just a string of characters, no keyup
+                * information.
+                */
+               s = emalloc9p(n+1);
+               memmove(s, p, n);
+               s[n] = 0;
+               p = s;
+               while(*p){
+                       p += chartorune(&k.r, p);
+                       if(k.r)
+                               send(rawchan, &k.r);
+               }
+               free(s);
+               return;
+       }
+Nextmsg:
+       if(n < 2)
+               return;
+       switch(p[0]){
+       case 'R':
+       case 'r':
+               /* rune up/down */
+               chartorune(&k.r, p+1);
+               if(k.r == 0)
+                       break;
+               k.b = k.r;
+               k.down = (p[0] == 'r');
+               /*
+                * assign button according to keymap.
+                */
+               for(i=0; i<Nscan; i++){
+                       if((a->shift && kbtabshift[i] == k.r) || (kbtab[i] == k.r)){
+                               if(kbtab[i])
+                                       k.b = kbtab[i];
+                               break;
+                       }
+               }
+               send(keychan, &k);
+               if(k.r == Kshift)
+                       a->shift = k.down;
+               else if(k.r == Kaltgr)
+                       a->altgr = k.down;
+               else if(k.r == Kctl)
+                       a->ctl = k.down;
+               break;
+
+       case 'c':
+               chartorune(&k.r, p+1);
+               nbsend(runechan, &k.r);
+               break;
+
+       default:
+               if(!kbdopen)
+                       break;
+               i = strlen(p)+1;
+               s = emalloc9p(i);
+               memmove(s, p, i);
+               if(nbsendp(kbdchan, s) <= 0)
+                       free(s);
+       }
+       i = strlen(p)+1;
+       n -= i, p += i;
+       goto Nextmsg;
 }
 
 void
@@ -335,6 +521,24 @@ scanproc(void *)
                        kbdputsc(&scan, buf[i]);
                setleds(&scan, (scan.num<<1) | (scan.caps<<2));
        }
+
+       shutdown();
+}
+
+void
+kbdiproc(void *)
+{
+       char buf[1024];
+       Scan scan;
+       int n;
+
+       threadsetname("kbdiproc");
+
+       memset(&scan, 0, sizeof scan);
+       while((n = read(kbdifd, buf, sizeof buf)) > 0)
+               kbdin(&scan, buf, n);
+
+       shutdown();
 }
 
 char*
@@ -353,62 +557,64 @@ utfconv(Rune *r, int n)
 
 /*
  * Read key events from keychan and produce characters to
- * rawchan and keystate in kbdchan. this way here is only
- * one global keystate even if multiple keyboards are used.
+ * rawchan and keystate in kbdchan.
  */
 void
 keyproc(void *)
 {
-       Rune rb[Nscan*2+1];
-       int cb[Nscan];
+       Rune rb[Nscan+1];
        Key key;
-       int i, nb;
+       int i, nb, mouseb;
        char *s;
 
        threadsetname("keyproc");
 
        nb = 0;
+       mouseb = 0;
        while(recv(keychan, &key) > 0){
-               if(key.down && key.r)
-                       send(rawchan, &key.r);
+               if(msinfd >= 0 && key.r >= Kmouse+1 && key.r <= Kmouse+5){
+                       i = 1<<(key.r-(Kmouse+1));
+                       if(key.down)
+                               mouseb |= i;
+                       else
+                               mouseb &= ~i;
+                       fprint(msinfd, "m%11d %11d %11d", 0, 0, mouseb);
+                       continue; /* ignored when mapped to mouse button */
+               }
 
                rb[0] = 0;
-               for(i=0; i<nb && cb[i] != key.c; i++)
+               for(i=0; i<nb && rb[i+1] != key.b; i++)
                        ;
                if(!key.down){
-                       while(i < nb && cb[i] == key.c){
-                               memmove(cb+i, cb+i+1, (nb-i+1) * sizeof(cb[0]));
+                       while(i < nb && rb[i+1] == key.b){
                                memmove(rb+i+1, rb+i+2, (nb-i+1) * sizeof(rb[0]));
                                nb--;
                                rb[0] = 'K';
                        }
-               } else if(i == nb && nb < nelem(cb) && key.b){
-                       cb[nb] = key.c;
-                       rb[nb+1] = key.b;
-                       nb++;
-                       if(nb < nelem(cb) && key.r && key.b != key.r){
-                               cb[nb] = key.c;
-                               rb[nb+1] = key.r;
-                               nb++;
-                       }
+               } else if(i == nb && nb < nelem(rb)-1 && key.b){
+                       rb[++nb] = key.b;
                        rb[0] = 'k';
                }
                if(rb[0]){
-                       if(key.r == Kshift && mctlfd >= 0){
-                               if(key.down){
-                                       fprint(mctlfd, "buttonmap 132");
-                               } else {
-                                       fprint(mctlfd, "swap");
-                                       fprint(mctlfd, "swap");
-                               }
-                       }
-
                        if(kbdopen){
                                s = utfconv(rb, nb+1);
                                if(nbsendp(kbdchan, s) <= 0)
                                        free(s);
                        }
+                       if(mctlfd >= 0){
+                               if(key.r == Kshift){
+                                       if(key.down){
+                                               fprint(mctlfd, "buttonmap 132");
+                                       } else {
+                                               fprint(mctlfd, "swap");
+                                               fprint(mctlfd, "swap");
+                                       }
+                               }
+                               fprint(mctlfd, "twitch");
+                       }
                }
+               if(key.down && key.r)
+                       send(rawchan, &key.r);
        }
 }
 
@@ -447,6 +653,8 @@ consproc(void *)
                memmove(buf, p, n);
                p = buf + n;
        }
+
+       shutdown();
 }
 
 static int
@@ -517,22 +725,22 @@ Forward:
                if(nextrune(rawchan, &r))
                        continue;
 
-               if(r == 'X'){
+               if(r == 'x' || r == 'X'){
+                       i = (r == 'X') ? 4 : 6;
                        r = 0;
-                       for(i = 0; i<4; i++){
+                       do {
                                if(nextrune(rawchan, &rr))
                                        break;
-                               r <<= 4;
                                if(rr >= '0' && rr <= '9')
-                                       r |= (rr - '0');
+                                       r = (r << 4) | (rr - '0');
                                else if(rr >= 'a' && rr <= 'f')
-                                       r |= 10 + (rr - 'a');
+                                       r = (r << 4) | (10 + (rr - 'a'));
                                else if(rr >= 'A' && rr <= 'F')
-                                       r |= 10 + (rr - 'A');
+                                       r = (r << 4) | (10 + (rr - 'A'));
                                else
                                        break;
-                       }
-                       if(i == 4 && r)
+                       } while(--i > 0);
+                       if((i == 0 || rr == ';') && r != 0 && r <= Runemax)
                                goto Forward;
                } else {
                        if(nextrune(rawchan, &rr))
@@ -559,6 +767,21 @@ Forward:
        }
 }
 
+/*
+ * Need to do this in a separate proc because if process we're interrupting
+ * is dying and trying to print tombstone, kernel is blocked holding p->debug lock.
+ */
+void
+intrproc(void *)
+{
+       threadsetname("intrproc");
+
+       for(;;){
+               if(recv(intchan, nil) > 0)
+                       write(notefd, "interrupt", 9);
+       }
+}
+
 /*
  * Cook lines for cons
  */
@@ -580,6 +803,10 @@ lineproc(void *aux)
                do {
                        recv(cook, &r);
                        switch(r){
+                       case Kdel:
+                               if(nbsend(intchan, &notefd) <= 0)
+                                       continue;
+                               /* no break */
                        case '\0':      /* flush */
                                nr = 0;
                                continue;
@@ -624,10 +851,11 @@ reqproc(void *aux)
        Channel **ac;
        Req *r, *q, **qq;
        char *s, *p, *e;
-       int n;
+       int n, m;
 
        threadsetname("reqproc");
 
+       e = nil;
        s = nil;
        p = nil;
 
@@ -645,7 +873,7 @@ reqproc(void *aux)
        a[AEND].op = CHANEND;
 
        for(;;){
-               a[ASTR].op = s ? CHANNOP : CHANRCV;
+               a[ASTR].op = s != nil ? CHANNOP : CHANRCV;
 
                switch(alt(a)){
                case AREQ:
@@ -676,27 +904,38 @@ reqproc(void *aux)
                                p = s;
                        }
 
-                       while(s && q){
+                       while(s != nil && q != nil){
                                r = q;
                                if((q = q->aux) == nil)
                                        qq = &q;
-
-                               e = s + strlen(s);
-                               if(p == s && r->fid->qid.path == Qkbd)
-                                       e++; /* send terminating \0 if its kbd file */
+                               r->ofcall.count = 0;
+                               if(s == p){
+                               More:
+                                       e = s + strlen(s);
+                                       if(r->fid->qid.path == Qkbd)
+                                               e++; /* send terminating \0 if its kbd file */
+                               }
                                n = e - p;
-                               if(n > r->ifcall.count)
-                                       n = r->ifcall.count;
-
-                               r->ofcall.count = n;
-                               memmove(r->ofcall.data, p, n);
-                               respond(r, nil);
-
+                               m = r->ifcall.count - r->ofcall.count;
+                               if(n > m){
+                                       if(r->ofcall.count > 0){
+                                               respond(r, nil);
+                                               continue;
+                                       }
+                                       n = m;
+                               }
+                               memmove((char*)r->ofcall.data + r->ofcall.count, p, n);
+                               r->ofcall.count += n;
                                p += n;
                                if(p >= e){
                                        free(s);
-                                       s = nil;
+                                       s = nbrecvp(a[ASTR].c);
+                                       if(s != nil){
+                                               p = s;
+                                               goto More;
+                                       }
                                }
+                               respond(r, nil);
                        }
                }
        }
@@ -718,10 +957,14 @@ ctlproc(void *)
 
        threadsetname("ctlproc");
 
+       if(kbdifd >= 0)
+               proccreate(kbdiproc, nil, STACK);       /* kbdifd -> kbdin() */
        if(scanfd >= 0)
                proccreate(scanproc, nil, STACK);       /* scanfd -> keychan */
        if(consfd >= 0)
                proccreate(consproc, nil, STACK);       /* consfd -> runechan */
+       if(notefd >= 0)
+               proccreate(intrproc, nil, STACK);       /* intchan -> notefd */
 
        threadcreate(keyproc, nil, STACK);              /* keychan -> rawchan, kbdchan */
        threadcreate(runeproc, nil, STACK);             /* rawchan -> runechan */
@@ -790,22 +1033,19 @@ ctlproc(void *)
 Rune*
 kbmapent(int t, int sc)
 {
-       if(sc < 0 || sc >= Nscan)
-               return nil;
-       switch(t){
-       default:
-               return nil;
-       case 0:
-               return &kbtab[sc];
-       case 1:
-               return &kbtabshift[sc];
-       case 2:
-               return &kbtabesc1[sc];
-       case 3:
-               return &kbtabaltgr[sc];
-       case 4:
-               return &kbtabctl[sc];
-       }
+       static Rune *tabs[] = { 
+       /* 0 */ kbtab,
+       /* 1 */ kbtabshift,
+       /* 2 */ kbtabesc1,
+       /* 3 */ kbtabaltgr,
+       /* 4 */ kbtabctl,
+       /* 5 */ kbtabctrlesc1,
+       /* 6 */ kbtabshiftesc1,
+       /* 7 */ kbtabshiftaltgr,
+       };
+       if(t >= 0 && t < nelem(tabs) && sc >= 0 && sc < Nscan)
+               return &tabs[t][sc];
+       return nil;
 }
 
 void
@@ -830,6 +1070,18 @@ kbmapread(Req *req)
        respond(req, nil);
 }
 
+Rune
+kbcompat(Rune r)
+{
+       static Rune o = Spec|0x60, tab[] = {
+               Kshift, Kbreak, Kctl, Kalt,
+               Kcaps, Knum, Kmiddle, Kaltgr,
+       };
+       if(r >= o && r < o+nelem(tab))
+               return tab[r - o];
+       return r;
+}
+
 void
 kbmapwrite(Req *req)
 {
@@ -880,12 +1132,12 @@ kbmapwrite(Req *req)
                                else
                                        goto Badarg;
                        }else if(*lp == 'M' && ('1' <= lp[1] && lp[1] <= '5'))
-                               r = 0xF900+lp[1]-'0';
+                               r = Kmouse+lp[1]-'0';
                        else if(*lp>='0' && *lp<='9') /* includes 0x... */
                                r = strtoul(lp, &lp, 0);
                        else
                                goto Badarg;
-                       *rp = r;
+                       *rp = kbcompat(r);
                        lp = line;
                }
        }
@@ -1086,23 +1338,21 @@ fswrite(Req *r)
        int n, i;
 
        f = r->fid;
+       p = r->ifcall.data;
+       n = r->ifcall.count;
        switch((ulong)f->qid.path){
        default:
                respond(r, Ephase);
                return;
 
        case Qcons:
-               n = r->ifcall.count;
-               if(write(1, r->ifcall.data, n) != n){
+               if(write(1, p, n) != n){
                        responderror(r);
                        return;
                }
-               r->ofcall.count = n;
                break;
 
        case Qconsctl:
-               p = r->ifcall.data;
-               n = r->ifcall.count;
                if(n >= 5 && memcmp(p, "rawon", 5) == 0)
                        sendul(ctlchan, Rawon);
                else if(n >= 6 && memcmp(p, "rawoff", 6) == 0)
@@ -1111,17 +1361,22 @@ fswrite(Req *r)
                        respond(r, Ebadarg);
                        return;
                }
-               r->ofcall.count = n;
                break;
 
        case Qkbin:
+       case Qkbdin:
+               if(n == 0)
+                       break;
                if(f->aux == nil){
                        f->aux = emalloc9p(sizeof(Scan));
                        memset(f->aux, 0, sizeof(Scan));
                }
-               for(i=0; i<r->ifcall.count; i++)
-                       kbdputsc((Scan*)f->aux, (uchar)r->ifcall.data[i]);
-               r->ofcall.count = i;
+               if(f->qid.path == Qkbin){
+                       for(i=0; i<n; i++)
+                               kbdputsc((Scan*)f->aux, (uchar)p[i]);
+               } else {
+                       kbdin((Scan*)f->aux, p, n);
+               }
                break;
 
        case Qkbmap:
@@ -1129,6 +1384,7 @@ fswrite(Req *r)
                return;
 
        }
+       r->ofcall.count = n;
        respond(r, nil);
 }
 
@@ -1153,6 +1409,7 @@ fsdestroyfid(Fid *f)
 
        if(f->omode != -1)
                switch((ulong)f->qid.path){
+               case Qkbdin:
                case Qkbin:
                case Qkbmap:
                        if(p = f->aux){
@@ -1170,61 +1427,25 @@ fsdestroyfid(Fid *f)
                }
 }
 
-static void
-fsend(Srv*)
-{
-       threadexitsall(nil);
-}
-
-Srv fs = {
-       .attach=                        fsattach,
-       .walk1=                 fswalk1,
-       .open=                  fsopen,
-       .read=                  fsread,
-       .write=                 fswrite,
-       .stat=                  fsstat,
-       .flush=                 fsflush,
-       .destroyfid=            fsdestroyfid,
-       .end=                   fsend,
-};
-
-int
-eopen(char *name, int mode)
-{
-       int fd;
-
-       fd = open(name, mode);
-       if(fd < 0 && !quiet)
-               fprint(2, "%s: warning: can't open %s: %r\n", argv0, name);
-       return fd;
-}
-
-void
-reboot(void)
+static int
+procopen(int pid, char *name, int mode)
 {
-       int fd;
-
-       if(debug)
-               return;
+       char buf[128];
 
-       if((fd = eopen("/dev/reboot", OWRITE)) < 0)
-               return;
-       fprint(fd, "reboot\n");
-       close(fd);
+       snprint(buf, sizeof(buf), "/proc/%d/%s", pid, name);
+       return eopen(buf, mode);
 }
 
-void
+static void
 elevate(void)
 {
-       char buf[128];
        Dir *d, nd;
        int fd;
 
        if(debug)
                return;
 
-       snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
-       if((fd = eopen(buf, OWRITE)) < 0)
+       if((fd = procopen(getpid(), "ctl", OWRITE)) < 0)
                return;
 
        /* get higher than normal priority */
@@ -1244,21 +1465,43 @@ elevate(void)
        close(fd);
 }
 
+static void
+fsstart(Srv*)
+{
+       killfd = procopen(getpid(), "notepg", OWRITE);
+       elevate();
+       proccreate(ctlproc, nil, STACK);
+}
+
+static void
+fsend(Srv*)
+{
+       shutdown();
+}
+
+Srv fs = {
+       .start=                 fsstart,
+       .attach=                fsattach,
+       .walk1=                 fswalk1,
+       .open=                  fsopen,
+       .read=                  fsread,
+       .write=                 fswrite,
+       .stat=                  fsstat,
+       .flush=                 fsflush,
+       .destroyfid=            fsdestroyfid,
+       .end=                   fsend,
+};
+
 void
 usage(void)
 {
-       fprint(2, "usage: %s [ -qdD ] [ -s srv ] [ -m mntpnt ] [ file ]\n", argv0);
+       fprint(2, "usage: %s [ -qdD ] [ -s sname ] [ -m mntpnt ] [ file ]\n", argv0);
        exits("usage");
 }
 
 void
 threadmain(int argc, char** argv)
 {
-       char *mtpt = "/dev";
-       char *srv = nil;
-
-       consfd = -1;
-
        ARGBEGIN{
        case 'd':
                debug++;
@@ -1267,10 +1510,10 @@ threadmain(int argc, char** argv)
                chatty9p++;
                break;
        case 's':
-               srv = EARGF(usage());
+               sname = EARGF(usage());
                break;
        case 'm':
-               mtpt = EARGF(usage());
+               mntpt = EARGF(usage());
                break;
        case 'q':
                quiet++;
@@ -1279,13 +1522,19 @@ threadmain(int argc, char** argv)
                usage();
        }ARGEND
 
-       scanfd = eopen("/dev/scancode", OREAD);
-       ledsfd = eopen("/dev/leds", OWRITE);
-       mctlfd = eopen("/dev/mousectl", OWRITE);
-
        if(*argv)
                consfd = eopen(*argv, OREAD);
 
+       kbdifd = open(dev("kbd"), OREAD);
+       if(kbdifd < 0){
+               scanfd = eopen(dev("scancode"), OREAD);
+               ledsfd = eopen(dev("leds"), OWRITE);
+               mctlfd = eopen(dev("mousectl"), OWRITE);
+               msinfd = eopen(dev("mousein"), OWRITE);
+       }
+
+       notefd = procopen(getpid(), "notepg", OWRITE);
+
        consreqchan = chancreate(sizeof(Req*), 0);
        kbdreqchan = chancreate(sizeof(Req*), 0);
 
@@ -1295,8 +1544,8 @@ threadmain(int argc, char** argv)
        runechan = chancreate(sizeof(Rune), 32);
        conschan = chancreate(sizeof(char*), 16);
        kbdchan = chancreate(sizeof(char*), 16);
+       intchan = chancreate(sizeof(int), 0);
 
-       elevate();
-       procrfork(ctlproc, nil, STACK, RFNAMEG|RFNOTEG);
-       threadpostmountsrv(&fs, srv, mtpt, MBEFORE);
+       threadpostmountsrv(&fs, sname, mntpt, MBEFORE);
+       threadexits(0);
 }