home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bbs
/
may94
/
util
/
edit
/
jade.lha
/
Jade
/
src
/
keys.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-19
|
11KB
|
507 lines
/* keys.c -- Key binding and evaluating
Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
This file is part of Jade.
Jade 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.
Jade 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 Jade; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "jade.h"
#include "jade_protos.h"
#include <string.h>
_PR VALUE usekey(void *, Event *, bool);
_PR void keymap_sweep(void);
_PR void keymap_prin(VALUE, VALUE);
_PR void keys_init(void);
_PR void keys_kill(void);
_PR Event *CurrentEvent;
Event *CurrentEvent;
Keytab *KeytabChain;
Keylist *KeylistChain;
static VALUE sym_keymap_path, sym_unbound_key_hook, NextKeymapPath;
/*
::doc:keymap_path::
A list of keymaps (ie, keylists and/or keytables). When an event occurs
each keymap in the list is searched for an event binding which matches
it. These bindings are installed in a keymap by the function `bind-keys'.
See also `next-keymap-path'.
::end::
::doc:unbound_key_hook::
When no event binding can be found for an event this hook is evaluated in
the standard manner (see the function `eval-hook' for details).
::end::
*/
static Key *
findkey(VALUE v, EventDef *evd)
{
Key *nxt, *k = NULL;
switch(VTYPE(v))
{
case V_Keytab:
k = VKEYTAB(v)->kt_Keys[evd->evd_Code & EV_HASH_MASK];
while(k)
{
if((k->ky_Event.evd_Type == evd->evd_Type)
&& (k->ky_Event.evd_Mods == evd->evd_Mods)
&& (k->ky_Event.evd_Code == evd->evd_Code))
break;
k = k->ky_Link.next;
}
break;
case V_Keylist:
k = (Key *)VKEYLIST(v)->kl_List.mlh_Head;
while((nxt = (Key *)k->ky_Link.node.mln_Succ))
{
if((k->ky_Event.evd_Type == evd->evd_Type)
&& (k->ky_Event.evd_Mods == evd->evd_Mods)
&& (k->ky_Event.evd_Code == evd->evd_Code))
break;
k = nxt;
}
if(!k->ky_Link.node.mln_Succ)
k = NULL;
break;
}
return(k);
}
static VALUE
evalbinding(EventDef *evd)
{
VALUE kp;
if(!NILP(NextKeymapPath))
{
kp = NextKeymapPath;
NextKeymapPath = sym_nil;
}
else
{
if(!(kp = cmd_symbol_value(sym_keymap_path)))
return(NULL);
}
while(CONSP(kp))
{
VALUE thispath = VCAR(kp);
Key *k;
switch(VTYPE(thispath))
{
case V_Symbol:
if(!(thispath = cmd_symbol_value(thispath))
|| (!KEYTABP(thispath) && !KEYLISTP(thispath)))
break;
/* FALL THROUGH */
case V_Keytab:
case V_Keylist:
k = findkey(thispath, evd);
if(k)
return(k->ky_Form);
break;
}
kp = VCDR(kp);
}
return(NULL);
}
/*
* `OSInputMsg' is the raw input event from the window-system, this is
* only used to cook a string from.
* `ev' is the translation of `OSInputMsg'.
*/
VALUE
usekey(void *OSInputMsg, Event *ev, bool cursState)
{
VALUE cmd, result = sym_nil;
VW *vw = CurrVW;
bool inmulti = !NILP(NextKeymapPath);
CurrentEvent = ev;
resettitle(vw);
cmd = evalbinding(&ev->ev_EventDef);
if(cmd)
{
if(cursState)
{
cursor(vw, CURS_OFF);
cursState = FALSE;
}
switch(VTYPE(cmd))
{
case V_Symbol:
result = funcall(cmd, sym_nil);
break;
case V_Cons:
if(VCAR(cmd) == sym_lambda)
{
result = funcall(cmd, sym_nil);
break;
}
/* FALL THROUGH */
default:
result = cmd_eval(cmd);
}
}
else if(inmulti)
beep(vw);
else if(ev->ev_EventDef.evd_Type == EV_TYPE_KEYBD)
{
u_char buff[256];
int len;
if((len = cookkey(OSInputMsg, buff, 256 - 1)) > 0)
{
if(cursState)
{
cursor(vw, CURS_OFF);
cursState = FALSE;
}
buff[len] = 0;
if((!(result = cmd_eval_hook2(sym_unbound_key_hook, sym_nil)))
|| NILP(result))
{
if(!readonly(vw->vw_Tx) && padcursor(vw))
{
POS start, tmp;
start = tmp = vw->vw_CursorPos;
insertstrn(vw->vw_Tx, buff, len, &tmp);
flaginsertion(vw->vw_Tx, &start, &vw->vw_CursorPos);
result = sym_t;
}
else
result = NULL;
}
}
else if(len < 0)
settitle("error: key translation screwup");
}
CurrentEvent = NULL;
if(CurrVW)
{
refreshworld();
if(!cursState)
cursor(CurrVW, CURS_ON);
}
return(result);
}
void
keymap_sweep(void)
{
Keytab *kt = KeytabChain;
Keylist *kl = KeylistChain;
KeytabChain = NULL;
KeylistChain = NULL;
while(kt)
{
Keytab *nxtkt = kt->kt_Next;
if(!GC_MARKEDP(kt))
{
int i;
for(i = 0; i < 128; i++)
{
Key *this = kt->kt_Keys[i];
while(this)
{
Key *nxt = this->ky_Link.next;
mystrfree(this);
this = nxt;
}
}
myfree(kt);
}
else
{
GC_CLR(kt);
kt->kt_Next = KeytabChain;
KeytabChain = kt;
}
kt = nxtkt;
}
while(kl)
{
Keylist *nxtkl = kl->kl_Next;
if(!GC_MARKEDP(kl))
{
Key *this, *next;
this = (Key *)kl->kl_List.mlh_Head;
while((next = (Key *)this->ky_Link.node.mln_Succ))
{
mystrfree(this);
this = next;
}
mystrfree(kl);
}
else
{
GC_CLR(kl);
kl->kl_Next = KeylistChain;
KeylistChain = kl;
}
kl = nxtkl;
}
}
void
keymap_prin(VALUE strm, VALUE obj)
{
switch(VTYPE(obj))
{
case V_Keytab:
streamputs(strm, "#<key-table>", FALSE);
break;
case V_Keylist:
streamputs(strm, "#<key-list>", FALSE);
break;
}
}
_PR VALUE cmd_make_keytab(void);
DEFUN("make-keytab", cmd_make_keytab, subr_make_keytab, (void), V_Subr0, DOC_make_keytab) /*
::doc:make_keytab::
(make-keytab)
Return a new key-table suitable for storing bindings in.
::end:: */
{
Keytab *kt = mycalloc(sizeof(Keytab));
if(kt)
{
kt->kt_Type = V_Keytab;
kt->kt_Next = KeytabChain;
KeytabChain = kt;
}
return(kt);
}
_PR VALUE cmd_make_keylist(void);
DEFUN("make-keylist", cmd_make_keylist, subr_make_keylist, (void), V_Subr0, DOC_make_keylist) /*
::doc:make_keylist::
(make-keylist)
Return a new key-list suitable for storing bindings in.
::end:: */
{
Keylist *kl = mystralloc(sizeof(Keylist));
if(kl)
{
kl->kl_Type = V_Keylist;
kl->kl_Next = KeylistChain;
KeylistChain = kl;
NewMList(&kl->kl_List);
}
return(kl);
}
_PR VALUE cmd_bind_keys(VALUE args);
DEFUN("bind-keys", cmd_bind_keys, subr_bind_keys, (VALUE args), V_SubrN, DOC_bind_keys) /*
::doc:bind_keys::
(bind-keys KEY-MAP { KEY-DESCRIPTION FUNCTION }...)
::end:: */
{
bool rc = TRUE;
bool iskt;
VALUE km, arg1, res = NULL;
if(!CONSP(args))
return(NULL);
km = VCAR(args);
switch(VTYPE(km))
{
case V_Keytab:
iskt = TRUE;
break;
case V_Keylist:
iskt = FALSE;
break;
default:
goto end;
}
args = VCDR(args);
while(rc && CONSP(args) && CONSP(VCDR(args)))
{
EventDef ie;
Key *rt;
arg1 = VCAR(args);
args = VCDR(args);
ie.evd_Type = ie.evd_Mods = ie.evd_Code = 0;
if(STRINGP(arg1))
{
if(!lookupevent(&ie, VSTR(arg1)))
goto end;
}
else
{
cmd_signal(sym_bad_event_desc, LIST_1(arg1));
goto end;
}
rc = FALSE;
rt = mystralloc(sizeof(Key));
if(rt)
{
if(iskt)
{
u_long entry = ie.evd_Code & EV_HASH_MASK;
rt->ky_Link.next = VKEYTAB(km)->kt_Keys[entry];
VKEYTAB(km)->kt_Keys[entry] = rt;
}
else
InsertM(&VKEYLIST(km)->kl_List, &rt->ky_Link.node, NULL);
rt->ky_Form = VCAR(args);
args = VCDR(args);
rt->ky_Event = ie;
rc = TRUE;
}
else
goto end;
}
if(rc)
res = (sym_t);
end:
return(res);
}
_PR VALUE cmd_unbind_keys(VALUE args);
DEFUN("unbind-keys", cmd_unbind_keys, subr_unbind_keys, (VALUE args), V_SubrN, DOC_unbind_keys) /*
::doc:unbind_keys::
(unbind-keys KEY-MAP KEY-DESCRIPTION...)
::end:: */
{
bool rc = TRUE;
bool iskt;
VALUE km, arg1, res = NULL;
if(!CONSP(args))
return(NULL);
km = VCAR(args);
args = VCDR(args);
switch(VTYPE(km))