/* This file is part of
* ======================================================
* 
*           LyX, the High Level Word Processor
* 	 
*	    Copyright (C) 1995 1996 Matthias Ettrich
*           and the LyX Team.
*
*======================================================*/


/* ======================================================================= *\
    File   : keybind.C, keybind.C,v 1.4 1996/08/29 15:41:04 larsbj Exp
    Author : chb, 28.Oct.1995
    Docu   : see keybind.h
    Purpose: rebindable keys for LyX
\* ======================================================================= */

#define  _KEYBIND_C_

#include "config.h"

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#if defined(__sgi)
#include <strings.h>
#endif

#include "definitions.h"
#include "file.h"
#include "kbmap.h"
#include "keybind.h"
#include "lyxserver.h"
#include "lyx.h"
#include "intl.h"
#include "tex-defs.h"
#include "buffer.h"
#include "lyx_cb.h"
#include "formula.h"
#include "toolbar.h"
#include "spellchecker.h" // RVDK_PATCH_5
#include "minibuffer.h"

extern void math_insert_symbol(const char*);
extern Bool math_insert_greek(const char);
extern short greek_kb_flag;

extern FD_form_toc *fd_form_toc;
//extern FL_OBJECT *choice_layouts; // the layouts in the toolbar

extern bool selection_possible;


extern void Update(signed char);
extern void BeforeChange();
extern void UpdateScrollbar();
extern void MenuNew();
extern void MenuOpen();
extern void MenuOpenByName( const char *menuName );         // RVDK_PATCH_5
extern void MenuWrite(Buffer*);
extern void MenuWriteAs();
extern void MenuRunLaTeX();
extern void MenuPrint();
extern void CloseBuffer();
extern void MenuQuit();
extern void QuitLyX();
extern void AutoSave();
extern void MenuSearch();
extern void CopyCB();
extern void GotoError();
extern void GotoNote();
extern void NoteCB();
extern void OpenStuff();
extern void HyphenationPoint();
extern void HFill();
extern void MenuLoadAutoSave();
extern void MenuUndo();
extern void MenuRedo();
extern void ResizeCurrentBufferPseudoExpose();
extern void CursorPrevious();
extern void CursorNext();
extern void SmallUpdate(signed char);
extern void SetUpdateTimer();
extern void FreeUpdateTimer();
extern void InsertCorrectQuote();
extern void MenuPreview();
extern void MenuPreviewPS();
extern void MenuInsertLabel();
extern void MenuInsertRef();
extern void MenuLayoutCharacter();
extern void MenuLayoutParagraph();
extern void MenuLayoutDocument();
extern void MenuLayoutQuotes();
extern void MenuLayoutPreamble();

extern void InsertLyxFile(char *);
extern void NewLyxFile(char *);
extern void LoadLyXFile(const char *);

extern int work_area_height;

extern char *cdefmap[];

extern int UnlockInset(UpdatableInset*);

static
void do_accent_char(tex_accent_struct,int,kb_action);

static
inline
tex_accent_struct get_accent(kb_action);

/* === globals =========================================================== */

kb_keymap *toplevel_keymap;
kb_sequence keyseq;
kb_sequence cancel_meta_seq;                            // RVDK_PATCH_5
unsigned meta_fake_bit = 0;                             // RVDK_PATCH_5

static kb_action lyx_dead_action = LFUN_NOACTION;
static kb_action lyx_calling_dead_action = LFUN_NOACTION;

// if we use WorkAreaKeyPress as function dispatcher, set this:

static kb_action dispatch_action = LFUN_NOACTION;
static char *dispatch_argument   = NULL;
static char *dispatch_result     = NULL;
static char  dispatch_buffer[100];


struct kb_func_table {
   char *name;
   kb_action action;
};

 
 /*  
     NAMING RULES FOR USER-COMMANDS
     Here's the set of rules to apply when a new command name is introduced:
 
     1) Use the object.event order. That is, use `word-forward' instead of `forward-word'.
     2) Don't introduce an alias for an already named object. Same for events.
     3) Forward movement or focus is called `forward' (not `right').
     4) Backward movement or focus is called `backward' (not `left').
     5) Upward movement of focus is called `up'.
     6) Downward movement is called `down'.
     7) The begin of an object is called `begin' (not `start').
     8) The end of an object is called `end'.
 
     (May 19 1996, 12:04, RvdK)
 */
 
 
/* This table is sorted alphabetically [asierra 14Jan96] */
static kb_func_table lyx_func_table[] = {
    // { "line-at",                           LFUN_LINEATCURSOR, },  // Not used.
    // { "server-get-buffer-name",            LFUN_GETBUFNAME, },    // Not used.
    { "accent-acute",                         LFUN_ACUTE, },
    { "accent-breve",                         LFUN_BREVE, },
    { "accent-caron",                         LFUN_CARON, },
    { "accent-cedilla",                       LFUN_CEDILLA, },
    { "accent-circle",                        LFUN_CIRCLE, },
    { "accent-circumflex",                    LFUN_CIRCUMFLEX, },
    { "accent-dot",                           LFUN_DOT, },
    { "accent-grave",                         LFUN_GRAVE, },
    { "accent-hungarian-umlaut",              LFUN_HUNG_UMLAUT, },
    { "accent-macron",                        LFUN_MACRON, },
    { "accent-special-caron",                 LFUN_SPECIAL_CARON, },
    { "accent-tie",                           LFUN_TIE, },
    { "accent-tilde",                         LFUN_TILDE, },
    { "accent-umlaut",                        LFUN_UMLAUT, },
    { "accent-underbar",                      LFUN_UNDERBAR, },
    { "accent-underdot",                      LFUN_UNDERDOT, },
    { "accent-vector",                        LFUN_VECTOR, }, 
    { "backward-select",                      LFUN_LEFTSEL, },
    { "break-line",                           LFUN_BREAKLINE, },
    { "break-paragraph",                      LFUN_BREAKPARAGRAPH, },
    { "break-paragraph-keep-layout",          LFUN_BREAKPARAGRAPHKEEPLAYOUT, },
    { "buffer-auto-save",                     LFUN_AUTOSAVE, },
    { "buffer-begin",                         LFUN_BEGINNINGBUF, },
    { "buffer-begin-select",                  LFUN_BEGINNINGBUFSEL, },
    { "buffer-close",                         LFUN_CLOSEBUFFER, },         
    { "buffer-end",                           LFUN_ENDBUF, },
    { "buffer-end-select",                    LFUN_ENDBUFSEL, },
    { "buffer-load-auto-save",                LFUN_MENULOADAUTO, },
    { "buffer-new",                           LFUN_MENUNEW, },     
    { "buffer-open",                          LFUN_MENUOPEN, },    
    { "buffer-previous",                      LFUN_PREVBUFFER, },  
    { "buffer-print",                         LFUN_MENUPRINT, },   
    { "buffer-typeset",                       LFUN_RUNLATEX, },        // Alejandro's proposal
    { "buffer-view",                          LFUN_PREVIEW, },
    { "buffer-view-ps",                       LFUN_PREVIEWPS, },
    { "buffer-write",                         LFUN_MENUWRITE, },   
    { "buffer-write-as",                      LFUN_MENUWRITEAS, }, 
    { "cancel",                               LFUN_CANCEL, },
    { "char-backward",                             LFUN_LEFT, },
    { "char-forward",                              LFUN_RIGHT, },
    { "command-execute", 					  LFUN_EXEC_COMMAND, },
    { "command-prefix",                       LFUN_PREFIX, },
    { "copy",                                 LFUN_COPY, },
    { "cut",                                  LFUN_CUT, },
    { "delete-backward",                      LFUN_BACKSPACE, },
    { "delete-forward",                       LFUN_DELETE, },
    { "depth-decrement",                      LFUN_DEPTH_MIN, },
    { "depth-increment",                      LFUN_DEPTH_PLUS, },  
    { "depth-next",                           LFUN_DEPTH, },
    { "down",                                 LFUN_DOWN, },                 
    { "down-select",                          LFUN_DOWNSEL, },
    { "drop-layouts-choice",                               LFUN_DROP_LAYOUTS_CHOICE, },
    { "error-next",                           LFUN_GOTOERROR, },   
    { "figure-insert",                        LFUN_FIGURE, },
    { "file-insert",                          LFUN_FILE_INSERT, },
    { "file-new",                             LFUN_FILE_NEW, },
    { "file-open",                            LFUN_FILE_OPEN, },
    { "find-replace",                         LFUN_MENUSEARCH, },  
    { "font-bold",                            LFUN_BOLD, },        
    { "font-code",                            LFUN_CODE, },        
    { "font-default",                         LFUN_DEFAULT, },     
    { "font-emph",                            LFUN_EMPH, },        
    { "font-free",                            LFUN_FREE, },
    { "font-roman",                           LFUN_ROMAN, },          
    { "font-sans",                            LFUN_SANS, },
    { "font-size",                            LFUN_FONT_SIZE, },
    { "font-smallcaps",                       LFUN_NOUN, },        
    { "font-state",                           LFUN_FONT_STATE, }, 
    { "font-underline",                       LFUN_UNDERLINE, },   
    { "footnote-insert",                      LFUN_FOOTMELT, },    
    { "forward-select",                       LFUN_RIGHTSEL, },
    { "hfill-insert",                         LFUN_HFILL, },
    { "hyphenation-point-insert",             LFUN_HYPHENATION, },
    { "inset-formula-latex-deletable-insert", LFUN_INSERT_INSET_FORMULA_LATEX_DEL, },
    { "inset-formula-latex-insert",           LFUN_INSERT_INSET_FORMULA_LATEX, },
    { "inset-latex-deletable-insert",         LFUN_INSERT_INSET_LATEX_DEL, },
    { "inset-latex-insert",                   LFUN_INSERT_INSET_LATEX, },
    { "keymap-off",                           LFUN_KMAP_OFF, },
    { "keymap-primary",                       LFUN_KMAP_PRIM, },
    { "keymap-secondary",                     LFUN_KMAP_SEC, },
    { "keymap-toggle",                        LFUN_KMAP_TOGGLE, },
    { "label-insert",                         LFUN_INSERT_LABEL, }, 
    { "layout",                               LFUN_LAYOUT, },
    { "layout-character",                               LFUN_LAYOUT_CHARACTER, },
    { "layout-document",                               LFUN_LAYOUT_DOCUMENT, },
    { "layout-paragraph",                               LFUN_LAYOUT_PARAGRAPH, },
    { "layout-preamble",                               LFUN_LAYOUT_PREAMBLE, },
    { "layout-quotes",                               LFUN_LAYOUT_QUOTES, },
    { "line-begin",                           LFUN_HOME, },        
    { "line-begin-select",                    LFUN_HOMESEL, },     
    { "line-delete-forward",                  LFUN_DELETE_LINE_FORWARD, },  
    { "line-end",                             LFUN_END, },         
    { "line-end-select",                      LFUN_ENDSEL, },      
    { "lyx-quit",                             LFUN_QUIT, },
    { "marginpar-insert",                     LFUN_MARGINMELT, },  
    { "mark-off",                             LFUN_MARK_OFF, },    
    { "mark-on",                              LFUN_MARK_ON, },     
    { "mark-toggle",                          LFUN_SETMARK, }, 
    { "math-delim",                           LFUN_MATH_DELIM },
    { "math-display",                         LFUN_MATH_DISPLAY, }, // Alejandro's proposal
    { "math-greek",                           LFUN_GREEK, },   
    { "math-greek-toggle",                    LFUN_GREEK_TOGGLE, },   
    { "math-insert",                          LFUN_INSERT_MATH, },   
    { "math-limits",                          LFUN_MATH_LIMITS, },
    { "math-matrix",                          LFUN_INSERT_MATRIX, }, 
    { "math-mode",                            LFUN_MATH_MODE, },
    { "math-mode-old",                        LFUN_FORMULA, },         // Alejandro's proposal     // Alejandro's proposal
    { "math-nonumber",                        LFUN_MATH_NONUMBER, },
    { "math-number",                          LFUN_MATH_NUMBER, }, 
    { "math-size",                            LFUN_MATH_SIZE, }, 
    { "melt",                                 LFUN_MELT, },            // Needs better name.
    { "menu-open",                            LFUN_MENU_OPEN_BY_NAME, },    
    { "meta-prefix",                          LFUN_META_FAKE, },
    { "note-insert",                          LFUN_INSERT_NOTE, },
    { "note-next",                            LFUN_GOTONOTE, },
    { "open-stuff",                           LFUN_OPENSTUFF, },       // Needs better name.
    { "paste",                                LFUN_PASTE, },
    { "prefix-arg",                           LFUN_PREFIXARG, },
    { "protected-space-insert",               LFUN_PROTECTEDSPACE, },
    { "quote-insert",                         LFUN_QUOTE, },
    { "redo",                                 LFUN_REDO, },
    { "ref-insert",                           LFUN_INSERT_REF, },      // reference-insert?
    { "screen-down",                          LFUN_NEXT, },        
    { "screen-down-select",                   LFUN_NEXTSEL, },     
    { "screen-recenter",                      LFUN_CENTER, },
    { "screen-up",                            LFUN_PRIOR, },       
    { "screen-up-select",                     LFUN_PRIORSEL, },    
    { "self-insert",                          LFUN_SELFINSERT, },
    { "server-char-after",                    LFUN_CHARATCURSOR, },
    { "server-get-font",                      LFUN_GETFONT, },
    { "server-get-latex",                     LFUN_GETLATEX, },
    { "server-get-layout",                    LFUN_GETLAYOUT, },
    { "server-get-name",                      LFUN_GETNAME, },
    { "server-get-xy",                        LFUN_GETXY, },
    { "server-notify",                        LFUN_NOTIFY, },
    { "server-set-xy",                        LFUN_SETXY, },
    { "spellchecker",                         LFUN_SPELLCHECK, },  
    { "symbol-insert",                        LFUN_INSERT_MATH, },
    { "tab-forward",                          LFUN_TAB, },
    { "table-insert",                         LFUN_TABLE, },
    { "tex-mode",                             LFUN_TEX, },
    { "toc-update",                           LFUN_TOCUPDATE, },
    { "toolbar-add-to",                       LFUN_ADD_TO_TOOLBAR },
    { "toolbar-push",                         LFUN_PUSH_TOOLBAR },
    { "undo",                                 LFUN_UNDO, },
    { "up",                                   LFUN_UP, },          
    { "up-select",                            LFUN_UPSEL, },       
    { "word-backward",                        LFUN_WORDLEFT, },
    { "word-backward-select",                 LFUN_WORDLEFTSEL, },
    { "word-capitalize",                      LFUN_CAPITALIZE_WORD, },
    { "word-delete-backward",                 LFUN_DELETE_WORD_BACKWARD, },    
    { "word-delete-forward",                  LFUN_DELETE_WORD_FORWARD, }, 
    { "word-forward",                         LFUN_WORDRIGHT, },
    { "word-forward-select",                  LFUN_WORDRIGHTSEL, },
    { "word-lowcase",                         LFUN_LOWCASE_WORD, },
    { "word-upcase",                          LFUN_UPCASE_WORD, },
};


/* === code ============================================================== */

/* This routines allow binding actions with argument.
 * Provisionally a fixed size array and global functions are used.
 * [asierra 20Jan96]
 */
#define MAX_PSEUDO_ACTION 128

static kb_func_table lyx_func_args[MAX_PSEUDO_ACTION];
static int psd_idx = 0;

// Search for an existent pseudoaction, returns -1 if it doesn't exist.
int search_action_arg(kb_action action, const char *arg)
{
   kb_func_table *tb = &lyx_func_args[0];
   for (int i=0; i<psd_idx; i++) {
      if (action==tb->action && !strcmp(tb->name, arg)) {	 
#ifdef DEBUG
	 fprintf(stderr, "Pseudoaction already exist[%d|%s]", action, arg);
#endif
	return LFUN_LASTACTION+i;
      }
      tb++;
   }
   return -1;
}

// Returns a pseudo-action given an action and its argument
int get_pseudo_action(kb_action action, const char *arg)
{
   // Check if the pseudo-action already exist.
   int psdaction = search_action_arg(action, arg);
   
   if (psdaction >= 0) return psdaction;

   if (psd_idx>=MAX_PSEUDO_ACTION) {
      fprintf(stderr, "Lyx Error: No more pseudo-actions allowed\n");
      return -1;
   }
   lyx_func_args[psd_idx].name = strdup(arg);
   lyx_func_args[psd_idx].action = action;
   psd_idx++;
   return LFUN_LASTACTION+psd_idx-1;
}

// Retrieves the real action and its argument, or -1
int retrieve_action_arg(int i, char** arg)
{
   i -= LFUN_LASTACTION;
   if (i >= 0 &&  i <psd_idx) {
      *arg = lyx_func_args[i].name;
      return (int)lyx_func_args[i].action;
   } else {
      fprintf(stderr, "Lyx Error: Unrecognized pseudo-action\n");
      return -1;
   }
}


/* Binary search for Lyx Functions. [asierra 14Jan96] */
int LookupLyxFunc(const char *func)
{
   /* Let the range depend of the size of the lyx_func_table. RVDK_PATCH_5 */
   static int funcCount = sizeof(lyx_func_table) / sizeof(kb_func_table); 

   if (!func) 
     return -1;         
   if (func[0] == '\0')
     return LFUN_NOACTION;
 
   /* In the scan loop below, l can never become r, so set r one past the last
      valid func table slot. RVDK_PATCH_5 */
   int m, k, l= 0, r = funcCount;
   int action = -1;
   char *arg = (char *) strchr(func, ' ');

   if (arg) *(arg++) = '\0';      

   while (l < r) {
      m = (l+r)/2;
      k = strcmp(lyx_func_table[m].name, func);
      if (k==0) {
	 action = lyx_func_table[m].action;
	 break;
      } else
      	if (k<0) l = m+1; else r = m;
   }
   if (arg && action >= 0) {
      action = get_pseudo_action((kb_action)action, arg);
#ifdef DEBUG
      fprintf(stderr, "Pseudo action_arg[%d|%s]", action, arg);
#endif
   }
   return action;
}

/* ---F+------------------------------------------------------------------ *\
    Function  : DispatchFunction
    Called by : [user]
    Purpose   : Call a LyX editing function manually
    Parameters: action   - the kb_action to call
                argument - a string argument
    Returns   : dispatch_result (set by WorkAreaKeyPress)
    Note      : dispatch_result will always point to a static string;
                so the caller should save it if it's to be used later.
\* ---F------------------------------------------------------------------- */

char *DispatchFunction(int ac,
		       const char *argument,
		       FL_OBJECT *ob)
{
	char *arg = StringCopy(argument);
	// we should check here if the action is a a pseudo action
	if (arg == NULL) {
		if (IsPseudoAction((int)ac)) {
			//fprintf(stderr, "pseudo action %d\n)", (int)ac);
			ac = retrieve_action_arg((int)ac, &arg);
			//fprintf(stderr, "retrieved action %d\n", (int)ac);
		}
	}
	if (ac>=0 && ac<=LFUN_LASTACTION) {
                kb_action action = (kb_action)ac;
                // char *res = NULL; // unused
                
		dispatch_action   = action;
		dispatch_argument = StringCopy(arg);
		dispatch_result   = NULL;

		WorkAreaKeyPress(ob, 0, 0, 0, 0, 0);
		
		delete dispatch_argument;
		dispatch_argument = NULL;
   
		return dispatch_result;

        } else 
                fprintf(stderr, "Dispatch Error: Undefinded action [%d]", ac);

	char *ret = "";
	return ret;
}


/* ---F+------------------------------------------------------------------ *\
    Function  : MoveCursorUpdate
    Called by : WorkAreaKeyPress
    Purpose   : update display after cursor movement
    Parameters: shift - 1 if *SEL command
    Returns   : nothing
\* ---F------------------------------------------------------------------- */

void MoveCursorUpdate(int shift)
{
  static LyXFont last_font = bufferlist.current()->text->real_current_font;
  bufferlist.current()->text->FinishUndo();
  if (shift || bufferlist.current()->text->mark_set) {
    bufferlist.current()->text->SetSelection();
    bufferlist.current()->screen->ToggleToggle();
    Update(0);
    bufferlist.current()->screen->ShowCursor();

  } else {
    Update(-2); // this IS necessary (Matthias)
    bufferlist.current()->screen->ShowCursor();
  }

  /* ---> Everytime the cursor is moved, show the current font state. */
  if (!FontEqual(last_font, bufferlist.current()->text->real_current_font)){
    last_font = bufferlist.current()->text->real_current_font;
    FontStateShowCB( 0, 0 );
  }
    
}


/* ---F+------------------------------------------------------------------ *\
    Function  : WorkAreaKeyPress
    Called by : XForms Call back
    Purpose   : process key bindings for LyX
    Parameters: ob   - XForms object; passed but not used in called funcs
                win  - unused
                w, h - unused
                ev   - X Event
                d    - unused
    Returns   : 0
\* ---F------------------------------------------------------------------- */

int WorkAreaKeyPress(FL_OBJECT *ob,
                     Window,         // unused
                     int,              // unused
                     int,              // unused
                     XEvent *ev,
                     void *)            // unused
{
	static char s_r[10];
	static int num_bytes;
	int action; // kb_action action;
	kb_action tmp_action;
	char *argument;
	XKeyEvent *keyevent = &ev->xkey;
	KeySym keysym_return;
	
	selection_possible = false;
	if (bufferlist.current()->screen)
		bufferlist.current()->screen->HideCursor();
	
	if(dispatch_action != LFUN_NOACTION)
	{
		action = dispatch_action;
		dispatch_action = LFUN_NOACTION;
		argument = dispatch_argument;
	} else {
		num_bytes = XLookupString(keyevent, s_r, 10, &keysym_return, NULL);
		
		
		// Experimental: to make accesible the math functions
		// this function should be used always [asierra060396]
		if (bufferlist.current()->the_locking_inset && keysym_return == XK_Escape) {
			UnlockInset(bufferlist.current()->the_locking_inset);
			return 0;
		}
		
		if((keysym_return>=XK_Shift_L && keysym_return <= XK_Hyper_R)
		   || keysym_return == 0x0)
			return 0;

               // Do a one-deep top-level lookup for cancel and meta-fake keys. RVDK_PATCH_5
               cancel_meta_seq.reset();
               action = cancel_meta_seq.addkey(keysym_return, keyevent->state
                                               &(ShiftMask|ControlMask
                                                 |Mod1Mask|Mod2Mask)); 

               // When not cancel or meta-fake, do the normal lookup. 
               // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
               // Mostly, meta_fake_bit = 0. RVDK_PATCH_5.
               if ( (action != LFUN_CANCEL) && (action != LFUN_META_FAKE) ) {

                   // remove Caps Lock as a modifier
                   action = keyseq.addkey(keysym_return, (keyevent->state | meta_fake_bit)
                                          &(ShiftMask|ControlMask
                                            |Mod1Mask|Mod2Mask));      
               }
               meta_fake_bit = 0;
		
		// I have not decided if this is a good thing or not. Lgb.
		// if action==-1 lets check if there is a real action
		// for state = 0; this is not called if key is an implicit selfinsert
		//if (action==-1 && keyevent->state!=0
		//	  && keyevent->state!=LockMask && !keyseq.getiso()) { 
		//	 action = (kb_action)keyseq.addkey(keysym_return, 0);
		//}
		
		if (action==0) action = LFUN_PREFIX;      
		
		// if action is a pseudo-action, we need the real action
		if (IsPseudoAction(action)) {
			action = retrieve_action_arg(action, &argument);
		} else
			argument = NULL;
		
		if (lyx_debug_level & DEBUG_KEY) {
			char buf[100];
			keyseq.print(buf,100);
			fprintf(stderr, "Key: %s  Action: %d Argument: %s\n",
				buf, action, argument);
		}
		
	}
	
	tmp_action = (kb_action)action;
	if (lyx_calling_dead_action)
		action = lyx_dead_action;
	
	if(!bufferlist.current()->screen){
		switch(action){
		case LFUN_MENU_OPEN_BY_NAME:
		case LFUN_PREFIX:
		case LFUN_MENUNEW:
		case LFUN_MENUOPEN:
		case LFUN_QUIT:
		case LFUN_PUSH_TOOLBAR:
		case LFUN_ADD_TO_TOOLBAR:
		case LFUN_EXEC_COMMAND:
		case LFUN_DROP_LAYOUTS_CHOICE:
		case LFUN_FILE_NEW:
		case LFUN_FILE_OPEN:
			break;
		default:
			if (lyx_debug_level & DEBUG_KEY) {
				fprintf(stderr, "action not allowed!\n");
			}
			return 0;  // action not allowed
		}
	}

	if(keyseq.length>1 || keyseq.length<-1){
		char buf[100];
		keyseq.print(buf,100);
		minibuffer.Set(buf);
	}
   
	// If in math mode pass the control to
	// the math inset [asierra060396]
	if (bufferlist.current()->the_locking_inset) {
		if (action>1 || (action==-1 && keyseq.length>=-1)) {
			char s[8];
			if (action==-1 && !argument) {
				sprintf(s, "%c", keyseq.getiso());
				argument = &s[0];
			}
		       if (bufferlist.current()->the_locking_inset->LocalDispatch(action, argument))
		               return 0;
		}
	}
	
	switch(action)
	{
		// --- Misc --------------------------------------------------
	case LFUN_PREFIX:
	{
		if(bufferlist.current()->screen) Update(-2);
		char buf[100];
		keyseq.print(buf,100, true);
		minibuffer.Set(buf, "", "", 1);
	}
	break;
	
	case LFUN_PREFIXARG:
		// !!! add prefixarg setting here	    
		break;
		
		// --- Misc --------------------------------------------------
	case LFUN_EXEC_COMMAND:
		minibuffer.ExecCommand(); break;
	case LFUN_CANCEL:                                     // RVDK_PATCH_5
		// LyXBell();   
		keyseq.reset();
		meta_fake_bit = 0;
		minibuffer.Set("Cancel");
		break;
		
	case LFUN_META_FAKE:                                 // RVDK_PATCH_5
	{
		meta_fake_bit = Mod1Mask;
		char buf[100];
		keyseq.print(buf, 100, true);
		strcat( buf, " M-" );
		minibuffer.Set(buf, "", "");                 // RVDK_PATCH_5
	}
	break;  

	case LFUN_CENTER:
		BeforeChange();
		Update(-2);
		if (bufferlist.current()->text->cursor.y >
		    work_area_height / 2)
		{
			bufferlist.current()->screen->
				Draw(bufferlist.current()->text->cursor.y
				     - work_area_height / 2);
			UpdateScrollbar();
			minibuffer.Set("Screen centered");
		}
		else
		{
			LyXBell();
			minibuffer.Set("Cannot center top of document");
		}
		Update(0);
		break;
		
		// --- Menus -----------------------------------------------
	case LFUN_MENUNEW:      MenuNew();       break;
	case LFUN_MENUOPEN:     MenuOpen();      break;
	case LFUN_MENUWRITE:    MenuWrite(bufferlist.current());      break;
	case LFUN_MENUWRITEAS:  MenuWriteAs();   break;
	case LFUN_RUNLATEX:     MenuRunLaTeX();  break;
	case LFUN_PREVIEW:      MenuPreview();   break;
	case LFUN_PREVIEWPS:    MenuPreviewPS(); break;
	case LFUN_MENUPRINT:    MenuPrint();     break; 
	case LFUN_CLOSEBUFFER:  CloseBuffer();   break;
	case LFUN_QUIT:     QuitLyX();      break;
	case LFUN_TOCUPDATE:
		TocUpdateCB(ob, 0);
		if (fd_form_toc->form_toc->visible) {
			fl_raise_form(fd_form_toc->form_toc);
		} else
			fl_show_form(fd_form_toc->form_toc,
				     FL_PLACE_MOUSE |
				     FL_FREE_SIZE, FL_FULLBORDER,
				     "Table of Contents");
		break;

	case LFUN_TABLE:        TableCB(ob, 0);  break; 
	case LFUN_FIGURE:       FigureCB(ob, 0); break;  
	case LFUN_AUTOSAVE:     AutoSave();      break;
	case LFUN_MENULOADAUTO: MenuLoadAutoSave(); break;
	case LFUN_UNDO: MenuUndo(); break;
	case LFUN_REDO: MenuRedo(); break;
	case LFUN_MENUSEARCH:   MenuSearch();    break;
	case LFUN_PASTE:        PasteCB();  break;
	case LFUN_CUT:          CutCB();    break;
	case LFUN_COPY:         CopyCB();        break;
	case LFUN_GOTOERROR:    GotoError();     break;
	case LFUN_GOTONOTE:     GotoNote();     break;
	case LFUN_OPENSTUFF:    OpenStuff();     break;
	case LFUN_HYPHENATION:  HyphenationPoint(); break;
	case LFUN_HFILL:        HFill();         break;
	case LFUN_DEPTH:        DepthCB(ob, 0);  break;
	case LFUN_DEPTH_MIN:    DepthCB(ob, -1); break;
	case LFUN_DEPTH_PLUS:   DepthCB(ob, 1);  break;
	case LFUN_FREE:         FreeCB(ob, 0);   break;
	case LFUN_TEX:          TexCB(ob, 0);    break;
	case LFUN_FORMULA:      FormulaCB(ob, 0); break;
	case LFUN_MELT:         MeltCB(ob, 0); break;
		
	case LFUN_FOOTMELT:
		if (bufferlist.current()->text
		    && !bufferlist.current()->text->selection
		    && bufferlist.current()->text->cursor.par->footnoteflag
		    != LYX_NO_FOOTNOTE)
			MeltCB(ob,0);
		else
			FootCB(ob, 0); 
		break;
		
	case LFUN_MARGINMELT:
		if (bufferlist.current()->text
		    && !bufferlist.current()->text->selection
		    && bufferlist.current()->text->cursor.par->footnoteflag
		    != LYX_NO_FOOTNOTE)
			MeltCB(ob,0);
		else
			MarginCB(ob, 0); 
		break;
      
		// --- buffers ----------------------------------------
	case LFUN_PREVBUFFER:
		if (bufferlist.current()->text){	  
			BeforeChange();
			Update(-2);
		}
		bufferlist.prev();

		ResizeCurrentBufferPseudoExpose();
		minibuffer.Init();
		break;
        case LFUN_FILE_INSERT:
		InsertLyxFile(argument);
		break;
        case LFUN_FILE_NEW:
		// servercmd: argument must be <file>:<template>
		NewLyxFile(argument);
		break;

        case LFUN_FILE_OPEN:
		LoadLyXFile(argument);
                ResizeCurrentBufferPseudoExpose();
		break;

		// --- text style --------------------------------------
	case LFUN_LAYOUT:
	{
		/* Derive layout number from given argument (string)
		 * and current buffer's textclass (number). */    
		int layoutno = lyxstyle.NumberOfLayout(
			bufferlist.current()->text->parameters->textclass,
			argument );
		//if ( fl_get_choice(choice_layouts) != (layoutno+1) ) {
		if ( toolbar.combox->get() != (layoutno + 1) ) {
			Update( -2 );
			bufferlist.current()->text->SetLayout( layoutno );
			// fl_set_choice( choice_layouts, (layoutno+1) );
			// this is because some paragraphs refuses some layouts
			// (i.e. a table-paragraph is always standard)
			// fl_set_choice(choice_layouts,
// 				      bufferlist.current()->text->cursor.par->GetLayout()+1);
			toolbar.combox->select(bufferlist.current()->
					       text->cursor.par->
					       GetLayout() + 1);
		}
		Update(1);
	}
	break;

	case LFUN_LAYOUT_DOCUMENT:
	  MenuLayoutDocument(); break;
	case LFUN_LAYOUT_PARAGRAPH:
	  MenuLayoutParagraph(); break;
	case LFUN_LAYOUT_CHARACTER:
	  MenuLayoutCharacter(); break;
	case LFUN_LAYOUT_QUOTES:
	  MenuLayoutQuotes(); break;
	case LFUN_LAYOUT_PREAMBLE:
	  MenuLayoutPreamble(); break;
	
	case LFUN_DROP_LAYOUTS_CHOICE: toolbar.combox->Show(); break;

	case LFUN_EMPH:          EmphCB(ob, 0);       break;
	case LFUN_BOLD:          BoldCB(ob, 0);       break;
	case LFUN_NOUN:          NounCB(ob, 0);       break;
	case LFUN_CODE:		 CodeCB(ob, 0);	      break;
	case LFUN_SANS:		 SansCB(ob, 0);	      break;
	case LFUN_ROMAN:		 RomanCB(ob, 0);	      break;
	case LFUN_DEFAULT:	 StyleResetCB(ob, 0); break;
	case LFUN_UNDERLINE:	 UnderlineCB(ob, 0);  break;
		
	case LFUN_FONT_SIZE:
	{
		char* sizeVc[] = { "tiny", "small", "normal", "large",
				   "larger", "largest", "huge", "giant" };
		int ix;
		for ( ix = 0; ix < 8; ix++ )
			if ( !strcmp(argument, sizeVc[ix]) ) break;
		if ( ix == 8 ) ix = 2;
		FontSizeCB( ob, ix );
	}
	break;
	
	case LFUN_FONT_STATE:  FontStateShowCB(ob, 0); break;
		
	case LFUN_UPCASE_WORD:
		Update(-2);
		FreeUpdateTimer();
		bufferlist.current()->text->UpcaseWord();
	  	Update( 1 );
//		minibuffer.Set( "Upcase-word");
		SetUpdateTimer();
		break;
		
	case LFUN_LOWCASE_WORD:
		Update(-2);
		FreeUpdateTimer();
		bufferlist.current()->text->LowcaseWord();
	  	Update( 1 );
//		minibuffer.Set( "Lowcase-word");
		SetUpdateTimer();
		break;
		
	case LFUN_CAPITALIZE_WORD:
		Update(-2);
		FreeUpdateTimer();
		bufferlist.current()->text->CapitalizeWord();
	  	Update( 1 );
//		minibuffer.Set( "Capitalize-word");
		SetUpdateTimer();
		break;
		
	case LFUN_INSERT_LABEL:		  MenuInsertLabel();   break;
	case LFUN_INSERT_REF:		  MenuInsertRef();     break;
	case LFUN_MENU_OPEN_BY_NAME: MenuOpenByName( argument ); break; // RVDK_PATCH_5
	case LFUN_SPELLCHECK:        ShowSpellChecker();        break; // RVDK_PATCH_5

      // --- Cursor Movements ---------------------------------------------
	case LFUN_RIGHT:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorRight();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_LEFT:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorLeft();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_UP:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorUp();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_DOWN:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorDown();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_PRIOR:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		CursorPrevious();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_NEXT:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		CursorNext();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_HOME:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorHome();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_END:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorEnd();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_TAB:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorTab();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_WORDRIGHT:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorRightOneWord();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_WORDLEFT:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorLeftOneWord();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_BEGINNINGBUF:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorTop();
		MoveCursorUpdate(0);
		break;
		
	case LFUN_ENDBUF:
		if(!bufferlist.current()->text->mark_set) BeforeChange();
		Update(-2);
		bufferlist.current()->text->CursorBottom();
		MoveCursorUpdate(0);
		break;

      
		/* cursor selection ---------------------------- */
	case LFUN_RIGHTSEL:
		Update(-2);
		bufferlist.current()->text->CursorRight();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_LEFTSEL:
		Update(-2);
		bufferlist.current()->text->CursorLeft();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_UPSEL:
		Update(-2);
		bufferlist.current()->text->CursorUp();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_DOWNSEL:
		Update(-2);
		bufferlist.current()->text->CursorDown();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_PRIORSEL:
		Update(-2);
		CursorPrevious();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_NEXTSEL:
		Update(-2);
		CursorNext();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_HOMESEL:
		Update(-2);
		bufferlist.current()->text->CursorHome();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_ENDSEL:
		Update(-2);
		bufferlist.current()->text->CursorEnd();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_WORDRIGHTSEL:
		Update(-2);
		bufferlist.current()->text->CursorRightOneWord();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_WORDLEFTSEL:
		Update(-2);
		bufferlist.current()->text->CursorLeftOneWord();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_BEGINNINGBUFSEL:
		Update(-2);
		bufferlist.current()->text->CursorTop();
		MoveCursorUpdate(1);
		break;
		
	case LFUN_ENDBUFSEL:
		Update(-2);
		bufferlist.current()->text->CursorBottom();
		MoveCursorUpdate(1);
		break;

		// --- text changing commands --------------------------
	case LFUN_BREAKLINE:
		BeforeChange();
		bufferlist.current()->text->InsertChar(LYX_META_NEWLINE);
		SmallUpdate(1);
		SetUpdateTimer();
		break;
		
	case LFUN_PROTECTEDSPACE:
		BeforeChange();
		bufferlist.current()->text->
			InsertChar(LYX_META_PROTECTED_SEPARATOR);
		SmallUpdate(1);
		SetUpdateTimer();
		break;
		
	case LFUN_SETMARK:
		if(bufferlist.current()->text->mark_set)
		{
			BeforeChange();
			Update(0);
			minibuffer.Set("Mark removed");
		}
		else
		{
			BeforeChange();
			bufferlist.current()->text->mark_set = 1;
			Update(0);
			minibuffer.Set("Mark set");
		}
		bufferlist.current()->text->sel_cursor =
			bufferlist.current()->text->cursor;
		break;
		
	case LFUN_DELETE:
		FreeUpdateTimer();
		if (!bufferlist.current()->text->selection) {
			bufferlist.current()->text->Delete();
			bufferlist.current()->text->sel_cursor =
				bufferlist.current()->text->cursor;
			SmallUpdate(1);
		}
		else
		{
			bufferlist.current()->text->CutSelection();
			Update(1);
			minibuffer.Set("Cut");
		}
		SetUpdateTimer();
		break;

		/* -------> Delete word forward. */
	case LFUN_DELETE_WORD_FORWARD:
		Update(-2);
		FreeUpdateTimer();
		bufferlist.current()->text->DeleteWordForward();
		Update( 1 );
//		minibuffer.Set( "Delete-word-forward");
		SetUpdateTimer();
		break;

		/* -------> Delete word backward. */
	case LFUN_DELETE_WORD_BACKWARD:
		Update(-2);
		FreeUpdateTimer();
		bufferlist.current()->text->DeleteWordBackward();
		Update( 1 );
//		minibuffer.Set( "Delete-word-backward");
		SetUpdateTimer();
		break;

		/* -------> Kill to end of line. */
	case LFUN_DELETE_LINE_FORWARD:
		FreeUpdateTimer();
		Update(-2);
		bufferlist.current()->text->DeleteLineForward();
		Update( 1 );
		SetUpdateTimer();
//		minibuffer.Set( "Kill-line");
		break;

		/* -------> Set mark off. */
	case LFUN_MARK_OFF:
		BeforeChange();
		Update( 0 );
		bufferlist.current()->text->sel_cursor =
			bufferlist.current()->text->cursor;
		minibuffer.Set( "Mark off" );
		break;

		/* -------> Set mark on. */
	case LFUN_MARK_ON:
		BeforeChange();
		bufferlist.current()->text->mark_set = 1;
		Update( 0 );
		bufferlist.current()->text->sel_cursor =
			bufferlist.current()->text->cursor;
		minibuffer.Set( "Mark on");
		break;

	case LFUN_BACKSPACE:
		BeforeChange();
		bufferlist.current()->text->Backspace();
		SmallUpdate(1);
		SetUpdateTimer();
		bufferlist.current()->text->sel_cursor =
			bufferlist.current()->text->cursor;
		break;
		
	case LFUN_BREAKPARAGRAPH:
	{
		BeforeChange();
		bufferlist.current()->text->BreakParagraph(0);
		SmallUpdate(1);
		SetUpdateTimer();
		bufferlist.current()->text->sel_cursor =
			bufferlist.current()->text->cursor;
		break;
	}

	case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
	{
		BeforeChange();
		bufferlist.current()->text->BreakParagraph(1);
		SmallUpdate(1);
		SetUpdateTimer();
		bufferlist.current()->text->sel_cursor =
			bufferlist.current()->text->cursor;
		break;
	}
	
	case LFUN_QUOTE:
		BeforeChange();
		bufferlist.current()->text->InsertChar('\"');
		SmallUpdate(1);
		SetUpdateTimer();
		break;

		// --- lyxserver commands ------------------------------

	case LFUN_CHARATCURSOR:
	{
		int pos;
		char chr;
		pos = bufferlist.current()->text->cursor.pos;
		if(pos < bufferlist.current()->text->cursor.par->last)
			chr = bufferlist.current()->text->
				cursor.par->text[pos];
		else
			chr = '\0';
		if(chr)
		{
			dispatch_buffer[0] = chr;
			dispatch_buffer[1] = '\0';
		}
		else
		{
			dispatch_buffer[0] = 'E';
			dispatch_buffer[1] = 'O';
			dispatch_buffer[2] = 'F';
			dispatch_buffer[3] = '\0';
		}
		dispatch_result = dispatch_buffer;
	}
	break;
	
	case LFUN_GETXY:
		sprintf(dispatch_buffer, "%d %ld",
			bufferlist.current()->text->cursor.x,
			bufferlist.current()->text->cursor.y);
		dispatch_result = dispatch_buffer;
		break;
		
	case LFUN_SETXY:
	{
		int  x;
		long y;
		sscanf(argument, " %d %ld", &x, &y);
		bufferlist.current()->text->SetCursorFromCoordinates(x, y);
	}
	break;
	
	case LFUN_GETLAYOUT:
		sprintf(dispatch_buffer, "%d",
			(int)bufferlist.current()->text->cursor.par->layout);
		dispatch_result = dispatch_buffer;
		break;
	case LFUN_GETFONT:
	{
		LyXFont *font = &(bufferlist.current()->text->current_font);
		if(font->shape == LYX_ITALIC_SHAPE)
			dispatch_buffer[0] = 'E';
		else if(font->shape == LYX_SMALLCAPS_SHAPE)
			dispatch_buffer[0] = 'N';
		else
			dispatch_buffer[0] = '0';
		dispatch_buffer[1] = '\0';
		dispatch_result = dispatch_buffer;
	}
	break;
	
	case LFUN_GETLATEX:
	{
		LyXFont *font = &(bufferlist.current()->text->current_font);
		if(font->latex == LYX_LATEX)
			dispatch_buffer[0] = 'L';
		else if(font->latex == LYX_FORMULA_LATEX)
			dispatch_buffer[0] = 'F';
		else
			dispatch_buffer[0] = '0';
		dispatch_buffer[1] = '\0';
		dispatch_result = dispatch_buffer;
	}
	break;
	
	case LFUN_GETNAME:
		dispatch_result = bufferlist.current()->filename;
		break;
		
	case LFUN_NOTIFY:
		keyseq.print(dispatch_buffer,100);
		LyxNotifyClient(dispatch_buffer);
		break;

		// --- accented characters ------------------------------

	case LFUN_UMLAUT:
	case LFUN_CIRCUMFLEX:
	case LFUN_GRAVE:
	case LFUN_ACUTE:
	case LFUN_TILDE:
	case LFUN_CEDILLA:
	case LFUN_MACRON:
	case LFUN_DOT:
	case LFUN_UNDERDOT:
	case LFUN_UNDERBAR:
	case LFUN_CARON:
	case LFUN_SPECIAL_CARON:
	case LFUN_BREVE:
	case LFUN_TIE:
	case LFUN_HUNG_UMLAUT:
	case LFUN_CIRCLE:
		if (lyx_calling_dead_action == LFUN_NOACTION){
			// a dead key was pressed, just remember
			// it for the next char inserted.
			lyx_calling_dead_action = (kb_action)action;
			lyx_dead_action = (kb_action)action;
			break;
		}
		do_accent_char(get_accent((kb_action)action),
			       num_bytes, tmp_action);
		break;

		// --- toolbar ----------------------------------
	case LFUN_PUSH_TOOLBAR:
	{
		int nth = atoi(argument);
		if (lyx_debug_level & DEBUG_TOOLBAR) {
			fprintf(stderr,"LFUN_PUSH_TOOLBAR: argument = `%s'\n",
				argument);
			fprintf(stderr,"LFUN_PUSH_TOOLBAR: nth = ´%d'\n",
				nth);
		}
		
		if (nth <= 0) {
			LyXBell();
			minibuffer.Set("Push-toolbar needs argument <0\n");
		} else {
			toolbar.push(nth);
		}
	}
	break;
	
	case LFUN_ADD_TO_TOOLBAR:
	{
		if (lyx_debug_level & DEBUG_TOOLBAR) {
			fprintf(stderr,
				"LFUN_ADD_TO_TOOLBAR: argument = `%s'\n",
				argument);
		}
		toolbar.add(argument, false);
		toolbar.set();
	}
	break;
	
	   // --- insert characters ----------------------------------------

	case LFUN_INSERT_INSET_LATEX:
	{
		Inset *new_inset = new InsetLatex(argument);
		BeforeChange();
		bufferlist.current()->text->InsertInset(new_inset);
		Update(1);
	}
	break;

	case LFUN_INSERT_INSET_LATEX_DEL:
	{
		Inset *new_inset = new InsetLatexDel(argument);
		BeforeChange();
		bufferlist.current()->text->InsertInset(new_inset);
		Update(1);
	}
	break;
	
	   
	// ---  Mathed stuff. If we are here, there is no locked inset yet.
	      
        // Greek mode     
        case LFUN_GREEK:
        {
	   if (!greek_kb_flag) {
	      greek_kb_flag = 1;
	      minibuffer.Set("Math greek mode on");
	   } else
	     greek_kb_flag = 0;
	   break;
	}  
      
	// Greek keyboard      
        case LFUN_GREEK_TOGGLE:
        {
	   greek_kb_flag = (greek_kb_flag) ? 0: 2;
	   if (greek_kb_flag)
	     minibuffer.Set("Math greek keyboard on");
	   else
	     minibuffer.Set("Math greek keyboard off");
	   break;
	}
	
	case LFUN_MATH_DELIM:     
	case LFUN_INSERT_MATRIX:
	{ 	   
	        if (bufferlist.current()->text) { 
		   bufferlist.open_new_inset(new InsetFormula(false));
		   bufferlist.current()->the_locking_inset->LocalDispatch(action, argument);
		}
		break;
	}	   
	       
	case LFUN_INSERT_MATH:
	{
		math_insert_symbol(argument);
		break;
	}
	
	case LFUN_MATH_DISPLAY:
	{
	        if (bufferlist.current()->text) 
		   bufferlist.open_new_inset(new InsetFormula(true));
		break;
	}
	
	   
	case LFUN_MATH_MODE:   // Open or create a math inset
	{
	        if (OpenMathInset()) 
	            minibuffer.Set("Math editor mode");	
	        else
	            fprintf(stderr, "Couldn't open a math inset\n");
		break;
	}
	  
	case LFUN_MATH_NUMBER:
	case LFUN_MATH_LIMITS:
	{   
	        minibuffer.Set("This is only allowed in math mode");	
	        break;
	}
	    
	   
	// --- Obsolete formula stuff. Should be removed   
	   
	case LFUN_INSERT_INSET_FORMULA_LATEX:
	{
		Inset *new_inset = new InsetFormulaLatex(argument);
		BeforeChange();
		bufferlist.current()->text->InsertInset(new_inset);
		Update(1);
	}
	break;

	case LFUN_INSERT_INSET_FORMULA_LATEX_DEL:
	{
		Inset *new_inset = new InsetFormulaLatexDel(argument);
		BeforeChange();
		bufferlist.current()->text->InsertInset(new_inset);
		Update(1);
	}
	break;

	case LFUN_INSERT_NOTE: NoteCB(); break;

	case LFUN_KMAP_OFF:		// keymap off
		KeyMapOn(false);
		break;
		
	case LFUN_KMAP_PRIM:	// primary keymap
		KeyMapPrim();
		break;
		
	case LFUN_KMAP_SEC:		// secondary keymap
		KeyMapSec();
		break;
		
	case LFUN_KMAP_TOGGLE:	// toggle keymap
		ToggleKeyMap();
		break;

	case LFUN_SELFINSERT:
		if (num_bytes == 1) {
			bufferlist.current()->text->InsertChar((int)s_r[0]);
			SmallUpdate(1);
			SetUpdateTimer();
			bufferlist.current()->text->sel_cursor =
				bufferlist.current()->text->cursor;
		} else {
			char buf[100];
			LyXBell();
			keyseq.print(buf,100);
			minibuffer.Set("Command cannot be self-inserted:",buf);
		}
		break;

	default:
	{
		if(action==-1 && keyseq.length<-1) // unknown key sequence...
		{
			char buf[100];
			LyXBell();
			keyseq.print(buf,100);
			minibuffer.Set("Unknown command:",buf);
			break;
		}
		static char isochar;
		isochar = keyseq.getiso(); // now we call getiso only once
		if(argument ||
		   (!(keyevent->state&ControlMask) &&
		    !(keyevent->state&Mod1Mask) &&
		    (isochar && keysym_return < 0xF000))){
			
			/* Automatically delete the currently selected text
			 * and replace it with what is being typed in now.
			 * Depends on lyxrc settings "auto_region_delete",
			 * which defaults to true (on). */
			
			//extern LyXRC lyxrc;
			if ( lyxrc.auto_region_delete ) {
				if (bufferlist.current()->text->selection){
					bufferlist.current()->text->CutSelection();
					Update(-1);
				}
			}
			
			BeforeChange();
			if(argument) {
				char *p;
				for(p = argument; *p; p++) {
					/* the quotes */ 
					TranslateAndInsert(*p, bufferlist.current()->text);
				}
			} else {
				if (greek_kb_flag) {
					if (!math_insert_greek(isochar))
						TranslateAndInsert(isochar, bufferlist.current()->text);
				} else
					TranslateAndInsert(isochar, bufferlist.current()->text);
			}
			
			SmallUpdate(1);
			SetUpdateTimer();
			
			bufferlist.current()->text->sel_cursor =
				bufferlist.current()->text->cursor;
			return 0;
		}
		
	}
		break;
	}
   
	return 0;
}


static
inline
tex_accent_struct get_accent(kb_action action)
{
        int i=0;
        while (i<=TEX_MAX_ACCENT){
                if (lyx_accent_table[i].action == action)
                        return lyx_accent_table[i];
                i++;
        }
        struct tex_accent_struct temp = { (tex_accent)0, NULL, NULL,
					  NULL,(kb_action)0};
	return temp;
}


static
void do_accent_char(tex_accent_struct taccent, int num_bytes,
		    kb_action tmp_action)
{
	// this function is called when you try to insert an accented
	// char through the dead key mecanism.
	char *cmd = taccent.cmd;
	int i;
	
        char tbuf[10];
	
        KeySym tmp = keyseq.getsym();
        if (lyx_calling_dead_action && 
            tmp_action == lyx_calling_dead_action)
                tmp = XK_space;
        lyx_calling_dead_action = LFUN_NOACTION;
	
        if (num_bytes!=1) return; // only single chars are valid
	
	// First: check if we should print this character at all
	if (!bufferlist.current()->allowAccents &&
	    strchr(taccent.native,tmp) == NULL)
	{
		LyXBell();
		return;
	}
	
	// now build the tex command for this accented char
	if (tmp=='i' || tmp=='j')
		// remember to remove the dot above `i' and `j'
		sprintf(tbuf,"%s\\%c ",cmd,(char)tmp);
	else
		sprintf(tbuf,"%s%c",cmd,(char)tmp);

	// we use the character encoding map
	// from intl.C
	for (i=255; i >=0; i--)
		if (cdefmap[i]) {
			if (strcmp(cdefmap[i], tbuf) == 0) break;
		}
	
	if (i > 0){
		TranslateAndInsert((char)i, bufferlist.current()->text);
	} else {
		// the current font did not contain this char
		// We must draw it using an inset.
		Inset *new_inset = new InsetLatexAccent(tbuf);
		bufferlist.current()->text->InsertInset(new_inset);
		
	}
	SmallUpdate(1);
	SetUpdateTimer();
	bufferlist.current()->text->sel_cursor = 
                bufferlist.current()->text->cursor;
}


/* ---F+------------------------------------------------------------------ *\
    Function  : LyxDefaultKeyBindings
    Called by : init()
    Purpose   : define the default key bindings for LyX
    Parameters: none
    Returns   : nothing
\* ---F------------------------------------------------------------------- */
void LyxDefaultKeyBindings()
{
   toplevel_keymap = new kb_keymap;
   kb_keymap *m = toplevel_keymap;

   //   m->bind("C-u", LFUN_UNIVERSAL_ARGUMENT);
   //   m->bind("C-z", LFUN_ICONIFY_OR_DEICONIFY);

   m->bind("Right",   LFUN_RIGHT);
   m->bind("Left",    LFUN_LEFT);
   m->bind("Up",      LFUN_UP);
   m->bind("Down",    LFUN_DOWN);

   m->bind("Tab",  LFUN_TAB);

   m->bind("Home",    LFUN_HOME);
   m->bind("End",     LFUN_END);
   m->bind("Prior",   LFUN_PRIOR);
   m->bind("Next",    LFUN_NEXT);

   m->bind("Return",  LFUN_BREAKPARAGRAPH);

   m->bind("Delete",  LFUN_DELETE);
   m->bind("BackSpace",    LFUN_BACKSPACE);

   // m->bindings for transparent handling of deadkeys
   m->bind("~C-~S-~M-~W-dead_acute",           LFUN_ACUTE);
   m->bind("~C-~S-~M-~W-dead_breve",           LFUN_BREVE);
   m->bind("~C-~S-~M-~W-dead_caron",           LFUN_CARON);
   m->bind("~C-~S-~M-~W-dead_cedilla",         LFUN_CEDILLA);
   m->bind("~C-~S-~M-~W-dead_circle",          LFUN_CIRCLE);
   m->bind("~C-~S-~M-~W-dead_circumflex",      LFUN_CIRCUMFLEX);
   m->bind("~C-~S-~M-~W-dead_dot",             LFUN_DOT);
   m->bind("~C-~S-~M-~W-dead_grave",           LFUN_GRAVE);
   m->bind("~C-~S-~M-~W-dead_doubleacute",     LFUN_HUNG_UMLAUT);
   m->bind("~C-~S-~M-~W-dead_macron",          LFUN_MACRON);
   m->bind("~C-~S-~M-~W-dead_special_caron",   LFUN_SPECIAL_CARON);
   m->bind("~C-~S-~M-~W-dead_tilde",           LFUN_TILDE);
   m->bind("~C-~S-~M-~W-dead_diaeresis",       LFUN_UMLAUT);
   m->bind("~C-~S-~M-~W-dead_underbar",        LFUN_UNDERBAR);
   m->bind("~C-~S-~M-~W-dead_underdot",        LFUN_UNDERDOT);
   m->bind("~C-~S-~M-~W-dead_tie",             LFUN_TIE);

   // bindings to utilize the use of the numeric keypad
   // e.g. Num Lock set
   m->bind("KP_0",        LFUN_SELFINSERT);
   m->bind("KP_Decimal",  LFUN_SELFINSERT);
   m->bind("KP_Enter",    LFUN_SELFINSERT);
   m->bind("KP_1",        LFUN_SELFINSERT);
   m->bind("KP_2",        LFUN_SELFINSERT);
   m->bind("KP_3",        LFUN_SELFINSERT);
   m->bind("KP_4",        LFUN_SELFINSERT);
   m->bind("KP_5",        LFUN_SELFINSERT);
   m->bind("KP_6",        LFUN_SELFINSERT);
   m->bind("KP_Add",      LFUN_SELFINSERT);
   m->bind("KP_7",        LFUN_SELFINSERT);
   m->bind("KP_8",        LFUN_SELFINSERT);
   m->bind("KP_9",        LFUN_SELFINSERT);
   m->bind("KP_Divide",   LFUN_SELFINSERT);
   m->bind("KP_Multiply", LFUN_SELFINSERT);
   m->bind("KP_Subtract", LFUN_SELFINSERT);

   /* Most self-insert keys are handled in the 'default:' section of
    * WorkAreaKeyPress - so we don't have to define them all.
    * However keys explicit decleared as self-insert are
    * handled seperatly (LFUN_SELFINSERT.) Lgb. */

   keyseq.stdmap = keyseq.curmap = toplevel_keymap;
   cancel_meta_seq.stdmap = cancel_meta_seq.curmap = toplevel_keymap; // RVDK_PATCH_5
}


/* === End of File: keybind.C ============================================ */
