ターミナルのカーソル位置を取得
(2018/3/21)
ESC [ 6 n
というエスケープシーケンスを利用してターミナル上のカーソル位置を取得する話 VT100のようなターミナルのカーソルを動かすために
ESC [ ...
というエスケープシーケンスが広く利用されている MacのTerminal.appをはじめ、現在ほぼすべてのターミナルエミュレータはVT100互換(というかANSI)なので同じシーケンスを使うことができる
エスケープシーケンスは普通はカーソルを動かすために使われるのだが、カーソル位置を知るためのシーケンスも用意されており、これを使ってターミナル上のカーソル位置を知るプログラムを書くことができる
ESC [ 6 n
という問い合わせシーケンスを送るとき tty
からエコーが返るのは嫌なのでエコーは禁止しておくのが良いと思われる ioctl(2)
で制御できると思ったのだがどうもうまくいかない tcgetattr(3)
でできるということを教えてもらってやっとうまくいった このシーケンスの話はこちらで知った
エスケープシーケンスだの
ioctl()
だのには前世紀におおいに苦労したものだが、Web時代だとそんな情報ぐらい楽々手に入るだろうと思ったら意外に大変だった 話題が古いせいかサンプルプログラムもほとんどみつからなかった
cursorpos.c
#include <stdio.h>
#include <unistd.h>
#include <termios.h>
struct termios state, oldstate;
void echo_off()
{
tcgetattr(0, &oldstate);
state = oldstate;
state.c_lflag &= ~(ICANON | ECHO);
tcsetattr(0, TCSANOW, &state);
}
void echo_on()
{
tcsetattr(0, TCSANOW, &oldstate);
}
int main(){
char buf[10];
char *p = buf;
char c;
echo_off();
write(0,"\x1b[6n",4);
for (int i=0;;i++){
read(0,&c,1);
if(c >= 0x30 && c <= 0x39) *p++ = c;
if(c == ';') *p++ = ' ';
if(c == 'R') break;
}
*p = '\0';
echo_on();
printf("%s\n",buf);
}
2018/3/21 09:59