#define KEYMAP_SIZE_VARIABLE
#include <sys/types.h>
#include <sys/cred.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/kmem.h>
#include <sys/kbd.h>
#include <sys/cmn_err.h>
#include <sys/modctl.h>
#include <sys/kbio.h>
#include <sys/vuid_event.h>
#include <sys/consdev.h>
#include <sys/kbtrans.h>
#include <sys/errno.h>
#include <sys/promif.h>
#include <sys/varargs.h>
#include "kbtrans_lower.h"
static boolean_t kbtrans_do_compose(struct kbtrans_lower *, keymap_entry_t,
keymap_entry_t, keymap_entry_t *);
static void kbtrans_translate(struct kbtrans_lower *,
struct keyboard_callback *, kbtrans_key_t, enum keystate);
void
kbtrans_processkey(struct kbtrans_lower *lower,
struct keyboard_callback *cb, kbtrans_key_t key, enum keystate state)
{
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "kbtrans_processkey: "
"newstate=%d key=%d", state, key));
if (cb->kc_keypressed_raw != NULL) {
if (state == KEY_PRESSED) {
cb->kc_keypressed_raw(lower->kbtrans_upper, key);
} else {
cb->kc_keyreleased_raw(lower->kbtrans_upper, key);
}
return;
}
kbtrans_translate(lower, cb, key, state);
}
static void
kbtrans_translate(struct kbtrans_lower *lower, struct keyboard_callback *cb,
kbtrans_key_t key, enum keystate newstate)
{
unsigned shiftmask;
register keymap_entry_t entry;
register unsigned entrytype;
keymap_entry_t result;
keymap_entry_t *ke;
int i;
boolean_t good_compose;
DPRINTF(PRINT_L0, PRINT_MASK_ALL, (lower, "KEY TRANSLATE "
"newstate=0x%x key=0x%x\n", newstate, key));
if (lower->kbtrans_keyboard == NULL) {
return;
}
shiftmask = lower->kbtrans_shiftmask;
if (newstate == KEY_RELEASED)
shiftmask |= UPMASK;
ke = kbtrans_find_entry(lower, shiftmask, key);
if (ke == NULL) {
cb->kc_cancel_repeat(lower->kbtrans_upper);
return;
}
entry = *ke;
if (entry == NONL) {
ke = kbtrans_find_entry(lower, shiftmask & ~NUMLOCKMASK, key);
if (ke == NULL) {
cb->kc_cancel_repeat(lower->kbtrans_upper);
return;
}
entry = *ke;
}
entrytype = KEYFLAGS(entry);
if (entrytype == SHIFTKEYS) {
if ((1 << (entry & 0x0F)) &
lower->kbtrans_keyboard->k_toggleshifts) {
if ((1 << (entry & 0x0F)) & lower->kbtrans_togglemask) {
newstate = KEY_RELEASED;
} else {
newstate = KEY_PRESSED;
}
}
} else {
switch (lower->kbtrans_state) {
case COMPOSE1:
if (newstate == KEY_RELEASED)
return;
if (entry < ASCII_SET_SIZE) {
if (lower->kbtrans_compose_map[entry] >= 0) {
lower->kbtrans_compose_key = entry;
lower->kbtrans_state = COMPOSE2;
return;
}
}
lower->kbtrans_state = NORMAL;
lower->kbtrans_led_state &= ~LED_COMPOSE;
cb->kc_setled(lower->kbtrans_upper);
return;
case COMPOSE2:
if (newstate == KEY_RELEASED)
return;
lower->kbtrans_state = NORMAL;
lower->kbtrans_led_state &= ~LED_COMPOSE;
cb->kc_setled(lower->kbtrans_upper);
good_compose = kbtrans_do_compose(lower,
lower->kbtrans_compose_key, entry, &result);
if (good_compose) {
cb->kc_keypressed(lower->kbtrans_upper,
entrytype, key, result);
}
return;
case FLTACCENT:
if (newstate == KEY_RELEASED)
return;
lower->kbtrans_state = NORMAL;
for (i = 0;
(lower->kbtrans_fltaccent_table[i].fa_entry !=
lower->kbtrans_fltaccent_entry) ||
(lower->kbtrans_fltaccent_table[i].ascii != entry);
i++) {
if (lower->kbtrans_fltaccent_table[i].fa_entry
== 0) {
return;
}
}
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
lower->kbtrans_fltaccent_table[i].utf8);
return;
}
}
if (newstate == KEY_PRESSED && entrytype != SHIFTKEYS &&
entrytype != BUCKYBITS && entrytype != FUNNY &&
entrytype != FA_CLASS) {
if (lower->kbtrans_repeatkey != key) {
cb->kc_cancel_repeat(lower->kbtrans_upper);
cb->kc_setup_repeat(lower->kbtrans_upper, entrytype,
key);
}
} else if (key == lower->kbtrans_repeatkey) {
cb->kc_cancel_repeat(lower->kbtrans_upper);
}
if (newstate == KEY_RELEASED) {
cb->kc_keyreleased(lower->kbtrans_upper, key);
}
switch (entrytype) {
case 0x0:
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
SPECIAL(lower->kbtrans_buckybits, entry));
break;
case SHIFTKEYS: {
uint_t shiftbit = 1 << (entry & 0x0F);
if (shiftbit & lower->kbtrans_keyboard->k_toggleshifts) {
if (newstate == KEY_RELEASED) {
if (shiftbit == CAPSMASK) {
lower->kbtrans_led_state &=
~LED_CAPS_LOCK;
cb->kc_setled(lower->kbtrans_upper);
} else if (shiftbit == NUMLOCKMASK) {
lower->kbtrans_led_state &=
~LED_NUM_LOCK;
cb->kc_setled(lower->kbtrans_upper);
}
lower->kbtrans_togglemask &= ~shiftbit;
} else {
if (shiftbit == CAPSMASK) {
lower->kbtrans_led_state |=
LED_CAPS_LOCK;
cb->kc_setled(lower->kbtrans_upper);
} else if (shiftbit == NUMLOCKMASK) {
lower->kbtrans_led_state |=
LED_NUM_LOCK;
cb->kc_setled(lower->kbtrans_upper);
}
lower->kbtrans_togglemask |= shiftbit;
}
}
if (newstate == KEY_RELEASED)
lower->kbtrans_shiftmask &= ~shiftbit;
else
lower->kbtrans_shiftmask |= shiftbit;
if (newstate == KEY_PRESSED) {
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
entry);
}
break;
}
case BUCKYBITS:
lower->kbtrans_buckybits ^= 1 << (entry & 0x0F);
if (newstate == KEY_PRESSED) {
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
entry);
}
break;
case FUNNY:
switch (entry) {
case NOP:
break;
case IDLE:
case RESET:
case ERROR:
lower->kbtrans_shiftmask &=
lower->kbtrans_keyboard->k_idleshifts;
lower->kbtrans_shiftmask |=
lower->kbtrans_togglemask;
lower->kbtrans_buckybits &=
lower->kbtrans_keyboard->k_idlebuckys;
cb->kc_cancel_repeat(lower->kbtrans_upper);
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key,
entry);
break;
case COMPOSE:
lower->kbtrans_state = COMPOSE1;
lower->kbtrans_led_state |= LED_COMPOSE;
cb->kc_setled(lower->kbtrans_upper);
break;
default:
break;
}
break;
case FA_CLASS:
if (lower->kbtrans_state == NORMAL) {
lower->kbtrans_fltaccent_entry = entry;
lower->kbtrans_state = FLTACCENT;
}
break;
case STRING:
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
break;
case FUNCKEYS:
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
break;
case PADKEYS:
cb->kc_keypressed(lower->kbtrans_upper, entrytype, key, entry);
break;
}
}
static boolean_t
kbtrans_do_compose(struct kbtrans_lower *lower, keymap_entry_t first_entry,
keymap_entry_t second_entry, keymap_entry_t *result_ptr)
{
struct compose_sequence_t *ptr;
keymap_entry_t tmp;
if (second_entry >= ASCII_SET_SIZE)
return (B_FALSE);
if (lower->kbtrans_compose_map[second_entry] < 0)
return (B_FALSE);
if (first_entry > second_entry) {
tmp = first_entry;
first_entry = second_entry;
second_entry = tmp;
}
ptr = lower->kbtrans_compose_table +
lower->kbtrans_compose_map[first_entry];
while (ptr->first == first_entry) {
if (ptr->second == second_entry) {
*result_ptr = ptr->utf8;
return (B_TRUE);
}
ptr++;
}
return (B_FALSE);
}
keymap_entry_t *
kbtrans_find_entry(struct kbtrans_lower *lower, uint_t mask,
kbtrans_key_t key_station)
{
register struct keyboard *kp;
keymap_entry_t *km;
struct exception_map *ex;
kp = lower->kbtrans_keyboard;
if (kp == NULL)
return (NULL);
if (key_station < 0 || key_station >= kp->k_keymap_size)
return (NULL);
ex = kp->k_except;
if (ex != NULL) {
for (; ex->exc_care != 0; ex++) {
if ((mask & ex->exc_care) == ex->exc_mask &&
key_station == ex->exc_key)
return (&ex->exc_entry);
}
}
if (mask & UPMASK)
km = kp->k_up;
else if (mask & NUMLOCKMASK)
km = kp->k_numlock;
else if (mask & CTRLMASK)
km = kp->k_control;
else if (mask & ALTGRAPHMASK)
km = kp->k_altgraph;
else if (mask & SHIFTMASK)
km = kp->k_shifted;
else if (mask & CAPSMASK)
km = kp->k_caps;
else km = kp->k_normal;
return (&km[key_station]);
}
#ifdef DEBUG
void
kbtrans_dprintf(void *un, const char *fmt, ...)
{
char buf[256];
va_list ap;
va_start(ap, fmt);
(void) vsprintf(buf, fmt, ap);
va_end(ap);
cmn_err(CE_CONT, "kbtrans: %s", buf);
}
#endif