1
0
mirror of https://github.com/rfivet/uemacs.git synced 2024-06-03 02:50:42 +00:00

Manage key binding table dynamically.

Avoid deleting or binding to active prefix keys.
This commit is contained in:
Renaud 2021-07-24 16:34:54 +08:00
parent ba1bfcd0db
commit 735aefc166
4 changed files with 146 additions and 119 deletions

123
bind.c
View File

@ -36,7 +36,6 @@ static int buildlist( char *mstring) ;
static void cmdstr( int c, char *seq) ; static void cmdstr( int c, char *seq) ;
static unsigned int getckey( int mflag) ; static unsigned int getckey( int mflag) ;
static unsigned int stock( char *keyname) ; static unsigned int stock( char *keyname) ;
static boolean unbindchar( unsigned c) ;
static const char *getfname( unsigned keycode, char *failmsg) ; static const char *getfname( unsigned keycode, char *failmsg) ;
@ -123,7 +122,7 @@ BINDABLE( bindtokey) {
/* get the command sequence to bind */ /* get the command sequence to bind */
boolean prefix_f = (kfunc == metafn) || (kfunc == cex) || boolean prefix_f = (kfunc == metafn) || (kfunc == cex) ||
(kfunc == unarg) || (kfunc == ctrlg) ; (kfunc == unarg) || (kfunc == ctrlg) ;
unsigned c = getckey( prefix_f) ; int c = getckey( prefix_f) ;
/* change it to something we can print as well */ /* change it to something we can print as well */
cmdstr( c, outseq) ; cmdstr( c, outseq) ;
@ -131,12 +130,26 @@ BINDABLE( bindtokey) {
/* and dump it out */ /* and dump it out */
ostring( outseq) ; ostring( outseq) ;
/* key sequence can't be an active prefix key */
if( c == metac || c == ctlxc || c == reptc || c == abortc) {
if( (c == metac && kfunc == metafn)
|| (c == ctlxc && kfunc == cex)
|| (c == reptc && kfunc == unarg)
|| (c == abortc && kfunc == ctrlg))
return TRUE ;
mlwrite( "(Can't bind to active prefix)") ;
return FALSE ;
}
/* if the function is a prefix key */ /* if the function is a prefix key */
if( prefix_f) { if( prefix_f) {
/* search and remove all existing binding for the prefix */ /* remove existing binding for the prefix */
for( ktp = keytab ; ktp->k_code != 0 ; ktp++) for( ktp = keytab ; ktp->k_code != 0 ; ktp++)
if( ktp->k_nbp == nbp) if( ktp->k_nbp == nbp) {
unbindchar( ktp->k_code) ; delkeybinding( ktp->k_code) ;
break ;
}
/* set the appropriate global prefix variable */ /* set the appropriate global prefix variable */
if( kfunc == metafn) if( kfunc == metafn)
@ -149,29 +162,13 @@ BINDABLE( bindtokey) {
abortc = c ; abortc = c ;
} }
/* search the table to see if it exists */ ktp = setkeybinding( c, nbp) ;
for( ktp = keytab ; ktp->k_code != 0 ; ktp++) { if( ktp->k_code == 0) {
if( ktp->k_code == c) {
/* it exists, just change it then */
ktp->k_nbp = nbp ;
return TRUE ;
}
}
/* otherwise we need to add it to the end */
/* if we run out of binding room, bitch */
if( ktp >= &keytab[ NBINDS]) {
mlwrite( "Binding table FULL!") ; mlwrite( "Binding table FULL!") ;
return FALSE ; return FALSE ;
} }
ktp->k_code = c; /* add keycode */ return TRUE ;
ktp->k_nbp = nbp ;
++ktp; /* and make sure the next is null */
ktp->k_code = 0;
ktp->k_nbp = NULL ;
return TRUE;
} }
/* /*
@ -180,60 +177,34 @@ BINDABLE( bindtokey) {
* *
* int f, n; command arguments [IGNORED] * int f, n; command arguments [IGNORED]
*/ */
int unbindkey(int f, int n) BINDABLE( unbindkey) {
{ char outseq[ 80] ; /* output buffer for keystroke sequence */
int c; /* command key to unbind */
char outseq[80]; /* output buffer for keystroke sequence */
/* prompt the user to type in a key to unbind */ /* prompt the user to type in a key to unbind */
mlwrite("unbind-key: "); mlwrite( "unbind-key: ") ;
/* get the command sequence to unbind */ /* get the command sequence to unbind */
c = getckey(FALSE); /* get a command sequence */ int c = getckey( FALSE) ; /* get a command sequence */
/* change it to something we can print as well */ /* change it to something we can print as well */
cmdstr(c, &outseq[0]); cmdstr( c, outseq) ;
/* and dump it out */ /* and dump it out */
ostring(outseq); ostring( outseq) ;
/* if it isn't bound, bitch */
if (unbindchar(c) == FALSE) {
mlwrite("(Key not bound)");
return FALSE;
}
return TRUE;
}
/*
* unbindchar()
*
* int c; command key to unbind
*/
static boolean unbindchar( unsigned c) {
key_tab *ktp ; /* pointer into the command table */
/* search the table to see if the key exists */
for( ktp = keytab ; ktp->k_code != 0 ; ktp++) {
if (ktp->k_code == c) {
/* save the pointer and scan to the end of the table */
key_tab *sav_ktp = ktp ;
while( (++ktp)->k_code != 0) ;
ktp -= 1 ; /* backup to the last legit entry */
/* copy the last entry to the current one */
sav_ktp->k_code = ktp->k_code ;
sav_ktp->k_nbp = ktp->k_nbp ;
/* null out the last one */
ktp->k_code = 0 ;
ktp->k_nbp = NULL ;
return TRUE ;
}
}
/* prefix key sequence can't be undound, just redefined */
if( c == reptc || c == abortc) {
mlwrite( "(Can't unbind prefix)") ;
return FALSE ; return FALSE ;
}
/* if it isn't bound, bitch */
if( delkeybinding( c) == FALSE) {
mlwrite( "(Key not bound)") ;
return FALSE ;
}
return TRUE ;
} }
#if APROP #if APROP
@ -452,8 +423,10 @@ static void cmdstr( int c, char *seq) {
/* apply ^X sequence if needed */ /* apply ^X sequence if needed */
if (c & CTLX) { if (c & CTLX) {
*ptr++ = '^'; if( ctlxc & CONTROL)
*ptr++ = 'X'; *ptr++ = '^' ;
*ptr++ = ctlxc & 0x1FFFFF ;
} }
/* apply SPEC sequence if needed */ /* apply SPEC sequence if needed */
@ -469,7 +442,7 @@ static void cmdstr( int c, char *seq) {
/* and output the final sequence */ /* and output the final sequence */
*ptr++ = c & 255; /* strip the prefixes */ *ptr++ = c & 0x1FFFFF ; /* strip the prefixes */
*ptr = 0; /* terminate the string */ *ptr = 0; /* terminate the string */
} }

5
main.c
View File

@ -165,7 +165,10 @@ int main(int argc, char **argv)
} }
/* Initialize the editor. */ /* Initialize the editor. */
init_bindings() ; /* initialize mapping of function to name and key */ if( !init_bindings()) { /* initialize mapping of function to name and key */
return( EXIT_FAILURE) ;
}
vtinit(); /* Display */ vtinit(); /* Display */
mloutfmt = mlwrite ; mloutfmt = mlwrite ;
edinit("main"); /* Buffers, windows */ edinit("main"); /* Buffers, windows */

117
names.c
View File

@ -1,8 +1,6 @@
/* names.c -- implements names.h */ /* names.c -- implements names.h */
#include "names.h" #include "names.h"
#define PARANOID 1
/* Name to function binding table. /* Name to function binding table.
* *
* This table gives the names of all the bindable functions and their C * This table gives the names of all the bindable functions and their C
@ -10,9 +8,8 @@
* command line parsing. * command line parsing.
*/ */
#ifdef PARANOID
#include <assert.h> #include <assert.h>
#endif #include <stdlib.h>
#include <string.h> #include <string.h>
#include "basic.h" #include "basic.h"
@ -216,7 +213,7 @@ const name_bind names[] = {
{" set", setvar, CTLX | 'A'} , {" set", setvar, CTLX | 'A'} ,
{" set-fill-column", setfillcol, CTLX | 'F'} , {" set-fill-column", setfillcol, CTLX | 'F'} ,
{" set-mark", (fnp_t) setmark, META | ' '} , /* M. */ {" set-mark", (fnp_t) setmark, META | ' '} , /* M. */
{" shell-command", spawn, CTLX | '?'} , {" shell-command", spawn, CTLX | '!'} ,
{" shrink-window", shrinkwind, CTLX | CTL_ | 'Z'} , {" shrink-window", shrinkwind, CTLX | CTL_ | 'Z'} ,
{" split-current-window", splitwind, CTLX | '2'} , {" split-current-window", splitwind, CTLX | '2'} ,
{" store-macro", storemac, 0} , {" store-macro", storemac, 0} ,
@ -275,77 +272,129 @@ const name_bind names[] = {
{ NULL, NULL, 0} { NULL, NULL, 0}
} ; } ;
static int lastidx = 0 ; static int lastnmidx = 0 ; /* index of last name entry */
key_tab keytab[ NBINDS] = {
{0, NULL}
} ;
void init_bindings( void) { key_tab *keytab ;
static int ktsize = 140 ; /* last check: need at least 133 + 1 */
boolean init_bindings( void) {
/* allocate table */
keytab = malloc( ktsize * sizeof *keytab) ;
if( keytab == NULL)
return FALSE ;
/* insert end of table mark */
keytab->k_code = 0 ;
keytab->k_nbp = NULL ;
/* Add default key bindings */ /* Add default key bindings */
key_tab *ktp = keytab ;
const name_bind *nbp ; const name_bind *nbp ;
for( nbp = names ; nbp->n_func != NULL ; nbp++) { for( nbp = names ; nbp->n_func != NULL ; nbp++) {
#ifdef PARANOID
/* Check entries and strict order */ /* Check entries and strict order */
assert( (nbp->n_name != NULL) && assert( (nbp->n_name != NULL) &&
((nbp == names) || ((nbp == names) ||
(0 > strcmp( bind_name( nbp - 1), bind_name( nbp))) (0 > strcmp( bind_name( nbp - 1), bind_name( nbp)))
) )
) ; ) ;
#endif
/* Add key definition */ /* Add key definition */
if( nbp->n_keycode) { if( nbp->n_keycode) {
ktp->k_code = nbp->n_keycode ; key_tab *ktp = setkeybinding( nbp->n_keycode, nbp) ;
ktp->k_nbp = nbp ; /* check it was indeed an insertion at end of table not a
ktp += 1 ; * key code re-definition */
assert( (++ktp)->k_code == 0) ;
} }
} }
/* memorize position after last valid function entry */ /* memorize position after last valid function entry */
lastidx = nbp - names ; lastnmidx = nbp - names ;
/* Process extra key bindings if any */ /* Process extra key bindings if any */
for( nbp++ ; nbp->n_func != NULL ; nbp++) { for( nbp++ ; nbp->n_func != NULL ; nbp++) {
#ifdef PARANOID
/* Check entry */ /* Check entry */
assert( nbp->n_keycode && (nbp->n_name == NULL)) ; assert( nbp->n_keycode && (nbp->n_name == NULL)) ;
#endif
/* Look for corresponding function and add extra key binding */ /* Look for corresponding function and add extra key binding */
const name_bind *fnbp ; const name_bind *fnbp ;
for( fnbp = names ; fnbp->n_func != NULL ; fnbp++) for( fnbp = names ; fnbp->n_func != NULL ; fnbp++)
if( fnbp->n_func == nbp->n_func) { if( fnbp->n_func == nbp->n_func) {
ktp->k_code = nbp->n_keycode ; setkeybinding( nbp->n_keycode, fnbp) ;
ktp->k_nbp = fnbp ;
ktp += 1 ;
break ; break ;
} }
#ifdef PARANOID /* Insure there is a name entry for the keycode */
/* Insure there is a name entry for the keycode and no double keycode */
assert( fnbp->n_func != NULL) ; assert( fnbp->n_func != NULL) ;
int kcnt = 0 ;
for( key_tab *kktp = keytab ; kktp < ktp ; kktp++)
if( kktp->k_code == (ktp - 1)->k_code)
kcnt += 1 ;
assert( kcnt == 1) ;
#endif
} }
/* Mark position after last valid key entry */ return TRUE ;
}
key_tab *setkeybinding( unsigned key, const name_bind *nbp) {
key_tab *ktp ;
/* search the table to see if it exists */
for( ktp = keytab ; ktp->k_code != 0 ; ktp++)
if( ktp->k_code == key) {
/* it exists, just change it then */
ktp->k_nbp = nbp ;
return ktp ;
}
/* otherwise we need to add it to the end */
/* check if the end marker is at the end of the table */
if( ktp == &keytab[ ktsize - 1]) {
/* out of binding room */
int newsize = ktsize + 10 ;
key_tab *newkeytab = realloc( keytab, newsize * sizeof *keytab) ;
if( newkeytab == NULL)
/* out of space */
return ktp ;
keytab = newkeytab ;
ktp = &keytab[ ktsize - 1] ;
ktsize = newsize ;
}
ktp->k_code = key ; /* add keycode */
ktp->k_nbp = nbp ;
++ktp ; /* and make sure the next is null */
ktp->k_code = 0 ; ktp->k_code = 0 ;
ktp->k_nbp = NULL ; ktp->k_nbp = NULL ;
return ktp - 1 ;
}
boolean delkeybinding( unsigned key) {
key_tab *ktp ; /* pointer into the key binding table */
/* search the table to see if the key exists */
for( ktp = keytab ; ktp->k_code != 0 ; ktp++) {
if( ktp->k_code == key) {
/* save the pointer and scan to the end of the table */
key_tab *sav_ktp = ktp ;
while( (++ktp)->k_code != 0) ;
ktp -= 1 ; /* backup to the last legit entry */
/* copy the last entry to the current one */
sav_ktp->k_code = ktp->k_code ;
sav_ktp->k_nbp = ktp->k_nbp ;
/* null out the last one */
ktp->k_code = 0 ;
ktp->k_nbp = NULL ;
return TRUE ;
}
}
return FALSE ;
} }
#define BINARY 1 #define BINARY 1
const name_bind *fncmatch( char *name) { const name_bind *fncmatch( char *name) {
#ifdef BINARY #ifdef BINARY
int found = lastidx ; int found = lastnmidx ;
int low = 0 ; int low = 0 ;
int high = found - 1 ; int high = found - 1 ;
do { do {

12
names.h
View File

@ -3,6 +3,9 @@
#ifndef _NAMES_H_ #ifndef _NAMES_H_
#define _NAMES_H_ #define _NAMES_H_
#include "retcode.h"
/* Bindable uEMACS function pointer type and definition template */ /* Bindable uEMACS function pointer type and definition template */
#define BINDABLE( fname) int fname( int f, int n) #define BINDABLE( fname) int fname( int f, int n)
@ -27,13 +30,12 @@ typedef struct {
extern const name_bind names[] ; /* name to function mapping table */ extern const name_bind names[] ; /* name to function mapping table */
extern key_tab *keytab ; /* key bind to functions table */
/* keycode to function mapping table */
#define NBINDS 256 /* max # of bound keys */
extern key_tab keytab[ NBINDS] ; /* key bind to functions table */
void init_bindings( void) ; boolean init_bindings( void) ;
key_tab *setkeybinding( unsigned key, const name_bind *nbp) ;
boolean delkeybinding( unsigned key) ;
const name_bind *fncmatch( char *name) ; /* look up by name */ const name_bind *fncmatch( char *name) ; /* look up by name */
/* bindable functions mapped to prefix keys and hooks */ /* bindable functions mapped to prefix keys and hooks */