/*
***********************************************************************
* modified by Edward Der-Hua Liu, Taiwan for X dosemu
************************************************************************/
/*
 *	$XConsortium: data.c,v 1.10 91/02/06 14:23:58 gildea Exp $
 */

/*
 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 *
 *                         All Rights Reserved
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of Digital Equipment
 * Corporation not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission.
 *
 *
 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/* input.c */

#include "ptyx.h"		/* gets Xt headers, too */
#include <X11/keysym.h>
#include <X11/DECkeysym.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include "emu.h"

static XComposeStatus compose_status = {NULL, 0};

static void
AdjustAfterInput (screen)
register TScreen *screen;
{
	if(screen->scrollkey && screen->topline != 0)
		WindowScroll(screen, 0);
	if(screen->marginbell) {
		int col = screen->max_col - screen->nmarginbell;
		if(screen->bellarmed >= 0) {
			if(screen->bellarmed == screen->cur_row) {
			    if(screen->cur_col >= col) {
				Bell();
				screen->bellarmed = -1;
			    }
			} else
			    screen->bellarmed =
				screen->cur_col < col ? screen->cur_row : -1;
		} else if(screen->cur_col < col)
			screen->bellarmed = screen->cur_row;
	}
}

unsigned char cursor_tran[]={
0x47, /* HOME */
0x4b, /* Left */
0x48, /* Up */
0x4d, /* Right */
0x50, /* Down */
0x49, /* PgUp */
0x51, /* PgDn */
79  /* End */
};
unsigned char cursor_tran_ctl[]={
0x77, /* HOME */
115, /* Left */
160, /* Up */
116, /* Right */
164, /* Down */
132, /* PgUp */
118, /* PgDn */
117  /* End */
};

unsigned char a_z_tran[]={
30,48,46,32,18,33,34,35,23,36,37,38,50,49,24,25,26,19,31,20,22,47,17,45,21,44
};
unsigned char _0_9_tran[]={
	129,120,121,122,123,124,125,126,127,128
};

unsigned char highscan[256] = {  /* borrowed from dosemu48 */
0,0x1e,0x30,0x2e,0x20,0x12,0x21,0x22,0xe,0x0f,0x24,0x25,0x2e,0x1c,  /* 0-0xd */
0x31,0x18,0x19,0x10,0x13,0x1f,0x14,0x16,0x2f,0x11,0x2d,0x15,0x2c, /* -> 0x1a */
1,0x2b,0,7,0xc,  /* ASCII 1b-1F */
0x39,2,0x28,4,5,6,8,0x28,0xa,0xb,9,0xd, 0x33, 0x0c, 0x34, 0x35,  /* -> 2F */
0x0b,2,3,4,5,6,7,8,9,0xa,    /* numbers 0, 1-9; ASCII 0x30-0x39 */
0x27,0x27,0x33,0xd,0x34,0x35,3,  /* ASCII 0x3A-0x40  */
0x1e,0x30,0x2e,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31, /* CAP LETERS A-N */
0x18,0x19,0x10,0x13,0x1f,0x14,0x16,0x2f,0x11,0x2d,0x15,0x2c, /* CAP O-Z last ASCII 0x5a */
0x1a,0x2b,0x1b,7,0x0c,0x29, /* ASCII 0x5b-0x60 */
/* 0x61 - 0x7a on next 2 lines */
0x1e,0x30,0x2e,0x20,0x12,0x21,0x22,0x23,0x17,0x24,0x25,0x26,0x32,0x31,0x18, /* lower a-o */
0x19,0x10,0x13,0x1f,0x14,0x16,0x2f,0x11,0x2d,0x15,0x2c,   /* lowercase p-z */
0x1a,0x2b,0x1b,0x29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ASC 0x7b-0x8f */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ASC 0x90-0x9f */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ASC 0xa0-0xaf */
0x81,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0,0,0,0,0,0, /* 0xb0-0xbf */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ASC 0xc0-0xcf */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ASC 0xd0-0xdf */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* ASC 0xe0-0xef */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0  /* ASC 0xf0-0xff */
};

extern int int9_fq, int9_eq, int9_cq;
extern int int9_key[100], int9_atkey[100];
int enter_flush_fd=1;

extern int X_kbd_state;

int int_key=0, at_key=0;
void tran_scancode(KeySym keysym, int evtype)
{

#if	0
	printf("keysym: %x\n", keysym);
#endif	0
	
	at_key=int_key=0;

	if (keysym>=XK_Home && keysym<=XK_End)
		int_key=cursor_tran[keysym-XK_Home];
	else
	if (keysym>=XK_space && keysym<=XK_asciitilde)
		int_key=highscan[keysym];
	else
	if (keysym >= XK_F1 && keysym <= XK_F12)
		int_key=keysym-XK_F1 + ';' ;
	else
	switch (keysym) {
	case XK_Return:
		int_key=0x1c;
		{
			extern void floppy_close_all();
			if (enter_flush_fd) floppy_close_all();
		}
		break;
	case XK_BackSpace:
		int_key=0xe;
		break;
	case XK_Tab:
		int_key=0xf;
		break;
	case XK_Escape:
		int_key=0x1;
		break;
	case XK_Insert:
		int_key=0x52;
		break;
	case XK_Delete:
		int_key=0x53;
		break;
	case XK_Pause:
		int_key=0x1d;
		break;
	case XK_Num_Lock:
		int_key=0x45;
		break;
	case XK_Shift_L:
		int_key=0x2a;
		if (evtype==KeyRelease)
			X_kbd_state &= ~ShiftMask;
		else
			X_kbd_state |= ShiftMask;
		break;
	case XK_Shift_R:
		int_key=0x36;
		if (evtype==KeyRelease)
			X_kbd_state &= ~ShiftMask;
		else
			X_kbd_state |= ShiftMask;
		break;
	case XK_Control_L:
		int_key=0x1d;
		if (evtype==KeyRelease)
			X_kbd_state &= ~ControlMask;
		else
			X_kbd_state |= ControlMask;
		break;
	case XK_Control_R:
		int9_atkey[int9_eq]=0xe0;
		int_key=0x1d;
		if (evtype==KeyRelease)
			X_kbd_state &= ~ControlMask;
		else
			X_kbd_state |= ControlMask;
		break;
	case XK_Alt_L:
		int_key=0x38;
		if (evtype==KeyRelease)
			X_kbd_state &= ~(Mod1Mask|Mod5Mask);
		else
			X_kbd_state |= (Mod1Mask|Mod5Mask); 
		break;
	case XK_Alt_R:
		at_key=0xe0;
		int_key=0x38;
		if (evtype==KeyRelease)
			X_kbd_state &= ~(Mod1Mask|Mod5Mask);
		else
			X_kbd_state |= (Mod1Mask|Mod5Mask); 
		break;
	case XK_Caps_Lock:
		int_key=0x1d;	
		X_kbd_state ^= LockMask;
		break;
	case XK_KP_Enter:
		at_key=0xe0;
		int_key=0x1c;
		break;
	case XK_KP_Add:
		int_key=0x4e;
		break;
	case XK_KP_Subtract:
		int_key=0x4a;
		break;
	case XK_KP_Multiply:
		int_key=0x37;
		break;
	case XK_KP_Divide:
		at_key=0xe0;
		int_key=0x35;
		break;
	case XK_KP_Decimal:
		int_key=0x53;
		break;
	case XK_Print:
		int_key=0x72;
		break;
	default:
#if	0
		printf("??key %x\n", keysym);
#endif
		return;
	}
	int9_atkey[int9_eq]=at_key;
	int9_key[int9_eq]=int_key;
#if	1
	int9_eq++;
#endif
/*	printf("q %x %x\n", int9_fq, int9_eq); */
}


extern void put_key();
int by_int16, ret_imm;

extern int ret_imm;

Input (keyboard, screen, event, eightbit)
    register TKeyboard	*keyboard;
    register TScreen	*screen;
    register XKeyEvent *event;
    Bool eightbit;
{
	unsigned short PressKey=0;

#define STRBUFSIZE 100

	register char *string;
	register int key = FALSE;
	int	pty	= screen->respond;
	int	nbytes;
	KeySym  keysym;
#if	0
	ANSI	reply;
#endif
	char	tmp[STRBUFSIZE];
	int	count;
	XEvent	ev;


	count = XLookupString (event, tmp, STRBUFSIZE,
			       &keysym, &compose_status);
#if	CHSYS
		if (tmp[0]==1 && (event->state & ControlMask) 
			&& (event->state & (Mod1Mask|Mod5Mask))	) {
			int tt;
			extern int X_busy,enable_chsys;
			extern char scr_mirror[];
			
			enable_chsys^=1;
			for(tt=0;tt<80*25*2;scr_mirror[tt++]=0xffff);
			tt=X_busy;
			X_busy=1;
			if (enable_chsys) restore_screen2();
                        else restore_screen();
			if (!tt) X_busy=0;
#if	0
			if (enable_chsys) puts("enable ch");
			else
			puts("disable ch");
#endif
			return;
		}
#endif

	tran_scancode(keysym, event->type);
#if	0
	if (count > 1) puts("PPP");
#endif
	if (keysym>=XK_Home && keysym<=XK_End) {
		if (event->state & ControlMask)
			PressKey=cursor_tran_ctl[keysym-XK_Home];
		else
			PressKey=cursor_tran[keysym-XK_Home];
		put_key((unsigned short)PressKey<<=8);
		return;
	}
	if (keysym>=XK_F1 && keysym <=XK_F12) {
		PressKey=keysym-XK_F1+59;
		if (event->state & ControlMask)
			PressKey+=94-59;
		else
		if (event->state & ShiftMask)
			PressKey+=84-59;
		else
		if (event->state & (Mod1Mask|Mod5Mask))
			PressKey+=104-59;
		put_key((unsigned short)PressKey<<=8);
		return;
	}
	if (count > 0) {
		char ch=tmp[0];
		if ((event->state & (Mod1Mask|Mod5Mask))) {
		        if ((ch>='A'&&ch<='Z')||(ch>='a'&&ch<='z')) {
				if (ch>='a') ch-='a';
				else ch-='A';
				PressKey=a_z_tran[ch];
			} else if (ch>='0' && ch<='9') {
				PressKey=_0_9_tran[ch-'0'];
			} else 
			if (ch=='-') PressKey=130;
			else
			if (ch=='=') PressKey=131;
			PressKey<<=8;

		} else
		if (ch==127)
			PressKey=0x5300;
		else if (ch==8) {
			if (event->state & ControlMask) PressKey=0xe7f;
			else PressKey=0xe08;
		} 
		else {
			if (int_key)
				PressKey=ch;
			else
				PressKey=highscan[ch]<<8 | ch;
		}
		PressKey|=int_key<<8;
		put_key(PressKey);
		return;
	}
	switch (keysym) {
	case XK_Insert:
		put_key((unsigned short)(82<<8));
		return;
	case XK_Break: /* with CTRL */
                *(unsigned char *)0x471 = 0x80;  /* ctrl-break flag */
                *(unsigned short *)0x41a = 0x1e; /* key buf start ofs */
                *(unsigned short *)0x41c = 0x20;      /* key buf end ofs */
                *(unsigned short *)0x41e = 0;         /* put 0 word in buffer */
		puts("break");
                run_int(0x1b);
		return;
	case XK_Pause: /* pause */
		{ extern int d_ready();
		  extern int Xsocket;
		  while (!d_ready(Xsocket));
		}
		return;
	case XK_Print:
		if (event->state & ControlMask)
			put_key(0x7200);
		return;
	case XK_BackSpace:
		put_key(0x7200);
	default:
/*		printf("?? key: %x\n", keysym); */
		return;
	}
}


int get_kbd_state()
{	
	int rr=0;
	if (X_kbd_state & ShiftMask) rr=3;
	if (X_kbd_state & ControlMask) rr|=4;
	if (X_kbd_state & (Mod1Mask|Mod5Mask)) rr|=8;
	if (X_kbd_state & Mod3Mask) rr|=16;
/*	if (X_kbd_state & XK_Num_Lock) rr|=32; */
	if (X_kbd_state & LockMask) rr|=64;
	return rr;
}

StringInput (screen, string, nbytes)
    register TScreen	*screen;
    register char *string;
    int nbytes;
{
	int	pty	= screen->respond;

	while (nbytes-- > 0)
		unparseputc(*string++, pty);
	if(!screen->TekEmu)
	        AdjustAfterInput(screen);
}
