2007-07-27 09:50:37 -04:00
|
|
|
/** Support for mouse interface
|
|
|
|
* @file */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* TODO: cleanup includes */
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#ifdef HAVE_TERMIOS_H
|
|
|
|
#include <termios.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef __hpux__
|
|
|
|
#include <limits.h>
|
|
|
|
#define HPUX_PIPE (len > PIPE_BUF || errno != EAGAIN)
|
|
|
|
#else
|
|
|
|
#define HPUX_PIPE 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "elinks.h"
|
|
|
|
|
2022-01-02 09:17:53 -05:00
|
|
|
#include "config/home.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "config/options.h"
|
2021-09-21 13:02:43 -04:00
|
|
|
#include "dialogs/status.h"
|
2021-08-08 15:25:08 -04:00
|
|
|
#include "intl/libintl.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "main/select.h"
|
|
|
|
#include "main/timer.h"
|
|
|
|
#include "osdep/ascii.h"
|
|
|
|
#include "osdep/osdep.h"
|
2021-09-21 13:02:43 -04:00
|
|
|
#include "session/session.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "terminal/hardio.h"
|
|
|
|
#include "terminal/itrm.h"
|
|
|
|
#include "terminal/kbd.h"
|
|
|
|
#include "terminal/mouse.h"
|
|
|
|
#include "terminal/terminal.h"
|
|
|
|
#include "util/error.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
#include "util/time.h"
|
|
|
|
|
|
|
|
extern struct itrm *ditrm;
|
|
|
|
|
|
|
|
#define write_sequence(fd, seq) \
|
|
|
|
hard_write(fd, seq, sizeof(seq) - 1)
|
|
|
|
|
|
|
|
|
2007-07-27 09:50:37 -04:00
|
|
|
#define INIT_TWIN_MOUSE_SEQ "\033[?9h" /**< Send MIT Mouse Row & Column on Button Press */
|
|
|
|
#define INIT_XWIN_MOUSE_SEQ "\033[?1000h" /**< Send Mouse X & Y on button press and release */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
send_mouse_init_sequence(int h)
|
|
|
|
{
|
|
|
|
write_sequence(h, INIT_TWIN_MOUSE_SEQ);
|
|
|
|
write_sequence(h, INIT_XWIN_MOUSE_SEQ);
|
|
|
|
}
|
|
|
|
|
2007-07-27 09:50:37 -04:00
|
|
|
#define DONE_TWIN_MOUSE_SEQ "\033[?9l" /**< Don't Send MIT Mouse Row & Column on Button Press */
|
|
|
|
#define DONE_XWIN_MOUSE_SEQ "\033[?1000l" /**< Don't Send Mouse X & Y on button press and release */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
send_mouse_done_sequence(int h)
|
|
|
|
{
|
|
|
|
/* This is a hack to make xterm + alternate screen working,
|
|
|
|
* if we send only DONE_XWIN_MOUSE_SEQ, mouse is not totally
|
|
|
|
* released it seems, in rxvt and xterm... --Zas */
|
|
|
|
write_sequence(h, DONE_TWIN_MOUSE_SEQ);
|
|
|
|
write_sequence(h, DONE_XWIN_MOUSE_SEQ);
|
|
|
|
}
|
|
|
|
|
2022-01-02 09:17:53 -05:00
|
|
|
int mouse_enabled;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
void
|
|
|
|
disable_mouse(void)
|
|
|
|
{
|
2006-07-01 23:28:51 -04:00
|
|
|
if (!mouse_enabled) return;
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
unhandle_mouse(ditrm->mouse_h);
|
2020-05-26 15:36:46 -04:00
|
|
|
if (is_xterm()) send_mouse_done_sequence(get_output_handle());
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
mouse_enabled = 0;
|
|
|
|
}
|
|
|
|
|
2022-01-02 09:17:53 -05:00
|
|
|
static int
|
|
|
|
mouse_lock_exists(void)
|
|
|
|
{
|
2022-12-26 11:36:31 -05:00
|
|
|
char *lock_filename = straconcat(empty_string_or_(get_xdg_config_home()), "mouse.lock", (char *) NULL);
|
2022-01-02 09:17:53 -05:00
|
|
|
int res = 0;
|
|
|
|
|
|
|
|
if (lock_filename) {
|
|
|
|
res = !access(lock_filename, F_OK);
|
|
|
|
mem_free(lock_filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
|
|
|
enable_mouse(void)
|
|
|
|
{
|
2020-05-25 05:27:02 -04:00
|
|
|
if (get_opt_bool("ui.mouse_disable", NULL))
|
|
|
|
return;
|
|
|
|
|
2022-01-02 09:17:53 -05:00
|
|
|
if (mouse_lock_exists()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-07-01 23:28:51 -04:00
|
|
|
if (mouse_enabled) return;
|
|
|
|
|
2020-05-26 15:36:46 -04:00
|
|
|
if (is_xterm()) send_mouse_init_sequence(get_output_handle());
|
2021-01-02 10:20:27 -05:00
|
|
|
ditrm->mouse_h = handle_mouse(0, (void (*)(void *, char *, int)) itrm_queue_event, ditrm);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
mouse_enabled = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2021-09-21 13:02:43 -04:00
|
|
|
toggle_mouse(struct session *ses)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
2021-09-21 13:02:43 -04:00
|
|
|
if (mouse_enabled) {
|
2005-09-15 09:58:31 -04:00
|
|
|
disable_mouse();
|
2021-09-21 13:02:43 -04:00
|
|
|
} else {
|
2005-09-15 09:58:31 -04:00
|
|
|
enable_mouse();
|
2021-09-21 13:02:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mouse_enabled) {
|
|
|
|
mem_free_set(&ses->status.window_status, stracpy(_("Mouse enabled", ses->tab->term)));
|
|
|
|
} else {
|
|
|
|
mem_free_set(&ses->status.window_status, stracpy(_("Mouse disabled", ses->tab->term)));
|
|
|
|
}
|
|
|
|
print_screen_status(ses);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
decode_mouse_position(struct itrm *itrm, int from)
|
|
|
|
{
|
|
|
|
int position;
|
|
|
|
|
|
|
|
position = (unsigned char) (itrm->in.queue.data[from]) - ' ' - 1
|
|
|
|
+ ((int) ((unsigned char) (itrm->in.queue.data[from + 1]) - ' ' - 1) << 7);
|
|
|
|
|
|
|
|
return (position & (1 << 13)) ? 0 : position;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define get_mouse_x_position(itrm, esclen) decode_mouse_position(itrm, (esclen) + 1)
|
|
|
|
#define get_mouse_y_position(itrm, esclen) decode_mouse_position(itrm, (esclen) + 3)
|
|
|
|
|
|
|
|
#define TW_BUTT_LEFT 1
|
|
|
|
#define TW_BUTT_MIDDLE 2
|
|
|
|
#define TW_BUTT_RIGHT 4
|
|
|
|
|
2007-07-27 09:50:37 -04:00
|
|
|
/** @returns length of the escape sequence or -1 if the caller needs to set up
|
2005-09-15 09:58:31 -04:00
|
|
|
* the ESC delay timer. */
|
|
|
|
int
|
2006-08-05 04:49:57 -04:00
|
|
|
decode_terminal_mouse_escape_sequence(struct itrm *itrm, struct interlink_event *ev,
|
2005-09-15 09:58:31 -04:00
|
|
|
int el, int v)
|
|
|
|
{
|
|
|
|
static int xterm_button = -1;
|
2006-08-05 04:49:57 -04:00
|
|
|
struct interlink_event_mouse mouse;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (itrm->in.queue.len - el < 3)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (v == 5) {
|
|
|
|
if (xterm_button == -1)
|
|
|
|
xterm_button = 0;
|
|
|
|
|
|
|
|
if (itrm->in.queue.len - el < 5)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
mouse.x = get_mouse_x_position(itrm, el);
|
|
|
|
mouse.y = get_mouse_y_position(itrm, el);
|
|
|
|
|
|
|
|
switch ((itrm->in.queue.data[el] - ' ') ^ xterm_button) { /* Every event changes only one bit */
|
|
|
|
case TW_BUTT_LEFT:
|
|
|
|
mouse.button = B_LEFT | ((xterm_button & TW_BUTT_LEFT) ? B_UP : B_DOWN);
|
|
|
|
break;
|
|
|
|
case TW_BUTT_MIDDLE:
|
|
|
|
mouse.button = B_MIDDLE | ((xterm_button & TW_BUTT_MIDDLE) ? B_UP : B_DOWN);
|
|
|
|
break;
|
|
|
|
case TW_BUTT_RIGHT:
|
|
|
|
mouse.button = B_RIGHT | ((xterm_button & TW_BUTT_RIGHT) ? B_UP : B_DOWN);
|
|
|
|
break;
|
|
|
|
case 0:
|
|
|
|
mouse.button = B_DRAG;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mouse.button = 0; /* shut up warning */
|
|
|
|
/* default : Twin protocol error */
|
|
|
|
}
|
|
|
|
|
|
|
|
xterm_button = itrm->in.queue.data[el] - ' ';
|
|
|
|
el += 5;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* See terminal/mouse.h about details of the mouse reporting
|
|
|
|
* protocol and {struct term_event_mouse->button} bitmask
|
|
|
|
* structure. */
|
|
|
|
mouse.x = itrm->in.queue.data[el+1] - ' ' - 1;
|
|
|
|
mouse.y = itrm->in.queue.data[el+2] - ' ' - 1;
|
|
|
|
|
|
|
|
/* There are rumours arising from remnants of code dating to
|
|
|
|
* the ancient Mikulas' times that bit 4 indicated B_DRAG.
|
|
|
|
* However, I didn't find on what terminal it should be ever
|
|
|
|
* supposed to work and it conflicts with wheels. So I removed
|
|
|
|
* the last remnants of the code as well. --pasky */
|
|
|
|
|
|
|
|
mouse.button = (itrm->in.queue.data[el] & 7) | B_DOWN;
|
|
|
|
/* smartglasses1 - rxvt wheel: */
|
|
|
|
if (mouse.button == 3 && xterm_button != -1) {
|
|
|
|
mouse.button = xterm_button | B_UP;
|
|
|
|
}
|
|
|
|
/* xterm wheel: */
|
|
|
|
if ((itrm->in.queue.data[el] & 96) == 96) {
|
|
|
|
mouse.button = (itrm->in.queue.data[el] & 1) ? B_WHEEL_DOWN : B_WHEEL_UP;
|
|
|
|
}
|
|
|
|
|
|
|
|
xterm_button = -1;
|
|
|
|
/* XXX: Eterm/aterm uses rxvt-like reporting, but sends the
|
|
|
|
* release sequence for wheel. rxvt itself sends only press
|
|
|
|
* sequence. Since we can't reliably guess what we're talking
|
|
|
|
* with from $TERM, we will rather support Eterm/aterm, as in
|
|
|
|
* rxvt, at least each second wheel up move will work. */
|
|
|
|
if (mouse_action_is(&mouse, B_DOWN))
|
|
|
|
xterm_button = mouse_get_button(&mouse);
|
|
|
|
|
|
|
|
el += 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Postpone changing of the event type until all sanity
|
|
|
|
* checks have been done. */
|
2006-08-05 04:49:57 -04:00
|
|
|
set_mouse_interlink_event(ev, mouse.x, mouse.y, mouse.button);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
return el;
|
|
|
|
}
|