/*
 *	$Source: /u1/Xr/src/Xrlib/Intrinsic/RCS/inputlib.c,v $
 *	$Header: inputlib.c,v 1.1 86/12/17 09:09:08 swick Exp $
 */

#ifndef lint
static char *rcsid_inputlib_c = "$Header: inputlib.c,v 1.1 86/12/17 09:09:08 swick Exp $";
#endif	lint

#include <Xr/xr-copyright.h>

/* $Header: inputlib.c,v 1.1 86/12/17 09:09:08 swick Exp $ */
/* Copyright 1986, Hewlett-Packard Company */
/* Copyright 1986, Massachussetts Institute of Technology */

static char rcsid[] = "$Header: inputlib.c,v 1.1 86/12/17 09:09:08 swick Exp $";
/*************************************<+>*************************************
 *****************************************************************************
 **
 **   File:        inputlib.c
 **
 **   Project:     X-ray Toolbox
 **
 **   Description: 
 **
 **
 **   ------------------------ MODIFICATION RECORD   ------------------------
 *
 * $Log:	inputlib.c,v $
 * Revision 1.1  86/12/17  09:09:08  swick
 * Initial revision
 * 
 * Revision 7.0  86/11/13  08:21:32  08:21:32  rick ()
 * Final QA release
 * 
 * Revision 6.0  86/11/10  15:22:40  15:22:40  rick ()
 * QA #2 release
 * 
 * Revision 5.1  86/11/07  14:02:27  14:02:27  rick ()
 * Added the copyright message.
 * 
 * Revision 5.0  86/10/28  08:23:22  08:23:22  rick ()
 * QA #1.1 release
 * 
 * Revision 4.2  86/10/24  10:19:33  10:19:33  karen
 * remove display parameter for XrInputInit(), use macro to get display type
 * 
 * Revision 3.1  86/10/09  11:04:18  11:04:18  rick ()
 * Fixed a couple of bugs.
 * 
 * Revision 3.0  86/10/02  15:59:11  15:59:11  rick ()
 *  Alpha release set to 3.0
 * 
 * Revision 1.1  86/10/02  07:17:21  07:17:21  fred ()
 * Initial revision
 * 
 *
 *****************************************************************************
 *************************************<+>*************************************/



#define	TRUE	1
#define	FALSE	0

#include <Xr/keycode.h>
#include "X/Xlib.h"
#include <fcntl.h>

static struct kbd_state *k;

extern unsigned char * k_alttab[];
extern unsigned char * k_langtab[];
extern unsigned char * k_isotab[];
extern unsigned short k_mute_enable[];
extern unsigned char k_alt_enable[];
extern unsigned char k_16bit_enable[];
extern unsigned short k_code[];
extern char klang_jump[];

extern char * getenv();
extern char * malloc();

/* Initialize input structure */
unsigned char *
XrInputInit()
{
    char *home = getenv ("HOME");

    k = (struct kbd_state *)malloc (sizeof(struct kbd_state));

    if (DisplayType() >= 800 && DisplayType() < 900)
    {
    	k->type = K_HP;
    	k->language = k->pwr_language = 
			klang_jump[(DisplayType() - 800) & 0x01F];
    } else
    {
	k->type = K_DEFAULT;
    	k->language = k->pwr_language = K_HP_USASCII;
    }

    k->last_char = 0;
    k->flags = K_ASCII8;
    if (home)
    {
	int homelen = strlen (home);
	char * keymapstr = "/.Xkeymap";
	int keymapstrlen = strlen (keymapstr);
	char *filename = malloc (homelen + keymapstrlen + 1);
	int file = -1;

	strncpy (filename, home, homelen + 1);
	strncat (filename, keymapstr, keymapstrlen);
	file = open (filename, O_RDONLY, 0);
	if (file >= 0)
	{
		k->flags |= K_LOCALMAP;
		close (file);
	}
	free (filename);
    }
    kbd_language();
    return ((unsigned char *) &k->k_iso7to8[0]);
}

/* Switch to a different keyboard language */
static
kbd_language()
{
    register unsigned char *p;
    register i;

    /* Point to Language Dependent Keycode Table */
    k->langtab = k_langtab[k->language];
    k->alttab = k_alttab[k->language];

    /* Preload iso translation tables */
    for (i = 0; i < 128; i++)
	k->k_iso7to8[i] = k->k_iso8to7[i] = (unsigned char)i;
    for (; i < 256; i++)
	k->k_iso8to7[i] = (unsigned char)i;

    /* Set up ISO 7 Bit Conversion Routine */
    p = k_isotab[k->language];

    /* Fill in 7 to 8 bit translations */
    k->k_iso8to7[*p] = 35;
    k->k_iso7to8[35] = *p++;
    k->k_iso8to7[*p] = 39;
    k->k_iso7to8[39] = *p++;
    k->k_iso8to7[*p] = 60;
    k->k_iso7to8[60] = *p++;
    k->k_iso8to7[*p] = 62;
    k->k_iso7to8[62] = *p++;
    k->k_iso8to7[*p] = 64;
    k->k_iso7to8[64] = *p++;
    for (i = 91; i <= 94; i++) {
	k->k_iso8to7[*p] = i;
	k->k_iso7to8[i] = *p++;
    }
    i++;
    k->k_iso8to7[*p] = i;
    k->k_iso7to8[i] = *p++;
    for (i = 123; i <= 126; i++) {
	k->k_iso8to7[*p] = i;
	k->k_iso7to8[i] = *p++;
    }

    /* Set the default value for K_MUTE */
    k->flags &= ~K_MUTE;
    k->flags |= k_mute_enable[(int)k->language];
    k->flags &= ~K_ALT;
    k->alt = k_alt_enable[(int)k->language];
    k->flags &= ~K_16BITIO;
    k->i16bit = k_16bit_enable[(int)k->language];
}

XrInputMute(c)
unsigned char c;
{
#ifndef CR
#define CR	13
#endif
    unsigned char last;

    /* Handle ISO 7 Bit */
    if (!(k->flags & K_ASCII8)) {
	last = k->k_iso8to7[c] & 0x07f;
	return(last);
    }

    /* Handle Mutes */
    if (k->flags & K_MUTE) {
	last = k->last_char;

	/* Handle mutes or non-advancing diacriticals */
	k->last_char = c;
	switch (c) {
	default:
	    break;
	case R_BQUOTE: /* Back accent */
	case R_FQUOTE: /* Forward accent */
	case R_HAT: /* Hat accent */
	case R_DDOT: /* Double Dot accent */
	case R_TILTA:	/* Tilda accent */
	    return(0+K_s);
	}
	switch (last) {
	default:
	    return(c);

	case R_BQUOTE: /* Back accent */
	    switch (c) {
	    default:
		break;
	    case 'a':
		c = R_a_BQUOTE;
		break;
	    case 'A':
		c = R_A_BQUOTE;
		break;
	    case 'e':
		c = R_e_BQUOTE;
		break;
	    case 'E':
		c = R_E_BQUOTE;
		break;
	    case 'i':
		c = R_i_BQUOTE;
		break;
	    case 'I':
		c = R_I_BQUOTE;
		break;
	    case 'o':
		c = R_o_BQUOTE;
		break;
	    case 'O':
		c = R_O_BQUOTE;
		break;
	    case 'u':
		c = R_u_BQUOTE;
		break;
	    case 'U':
		c = R_U_BQUOTE;
		break;
	    case ' ':
		c = last;
		break;
	    case CR: /* Send last first then what is there */
	   	return (last);
	    }
	    break;
	case R_FQUOTE: /* Forward accent */
	    switch (c) {
	    default:
		break;
	    case 'a':
		c = R_a_FQUOTE;
		break;
	    case 'A':
		c = R_A_FQUOTE;
		break;
	    case 'e':
		c = R_e_FQUOTE;
		break;
	    case 'E':
		c = R_E_FQUOTE;
		break;
	    case 'i':
		c = R_i_FQUOTE;
		break;
	    case 'I':
		c = R_I_FQUOTE;
		break;
	    case 'o':
		c = R_o_FQUOTE;
		break;
	    case 'O':
		c = R_O_FQUOTE;
		break;
	    case 'u':
		c = R_u_FQUOTE;
		break;
	    case 'U':
		c = R_U_FQUOTE;
		break;
	    case ' ':
		c = last;
		break;
	    case CR: /* Send last first then what is there */
		return (last);
	    }
	    break;
	case R_HAT: /* Hat accent */
	    switch (c) {
	    default:
		break;
	    case 'a':
		c = R_a_HAT;
		break;
	    case 'A':
		c = R_A_HAT;
		break;
	    case 'e':
		c = R_e_HAT;
		break;
	    case 'E':
		c = R_E_HAT;
		break;
	    case 'i':
		c = R_i_HAT;
		break;
	    case 'I':
		c = R_I_HAT;
		break;
	    case 'o':
		c = R_o_HAT;
		break;
	    case 'O':
		c = R_O_HAT;
		break;
	    case 'u':
		c = R_u_HAT;
		break;
	    case 'U':
		c = R_U_HAT;
		break;
	    case ' ':
		c = last;
		break;
	    case CR: /* Send last first then what is there */
		return(last);
	    }
	    break;
	case R_DDOT: /* Double Dot accent */
	    switch (c) {
	    default:
		break;
	    case 'a':
		c = R_a_DDOT;
		break;
	    case 'A':
		c = R_A_DDOT;
		break;
	    case 'e':
		c = R_e_DDOT;
		break;
	    case 'E':
		c = R_E_DDOT;
		break;
	    case 'i':
		c = R_i_DDOT;
		break;
	    case 'I':
		c = R_I_DDOT;
		break;
	    case 'o':
		c = R_o_DDOT;
		break;
	    case 'O':
		c = R_O_DDOT;
		break;
	    case 'u':
		c = R_u_DDOT;
		break;
	    case 'U':
		c = R_U_DDOT;
		break;
	    case 'y':
		c = R_y_DDOT;
		break;
	    case 'Y':
		c = R_Y_DDOT;
		break;
	    case ' ':
		c = last;
		break;
	    case CR: /* Send last first then what is there */
		return(last);
	    }
	    break;
	case R_TILTA: /* Tilda accent */
	    switch (c) {
	    default:
		break;
	    case 'a':
		c = R_a_TILTA;
		break;
	    case 'A':
		c = R_A_TILTA;
		break;
	    case 'o':
		c = R_o_TILTA;
		break;
	    case 'O':
		c = R_O_TILTA;
		break;
	    case 'n':
		c = R_n_TILTA;
		break;
	    case 'N':
		c = R_N_TILTA;
		break;
	    case ' ':
		c = last;
		break;
	    case CR: /* Send last first then what is there */
		return(last);
	    }
	    break;
	}
    }
    return(c);
}

int
XrInputConf(param, value)
{
    switch (param) {
    case K_TYPE:
	if (value != -1)
	{
		if (value >= K_HP && value <= K_DEFAULT)
		   k->type = value;
	}
	return (k->type);

    case K_LANGUAGE:
	if (value != -1) {
	    if (value < K_HP_USASCII || value > K_HP_KANJI)
		k->language = k->pwr_language;
	    else
		k->language = value;
	    kbd_language();
	}
	return(k->language);

    case K_ALT_ENABLE:
	if (value != -1)
	{
		if (value >= 0 && value <= 4)
		{
			k->alt = value;
			k->flags &= ~K_ALT;
		}
	}
	return (k->alt);

    case K_16BITIO_ENABLE:
	if (value != -1)
	{
		if (value >= 0 && value <= 4)
		{
			k->i16bit = value;
			k->flags &= ~K_16BITIO;
		}
	}
	return (k->i16bit);

    case K_ASCII8:
    case K_MUTE:
	if (value != -1) {
	    if (value)
		k->flags |= param;
	    else
		k->flags &= ~param;
	}
    case K_ALT: /* Read only */
    case K_16BITIO: /* Read only */
	return(((k->flags & param) ? 1 : 0));

    default:
	return(-1);
    }
}


unsigned char *
XrInputMap (kptr, nbytes)
XKeyPressedEvent * kptr;
int * nbytes;
{
    register unsigned key;
    register control, shift, shiftlock, meta;
    unsigned char * string;
    register unsigned short s_key;
    static unsigned char c_key;
    static unsigned char f_key[2];

    if ((k->type == K_DEFAULT) || (k->flags & K_LOCALMAP))
    {
	string = (unsigned char *)XLookupMapping (kptr, nbytes);
	if (*nbytes != 0)
	{
		
		return (string);
	} 
    }
    key = kptr->detail;
    control = (key & KEYCNTL);
    shift = (key & KEYSHIFT);
    meta = (key & KEYMETA);
    shiftlock = (key & KEYSHIFTLOCK);
    key &= ValueMask;
    /* make sure the code is in our tables */
    if ((key < FIRST_LK201) || (key >= CODE_SHIFT + FIRST_LK201))
    {
        *nbytes = 0;
	return (0);
    }
    key -= FIRST_LK201;	/* subtract off front of unused LK201 codes */

    /* Check for the KATAKANA Alternate Keyboard */
    if (((k->flags & (K_ASCII8 | K_ALT)) == (K_ASCII8 | K_ALT))  &&
    	 (key >= FIRST_CHAR))
    {
	c_key = k->alttab[key-FIRST_CHAR+(shift ? CHAR_SHIFT:0)];
	*nbytes = 1;
	return (&c_key);
    } else  if (meta && (k->alt == 0) && (k->flags & K_ASCII8) && 
	(key >= FIRST_CHAR)) 
    {					/* Check for the EXTEND Keyboard */
	/* Look up ALT SHIFT Set via keycode shifted */

	s_key = k->alttab[key-FIRST_CHAR+(shift ? CHAR_SHIFT:0)];

	/* Check for CAPS */
	if (shiftlock)
	    switch (s_key) {
	    case R_ZERO:
		s_key = R_zero;
		break;
	    case R_zero:
		s_key = R_ZERO;
		break;
	    case R_IP:
		s_key = R_ip;
		break;
	    case R_ip:
		s_key = R_IP;
		break;
	    case R_A_DOT:
		s_key = R_a_DOT;
		break;
	    case R_a_DOT:
		s_key = R_A_DOT;
		break;
	    case R_AE:
		s_key = R_ae;
		break;
	    case R_ae:
		s_key = R_AE;
		break;
	    case R_D_CROSS:
		s_key = R_d_CROSS;
		break;
	    case R_d_CROSS:
		s_key = R_D_CROSS;
		break;
	    case R_S_V:
		s_key = R_s_V;
		break;
	    case R_s_V:
		s_key = R_S_V;
		break;
	    case R_C_BEARD:
		s_key = R_c_BEARD;
		break;
	    case R_c_BEARD:
		s_key = R_C_BEARD;
		break;
	    default:
		break;
	    }
	    s_key = XrInputMute (s_key);
	    if (s_key == K_s)
	    {
		*nbytes = 0;
		return (0);
	    } else
	    {
		c_key = s_key;
	    	*nbytes = 1;
	    	return (&c_key);
	    }
    } else
    { 
    	s_key = k_code[(shift ? (key+CODE_SHIFT) : key)];

    	/* Handle Special Keys First */
    	if (s_key & K_s)
	{
		f_key[0] = K_FUNCTION;
		*nbytes = 2;
		switch (s_key & 0xFF) {
		case K_ILLEGAL:
			*nbytes = 0;
			return (0);

    		case TO_ROMAN_KEY:		/* left extend key */
			switch (k->alt) {
			case 1:
	    			k->flags &= ~K_ALT; /* Roman */
				f_key[1] = TO_ROMAN_KEY;
    	    			return (f_key);

			case 2:
		    		k->flags |= K_ALT;  /* Alternate */
				f_key[1] = TO_ALT_KEY;
    	    			return (f_key);

			case 4:
				k->flags ^= K_ALT;  /* Toggle */
				f_key[1] = (k->flags & K_ALT) ? 
				        TO_ALT_KEY : TO_ROMAN_KEY;
    	    			return (f_key);
			}
			switch (k->i16bit) {
			case 1:
	    			k->flags &= ~K_16BITIO; /* leave 16 bit */

				/* later this return of code will be 
				replaced by calls to 16bit input routines */

				f_key[1] = LEAVE_16BIT_KEY;
    	    			return (f_key);

			case 2:
		    		k->flags |= K_16BITIO;  /* enter 16 bit */

				/* later this return of code will be 
				replaced by calls to 16bit input routines */

				f_key[1] = GO_16BIT_KEY;
    	    			return (f_key);

			case 4:
				k->flags ^= K_16BITIO;

				/* later this return of code will be 
				replaced by calls to 16bit input routines */

				f_key[1] = (k->flags & K_16BITIO) ? 
				        GO_16BIT_KEY : LEAVE_16BIT_KEY;
    	    			return (f_key);

			default:
				*nbytes = 0;
	    			return(0);
			}

    		case TO_ALT_KEY:		/* right extend key */
			switch (k->alt) {
			case 1:
		    		k->flags |= K_ALT;  /* Alternate */
				f_key[1] = TO_ALT_KEY;
    	    			return (f_key);

			case 2:
	    			k->flags &= ~K_ALT; /* Roman */
				f_key[1] = TO_ROMAN_KEY;
    	    			return (f_key);

			case 3:
				k->flags ^= K_ALT;  /* Toggle */
				f_key[1] = (k->flags & K_ALT) ? 
				        TO_ALT_KEY : TO_ROMAN_KEY;
    	    			return (f_key);
			}
			switch (k->i16bit) {
			case 1:
		    		k->flags |= K_16BITIO;  /* enter 16 bit */

				/* later this return of code will be 
				replaced by calls to 16bit input routines */

				f_key[1] = GO_16BIT_KEY;
    	    			return (f_key);

			case 2:
	    			k->flags &= ~K_16BITIO; /* leave 16 bit */

				/* later this return of code will be 
				replaced by calls to 16bit input routines */

				f_key[1] = LEAVE_16BIT_KEY;
    	    			return (f_key);

			case 3:
				k->flags ^= K_16BITIO;

				/* later this return of code will be 
				replaced by calls to 16bit input routines */

				f_key[1] = (k->flags & K_16BITIO) ? 
				        GO_16BIT_KEY : LEAVE_16BIT_KEY;
    	    			return (f_key);

			default:
				*nbytes = 0;
	    			return(0);
			}

		default:
		    f_key[1] = (unsigned char) s_key;
		    return (f_key);
		}
    	} else
	{
    		/* If it is a language dependent key, look up again. */
    		if ((s_key >= K_LANG_START) && (s_key <= K_LANG_END)) 
			s_key = k->langtab[s_key-K_LANG_START];

    		/* Check for caps mode */
    		if ((shiftlock) && !(k->flags & K_ALT))
    		{
	    		/* Check for keys affected by capitalization. */
	    		if ((s_key >= 'a' && s_key <= 'z') || 
				(s_key >= 'A' && s_key <= 'Z')) 
	    		{
			        /* Invert Case */
				s_key ^= 0x20;
			    } else {
				/* Check for roman characters */
				    switch (k->language) {
				    case K_HP_KATAKANA:
				    case K_HP_KANJI:
				    case K_HP_SWISSFRENCH:
				    case K_HP_SWISSGERMAN:
				    case K_HP_SWISSFRENCH2:
				    case K_HP_SWISSGERMAN2:
					    break;	/* Nothing */

				    case K_HP_CANENG:
				    case K_HP_CANFRENCH:
		   		 /* Check for C_BEARDS */
				    	if (s_key == R_C_BEARD) {
						s_key = R_c_BEARD;
						break;
		    			}
				    	if (s_key == R_c_BEARD) {
						s_key = R_C_BEARD;
						break;
		    			}
				    case K_HP_FINNISH:
				    case K_HP_SWEDISH:
				    /* Check for E_BQUOTES */
				    	if (s_key == R_E_BQUOTE) {
						s_key = R_e_BQUOTE;
						break;
		    			}
				    	if (s_key == R_e_BQUOTE) {
						s_key = R_E_BQUOTE;
						break;
		    			}
				    default:
				    	switch (s_key) {
		    				case R_U_DDOT:
							s_key = R_u_DDOT;
							break;
					    	case R_u_DDOT:
							s_key = R_U_DDOT;
							break;
					    	case R_O_DDOT:
							s_key = R_o_DDOT;
							break;
					    	case R_o_DDOT:
							s_key = R_O_DDOT;
							break;
					    	case R_A_DDOT:
							s_key = R_a_DDOT;
							break;
					    	case R_a_DDOT:
							s_key = R_A_DDOT;
							break;
					    	case R_A_DOT:
							s_key = R_a_DOT;
							break;
					    	case R_a_DOT:
							s_key = R_A_DOT;
							break;
					    	case R_N_TILTA:
							s_key = R_n_TILTA;
							break;
					    	case R_n_TILTA:
							s_key = R_N_TILTA;
							break;
					    	case R_AE:
							s_key = R_ae;
							break;
					    	case R_ae:
							s_key = R_AE;
							break;
					    	case R_ZERO:
							s_key = R_zero;
							break;
					    	case R_zero:
							s_key = R_ZERO;
							break;
					    	default:
							break;
				    	}
				    break;
				    }
			}
    		}

    		if (control) {
		/* Only convert codes codes 64 to 127
			** as does the 2622 only if enabled
			*/
			if (s_key >= 64 && s_key <= 127)
			    s_key &= CNTLKEY_MASK;	/* Convert to control */
    		}
		s_key = XrInputMute (s_key);
	        if (s_key == K_s)
	        {
		    *nbytes = 0;
		    return (0);
	        } else
	        {
		    c_key = s_key;
		    *nbytes = 1;
		    return (&c_key);
		}
    	}
    }
}
