Greatly simplified keyboard handling. - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
(DIR) commit d16e3252dccaf9fe42dcaccdb0f41ca955689acc
(DIR) parent 35ebbbec7c409c8852a3f16fe2d401ab39fcef87
(HTM) Author: Rob King <jking@deadpixi.com>
Date: Thu, 11 Aug 2016 19:49:27 -0500
Greatly simplified keyboard handling.
Diffstat:
config.h | 3 ---
include/commands.h | 26 ++++++++++++++++++++++++++
include/libg.h | 8 ++------
libXg/gwin.c | 152 ++++++++++++++++++++-----------
libXg/xtbinit.c | 4 ++--
samterm/io.c | 8 +-------
samterm/main.c | 462 ++++++++++++++++++-------------
samterm/samterm.h | 1 -
8 files changed, 408 insertions(+), 256 deletions(-)
---
(DIR) diff --git a/config.h b/config.h
@@ -19,9 +19,6 @@
#define CHARLEFT 0x13 /* Ctrl-S */
#define CHARRIGHT 0x04 /* Ctrl-D */
#define COMMANDKEY 0x0B /* Ctrl-K */
-#define SCROLLKEY 0x80 /* Scroll down. */
-#define UPKEY 0x81 /* Scroll up. */
-#define ESC 0x1B /* Escape */
/* The remote shell to use for remote connections. */
#define RXPATH "/usr/bin/ssh"
(DIR) diff --git a/include/commands.h b/include/commands.h
@@ -0,0 +1,26 @@
+#ifndef _COMMANDS_H
+#define _COMMANDS_H
+
+enum{
+ Knone,
+ Kraw,
+ Kcomposed,
+ Kcommand
+};
+
+enum{
+ Cescape,
+ Cscrolldown,
+ Cscrollup,
+ Cjump,
+ Ccharright,
+ Ccharleft,
+ Clinedown,
+ Clineup,
+ Cdelword,
+ Cdelbol,
+ Cdel,
+ Cmax
+}; /* virtual command keystrokes */
+
+#endif
(DIR) diff --git a/include/libg.h b/include/libg.h
@@ -13,6 +13,8 @@
#include <X11/Xft/Xft.h>
#undef Cursor
+#include <commands.h>
+
enum{ EMAXMSG = 128+8192 }; /* max event size */
/*
@@ -59,12 +61,6 @@ struct Mouse
unsigned long msec;
};
-enum{
- Kraw,
- Kcomposed,
- Kcommand
-};
-
struct Keystroke
{
int k;
(DIR) diff --git a/libXg/gwin.c b/libXg/gwin.c
@@ -19,6 +19,8 @@ typedef char* caddr_t;
#endif
#include "GwinP.h"
+#include "../config.h"
+#include <commands.h>
/* Forward declarations */
static void Realize(Widget, XtValueMask *, XSetWindowAttributes *);
@@ -170,6 +172,7 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
static unsigned char compose[5];
static int composing = -2;
int composed = 0;
+ int kind = Kraw;
int c, minmod;
KeySym k, mk;
@@ -212,58 +215,78 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
}
if(k == NoSymbol)
return;
- if(k&0xFF00){
- switch(k){
- case XK_BackSpace:
- case XK_Tab:
- case XK_Escape:
- case XK_Delete:
- case XK_KP_0:
- case XK_KP_1:
- case XK_KP_2:
- case XK_KP_3:
- case XK_KP_4:
- case XK_KP_5:
- case XK_KP_6:
- case XK_KP_7:
- case XK_KP_8:
- case XK_KP_9:
- case XK_KP_Divide:
- case XK_KP_Multiply:
- case XK_KP_Subtract:
- case XK_KP_Add:
- case XK_KP_Decimal:
- k &= 0x7F;
- break;
- case XK_Linefeed:
- k = '\r';
- break;
- case XK_KP_Enter:
- case XK_Return:
- k = '\n';
- break;
- case XK_Left:
- case XK_Down:
- case XK_Right:
- case XK_Next:
- k = 0x80; /* VIEW -- "Scroll" */
- break;
- case XK_Up:
- case XK_Prior:
- k = 0x81; /* PREVIEW -- "Scroll back" */
- break;
- default:
- return; /* not ISO-1 or tty control */
- }
- }
+
+ if (k & 0xFF00){
+ switch(k){
+ case XK_Escape:
+ kind = Kcommand;
+ k = Cescape;
+ break;
+
+ case XK_BackSpace:
+ case XK_Delete:
+ kind = Kcommand;
+ k = Cdel;
+ break;
+
+ case XK_Tab:
+ case XK_KP_0:
+ case XK_KP_1:
+ case XK_KP_2:
+ case XK_KP_3:
+ case XK_KP_4:
+ case XK_KP_5:
+ case XK_KP_6:
+ case XK_KP_7:
+ case XK_KP_8:
+ case XK_KP_9:
+ case XK_KP_Divide:
+ case XK_KP_Multiply:
+ case XK_KP_Subtract:
+ case XK_KP_Add:
+ case XK_KP_Decimal:
+ k &= 0x7F;
+ break;
+
+ case XK_Linefeed:
+ k = '\r';
+ break;
+
+ case XK_KP_Enter:
+ case XK_Return:
+ k = '\n';
+ break;
+
+ case XK_Up:
+ case XK_Prior:
+ case XK_Left:
+ kind = Kcommand;
+ k = Cscrollup;
+ break;
+
+ case XK_Right:
+ case XK_Next:
+ case XK_Down:
+ kind = Kcommand;
+ k = Cscrolldown;
+ break;
+
+ default:
+ return; /* not ISO-1 or tty control */
+ }
+ }
+
/* Compensate for servers that call a minus a hyphen */
- if(k == XK_hyphen)
- k = XK_minus;
+ if (k == XK_hyphen)
+ k = XK_minus;
+
/* Do control mapping ourselves if translator doesn't */
- if((e->xkey.state&ControlMask) && !(md&ControlMask))
- k &= 0x9f;
- if(k == NoSymbol)
- return;
+ if ((e->xkey.state & ControlMask) && !(md & ControlMask))
+ k &= 0x9f;
+
+ if(k == NoSymbol)
+ return;
+
/* Check to see if we are in a composition sequence */
if (!((GwinWidget)w)->gwin.compose && (e->xkey.state & Mod1Mask)
&& composing == -2)
@@ -306,9 +329,36 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
if (composing >= -1)
return;
+ switch (c){
+ case LINEUP:
+ kind = Kcommand;
+ c = Clineup;
+ break;
+
+ case LINEDOWN:
+ kind = Kcommand;
+ c = Clinedown;
+ break;
+
+ case CHARLEFT:
+ kind = Kcommand;
+ c = Ccharleft;
+ break;
+
+ case CHARRIGHT:
+ kind = Kcommand;
+ c = Ccharright;
+ break;
+
+ case COMMANDKEY:
+ kind = Kcommand;
+ c = Cjump;
+ break;
+ }
+
f = ((GwinWidget)w)->gwin.gotchar;
if(f)
- (*f)(c, composed);
+ (*f)(c, kind);
}
static void
(DIR) diff --git a/libXg/xtbinit.c b/libXg/xtbinit.c
@@ -273,7 +273,7 @@ reshaped(int minx, int miny, int maxx, int maxy)
}
static void
-gotchar(int c, int composed)
+gotchar(int c, int kind)
{
Ebuf *eb;
Keystroke k;
@@ -284,7 +284,7 @@ gotchar(int c, int composed)
if (eb == 0)
berror("eballoc can't malloc");
k.c = c;
- k.k = composed ? Kcomposed : Kraw;
+ k.k = kind;
memcpy(eb->buf, &k, sizeof(Keystroke));
esrc[Skeyboard].count++;
}
(DIR) diff --git a/samterm/io.c b/samterm/io.c
@@ -156,7 +156,7 @@ kbdchar(void)
return k;
if(got & Ekeyboard){
k = keystroke;
- keystroke.c = -1;
+ memset(&keystroke, 0, sizeof(keystroke));
got &= ~Ekeyboard;
return k;
}
@@ -174,12 +174,6 @@ kbdchar(void)
return ekbd();
}
-int
-qpeekc(void)
-{
- return keystroke.c;
-}
-
void
ereshaped(Rectangle r)
{
(DIR) diff --git a/samterm/main.c b/samterm/main.c
@@ -6,6 +6,7 @@
#include <unistd.h>
#include "flayer.h"
#include "samterm.h"
+#include <commands.h>
Text cmd;
Rune *scratch;
@@ -470,58 +471,259 @@ flushtyping(int clearesc)
XFlush(_dpy);
}
+long
+cmdscrolldown(Flayer *l, long a, Text *t)
+{
+ flushtyping(0);
+ center(l, l->origin + l->f.nchars + 1);
+ return a;
+}
+
+long
+cmdscrollup(Flayer *l, long a, Text *t)
+{
+ flushtyping(0);
+ outTsll(Torigin, t->tag, l->origin, l->f.maxlines + 1);
+ return a;
+}
+
+long
+cmdcharleft(Flayer *l, long a, Text *t)
+{
+ flsetselect(l, a, a);
+ flushtyping(0);
+ if (a > 0)
+ a--;
+ flsetselect(l, a, a);
+ center(l, a);
+
+ return a;
+}
+
+long
+cmdcharright(Flayer *l, long a, Text *t)
+{
+ flsetselect(l, a, a);
+ flushtyping(0);
+ if (a < t->rasp.nrunes)
+ a++;
+ flsetselect(l, a, a);
+ center(l, a);
+
+ return a;
+}
+
+long
+cmdlineup(Flayer *l, long a, Text *t)
+{
+ flsetselect(l, a, a);
+ flushtyping(1);
+ if (a > 0){
+ long n0, n1, count = 0;
+ while (a > 0 && raspc(&t->rasp, a - 1) != '\n'){
+ a--;
+ count++;
+ }
+ if (a > 0){
+ n1 = a;
+ a--;
+ while (a > 0 && raspc(&t->rasp, a - 1) != '\n')
+ a--;
+
+ n0 = a;
+ a = (n0 + count >= n1) ? n1 - 1 : n0 + count;
+ flsetselect(l, a, a);
+ center(l, a);
+ }
+ }
+
+ return a;
+}
+
+long
+cmdlinedown(Flayer *l, long a, Text *t)
+{
+ flsetselect(l, a, a);
+ flushtyping(1);
+ if (a < t->rasp.nrunes){
+ long p0, count = 0;
+
+ p0 = a;
+ while (a > 0 && raspc(&t->rasp, a - 1) != '\n'){
+ a--;
+ count++;
+ }
+
+ a = p0;
+ while (a < t->rasp.nrunes && raspc(&t->rasp, a) != '\n')
+ a++;
+
+ if (a < t->rasp.nrunes){
+ a++;
+ while (a < t->rasp.nrunes && count > 0 && raspc(&t->rasp, a) != '\n'){
+ a++;
+ count--;
+ }
+ if (a != p0){
+ flsetselect(l, a, a);
+ center(l, a);
+ }
+ }
+ }
+
+ return a;
+}
+
+long
+cmdjump(Flayer *l, long a, Text *u)
+{
+ Text *t = NULL;
+
+ if (which == &cmd.l[cmd.front] && flast)
+ current(flast);
+ else{
+ l = &cmd.l[cmd.front];
+ t = (Text *)l->user1;
+ flast = which;
+ current(l);
+ flushtyping(0);
+ flsetselect(l, t->rasp.nrunes, t->rasp.nrunes);
+ center(l, a);
+ }
+
+ return a;
+}
+
+long
+cmdescape(Flayer *l, long a, Text *t)
+{
+ if (typeesc >= 0){
+ l->p0 = typeesc;
+ l->p1 = a;
+ flushtyping(1);
+ }
+
+ for (l = t->l; l < &t->l[NL]; l++)
+ if (l->textfn)
+ flsetselect(l, l->p0, l->p1);
+
+ return a;
+}
+
+long
+cmddelword(Flayer *l, long a, Text *t)
+{
+ if (l->f.p0 > 0 && a > 0)
+ l->p0 = ctlw(&t->rasp, l->origin, a);
+
+ l->p1 = a;
+ if (l->p1 != l->p0){
+ if(typestart<=l->p0 && l->p1<=typeend){
+ t->lock++; /* to call hcut */
+ hcut(t->tag, l->p0, l->p1-l->p0);
+ /* hcheck is local because we know rasp is contiguous */
+ hcheck(t->tag);
+ }else{
+ flushtyping(0);
+ cut(t, t->front, 0, 1);
+ }
+ }
+
+ return a;
+}
+
+long
+cmddelbol(Flayer *l, long a, Text *t)
+{
+ if (l->f.p0 > 0 && a > 0)
+ l->p0 = ctlu(&t->rasp, l->origin, a);
+
+ l->p1 = a;
+ if (l->p1 != l->p0){
+ if(typestart<=l->p0 && l->p1<=typeend){
+ t->lock++; /* to call hcut */
+ hcut(t->tag, l->p0, l->p1-l->p0);
+ /* hcheck is local because we know rasp is contiguous */
+ hcheck(t->tag);
+ }else{
+ flushtyping(0);
+ cut(t, t->front, 0, 1);
+ }
+ }
+
+ return a;
+}
+
+long
+cmddel(Flayer *l, long a, Text *t)
+{
+ if (l->f.p0 > 0 && a > 0)
+ l->p0 = a - 1;
+
+ l->p1 = a;
+ if (l->p1 != l->p0){
+ if(typestart<=l->p0 && l->p1<=typeend){
+ t->lock++; /* to call hcut */
+ hcut(t->tag, l->p0, l->p1-l->p0);
+ /* hcheck is local because we know rasp is contiguous */
+ hcheck(t->tag);
+ }else{
+ flushtyping(0);
+ cut(t, t->front, 0, 1);
+ }
+ }
+
+ return a;
+}
+
+typedef long (*Commandfunc)(Flayer *, long, Text *);
+typedef struct CommandEntry CommandEntry;
+struct CommandEntry{
+ Commandfunc f;
+ int lock;
+};
+
+CommandEntry commands[Cmax] ={
+ [Cscrolldown] = {cmdscrolldown, 0},
+ [Cscrollup] = {cmdscrollup, 0},
+ [Ccharleft] = {cmdcharleft, 0},
+ [Ccharright] = {cmdcharright, 0},
+ [Clineup] = {cmdlineup, 0},
+ [Clinedown] = {cmdlinedown, 0},
+ [Cjump] = {cmdjump, 0},
+ [Cescape] = {cmdescape, 0},
+ [Cdelword] = {cmddelword, 1},
+ [Cdelbol] = {cmddelbol, 1},
+ [Cdel] = {cmddel, 1}
+};
+
void
type(Flayer *l, int res) /* what a bloody mess this is */
{
Text *t = (Text *)l->user1;
Rune buf[100];
- Keystroke k;
+ Keystroke k = {0};
Rune *p = buf;
- int c, backspacing, moving;
+ int backspacing, moving;
long a;
- int scrollkey, upkey, movekey;
-
- scrollkey = 0;
- upkey = 0;
- movekey = 0;
- if(res == RKeyboard) {
- int pc = qpeekc();
- scrollkey = pc==SCROLLKEY; /* ICK */
- upkey = pc == UPKEY;
- movekey = (pc == CHARLEFT || pc == CHARRIGHT || pc == LINEUP || pc == LINEDOWN || pc == COMMANDKEY);
- }
if(lock || t->lock){
kbdblock();
return;
}
+
a = l->p0;
- if(a!=l->p1 && !scrollkey && !upkey && !movekey){
+ if (a != l->p1 && k.k != Kcommand){
flushtyping(1);
cut(t, t->front, 1, 1);
return; /* it may now be locked */
}
- backspacing = 0;
- moving = 0;
- while(((k = kbdchar()), k.c) > 0){
- c = k.c;
- if(res == RKeyboard){
- if(c == UPKEY || c==SCROLLKEY || c==ESC || c==COMMANDKEY)
- break;
-
- /* ctrl-s, ctrl-e, ctrl-d, ctrl-x */
- if (c==CHARLEFT || c==CHARRIGHT || c==LINEUP || c==LINEDOWN){
- moving = 1;
- break;
- }
- /* backspace, ctrl-u, ctrl-w, del */
- if(c=='\b' || c==0x15 || c==0x17 || c==0x7F){
- backspacing = 1;
- break;
- }
- }
- if (expandtabs && c == '\t' && k.k != Kcomposed){
+ while (((k = kbdchar()), k.c) > 0) {
+ if (k.k == Kcommand)
+ break;
+
+ if (expandtabs && k.c == '\t' && k.k != Kcomposed){
int col = 0, nspaces = 8, off = a;
int i;
while (off > 0 && raspc(&t->rasp, off - 1) != '\n')
@@ -532,164 +734,52 @@ type(Flayer *l, int res) /* what a bloody mess this is */
pushkbd(' ');
break;
}
- *p++ = c;
- if(c == '\n' || p >= buf+sizeof(buf)/sizeof(buf[0]))
+
+ *p++ = k.c;
+ if (k.c == '\n' || p >= buf + sizeof(buf) / sizeof(buf[0]))
break;
}
- if(p > buf){
- if(typestart < 0)
- typestart = a;
- if(typeesc < 0)
- typeesc = a;
- hgrow(t->tag, a, p-buf, 0);
- t->lock++; /* pretend we Trequest'ed for hdatarune*/
- hdatarune(t->tag, a, buf, p-buf);
- a += p-buf;
- l->p0 = a;
- l->p1 = a;
- typeend = a;
- if(c=='\n' || typeend-typestart>100)
- flushtyping(0);
- onethird(l, a);
- }
- if(c == SCROLLKEY){
- flushtyping(0);
- center(l, l->origin+l->f.nchars+1);
- } else if (c == UPKEY) {
- flushtyping(0);
- outTsll(Torigin, t->tag, l->origin, l->f.maxlines+1);
- /* backspacing immediately after outcmd(): sorry */
- } else if (moving){
- if (c == CHARLEFT){
- flsetselect(l, a, a);
- flushtyping(0);
- if (a > 0)
- a--;
- flsetselect(l, a, a);
- center(l, a);
- } else if (c == CHARRIGHT){
- flsetselect(l, a, a);
+
+ if (p > buf){
+ if (typestart < 0)
+ typestart = a;
+
+ if (typeesc < 0)
+ typeesc = a;
+
+ hgrow(t->tag, a, p-buf, 0);
+ t->lock++; /* pretend we Trequest'ed for hdatarune*/
+ hdatarune(t->tag, a, buf, p-buf);
+ a += p-buf;
+ l->p0 = a;
+ l->p1 = a;
+ typeend = a;
+ if (k.c == '\n' || typeend - typestart > 100)
flushtyping(0);
- if (a < t->rasp.nrunes)
- a++;
- flsetselect(l, a, a);
- center(l, a);
- } else if (c == LINEUP){
- flsetselect(l, a, a);
- flushtyping(1);
- if (a > 0){
- long n0, n1, count = 0;
- while (a > 0 && raspc(&t->rasp, a - 1) != '\n'){
- a--;
- count++;
- }
- if (a > 0){
- n1 = a;
- a--;
- while (a > 0 && raspc(&t->rasp, a - 1) != '\n')
- a--;
-
- n0 = a;
- a = (n0 + count >= n1) ? n1 - 1 : n0 + count;
- flsetselect(l, a, a);
- center(l, a);
- }
- }
- } else if (c == LINEDOWN){
- flsetselect(l, a, a);
- flushtyping(1);
- if (a < t->rasp.nrunes){
- long p0, count = 0;
-
- p0 = a;
- while (a > 0 && raspc(&t->rasp, a - 1) != '\n'){
- a--;
- count++;
- }
-
- a = p0;
- while (a < t->rasp.nrunes && raspc(&t->rasp, a) != '\n')
- a++;
-
- if (a < t->rasp.nrunes){
- a++;
- while (a < t->rasp.nrunes && count > 0 && raspc(&t->rasp, a) != '\n'){
- a++;
- count--;
- }
- if (a != p0){
- flsetselect(l, a, a);
- center(l, a);
- }
- }
- }
+ onethird(l, a);
+ }
+
+ if (k.k == Kcommand){
+ CommandEntry *e = &commands[k.k];
+ if (e->lock == 0 || !lock)
+ a = e->f(l, a, t);
+ }
+
+ if (typeesc >= l->p0)
+ typeesc = l->p0;
+
+ if (typestart >= 0){
+ if(typestart >= l->p0)
+ typestart = l->p0;
+ typeend = l->p0;
+ if (typestart == typeend){
+ typestart = -1;
+ typeend = -1;
+ modified = 0;
}
- }else if(backspacing && !lock){
- if(l->f.p0>0 && a>0){
- switch(c){
- case '\b':
- case 0x7F: /* del */
- l->p0 = a-1;
- break;
- case 0x15: /* ctrl-u */
- l->p0 = ctlu(&t->rasp, l->origin, a);
- break;
- case 0x17: /* ctrl-w */
- l->p0 = ctlw(&t->rasp, l->origin, a);
- break;
- }
- l->p1 = a;
- if(l->p1 != l->p0){
- /* cut locally if possible */
- if(typestart<=l->p0 && l->p1<=typeend){
- t->lock++; /* to call hcut */
- hcut(t->tag, l->p0, l->p1-l->p0);
- /* hcheck is local because we know rasp is contiguous */
- hcheck(t->tag);
- }else{
- flushtyping(0);
- cut(t, t->front, 0, 1);
- }
- }
- if(typeesc >= l->p0)
- typeesc = l->p0;
- if(typestart >= 0){
- if(typestart >= l->p0)
- typestart = l->p0;
- typeend = l->p0;
- if(typestart == typeend){
- typestart = -1;
- typeend = -1;
- modified = 0;
- }
- }
- }
- }else if(c==COMMANDKEY){
- if(which == &cmd.l[cmd.front]){
- if (flast)
- current(flast);
- }else{
- l = &cmd.l[cmd.front];
- Text *t = (Text *)l->user1;
- flast = which;
- current(l);
- flushtyping(0);
- flsetselect(l, t->rasp.nrunes, t->rasp.nrunes);
- center(l, a);
- }
- }else{
- if(c==ESC && typeesc>=0){
- l->p0 = typeesc;
- l->p1 = a;
- flushtyping(1);
- }
- for(l=t->l; l<&t->l[NL]; l++)
- if(l->textfn)
- flsetselect(l, l->p0, l->p1);
- }
+ }
}
-
void
outcmd(void){
if(work)
(DIR) diff --git a/samterm/samterm.h b/samterm/samterm.h
@@ -91,7 +91,6 @@ int waitforio(void);
int rcvchar(void);
int getch(void);
Keystroke kbdchar(void);
-int qpeekc(void);
void mouseexit(void);
void cut(Text*, int, int, int);
void paste(Text*, int);