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 20use strict; 21use 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); 22use Math::Trig; 23 24use 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 37my @BUTTONS = ('', '_middle', '_right'); 38 39my $mouse_xterm_status = -1; # -1:off 0,1,2:filling mouse_xterm_combo 40my @mouse_xterm_combo = (3, 0, 0); # 0:button 1:x 2:y 41my @mouse_xterm_previous; # previous contents of mouse_xterm_combo 42 43sub mouse_enable { 44 print STDERR "\e[?1000h"; # start tracking 45} 46 47sub mouse_disable { 48 print STDERR "\e[?1000l"; # stop tracking 49} 50 51# Handle mouse event (button press or release) 52sub 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 105sub cmd 106{ 107 my ($setting) = @_; 108 signal_emit("send command", settings_get_str($setting), active_win->{'active_server'}, active_win->{'active'}); 109} 110 111 112signal_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 131sub UNLOAD { 132 mouse_disable(); 133} 134 135if ($ENV{"TERM"} !~ /^rxvt|screen|xterm(-color)?$/) { 136 die "Your terminal doesn't seem to support this."; 137} 138 139mouse_enable(); 140 141Irssi::command("/^bind meta-[M /mouse_xterm"); # FIXME evil 142Irssi::command_bind("mouse_xterm", sub {$mouse_xterm_status = 0;}); 143Irssi::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) 150Irssi::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 157for 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 167settings_add_str("lookandfeel", "mouse_scroll_up", "/scrollback goto -10"); 168settings_add_str("lookandfeel", "mouse_scroll_down", "/scrollback goto +10"); 169