reordered KEY_xxx definitions

added KEY_DEL=127 (formerly KEY_BACKSPACE)
added KEY_BS=8  C-H  to handle control-h as backspace on some ttys
fixed KEY_F6 thru KEY_F12 (were off by one)
added strtokeys() to convert a string with key names to a key buffer
added define-kbd-macro() from key string
added execute-macro-keys() to execute commands from a key string
improved qe_key_process().
changed method to update shell cursor : tty_update_cursor disabled
  shell_display_hook() used instead
greatly improved shell buffer behaviour, charset handling.
much improved tty input handling : support more key combinations and modes.
added missing charset declarations in qe.h
added borders_invalid and complete_refresh window flags
made C-L completely refresh display
moved window border display to separate function
changed edit_display() to allow complete redisplay even with popups
fixed window delete crash bugs by improving consistency with
  edit_attach and edit_detach.
This commit is contained in:
Charlie Gordon 2005-05-09 02:17:47 +00:00
commit 8fac0ab42e
9 changed files with 567 additions and 226 deletions

View file

@ -102,6 +102,7 @@ typedef struct QEDisplay {
int x, int y, int w, int h);
void (*dpy_selection_activate)(QEditScreen *s);
void (*dpy_selection_request)(QEditScreen *s);
void (*dpy_invalidate)(void);
/* bitmap support */
int (*dpy_bmp_alloc)(QEditScreen *s, QEBitmap *b);
void (*dpy_bmp_free)(QEditScreen *s, QEBitmap *b);

235
qe.c
View file

@ -329,22 +329,14 @@ void command_completion(StringArray *cs, const char *input)
void do_global_set_key(EditState *s, const char *keystr, const char *cmd_name)
{
int key, nb_keys;
int nb_keys;
unsigned int keys[MAX_KEYS];
const char *p;
CmdDef *d;
p = keystr;
nb_keys = 0;
for(;;) {
skip_spaces(&p);
if (*p == '\0')
break;
key = strtokey(&p);
keys[nb_keys++] = key;
if (nb_keys >= MAX_KEYS)
break;
}
nb_keys = strtokeys(keystr, keys, MAX_KEYS);
if (!nb_keys)
return;
d = qe_find_cmd(cmd_name);
if (!d)
return;
@ -1681,6 +1673,7 @@ void do_insert_file(EditState *s, const char *filename);
void do_save(EditState *s, int save_as);
void do_isearch(EditState *s, int dir);
void do_refresh(EditState *s);
void do_refresh_complete(EditState *s);
/* compute string for the first part of the mode line (flags,
filename, modename) */
@ -1767,6 +1760,45 @@ void display_mode_line(EditState *s)
}
}
void display_window_borders(EditState *e)
{
QEmacsState *qs = e->qe_state;
if (e->borders_invalid) {
if (e->flags & (WF_POPUP | WF_RSEPARATOR)) {
CSSRect rect;
QEColor color;
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = qs->width;
rect.y2 = qs->height;
set_clip_rectangle(qs->screen, &rect);
color = qe_styles[QE_STYLE_WINDOW_BORDER].bg_color;
if (e->flags & WF_POPUP) {
fill_rectangle(qs->screen,
e->x1, e->y1,
qs->border_width, e->y2 - e->y1, color);
fill_rectangle(qs->screen,
e->x2 - qs->border_width, e->y1,
qs->border_width, e->y2 - e->y1, color);
fill_rectangle(qs->screen,
e->x1, e->y1,
e->x2 - e->x1, qs->border_width, color);
fill_rectangle(qs->screen,
e->x1, e->y2 - qs->border_width,
e->x2 - e->x1, qs->border_width, color);
}
if (e->flags & WF_RSEPARATOR) {
fill_rectangle(qs->screen,
e->x2 - qs->separator_width, e->y1,
qs->separator_width, e->y2 - e->y1, color);
}
}
e->borders_invalid = 0;
}
}
/* compute style */
static void apply_style(QEStyleDef *style, int style_index)
{
@ -3320,6 +3352,7 @@ void window_display(EditState *s)
s->mode->display(s);
display_mode_line(s);
display_window_borders(s);
}
/* display all windows */
@ -3335,23 +3368,34 @@ void edit_display(QEmacsState *qs)
s->mode->display_hook(s);
}
/* first display popups and minibuf */
/* count popups */
/* CG: maybe a separate list for popups? */
has_popups = 0;
for (s = qs->first_window; s != NULL; s = s->next_window) {
if (s->flags & WF_POPUP) {
window_display(s);
has_popups = 1;
} else if (s->minibuf) {
window_display(s);
}
}
if (!has_popups) {
for(s = qs->first_window; s != NULL; s = s->next_window) {
if (!s->minibuf)
window_display(s);
}
/* refresh normal windows and minibuf with popup kludge */
for (s = qs->first_window; s != NULL; s = s->next_window) {
if (!(s->flags & WF_POPUP) &&
(s->minibuf || !has_popups || qs->complete_refresh)) {
window_display(s);
}
}
/* refresh popups if any */
if (has_popups) {
for (s = qs->first_window; s != NULL; s = s->next_window) {
if (s->flags & WF_POPUP) {
if (qs->complete_refresh)
/* refresh frame */;
window_display(s);
}
}
}
qs->complete_refresh = 0;
}
void do_universal_argument(EditState *s)
@ -3442,6 +3486,46 @@ void do_call_macro(EditState *s)
}
}
void do_execute_macro_keys(EditState *s, const char *keys)
{
int key;
const char *p;
p = keys;
for (;;) {
skip_spaces(&p);
if (*p == '\0')
break;
key = strtokey(&p);
qe_key_process(key);
}
}
void do_define_kbd_macro(EditState *s, const char *name, const char *keys,
const char *keystr)
{
CmdDef *def;
int size;
char *macro_name, *p;
size = strlen(name) + 1;
macro_name = malloc(size + 2);
memcpy(macro_name, name, size);
p = macro_name + size;
*p++ = 'S';
*p++ = '\0';
def = malloc(2 * sizeof(CmdDef));
memset(def, 0, sizeof(CmdDef) * 2);
def->key = def->alt_key = KEY_NONE;
def->name = macro_name;
def->action.func = do_execute_macro_keys;
def->val = strdup(keystr);
qe_register_cmd_table(def, NULL);
do_global_set_key(s, keystr, name);
}
#define MACRO_KEY_INCR 64
static void macro_add_key(int key)
@ -3518,7 +3602,7 @@ static void qe_key_process(int key)
EditState *s;
KeyDef *kd;
CmdDef *d;
char buf1[32];
char buf1[128];
int len;
if (qs->defining_macro) {
@ -3544,14 +3628,14 @@ static void qe_key_process(int key)
/* special case for escape : we transform it as meta so
that unix users are happy ! */
/* CG: should allow for other key compositions, such as
* diacritics, and compositions of more than 2 keys
*/
if (key == KEY_ESC) {
c->is_escape = 1;
goto next;
} else if (c->is_escape) {
if (c->nb_keys >= 2) {
c->nb_keys--;
c->keys[c->nb_keys - 1] = KEY_META(key);
}
compose_keys(c->keys, &c->nb_keys);
c->is_escape = 0;
}
@ -3595,8 +3679,15 @@ static void qe_key_process(int key)
}
}
}
qe_key_init();
if (!c->describe_key)
/* CG: should beep */;
put_status(s, "No command on %s",
keys_to_str(buf1, sizeof(buf1), c->keys, c->nb_keys));
c->describe_key = 0;
qe_key_init();
dpy_flush(&global_screen);
return;
} else if (c->nb_keys == kd->nb_keys) {
exec_cmd:
d = kd->cmd;
@ -3615,7 +3706,6 @@ static void qe_key_process(int key)
}
}
if (c->describe_key) {
char buf1[128];
put_status(s, "%s runs the command %s",
keys_to_str(buf1, sizeof(buf1), c->keys, c->nb_keys),
d->name);
@ -3632,6 +3722,7 @@ static void qe_key_process(int key)
next:
/* display key pressed */
if (!s->minibuf) {
/* Should print argument if any in a more readable way */
keytostr(buf1, sizeof(buf1), key);
len = strlen(c->buf);
if (len >= 1)
@ -3806,6 +3897,7 @@ static void compute_client_area(EditState *s)
EditState *edit_new(EditBuffer *b,
int x1, int y1, int width, int height, int flags)
{
/* b may be NULL ??? */
EditState *s;
QEmacsState *qs = &qe_state;
@ -3829,6 +3921,30 @@ EditState *edit_new(EditBuffer *b,
return s;
}
/* detach the window from the window tree. */
void edit_detach(EditState *s)
{
QEmacsState *qs = s->qe_state;
EditState **ep;
for (ep = &qs->first_window; *ep; ep = &(*ep)->next_window) {
if (*ep == s) {
*ep = s->next_window;
s->next_window = NULL;
break;
}
}
if (qs->active_window == s)
qs->active_window = qs->first_window;
}
/* attach the window to the window list. */
void edit_attach(EditState *s, EditState **ep)
{
s->next_window = *ep;
*ep = s;
}
/* close the edit window. If it is active, find another active
window. If the buffer is only referenced by this window, then save
in the buffer all the window state so that it can be recovered. */
@ -4222,6 +4338,7 @@ void minibuffer_edit(const char *input, const char *prompt,
s = edit_new(b, 0, qs->screen->height - qs->status_height,
qs->screen->width, qs->status_height, 0);
/* Should insert at end of window list */
do_set_mode(s, &minibuffer_mode, NULL);
s->prompt = strdup(prompt);
s->minibuf = 1;
@ -4274,6 +4391,7 @@ void do_less_quit(EditState *s)
QEmacsState *qs = s->qe_state;
EditBuffer *b;
/* CG: should verify that popup_saved_active still exists */
qs->active_window = popup_saved_active;
b = s->b;
edit_close(s);
@ -5065,7 +5183,8 @@ static void isearch_key(void *opaque, int ch)
int i, j;
switch (ch) {
case KEY_BACKSPACE:
case KEY_DEL:
case KEY_BS: /* Should test actual binding of KEY_BS */
if (is->pos > 0)
is->pos--;
break;
@ -5306,6 +5425,7 @@ static void do_query_replace(EditState *s,
void do_doctor(EditState *s)
{
/* Should show keys? */
put_status(s, "Hello, how are you ?");
}
@ -5334,6 +5454,11 @@ void do_refresh(EditState *s1)
int new_status_height, new_mode_line_height, content_height;
int width, height;
if (qs->complete_refresh) {
if (qs->screen->dpy.dpy_invalidate)
qs->screen->dpy.dpy_invalidate();
}
/* recompute various dimensions */
if (qs->screen->media & CSS_MEDIA_TTY) {
qs->separator_width = 1;
@ -5396,41 +5521,21 @@ void do_refresh(EditState *s1)
/* invalidate all the edit windows and draw borders */
for(e = qs->first_window; e != NULL; e = e->next_window) {
edit_invalidate(e);
if (e->flags & (WF_POPUP | WF_RSEPARATOR)) {
CSSRect rect;
QEColor color;
rect.x1 = 0;
rect.y1 = 0;
rect.x2 = qs->width;
rect.y2 = qs->height;
set_clip_rectangle(qs->screen, &rect);
color = qe_styles[QE_STYLE_WINDOW_BORDER].bg_color;
if (e->flags & WF_POPUP) {
fill_rectangle(qs->screen,
e->x1, e->y1,
qs->border_width, e->y2 - e->y1, color);
fill_rectangle(qs->screen,
e->x2 - qs->border_width, e->y1,
qs->border_width, e->y2 - e->y1, color);
fill_rectangle(qs->screen,
e->x1, e->y1,
e->x2 - e->x1, qs->border_width, color);
fill_rectangle(qs->screen,
e->x1, e->y2 - qs->border_width,
e->x2 - e->x1, qs->border_width, color);
}
if (e->flags & WF_RSEPARATOR) {
fill_rectangle(qs->screen,
e->x2 - qs->separator_width, e->y1,
qs->separator_width, e->y2 - e->y1, color);
}
}
e->borders_invalid = 1;
}
/* invalidate status line */
qs->status_shadow[0] = '\0';
put_status(NULL, " ");
}
void do_refresh_complete(EditState *s)
{
QEmacsState *qs = s->qe_state;
qs->complete_refresh = 1;
do_refresh(s);
}
void do_other_window(EditState *s)
{
QEmacsState *qs = s->qe_state;
@ -5510,6 +5615,8 @@ void do_delete_window(EditState *s, int force)
if (e)
compute_client_area(e);
}
if (qs->active_window == s)
qs->active_window = e ? e : qs->first_window;
edit_close(s);
if (qs->first_window)
do_refresh(qs->first_window);
@ -5539,6 +5646,7 @@ void do_delete_other_windows(EditState *s)
/* XXX: add minimum size test and refuse to split if reached */
void do_split_window(EditState *s, int horiz)
{
QEmacsState *qs = s->qe_state;
EditState *e;
int x, y;
@ -5564,6 +5672,13 @@ void do_split_window(EditState *s, int horiz)
return;
s->y2 = y;
}
/* insert in the window list after current window */
edit_detach(e);
edit_attach(e, &s->next_window);
if (qs->flag_split_window_change_focus)
qs->active_window = e;
compute_client_area(s);
do_refresh(s);
}
@ -5638,7 +5753,7 @@ void do_describe_bindings(EditState *s)
b->flags |= BF_READONLY;
if (show) {
show_popup(b);
eb_free(b);
//eb_free(b);
}
}

133
qe.h
View file

@ -92,7 +92,9 @@ int ustristart(const unsigned int *str, const char *val, const unsigned int **pt
void css_strtolower(char *buf, int buf_size);
void get_str(const char **pp, char *buf, int buf_size, const char *stop);
int compose_keys(int *keys, int *nb_keys);
int strtokey(const char **pp);
int strtokeys(const char *keystr, unsigned int *keys, int max_keys);
void keytostr(char *buf, int buf_size, int key);
int css_define_color(const char *name, const char *value);
int css_get_color(int *color_ptr, const char *p);
@ -209,8 +211,32 @@ typedef struct QECharset {
struct QECharset *next;
} QECharset;
extern QECharset charset_utf8, charset_8859_1; /* predefined charsets */
extern QECharset *first_charset;
extern QECharset charset_utf8, charset_8859_1; /* predefined charsets */
extern QECharset charset_8859_2;
extern QECharset charset_cp1125;
extern QECharset charset_cp737;
extern QECharset charset_koi8_r;
extern QECharset charset_8859_4;
extern QECharset charset_cp1250;
extern QECharset charset_cp850;
extern QECharset charset_koi8_u;
extern QECharset charset_viscii;
extern QECharset charset_8859_13;
extern QECharset charset_8859_5;
extern QECharset charset_cp1251;
extern QECharset charset_cp852;
extern QECharset charset_mac_lat2;
extern QECharset charset_8859_15;
extern QECharset charset_8859_7;
extern QECharset charset_cp1257;
extern QECharset charset_cp866;
extern QECharset charset_macroman;
extern QECharset charset_8859_16;
extern QECharset charset_8859_9;
extern QECharset charset_cp437;
extern QECharset charset_kamen;
extern QECharset charset_tcvn5712;
typedef struct CharsetDecodeState {
/* 256 ushort table for hyper fast decoding */
@ -286,50 +312,63 @@ enum QEEventType {
QE_SELECTION_CLEAR_EVENT, /* request selection clear (X11 type selection) */
};
#define KEY_META(c) ((c) | 0xe000)
#define KEY_ESC1(c) ((c) | 0xe100)
#define KEY_CTRLX(c) ((c) | 0xe200)
#define KEY_CTRL(c) ((c) & 0x001f)
#define KEY_META(c) ((c) | 0xe000)
#define KEY_ESC1(c) ((c) | 0xe100)
#define KEY_CTRLX(c) ((c) | 0xe200)
#define KEY_CTRLXRET(c) ((c) | 0xe300)
#define KEY_CTRLH(c) ((c) | 0xe500)
#define KEY_CTRL(c) ((c) & 0x1f)
#define KEY_UP KEY_ESC1('A')
#define KEY_DOWN KEY_ESC1('B')
#define KEY_RIGHT KEY_ESC1('C')
#define KEY_LEFT KEY_ESC1('D')
#define KEY_CTRL_UP KEY_ESC1('a')
#define KEY_CTRL_DOWN KEY_ESC1('b')
#define KEY_CTRL_RIGHT KEY_ESC1('c')
#define KEY_CTRL_LEFT KEY_ESC1('d')
#define KEY_CTRL_HOME 0xe402
#define KEY_CTRL_END 0xe403
#define KEY_TAB KEY_CTRL('i')
#define KEY_SHIFT_TAB 0xe404
#define KEY_F1 KEY_ESC1(11)
#define KEY_F2 KEY_ESC1(12)
#define KEY_F3 KEY_ESC1(13)
#define KEY_F4 KEY_ESC1(14)
#define KEY_F5 KEY_ESC1(15)
#define KEY_F6 KEY_ESC1(16)
#define KEY_F7 KEY_ESC1(17)
#define KEY_F8 KEY_ESC1(18)
#define KEY_F9 KEY_ESC1(19)
#define KEY_F10 KEY_ESC1(20)
#define KEY_F11 KEY_ESC1(21)
#define KEY_F12 KEY_ESC1(22)
#define KEY_BACKSPACE 127
#define KEY_INSERT KEY_ESC1(2)
#define KEY_DELETE KEY_ESC1(3)
#define KEY_PAGEUP KEY_ESC1(5)
#define KEY_PAGEDOWN KEY_ESC1(6)
#define KEY_HOME KEY_ESC1(7)
#define KEY_END KEY_ESC1(8)
#define KEY_REFRESH KEY_CTRL('l')
#define KEY_RET 0x000d
#define KEY_ESC 0x001b
#define KEY_SPC 0x0020
#define KEY_NONE 0xffff
#define KEY_DEFAULT 0xe401 /* to handle all non special keys */
#define KEY_SPECIAL(c) (((c) >= 0xe000 && (c) < 0xf000) || ((c) >= 0 && (c) < 32))
#define KEY_CTRLH(c) ((c) | 0xe500)
#define KEY_SPECIAL(c) (((c) >= 0xe000 && (c) < 0xf000) || ((c) >= 0 && (c) < 32))
#define KEY_NONE 0xffff
#define KEY_TAB KEY_CTRL('i')
#define KEY_RET KEY_CTRL('m')
#define KEY_REFRESH KEY_CTRL('l')
#define KEY_ESC KEY_CTRL('[')
#define KEY_SPC 0x0020
#define KEY_DEL 127 // kbs
#define KEY_BS KEY_CTRL('h') // kbs
#define KEY_DEFAULT 0xe401 /* to handle all non special keys */
#define KEY_UP KEY_ESC1('A') // kcuu1
#define KEY_DOWN KEY_ESC1('B') // kcud1
#define KEY_RIGHT KEY_ESC1('C') // kcuf1
#define KEY_LEFT KEY_ESC1('D') // kcub1
#define KEY_CTRL_UP KEY_ESC1('a')
#define KEY_CTRL_DOWN KEY_ESC1('b')
#define KEY_CTRL_RIGHT KEY_ESC1('c')
#define KEY_CTRL_LEFT KEY_ESC1('d')
#define KEY_CTRL_END KEY_ESC1('f')
#define KEY_CTRL_HOME KEY_ESC1('h')
#define KEY_CTRL_PAGEUP KEY_ESC1('i')
#define KEY_CTRL_PAGEDOWN KEY_ESC1('j')
#define KEY_SHIFT_TAB KEY_ESC1('Z') // kcbt
#define KEY_HOME KEY_ESC1(1) // khome
#define KEY_INSERT KEY_ESC1(2) // kich1
#define KEY_DELETE KEY_ESC1(3) // kdch1
#define KEY_END KEY_ESC1(4) // kend
#define KEY_PAGEUP KEY_ESC1(5) // kpp
#define KEY_PAGEDOWN KEY_ESC1(6) // knp
#define KEY_F1 KEY_ESC1(11)
#define KEY_F2 KEY_ESC1(12)
#define KEY_F3 KEY_ESC1(13)
#define KEY_F4 KEY_ESC1(14)
#define KEY_F5 KEY_ESC1(15)
#define KEY_F6 KEY_ESC1(17)
#define KEY_F7 KEY_ESC1(18)
#define KEY_F8 KEY_ESC1(19)
#define KEY_F9 KEY_ESC1(20)
#define KEY_F10 KEY_ESC1(21)
#define KEY_F11 KEY_ESC1(23)
#define KEY_F12 KEY_ESC1(24)
#define KEY_F13 KEY_ESC1(25)
#define KEY_F14 KEY_ESC1(26)
#define KEY_F15 KEY_ESC1(28)
#define KEY_F16 KEY_ESC1(29)
#define KEY_F17 KEY_ESC1(31)
#define KEY_F18 KEY_ESC1(32)
#define KEY_F19 KEY_ESC1(33)
#define KEY_F20 KEY_ESC1(34)
typedef struct QEKeyEvent {
enum QEEventType type;
@ -698,6 +737,7 @@ typedef struct EditState {
produce the display */
int display_invalid; /* true if the display was invalidated. Full
redraw should be done */
int borders_invalid; /* true if window borders should be redrawn */
int show_selection; /* if true, the selection is displayed */
/* display area info */
int width, height;
@ -838,8 +878,10 @@ typedef struct QEmacsState {
int separator_width;
/* full screen state */
int hide_status; /* true if status should be hidden */
int complete_refresh;
int is_full_screen;
/* commands */
int flag_split_window_change_focus;
void *last_cmd_func; /* last executed command function call */
/* keyboard macros */
int defining_macro;
@ -1082,6 +1124,8 @@ void do_find_window(EditState *s, int key);
/* window handling */
void edit_close(EditState *s);
void edit_detach(EditState *s);
void edit_append(EditState *s, EditState *e);
EditState *edit_new(EditBuffer *b,
int x1, int y1, int width, int height, int flags);
void do_refresh(EditState *s);
@ -1106,6 +1150,7 @@ void do_char(EditState *s, int key);
void do_switch_to_buffer(EditState *s, const char *bufname);;
void do_set_mode(EditState *s, ModeDef *m, ModeSavedData *saved_data);
void text_move_left_right_visual(EditState *s, int dir);
void text_move_word_left_right(EditState *s, int dir);
void text_move_up_down(EditState *s, int dir);
void text_scroll_up_down(EditState *s, int dir);
void text_write_char(EditState *s, int key);

View file

@ -16,10 +16,10 @@ CmdDef basic_commands[] = {
CMD1( KEY_CTRL('z'), KEY_NONE, "scroll-up-one", do_scroll_up_down, 1 )
CMD0( KEY_HOME, KEY_CTRL('a'), "beginning-of-line", do_bol)
CMD0( KEY_END, KEY_CTRL('e'), "end-of-line", do_eol)
CMD0( KEY_ESC1(2), KEY_NONE, "overwrite-mode", do_insert)
CMD0( KEY_INSERT, KEY_NONE, "overwrite-mode", do_insert)
CMD0( KEY_CTRL('d'), KEY_DELETE, "delete-char", do_delete_char)
CMD0( 127, KEY_NONE, "backward-delete-char", do_backspace)
CMD1( KEY_META(KEY_BACKSPACE) , KEY_NONE,
CMD1( KEY_META(KEY_DEL) , KEY_META(KEY_BS),
"backward-delete-word", do_delete_word, -1)
CMD1( KEY_META('d') , KEY_NONE, "delete-word", do_delete_word, 1)
CMD1( KEY_CTRL('k'), KEY_NONE, "kill-line", do_kill_region, 2 )
@ -59,7 +59,7 @@ CmdDef basic_commands[] = {
"s{Query replace: }|search|s{With: }|replace|")
CMD0( KEY_CTRLX('u'), KEY_CTRL('_'), "undo", do_undo)
CMD0( KEY_RET, KEY_NONE, "newline", do_return)
CMD0( KEY_CTRL('l'), KEY_NONE, "refresh", do_refresh)
CMD0( KEY_CTRL('l'), KEY_NONE, "refresh", do_refresh_complete)
CMD_( KEY_META('g'), KEY_NONE, "goto-line", do_goto_line, "i{Goto line: }")
CMD_( KEY_NONE, KEY_NONE, "goto-char", do_goto_char, "i{Goto char: }")
CMD0( KEY_CTRLX(KEY_CTRL('q')), KEY_NONE, "vc-toggle-read-only",
@ -80,8 +80,10 @@ CmdDef basic_commands[] = {
CMD0( KEY_CTRLX('('), KEY_NONE, "start-kbd-macro", do_start_macro)
CMD0( KEY_CTRLX(')'), KEY_NONE, "end-kbd-macro", do_end_macro)
CMD0( KEY_CTRLX('e'), KEY_NONE, "call-last-kbd-macro", do_call_macro)
CMD_( KEY_NONE, KEY_NONE, "define-kbd-macro", do_define_kbd_macro,
"s{Macro name: }[command]s{Macro keys: }s{Bind to key: }[key]")
CMD_( KEY_NONE, KEY_NONE, "global-set-key", do_global_set_key,
"s{Set key globally: }s{command: }[command]|command|")
"s{Set key globally: }[key]s{command: }[command]|command|")
/* window handling */
CMD0( KEY_CTRLX('o'), KEY_NONE, "other-window", do_other_window)
@ -106,7 +108,7 @@ CmdDef basic_commands[] = {
/* help */
CMD0( KEY_CTRLH(KEY_CTRL('h')), KEY_F1, "help-for-help", do_help_for_help)
CMD0( KEY_CTRLH('b'), KEY_NONE, "describe-bindings", do_describe_bindings)
CMD0( KEY_CTRLH('c'), KEY_NONE, "describe-key-briefly",
CMD0( KEY_CTRLH('c'), KEY_CTRLH('k'), "describe-key-briefly",
do_describe_key_briefly)
/* international */

66
shell.c
View file

@ -54,6 +54,7 @@ typedef struct ShellState {
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
int state;
int shifted;
EditBuffer *b;
EditBuffer *b_color; /* color buffer, one byte per char */
int is_shell; /* only used to display final message */
@ -233,6 +234,7 @@ void tty_csi_m(ShellState *s, int c)
/* Well, almost a hack to update cursor */
static void tty_update_cursor(ShellState *s)
{
#if 0
QEmacsState *qs = s->qe_state;
EditState *e;
@ -244,6 +246,17 @@ static void tty_update_cursor(ShellState *s)
e->offset = s->cur_offset;
}
}
#endif
}
/* CG: much cleaner way! */
/* would need a kill hook as well ? */
static void shell_display_hook(EditState *e)
{
ShellState *s = e->b->priv_data;
if (e->interactive)
e->offset = s->cur_offset;
}
static void tty_emulate(ShellState *s, int c)
@ -288,6 +301,14 @@ static void tty_emulate(ShellState *s, int c)
s->cur_offset = offset1;
}
break;
case 14:
eb_set_charset(s->b, &charset_8859_1);
s->shifted = 1;
break;
case 15:
eb_set_charset(s->b, &charset_cp1125);
s->shifted = 0;
break;
case 27:
s->state = TTY_STATE_ESC;
break;
@ -317,7 +338,7 @@ static void tty_emulate(ShellState *s, int c)
break;
case TTY_STATE_ESC:
if (c == '[') {
for(i=0;i<MAX_ESC_PARAMS;i++)
for (i = 0; i < MAX_ESC_PARAMS; i++)
s->esc_params[i] = 0;
s->nb_esc_params = 0;
s->state = TTY_STATE_CSI;
@ -663,36 +684,46 @@ void shell_move_left_right(EditState *e, int dir)
{
if (e->interactive) {
ShellState *s = e->b->priv_data;
if (dir > 0)
tty_write(s, "\033[C", -1);
else
tty_write(s, "\033[D", -1);
tty_write(s, dir > 0 ? "\033[C" : "\033[D", -1);
} else {
text_move_left_right_visual(e, dir);
}
}
void shell_move_word_left_right(EditState *e, int dir)
{
if (e->interactive) {
ShellState *s = e->b->priv_data;
tty_write(s, dir > 0 ? "\033f" : "\033b", -1);
} else {
text_move_word_left_right(e, dir);
}
}
void shell_move_up_down(EditState *e, int dir)
{
if (e->interactive) {
ShellState *s = e->b->priv_data;
if (dir > 0)
tty_write(s, "\033[B", -1);
else
tty_write(s, "\033[A", -1);
tty_write(s, dir > 0 ? "\033[B" : "\033[A", -1);
} else {
text_move_up_down(e, dir);
}
}
void shell_scroll_up_down(EditState *e, int dir)
{
ShellState *s = e->b->priv_data;
e->interactive = 0;
text_scroll_up_down(e, dir);
e->interactive = (e->offset == s->cur_offset);
}
void shell_move_bol(EditState *e)
{
if (e->interactive) {
ShellState *s = e->b->priv_data;
unsigned char ch;
ch = 1;
tty_write(s, &ch, 1);
tty_write(s, "\001", -1); /* Control-A */
} else {
text_move_bol(e);
}
@ -702,9 +733,7 @@ void shell_move_eol(EditState *e)
{
if (e->interactive) {
ShellState *s = e->b->priv_data;
unsigned char ch;
ch = 5;
tty_write(s, &ch, 1);
tty_write(s, "\005", -1); /* Control-E */
} else {
text_move_eol(e);
}
@ -746,10 +775,12 @@ void shell_write_char(EditState *e, int c)
void do_shell_toggle_input(EditState *e)
{
e->interactive = !e->interactive;
#if 0
if (e->interactive) {
ShellState *s = e->b->priv_data;
tty_update_cursor(s);
}
#endif
}
static int error_offset = -1;
@ -916,8 +947,11 @@ static int shell_init(void)
shell_mode.name = "shell";
shell_mode.mode_probe = NULL;
shell_mode.mode_init = shell_mode_init;
shell_mode.display_hook = shell_display_hook;
shell_mode.move_left_right = shell_move_left_right;
shell_mode.move_word_left_right = shell_move_word_left_right;
shell_mode.move_up_down = shell_move_up_down;
shell_mode.scroll_up_down = shell_scroll_up_down;
shell_mode.move_bol = shell_move_bol;
shell_mode.move_eol = shell_move_eol;
shell_mode.write_char = shell_write_char;

156
tty.c
View file

@ -41,6 +41,7 @@ enum InputState {
IS_NORM,
IS_ESC,
IS_CSI,
IS_CSI2,
IS_ESC2,
};
@ -103,6 +104,7 @@ static int term_init(QEditScreen *s, int w, int h)
s->charset = &charset_8859_1;
#ifndef CONFIG_CYGWIN
/* CG: Should also have a command line switch */
/* test UTF8 support by looking at the cursor position (idea from
Ricardas Cepas <rch@pub.osf.lt>). Since uClibc actually tests
to ensure that the format string is a valid multibyte sequence
@ -197,6 +199,11 @@ static void tty_resize(int sig)
s->clip_y2 = s->height;
}
static void term_invalidate(void)
{
tty_resize(0);
}
static void term_cursor_at(QEditScreen *s, int x1, int y1, int w, int h)
{
TTYState *ts = s->private;
@ -219,6 +226,44 @@ static int term_is_user_input_pending(QEditScreen *s)
return 0;
}
static int const csi_lookup[] = {
KEY_NONE, /* 0 */
KEY_HOME, /* 1 */
KEY_INSERT, /* 2 */
KEY_DELETE, /* 3 */
KEY_END, /* 4 */
KEY_PAGEUP, /* 5 */
KEY_PAGEDOWN, /* 6 */
KEY_NONE, /* 7 */
KEY_NONE, /* 8 */
KEY_NONE, /* 9 */
KEY_NONE, /* 10 */
KEY_F1, /* 11 */
KEY_F2, /* 12 */
KEY_F3, /* 13 */
KEY_F4, /* 14 */
KEY_F5, /* 15 */
KEY_NONE, /* 16 */
KEY_F6, /* 17 */
KEY_F7, /* 18 */
KEY_F8, /* 19 */
KEY_F9, /* 20 */
KEY_F10, /* 21 */
KEY_NONE, /* 22 */
KEY_F11, /* 23 */
KEY_F12, /* 24 */
KEY_F13, /* 25 */
KEY_F14, /* 26 */
KEY_NONE, /* 27 */
KEY_F15, /* 28 */
KEY_F16, /* 29 */
KEY_NONE, /* 30 */
KEY_F17, /* 31 */
KEY_F18, /* 32 */
KEY_F19, /* 33 */
KEY_F20, /* 34 */
};
static void tty_read_handler(void *opaque)
{
QEditScreen *s = opaque;
@ -232,6 +277,13 @@ static void tty_read_handler(void *opaque)
if (trace_buffer) {
eb_write(trace_buffer, trace_buffer->total_size,
ts->buf + ts->utf8_index, 1);
#if 0
ch = ts->buf[ts->utf8_index];
if (ch < 32 || ch == 127)
fprintf(stderr, "got %d '^%c'\n", ch, ('@' + ch) & 127);
else
fprintf(stderr, "got %d '%c'\n", ch, ch);
#endif
}
/* charset handling */
@ -257,6 +309,10 @@ static void tty_read_handler(void *opaque)
goto the_end;
break;
case IS_ESC:
if (ch == '\033') {
/* cygwin A-right transmit ESC ESC[C ... */
goto the_end;
}
if (ch == '[') {
ts->input_state = IS_CSI;
ts->input_param = 0;
@ -269,43 +325,82 @@ static void tty_read_handler(void *opaque)
}
break;
case IS_CSI:
if (!isdigit(ch)) {
ts->input_state = IS_NORM;
switch(ch) {
case '~':
ch = KEY_ESC1(ts->input_param);
goto the_end;
case 'H':
ch = KEY_HOME;
goto the_end;
case 'F':
ch = KEY_END;
goto the_end;
case 'Z':
ch = KEY_SHIFT_TAB;
goto the_end;
default:
/* xterm CTRL-arrows */
if (ts->input_param == 5 && ch >= 'A' && ch <= 'D')
ch += 'a' - 'A';
ch = KEY_ESC1(ch);
if (isdigit(ch)) {
ts->input_param = ts->input_param * 10 + ch - '0';
break;
}
ts->input_state = IS_NORM;
switch(ch) {
case '[':
ts->input_state = IS_CSI2;
break;
case '~':
if (ts->input_param < sizeof(csi_lookup)/sizeof(csi_lookup[0])) {
ch = csi_lookup[ts->input_param];
goto the_end;
}
} else {
ts->input_param = ts->input_param * 10 + ch - '0';
break;
/* All these for ansi|cygwin */
case 'A': ch = KEY_UP; goto the_end; // kcuu1
case 'B': ch = KEY_DOWN; goto the_end; // kcud1
case 'C': ch = KEY_RIGHT; goto the_end; // kcuf1
case 'D': ch = KEY_LEFT; goto the_end; // kcub1
case 'F': ch = KEY_END; goto the_end; // kend
//case 'G': ch = KEY_CENTER; goto the_end; // kb2
case 'H': ch = KEY_HOME; goto the_end; // khome
case 'L': ch = KEY_INSERT; goto the_end; // kich1
//case 'M': ch = KEY_MOUSE; goto the_end; // kmous
case 'Z': ch = KEY_SHIFT_TAB; goto the_end; // kcbt
default:
#if 0 /* xterm CTRL-arrows */
if (ts->input_param == 5) {
switch (ch) {
case 'A': ch = KEY_CTRL_UP; goto the_end;
case 'B': ch = KEY_CTRL_DOWN; goto the_end;
case 'C': ch = KEY_CTRL_RIGHT; goto the_end;
case 'D': ch = KEY_CTRL_LEFT; goto the_end;
}
}
#endif
break;
}
break;
case IS_ESC2:
/* xterm fn */
case IS_CSI2:
/* cygwin/linux terminal */
ts->input_state = IS_NORM;
if (ch >= 'P' && ch <= 'S') {
ch = KEY_F1 + ch - 'P';
the_end:
ev->key_event.type = QE_KEY_EVENT;
ev->key_event.key = ch;
qe_handle_event(ev);
switch(ch) {
case 'A': ch = KEY_F1; goto the_end;
case 'B': ch = KEY_F2; goto the_end;
case 'C': ch = KEY_F3; goto the_end;
case 'D': ch = KEY_F4; goto the_end;
case 'E': ch = KEY_F5; goto the_end;
}
break;
case IS_ESC2: // "\EO"
/* xterm/vt100 fn */
ts->input_state = IS_NORM;
switch(ch) {
case 'A': ch = KEY_UP; goto the_end;
case 'B': ch = KEY_DOWN; goto the_end;
case 'C': ch = KEY_RIGHT; goto the_end;
case 'D': ch = KEY_LEFT; goto the_end;
case 'P': ch = KEY_F1; goto the_end;
case 'Q': ch = KEY_F2; goto the_end;
case 'R': ch = KEY_F3; goto the_end;
case 'S': ch = KEY_F4; goto the_end;
case 't': ch = KEY_F5; goto the_end;
case 'u': ch = KEY_F6; goto the_end;
case 'v': ch = KEY_F7; goto the_end;
case 'l': ch = KEY_F8; goto the_end;
case 'w': ch = KEY_F9; goto the_end;
case 'x': ch = KEY_F10; goto the_end;
}
break;
the_end:
ev->key_event.type = QE_KEY_EVENT;
ev->key_event.key = ch;
qe_handle_event(ev);
break;
}
}
@ -577,6 +672,7 @@ static QEDisplay tty_dpy = {
term_set_clip,
NULL, /* no selection handling */
NULL, /* no selection handling */
term_invalidate,
};
static int tty_init(void)

183
util.c
View file

@ -466,64 +466,95 @@ int css_get_enum(const char *str, const char *enum_str)
}
unsigned short keycodes[] = {
KEY_LEFT,
KEY_RIGHT,
KEY_UP,
KEY_DOWN,
KEY_CTRL_LEFT,
KEY_CTRL_RIGHT,
KEY_CTRL_UP,
KEY_CTRL_DOWN,
KEY_CTRL_HOME,
KEY_CTRL_END,
KEY_CTRL(' '),
KEY_CTRL('\\'),
KEY_CTRL(']'),
KEY_CTRL('^'),
KEY_CTRL('_'),
KEY_BACKSPACE,
KEY_INSERT,
KEY_DELETE,
KEY_PAGEUP,
KEY_PAGEDOWN,
KEY_HOME,
KEY_END,
' ',
KEY_RET,
KEY_ESC,
KEY_TAB,
KEY_SHIFT_TAB,
KEY_DEFAULT,
KEY_SPC, KEY_DEL, KEY_RET, KEY_ESC, KEY_TAB, KEY_SHIFT_TAB,
KEY_CTRL(' '), KEY_DEL, KEY_CTRL('\\'),
KEY_CTRL(']'), KEY_CTRL('^'), KEY_CTRL('_'),
KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN,
KEY_HOME, KEY_END, KEY_PAGEUP, KEY_PAGEDOWN,
KEY_CTRL_LEFT, KEY_CTRL_RIGHT, KEY_CTRL_UP, KEY_CTRL_DOWN,
KEY_CTRL_HOME, KEY_CTRL_END, KEY_CTRL_PAGEUP, KEY_CTRL_PAGEDOWN,
KEY_PAGEUP, KEY_PAGEDOWN, KEY_CTRL_PAGEUP, KEY_CTRL_PAGEDOWN,
KEY_INSERT, KEY_DELETE, KEY_DEFAULT,
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,
KEY_F11, KEY_F12, KEY_F13, KEY_F14, KEY_F15,
KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20,
};
const char *keystr[] = {
"SPC", "DEL", "RET", "ESC", "TAB", "S-TAB",
"C-SPC", "C-?", "C-\\", "C-]", "C-^", "C-_",
"left", "right", "up", "down",
"C-left", "C-right", "C-up", "C-down",
"C-home", "C-end",
"C-space", "C-\\", "C-]", "C-^", "C-_",
"backspace", "insert", "delete", "prior", "next",
"home", "end",
"SPC", "RET", "ESC",
"TAB", "S-TAB",
"default",
"home", "end", "prior", "next",
"C-left", "C-right", "C-up", "C-down",
"C-home", "C-end", "C-prior", "C-next",
"pageup", "pagedown", "C-pageup", "C-pagedown",
"insert", "delete", "default",
"f1", "f2", "f3", "f4", "f5",
"f6", "f7", "f8", "f9", "f10",
"f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20",
};
static int strtokey1(const char *p)
int compose_keys(int *keys, int *nb_keys)
{
int i, n;
int *keyp;
for (i = 0; i < (int)(sizeof(keycodes)/sizeof(keycodes[0])); i++) {
if (!strcmp(p, keystr[i]))
return keycodes[i];
if (*nb_keys < 2)
return 0;
/* compose KEY_ESC as META prefix */
keyp = keys + *nb_keys - 2;
if (keyp[0] == KEY_ESC) {
if (keyp[1] <= 0xff) {
keyp[0] = KEY_META(keyp[1]);
--*nb_keys;
return 1;
}
}
return 0;
}
/* CG: this code is still quite inelegant */
static int strtokey1(const char **pp)
{
const char *p, *p1, *q;
int i, key;
/* should return KEY_NONE at end and KEY_UNKNOWN if unrecognized */
p = *pp;
/* scan for separator */
for (p1 = p; *p1 && *p1 != ' '; p1++)
continue;
for (i = 0; i < sizeof(keycodes)/sizeof(keycodes[0]); i++) {
if (strstart(p, keystr[i], &q) && q == p1) {
key = keycodes[i];
*pp = p1;
return key;
}
}
#if 0
if (p[0] == 'f' && p[1] >= '1' && p[1] <= '9') {
p++;
n = *p - '0';
if (isdigit((unsigned char)p[1]))
n = n * 10 + p[1] - '0';
return KEY_F1 + n - 1;
i = p[1] - '0';
p += 2;
if (p1 == isdigit((unsigned char)*p))
i = i * 10 + *p++ - '0';
key = KEY_F1 + i - 1;
*pp = p1;
return key;
}
return utf8_decode(&p);
#endif
if (p[0] == 'C' && p[1] == '-' && p1 == p + 3) {
/* control */
key = KEY_CTRL(p[2]);
} else {
key = utf8_decode(&p);
}
*pp = p1;
return key;
}
int strtokey(const char **pp)
@ -531,29 +562,42 @@ int strtokey(const char **pp)
const char *p;
int key;
/* XXX: handle all cases */
p = *pp;
if (p[0] == 'C' && p[1] == '-') {
/* control */
if (p[0] == 'M' && p[1] == '-') {
p += 2;
key = strtokey1(p);
if (key >= 'a' && key <= 'z')
key = KEY_CTRL(key);
} else if (p[0] == 'M' && p[1] == '-') {
p += 2;
key = strtokey1(p);
if ((key >= 'a' && key <= 'z') ||
key == KEY_BACKSPACE)
key = KEY_META(key);
key = KEY_META(strtokey1(&p));
} else
if (p[0] == 'C' && p[1] == '-' && p[0] == 'M' && p[1] == '-') {
p += 4;
key = KEY_META(KEY_CTRL(strtokey1(&p)));
} else {
key = strtokey1(p);
key = strtokey1(&p);
}
while (*p != ' ' && *p != '\0')
p++;
*pp = p;
return key;
}
int strtokeys(const char *keystr, unsigned int *keys, int max_keys)
{
int key, nb_keys;
const char *p;
p = keystr;
nb_keys = 0;
for (;;) {
skip_spaces(&p);
if (*p == '\0')
break;
key = strtokey(&p);
keys[nb_keys++] = key;
compose_keys(keys, &nb_keys);
if (nb_keys >= max_keys)
break;
}
return nb_keys;
}
void keytostr(char *buf, int buf_size, int key)
{
int i;
@ -565,18 +609,21 @@ void keytostr(char *buf, int buf_size, int key)
return;
}
}
if (key >= KEY_META(' ') && key <= KEY_META(127)) {
if (key >= KEY_META(0) && key <= KEY_META(0xff)) {
keytostr(buf1, sizeof(buf1), key & 0xff);
snprintf(buf, buf_size, "M-%s", buf1);
} else if (key >= 1 && key <= 31) {
} else if (key >= KEY_CTRL('a') && key <= KEY_CTRL('z')) {
snprintf(buf, buf_size, "C-%c", key + 'a' - 1);
} else if (key >= KEY_F1 && key <= KEY_F12) {
snprintf(buf, buf_size, "F%d", key - KEY_F1 + 1);
} else if (key >= KEY_F1 && key <= KEY_F20) {
snprintf(buf, buf_size, "f%d", key - KEY_F1 + 1);
} else if (key > 32 && key < 127 && buf_size >= 2) {
buf[0] = key;
buf[1] = '\0';
} else {
char *q;
/* CG: assuming buf_size > 5 */
q = utf8_encode(buf, key);
q = utf8_encode(buf1, key);
*q = '\0';
pstrcpy(buf, buf_size, buf1);
}
}

View file

@ -268,7 +268,7 @@ LRESULT CALLBACK qe_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch(scan) {
case 0x00E:
ignore_wchar_msg = 1;
push_key(KEY_BACKSPACE);
push_key(KEY_DEL);
break;
case 0x039: /* space */
ignore_wchar_msg = 1;

5
x11.c
View file

@ -1285,7 +1285,7 @@ static void x11_handle_event(void *opaque)
} else if (meta) {
switch(keysym) {
case XK_BackSpace:
key = KEY_META(KEY_BACKSPACE);
key = KEY_META(KEY_DEL);
goto got_key;
default:
if (keysym >= ' ' && keysym <= '~') {
@ -1323,7 +1323,7 @@ static void x11_handle_event(void *opaque)
key = KEY_LEFT;
goto got_key;
case XK_BackSpace:
key = KEY_BACKSPACE;
key = KEY_DEL;
goto got_key;
case XK_Insert:
key = KEY_INSERT;
@ -1676,6 +1676,7 @@ static QEDisplay x11_dpy = {
term_set_clip,
term_selection_activate,
term_selection_request,
NULL,
x11_bmp_alloc,
x11_bmp_free,
x11_bmp_draw,