2

How can I use ANSI escape codes from within perl to query the cursor position?

I'm trying

use strict;

my $variable;

open GRABSTDOUT, '>', \$variable or die "Can't open STDOUT: $!";
select GRABSTDOUT;

print "\e[6n";
select STDOUT;

print "Cursor location is >$variable<\n";
print "Bye\n";

But the query result is not being caught by my variable

mymachine:~/play> perl ansi.pl
Cursor location is ><
Bye
^[[36;21Rmymachine:~/play> ;21R
Jasancos
  • 711
  • 1
  • 5
  • 11
  • 1
    What makes you think that this could work? What is `GRABSTDOUT`? – innaM May 03 '13 at 14:29
  • GRABSTDOUT is the filehandle whose output I redirect to my variable; I then select GRABSTDOUT to replace STDOUT as default output hoping that when I print the ANSI code it will be redirected there and therefore to my variable. The code may be crude but it's purpose is to show my intent. – Jasancos May 03 '13 at 14:44
  • 1
    Related: http://stackoverflow.com/questions/8343250/how-can-i-get-position-of-cursor-in-terminal – Ilmari Karonen May 03 '13 at 14:50

1 Answers1

4

After looking at the suggested link (How can I get position of cursor in terminal?) I came up with the following horrible piece of code that sort of does what I want, although there's lots of scope for improvement:

use strict;

my $x='';
system "stty cbreak </dev/tty >/dev/tty 2>&1";
print "\e[6n";
$x=getc STDIN;
$x.=getc STDIN;
$x.=getc STDIN;
$x.=getc STDIN;
$x.=getc STDIN;
$x.=getc STDIN;
system "stty -cbreak </dev/tty >/dev/tty 2>&1";

my($n, $m)=$x=~m/(\d+)\;(\d+)/;
print "\nCursor location is $n,$m\n";
print "Bye\n";

Basically when you do an ANSI code query the reply goes to STDIN, as if you had typed it on your terminal, not STDOUT as I thought. You can use

$x=<STDIN>;

but in that case the user needs to press ENTER in order to capture the reply.

Using getc solves this but from what I read it's tricky and has portability issues. (How can I get user input without waiting for enter in Perl?, http://perldoc.perl.org/functions/getc.html).

Community
  • 1
  • 1
Jasancos
  • 711
  • 1
  • 5
  • 11