
/* 
   This is part of the hack to make the keyboard work in XGGI
   with the current libGGI.

   Copyright (C) 1997 Michael Krause - rawstyle@ms.demo.org

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <stdio.h>
#include <X11/X.h>

#define XK_MISCELLANY
#define XK_LATIN1
#include <X11/keysymdef.h>

#include <linux/keyboard.h>

#define mem_vaddr unsigned long
#include "keymap.inc"

#define GLYPHS_PER_KEY 4

static KeySym keysymtab[NR_KEYS * GLYPHS_PER_KEY];
static unsigned char map_letters[256], map_spec[256], map_shift[256], map_fn[256], map_cur[256];

static void write_file(char *name) {
    FILE *f;

    if((f = fopen(name, "w"))) {
	fwrite(keysymtab, sizeof(KeySym), NR_KEYS * GLYPHS_PER_KEY, f);
	fwrite(map_letters, 1, 256, f);
	fwrite(map_spec, 1, 256, f);
	fwrite(map_shift, 1, 256, f);
	fwrite(map_fn, 1, 256, f);
	fwrite(map_cur, 1, 256, f);
	fclose(f);
    }
}

static void fill_keysymtab_one(int col, unicode *map) {
    int i;
    KeySym *d;
    unicode u;

    for(i = 0, d = keysymtab + col; i < NR_KEYS; i++, d += GLYPHS_PER_KEY) {
	u = map[i];

	switch(u) {
	case 0xf020 ... 0xf0ff:
	case 0xfb20 ... 0xfbff:
	    *d = u & 0xff;
	    break;
	    
	case 0xf01b: *d = XK_Escape; break;
	case 0xf008: *d = XK_BackSpace; break;
	case 0xf009: *d = XK_Tab; break;
	    
	case 0xf400 ... 0xf4ff:
	    /* KT_DEAD keys */
	    break;
	    
	case 0xf200 ... 0xf2ff: /* KT_SPEC keys */
	    switch(u) {
	    case U(K_ENTER): *d = XK_Return; break;
	    case U(K_CAPS): *d = XK_Caps_Lock; break;
	    }
	    if(*d) {
		map_spec[u & 0xff] = i + 1;
	    }
	    break;
	    
	case 0xf700 ... 0xf7ff:
	    /* KT_SHIFT keys */
	    switch(u) {
	    case U(K_NORMAL_SHIFT):
	    case U(K_NORMAL_SHIFTL): *d = XK_Shift_L; break;
	    case U(K_NORMAL_SHIFTR): *d = XK_Shift_R; break;
	    case U(K_STICKY_SHIFT): *d = XK_Caps_Lock; break;
	    case U(K_LOCKED_SHIFT): *d = XK_Shift_Lock; break;
	    case U(K_NORMAL_CTRL):
	    case U(K_NORMAL_CTRLL): *d = XK_Control_L; break;
	    case U(K_NORMAL_CTRLR): *d = XK_Control_R; break;
	    case U(K_NORMAL_ALT): *d = XK_Meta_L; break;
	    case U(K_NORMAL_ALTGR): *d = XK_Meta_R; break;
	    }
	    if(*d) {
		map_shift[u & 0xff] = i + 1;
	    }
	    break;
	    
	case 0xf300 ... 0xf3ff:
	    /* KT_PAD keys */
	    break;
	    
	case 0xf600 ... 0xf6ff:
	    /* KT_CUR keys */
	    switch(u) {
	    case U(K_LEFT): *d = XK_Left; break;
	    case U(K_RIGHT): *d = XK_Right; break;
	    case U(K_UP): *d = XK_Up; break;
	    case U(K_DOWN): *d = XK_Down; break;
	    }
	    if(*d) {
		map_cur[u & 0xff] = i + 1;
	    }
	    break;
	    
	case 0xf100 ... 0xf1ff:
	    /* KT_FN keys */
	    switch(u) {
	    case U(K_F1) ... U(K_F20): *d = XK_F1 + u - U(K_F1); break;
	    case U(K_PGUP): *d = XK_Prior; break;
	    case U(K_PGDN): *d = XK_Next; break;
	    }
	    if(*d) {
		map_fn[u & 0xff] = i + 1;
	    }
	    break;
	    
	default:
	    printf("unhandled: %x\n", u);
	    break;
	}
    }
}

static void fill_keysymtab(void) {
    fill_keysymtab_one(0, plain_map);
    fill_keysymtab_one(1, shift_map);
}

static void fill_maptab_latin(unsigned char *d, const unicode *from) {
    int i;
    unicode u;

    for(i = 0; i < NR_KEYS; i++) {
	u = *from++;

	if((u & 0xff00) == 0xf000 || (u & 0xff00) == 0xfb00) {
	    if(!d[u & 0xff]) {
		d[u & 0xff] = i + 1;
	    }
	}
    }
}

static void fill_maptab_shift(unsigned char *d) {
    if(!d[K_NORMAL_SHIFTL & 0xff])
	d[K_NORMAL_SHIFTL & 0xff] = d[K_NORMAL_SHIFT & 0xff];
    if(!d[K_NORMAL_SHIFTR & 0xff])
	d[K_NORMAL_SHIFTR & 0xff] = d[K_NORMAL_SHIFT & 0xff];
    if(!d[K_NORMAL_CTRLL & 0xff])
	d[K_NORMAL_CTRLL & 0xff] = d[K_NORMAL_CTRL & 0xff];
    if(!d[K_NORMAL_CTRLR & 0xff])
	d[K_NORMAL_CTRLR & 0xff] = d[K_NORMAL_CTRL & 0xff];
}

static void fill_maptab(void) {
    fill_maptab_latin(map_letters, plain_map);
    fill_maptab_latin(map_letters, shift_map);
    fill_maptab_latin(map_letters, ctrl_map);
    fill_maptab_shift(map_shift);
}

int main(int argc, char **argv) {
    if(argc != 2) {
	printf("Usage: %s destination-file\n", argv[0]);
	return 1;
    }

    fill_keysymtab();
    fill_maptab();

    write_file(argv[1]);

    return 0;
}










