wskbd.c revision 1.33 1 /* $NetBSD: wskbd.c,v 1.33 1999/12/01 23:22:59 augustss Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
5 *
6 * Keysym translator:
7 * Contributed to The NetBSD Foundation by Juergen Hannken-Illjes.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Christopher G. Demetriou
20 * for the NetBSD Project.
21 * 4. The name of the author may not be used to endorse or promote products
22 * derived from this software without specific prior written permission
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 static const char _copyright[] __attribute__ ((unused)) =
37 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.";
38 static const char _rcsid[] __attribute__ ((unused)) =
39 "$NetBSD: wskbd.c,v 1.33 1999/12/01 23:22:59 augustss Exp $";
40
41 /*
42 * Copyright (c) 1992, 1993
43 * The Regents of the University of California. All rights reserved.
44 *
45 * This software was developed by the Computer Systems Engineering group
46 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
47 * contributed to Berkeley.
48 *
49 * All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the University of
52 * California, Lawrence Berkeley Laboratory.
53 *
54 * Redistribution and use in source and binary forms, with or without
55 * modification, are permitted provided that the following conditions
56 * are met:
57 * 1. Redistributions of source code must retain the above copyright
58 * notice, this list of conditions and the following disclaimer.
59 * 2. Redistributions in binary form must reproduce the above copyright
60 * notice, this list of conditions and the following disclaimer in the
61 * documentation and/or other materials provided with the distribution.
62 * 3. All advertising materials mentioning features or use of this software
63 * must display the following acknowledgement:
64 * This product includes software developed by the University of
65 * California, Berkeley and its contributors.
66 * 4. Neither the name of the University nor the names of its contributors
67 * may be used to endorse or promote products derived from this software
68 * without specific prior written permission.
69 *
70 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
71 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
74 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
75 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
76 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
78 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
79 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80 * SUCH DAMAGE.
81 *
82 * @(#)kbd.c 8.2 (Berkeley) 10/30/93
83 */
84
85 /*
86 * Keyboard driver (/dev/wskbd*). Translates incoming bytes to ASCII or
87 * to `wscons_events' and passes them up to the appropriate reader.
88 */
89
90 #include "opt_ddb.h"
91
92 #include <sys/param.h>
93 #include <sys/conf.h>
94 #include <sys/device.h>
95 #include <sys/ioctl.h>
96 #include <sys/kernel.h>
97 #include <sys/proc.h>
98 #include <sys/syslog.h>
99 #include <sys/systm.h>
100 #include <sys/malloc.h>
101 #include <sys/tty.h>
102 #include <sys/signalvar.h>
103 #include <sys/errno.h>
104 #include <sys/fcntl.h>
105 #include <sys/vnode.h>
106
107 #include <dev/wscons/wsconsio.h>
108 #include <dev/wscons/wskbdvar.h>
109 #include <dev/wscons/wsksymdef.h>
110 #include <dev/wscons/wsksymvar.h>
111 #include <dev/wscons/wseventvar.h>
112 #include <dev/wscons/wscons_callbacks.h>
113
114 #include "opt_wsdisplay_compat.h"
115
116 #include "wsdisplay.h"
117 #include "wsmux.h"
118
119 #ifdef WSKBD_DEBUG
120 #define DPRINTF(x) if (wskbddebug) printf x
121 int wskbddebug = 0;
122 #else
123 #define DPRINTF(x)
124 #endif
125
126 #if NWSMUX > 0 || NWSDISPLAY > 0
127 #include <dev/wscons/wsmuxvar.h>
128 #endif
129
130 struct wskbd_internal {
131 const struct wskbd_mapdata *t_keymap;
132
133 const struct wskbd_consops *t_consops;
134 void *t_consaccesscookie;
135
136 int t_modifiers;
137 int t_composelen; /* remaining entries in t_composebuf */
138 keysym_t t_composebuf[2];
139
140 struct wskbd_softc *t_sc; /* back pointer */
141 };
142
143 struct wskbd_softc {
144 struct device sc_dv;
145
146 struct wskbd_internal *id;
147
148 const struct wskbd_accessops *sc_accessops;
149 void *sc_accesscookie;
150
151 int sc_ledstate;
152
153 int sc_ready; /* accepting events */
154 struct wseventvar sc_events; /* event queue state */
155
156 int sc_isconsole;
157 #if NWSDISPLAY > 0
158 struct device *sc_displaydv;
159 #endif
160
161 struct wskbd_bell_data sc_bell_data;
162 struct wskbd_keyrepeat_data sc_keyrepeat_data;
163
164 int sc_repeating; /* we've called timeout() */
165 keysym_t sc_repeatsym; /* repeated symbol */
166
167 int sc_translating; /* xlate to chars for emulation */
168
169 int sc_maplen; /* number of entries in sc_map */
170 struct wscons_keymap *sc_map; /* current translation map */
171 kbd_t sc_layout; /* current layout */
172
173 int sc_refcnt;
174 u_char sc_dying; /* device is being detached */
175
176 #if NWSMUX > 0 || NWSDISPLAY > 0
177 struct wsmux_softc *sc_mux;
178 #endif
179 };
180
181 #define MOD_SHIFT_L (1 << 0)
182 #define MOD_SHIFT_R (1 << 1)
183 #define MOD_SHIFTLOCK (1 << 2)
184 #define MOD_CAPSLOCK (1 << 3)
185 #define MOD_CONTROL_L (1 << 4)
186 #define MOD_CONTROL_R (1 << 5)
187 #define MOD_META_L (1 << 6)
188 #define MOD_META_R (1 << 7)
189 #define MOD_MODESHIFT (1 << 8)
190 #define MOD_NUMLOCK (1 << 9)
191 #define MOD_COMPOSE (1 << 10)
192 #define MOD_HOLDSCREEN (1 << 11)
193 #define MOD_COMMAND (1 << 12)
194 #define MOD_COMMAND1 (1 << 13)
195 #define MOD_COMMAND2 (1 << 14)
196
197 #define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK)
198 #define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R)
199 #define MOD_ANYMETA (MOD_META_L | MOD_META_R)
200
201 #define MOD_ONESET(id, mask) (((id)->t_modifiers & (mask)) != 0)
202 #define MOD_ALLSET(id, mask) (((id)->t_modifiers & (mask)) == (mask))
203
204 int wskbd_match __P((struct device *, struct cfdata *, void *));
205 void wskbd_attach __P((struct device *, struct device *, void *));
206 int wskbd_detach __P((struct device *, int));
207 int wskbd_activate __P((struct device *, enum devact));
208
209 static int wskbd_displayioctl
210 __P((struct device *, u_long, caddr_t, int, struct proc *p));
211 int wskbd_set_display __P((struct device *, struct wsmux_softc *));
212
213 static inline void update_leds __P((struct wskbd_internal *));
214 static inline void update_modifier __P((struct wskbd_internal *, u_int, int, int));
215 static int internal_command __P((struct wskbd_softc *, u_int *, keysym_t));
216 static keysym_t wskbd_translate __P((struct wskbd_internal *, u_int, int));
217 static int wskbd_enable __P((struct wskbd_softc *, int));
218 #if NWSDISPLAY > 0
219 static void wskbd_holdscreen __P((struct wskbd_softc *, int));
220 #endif
221
222 int wskbd_do_ioctl __P((struct wskbd_softc *, u_long, caddr_t,
223 int, struct proc *));
224
225 int wskbddoclose __P((struct device *, int, int, struct proc *));
226 int wskbddoioctl __P((struct device *, u_long, caddr_t, int,
227 struct proc *));
228
229 struct cfattach wskbd_ca = {
230 sizeof (struct wskbd_softc), wskbd_match, wskbd_attach,
231 wskbd_detach, wskbd_activate
232 };
233
234 extern struct cfdriver wskbd_cd;
235
236 #ifndef WSKBD_DEFAULT_BELL_PITCH
237 #define WSKBD_DEFAULT_BELL_PITCH 1500 /* 1500Hz */
238 #endif
239 #ifndef WSKBD_DEFAULT_BELL_PERIOD
240 #define WSKBD_DEFAULT_BELL_PERIOD 100 /* 100ms */
241 #endif
242 #ifndef WSKBD_DEFAULT_BELL_VOLUME
243 #define WSKBD_DEFAULT_BELL_VOLUME 50 /* 50% volume */
244 #endif
245
246 struct wskbd_bell_data wskbd_default_bell_data = {
247 WSKBD_BELL_DOALL,
248 WSKBD_DEFAULT_BELL_PITCH,
249 WSKBD_DEFAULT_BELL_PERIOD,
250 WSKBD_DEFAULT_BELL_VOLUME,
251 };
252
253 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1
254 #define WSKBD_DEFAULT_KEYREPEAT_DEL1 400 /* 400ms to start repeating */
255 #endif
256 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN
257 #define WSKBD_DEFAULT_KEYREPEAT_DELN 100 /* 100ms to between repeats */
258 #endif
259
260 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = {
261 WSKBD_KEYREPEAT_DOALL,
262 WSKBD_DEFAULT_KEYREPEAT_DEL1,
263 WSKBD_DEFAULT_KEYREPEAT_DELN,
264 };
265
266 cdev_decl(wskbd);
267
268 #if NWSMUX > 0 || NWSDISPLAY > 0
269 struct wsmuxops wskbd_muxops = {
270 wskbdopen, wskbddoclose, wskbddoioctl, wskbd_displayioctl,
271 wskbd_set_display
272 };
273 #endif
274
275 #if NWSDISPLAY > 0
276 static void wskbd_repeat __P((void *v));
277 #endif
278
279 static int wskbd_console_initted;
280 static struct wskbd_softc *wskbd_console_device;
281 static struct wskbd_internal wskbd_console_data;
282
283 /*
284 * Print function (for parent devices).
285 */
286 int
287 wskbddevprint(aux, pnp)
288 void *aux;
289 const char *pnp;
290 {
291 #if 0
292 struct wskbddev_attach_args *ap = aux;
293 #endif
294
295 if (pnp)
296 printf("wskbd at %s", pnp);
297 #if 0
298 printf(" console %d", ap->console);
299 #endif
300
301 return (UNCONF);
302 }
303
304 int
305 wskbd_match(parent, match, aux)
306 struct device *parent;
307 struct cfdata *match;
308 void *aux;
309 {
310 struct wskbddev_attach_args *ap = aux;
311
312 if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) {
313 /*
314 * If console-ness of device specified, either match
315 * exactly (at high priority), or fail.
316 */
317 if (match->wskbddevcf_console != 0 && ap->console != 0)
318 return (10);
319 else
320 return (0);
321 }
322
323 /* If console-ness unspecified, it wins. */
324 return (1);
325 }
326
327 void
328 wskbd_attach(parent, self, aux)
329 struct device *parent, *self;
330 void *aux;
331 {
332 struct wskbd_softc *sc = (struct wskbd_softc *)self;
333 struct wskbddev_attach_args *ap = aux;
334 #if NWSMUX > 0 || NWSDISPLAY > 0
335 int mux;
336 #endif
337
338 #if NWSDISPLAY > 0
339 sc->sc_displaydv = NULL;
340 #endif
341 sc->sc_isconsole = ap->console;
342
343 #if NWSMUX > 0 || NWSDISPLAY > 0
344 mux = sc->sc_dv.dv_cfdata->wskbddevcf_mux;
345 if (sc->sc_isconsole && mux != WSKBDDEVCF_MUX_DEFAULT) {
346 printf(" (mux %d ignored for console)", mux);
347 mux = WSKBDDEVCF_MUX_DEFAULT;
348 }
349 if (mux != WSKBDDEVCF_MUX_DEFAULT)
350 printf(" mux %d", mux);
351 #endif
352
353 if (ap->console) {
354 sc->id = &wskbd_console_data;
355 } else {
356 sc->id = malloc(sizeof(struct wskbd_internal),
357 M_DEVBUF, M_WAITOK);
358 sc->id->t_keymap = ap->keymap;
359 sc->id->t_modifiers = 0;
360 }
361
362 sc->id->t_sc = sc;
363
364 sc->sc_accessops = ap->accessops;
365 sc->sc_accesscookie = ap->accesscookie;
366 sc->sc_ready = 0; /* sanity */
367 sc->sc_repeating = 0;
368 sc->sc_translating = 1;
369 sc->sc_ledstate = -1; /* force update */
370
371 if (wskbd_load_keymap(sc->id->t_keymap,
372 &sc->sc_map, &sc->sc_maplen) != 0)
373 panic("cannot load keymap");
374
375 sc->sc_layout = sc->id->t_keymap->layout;
376
377 /* set default bell and key repeat data */
378 sc->sc_bell_data = wskbd_default_bell_data;
379 sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data;
380
381 if (ap->console) {
382 KASSERT(wskbd_console_initted);
383 KASSERT(wskbd_console_device == NULL);
384
385 wskbd_console_device = sc;
386
387 printf(": console keyboard");
388
389 #if NWSDISPLAY > 0
390 if ((sc->sc_displaydv = wsdisplay_set_console_kbd(self)))
391 printf(", using %s", sc->sc_displaydv->dv_xname);
392 #endif
393 }
394 printf("\n");
395
396 #if NWSMUX > 0
397 if (mux != WSKBDDEVCF_MUX_DEFAULT)
398 wsmux_attach(mux, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
399 &sc->sc_mux, &wskbd_muxops);
400 #endif
401
402 }
403
404 void
405 wskbd_cnattach(consops, conscookie, mapdata)
406 const struct wskbd_consops *consops;
407 void *conscookie;
408 const struct wskbd_mapdata *mapdata;
409 {
410 KASSERT(!wskbd_console_initted);
411
412 wskbd_console_data.t_keymap = mapdata;
413
414 wskbd_console_data.t_consops = consops;
415 wskbd_console_data.t_consaccesscookie = conscookie;
416
417 #if NWSDISPLAY > 0
418 wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc);
419 #endif
420
421 wskbd_console_initted = 1;
422 }
423
424 void
425 wskbd_cndetach()
426 {
427 KASSERT(wskbd_console_initted);
428
429 wskbd_console_data.t_keymap = 0;
430
431 wskbd_console_data.t_consops = 0;
432 wskbd_console_data.t_consaccesscookie = 0;
433
434 #if NWSDISPLAY > 0
435 wsdisplay_unset_cons_kbd();
436 #endif
437
438 wskbd_console_initted = 0;
439 }
440
441 #if NWSDISPLAY > 0
442 static void
443 wskbd_repeat(v)
444 void *v;
445 {
446 struct wskbd_softc *sc = (struct wskbd_softc *)v;
447 int s = spltty();
448
449 if (!sc->sc_repeating) {
450 /*
451 * race condition: a "key up" event came in when wskbd_repeat()
452 * was already called but not yet spltty()'d
453 */
454 splx(s);
455 return;
456 }
457 if (sc->sc_displaydv != NULL)
458 wsdisplay_kbdinput(sc->sc_displaydv, sc->sc_repeatsym);
459 timeout(wskbd_repeat, sc,
460 (hz * sc->sc_keyrepeat_data.delN) / 1000);
461 splx(s);
462 }
463 #endif
464
465 int
466 wskbd_activate(self, act)
467 struct device *self;
468 enum devact act;
469 {
470 /* XXX should we do something more? */
471 return (0);
472 }
473
474 /*
475 * Detach a keyboard. To keep track of users of the softc we keep
476 * a reference count that's incremented while inside, e.g., read.
477 * If the keyboard is active and the reference count is > 0 (0 is the
478 * normal state) we post an event and then wait for the process
479 * that had the reference to wake us up again. Then we blow away the
480 * vnode and return (which will deallocate the softc).
481 */
482 int
483 wskbd_detach(self, flags)
484 struct device *self;
485 int flags;
486 {
487 struct wskbd_softc *sc = (struct wskbd_softc *)self;
488 struct wseventvar *evar;
489 int maj, mn;
490 int s;
491 #if NWSMUX > 0
492 int mux;
493
494 mux = sc->sc_dv.dv_cfdata->wskbddevcf_mux;
495 if (mux != WSMOUSEDEVCF_MUX_DEFAULT)
496 wsmux_detach(mux, &sc->sc_dv);
497 #endif
498
499 evar = &sc->sc_events;
500 if (evar->io) {
501 s = spltty();
502 if (--sc->sc_refcnt >= 0) {
503 /* Wake everyone by generating a dummy event. */
504 if (++evar->put >= WSEVENT_QSIZE)
505 evar->put = 0;
506 WSEVENT_WAKEUP(evar);
507 /* Wait for processes to go away. */
508 if (tsleep(sc, PZERO, "wskdet", hz * 60))
509 printf("wskbd_detach: %s didn't detach\n",
510 sc->sc_dv.dv_xname);
511 }
512 splx(s);
513 }
514
515 /* locate the major number */
516 for (maj = 0; maj < nchrdev; maj++)
517 if (cdevsw[maj].d_open == wskbdopen)
518 break;
519
520 /* Nuke the vnodes for any open instances. */
521 mn = self->dv_unit;
522 vdevgone(maj, mn, mn, VCHR);
523
524 return (0);
525 }
526
527 void
528 wskbd_input(dev, type, value)
529 struct device *dev;
530 u_int type;
531 int value;
532 {
533 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
534 struct wscons_event *ev;
535 struct wseventvar *evar;
536 struct timeval xxxtime;
537 #if NWSDISPLAY > 0
538 keysym_t ks;
539 #endif
540 int put;
541
542 #if NWSDISPLAY > 0
543 if (sc->sc_repeating) {
544 sc->sc_repeating = 0;
545 untimeout(wskbd_repeat, sc);
546 }
547
548 /*
549 * If /dev/wskbd is not connected in event mode translate and
550 * send upstream.
551 */
552 if (sc->sc_translating) {
553 ks = wskbd_translate(sc->id, type, value);
554 if (ks != KS_voidSymbol) {
555 sc->sc_repeatsym = ks;
556 if (sc->sc_displaydv != NULL)
557 wsdisplay_kbdinput(sc->sc_displaydv,
558 sc->sc_repeatsym);
559
560 sc->sc_repeating = 1;
561 timeout(wskbd_repeat, sc,
562 (hz * sc->sc_keyrepeat_data.del1) / 1000);
563 }
564 return;
565 }
566 #endif
567
568 /*
569 * Keyboard is generating events. Turn this keystroke into an
570 * event and put it in the queue. If the queue is full, the
571 * keystroke is lost (sorry!).
572 */
573
574 /* no one to receive; punt!*/
575 if (!sc->sc_ready)
576 return;
577
578 #if NWSMUX > 0
579 if (sc->sc_mux)
580 evar = &sc->sc_mux->sc_events;
581 else
582 #endif
583 evar = &sc->sc_events;
584
585 put = evar->put;
586 ev = &evar->q[put];
587 put = (put + 1) % WSEVENT_QSIZE;
588 if (put == evar->get) {
589 log(LOG_WARNING, "%s: event queue overflow\n",
590 sc->sc_dv.dv_xname);
591 return;
592 }
593 ev->type = type;
594 ev->value = value;
595 microtime(&xxxtime);
596 TIMEVAL_TO_TIMESPEC(&xxxtime, &ev->time);
597 evar->put = put;
598 WSEVENT_WAKEUP(evar);
599 }
600
601 #ifdef WSDISPLAY_COMPAT_RAWKBD
602 void
603 wskbd_rawinput(dev, buf, len)
604 struct device *dev;
605 char *buf;
606 int len;
607 {
608 #if NWSDISPLAY > 0
609 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
610 int i;
611
612 for (i = 0; i < len; i++)
613 wsdisplay_kbdinput(sc->sc_displaydv, buf[i]);
614 /* this is KS_GROUP_Ascii */
615 #endif
616 }
617 #endif /* WSDISPLAY_COMPAT_RAWKBD */
618
619 #if NWSDISPLAY > 0
620 static void
621 wskbd_holdscreen(sc, hold)
622 struct wskbd_softc *sc;
623 int hold;
624 {
625 int new_state;
626
627 if (sc->sc_displaydv != NULL) {
628 wsdisplay_kbdholdscreen(sc->sc_displaydv, hold);
629 new_state = sc->sc_ledstate;
630 if (hold)
631 new_state |= WSKBD_LED_SCROLL;
632 else
633 new_state &= ~WSKBD_LED_SCROLL;
634 if (new_state != sc->sc_ledstate) {
635 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie,
636 new_state);
637 sc->sc_ledstate = new_state;
638 }
639 }
640 }
641 #endif
642
643 static int
644 wskbd_enable(sc, on)
645 struct wskbd_softc *sc;
646 int on;
647 {
648 int res;
649
650 /* XXX reference count? */
651 if (!on && (!sc->sc_translating
652 #if NWSDISPLAY > 0
653 || sc->sc_displaydv
654 #endif
655 ))
656 return (EBUSY);
657
658 res = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on);
659 return (res);
660 }
661
662 int
663 wskbdopen(dev, flags, mode, p)
664 dev_t dev;
665 int flags, mode;
666 struct proc *p;
667 {
668 struct wskbd_softc *sc;
669 int unit;
670
671 unit = minor(dev);
672 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */
673 (sc = wskbd_cd.cd_devs[unit]) == NULL)
674 return (ENXIO);
675
676 if (sc->sc_dying)
677 return (EIO);
678
679 if (!(flags & FREAD)) {
680 /* Not opening for read, only ioctl is available. */
681 return (0);
682 }
683
684 #if NWSMUX > 0
685 if (sc->sc_mux)
686 return (EBUSY);
687 #endif
688
689 if (sc->sc_events.io) /* and that it's not in use */
690 return (EBUSY);
691
692 sc->sc_events.io = p;
693 wsevent_init(&sc->sc_events); /* may cause sleep */
694
695 sc->sc_translating = 0;
696 sc->sc_ready = 1; /* start accepting events */
697
698 wskbd_enable(sc, 1);
699 return (0);
700 }
701
702 int
703 wskbdclose(dev, flags, mode, p)
704 dev_t dev;
705 int flags, mode;
706 struct proc *p;
707 {
708 return (wskbddoclose(wskbd_cd.cd_devs[minor(dev)], flags, mode, p));
709 }
710
711 int
712 wskbddoclose(dv, flags, mode, p)
713 struct device *dv;
714 int flags, mode;
715 struct proc *p;
716 {
717 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
718
719 if (!(flags & FREAD)) {
720 /* Nothing to do, because open didn't do anything. */
721 return (0);
722 }
723
724 sc->sc_ready = 0; /* stop accepting events */
725 sc->sc_translating = 1;
726
727 wsevent_fini(&sc->sc_events);
728 sc->sc_events.io = NULL;
729
730 wskbd_enable(sc, 0);
731 return (0);
732 }
733
734 int
735 wskbdread(dev, uio, flags)
736 dev_t dev;
737 struct uio *uio;
738 int flags;
739 {
740 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
741 int error;
742
743 if (sc->sc_dying)
744 return (EIO);
745
746 sc->sc_refcnt++;
747 error = wsevent_read(&sc->sc_events, uio, flags);
748 if (--sc->sc_refcnt < 0) {
749 wakeup(sc);
750 error = EIO;
751 }
752 return (error);
753 }
754
755 int
756 wskbdioctl(dev, cmd, data, flag, p)
757 dev_t dev;
758 u_long cmd;
759 caddr_t data;
760 int flag;
761 struct proc *p;
762 {
763 return (wskbddoioctl(wskbd_cd.cd_devs[minor(dev)], cmd, data, flag,p));
764 }
765
766 /* A wrapper around the ioctl() workhorse to make reference counting easy. */
767 int
768 wskbddoioctl(dv, cmd, data, flag, p)
769 struct device *dv;
770 u_long cmd;
771 caddr_t data;
772 int flag;
773 struct proc *p;
774 {
775 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
776 int error;
777
778 sc->sc_refcnt++;
779 error = wskbd_do_ioctl(sc, cmd, data, flag, p);
780 if (--sc->sc_refcnt < 0)
781 wakeup(sc);
782 return (error);
783 }
784
785 int
786 wskbd_do_ioctl(sc, cmd, data, flag, p)
787 struct wskbd_softc *sc;
788 u_long cmd;
789 caddr_t data;
790 int flag;
791 struct proc *p;
792 {
793 int error;
794
795 /*
796 * Try the generic ioctls that the wskbd interface supports.
797 */
798 switch (cmd) {
799 case FIONBIO: /* we will remove this someday (soon???) */
800 return (0);
801
802 case FIOASYNC:
803 sc->sc_events.async = *(int *)data != 0;
804 return (0);
805
806 case TIOCSPGRP:
807 if (*(int *)data != sc->sc_events.io->p_pgid)
808 return (EPERM);
809 return (0);
810 }
811
812 /*
813 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
814 * if it didn't recognize the request.
815 */
816 error = wskbd_displayioctl((struct device *)sc, cmd, data, flag, p);
817 return (error != -1 ? error : ENOTTY);
818 }
819
820 /*
821 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode.
822 * Some of these have no real effect in raw mode, however.
823 */
824 static int
825 wskbd_displayioctl(dev, cmd, data, flag, p)
826 struct device *dev;
827 u_long cmd;
828 caddr_t data;
829 int flag;
830 struct proc *p;
831 {
832 struct wskbd_softc *sc = (struct wskbd_softc *)dev;
833 struct wskbd_bell_data *ubdp, *kbdp;
834 struct wskbd_keyrepeat_data *ukdp, *kkdp;
835 struct wskbd_map_data *umdp;
836 struct wskbd_mapdata md;
837 void *buf;
838 int len, error;
839
840 switch (cmd) {
841 #define SETBELL(dstp, srcp, dfltp) \
842 do { \
843 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \
844 (srcp)->pitch : (dfltp)->pitch; \
845 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \
846 (srcp)->period : (dfltp)->period; \
847 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \
848 (srcp)->volume : (dfltp)->volume; \
849 (dstp)->which = WSKBD_BELL_DOALL; \
850 } while (0)
851
852 case WSKBDIO_BELL:
853 if ((flag & FWRITE) == 0)
854 return (EACCES);
855 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
856 WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p));
857
858 case WSKBDIO_COMPLEXBELL:
859 if ((flag & FWRITE) == 0)
860 return (EACCES);
861 ubdp = (struct wskbd_bell_data *)data;
862 SETBELL(ubdp, ubdp, &sc->sc_bell_data);
863 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie,
864 WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p));
865
866 case WSKBDIO_SETBELL:
867 if ((flag & FWRITE) == 0)
868 return (EACCES);
869 kbdp = &sc->sc_bell_data;
870 setbell:
871 ubdp = (struct wskbd_bell_data *)data;
872 SETBELL(kbdp, ubdp, kbdp);
873 return (0);
874
875 case WSKBDIO_GETBELL:
876 kbdp = &sc->sc_bell_data;
877 getbell:
878 ubdp = (struct wskbd_bell_data *)data;
879 SETBELL(ubdp, kbdp, kbdp);
880 return (0);
881
882 case WSKBDIO_SETDEFAULTBELL:
883 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
884 return (error);
885 kbdp = &wskbd_default_bell_data;
886 goto setbell;
887
888
889 case WSKBDIO_GETDEFAULTBELL:
890 kbdp = &wskbd_default_bell_data;
891 goto getbell;
892
893 #undef SETBELL
894
895 #define SETKEYREPEAT(dstp, srcp, dfltp) \
896 do { \
897 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \
898 (srcp)->del1 : (dfltp)->del1; \
899 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \
900 (srcp)->delN : (dfltp)->delN; \
901 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \
902 } while (0)
903
904 case WSKBDIO_SETKEYREPEAT:
905 if ((flag & FWRITE) == 0)
906 return (EACCES);
907 kkdp = &sc->sc_keyrepeat_data;
908 setkeyrepeat:
909 ukdp = (struct wskbd_keyrepeat_data *)data;
910 SETKEYREPEAT(kkdp, ukdp, kkdp);
911 return (0);
912
913 case WSKBDIO_GETKEYREPEAT:
914 kkdp = &sc->sc_keyrepeat_data;
915 getkeyrepeat:
916 ukdp = (struct wskbd_keyrepeat_data *)data;
917 SETKEYREPEAT(ukdp, kkdp, kkdp);
918 return (0);
919
920 case WSKBDIO_SETDEFAULTKEYREPEAT:
921 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
922 return (error);
923 kkdp = &wskbd_default_keyrepeat_data;
924 goto setkeyrepeat;
925
926
927 case WSKBDIO_GETDEFAULTKEYREPEAT:
928 kkdp = &wskbd_default_keyrepeat_data;
929 goto getkeyrepeat;
930
931 #undef SETKEYREPEAT
932
933 case WSKBDIO_SETMAP:
934 if ((flag & FWRITE) == 0)
935 return (EACCES);
936 umdp = (struct wskbd_map_data *)data;
937 len = umdp->maplen*sizeof(struct wscons_keymap);
938 buf = malloc(len, M_TEMP, M_WAITOK);
939 error = copyin(umdp->map, buf, len);
940 if (error == 0) {
941 wskbd_init_keymap(umdp->maplen,
942 &sc->sc_map, &sc->sc_maplen);
943 memcpy(sc->sc_map, buf, len);
944 sc->sc_layout = KB_USER;
945 }
946 free(buf, M_TEMP);
947 return(error);
948
949 case WSKBDIO_GETMAP:
950 umdp = (struct wskbd_map_data *)data;
951 if (umdp->maplen > sc->sc_maplen)
952 umdp->maplen = sc->sc_maplen;
953 error = copyout(sc->sc_map, umdp->map,
954 umdp->maplen*sizeof(struct wscons_keymap));
955 return(error);
956
957 case WSKBDIO_GETENCODING:
958 *((kbd_t *) data) = sc->sc_layout;
959 return(0);
960
961 case WSKBDIO_SETENCODING:
962 if ((flag & FWRITE) == 0)
963 return (EACCES);
964 md = *(sc->id->t_keymap); /* structure assignment */
965 md.layout = *((kbd_t *)data);
966 error = wskbd_load_keymap(&md, &sc->sc_map, &sc->sc_maplen);
967 if (error == 0)
968 sc->sc_layout = *((kbd_t *)data);
969 return(error);
970 }
971
972 /*
973 * Try the keyboard driver for WSKBDIO ioctls. It returns -1
974 * if it didn't recognize the request, and in turn we return
975 * -1 if we didn't recognize the request.
976 */
977 /* printf("kbdaccess\n"); */
978 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data,
979 flag, p);
980 #ifdef WSDISPLAY_COMPAT_RAWKBD
981 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) {
982 int s = spltty();
983 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
984 | MOD_CONTROL_L | MOD_CONTROL_R
985 | MOD_META_L | MOD_META_R
986 | MOD_COMMAND
987 | MOD_COMMAND1 | MOD_COMMAND2);
988 #if NWSDISPLAY > 0
989 if (sc->sc_repeating) {
990 sc->sc_repeating = 0;
991 untimeout(wskbd_repeat, sc);
992 }
993 #endif
994 splx(s);
995 }
996 #endif
997 return (error);
998 }
999
1000 int
1001 wskbdpoll(dev, events, p)
1002 dev_t dev;
1003 int events;
1004 struct proc *p;
1005 {
1006 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)];
1007
1008 return (wsevent_poll(&sc->sc_events, events, p));
1009 }
1010
1011 #if NWSDISPLAY > 0
1012
1013 int
1014 wskbd_pickfree()
1015 {
1016 int i;
1017 struct wskbd_softc *sc;
1018
1019 for (i = 0; i < wskbd_cd.cd_ndevs; i++) {
1020 if ((sc = wskbd_cd.cd_devs[i]) == NULL)
1021 continue;
1022 if (sc->sc_displaydv == NULL)
1023 return (i);
1024 }
1025 return (-1);
1026 }
1027
1028 struct device *
1029 wskbd_set_console_display(displaydv, muxsc)
1030 struct device *displaydv;
1031 struct wsmux_softc *muxsc;
1032 {
1033 struct wskbd_softc *sc = wskbd_console_device;
1034
1035 if (!sc)
1036 return (0);
1037 sc->sc_displaydv = displaydv;
1038 (void)wsmux_attach_sc(muxsc, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
1039 &sc->sc_mux, &wskbd_muxops);
1040 return (&sc->sc_dv);
1041 }
1042
1043 int
1044 wskbd_set_display(dv, muxsc)
1045 struct device *dv;
1046 struct wsmux_softc *muxsc;
1047 {
1048 struct wskbd_softc *sc = (struct wskbd_softc *)dv;
1049 struct device *displaydv = muxsc ? muxsc->sc_displaydv : 0;
1050 struct device *odisplaydv;
1051 int error;
1052
1053 DPRINTF(("wskbd_set_display: %s mux=%p disp=%p odisp=%p cons=%d\n",
1054 dv->dv_xname, muxsc, sc->sc_displaydv, displaydv,
1055 sc->sc_isconsole));
1056
1057 if (sc->sc_isconsole)
1058 return (EBUSY);
1059
1060 if (displaydv) {
1061 if (sc->sc_displaydv)
1062 return (EBUSY);
1063 } else {
1064 if (sc->sc_displaydv == NULL)
1065 return (ENXIO);
1066 }
1067
1068 odisplaydv = sc->sc_displaydv;
1069 sc->sc_displaydv = displaydv;
1070
1071 error = wskbd_enable(sc, displaydv != NULL);
1072 if (error) {
1073 sc->sc_displaydv = odisplaydv;
1074 return (error);
1075 }
1076
1077 if (displaydv)
1078 printf("%s: connecting to %s\n",
1079 sc->sc_dv.dv_xname, displaydv->dv_xname);
1080 else
1081 printf("%s: disconnecting from %s\n",
1082 sc->sc_dv.dv_xname, odisplaydv->dv_xname);
1083
1084 return (0);
1085 }
1086
1087 int
1088 wskbd_add_mux(unit, muxsc)
1089 int unit;
1090 struct wsmux_softc *muxsc;
1091 {
1092 struct wskbd_softc *sc;
1093
1094 DPRINTF(("wskbd_add_mux: %d %s %p\n", unit, muxsc->sc_dv.dv_xname,
1095 muxsc->sc_displaydv));
1096 if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1097 (sc = wskbd_cd.cd_devs[unit]) == NULL)
1098 return (ENXIO);
1099
1100 if (sc->sc_mux || sc->sc_events.io)
1101 return (EBUSY);
1102
1103 return (wsmux_attach_sc(muxsc, WSMUX_KBD, &sc->sc_dv, &sc->sc_events,
1104 &sc->sc_mux, &wskbd_muxops));
1105 }
1106
1107 int
1108 wskbd_rem_mux(unit, muxsc)
1109 int unit;
1110 struct wsmux_softc *muxsc;
1111 {
1112 struct wskbd_softc *sc;
1113
1114 DPRINTF(("wskbd_rem_mux: %d %s\n", unit, muxsc->sc_dv.dv_xname));
1115 if (unit < 0 || unit >= wskbd_cd.cd_ndevs ||
1116 (sc = wskbd_cd.cd_devs[unit]) == NULL)
1117 return (ENXIO);
1118
1119 return (wsmux_detach_sc(muxsc, &sc->sc_dv));
1120 }
1121
1122 #endif /* NWSDISPLAY > 0 */
1123
1124 /*
1125 * Console interface.
1126 */
1127 int
1128 wskbd_cngetc(dev)
1129 dev_t dev;
1130 {
1131 u_int type;
1132 int data;
1133 keysym_t ks;
1134
1135 if (!wskbd_console_initted)
1136 return 0;
1137
1138 if (wskbd_console_device != NULL &&
1139 !wskbd_console_device->sc_translating)
1140 return 0;
1141
1142 for(;;) {
1143 (*wskbd_console_data.t_consops->getc)
1144 (wskbd_console_data.t_consaccesscookie, &type, &data);
1145 ks = wskbd_translate(&wskbd_console_data, type, data);
1146
1147 if (KS_GROUP(ks) == KS_GROUP_Ascii)
1148 return (KS_VALUE(ks));
1149 }
1150 }
1151
1152 void
1153 wskbd_cnpollc(dev, poll)
1154 dev_t dev;
1155 int poll;
1156 {
1157
1158 if (!wskbd_console_initted)
1159 return;
1160
1161 if (wskbd_console_device != NULL &&
1162 !wskbd_console_device->sc_translating)
1163 return;
1164
1165 (*wskbd_console_data.t_consops->pollc)
1166 (wskbd_console_data.t_consaccesscookie, poll);
1167 }
1168
1169 static inline void
1170 update_leds(id)
1171 struct wskbd_internal *id;
1172 {
1173 int new_state;
1174
1175 new_state = 0;
1176 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK))
1177 new_state |= WSKBD_LED_CAPS;
1178 if (id->t_modifiers & MOD_NUMLOCK)
1179 new_state |= WSKBD_LED_NUM;
1180 if (id->t_modifiers & MOD_COMPOSE)
1181 new_state |= WSKBD_LED_COMPOSE;
1182 if (id->t_modifiers & MOD_HOLDSCREEN)
1183 new_state |= WSKBD_LED_SCROLL;
1184
1185 if (id->t_sc && new_state != id->t_sc->sc_ledstate) {
1186 (*id->t_sc->sc_accessops->set_leds)
1187 (id->t_sc->sc_accesscookie, new_state);
1188 id->t_sc->sc_ledstate = new_state;
1189 }
1190 }
1191
1192 static inline void
1193 update_modifier(id, type, toggle, mask)
1194 struct wskbd_internal *id;
1195 u_int type;
1196 int toggle;
1197 int mask;
1198 {
1199 if (toggle) {
1200 if (type == WSCONS_EVENT_KEY_DOWN)
1201 id->t_modifiers ^= mask;
1202 } else {
1203 if (type == WSCONS_EVENT_KEY_DOWN)
1204 id->t_modifiers |= mask;
1205 else
1206 id->t_modifiers &= ~mask;
1207 }
1208 }
1209
1210 static int
1211 internal_command(sc, type, ksym)
1212 struct wskbd_softc *sc;
1213 u_int *type;
1214 keysym_t ksym;
1215 {
1216 switch (ksym) {
1217 case KS_Cmd:
1218 update_modifier(sc->id, *type, 0, MOD_COMMAND);
1219 break;
1220
1221 case KS_Cmd1:
1222 update_modifier(sc->id, *type, 0, MOD_COMMAND1);
1223 break;
1224
1225 case KS_Cmd2:
1226 update_modifier(sc->id, *type, 0, MOD_COMMAND2);
1227 break;
1228 }
1229
1230 if (*type != WSCONS_EVENT_KEY_DOWN ||
1231 (! MOD_ONESET(sc->id, MOD_COMMAND) &&
1232 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)))
1233 return (0);
1234
1235 switch (ksym) {
1236 #ifdef DDB
1237 case KS_Cmd_Debugger:
1238 if (sc->sc_isconsole)
1239 console_debugger();
1240 /* discard this key (ddb discarded command modifiers) */
1241 *type = WSCONS_EVENT_KEY_UP;
1242 return (1);
1243 #endif
1244
1245 #if NWSDISPLAY > 0
1246 case KS_Cmd_Screen0:
1247 case KS_Cmd_Screen1:
1248 case KS_Cmd_Screen2:
1249 case KS_Cmd_Screen3:
1250 case KS_Cmd_Screen4:
1251 case KS_Cmd_Screen5:
1252 case KS_Cmd_Screen6:
1253 case KS_Cmd_Screen7:
1254 case KS_Cmd_Screen8:
1255 case KS_Cmd_Screen9:
1256 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0);
1257 return (1);
1258 case KS_Cmd_ResetEmul:
1259 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL);
1260 return (1);
1261 case KS_Cmd_ResetClose:
1262 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE);
1263 return (1);
1264 #endif
1265 }
1266 return (0);
1267 }
1268
1269 static keysym_t
1270 wskbd_translate(id, type, value)
1271 struct wskbd_internal *id;
1272 u_int type;
1273 int value;
1274 {
1275 struct wskbd_softc *sc = id->t_sc;
1276 keysym_t ksym, res, *group;
1277 struct wscons_keymap kpbuf, *kp;
1278 int iscommand = 0;
1279
1280 if (type == WSCONS_EVENT_ALL_KEYS_UP) {
1281 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R
1282 | MOD_CONTROL_L | MOD_CONTROL_R
1283 | MOD_META_L | MOD_META_R
1284 | MOD_MODESHIFT
1285 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2);
1286 update_leds(id);
1287 return (KS_voidSymbol);
1288 }
1289
1290 if (sc != NULL) {
1291 if (value < 0 || value >= sc->sc_maplen) {
1292 #ifdef DEBUG
1293 printf("wskbd_translate: keycode %d out of range\n",
1294 value);
1295 #endif
1296 return (KS_voidSymbol);
1297 }
1298 kp = sc->sc_map + value;
1299 } else {
1300 kp = &kpbuf;
1301 wskbd_get_mapentry(id->t_keymap, value, kp);
1302 }
1303
1304 /* if this key has a command, process it first */
1305 if (sc != NULL && kp->command != KS_voidSymbol)
1306 iscommand = internal_command(sc, &type, kp->command);
1307
1308 /* Now update modifiers */
1309 switch (kp->group1[0]) {
1310 case KS_Shift_L:
1311 update_modifier(id, type, 0, MOD_SHIFT_L);
1312 break;
1313
1314 case KS_Shift_R:
1315 update_modifier(id, type, 0, MOD_SHIFT_R);
1316 break;
1317
1318 case KS_Shift_Lock:
1319 update_modifier(id, type, 1, MOD_SHIFTLOCK);
1320 break;
1321
1322 case KS_Caps_Lock:
1323 update_modifier(id, type, 1, MOD_CAPSLOCK);
1324 break;
1325
1326 case KS_Control_L:
1327 update_modifier(id, type, 0, MOD_CONTROL_L);
1328 break;
1329
1330 case KS_Control_R:
1331 update_modifier(id, type, 0, MOD_CONTROL_R);
1332 break;
1333
1334 case KS_Alt_L:
1335 update_modifier(id, type, 0, MOD_META_L);
1336 break;
1337
1338 case KS_Alt_R:
1339 update_modifier(id, type, 0, MOD_META_R);
1340 break;
1341
1342 case KS_Mode_switch:
1343 update_modifier(id, type, 0, MOD_MODESHIFT);
1344 break;
1345
1346 case KS_Num_Lock:
1347 update_modifier(id, type, 1, MOD_NUMLOCK);
1348 break;
1349
1350 #if NWSDISPLAY > 0
1351 case KS_Hold_Screen:
1352 if (sc != NULL) {
1353 update_modifier(id, type, 1, MOD_HOLDSCREEN);
1354 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN);
1355 }
1356 break;
1357 #endif
1358 }
1359
1360 /* If this is a key release or we are in command mode, we are done */
1361 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) {
1362 update_leds(id);
1363 return (KS_voidSymbol);
1364 }
1365
1366 /* Get the keysym */
1367 if (id->t_modifiers & MOD_MODESHIFT)
1368 group = & kp->group2[0];
1369 else
1370 group = & kp->group1[0];
1371
1372 if ((id->t_modifiers & MOD_NUMLOCK) != 0 &&
1373 KS_GROUP(group[1]) == KS_GROUP_Keypad) {
1374 if (MOD_ONESET(id, MOD_ANYSHIFT))
1375 ksym = group[0];
1376 else
1377 ksym = group[1];
1378 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) {
1379 ksym = group[0];
1380 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) {
1381 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R))
1382 ksym = group[0];
1383 else
1384 ksym = group[1];
1385 if (ksym >= KS_a && ksym <= KS_z)
1386 ksym += KS_A - KS_a;
1387 else if (ksym >= KS_agrave && ksym <= KS_thorn &&
1388 ksym != KS_division)
1389 ksym += KS_Agrave - KS_agrave;
1390 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) {
1391 ksym = group[1];
1392 } else {
1393 ksym = group[0];
1394 }
1395
1396 /* Process compose sequence and dead accents */
1397 res = KS_voidSymbol;
1398
1399 switch (KS_GROUP(ksym)) {
1400 case KS_GROUP_Ascii:
1401 case KS_GROUP_Keypad:
1402 case KS_GROUP_Function:
1403 res = ksym;
1404 break;
1405
1406 case KS_GROUP_Mod:
1407 if (ksym == KS_Multi_key) {
1408 update_modifier(id, 1, 0, MOD_COMPOSE);
1409 id->t_composelen = 2;
1410 }
1411 break;
1412
1413 case KS_GROUP_Dead:
1414 if (id->t_composelen == 0) {
1415 update_modifier(id, 1, 0, MOD_COMPOSE);
1416 id->t_composelen = 1;
1417 id->t_composebuf[0] = ksym;
1418 } else
1419 res = ksym;
1420 break;
1421 }
1422
1423 if (res == KS_voidSymbol) {
1424 update_leds(id);
1425 return (res);
1426 }
1427
1428 if (id->t_composelen > 0) {
1429 id->t_composebuf[2 - id->t_composelen] = res;
1430 if (--id->t_composelen == 0) {
1431 res = wskbd_compose_value(id->t_composebuf);
1432 update_modifier(id, 0, 0, MOD_COMPOSE);
1433 } else {
1434 return (KS_voidSymbol);
1435 }
1436 }
1437
1438 update_leds(id);
1439
1440 /* We are done, return the symbol */
1441 if (KS_GROUP(res) == KS_GROUP_Ascii) {
1442 if (MOD_ONESET(id, MOD_ANYCONTROL)) {
1443 if ((res >= KS_at && res <= KS_z) || res == KS_space)
1444 res = res & 0x1f;
1445 else if (res == KS_2)
1446 res = 0x00;
1447 else if (res >= KS_3 && res <= KS_7)
1448 res = KS_Escape + (res - KS_3);
1449 else if (res == KS_8)
1450 res = KS_Delete;
1451 }
1452 if (MOD_ONESET(id, MOD_ANYMETA))
1453 res |= 0x80;
1454 }
1455
1456 return (res);
1457 }
1458