1 /* Support for mouse interface */
7 /* TODO: cleanup includes */
19 #define HPUX_PIPE (len > PIPE_BUF || errno != EAGAIN)
26 #include "config/options.h"
27 #include "intl/gettext/libintl.h"
28 #include "main/select.h"
29 #include "main/timer.h"
30 #include "osdep/ascii.h"
31 #include "osdep/osdep.h"
32 #include "terminal/hardio.h"
33 #include "terminal/itrm.h"
34 #include "terminal/kbd.h"
35 #include "terminal/mouse.h"
36 #include "terminal/terminal.h"
37 #include "util/error.h"
38 #include "util/memory.h"
39 #include "util/string.h"
40 #include "util/time.h"
42 extern struct itrm
*ditrm
;
44 #define write_sequence(fd, seq) \
45 hard_write(fd, seq, sizeof(seq) - 1)
48 #define INIT_TWIN_MOUSE_SEQ "\033[?9h" /* Send MIT Mouse Row & Column on Button Press */
49 #define INIT_XWIN_MOUSE_SEQ "\033[?1000h" /* Send Mouse X & Y on button press and release */
52 send_mouse_init_sequence(int h
)
54 write_sequence(h
, INIT_TWIN_MOUSE_SEQ
);
55 write_sequence(h
, INIT_XWIN_MOUSE_SEQ
);
58 #define DONE_TWIN_MOUSE_SEQ "\033[?9l" /* Don't Send MIT Mouse Row & Column on Button Press */
59 #define DONE_XWIN_MOUSE_SEQ "\033[?1000l" /* Don't Send Mouse X & Y on button press and release */
62 send_mouse_done_sequence(int h
)
64 /* This is a hack to make xterm + alternate screen working,
65 * if we send only DONE_XWIN_MOUSE_SEQ, mouse is not totally
66 * released it seems, in rxvt and xterm... --Zas */
67 write_sequence(h
, DONE_TWIN_MOUSE_SEQ
);
68 write_sequence(h
, DONE_XWIN_MOUSE_SEQ
);
71 static int mouse_enabled
;
76 int h
= get_output_handle(); /* XXX: Is this all right? -- Miciah */
78 if (!mouse_enabled
) return;
80 unhandle_mouse(ditrm
->mouse_h
);
81 if (is_xterm()) send_mouse_done_sequence(h
);
89 int h
= get_output_handle(); /* XXX: Is this all right? -- Miciah */
91 if (mouse_enabled
) return;
93 if (is_xterm()) send_mouse_init_sequence(h
);
94 ditrm
->mouse_h
= handle_mouse(0, (void (*)(void *, unsigned char *, int)) itrm_queue_event
, ditrm
);
109 decode_mouse_position(struct itrm
*itrm
, int from
)
113 position
= (unsigned char) (itrm
->in
.queue
.data
[from
]) - ' ' - 1
114 + ((int) ((unsigned char) (itrm
->in
.queue
.data
[from
+ 1]) - ' ' - 1) << 7);
116 return (position
& (1 << 13)) ? 0 : position
;
119 #define get_mouse_x_position(itrm, esclen) decode_mouse_position(itrm, (esclen) + 1)
120 #define get_mouse_y_position(itrm, esclen) decode_mouse_position(itrm, (esclen) + 3)
122 #define TW_BUTT_LEFT 1
123 #define TW_BUTT_MIDDLE 2
124 #define TW_BUTT_RIGHT 4
126 /* Returns length of the escape sequence or -1 if the caller needs to set up
127 * the ESC delay timer. */
129 decode_terminal_mouse_escape_sequence(struct itrm
*itrm
, struct interlink_event
*ev
,
132 static int xterm_button
= -1;
133 struct interlink_event_mouse mouse
;
135 if (itrm
->in
.queue
.len
- el
< 3)
139 if (xterm_button
== -1)
142 if (itrm
->in
.queue
.len
- el
< 5)
145 mouse
.x
= get_mouse_x_position(itrm
, el
);
146 mouse
.y
= get_mouse_y_position(itrm
, el
);
148 switch ((itrm
->in
.queue
.data
[el
] - ' ') ^ xterm_button
) { /* Every event changes only one bit */
150 mouse
.button
= B_LEFT
| ((xterm_button
& TW_BUTT_LEFT
) ? B_UP
: B_DOWN
);
153 mouse
.button
= B_MIDDLE
| ((xterm_button
& TW_BUTT_MIDDLE
) ? B_UP
: B_DOWN
);
156 mouse
.button
= B_RIGHT
| ((xterm_button
& TW_BUTT_RIGHT
) ? B_UP
: B_DOWN
);
159 mouse
.button
= B_DRAG
;
162 mouse
.button
= 0; /* shut up warning */
163 /* default : Twin protocol error */
166 xterm_button
= itrm
->in
.queue
.data
[el
] - ' ';
170 /* See terminal/mouse.h about details of the mouse reporting
171 * protocol and {struct term_event_mouse->button} bitmask
173 mouse
.x
= itrm
->in
.queue
.data
[el
+1] - ' ' - 1;
174 mouse
.y
= itrm
->in
.queue
.data
[el
+2] - ' ' - 1;
176 /* There are rumours arising from remnants of code dating to
177 * the ancient Mikulas' times that bit 4 indicated B_DRAG.
178 * However, I didn't find on what terminal it should be ever
179 * supposed to work and it conflicts with wheels. So I removed
180 * the last remnants of the code as well. --pasky */
182 mouse
.button
= (itrm
->in
.queue
.data
[el
] & 7) | B_DOWN
;
183 /* smartglasses1 - rxvt wheel: */
184 if (mouse
.button
== 3 && xterm_button
!= -1) {
185 mouse
.button
= xterm_button
| B_UP
;
188 if ((itrm
->in
.queue
.data
[el
] & 96) == 96) {
189 mouse
.button
= (itrm
->in
.queue
.data
[el
] & 1) ? B_WHEEL_DOWN
: B_WHEEL_UP
;
193 /* XXX: Eterm/aterm uses rxvt-like reporting, but sends the
194 * release sequence for wheel. rxvt itself sends only press
195 * sequence. Since we can't reliably guess what we're talking
196 * with from $TERM, we will rather support Eterm/aterm, as in
197 * rxvt, at least each second wheel up move will work. */
198 if (mouse_action_is(&mouse
, B_DOWN
))
199 xterm_button
= mouse_get_button(&mouse
);
204 /* Postpone changing of the event type until all sanity
205 * checks have been done. */
206 set_mouse_interlink_event(ev
, mouse
.x
, mouse
.y
, mouse
.button
);