#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdio.h>

extern Display *d;
/*extern int column[16]; */
/*extern int row[16]; */
extern int matrix[16][16]; /* [r][c] */

extern int debug;

/*
 * FIXME: Add hardwire break key
 */
int scan_key() {
    XEvent xev;
    KeySym key;
    int v, ret = 0;

    extern int GO_FOR_IT;

#ifdef DEBUG_VIA
    puts("scan_key1");
#endif

    if (!GO_FOR_IT)
	return 0;

#ifdef DEBUG_VIA
    puts("scan_key2");
#endif


    while(XPending(d)) {
	XNextEvent(d, &xev);

	switch(xev.type) {
	    char buf;

	case KeyPress:
	case KeyRelease:

	    v = (xev.type == KeyPress) ? 1 : 0;
	    /*
	     * Due to horrible problems of keycodes being of different keys
	     * on most X systems than the BBC we need to use a higher level
	     * keyboard scan. The consequence of this is that we have far
	     * more work when dealing with Shift and need to disable
	     * auto repeat.
	     */
	    (void)XLookupString(&xev, &buf, 1, &key, NULL);

	    fprintf(stderr, "keycode=%d, state=%x, type=%d, sym=%x\n",
		    xev.xkey.keycode,
		    xev.xkey.state,
		    xev.xkey.type,
		    key);

	    switch(key) {
	    case XK_Escape:
		matrix[7][0] = v;
		break;
	    case XK_Tab:
		matrix[6][0] = v;
		break;
	    case XK_Caps_Lock:
		matrix[4][0] = v;
		break;
	    case XK_Control_L:
	    case XK_Control_R:
		matrix[0][1] = v;
		break;
	    case XK_Shift_Lock:
		matrix[5][0] = v;
		break;
	    case XK_Shift_L:
	    case XK_Shift_R:
		matrix[0][0] = v;
		break;
	    case XK_Insert: /* COPY */
		matrix[6][9] = v;
		break;
	    case XK_Delete:
		matrix[5][9] = v;
		break;
	    case XK_Return:
		/* printf("Return - setting to %d\n", v); */
		matrix[4][9] = v;
		break;
	    case XK_Up:
		matrix[3][9] = v;
		break;
	    case XK_Down:
		matrix[2][9] = v;
		break;
	    case XK_Left:
		matrix[1][9] = v;
		break;
	    case XK_Right:
		matrix[7][9] = v;
		break;
	    case XK_Pause:
	    case XK_Break:
		puts("BREAK pressed - we ought to do something with this");
		break;
	    case XK_F10: /* F0 */
		matrix[2][0] = v;
		break;
	    case XK_F1:
		matrix[7][1] = v;
		break;
	    case XK_F2:
		matrix[7][2] = v;
		break;
	    case XK_F3:
		matrix[7][3] = v;
		break;
	    case XK_F4:
		matrix[1][4] = v;
		break;
	    case XK_F5:
		matrix[7][4] = v;
		break;
	    case XK_F6:
		matrix[7][5] = v;
		break;
	    case XK_F7:
		matrix[1][6] = v;
		break;
	    case XK_F8:
		matrix[7][6] = v;
		break;
	    case XK_F9:
		matrix[7][7] = v;
		break;
	    case XK_space:
		matrix[6][2] = v;
		break;

	    /* Letters */
	    case XK_A:
	    case XK_a:
		matrix[4][1] = v;
		break;
	    case XK_B:
	    case XK_b:
		matrix[6][4] = v;
		break;
	    case XK_C:
	    case XK_c:
		matrix[5][2] = v;
		break;
	    case XK_D:
	    case XK_d:
		matrix[3][2] = v;
		break;
	    case XK_E:
	    case XK_e:
		matrix[2][2] = v;
		break;
	    case XK_F:
	    case XK_f:
		matrix[4][3] = v;
		break;
	    case XK_G:
	    case XK_g:
		matrix[5][3] = v;
		break;
	    case XK_H:
	    case XK_h:
		matrix[5][4] = v;
		break;
	    case XK_I:
	    case XK_i:
		matrix[2][5] = v;
		break;
	    case XK_J:
	    case XK_j:
		matrix[4][5] = v;
		break;
	    case XK_K:
	    case XK_k:
		matrix[4][6] = v;
		break;
	    case XK_L:
	    case XK_l:
		matrix[5][6] = v;
		break;
	    case XK_M:
	    case XK_m:
		matrix[6][5] = v;
		break;
	    case XK_N:
	    case XK_n:
		matrix[5][5] = v;
		break;
	    case XK_O:
	    case XK_o:
		matrix[3][6] = v;
		break;
	    case XK_P:
	    case XK_p:
		matrix[3][7] = v;
		break;
	    case XK_Q:
	    case XK_q:
		matrix[1][0] = v;
		break;
	    case XK_R:
	    case XK_r:
		matrix[3][3] = v;
		break;
	    case XK_S:
	    case XK_s:
		matrix[5][1] = v;
		break;
	    case XK_T:
	    case XK_t:
		matrix[2][3] = v;
		break;
	    case XK_U:
	    case XK_u:
		matrix[3][5] = v;
		break;
	    case XK_V:
	    case XK_v:
		matrix[6][3] = v;
		break;
	    case XK_W:
	    case XK_w:
		matrix[2][1] = v;
		break;
	    case XK_X:
	    case XK_x:
		matrix[4][2] = v;
		break;
	    case XK_Y:
	    case XK_y:
		matrix[4][4] = v;
		break;
	    case XK_Z:
	    case XK_z:
		matrix[6][1] = v;
/*
		puts("INT");
		disregion(0xdc1c, 0xde8c);
		puts("KEY");
		disregion(0xeeda, 0xf135);
		puts("END");
*/
		break;

	    /* Numbers */
	    case XK_0:
		matrix[2][7] = v;
		break;
	    case XK_1:
		matrix[3][0] = v;
		break;
	    case XK_2:
		matrix[3][1] = v;
		break;
	    case XK_3:
		matrix[1][1] = v;
		break;
	    case XK_4:
		matrix[1][2] = v;
		break;
	    case XK_5:
		matrix[1][3] = v;
		break;
	    case XK_6:
		matrix[3][4] = v;
		break;
	    case XK_7:
		matrix[2][4] = v;
		break;
	    case XK_8:
		matrix[1][5] = v;
		break;
	    case XK_9:
		matrix[2][6] = v;
		break;

	    /*
	     * Punctuation - we need to be careful here as each keyboard has
	     * these separate. Hence we cheat by setting shift correctly in
	     * each case.
	     */
#define shift_on()  if (v) matrix[0][0] = 1
#define shift_off() if (v) matrix[0][0] = 0
	    case XK_comma:
		matrix[6][6] = v;
		shift_off();
		break;
	    case XK_less:
		matrix[6][6] = v;
		shift_on();
		break;
	    case XK_period:
		matrix[6][7] = v;
		shift_off();
		break;
	    case XK_greater:
		matrix[6][7] = v;
		shift_on();
		break;
	    case XK_slash:
		matrix[6][8] = v;
		shift_off();
		break;
	    case XK_question:
		matrix[6][8] = v;
		shift_on();
		break;
	    case XK_minus:
		matrix[1][7] = v;
		shift_off();
		break;
	    case XK_equal:
		matrix[1][7] = v;
		shift_on();
		break;
	    case XK_colon:
		matrix[4][8] = v;
		shift_off();
		break;
	    case XK_asterisk:
		matrix[4][8] = v;
		shift_on();
		break;
	    case XK_semicolon:
		matrix[5][7] = v;
		shift_off();
		break;
	    case XK_plus:
		matrix[5][7] = v;
		shift_on();
		break;
	    case XK_at:
		matrix[4][7] = v;
		shift_off();
		break;
	    case XK_bracketleft:
		matrix[3][8] = v;
		shift_off();
		break;
	    case XK_braceleft:
		matrix[3][8] = v;
		shift_on();
		break;
	    case XK_backslash:
		matrix[7][8] = v;
		shift_off();
		break;
	    case XK_bar:
		matrix[7][8] = v;
		shift_on();
		break;
	    case XK_bracketright:
		matrix[5][8] = v;
		shift_off();
		break;
	    case XK_braceright:
		matrix[5][8] = v;
		shift_on();
		break;
	    case XK_asciicircum:
		matrix[1][8] = v;
		shift_off();
		break;
	    case XK_asciitilde:
		matrix[1][8] = v;
		shift_on();
		break;
	    case XK_underscore:
		matrix[2][8] = v;
		shift_off();
		break;
	    case XK_exclam: /* shift 1 */
		matrix[3][0] = v;
		shift_on();
		break;
	    case XK_quotedbl: /* shift 2 */
		matrix[3][1] = v;
		shift_on();
		break;
	    case XK_numbersign: /* shift 3 */
		matrix[1][1] = v;
		shift_on();
		break;
	    case XK_dollar: /* shift 4 */
		matrix[1][2] = v;
		shift_on();
		break;
	    case XK_percent: /* shift 5 */
		matrix[1][3] = v;
		shift_on();
		break;
	    case XK_ampersand: /* shift 6 */
		matrix[3][4] = v;
		shift_on();
		break;
	    case XK_apostrophe: /* shift 7 */
		matrix[2][4] = v;
		shift_on();
		break;	
	    case XK_parenleft: /* shift 8 */
		matrix[1][5] = v;
		shift_on();
		break;
	    case XK_parenright: /* shift 9 */
		matrix[2][6] = v;
		shift_on();
		break;

	    default:
		puts("ERROR! Unknown keypress");
	    }

#ifdef DEBUG_VIA
	    printf("%sed key '%c' %d\n", v ? "Press" : "Releas", key, key);
#endif

	    if (v)
		ret = 1;
	    /* debug=1; */
	}
    }

    return ret;
}
