html/mouse.pl
1 # See http://wouter.coekaerts.be/site/irssi/mouse
2 # based on irssi mouse patch by mirage: http://darksun.com.pt/mirage/irssi/
3
4 # Copyright (C) 2005-2009 Wouter Coekaerts <wouter@coekaerts.be>
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20 use strict;
21 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);
22 use Math::Trig;
23
24 use vars qw($VERSION %IRSSI);
25
26 $VERSION = '1.0.0';
27 %IRSSI = (
28 authors => 'Wouter Coekaerts',
29 contact => 'wouter@coekaerts.be',
30 name => 'mouse',
31 description => 'control irssi using mouse clicks and gestures',
32 license => 'GPLv2 or later',
33 url => 'http://wouter.coekaerts.be/irssi/',
34 changed => '2009-05-16',
35 );
36
37 my @BUTTONS = ('', '_middle', '_right');
38
39 my $mouse_xterm_status = -1; # -1:off 0,1,2:filling mouse_xterm_combo
40 my @mouse_xterm_combo = (3, 0, 0); # 0:button 1:x 2:y
41 my @mouse_xterm_previous; # previous contents of mouse_xterm_combo
42
43 sub mouse_enable {
44 print STDERR "\e[?1000h"; # start tracking
45 }
46
47 sub mouse_disable {
48 print STDERR "\e[?1000l"; # stop tracking
49 }
50
51 # Handle mouse event (button press or release)
52 sub mouse_event {
53 my ($b, $x, $y, $oldb, $oldx, $oldy) = @_;
54 my ($xd, $yd);
55 my ($distance, $angle);
56
57 # uhm, in the patch the scrollwheel didn't work for me, but this does:
58 if ($b == 64) {
59 cmd("mouse_scroll_up");
60 } elsif ($b == 65) {
61 cmd("mouse_scroll_down")
62 }
63
64 # proceed only if a button is being released
65 return if ($b != 3);
66
67 return unless (0 <= $oldb && $oldb <= 2);
68 my $button = $BUTTONS[$oldb];
69
70 # if it was a mouse click of the left button (press and release in the same position)
71 if ($x == $oldx && $y == $oldy) {
72 cmd("mouse" . $button . "_click");
73 return;
74 }
75
76 # otherwise, find mouse gestures
77 $xd = $x - $oldx;
78 $yd = -1 * ($y - $oldy);
79 $distance = sqrt($xd*$xd + $yd*$yd);
80 # ignore small gestures
81 if ($distance < 3) {
82 return;
83 }
84 $angle = asin($yd/$distance) * 180 / 3.14159265358979;
85 if ($angle < 20 && $angle > -20 && $xd > 0) {
86 if ($distance <= 40) {
87 cmd("mouse" . $button . "_gesture_right");
88 } else {
89 cmd("mouse" . $button . "_gesture_bigright");
90 }
91 } elsif ($angle < 20 && $angle > -20 && $xd < 0) {
92 if ($distance <= 40) {
93 cmd("mouse" . $button . "_gesture_left");
94 } else {
95 cmd("mouse" . $button . "_gesture_bigleft");
96 }
97 } elsif ($angle > 40) {
98 cmd("mouse" . $button . "_gesture_up");
99 } elsif ($angle < -40) {
100 cmd("mouse" . $button . "_gesture_down");
101 }
102 }
103
104 # executes the command configured in the given setting
105 sub cmd
106 {
107 my ($setting) = @_;
108 signal_emit("send command", settings_get_str($setting), active_win->{'active_server'}, active_win->{'active'});
109 }
110
111
112 signal_add_first("gui key pressed", sub {
113 my ($key) = @_;
114 if ($mouse_xterm_status != -1) {
115 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)
116 @mouse_xterm_previous = @mouse_xterm_combo;
117 }
118 $mouse_xterm_combo[$mouse_xterm_status] = $key-32;
119 $mouse_xterm_status++;
120 if ($mouse_xterm_status == 3) {
121 $mouse_xterm_status = -1;
122 # match screen coordinates
123 $mouse_xterm_combo[1]--;
124 $mouse_xterm_combo[2]--;
125 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]);
126 }
127 signal_stop();
128 }
129 });
130
131 sub UNLOAD {
132 mouse_disable();
133 }
134
135 if ($ENV{"TERM"} !~ /^rxvt|screen|xterm(-color)?$/) {
136 die "Your terminal doesn't seem to support this.";
137 }
138
139 mouse_enable();
140
141 Irssi::command("/^bind meta-[M /mouse_xterm"); # FIXME evil
142 Irssi::command_bind("mouse_xterm", sub {$mouse_xterm_status = 0;});
143 Irssi::command_bind 'mouse' => sub {
144 my ($data, $server, $item) = @_;
145 $data =~ s/\s+$//g;
146 Irssi::command_runsub('mouse', $data, $server, $item);
147 };
148
149 # temporarily disable mouse handling. Useful for copy-pasting without touching the keyboard (pressing shift)
150 Irssi::command_bind 'mouse tempdisable' => sub {
151 my ($data, $server, $item) = @_;
152 my $seconds = ($data eq '') ? 5 : $data; # optional argument saying how many seconds, defaulting to 5
153 mouse_disable();
154 Irssi::timeout_add_once($seconds * 1000, 'mouse_enable', undef); # turn back on after $second seconds
155 };
156
157 for my $button (@BUTTONS) {
158 settings_add_str("lookandfeel", "mouse" . $button . "_click", "/mouse tempdisable 5");
159 settings_add_str("lookandfeel", "mouse" . $button . "_gesture_up", "/window last");
160 settings_add_str("lookandfeel", "mouse" . $button . "_gesture_down", "/window goto active");
161 settings_add_str("lookandfeel", "mouse" . $button . "_gesture_left", "/window prev");
162 settings_add_str("lookandfeel", "mouse" . $button . "_gesture_bigleft", "/eval window prev;window prev");
163 settings_add_str("lookandfeel", "mouse" . $button . "_gesture_right", "/window next");
164 settings_add_str("lookandfeel", "mouse" . $button . "_gesture_bigright", "/eval window next;window next");
165 }
166
167 settings_add_str("lookandfeel", "mouse_scroll_up", "/scrollback goto -10");
168 settings_add_str("lookandfeel", "mouse_scroll_down", "/scrollback goto +10");