]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libscribble/graffiti.c
snes: fix input botch
[plan9front.git] / sys / src / libscribble / graffiti.c
1 /*
2  * Graffiti.c is based on the file Scribble.c copyrighted
3  * by Keith Packard:
4  *
5  * Copyright © 1999 Keith Packard
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of Keith Packard not be used in
12  * advertising or publicity pertaining to distribution of the software without
13  * specific, written prior permission.  Keith Packard makes no
14  * representations about the suitability of this software for any purpose.  It
15  * is provided "as is" without express or implied warranty.
16  *
17  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19  * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23  * PERFORMANCE OF THIS SOFTWARE.
24  */
25
26 #include <u.h>
27 #include <libc.h>
28 #include <draw.h>
29 #include <scribble.h>
30
31 #include "scribbleimpl.h"
32 #include "graffiti.h"
33
34 int ScribbleDebug;
35
36 char *cl_name[3] = {
37         DEFAULT_LETTERS_FILE,
38         DEFAULT_DIGITS_FILE,
39         DEFAULT_PUNC_FILE
40 };
41
42 Rune
43 recognize (Scribble *s)
44 {
45         struct graffiti *graf = s->graf;
46         Stroke      *ps = &s->ps;
47         Rune                rune;
48         int                     c;
49         int                             nr;
50         rec_alternative *ret;
51
52         if (ps->npts == 0)
53                 return '\0';
54
55         c = recognizer_translate(
56                 graf->rec[s->puncShift ? CS_PUNCTUATION : s->curCharSet],
57                 1, ps, false, &nr, &ret);
58         if (c != -1)
59                 delete_rec_alternative_array(nr, ret, false);
60
61         rune = '\0';
62
63         switch (c) {
64         case '\0':
65                 if(ScribbleDebug)fprint(2, "(case '\\0')\n");
66                 break;
67         case 'A':       /* space */
68                 rune = ' ';
69                 if(ScribbleDebug)fprint(2, "(case A) character = ' %C' (0x%x)\n", rune, rune);
70                 break;
71         case 'B':       /* backspace */
72                 rune = '\b';
73                 if(ScribbleDebug)fprint(2, "(case B) character = \\b (0x%x)\n", rune);
74                 break;
75         case 'N': /* numlock */
76                 if(ScribbleDebug)fprint(2, "(case N)\n");
77                 if (s->curCharSet == CS_DIGITS) {
78                         s->curCharSet = CS_LETTERS;
79                 } else {
80                         s->curCharSet = CS_DIGITS;
81                 }
82                 s->tmpShift = 0;
83                 s->puncShift = 0;
84                 s->ctrlShift = 0;
85                 break;
86         case 'P': /* usually puncshift, but we'll make it CTRL */
87                 if(ScribbleDebug)fprint(2, "(case P)\n");
88                 s->ctrlShift = !s->ctrlShift;
89                 s->tmpShift = 0;
90                 s->puncShift = 0;
91                 break;
92         case 'R':       /* newline */
93                 rune = '\n';
94                 if(ScribbleDebug)fprint(2, "(case R) character = \\n (0x%x)\n", rune);
95                 break;
96         case 'S': /* shift */
97                 if(ScribbleDebug)fprint(2, "(case S)\n");
98                 s->puncShift = 0;
99                 s->ctrlShift = 0;
100                 if (s->capsLock) {
101                         s->capsLock = 0;
102                         s->tmpShift = 0;
103                         break;
104                 }
105                 if (s->tmpShift == 0) {
106                         s->tmpShift++;
107                         break;
108                 }
109                 /* fall through */
110         case 'L': /* caps lock */
111                 if(ScribbleDebug)fprint(2, "(case L)\n");
112                 s->capsLock = !s->capsLock;
113                 break;
114         case '.':       /* toggle punctuation mode */
115                 if (s->puncShift) {
116                         s->puncShift = 0;
117                 } else {
118                         s->puncShift = 1;
119                         s->ctrlShift = 0;
120                         s->tmpShift = 0;
121                         return rune;
122                 }                       
123                 rune = '.';
124                 if(0)fprint(2, "(case .) character = %c (0x%x)\n", rune, rune);
125                 break;
126         default:
127                 if ('A' <= c && c <= 'Z') {
128                         if(ScribbleDebug)fprint(2, "(bad case?) character = %c (0x%x)\n", c, c);
129                         return rune;
130                 }
131                 rune = c;
132                 if (s->ctrlShift) 
133                 {
134                         if (c < 'a' || 'z' < c)
135                         {
136                                 if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune);
137                                 return rune;
138                         }
139                         rune = rune & 0x1f;
140                 } else if ((s->capsLock && !s->tmpShift) || 
141                                  (!s->capsLock && s->tmpShift)) 
142                 {
143                         if (rune < 0xff)
144                                 rune = toupper(rune);
145                 } 
146                 s->tmpShift = 0;
147                 s->puncShift = 0;
148                 s->ctrlShift = 0;
149                 if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune);
150         }
151         return rune;
152 }
153
154 /* This procedure is called to initialize pg by loading the three
155  * recognizers, loading the initial set of three classifiers, and
156  * loading & verifying the recognizer extension functions.  If the
157  * directory $HOME/.recognizers exists, the classifier files will be
158  * loaded from that directory.  If not, or if there is an error, the
159  * default files (directory specified in Makefile) will be loaded
160  * instead.  Returns non-zero on success, 0 on failure.  (Adapted from
161  * package tkgraf/src/GraffitiPkg.c.
162  */
163
164 static int
165 graffiti_load_recognizers(struct graffiti *pg)
166 {
167         bool usingDefault;
168         char* homedir;
169         int i;
170         rec_fn *fns;
171
172         /* First, load the recognizers... */
173         /* call recognizer_unload if an error ? */
174         for (i = 0; i < NUM_RECS; i++) {
175                 /* Load the recognizer itself... */
176                 pg->rec[i] = recognizer_load(DEFAULT_REC_DIR, "", nil);
177                 if (pg->rec[i] == nil) {
178                         fprint(2,"Error loading recognizer from %s.", DEFAULT_REC_DIR);
179                         return 0;
180                 }
181                 if ((* (int *)(pg->rec[i])) != 0xfeed) {
182                         fprint(2,"Error in recognizer_magic.");
183                         return 0;
184                 }
185         }
186
187         /* ...then figure out where the classifiers are... */
188         if ( (homedir = (char*)getenv("home")) == nil ) {
189                 if(0)fprint(2, "no homedir, using = %s\n", REC_DEFAULT_USER_DIR);
190                 strecpy(pg->cldir, pg->cldir+sizeof pg->cldir, REC_DEFAULT_USER_DIR);
191                 usingDefault = true;
192         } else {
193                 if(0)fprint(2, "homedir = %s\n", homedir);
194                 snprint(pg->cldir, sizeof pg->cldir, "%s/%s", homedir, CLASSIFIER_DIR);
195                 usingDefault = false;
196         }
197
198         /* ...then load the classifiers... */
199         for (i = 0; i < NUM_RECS; i++) {
200                 int rec_return;
201                 char *s;
202
203                 rec_return = recognizer_load_state(pg->rec[i], pg->cldir, cl_name[i]);
204                 if ((rec_return == -1) && (usingDefault == false)) {
205                         if(0)fprint(2, "Unable to load custom classifier file %s/%s.\nTrying default classifier file instead.\nOriginal error: %s\n ", 
206                                 pg->cldir, cl_name[i], 
207                                 (s = recognizer_error(pg->rec[i])) ? s : "(none)");
208                         rec_return = recognizer_load_state(pg->rec[i],
209                                                 REC_DEFAULT_USER_DIR, cl_name[i]);
210                 }
211                 if (rec_return == -1) {
212                         fprint(2, "Unable to load default classifier file %s.\nOriginal error: %s\n",
213                                 cl_name[i], 
214                                 (s = recognizer_error(pg->rec[i])) ? s : "(none)");
215                         return 0;
216                 }
217         }
218
219         /* We have recognizers and classifiers now.   */
220         /* Get the vector of LIextension functions..     */
221         fns = recognizer_get_extension_functions(pg->rec[CS_LETTERS]);
222         if (fns == nil) {
223                 fprint(2, "LI Recognizer Training:No extension functions!");
224                 return 0;
225         }
226         
227         /* ... and make sure the training & get-classes functions are okay. */
228         if( (pg->rec_train = (li_recognizer_train)fns[LI_TRAIN]) == nil ) {
229                 fprint(2,
230                         "LI Recognizer Training:li_recognizer_train() not found!");
231                 if (fns != nil) {
232                         free(fns);
233                 }
234                 return 0;
235         }
236   
237         if( (pg->rec_getClasses = (li_recognizer_getClasses)fns[LI_GET_CLASSES]) == nil ) {
238                 fprint(2,
239                         "LI Recognizer Training:li_recognizer_getClasses() not found!");
240                 if (fns != nil) {
241                         free(fns);
242                 }
243                 return 0;
244         }
245         free(fns);
246         return 1;
247 }
248
249 Scribble *
250 scribblealloc(void)
251 {
252         Scribble *s;
253
254         s = mallocz(sizeof(Scribble), 1);
255         if (s == nil)
256                 sysfatal("Initialize: %r");
257         s->curCharSet = CS_LETTERS;
258
259         s->graf = mallocz(sizeof(struct graffiti), 1);
260         if (s->graf == nil)
261                 sysfatal("Initialize: %r");
262
263         graffiti_load_recognizers(s->graf);
264
265         return s;
266 }