plan9front/sys/src/libscribble/graffiti.c

267 lines
7.2 KiB
C

/*
* 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;
}