commit 0c79c32675e83ff3d87d5bf52082652d85486a45
parent 60ca2be037f739e30daba1dc5b66a166fcdc0bf2
Author: Russ Cox <rsc@golang.org>
Date: Sat, 15 Jun 2024 10:55:21 -0400
acme: shift button 3 for reverse search
An experiment. Let's see if it's any good.
Also document the Mac conventions in devdraw(3).
Diffstat:
14 files changed, 269 insertions(+), 99 deletions(-)
diff --git a/man/man1/0intro.1 b/man/man1/0intro.1
@@ -29,7 +29,7 @@ conventionally
When programs need to access files in the tree,
they expect the
.B $PLAN9
-environment variable
+environment variable
to contain the name of the root of the tree.
See
.MR install (1)
@@ -57,7 +57,7 @@ expect Plan 9 regular expressions
(see
.MR regexp (7) ),
which are closest to what Unix calls extended regular expressions.
-Because of these differences, it is not recommended to put
+Because of these differences, it is not recommended to put
.B $PLAN9/bin
before the usual system
.B bin
@@ -99,6 +99,11 @@ The argument is one of
\fL'\fIxmin ymin xmax ymax\fL'\fR,
\fRor
\fIxmin\fL,\fIymin\fL,\fIxmax\fL,\fIymax\fR.
+See
+.MR devdraw (1)
+and
+.MR keyboard (7)
+for details about typing and clicking in graphical applications.
.PP
The
.MR plumber (4)
@@ -135,7 +140,7 @@ is an experimental client for acme.
Some programs rely on large databases that would be
cumbersome to include in every release.
Scripts are provided that download these databases separately.
-These databases can be downloaded separately.
+These databases can be downloaded separately.
See
.B $PLAN9/dict/README
and
@@ -148,7 +153,7 @@ and
(see
.MR 9c (1) )
provide a simple interface to the underlying system compiler and linker,
-similar to the
+similar to the
.I 2c
and
.I 2l
@@ -201,7 +206,7 @@ cannot)
and dump data structures,
but that it is the extent to which they have been developed and exercised.
.SS Porting programs
-The vast majority of the familiar Plan 9 programs
+The vast majority of the familiar Plan 9 programs
have been ported, including the Unicode-aware
.MR troff (1) .
.PP
@@ -222,7 +227,7 @@ is in progress; see
.SS Porting to new systems
Porting the tree to new operating systems or architectures
should be straightforward, as system-specific code has been
-kept to a minimum.
+kept to a minimum.
The largest pieces of system-specific code are
.BR <u.h> ,
which must include the right system files and
@@ -231,7 +236,7 @@ and
.IR libthread ,
which must implement spin locks, operating system thread
creation, and context switching routines.
-Portable implementations of these using
+Portable implementations of these using
.B <pthread.h>
and
.B <ucontext.h>
@@ -259,7 +264,7 @@ so that the Unix
utility can handle it.
Some systems, for example Debian Linux,
deduce the man page locations from the search path, so that
-adding
+adding
.B $PLAN9/bin
to your path is sufficient to cause
.B $PLAN9/man
diff --git a/man/man1/acme.1 b/man/man1/acme.1
@@ -588,6 +588,9 @@ not just
or
.BR 127 .
(There is an easier way to locate literal text; see below.)
+If shift is held down during the selection or click,
+any leading regular expression search defaults to
+searching backward in the text instead of forward.
.PP
If the text is a file name followed by a colon and an address,
.I acme
@@ -608,6 +611,8 @@ moved there. Thus, to search for occurrences of a word in a file,
just click button 3 on the word. Because of the rule of using the
selection as the button 3 action, subsequent clicks will find subsequent
occurrences without moving the mouse.
+If shift is held down during the selection or click,
+the search looks backward in the file.
.PP
In all these actions, the mouse motion is not done if the text is a null string
within a non-null selected string in the tag, so that (for example) complex regular expressions
diff --git a/man/man1/devdraw.1 b/man/man1/devdraw.1
@@ -2,7 +2,7 @@
.SH NAME
devdraw \- draw device simulator
.SH SYNOPSIS
-invoked via
+invoked via
.I initdraw
(see
.MR graphics (3) )
@@ -10,19 +10,71 @@ invoked via
.I Devdraw
serves a custom graphics protocol and is the only program
that talks directly to X window servers.
-On Macintosh, setting
-.BI devdrawretina
-to
-.BI 1
-will cause
-.I devdraw
-to use all available physical pixels on a retina display.
+.PP
+.SS "Apple macOS
+.PP
+On macOS, because a laptop trackpad click only has one button (the trackpad itself)
+Option-click is button 2, and Command-click is button 3.
+While the main mouse button is held down,
+Control, Option, and Command serve as simulated buttons 1, 2, 3 for chording in
+.MR acme (4) .
+For example, the 1-3 pasting chord in acme can be executed by
+highlighting text while holding down the trackpad button
+and then, while still holding down the button, pressing the Command key.
+.PP
+As usual, buttons 4 and 5 represent a scroll wheel.
+Two-finger scrolling on the trackpad sends those button events.
+.PP
+Holding down shift while clicking adds 5 to the button number.
+For example, Command-Click is button 3, so Command-Shift-Click is button 8.
+Most programs do not respond to those buttons; one notable exception is
+.MR acme (1) ,
+which interprets button 8 (shifted button 3) as a reverse search.
+.PP
+Typing Command-F toggles full screen mode.
+.PP
+.I Devdraw
+automatically detects high-resolution (retina) displays.
+For debugging, typing Command-R toggles retina mode.
+.PP
+Other than the special cases mentioned above,
+holding down Command while typing a character
+.B Kcmd
+(0xF100)
+plus that character.
+Some programs (notably
+.IR acme (1))
+recognize standard keyboard shortcuts such as
+Command-Z (undo), Command-Shift-Z (redo),
+Command-X (cut), and Command-V (paste).
+.SS "X Windows
+.PP
+On Unix systems, Control-click is mouse button 2,
+and Alt-click is mouse button 3.
+While the main mouse button is held down,
+Control and Alt serve as simulated buttons 2, 3 for chording in
+.MR acme (4) .
+For example, the 1-3 pasting chord in acme can be executed by
+highlighting text while holding down the trackpad button
+and then, while still holding down the button, pressing the Alt key.
+.PP
+Because the Control and Alt keys have other meanings
+(see
+.MR keyboard (7)
+for the Alt key's meaning)
+and there is no third modifier key like on the Mac,
+there is no way to type
+.B Kcmd
+variants,
+so there is no access to keyboard shortcuts for
+undo, redo, cut, and paste.
.SH SOURCE
.B \*9/src/cmd/devdraw
.SH "SEE ALSO
.MR draw (3) ,
.MR drawfcall (3) ,
-.MR graphics (3)
+.MR graphics (3) ,
+.MR keyboard (7)
.SH BUGS
.I Devdraw
should probably present a standard 9P server
diff --git a/man/man4/acme.4 b/man/man4/acme.4
@@ -361,6 +361,10 @@ for text inserted to the tag,
for a button 3 action in the body,
.B l
for a button 3 action in the tag,
+.B R
+for a shifted button 3 action in the body,
+.B r
+for a shifted button 3 action in the tag,
.B X
for a button 2 action in the body, and
.B x
diff --git a/man/man7/keyboard.7 b/man/man7/keyboard.7
@@ -62,16 +62,11 @@ Any rune can be typed using a compose key followed by several
other keys.
The compose key is also generally near the lower right of the main key area:
the
-.B NUM PAD
-key on the Gnot, the
-.B Alternate
-key on the Next, the
-.B Compose
-key on the SLC, the
.B Option
-key on the Magnum, and either
+key on the Mac
+and the
.B Alt
-key on the PC.
+key on Unix systems.
To type a single rune with the value specified by
a given four-digit hexadecimal number,
type the compose key,
diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c
@@ -1,4 +1,5 @@
#include <u.h>
+#include <pwd.h>
#include <signal.h>
#include <libc.h>
#include <ctype.h>
@@ -56,7 +57,7 @@ threadmaybackground(void)
void
threadmain(int argc, char *argv[])
{
- char *p;
+ char *p, *env;
rfork(RFNOTEG);
font = nil;
@@ -64,6 +65,25 @@ threadmain(int argc, char *argv[])
mainpid = getpid();
messagesize = 8192;
+ threadmaybackground();
+
+ env = getenv("__CFBundleIdentifier");
+ if(env != nil && strcmp(env, "com.swtch.9term") == 0) {
+ // Being invoked as $PLAN9/mac/9term.app.
+ // Set $SHELL and daemonize to let parent exit.
+ // This makes sure that each click on 9term
+ // brings up a new window.
+ extern void _threaddaemonize(void);
+ struct passwd *pw;
+
+ unsetenv("__CFBundleIdentifier");
+ pw = getpwuid(getuid());
+ if(pw != nil && pw->pw_shell != nil)
+ setenv("SHELL", pw->pw_shell, 1);
+ loginshell = TRUE;
+ //_threaddaemonize();
+ }
+
ARGBEGIN{
default:
usage();
diff --git a/src/cmd/acme/acme.c b/src/cmd/acme/acme.c
@@ -518,6 +518,7 @@ mousethread(void *v)
Mouse m;
char *act;
enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
+ enum { Shift = 5 };
static Alt alts[NMALT+1];
USED(v);
@@ -661,9 +662,9 @@ mousethread(void *v)
}else if(m.buttons & 2){
if(textselect2(t, &q0, &q1, &argt))
execute(t, q0, q1, FALSE, argt);
- }else if(m.buttons & 4){
+ }else if(m.buttons & (4|(4<<Shift))){
if(textselect3(t, &q0, &q1))
- look3(t, q0, q1, FALSE);
+ look3(t, q0, q1, FALSE, (m.buttons&(4<<Shift))!=0);
}
if(w)
winunlock(w);
@@ -770,7 +771,7 @@ waitthread(void *v)
pids = p;
}
}else{
- if(search(t, c->name, c->nname)){
+ if(search(t, c->name, c->nname, FALSE)){
textdelete(t, t->q0, t->q1, TRUE);
textsetselect(t, 0, 0);
}
diff --git a/src/cmd/acme/addr.c b/src/cmd/acme/addr.c
@@ -172,7 +172,7 @@ regexp(uint showerr, Text *t, Range lim, Range r, Rune *pat, int dir, int *found
}
Range
-address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp)
+address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, int (*getc)(void*, uint), int *evalp, uint *qp, int reverse)
{
int dir, size, npat;
int prevc, c, nc, n;
@@ -183,6 +183,8 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
r = ar;
q = q0;
dir = None;
+ if(reverse)
+ dir = Back;
size = Line;
c = 0;
while(q < q1){
@@ -201,7 +203,7 @@ address(uint showerr, Text *t, Range lim, Range ar, void *a, uint q0, uint q1, i
if(q>=q1 && t!=nil && t->file!=nil) /* rhs defaults to $ */
r.q1 = t->file->b.nc;
else{
- nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q);
+ nr = address(showerr, t, lim, ar, a, q, q1, getc, evalp, &q, FALSE);
r.q1 = nr.q1;
}
*qp = q;
diff --git a/src/cmd/acme/dat.h b/src/cmd/acme/dat.h
@@ -454,6 +454,7 @@ struct Expand
int nname;
char *bname;
int jump;
+ int reverse;
union{
Text *at;
Rune *ar;
diff --git a/src/cmd/acme/exec.c b/src/cmd/acme/exec.c
@@ -280,13 +280,14 @@ getarg(Text *argt, int doaddr, int dofile, Rune **rp, int *nrp)
Expand e;
char *a;
+ memset(&e, 0, sizeof e);
*rp = nil;
*nrp = 0;
if(argt == nil)
return nil;
a = nil;
textcommit(argt, TRUE);
- if(expand(argt, argt->q0, argt->q1, &e)){
+ if(expand(argt, argt->q0, argt->q1, &e, FALSE)){
free(e.bname);
if(e.nname && dofile){
e.name = runerealloc(e.name, e.nname+1);
@@ -1083,7 +1084,7 @@ look(Text *et, Text *t, Text *argt, int _0, int _1, Rune *arg, int narg)
if(et && et->w){
t = &et->w->body;
if(narg > 0){
- search(t, arg, narg);
+ search(t, arg, narg, FALSE);
return;
}
getarg(argt, FALSE, FALSE, &r, &n);
@@ -1092,7 +1093,7 @@ look(Text *et, Text *t, Text *argt, int _0, int _1, Rune *arg, int narg)
r = runemalloc(n);
bufread(&t->file->b, t->q0, r, n);
}
- search(t, r, n);
+ search(t, r, n, FALSE);
free(r);
}
}
diff --git a/src/cmd/acme/fns.h b/src/cmd/acme/fns.h
@@ -63,8 +63,8 @@ void fontx(Text*, Text*, Text*, int, int, Rune*, int);
#define isalnum acmeisalnum
int isalnum(Rune);
void execute(Text*, uint, uint, int, Text*);
-int search(Text*, Rune*, uint);
-void look3(Text*, uint, uint, int);
+int search(Text*, Rune*, uint, int);
+void look3(Text*, uint, uint, int, int);
void editcmd(Text*, Rune*, uint);
uint min(uint, uint);
uint max(uint, uint);
@@ -85,11 +85,11 @@ int isregexc(int);
void *emalloc(uint);
void *erealloc(void*, uint);
char *estrdup(char*);
-Range address(uint, Text*, Range, Range, void*, uint, uint, int (*)(void*, uint), int*, uint*);
+Range address(uint, Text*, Range, Range, void*, uint, uint, int (*)(void*, uint), int*, uint*, int);
int rxexecute(Text*, Rune*, uint, uint, Rangeset*);
int rxbexecute(Text*, uint, Rangeset*);
Window* makenewwindow(Text *t);
-int expand(Text*, uint, uint, Expand*);
+int expand(Text*, uint, uint, Expand*, int);
Rune* skipbl(Rune*, int, int*);
Rune* findbl(Rune*, int, int*);
char* edittext(Window*, int, Rune*, int);
diff --git a/src/cmd/acme/look.c b/src/cmd/acme/look.c
@@ -80,7 +80,7 @@ startplumbing(void)
void
-look3(Text *t, uint q0, uint q1, int external)
+look3(Text *t, uint q0, uint q1, int external, int reverse)
{
int n, c, f, expanded;
Text *ct;
@@ -94,7 +94,7 @@ look3(Text *t, uint q0, uint q1, int external)
ct = seltext;
if(ct == nil)
seltext = t;
- expanded = expand(t, q0, q1, &e);
+ expanded = expand(t, q0, q1, &e, reverse);
if(!external && t->w!=nil && t->w->nopen[QWevent]>0){
/* send alphanumeric expansion to external client */
if(expanded == FALSE)
@@ -109,6 +109,8 @@ look3(Text *t, uint q0, uint q1, int external)
c = 'l';
if(t->what == Body)
c = 'L';
+ if(reverse)
+ c += 'R' - 'L';
n = q1-q0;
if(n <= EVENTSIZE){
r = runemalloc(n);
@@ -203,12 +205,17 @@ look3(Text *t, uint q0, uint q1, int external)
ct = &t->w->body;
if(t->w != ct->w)
winlock(ct->w, 'M');
- if(t == ct)
- textsetselect(ct, e.q1, e.q1);
+ if(t == ct) {
+ uint q;
+ q = e.q1;
+ if(reverse)
+ q = e.q0;
+ textsetselect(ct, q, q);
+ }
n = e.q1 - e.q0;
r = runemalloc(n);
bufread(&t->file->b, e.q0, r, n);
- if(search(ct, r, n) && e.jump)
+ if(search(ct, r, n, reverse) && e.jump)
moveto(mousectl, addpt(frptofchar(&ct->fr, ct->fr.p0), Pt(4, ct->fr.font->height-4)));
if(t->w != ct->w)
winunlock(ct->w);
@@ -241,6 +248,7 @@ plumblook(Plumbmsg *m)
warning(nil, "insanely long file name (%d bytes) in plumb message (%.32s...)\n", m->ndata, m->data);
return;
}
+ memset(&e, 0, sizeof e);
e.q0 = 0;
e.q1 = 0;
if(m->data[0] == '\0')
@@ -303,11 +311,11 @@ plumbshow(Plumbmsg *m)
}
int
-search(Text *ct, Rune *r, uint n)
+search(Text *ct, Rune *r, uint n, int reverse)
{
- uint q, nb, maxn;
+ uint nb, maxn;
int around;
- Rune *s, *b, *c;
+ Rune *s, *b;
if(n==0 || n>ct->file->b.nc)
return FALSE;
@@ -321,55 +329,111 @@ search(Text *ct, Rune *r, uint n)
nb = 0;
b[nb] = 0;
around = 0;
- q = ct->q1;
- for(;;){
- if(q >= ct->file->b.nc){
- q = 0;
- around = 1;
- nb = 0;
- b[nb] = 0;
- }
- if(nb > 0){
- c = runestrchr(b, r[0]);
- if(c == nil){
- q += nb;
+ if(reverse){
+ uint q1;
+ q1 = ct->q0; // q1 is (past) end of text being searched.
+ for(;;){
+ if(q1 <= 0){
+ q1 = ct->file->b.nc;
+ around = 1;
nb = 0;
b[nb] = 0;
- if(around && q>=ct->q1)
- break;
- continue;
}
- q += (c-b);
- nb -= (c-b);
- b = c;
- }
- /* reload if buffer covers neither string nor rest of file */
- if(nb<n && nb!=ct->file->b.nc-q){
- nb = ct->file->b.nc-q;
- if(nb >= maxn)
- nb = maxn-1;
- bufread(&ct->file->b, q, s, nb);
- b = s;
- b[nb] = '\0';
+ if(nb > 0){
+ Rune *c;
+ for(c=b+nb; c>b; c--)
+ if(c[-1] == r[n-1])
+ break;
+ if(c == b) {
+ q1 -= nb;
+ nb = 0;
+ b[nb] = 0;
+ if(around && q1 <= 0)
+ break;
+ continue;
+ }
+ q1 -= nb - (c - b);
+ nb = c - b;
+ }
+ /* reload if buffer covers neither string nor beginning of file */
+ if(nb<n && nb!=q1){
+ nb = q1;
+ if(nb >= maxn)
+ nb = maxn-1;
+ bufread(&ct->file->b, q1-nb, s, nb);
+ b = s;
+ b[nb] = '\0';
+ }
+ if(runeeq(b+nb-n, n, r, n)==TRUE){
+ if(ct->w){
+ textshow(ct, q1-n, q1, 1);
+ winsettag(ct->w);
+ }else{
+ ct->q0 = q1-n;
+ ct->q1 = q1;
+ }
+ seltext = ct;
+ fbuffree(s);
+ return TRUE;
+ }
+ q1--;
+ nb--;
+ if(around && q1 <= 0)
+ break;
}
- /* this runeeq is fishy but the null at b[nb] makes it safe */
- if(runeeq(b, n, r, n)==TRUE){
- if(ct->w){
- textshow(ct, q, q+n, 1);
- winsettag(ct->w);
- }else{
- ct->q0 = q;
- ct->q1 = q+n;
+ }else{
+ uint q;
+ q = ct->q1;
+ for(;;){
+ if(q >= ct->file->b.nc){
+ q = 0;
+ around = 1;
+ nb = 0;
+ b[nb] = 0;
}
- seltext = ct;
- fbuffree(s);
- return TRUE;
+ if(nb > 0){
+ Rune *c;
+ c = runestrchr(b, r[0]);
+ if(c == nil){
+ q += nb;
+ nb = 0;
+ b[nb] = 0;
+ if(around && q>=ct->q1)
+ break;
+ continue;
+ }
+ q += (c-b);
+ nb -= (c-b);
+ b = c;
+ }
+ /* reload if buffer covers neither string nor rest of file */
+ if(nb<n && nb!=ct->file->b.nc-q){
+ nb = ct->file->b.nc-q;
+ if(nb >= maxn)
+ nb = maxn-1;
+ bufread(&ct->file->b, q, s, nb);
+ b = s;
+ b[nb] = '\0';
+ }
+ /* this runeeq is fishy but the null at b[nb] makes it safe */
+ if(runeeq(b, n, r, n)==TRUE){
+ if(ct->w){
+ textshow(ct, q, q+n, 1);
+ winsettag(ct->w);
+ }else{
+ ct->q0 = q;
+ ct->q1 = q+n;
+ }
+ seltext = ct;
+ fbuffree(s);
+ return TRUE;
+ }
+ --nb;
+ b++;
+ q++;
+ if(around && q>=ct->q1)
+ break;
}
- --nb;
- b++;
- q++;
- if(around && q>=ct->q1)
- break;
}
fbuffree(s);
return FALSE;
@@ -526,7 +590,7 @@ texthas(Text *t, uint q0, Rune *r)
}
int
-expandfile(Text *t, uint q0, uint q1, Expand *e)
+expandfile(Text *t, uint q0, uint q1, Expand *e, int reverse)
{
int i, n, nname, colon, eval;
uint amin, amax;
@@ -570,6 +634,11 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
break;
}else
amax = t->file->b.nc;
+ if(colon != q0)
+ reverse = FALSE;
+ }else if(reverse){
+ if(textreadc(t, q0) != ':')
+ reverse = FALSE;
}
amin = amax;
e->q0 = q0;
@@ -643,12 +712,16 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
}
Isfile:
+ print("isfile reverse=%d colon=%d q0=%d\n", reverse, colon, q0);
e->name = r;
e->nname = nname;
e->u.at = t;
e->a0 = amin+1;
+ e->reverse = reverse;
eval = FALSE;
- address(TRUE, nil, range(-1,-1), range(0,0), t, e->a0, amax, tgetc, &eval, (uint*)&e->a1);
+ // Note: address is repeated in openfile when
+ // expandfile returns to expand returns to look3.
+ address(TRUE, nil, range(-1,-1), range(0,0), t, e->a0, amax, tgetc, &eval, (uint*)&e->a1, e->reverse);
return TRUE;
Isntfile:
@@ -657,7 +730,7 @@ expandfile(Text *t, uint q0, uint q1, Expand *e)
}
int
-expand(Text *t, uint q0, uint q1, Expand *e)
+expand(Text *t, uint q0, uint q1, Expand *e, int reverse)
{
memset(e, 0, sizeof *e);
e->agetc = tgetc;
@@ -670,7 +743,7 @@ expand(Text *t, uint q0, uint q1, Expand *e)
e->jump = FALSE;
}
- if(expandfile(t, q0, q1, e))
+ if(expandfile(t, q0, q1, e, reverse))
return TRUE;
if(q0 == q1){
@@ -806,7 +879,7 @@ openfile(Text *t, Expand *e)
eval = FALSE;
else{
eval = TRUE;
- r = address(TRUE, t, range(-1,-1), range(t->q0, t->q1), e->u.at, e->a0, e->a1, e->agetc, &eval, &dummy);
+ r = address(TRUE, t, range(-1,-1), range(t->q0, t->q1), e->u.at, e->a0, e->a1, e->agetc, &eval, &dummy, e->reverse);
if(r.q0 > r.q1) {
eval = FALSE;
warning(nil, "addresses out of order\n");
diff --git a/src/cmd/acme/xfid.c b/src/cmd/acme/xfid.c
@@ -486,7 +486,7 @@ xfidwrite(Xfid *x)
t = &w->body;
wincommit(w, t);
eval = TRUE;
- a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb);
+ a = address(FALSE, t, w->limit, w->addr, r, 0, nr, rgetc, &eval, (uint*)&nb, FALSE);
free(r);
if(nb < nr){
respond(x, &fc, Ebadaddr);
@@ -900,7 +900,11 @@ xfideventwrite(Xfid *x, Window *w)
break;
case 'l':
case 'L':
- look3(t, q0, q1, TRUE);
+ look3(t, q0, q1, TRUE, FALSE);
+ break;
+ case 'r':
+ case 'R':
+ look3(t, q0, q1, TRUE, TRUE);
break;
default:
qunlock(&row.lk);
diff --git a/src/cmd/devdraw/mac-screen.m b/src/cmd/devdraw/mac-screen.m
@@ -631,12 +631,17 @@ rpc_resizewindow(Client *c, Rectangle r)
b = [NSEvent pressedMouseButtons];
b = (b&~6) | (b&4)>>1 | (b&2)<<1;
if(b){
+ int x;
+ x = 0;
if(m & ~omod & NSEventModifierFlagControl)
- b |= 1;
+ x = 1;
if(m & ~omod & NSEventModifierFlagOption)
- b |= 2;
+ x = 2;
if(m & ~omod & NSEventModifierFlagCommand)
- b |= 4;
+ x = 4;
+ if(m & NSEventModifierFlagShift)
+ x <<= 5;
+ b |= x;
[self sendmouse:b];
}else if(m & ~omod & NSEventModifierFlagOption)
gfx_keystroke(self.client, Kalt);
@@ -701,6 +706,8 @@ rpc_resizewindow(Client *c, Rectangle r)
}else
if(m & NSEventModifierFlagCommand)
b = 4;
+ if(m & NSEventModifierFlagShift)
+ b <<= 5;
}
[self sendmouse:b];
}