ref: 69352f66684cbc75e2cd68c80cd028324964c5aa
parent: 79c1842979b5c5579bb0db41861d63f5562c85f1
author: Jacob Moody <moody@posixcafe.org>
date: Sun Aug 14 23:45:42 EDT 2022
ktrans: tow inside the environment
--- /dev/null
+++ b/sys/man/1/ktrans
@@ -1,0 +1,117 @@
+.TH KTRANS 1
+.SH NAME
+ktrans \- language transliterator
+.SH SYNOPSIS
+.B ktrans
+[
+.B -t
+.I kbdtap
+]
+[
+.B -l
+.I lang
+]
+.SH DESCRIPTION
+.I Ktrans
+provides a transliteration layer
+to keyboard input through reads and
+writes to
+.BR /dev/kbdtap .
+The
+.B -t
+flag changes the
+.I kbdtap
+file used. The
+.B -l
+flag changes the initial
+language.
+.SH CONVERSION
+Conversion is done in two steps: An implicit layer
+that is used for direct mappings between ascii characters and
+an explicit multi rune conversion used for compound mappings.
+.I Ktrans
+does implicit conversion by passing through characters
+as they are input. Then when a sequence of input is matched,
+backspaces are emitted to clear the input sequence and the matched
+rune sequence is emitted. The last 'word' of input may be then
+explicitely transliterated by typing ctrl-\\. A newline character also
+performs this lookup, but additional newline characters will not
+cycle through alternatives.
+.SH CONTROL
+The language is selected by typing a control character:
+.TP
+.B ctl-t
+Passthrough mode
+.TP
+.B ctl-n
+Japanese mode. Implicit layer converts hepburn sequences to hiragana. Explicit
+layer converts sequences of hiragana with optional trailing particle or okurigana.
+.TP
+.B ctl-k
+Implicit only Japanese Katakana layer.
+.TP
+.B ctrl-c
+Chinese Wubi mode. No implicit conversion is done. Explicit layer
+converts sequences of latin characters to hanzi.
+.TP
+.B ctl-l
+Clear the explicit layer's current input sequence.
+.TP
+.B ctl-r
+Russian mode. Implicit layer converts latin to Cyrillic; the transliteration is mostly
+phonetic, with
+.B '
+for
+.IR myagkij-znak
+(ь),
+.B ''
+for
+.I tverdyj-znak
+(ъ)
+.I yo
+for ё,
+.B j
+for
+.IR i-kratkaya
+(й).
+.TP
+.B ctl-o
+Greek mode.
+.TP
+.B ctl-s
+Korean mode. Implicit layer converts latin to Korean Hangul.
+.SH SOURCE
+.B /sys/src/cmd/ktrans
+.SH SEE ALSO
+.IR rio (4)
+.IR kbdfs (8)
+.br
+.IR /sys/src/cmd/ktrans/README.kenji
+.br
+.IR /sys/src/cmd/ktrans/READMEJ.kenji
+.SH EXAMPLES
+To type the following Japanese text:
+
+.ft Jp
+私は毎日35分以上歩いて、 更に10分電車に乗って学校に通います。
+ 健康の維持にも役だっていますが、 なかなかたのしいものです。
+.ft
+
+your keyboard typing stream should be:
+
+watashiHA[^\\]mainichi[^\\]35[^l]fun[^\\]ijou[^\\]aruIte,[^\\]
+saraNI[^\\]10[^l]fun[^\\]denshaNI[^\\]noTte[^\\]gakkouNI[^\\]
+kayoImasu.[\\n]kenkouNO[^\\]ijiNImo[^\\]yakuDAtteimasuga,[^\\]
+nakanakatanoshiImonodesu.[\\n]
+
+where [^\\] and [^l] indicate 'ctl-\\' and 'ctl-l',
+respectively. See README.kenji for the details of this Japanese input
+method.
+.SH BUGS
+.PP
+There is no way to generate the control characters literally.
+.SH HISTORY
+Ktrans was originally written by Kenji Okamoto in August of 2000 for
+the 2nd edition of Plan 9. It was imported in to 9front in July of
+2022, with patches by several contributors. It was towed inside
+the environment during the 2022 9front hackathon.
--- a/sys/man/4/ktrans
+++ /dev/null
@@ -1,142 +1,0 @@
-.TH KTRANS 4
-.SH NAME
-ktrans \- language transliterator
-.SH SYNOPSIS
-.B ktrans
-[
-.B -K
-]
-[
-.B -k
-.I kbd
-]
-[
-.B -l
-.I lang
-]
-[
-.B -m
-.I mnt
-]
-.nf
-
-.IB /mnt/ktrans/kbd
-.IB /mnt/ktrans/kbdin
-.IB /mnt/ktrans/lang
-.fi
-.SH DESCRIPTION
-.I ktrans
-is a fileserver that provides a transliteration overlay to
-.IR kbdfs (8).
-When run,
-.I ktrans
-mounts itself to
-.B /mnt/ktrans
-and binds its own
-.B kbd
-and
-.B kbdin
-files over those present in
-.BR /dev .
-.PP
-By default,
-.I ktrans
-also forks and reads input from the existing
-.BR /dev/kbd .
-The
-.B -k
-flag changes which file is read. The
-.B -K
-flag disables this process all together, limiting
-input to only the
-.B kbdin
-file.
-.SH CONVERSION
-Conversion is done in two steps: An implicit layer
-that is used for direct mappings between latin characters and
-an explicit multi rune conversion used for compound mappings.
-.I Ktrans
-does implicit conversion by passing through characters
-as they are input. Then when a sequence of input is matched,
-backspaces are emitted to clear the input sequence and the matched
-rune sequence is emitted. The last 'word' of input may be then
-additionaly transliterated by typing ctrl-\\. A newline character also
-performs this lookup, but additional newline characters will not
-cycle through alternatives.
-.SH CONTROL
-The language is selected by typing a control character:
-.TP
-.B ctl-t
-Passthrough mode
-.TP
-.B ctl-n
-Japanese mode. Implicit layer converts hepburn sequences to hiragana. Explicit
-layer converts sequences of hiragana with optional trailing particle or okurigana.
-.TP
-.B ctl-k
-Implicit only Japanese Katakana layer.
-.TP
-.B ctrl-c
-Chinese Wubi mode. No implicit conversion is done. Explicit layer
-converts sequences of latin characters to hanzi.
-.TP
-.B ctl-l
-Clear the explicit layer's current input sequence.
-.TP
-.B ctl-r
-Russian mode. Implicit layer converts latin to Cyrillic; the transliteration is mostly
-phonetic, with
-.B '
-for
-.IR myagkij-znak
-(ь),
-.B ''
-for
-.I tverdyj-znak
-(ъ)
-.I yo
-for ё,
-.B j
-for
-.IR i-kratkaya
-(й).
-.TP
-.B ctl-o
-Greek mode.
-.TP
-.B ctl-s
-Korean mode. Implicit layer converts latin to Korean Hangul.
-.SH SOURCE
-.B /sys/src/cmd/ktrans
-.SH SEE ALSO
-.IR rio (1)
-.IR kbdfs (8)
-.br
-.IR /sys/src/cmd/ktrans/README.kenji
-.br
-.IR /sys/src/cmd/ktrans/READMEJ.kenji
-.SH EXAMPLES
-To type the following Japanese text:
-
-.ft Jp
-私は毎日35分以上歩いて、 更に10分電車に乗って学校に通います。
- 健康の維持にも役だっていますが、 なかなかたのしいものです。
-.ft
-
-your keyboard typing stream should be:
-
-watashiHA[^\\]mainichi[^\\]35[^l]fun[^\\]ijou[^\\]aruIte,[^\\]
-saraNI[^\\]10[^l]fun[^\\]denshaNI[^\\]noTte[^\\]gakkouNI[^\\]
-kayoImasu.[\\n]kenkouNO[^\\]ijiNImo[^\\]yakuDAtteimasuga,[^\\]
-nakanakatanoshiImonodesu.[\\n]
-
-where [^\\] and [^l] indicate 'ctl-\\' and 'ctl-l',
-respectively. See README.kenji for the details of this Japanese input
-method.
-.SH BUGS
-.PP
-There is no way to generate the control characters literally.
-.SH HISTORY
-Ktrans was originally written by Kenji Okamoto in August of 2000 for
-the 2nd edition of Plan 9. It was imported in to 9front in July of
-2022, with patches by several contributors.
--- a/sys/src/cmd/ktrans/fs.c
+++ /dev/null
@@ -1,401 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <fcall.h>
-#include <thread.h>
-#include <9p.h>
-
-#include "hash.h"
-#include "ktrans.h"
-
-static Channel *globalkbd;
-static char *user;
-
-char*
-parsekbd(Channel *out, char *buf, int n)
-{
- char *p, *e;
- Msg msg;
-
- for(p = buf; p < buf+n;){
- msg.code = p[0];
- p++;
- switch(msg.code){
- case 'c': case 'k': case 'K':
- break;
- default:
- return "malformed kbd message";
- }
- e = utfecpy(msg.buf, msg.buf + sizeof msg.buf, p);
- if(e == msg.buf)
- return "short command";
- p += e - msg.buf;
- p++;
- if(send(out, &msg) == -1)
- return nil;
- }
- return nil;
-}
-
-void
-kbdproc(void *a)
-{
- char *s;
- int fd, n;
- char buf[128];
-
- s = a;
- fd = open(s, OREAD);
- if(fd < 0){
- fprint(2, "could not open file %s: %r", s);
- chanclose(globalkbd);
- return;
- }
- for(;;){
- n = read(fd, buf, sizeof buf);
- if(n < 3){
- continue;
- }
- parsekbd(globalkbd, buf, n);
- }
-}
-
-Trans*
-spawntrans(int global)
-{
- Trans *t;
-
- t = mallocz(sizeof *t, 1);
- if(global)
- t->input = globalkbd;
- else
- t->input = chancreate(sizeof(Msg), 0);
- t->output = chancreate(sizeof(Msg), 0);
- t->dict = chancreate(sizeof(Msg), 0);
- t->done = chancreate(1, 0);
- t->lang = chancreate(sizeof(char*), 0);
- proccreate(keyproc, t, mainstacksize);
- return t;
-}
-
-void
-closetrans(Trans *t)
-{
- chanclose(t->input);
- chanclose(t->output);
- chanclose(t->dict);
-
- /* wait for threads to exit */
- recv(t->done, nil);
- recv(t->done, nil);
-
- chanfree(t->done);
- chanfree(t->input);
- chanfree(t->output);
- chanfree(t->dict);
- free(t);
-}
-
-enum{
- Qroot,
- Qkbd,
- Qkbdin,
- Qlang,
-};
-
-Dir dirtab[] = {
- {.qid={Qroot, 0, QTDIR}, .mode=0555, .name="/"},
- {.qid={Qkbd, 0, QTFILE}, .mode=0600, .name="kbd"},
- {.qid={Qkbdin, 0, QTFILE}, .mode=0200, .name="kbdin"},
- {.qid={Qlang, 0, QTFILE}, .mode=0600, .name="lang"},
-};
-
-static int
-dirgen(int n, Dir *dir, void*)
-{
- n++;
- if(n >= nelem(dirtab))
- return -1;
-
- *dir = dirtab[n];
- dir->name = estrdup9p(dir->name);
- dir->uid = estrdup9p(user);
- dir->gid = estrdup9p(user);
- dir->muid = estrdup9p(user);
- return 0;
-}
-
-typedef struct Aux Aux;
-struct Aux {
- Ref;
- Reqqueue *q;
- Trans *t;
-};
-
-static void
-fsattach(Req *r)
-{
- Aux *aux;
- Trans *t;
- char *aname;
-
- /*
- * Each attach allocates a new "keyboard".
- * The global attach argument denotes to
- * use /dev/kbd as the source of keyboard input.
- *
- * Sessions include one translation
- * process, and one read queue. Since
- * it is common for clients to constantly be
- * blocked on the kbd file, we need to assign it to
- * it's own process so we can service other requests
- * in the meantime.
- */
-
- aname = r->ifcall.aname;
- if(aname != nil && strcmp(aname, "global") == 0)
- t = spawntrans(1);
- else
- t = spawntrans(0);
-
- aux = mallocz(sizeof *aux, 1);
- aux->t = t;
- aux->q = reqqueuecreate();
- incref(aux);
-
- r->fid->aux = aux;
- r->ofcall.qid = dirtab[0].qid;
- r->fid->qid = dirtab[0].qid;
- respond(r, nil);
-}
-
-static void
-fsopen(Req *r)
-{
- respond(r, nil);
-}
-
-static void
-fskbd(Req *r)
-{
- Aux *aux;
- Msg m;
- char *p;
- char buf[1+128], *bp;
- Rune rn;
-
- aux = r->fid->aux;
- if(recv(aux->t->output, &m) == -1){
- respond(r, "closing");
- return;
- }
- if(m.code != 'c'){
- bp = seprint(buf, buf + sizeof buf, "%c%s", m.code, m.buf);
- goto Send;
- }
- p = m.buf;
- bp = buf;
- for(;bp < buf + sizeof buf;){
- p += chartorune(&rn, p);
- if(rn == Runeerror || rn == '\0')
- break;
- bp = seprint(bp, buf + sizeof buf, "c%C", rn);
- bp++;
- }
- if(bp >= buf + sizeof buf){
- while(*bp-- != '\0')
- ;
- bp++;
- }
-
-Send:
- r->ifcall.offset = 0;
- readbuf(r, buf, (bp-buf)+1);
- respond(r, nil);
-}
-
-static void
-fsread(Req *r)
-{
- Aux *aux;
- Msg m;
- char *p;
-
- aux = r->fid->aux;
- switch((uint)r->fid->qid.path){
- case Qroot:
- dirread9p(r, dirgen, nil);
- respond(r, nil);
- break;
- case Qkbd:
-
- reqqueuepush(aux->q, r, fskbd);
- break;
- case Qlang:
- m.code = 'q';
- m.buf[0] = '\0';
- if(send(aux->t->input, &m) == -1){
- respond(r, "closing");
- break;
- }
- if(recv(aux->t->lang, &p) == -1){
- respond(r, "closing");
- break;
- }
- snprint(m.buf, sizeof m.buf, "%s\n", p);
- readstr(r, m.buf);
- respond(r, nil);
- break;
- default:
- respond(r, "bad op");
- break;
- }
-}
-
-static void
-fswrite(Req *r)
-{
- Aux *aux;
- int n, lang;
- char *err, *p;
- Msg m;
-
- aux = r->fid->aux;
- n = r->ifcall.count;
- switch((uint)r->fid->qid.path){
- case Qkbdin:
- if(n < 3){
- respond(r, "short write");
- return;
- }
- err = parsekbd(aux->t->input, r->ifcall.data, n);
- if(err != nil){
- respond(r, err);
- return;
- }
- break;
- case Qlang:
- if(n >= sizeof m.buf){
- respond(r, "large write");
- return;
- }
- memmove(m.buf, r->ifcall.data, n);
- m.buf[n] = '\0';
- p = strchr(m.buf, '\n');
- if(p != nil)
- *p = '\0';
- lang = parselang(m.buf);
- if(lang < 0){
- respond(r, "unkonwn lang");
- return;
- }
- m.buf[0] = lang;
- m.buf[1] = '\0';
- m.code = 'c';
- send(aux->t->input, &m);
- }
- r->ofcall.count = n;
- respond(r, nil);
-}
-
-static void
-fsstat(Req *r)
-{
- if(dirgen(r->fid->qid.path - 1, &r->d, nil) == -1)
- respond(r, "invalid fid");
- else
- respond(r, nil);
-
-}
-
-static char*
-fswalk1(Fid *fid, char *name, Qid *qid)
-{
- int i;
-
- if(fid->qid.path != Qroot)
- return "walk from non root";
-
- for(i = 0; i < nelem(dirtab); i++)
- if(strcmp(name, dirtab[i].name) == 0){
- *qid = dirtab[i].qid;
- break;
- }
-
- if(i == nelem(dirtab))
- return "file does not exist";
-
- fid->qid = *qid;
- return nil;
-}
-
-static char*
-fsclone(Fid *oldfid, Fid *newfid)
-{
- Aux *aux;
-
- aux = oldfid->aux;
- incref(aux);
- newfid->aux = aux;
-
- return nil;
-}
-
-static void
-fidclunk(Fid *fid)
-{
- Aux *aux;
-
- aux = fid->aux;
- if(decref(aux) != 0)
- return;
-
- closetrans(aux->t);
- reqqueuefree(aux->q);
-}
-
-
-static Srv fs = {
- .attach=fsattach,
- .open=fsopen,
- .read=fsread,
- .write=fswrite,
- .stat=fsstat,
-
- .walk1=fswalk1,
- .clone=fsclone,
- .destroyfid=fidclunk,
-};
-
-void
-launchfs(char *srv, char *mnt, char *kbd)
-{
- int fd;
- char buf[128];
-
- user = getenv("user");
- if(user == nil)
- user = "glenda";
- if(kbd != nil){
- globalkbd = chancreate(sizeof(Msg), 0);
- proccreate(kbdproc, kbd, mainstacksize);
- }
-
- fd = threadpostsrv(&fs, srv);
- if(fd < 0)
- sysfatal("postsrv %r");
-
- if(kbd != nil){
- if(mount(fd, -1, mnt, MREPL, "global") < 0)
- sysfatal("mount %r");
-
- snprint(buf, sizeof buf, "%s/kbd", mnt);
- if(bind(buf, "/dev/kbd", MREPL) < 0)
- sysfatal("bind %r");
-
- snprint(buf, sizeof buf, "%s/kbdin", mnt);
- if(bind(buf, "/dev/kbdin", MREPL) < 0)
- sysfatal("bind %r");
- } else
- if(mount(fd, -1, mnt, MREPL, "") < 0)
- sysfatal("mount %r");
-}
--- a/sys/src/cmd/ktrans/ktrans.h
+++ /dev/null
@@ -1,25 +1,0 @@
-typedef struct Map Map;
-struct Map {
- char *roma;
- char *kana;
- char leadstomore;
-};
-
-typedef struct Msg Msg;
-struct Msg {
- char code;
- char buf[64];
-};
-
-typedef struct Trans Trans;
-struct Trans {
- Channel *input;
- Channel *output;
- Channel *dict;
- Channel *done;
- Channel *lang;
-};
-
-void keyproc(void*);
-void launchfs(char*,char*,char*);
-int parselang(char*);
--- a/sys/src/cmd/ktrans/main.c
+++ b/sys/src/cmd/ktrans/main.c
@@ -1,11 +1,3 @@
-/*
- * Mostly based on the original source codes of Plan 9 release 2
- * distribution.
- * by Kenji Okamoto, August 4 2000
- * Osaka Prefecture Univ.
- * okamoto@granite.cias.osakafu-u.ac.jp
- */
-
#include <u.h>
#include <libc.h>
#include <ctype.h>
@@ -13,16 +5,8 @@
#include <fcall.h>
#include <thread.h>
#include <9p.h>
-
#include "hash.h"
-#include "ktrans.h"
-static Hmap *jisho, *zidian;
-static int deflang;
-static char backspace[64];
-
-mainstacksize = 8192*2;
-
char*
pushutf(char *dst, char *e, char *u, int nrune)
{
@@ -83,12 +67,19 @@
void
popstr(Str *s)
{
- while(s->p > s->b && (*--s->p & 0xC0)==0x80)
+ while(s->p > s->b && (*--s->p & 0xC0)==Runesync)
;
s->p[0] = '\0';
}
+typedef struct Map Map;
+struct Map {
+ char *roma;
+ char *kana;
+ char leadstomore;
+};
+
Hmap*
openmap(char *file)
{
@@ -201,12 +192,14 @@
LangZH = '', // ^c
};
+int deflang;
+
Hmap *natural;
-Hmap *hira, *kata;
+Hmap *hira, *kata, *jisho;
Hmap *cyril;
Hmap *greek;
Hmap *hangul;
-Hmap *hanzi;
+Hmap *hanzi, *zidian;
Hmap **langtab[] = {
[LangEN] &natural,
@@ -274,6 +267,16 @@
return hmapget(*h, s, m);
}
+typedef struct Msg Msg;
+struct Msg {
+ char code;
+ char buf[64];
+};
+static Channel *dictch;
+static Channel *output;
+static Channel *input;
+static char backspace[64];
+
static int
emitutf(Channel *out, char *u, int nrune)
{
@@ -287,9 +290,8 @@
}
static void
-dictthread(void *a)
+dictthread(void*)
{
- Trans *t;
Msg m;
Rune r;
int n;
@@ -308,7 +310,6 @@
};
int mode;
- t = a;
dict = jisho;
selected = -1;
kouho[0] = nil;
@@ -316,7 +317,7 @@
resetstr(&last, &line, &okuri, nil);
threadsetname("dict");
- while(recv(t->dict, &m) != -1){
+ while(recv(dictch, &m) != -1){
for(p = m.buf; *p; p += n){
n = chartorune(&r, p);
if(r != ''){
@@ -337,10 +338,10 @@
break;
case '':
if(line.b == line.p){
- emitutf(t->output, "", 1);
+ emitutf(output, "", 1);
break;
}
- emitutf(t->output, backspace, utflen(line.b));
+ emitutf(output, backspace, utflen(line.b));
/* fallthrough */
case ' ': case ',': case '.':
case '':
@@ -360,7 +361,7 @@
break;
case '\n':
if(line.b == line.p){
- emitutf(t->output, "\n", 1);
+ emitutf(output, "\n", 1);
break;
}
/* fallthrough */
@@ -377,8 +378,8 @@
}
if(kouho[selected] == nil){
/* cycled through all matches; bail */
- emitutf(t->output, backspace, utflen(last.b));
- emitutf(t->output, line.b, 0);
+ emitutf(output, backspace, utflen(last.b));
+ emitutf(output, line.b, 0);
resetstr(&line, &last, &okuri, nil);
selected = -1;
break;
@@ -385,15 +386,15 @@
}
if(okuri.p != okuri.b)
- emitutf(t->output, backspace, utflen(okuri.b));
+ emitutf(output, backspace, utflen(okuri.b));
if(selected == 0)
- emitutf(t->output, backspace, utflen(line.b));
+ emitutf(output, backspace, utflen(line.b));
else
- emitutf(t->output, backspace, utflen(last.b));
+ emitutf(output, backspace, utflen(last.b));
- emitutf(t->output, kouho[selected], 0);
+ emitutf(output, kouho[selected], 0);
last.p = pushutf(last.b, strend(&last), kouho[selected], 0);
- emitutf(t->output, okuri.b, 0);
+ emitutf(output, okuri.b, 0);
resetstr(&line, nil);
mode = Kanji;
@@ -430,14 +431,11 @@
}
}
}
-
- send(t->done, nil);
}
-void
-keyproc(void *a)
+static void
+keythread(void*)
{
- Trans *t;
int lang;
Msg m;
Map lkup;
@@ -448,21 +446,21 @@
Str line;
int mode;
- t = a;
mode = 0;
peek[0] = lang = deflang;
- threadcreate(dictthread, a, mainstacksize);
resetstr(&line, nil);
if(lang == LangJP || lang == LangZH)
- emitutf(t->dict, peek, 1);
+ emitutf(dictch, peek, 1);
- threadsetname("key");
- while(recv(t->input, &m) != -1){
+ threadsetname("keytrans");
+ while(recv(input, &m) != -1){
+ if(m.code == 'r'){
+ emitutf(dictch, "", 1);
+ resetstr(&line, nil);
+ continue;
+ }
if(m.code != 'c'){
- if(m.code == 'q')
- send(t->lang, &langcodetab[lang]);
- else
- send(t->output, &m);
+ send(output, &m);
continue;
}
@@ -469,14 +467,14 @@
for(p = m.buf; *p; p += n){
n = chartorune(&r, p);
if(checklang(&lang, r)){
- emitutf(t->dict, "", 1);
+ emitutf(dictch, "", 1);
if(lang == LangJP || lang == LangZH)
- emitutf(t->dict, p, 1);
+ emitutf(dictch, p, 1);
resetstr(&line, nil);
continue;
}
if(lang == LangZH || lang == LangJP){
- emitutf(t->dict, p, 1);
+ emitutf(dictch, p, 1);
if(utfrune("\n", r) != nil){
resetstr(&line, nil);
continue;
@@ -489,7 +487,7 @@
}
}
- emitutf(t->output, p, 1);
+ emitutf(output, p, 1);
if(lang == LangEN || lang == LangZH)
continue;
if(r == '\b'){
@@ -512,52 +510,101 @@
resetstr(&line, nil);
if(lang == LangJP){
- emitutf(t->dict, backspace, utflen(lkup.roma));
- emitutf(t->dict, lkup.kana, 0);
+ emitutf(dictch, backspace, utflen(lkup.roma));
+ emitutf(dictch, lkup.kana, 0);
}
- emitutf(t->output, backspace, utflen(lkup.roma));
- emitutf(t->output, lkup.kana, 0);
+ emitutf(output, backspace, utflen(lkup.roma));
+ emitutf(output, lkup.kana, 0);
}
}
- send(t->done, nil);
}
+static int kbdin;
+static int kbdout;
+
void
+kbdtap(void*)
+{
+ Msg msg;
+ char buf[128];
+ char *p, *e;
+ int n;
+
+ threadsetname("kbdtap");
+ for(;;){
+Drop:
+ n = read(kbdin, buf, sizeof buf);
+ if(n < 0)
+ break;
+ for(p = buf; p < buf+n;){
+ msg.code = p[0];
+ p++;
+ switch(msg.code){
+ case 'c': case 'k': case 'K':
+ case 'r':
+ break;
+ default:
+ goto Drop;
+ }
+ e = utfecpy(msg.buf, msg.buf + sizeof msg.buf, p);
+ p += e - msg.buf;
+ p++;
+ if(send(input, &msg) == -1)
+ return;
+ }
+ }
+}
+
+void
+kbdsink(void*)
+{
+ Msg m;
+ char *p;
+ Rune rn;
+
+ threadsetname("kbdsink");
+ while(recv(output, &m) != -1){
+ if(m.code != 'c'){
+ fprint(kbdout, "%c%s", m.code, m.buf);
+ continue;
+ }
+ p = m.buf;
+ for(;;){
+ p += chartorune(&rn, p);
+ if(rn == Runeerror || rn == '\0')
+ break;
+ fprint(kbdout, "c%C", rn);
+ }
+ }
+}
+
+void
usage(void)
{
- fprint(2, "usage: %s [ -K ] [ -l lang ]\n", argv0);
- exits("usage");
+ fprint(2, "usage: %s [ -t tap ] [ -l lang ]\n", argv0);
+ threadexits("usage");
}
+mainstacksize = 8192*2;
+
void
threadmain(int argc, char *argv[])
{
char *jishoname, *zidianname;
- char *kbd, *srv, *mntpt;
+ char *tap;
- kbd = "/dev/kbd";
- srv = nil;
- mntpt = "/mnt/ktrans";
+ tap = "/dev/kbdtap";
deflang = LangEN;
ARGBEGIN{
- case 'K':
- kbd = nil;
+ case 't':
+ tap = EARGF(usage());
break;
- case 'k':
- kbd = EARGF(usage());
- break;
case 'l':
deflang = parselang(EARGF(usage()));
if(deflang < 0)
usage();
break;
- case 's':
- srv = EARGF(usage());
- break;
- case 'm':
- mntpt = EARGF(usage());
- break;
default:
usage();
}ARGEND;
@@ -564,6 +611,10 @@
if(argc != 0)
usage();
+ kbdin = kbdout = open(tap, ORDWR);
+ if(kbdin < 0 || kbdout < 0)
+ sysfatal("failed to get keyboard: %r");
+
memset(backspace, '\b', sizeof backspace-1);
backspace[sizeof backspace-1] = '\0';
@@ -582,5 +633,14 @@
cyril = openmap("/lib/ktrans/cyril.map");
hangul = openmap("/lib/ktrans/hangul.map");
- launchfs(srv, mntpt, kbd);
+ dictch = chancreate(sizeof(Msg), 0);
+ input = chancreate(sizeof(Msg), 0);
+ output = chancreate(sizeof(Msg), 0);
+
+ proccreate(kbdtap, nil, mainstacksize);
+ proccreate(kbdsink, nil, mainstacksize);
+ threadcreate(dictthread, nil, mainstacksize);
+ threadcreate(keythread, nil, mainstacksize);
+
+ threadexits(nil);
}
--- a/sys/src/cmd/ktrans/mkfile
+++ b/sys/src/cmd/ktrans/mkfile
@@ -2,10 +2,9 @@
BIN=/$objtype/bin
TARG=ktrans
-HFILES=ktrans.h
+HFILES=hash.h
OFILES=\
hash.$O\
main.$O\
- fs.$O\
</sys/src/cmd/mkone