Add support for VT200-style mouse input.
Right now if applications want to use the mouse on the command line, they use sysmouse(4) and install a signal handler in the kernel to deliver signals when mouse events arrive. This conflicts with my plan to change to TERM=xterm, so implement proper VT200-style mouse input. Because mouse input is now streamed through the TTY, it means you can now SSH to another system on the console and use the mouse there as well. The disadvantage of the VT200 mouse protocol, is that it doesn't seem to generate events when moving the cursor. Only when pressing and releasing mouse buttons. There are different protocols as well, but this one seems to be most commonly supported. Reported by: Paul B. Mahol <onemda gmail com> Tested with: vim(1)
This commit is contained in:
parent
27bfa95847
commit
53e69c0c2a
@ -117,6 +117,48 @@ sc_alloc_cut_buffer(scr_stat *scp, int wait)
|
||||
}
|
||||
#endif /* SC_NO_CUTPASTE */
|
||||
|
||||
static void
|
||||
sc_mouse_input_button(scr_stat *scp, int button)
|
||||
{
|
||||
char mouseb[6] = "\x1B[M";
|
||||
|
||||
mouseb[3] = ' ' + button;
|
||||
mouseb[4] = '!' + scp->mouse_pos % scp->xsize;
|
||||
mouseb[5] = '!' + scp->mouse_pos / scp->xsize;
|
||||
sc_respond(scp, mouseb, sizeof mouseb, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
sc_mouse_input(scr_stat *scp, mouse_info_t *mouse)
|
||||
{
|
||||
|
||||
switch (mouse->operation) {
|
||||
case MOUSE_BUTTON_EVENT:
|
||||
if (mouse->u.event.value > 0) {
|
||||
/* Mouse button pressed. */
|
||||
if (mouse->u.event.id & MOUSE_BUTTON1DOWN)
|
||||
sc_mouse_input_button(scp, 0);
|
||||
if (mouse->u.event.id & MOUSE_BUTTON2DOWN)
|
||||
sc_mouse_input_button(scp, 1);
|
||||
if (mouse->u.event.id & MOUSE_BUTTON3DOWN)
|
||||
sc_mouse_input_button(scp, 2);
|
||||
} else {
|
||||
/* Mouse button released. */
|
||||
sc_mouse_input_button(scp, 3);
|
||||
}
|
||||
break;
|
||||
case MOUSE_MOTION_EVENT:
|
||||
if (mouse->u.data.z < 0) {
|
||||
/* Scroll up. */
|
||||
sc_mouse_input_button(scp, 64);
|
||||
} else if (mouse->u.data.z > 0) {
|
||||
/* Scroll down. */
|
||||
sc_mouse_input_button(scp, 65);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* move mouse */
|
||||
void
|
||||
sc_mouse_move(scr_stat *scp, int x, int y)
|
||||
@ -755,6 +797,11 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
|
||||
cur_scp->status &= ~MOUSE_HIDDEN;
|
||||
|
||||
if (cur_scp->mouse_level > 0) {
|
||||
sc_mouse_input(scp, mouse);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
|
||||
/* has controlling process died? */
|
||||
if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))) {
|
||||
@ -811,6 +858,11 @@ sc_mouse_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
|
||||
|
||||
cur_scp->status &= ~MOUSE_HIDDEN;
|
||||
|
||||
if (cur_scp->mouse_level > 0) {
|
||||
sc_mouse_input(scp, mouse);
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur_scp->mouse_signal && cur_scp->mouse_proc) {
|
||||
if (cur_scp->mouse_proc != (p1 = pfind(cur_scp->mouse_pid))){
|
||||
cur_scp->mouse_signal = 0;
|
||||
|
@ -644,6 +644,9 @@ scteken_param(void *arg, int cmd, unsigned int value)
|
||||
scp->bell_pitch = TP_SETBELLPD_PITCH(value);
|
||||
scp->bell_duration = TP_SETBELLPD_DURATION(value);
|
||||
break;
|
||||
case TP_MOUSE:
|
||||
scp->mouse_level = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -652,5 +655,5 @@ scteken_respond(void *arg, const void *buf, size_t len)
|
||||
{
|
||||
scr_stat *scp = arg;
|
||||
|
||||
sc_respond(scp, buf, len);
|
||||
sc_respond(scp, buf, len, 0);
|
||||
}
|
||||
|
@ -3561,19 +3561,18 @@ sc_paste(scr_stat *scp, const u_char *p, int count)
|
||||
}
|
||||
|
||||
void
|
||||
sc_respond(scr_stat *scp, const u_char *p, int count)
|
||||
sc_respond(scr_stat *scp, const u_char *p, int count, int wakeup)
|
||||
{
|
||||
struct tty *tp;
|
||||
|
||||
tp = SC_DEV(scp->sc, scp->sc->cur_scp->index);
|
||||
if (!tty_opened(tp))
|
||||
return;
|
||||
for (; count > 0; --count)
|
||||
ttydisc_rint(tp, *p++, 0);
|
||||
#if 0
|
||||
/* XXX: we can't call ttydisc_rint_done() here! */
|
||||
ttydisc_rint_done(tp);
|
||||
#endif
|
||||
ttydisc_rint_simple(tp, p, count);
|
||||
if (wakeup) {
|
||||
/* XXX: we can't always call ttydisc_rint_done() here! */
|
||||
ttydisc_rint_done(tp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -314,6 +314,7 @@ typedef struct scr_stat {
|
||||
short mouse_buttons; /* mouse buttons */
|
||||
int mouse_cut_start; /* mouse cut start pos */
|
||||
int mouse_cut_end; /* mouse cut end pos */
|
||||
int mouse_level; /* xterm mouse protocol */
|
||||
struct proc *mouse_proc; /* proc* of controlling proc */
|
||||
pid_t mouse_pid; /* pid of controlling proc */
|
||||
int mouse_signal; /* signal # to report with */
|
||||
@ -564,7 +565,8 @@ int sc_switch_scr(sc_softc_t *sc, u_int next_scr);
|
||||
void sc_alloc_scr_buffer(scr_stat *scp, int wait, int discard);
|
||||
int sc_init_emulator(scr_stat *scp, char *name);
|
||||
void sc_paste(scr_stat *scp, const u_char *p, int count);
|
||||
void sc_respond(scr_stat *scp, const u_char *p, int count);
|
||||
void sc_respond(scr_stat *scp, const u_char *p,
|
||||
int count, int wakeup);
|
||||
void sc_bell(scr_stat *scp, int pitch, int duration);
|
||||
|
||||
/* schistory.c */
|
||||
|
@ -97,6 +97,7 @@ typedef void tf_param_t(void *, int, unsigned int);
|
||||
#define TP_SETBELLPD 6
|
||||
#define TP_SETBELLPD_PITCH(pd) ((pd) >> 16)
|
||||
#define TP_SETBELLPD_DURATION(pd) ((pd) & 0xffff)
|
||||
#define TP_MOUSE 7
|
||||
typedef void tf_respond_t(void *, const void *, size_t);
|
||||
|
||||
typedef struct {
|
||||
|
@ -932,6 +932,9 @@ teken_subr_reset_dec_mode(teken_t *t, unsigned int cmd)
|
||||
case 47: /* Switch to alternate buffer. */
|
||||
teken_printf("Switch to alternate buffer\n");
|
||||
break;
|
||||
case 1000: /* Mouse input. */
|
||||
teken_funcs_param(t, TP_MOUSE, 0);
|
||||
break;
|
||||
default:
|
||||
teken_printf("Unknown DECRST: %u\n", cmd);
|
||||
}
|
||||
@ -1078,6 +1081,9 @@ teken_subr_set_dec_mode(teken_t *t, unsigned int cmd)
|
||||
case 47: /* Switch to alternate buffer. */
|
||||
teken_printf("Switch away from alternate buffer\n");
|
||||
break;
|
||||
case 1000: /* Mouse input. */
|
||||
teken_funcs_param(t, TP_MOUSE, 1);
|
||||
break;
|
||||
default:
|
||||
teken_printf("Unknown DECSET: %u\n", cmd);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user