/* * Graffiti.c is based on the file Scribble.c copyrighted * by Keith Packard: * * Copyright © 1999 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include <u.h>#include <libc.h>#include <draw.h>#include <scribble.h> #include "scribbleimpl.h"#include "graffiti.h" int ScribbleDebug; char *cl_name[3] = { DEFAULT_LETTERS_FILE, DEFAULT_DIGITS_FILE, DEFAULT_PUNC_FILE}; Runerecognize (Scribble *s){ struct graffiti *graf = s->graf; Stroke *ps = &s->ps; Rune rune; int c; int nr; rec_alternative *ret; if (ps->npts == 0) return '\0'; c = recognizer_translate( graf->rec[s->puncShift ? CS_PUNCTUATION : s->curCharSet], 1, ps, false, &nr, &ret); if (c != -1) delete_rec_alternative_array(nr, ret, false); rune = '\0'; switch (c) { case '\0': if(ScribbleDebug)fprint(2, "(case '\\0')\n"); break; case 'A': /* space */ rune = ' '; if(ScribbleDebug)fprint(2, "(case A) character = ' %C' (0x%x)\n", rune, rune); break; case 'B': /* backspace */ rune = '\b'; if(ScribbleDebug)fprint(2, "(case B) character = \\b (0x%x)\n", rune); break; case 'N': /* numlock */ if(ScribbleDebug)fprint(2, "(case N)\n"); if (s->curCharSet == CS_DIGITS) { s->curCharSet = CS_LETTERS; } else { s->curCharSet = CS_DIGITS; } s->tmpShift = 0; s->puncShift = 0; s->ctrlShift = 0; break; case 'P': /* usually puncshift, but we'll make it CTRL */ if(ScribbleDebug)fprint(2, "(case P)\n"); s->ctrlShift = !s->ctrlShift; s->tmpShift = 0; s->puncShift = 0; break; case 'R': /* newline */ rune = '\n'; if(ScribbleDebug)fprint(2, "(case R) character = \\n (0x%x)\n", rune); break; case 'S': /* shift */ if(ScribbleDebug)fprint(2, "(case S)\n"); s->puncShift = 0; s->ctrlShift = 0; if (s->capsLock) { s->capsLock = 0; s->tmpShift = 0; break; } if (s->tmpShift == 0) { s->tmpShift++; break; } /* fall through */ case 'L': /* caps lock */ if(ScribbleDebug)fprint(2, "(case L)\n"); s->capsLock = !s->capsLock; break; case '.': /* toggle punctuation mode */ if (s->puncShift) { s->puncShift = 0; } else { s->puncShift = 1; s->ctrlShift = 0; s->tmpShift = 0; return rune; } rune = '.'; if(0)fprint(2, "(case .) character = %c (0x%x)\n", rune, rune); break; default: if ('A' <= c && c <= 'Z') { if(ScribbleDebug)fprint(2, "(bad case?) character = %c (0x%x)\n", c, c); return rune; } rune = c; if (s->ctrlShift) { if (c < 'a' || 'z' < c) { if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune); return rune; } rune = rune & 0x1f; } else if ((s->capsLock && !s->tmpShift) || (!s->capsLock && s->tmpShift)) { if (rune < 0xff) rune = toupper(rune); } s->tmpShift = 0; s->puncShift = 0; s->ctrlShift = 0; if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune); } return rune;} /* This procedure is called to initialize pg by loading the three * recognizers, loading the initial set of three classifiers, and * loading & verifying the recognizer extension functions. If the * directory $HOME/.recognizers exists, the classifier files will be * loaded from that directory. If not, or if there is an error, the * default files (directory specified in Makefile) will be loaded * instead. Returns non-zero on success, 0 on failure. (Adapted from * package tkgraf/src/GraffitiPkg.c. */ static intgraffiti_load_recognizers(struct graffiti *pg){ bool usingDefault; char* homedir; int i; rec_fn *fns; /* First, load the recognizers... */ /* call recognizer_unload if an error ? */ for (i = 0; i < NUM_RECS; i++) { /* Load the recognizer itself... */ pg->rec[i] = recognizer_load(DEFAULT_REC_DIR, "", nil); if (pg->rec[i] == nil) { fprint(2,"Error loading recognizer from %s.", DEFAULT_REC_DIR); return 0; } if ((* (int *)(pg->rec[i])) != 0xfeed) { fprint(2,"Error in recognizer_magic."); return 0; } } /* ...then figure out where the classifiers are... */ if ( (homedir = (char*)getenv("home")) == nil ) { if(0)fprint(2, "no homedir, using = %s\n", REC_DEFAULT_USER_DIR); strecpy(pg->cldir, pg->cldir+sizeof pg->cldir, REC_DEFAULT_USER_DIR); usingDefault = true; } else { if(0)fprint(2, "homedir = %s\n", homedir); snprint(pg->cldir, sizeof pg->cldir, "%s/%s", homedir, CLASSIFIER_DIR); usingDefault = false; } /* ...then load the classifiers... */ for (i = 0; i < NUM_RECS; i++) { int rec_return; char *s; rec_return = recognizer_load_state(pg->rec[i], pg->cldir, cl_name[i]); if ((rec_return == -1) && (usingDefault == false)) { if(0)fprint(2, "Unable to load custom classifier file %s/%s.\nTrying default classifier file instead.\nOriginal error: %s\n ", pg->cldir, cl_name[i], (s = recognizer_error(pg->rec[i])) ? s : "(none)"); rec_return = recognizer_load_state(pg->rec[i], REC_DEFAULT_USER_DIR, cl_name[i]); } if (rec_return == -1) { fprint(2, "Unable to load default classifier file %s.\nOriginal error: %s\n", cl_name[i], (s = recognizer_error(pg->rec[i])) ? s : "(none)"); return 0; } } /* We have recognizers and classifiers now. */ /* Get the vector of LIextension functions.. */ fns = recognizer_get_extension_functions(pg->rec[CS_LETTERS]); if (fns == nil) { fprint(2, "LI Recognizer Training:No extension functions!"); return 0; } /* ... and make sure the training & get-classes functions are okay. */ if( (pg->rec_train = (li_recognizer_train)fns[LI_TRAIN]) == nil ) { fprint(2, "LI Recognizer Training:li_recognizer_train() not found!"); if (fns != nil) { free(fns); } return 0; } if( (pg->rec_getClasses = (li_recognizer_getClasses)fns[LI_GET_CLASSES]) == nil ) { fprint(2, "LI Recognizer Training:li_recognizer_getClasses() not found!"); if (fns != nil) { free(fns); } return 0; } free(fns); return 1;} Scribble *scribblealloc(void){ Scribble *s; s = mallocz(sizeof(Scribble), 1); if (s == nil) sysfatal("Initialize: %r"); s->curCharSet = CS_LETTERS; s->graf = mallocz(sizeof(struct graffiti), 1); if (s->graf == nil) sysfatal("Initialize: %r"); graffiti_load_recognizers(s->graf); return s;}
/*
* Graffiti.c is based on the file Scribble.c copyrighted
* by Keith Packard:
*
* Copyright © 1999 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <scribble.h>
#include "scribbleimpl.h"
#include "graffiti.h"
int ScribbleDebug;
char *cl_name[3] = {
DEFAULT_LETTERS_FILE,
DEFAULT_DIGITS_FILE,
DEFAULT_PUNC_FILE
};
Rune
recognize (Scribble *s)
{
struct graffiti *graf = s->graf;
Stroke *ps = &s->ps;
Rune rune;
int c;
int nr;
rec_alternative *ret;
if (ps->npts == 0)
return '\0';
c = recognizer_translate(
graf->rec[s->puncShift ? CS_PUNCTUATION : s->curCharSet],
1, ps, false, &nr, &ret);
if (c != -1)
delete_rec_alternative_array(nr, ret, false);
rune = '\0';
switch (c) {
case '\0':
if(ScribbleDebug)fprint(2, "(case '\\0')\n");
break;
case 'A': /* space */
rune = ' ';
if(ScribbleDebug)fprint(2, "(case A) character = ' %C' (0x%x)\n", rune, rune);
break;
case 'B': /* backspace */
rune = '\b';
if(ScribbleDebug)fprint(2, "(case B) character = \\b (0x%x)\n", rune);
break;
case 'N': /* numlock */
if(ScribbleDebug)fprint(2, "(case N)\n");
if (s->curCharSet == CS_DIGITS) {
s->curCharSet = CS_LETTERS;
} else {
s->curCharSet = CS_DIGITS;
}
s->tmpShift = 0;
s->puncShift = 0;
s->ctrlShift = 0;
break;
case 'P': /* usually puncshift, but we'll make it CTRL */
if(ScribbleDebug)fprint(2, "(case P)\n");
s->ctrlShift = !s->ctrlShift;
s->tmpShift = 0;
s->puncShift = 0;
break;
case 'R': /* newline */
rune = '\n';
if(ScribbleDebug)fprint(2, "(case R) character = \\n (0x%x)\n", rune);
break;
case 'S': /* shift */
if(ScribbleDebug)fprint(2, "(case S)\n");
s->puncShift = 0;
s->ctrlShift = 0;
if (s->capsLock) {
s->capsLock = 0;
s->tmpShift = 0;
break;
}
if (s->tmpShift == 0) {
s->tmpShift++;
break;
}
/* fall through */
case 'L': /* caps lock */
if(ScribbleDebug)fprint(2, "(case L)\n");
s->capsLock = !s->capsLock;
break;
case '.': /* toggle punctuation mode */
if (s->puncShift) {
s->puncShift = 0;
} else {
s->puncShift = 1;
s->ctrlShift = 0;
s->tmpShift = 0;
return rune;
}
rune = '.';
if(0)fprint(2, "(case .) character = %c (0x%x)\n", rune, rune);
break;
default:
if ('A' <= c && c <= 'Z') {
if(ScribbleDebug)fprint(2, "(bad case?) character = %c (0x%x)\n", c, c);
return rune;
}
rune = c;
if (s->ctrlShift)
{
if (c < 'a' || 'z' < c)
{
if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune);
return rune;
}
rune = rune & 0x1f;
} else if ((s->capsLock && !s->tmpShift) ||
(!s->capsLock && s->tmpShift))
{
if (rune < 0xff)
rune = toupper(rune);
}
s->tmpShift = 0;
s->puncShift = 0;
s->ctrlShift = 0;
if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune);
}
return rune;
}
/* This procedure is called to initialize pg by loading the three
* recognizers, loading the initial set of three classifiers, and
* loading & verifying the recognizer extension functions. If the
* directory $HOME/.recognizers exists, the classifier files will be
* loaded from that directory. If not, or if there is an error, the
* default files (directory specified in Makefile) will be loaded
* instead. Returns non-zero on success, 0 on failure. (Adapted from
* package tkgraf/src/GraffitiPkg.c.
*/
static int
graffiti_load_recognizers(struct graffiti *pg)
{
bool usingDefault;
char* homedir;
int i;
rec_fn *fns;
/* First, load the recognizers... */
/* call recognizer_unload if an error ? */
for (i = 0; i < NUM_RECS; i++) {
/* Load the recognizer itself... */
pg->rec[i] = recognizer_load(DEFAULT_REC_DIR, "", nil);
if (pg->rec[i] == nil) {
fprint(2,"Error loading recognizer from %s.", DEFAULT_REC_DIR);
return 0;
}
if ((* (int *)(pg->rec[i])) != 0xfeed) {
fprint(2,"Error in recognizer_magic.");
return 0;
}
}
/* ...then figure out where the classifiers are... */
if ( (homedir = (char*)getenv("home")) == nil ) {
if(0)fprint(2, "no homedir, using = %s\n", REC_DEFAULT_USER_DIR);
strecpy(pg->cldir, pg->cldir+sizeof pg->cldir, REC_DEFAULT_USER_DIR);
usingDefault = true;
} else {
if(0)fprint(2, "homedir = %s\n", homedir);
snprint(pg->cldir, sizeof pg->cldir, "%s/%s", homedir, CLASSIFIER_DIR);
usingDefault = false;
}
/* ...then load the classifiers... */
for (i = 0; i < NUM_RECS; i++) {
int rec_return;
char *s;
rec_return = recognizer_load_state(pg->rec[i], pg->cldir, cl_name[i]);
if ((rec_return == -1) && (usingDefault == false)) {
if(0)fprint(2, "Unable to load custom classifier file %s/%s.\nTrying default classifier file instead.\nOriginal error: %s\n ",
pg->cldir, cl_name[i],
(s = recognizer_error(pg->rec[i])) ? s : "(none)");
rec_return = recognizer_load_state(pg->rec[i],
REC_DEFAULT_USER_DIR, cl_name[i]);
}
if (rec_return == -1) {
fprint(2, "Unable to load default classifier file %s.\nOriginal error: %s\n",
cl_name[i],
(s = recognizer_error(pg->rec[i])) ? s : "(none)");
return 0;
}
}
/* We have recognizers and classifiers now. */
/* Get the vector of LIextension functions.. */
fns = recognizer_get_extension_functions(pg->rec[CS_LETTERS]);
if (fns == nil) {
fprint(2, "LI Recognizer Training:No extension functions!");
return 0;
}
/* ... and make sure the training & get-classes functions are okay. */
if( (pg->rec_train = (li_recognizer_train)fns[LI_TRAIN]) == nil ) {
fprint(2,
"LI Recognizer Training:li_recognizer_train() not found!");
if (fns != nil) {
free(fns);
}
return 0;
}
if( (pg->rec_getClasses = (li_recognizer_getClasses)fns[LI_GET_CLASSES]) == nil ) {
fprint(2,
"LI Recognizer Training:li_recognizer_getClasses() not found!");
if (fns != nil) {
free(fns);
}
return 0;
}
free(fns);
return 1;
}
Scribble *
scribblealloc(void)
{
Scribble *s;
s = mallocz(sizeof(Scribble), 1);
if (s == nil)
sysfatal("Initialize: %r");
s->curCharSet = CS_LETTERS;
s->graf = mallocz(sizeof(struct graffiti), 1);
if (s->graf == nil)
sysfatal("Initialize: %r");
graffiti_load_recognizers(s->graf);
return s;
}