summaryrefslogtreecommitdiffstats
path: root/scripts/mouse.pl
blob: d9debc74d22478ba1a94fc4d0040fcf1de561f5b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# See http://wouter.coekaerts.be/site/irssi/mouse
# based on irssi mouse patch by mirage: http://darksun.com.pt/mirage/irssi/

# Copyright (C) 2005-2009  Wouter Coekaerts <wouter@coekaerts.be>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

use strict;
use Irssi qw(signal_emit settings_get_str active_win signal_stop settings_add_str settings_add_bool settings_get_bool signal_add signal_add_first);
use Math::Trig;

use vars qw($VERSION %IRSSI);

$VERSION = '1.1.2';
%IRSSI = (
	authors  	=> 'Wouter Coekaerts',
	contact  	=> 'wouter@coekaerts.be',
	name    	=> 'mouse',
	description 	=> 'control irssi using mouse clicks and gestures',
	license 	=> 'GPLv2 or later',
	url     	=> 'http://wouter.coekaerts.be/irssi/',
	changed  	=> '2021-03-05',
);

my @BUTTONS = ('', '_middle', '_right');

my $mouse_xterm_status = -1; # -1:off 0,1,2:filling mouse_xterm_combo
my @mouse_xterm_combo = (3, 0, 0); # 0:button 1:x 2:y
my @mouse_xterm_previous; # previous contents of mouse_xterm_combo

sub mouse_enable {
	print STDERR "\e[?1000h"; # start tracking 
}

sub mouse_disable {
	print STDERR "\e[?1000l"; # stop tracking 
}

# Handle mouse event (button press or release)
sub mouse_event {
	my ($b, $x, $y, $oldb, $oldx, $oldy) = @_;
	my ($xd, $yd);
	my ($distance, $angle);

	# uhm, in the patch the scrollwheel didn't work for me, but this does:
	if ($b == 64) {
		cmd("mouse_scroll_up");
	} elsif ($b == 65) {
		cmd("mouse_scroll_down")
	}

	# proceed only if a button is being released
	return if ($b != 3);

	return unless (0 <= $oldb && $oldb <= 2);
	my $button = $BUTTONS[$oldb];

	# if it was a mouse click of the left button (press and release in the same position)
	if ($x == $oldx && $y == $oldy) {
		cmd("mouse" . $button . "_click");
		return;
	}

	# otherwise, find mouse gestures
	$xd = $x - $oldx;
	$yd = -1 * ($y - $oldy);
	$distance = sqrt($xd*$xd + $yd*$yd);
	# ignore small gestures
	if ($distance < 3) {
		return;
	}
	$angle = asin($yd/$distance) * 180 / 3.14159265358979;
	if ($angle < 20 && $angle > -20 && $xd > 0) {
		if ($distance <= 40) {
			cmd("mouse" . $button . "_gesture_right");
		} else {
			cmd("mouse" . $button . "_gesture_bigright");
		}
	} elsif ($angle < 20 && $angle > -20 && $xd < 0) {
		if ($distance <= 40) {
			cmd("mouse" . $button . "_gesture_left");
		} else {
			cmd("mouse" . $button . "_gesture_bigleft");
		}
	} elsif ($angle > 40) {
		cmd("mouse" . $button . "_gesture_up");
	} elsif ($angle < -40) {
		cmd("mouse" . $button . "_gesture_down");
	}
}

# executes the command configured in the given setting
sub cmd
{
	my ($setting) = @_;
	signal_emit("send command", settings_get_str($setting), active_win->{'active_server'}, active_win->{'active'});
}


signal_add_first("gui key pressed", sub {
	my ($key) = @_;
	if ($mouse_xterm_status != -1) {
		if ($mouse_xterm_status == 0 && ($mouse_xterm_previous[0] != $mouse_xterm_combo[0])) { # if combo is starting, and previous what not a move (button not changed)
			@mouse_xterm_previous = @mouse_xterm_combo;
		}
		$mouse_xterm_combo[$mouse_xterm_status] = $key-32;
		$mouse_xterm_status++;
		if ($mouse_xterm_status == 3) {
			$mouse_xterm_status = -1;
			# match screen coordinates
			$mouse_xterm_combo[1]--;
			$mouse_xterm_combo[2]--;
			mouse_event($mouse_xterm_combo[0], $mouse_xterm_combo[1], $mouse_xterm_combo[2], $mouse_xterm_previous[0], $mouse_xterm_previous[1], $mouse_xterm_previous[2]);
		}
		signal_stop();
	}
});

sub UNLOAD {
	mouse_disable();
}

if ($ENV{"TERM"} !~ /^rxvt|screen|xterm|tmux(-(256)?(color|kitty))?$/) {
	die "Your terminal doesn't seem to support this.";
}

mouse_enable();

Irssi::command("/^bind meta-[M /mouse_xterm"); # FIXME evil
Irssi::command_bind("mouse_xterm", sub {$mouse_xterm_status = 0;});
Irssi::command_bind 'mouse' => sub {
	my ($data, $server, $item) = @_;
	$data =~ s/\s+$//g;
	Irssi::command_runsub('mouse', $data, $server, $item);
};

# temporarily disable mouse handling. Useful for copy-pasting without touching the keyboard (pressing shift)
Irssi::command_bind 'mouse tempdisable' => sub {
	my ($data, $server, $item) = @_;
	my $seconds = ($data eq '') ? 5 : $data; # optional argument saying how many seconds, defaulting to 5
	mouse_disable();
	Irssi::timeout_add_once($seconds * 1000, 'mouse_enable', undef); # turn back on after $second seconds
};

for my $button (@BUTTONS) {
	settings_add_str("lookandfeel", "mouse" . $button . "_click", "/mouse tempdisable 5");
	settings_add_str("lookandfeel", "mouse" . $button . "_gesture_up", "/window last");
	settings_add_str("lookandfeel", "mouse" . $button . "_gesture_down", "/window goto active");
	settings_add_str("lookandfeel", "mouse" . $button . "_gesture_left", "/window prev");
	settings_add_str("lookandfeel", "mouse" . $button . "_gesture_bigleft", "/eval window prev;window prev");
	settings_add_str("lookandfeel", "mouse" . $button . "_gesture_right", "/window next");
	settings_add_str("lookandfeel", "mouse" . $button . "_gesture_bigright", "/eval window next;window next");
}

settings_add_str("lookandfeel", "mouse_scroll_up", "/scrollback goto -10");
settings_add_str("lookandfeel", "mouse_scroll_down", "/scrollback goto +10");