/* $Id: keymap.cpp,v 1.9 2004/01/02 04:05:36 fesnel Exp $ */
/*******************************************************************************
 *   This program is part of the XFMail email client.                          *
 *                                                                             *
 *   Copyright : (C) 1995-1998 Gennady B. Sorokopud (gena@NetVision.net.il)    *
 *               (C) 1995 Ugen. J. S. Antsilevich (ugen@latte.worldbank.org)   *
 *               (C) 1998-2004 by the Archimedes Project                       *
 *                   http://sourceforge.net/projects/archimedes                *
 *                                                                             *
 *             --------------------------------------------                    *
 *                                                                             *
 *   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 of the License, 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., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA.  *
 *                                                                             *
 *   Additional Permission granted:                                            *
 *                                                                             *
 *   This program is designed to use the XForms library, so we consider        *
 *   permission to link to that non-GPL-compatible library is implicit.        *
 *   However, in case this is not considered so, we explicitly state:          *
 *                                                                             *
 *   "As a special exception, the Archimedes Project, with the permission      *
 *    of all earlier copyright holders, formally gives permission to link      *
 *    this program with the XForms library, and distribute the resulting       *
 *    executable without the source code for XForms in the source              *
 *    distribution".                                                           *
 *                                                                             *
 ******************************************************************************/


#include <fmail.h>
#include <umail.h>
#include <choose_folder.h>
#include <cfgfile.h>

extern cfgfile Config;

static FD_keymap *keymap_obj;
static int ready = 0;
char *keyfuncstr(int function);
char *keysymstr(int keysym);

typedef struct _fname {
	int function;
	char *name;
}
fname;

static struct _fname fnames[] = {
	{FL_TEXTKEY_HOME, "BOT"},
	{FL_TEXTKEY_END, "EOT"},
	{FL_TEXTKEY_LBEGIN, "BOL"},
	{FL_TEXTKEY_LEND, "EOL"},
	{FL_TEXTKEY_LEFT, "Left"},
	{FL_TEXTKEY_RIGHT, "Right"},
	{FL_TEXTKEY_UP, "Up"},
	{FL_TEXTKEY_DOWN, "Down"},
	{FL_TEXTKEY_SLEFT, "Select Left"},
	{FL_TEXTKEY_SRIGHT, "Select Right"},
	{FL_TEXTKEY_SUP, "Select Up"},
	{FL_TEXTKEY_SDOWN, "Select Down"},
	{FL_TEXTKEY_PAGEUP, "Pageup"},
	{FL_TEXTKEY_PAGEDOWN, "Pagedown"},
	{FL_TEXTKEY_LKILL, "DeleteEOL"},
	{FL_TEXTKEY_REFRESH, "Refresh"},
	{FL_TEXTKEY_LCLEAR, "Clearline"},
	{FL_TEXTKEY_PASTE, "Paste"},
	{FL_TEXTKEY_LDELETE, "Deleteline"},
	{FL_TEXTKEY_CLEAR, "ClearAll"},
	{FL_TEXTKEY_FIND, "Find"},
	{FL_TEXTKEY_FAGAIN, "FindAgain"},
	{FL_TEXTKEY_FORMAT, "Format"},
	{FL_TEXTKEY_DELETE, "Delete"},
	{FL_TEXTKEY_BACKSPACE, "Backspace"},
	{FL_TEXTKEY_WORDLEFT, "Wordleft"},
	{FL_TEXTKEY_WORDRIGHT, "Wordright"},
	{FL_TEXTKEY_DELWORDL, "DelPrevWord"},
	{FL_TEXTKEY_DELWORDR, "DelNextWord"},
	{FL_TEXTKEY_CUT, "Cut"},
	{FL_TEXTKEY_COPY, "Copy"},
	{FL_TEXTKEY_DIGRAPH, "Digraph"},
	{FL_TEXTKEY_ENDARRAY, ""}
};

int
Test_Call(FL_OBJECT * ob, int event,
		  FL_Coord mx, FL_Coord my, int key, void *raw_ev) {
	XKeyEvent *xkev = (XKeyEvent *) raw_ev;
	char buf[32];

	if(event != FL_KEYBOARD)
		return !FL_PREEMPT;

	if(xkev->state & ControlMask)
		snprintf(buf, sizeof(buf), "Ctrl+%s", keysymstr(key));
	else if(xkev->state & Mod1Mask)
		snprintf(buf, sizeof(buf), "Alt+%s", keysymstr(key));
	else if(xkev->state & ShiftMask)
		snprintf(buf, sizeof(buf), "Shift+%s", keysymstr(key));
	else
		strcpy(buf, keysymstr(key));

	fl_set_input(ob, buf);
	return FL_PREEMPT;
}

void Keymap_Call(FL_OBJECT * obj, long param) {
}

void Keymap_Default_Call(FL_OBJECT * obj, long param) {
	if(!obj->form->focusobj || (obj->form->focusobj->argument <= 0))
		return;

	fl_textedit_map_key(obj->form->focusobj->argument, -1, 0);
	fl_set_input(obj->form->focusobj,
				 keyfuncstr(obj->form->focusobj->argument));
}

long *strkeysym(char *str) {
	static long keys[FL_TEXTKEY_MAXBIND];
	int i, keysym;
	char *p, c;

	for(i = 0; i < FL_TEXTKEY_MAXBIND; i++)
		keys[i] = -1;

	if(!str)
		return NULL;

	if((p = strtok(str, ",")) == NULL)
		return NULL;

	i = 0;
	do {
		keys[i] = 0;
		if(!strncmp(p, "Ctrl+", 5)) {
			keys[i] = FL_CONTROL_MASK;
			p += 5;
		} else if(!strncmp(p, "Shift+", 6)) {
			keys[i] = FL_SHIFT_MASK;
			p += 6;
		} else if(!strncmp(p, "Alt+", 4)) {
			keys[i] = FL_ALT_MASK;
			p += 4;
		} else if(!strncmp(p, "Any+", 4)) {
			keys[i] = FL_ANY_MASK;
			p += 4;
		}

		if(!*p) {
			keys[i] = -1;
			continue;
		}

		keysym = NoSymbol;
		if(strlen(p) == 1) {
			c = *p;
			if((keys[i] != FL_ALT_MASK) && (keys[i] != FL_CONTROL_MASK)) {
				if(c >= 32) {
					keys[i] = -1;
					continue;
				}
			}

			if((c >= 'A') && (keys[i] != FL_ALT_MASK))
				keysym = c - 'A' + 1;
			else
				keysym = c;
		} else if(!strcasecmp(p, "Delete"))
			keysym = 127;
		else if(!strcasecmp(p, "Backspace"))
			keysym = '\b';
		else
			keysym = XStringToKeysym(p);

		if(keysym == NoSymbol) {
			keys[i] = -1;
			continue;
		}

		keys[i] |= keysym;

		if(++i >= FL_TEXTKEY_MAXBIND)
			break;

	} while((p = strtok(NULL, ",")) != NULL);

	if(keys[0] == -1)
		return NULL;

	return keys;
}

char *keysymstr(int keysym) {
	static char kstr[2];
	char *ks;

	if((ks = XKeysymToString(keysym)) == NULL) {
		switch(keysym) {
			case '\b':
				ks = "Backspace";
				break;

			case 127:
				ks = "Delete";
				break;

			default:
				if(keysym < 32)
					keysym = keysym + 'A' - 1;
				kstr[0] = keysym;
				kstr[1] = '\0';
				ks = kstr;
				break;
		}
	}

	return ks;
}

char *keyfuncstr(int function) {
	static char fstring[255];
	long keys[FL_TEXTKEY_MAXBIND];
	int i, keysym;
	char *ks;

	fstring[0] = '\0';
	fl_textedit_get_key(function, keys);
	for(i = 0; i < FL_TEXTKEY_MAXBIND; i++) {
		if(keys[i] > 0) {
			keysym = keys[i] & 0xffff;
			ks = keysymstr(keysym);

			if(*fstring)
				strcat(fstring, ",");

			if(keys[i] & FL_SHIFT_MASK)
				strcat(fstring, "Shift+");
			else if(keys[i] & FL_CONTROL_MASK)
				strcat(fstring, "Ctrl+");
			else if(keys[i] & FL_ALT_MASK)
				strcat(fstring, "Alt+");
			else if(keys[i] & FL_ANY_MASK)
				strcat(fstring, "Any+");

			strcat(fstring, ks);
		}
	}

	return fstring;
}

void display_keymap() {
	fl_set_input(keymap_obj->BOT, keyfuncstr(FL_TEXTKEY_HOME));
	fl_set_input(keymap_obj->EOT, keyfuncstr(FL_TEXTKEY_END));
	fl_set_input(keymap_obj->BOL, keyfuncstr(FL_TEXTKEY_LBEGIN));
	fl_set_input(keymap_obj->EOL, keyfuncstr(FL_TEXTKEY_LEND));
	fl_set_input(keymap_obj->Left, keyfuncstr(FL_TEXTKEY_LEFT));
	fl_set_input(keymap_obj->Right, keyfuncstr(FL_TEXTKEY_RIGHT));
	fl_set_input(keymap_obj->Up, keyfuncstr(FL_TEXTKEY_UP));
	fl_set_input(keymap_obj->Down, keyfuncstr(FL_TEXTKEY_DOWN));
	fl_set_input(keymap_obj->Pageup, keyfuncstr(FL_TEXTKEY_PAGEUP));
	fl_set_input(keymap_obj->Pagedown, keyfuncstr(FL_TEXTKEY_PAGEDOWN));
	fl_set_input(keymap_obj->Wordleft, keyfuncstr(FL_TEXTKEY_WORDLEFT));
	fl_set_input(keymap_obj->Wordright, keyfuncstr(FL_TEXTKEY_WORDRIGHT));
	fl_set_input(keymap_obj->Find, keyfuncstr(FL_TEXTKEY_FIND));
	fl_set_input(keymap_obj->Findagain, keyfuncstr(FL_TEXTKEY_FAGAIN));
	fl_set_input(keymap_obj->Clearline, keyfuncstr(FL_TEXTKEY_LCLEAR));
	fl_set_input(keymap_obj->Clearscreen, keyfuncstr(FL_TEXTKEY_CLEAR));
	fl_set_input(keymap_obj->Deleteline, keyfuncstr(FL_TEXTKEY_LDELETE));
	fl_set_input(keymap_obj->Delete, keyfuncstr(FL_TEXTKEY_DELETE));
	fl_set_input(keymap_obj->Deletend, keyfuncstr(FL_TEXTKEY_LKILL));
	fl_set_input(keymap_obj->Backspace, keyfuncstr(FL_TEXTKEY_BACKSPACE));
	fl_set_input(keymap_obj->Refresh, keyfuncstr(FL_TEXTKEY_REFRESH));
	fl_set_input(keymap_obj->Paste, keyfuncstr(FL_TEXTKEY_PASTE));
	fl_set_input(keymap_obj->Format, keyfuncstr(FL_TEXTKEY_FORMAT));
	fl_set_input(keymap_obj->Delprevword, keyfuncstr(FL_TEXTKEY_DELWORDL));
	fl_set_input(keymap_obj->Delnextword, keyfuncstr(FL_TEXTKEY_DELWORDR));
	fl_set_input(keymap_obj->SLeft, keyfuncstr(FL_TEXTKEY_SLEFT));
	fl_set_input(keymap_obj->SRight, keyfuncstr(FL_TEXTKEY_SRIGHT));
	fl_set_input(keymap_obj->SUp, keyfuncstr(FL_TEXTKEY_SUP));
	fl_set_input(keymap_obj->SDown, keyfuncstr(FL_TEXTKEY_SDOWN));
	fl_set_input(keymap_obj->Cut, keyfuncstr(FL_TEXTKEY_CUT));
	fl_set_input(keymap_obj->Copy, keyfuncstr(FL_TEXTKEY_COPY));
	fl_set_input(keymap_obj->Digraph, keyfuncstr(FL_TEXTKEY_DIGRAPH));

	return;
}

int set_keymap() {
	if(fl_textedit_set_key
	   (FL_TEXTKEY_HOME,
		strkeysym((char *) fl_get_input(keymap_obj->BOT))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->BOT);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_END,
		strkeysym((char *) fl_get_input(keymap_obj->EOT))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->EOT);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_LBEGIN,
		strkeysym((char *) fl_get_input(keymap_obj->BOL))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->BOL);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_LEND,
		strkeysym((char *) fl_get_input(keymap_obj->EOL))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->EOL);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_LEFT,
		strkeysym((char *) fl_get_input(keymap_obj->Left))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Left);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_RIGHT,
		strkeysym((char *) fl_get_input(keymap_obj->Right))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Right);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_UP,
		strkeysym((char *) fl_get_input(keymap_obj->Up))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Up);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_DOWN,
		strkeysym((char *) fl_get_input(keymap_obj->Down))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Down);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_PAGEUP,
		strkeysym((char *) fl_get_input(keymap_obj->Pageup))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Pageup);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_PAGEDOWN,
		strkeysym((char *) fl_get_input(keymap_obj->Pagedown))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Pagedown);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_WORDLEFT,
		strkeysym((char *) fl_get_input(keymap_obj->Wordleft))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Wordleft);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_WORDRIGHT,
		strkeysym((char *) fl_get_input(keymap_obj->Wordright))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Wordright);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_FIND,
		strkeysym((char *) fl_get_input(keymap_obj->Find))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Find);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_FAGAIN,
		strkeysym((char *) fl_get_input(keymap_obj->Findagain))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Findagain);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_LCLEAR,
		strkeysym((char *) fl_get_input(keymap_obj->Clearline))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Clearline);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_CLEAR,
		strkeysym((char *) fl_get_input(keymap_obj->Clearscreen))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Clearscreen);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_LDELETE,
		strkeysym((char *) fl_get_input(keymap_obj->Deleteline))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Deleteline);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_DELETE,
		strkeysym((char *) fl_get_input(keymap_obj->Delete))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Delete);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_LKILL,
		strkeysym((char *) fl_get_input(keymap_obj->Deletend))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Deletend);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_BACKSPACE,
		strkeysym((char *) fl_get_input(keymap_obj->Backspace))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Backspace);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_REFRESH,
		strkeysym((char *) fl_get_input(keymap_obj->Refresh))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Refresh);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_PASTE,
		strkeysym((char *) fl_get_input(keymap_obj->Paste))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Paste);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_FORMAT,
		strkeysym((char *) fl_get_input(keymap_obj->Format))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Format);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_DELWORDL,
		strkeysym((char *) fl_get_input(keymap_obj->Delprevword))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Delprevword);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_DELWORDR,
		strkeysym((char *) fl_get_input(keymap_obj->Delnextword))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Delnextword);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_SLEFT,
		strkeysym((char *) fl_get_input(keymap_obj->SLeft))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->SLeft);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_SRIGHT,
		strkeysym((char *) fl_get_input(keymap_obj->SRight))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->SRight);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_SUP,
		strkeysym((char *) fl_get_input(keymap_obj->SUp))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->SUp);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_SDOWN,
		strkeysym((char *) fl_get_input(keymap_obj->SDown))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->SDown);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_CUT,
		strkeysym((char *) fl_get_input(keymap_obj->Cut))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Cut);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_COPY,
		strkeysym((char *) fl_get_input(keymap_obj->Copy))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Copy);
		return -1;
	}

	if(fl_textedit_set_key
	   (FL_TEXTKEY_DIGRAPH,
		strkeysym((char *) fl_get_input(keymap_obj->Digraph))) != 0) {
		fl_ringbell(100);
		fl_set_focus_object(keymap_obj->keymap, keymap_obj->Digraph);
		return -1;
	}

	return 0;
}

int load_keymap() {
	char buf[255], funcname[32], mapstr[128];
	int i;
	long *keys;
	FILE *kfd;

	snprintf(buf, sizeof(buf), "%s/.xfmkeymap", configdir);

	if((kfd = fopen(buf, "r")) == NULL)
		return 0;

	while(fgets(buf, 255, kfd)) {
		if(buf[0] == '#')
			continue;

		strip_newline(buf);

		funcname[0] = '\0';
		mapstr[0] = '\0';

		if(sscanf(buf, "%31s\t%127s", funcname, mapstr) != 2)
			continue;

		if((keys = strkeysym(mapstr)) == NULL)
			continue;

		i = 0;
		while(fnames[i].function != FL_TEXTKEY_ENDARRAY) {
			if(!strcmp(fnames[i].name, funcname)) {
				fl_textedit_set_key(fnames[i].function, keys);
				break;
			}
			i++;
		}
	}

	fclose(kfd);
	return 0;
}

int save_keymap() {
	char buf[255];
	FILE *kfd;
	int i = 0;

	snprintf(buf, sizeof(buf), "%s/.xfmkeymap", configdir);

	if((kfd = fopen(buf, "w")) == NULL) {
		display_msg(MSG_WARN, "save keymap", "Can not open %s", buf);
		return -1;
	}

	while(fnames[i].function != FL_TEXTKEY_ENDARRAY) {
		if(fl_textedit_key_remapped(fnames[i].function))
			fprintf(kfd, "%s\t%s\n", fnames[i].name,
					keyfuncstr(fnames[i].function));
		i++;
	}

	fclose(kfd);
	return 0;
}

void keymap_conf() {
	if(ready)
		return;

	ready = 1;

	keymap_obj = create_form_keymap();
	fl_set_object_prehandler(keymap_obj->Test, Test_Call);
	keymap_obj->Test->wantkey = FL_KEY_ALL;
	keymap_obj->Test->objclass = FL_TEXTEDIT;

	display_keymap();

	fl_show_form(keymap_obj->keymap, FL_PLACE_CENTER, FL_TRANSIENT,
				 "Keymap");
	showkmap:
	fl_do_only_forms();

	if(set_keymap() != 0)
		goto showkmap;

	save_keymap();

	fl_hide_form(keymap_obj->keymap);
	fl_free_form(keymap_obj->keymap);
	fl_free(keymap_obj);
	keymap_obj = NULL;

	ready = 0;
	return;
}

void Keymap_Digraphs_Call(FL_OBJECT * obj, long param) {
	FD_Help_Form *help_obj = create_form_Help_Form();
	struct _digraph *dg = fl_textedit_get_digraphs();
	char *dstr = keyfuncstr(FL_TEXTKEY_DIGRAPH);
	char buf[64], geom[16];
	int i, w, h;

	fl_deactivate_form(keymap_obj->keymap);
	fl_freeze_form(help_obj->Help_Form);
	fl_set_browser_fontstyle(help_obj->Help_Browser, FL_FIXED_STYLE);
	fl_set_browser_fontsize(help_obj->Help_Browser, FL_MEDIUM_SIZE);
	fl_clear_browser(help_obj->Help_Browser);
	for(i = 0; dg[i].key != 0; i++) {
		snprintf(buf, sizeof(buf), "%c - <%s> <%c> <%c>", dg[i].key, dstr,
				 dg[i].seq[0], dg[i].seq[1]);
		fl_add_browser_line(help_obj->Help_Browser, buf);
	}

	Config.setFlags("digrgeom", CF_NOTCHANGED);
	w = 500;
	h = 300;
	sscanf(Config.get("digrgeom", "").c_str(), "%d %d", &w, &h);
	fl_deactivate_object(help_obj->HelpTop);
	fl_deactivate_object(help_obj->HelpBack);
	fl_set_object_callback(help_obj->Done_Help, NULL, 0);
	fl_unfreeze_form(help_obj->Help_Form);
	fl_set_form_minsize(help_obj->Help_Form, 400, 200);
	fl_set_form_size(help_obj->Help_Form, w, h);
	fl_show_form(help_obj->Help_Form, FL_PLACE_FREE, FL_TRANSIENT,
				 "List of digraph sequences");

	fl_do_only_forms();

	sprintf(geom, "%d %d", help_obj->Help_Form->w, help_obj->Help_Form->h);
	Config.set("digrgeom", geom);
	fl_hide_form(help_obj->Help_Form);
	fl_free_form(help_obj->Help_Form);
	fl_free(help_obj);
	fl_activate_form(keymap_obj->keymap);
}
