graffiti.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. #include <u.h>
  26. #include <libc.h>
  27. #include <draw.h>
  28. #include <scribble.h>
  29. #include "scribbleimpl.h"
  30. #include "graffiti.h"
  31. int ScribbleDebug;
  32. char *cl_name[3] = {
  33. DEFAULT_LETTERS_FILE,
  34. DEFAULT_DIGITS_FILE,
  35. DEFAULT_PUNC_FILE
  36. };
  37. Rune
  38. recognize (Scribble *s)
  39. {
  40. struct graffiti *graf = s->graf;
  41. Stroke *ps = &s->ps;
  42. Rune rune;
  43. int c;
  44. int nr;
  45. rec_alternative *ret;
  46. if (ps->npts == 0)
  47. return '\0';
  48. c = recognizer_translate(
  49. graf->rec[s->puncShift ? CS_PUNCTUATION : s->curCharSet],
  50. 1, ps, false, &nr, &ret);
  51. if (c != -1)
  52. delete_rec_alternative_array(nr, ret, false);
  53. rune = '\0';
  54. switch (c) {
  55. case '\0':
  56. if(ScribbleDebug)fprint(2, "(case '\\0')\n");
  57. break;
  58. case 'A': /* space */
  59. rune = ' ';
  60. if(ScribbleDebug)fprint(2, "(case A) character = ' %C' (0x%x)\n", rune, rune);
  61. break;
  62. case 'B': /* backspace */
  63. rune = '\b';
  64. if(ScribbleDebug)fprint(2, "(case B) character = \\b (0x%x)\n", rune);
  65. break;
  66. case 'N': /* numlock */
  67. if(ScribbleDebug)fprint(2, "(case N)\n");
  68. if (s->curCharSet == CS_DIGITS) {
  69. s->curCharSet = CS_LETTERS;
  70. } else {
  71. s->curCharSet = CS_DIGITS;
  72. }
  73. s->tmpShift = 0;
  74. s->puncShift = 0;
  75. s->ctrlShift = 0;
  76. break;
  77. case 'P': /* usually puncshift, but we'll make it CTRL */
  78. if(ScribbleDebug)fprint(2, "(case P)\n");
  79. s->ctrlShift = !s->ctrlShift;
  80. s->tmpShift = 0;
  81. s->puncShift = 0;
  82. break;
  83. case 'R': /* newline */
  84. rune = '\n';
  85. if(ScribbleDebug)fprint(2, "(case R) character = \\n (0x%x)\n", rune);
  86. break;
  87. case 'S': /* shift */
  88. if(ScribbleDebug)fprint(2, "(case S)\n");
  89. s->puncShift = 0;
  90. s->ctrlShift = 0;
  91. if (s->capsLock) {
  92. s->capsLock = 0;
  93. s->tmpShift = 0;
  94. break;
  95. }
  96. if (s->tmpShift == 0) {
  97. s->tmpShift++;
  98. break;
  99. }
  100. /* fall through */
  101. case 'L': /* caps lock */
  102. if(ScribbleDebug)fprint(2, "(case L)\n");
  103. s->capsLock = !s->capsLock;
  104. break;
  105. case '.': /* toggle punctuation mode */
  106. if (s->puncShift) {
  107. s->puncShift = 0;
  108. } else {
  109. s->puncShift = 1;
  110. s->ctrlShift = 0;
  111. s->tmpShift = 0;
  112. return rune;
  113. }
  114. rune = '.';
  115. if(0)fprint(2, "(case .) character = %c (0x%x)\n", rune, rune);
  116. break;
  117. default:
  118. if ('A' <= c && c <= 'Z') {
  119. if(ScribbleDebug)fprint(2, "(bad case?) character = %c (0x%x)\n", c, c);
  120. return rune;
  121. }
  122. rune = c;
  123. if (s->ctrlShift)
  124. {
  125. if (c < 'a' || 'z' < c)
  126. {
  127. if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune);
  128. return rune;
  129. }
  130. rune = rune & 0x1f;
  131. } else if ((s->capsLock && !s->tmpShift) ||
  132. (!s->capsLock && s->tmpShift))
  133. {
  134. if (rune < 0xff)
  135. rune = toupper(rune);
  136. }
  137. s->tmpShift = 0;
  138. s->puncShift = 0;
  139. s->ctrlShift = 0;
  140. if(ScribbleDebug)fprint(2, "(default) character = %c (0x%x)\n", rune, rune);
  141. }
  142. return rune;
  143. }
  144. /* This procedure is called to initialize pg by loading the three
  145. * recognizers, loading the initial set of three classifiers, and
  146. * loading & verifying the recognizer extension functions. If the
  147. * directory $HOME/.recognizers exists, the classifier files will be
  148. * loaded from that directory. If not, or if there is an error, the
  149. * default files (directory specified in Makefile) will be loaded
  150. * instead. Returns non-zero on success, 0 on failure. (Adapted from
  151. * package tkgraf/src/GraffitiPkg.c.
  152. */
  153. static int
  154. graffiti_load_recognizers(struct graffiti *pg)
  155. {
  156. bool usingDefault;
  157. char* homedir;
  158. int i;
  159. rec_fn *fns;
  160. /* First, load the recognizers... */
  161. /* call recognizer_unload if an error ? */
  162. for (i = 0; i < NUM_RECS; i++) {
  163. /* Load the recognizer itself... */
  164. pg->rec[i] = recognizer_load(DEFAULT_REC_DIR, "", nil);
  165. if (pg->rec[i] == nil) {
  166. fprint(2,"Error loading recognizer from %s.", DEFAULT_REC_DIR);
  167. return 0;
  168. }
  169. if ((* (int *)(pg->rec[i])) != 0xfeed) {
  170. fprint(2,"Error in recognizer_magic.");
  171. return 0;
  172. }
  173. }
  174. /* ...then figure out where the classifiers are... */
  175. if ( (homedir = (char*)getenv("home")) == nil ) {
  176. if(0)fprint(2, "no homedir, using = %s\n", REC_DEFAULT_USER_DIR);
  177. strecpy(pg->cldir, pg->cldir+sizeof pg->cldir, REC_DEFAULT_USER_DIR);
  178. usingDefault = true;
  179. } else {
  180. if(0)fprint(2, "homedir = %s\n", homedir);
  181. snprint(pg->cldir, sizeof pg->cldir, "%s/%s", homedir, CLASSIFIER_DIR);
  182. usingDefault = false;
  183. }
  184. /* ...then load the classifiers... */
  185. for (i = 0; i < NUM_RECS; i++) {
  186. int rec_return;
  187. char *s;
  188. rec_return = recognizer_load_state(pg->rec[i], pg->cldir, cl_name[i]);
  189. if ((rec_return == -1) && (usingDefault == false)) {
  190. if(0)fprint(2, "Unable to load custom classifier file %s/%s.\nTrying default classifier file instead.\nOriginal error: %s\n ",
  191. pg->cldir, cl_name[i],
  192. (s = recognizer_error(pg->rec[i])) ? s : "(none)");
  193. rec_return = recognizer_load_state(pg->rec[i],
  194. REC_DEFAULT_USER_DIR, cl_name[i]);
  195. }
  196. if (rec_return == -1) {
  197. fprint(2, "Unable to load default classifier file %s.\nOriginal error: %s\n",
  198. cl_name[i],
  199. (s = recognizer_error(pg->rec[i])) ? s : "(none)");
  200. return 0;
  201. }
  202. }
  203. /* We have recognizers and classifiers now. */
  204. /* Get the vector of LIextension functions.. */
  205. fns = recognizer_get_extension_functions(pg->rec[CS_LETTERS]);
  206. if (fns == nil) {
  207. fprint(2, "LI Recognizer Training:No extension functions!");
  208. return 0;
  209. }
  210. /* ... and make sure the training & get-classes functions are okay. */
  211. if( (pg->rec_train = (li_recognizer_train)fns[LI_TRAIN]) == nil ) {
  212. fprint(2,
  213. "LI Recognizer Training:li_recognizer_train() not found!");
  214. if (fns != nil) {
  215. free(fns);
  216. }
  217. return 0;
  218. }
  219. if( (pg->rec_getClasses = (li_recognizer_getClasses)fns[LI_GET_CLASSES]) == nil ) {
  220. fprint(2,
  221. "LI Recognizer Training:li_recognizer_getClasses() not found!");
  222. if (fns != nil) {
  223. free(fns);
  224. }
  225. return 0;
  226. }
  227. free(fns);
  228. return 1;
  229. }
  230. Scribble *
  231. scribblealloc(void)
  232. {
  233. Scribble *s;
  234. s = mallocz(sizeof(Scribble), 1);
  235. if (s == nil)
  236. sysfatal("Initialize: %r");
  237. s->curCharSet = CS_LETTERS;
  238. s->graf = mallocz(sizeof(struct graffiti), 1);
  239. if (s->graf == nil)
  240. sysfatal("Initialize: %r");
  241. graffiti_load_recognizers(s->graf);
  242. return s;
  243. }