如何使用termcap获取C程序中的光标位置,而不写字符? [英] How to get the cursor position in a C program using termcap, without writing a character?

查看:11
本文介绍了如何使用termcap获取C程序中的光标位置,而不写字符?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道如何在我的程序中获取光标位置 (x, y),而不在屏幕上写任何东西,也不会一直跟踪它.

我找到了一种使用此函数获取其位置的方法(我在这里不检查读取、写入等的返回来编写有关此主题的较小代码,但我在我的程序中这样做):

void get_cursor_position(int *col, int *rows){int a = 0;int i = 0;字符缓冲区[4];写(1,33[6n",4);//请求光标位置的字符串读(1,缓冲区,4);而 (buf[i]){如果 (buf[i] >= 48 && buf[i] <= 57){如果 (a == 0)*rows = atoi(&buf[i]) - 1;别的*col = atoi(&buf[i]) - 1;一个++;}我++;}}

这个函数给了我准确的光标位置(*rows = y,*col = x),但它写在屏幕上.

如何在屏幕上不写任何东西的情况下获取光标位置?
(如果光标在打印的字符之一上,它将覆盖它.)
应该在发送转义序列之前和之后切换 echo 吗?

这是一个学校项目,所以我只能用termcap,不能用ncurses函数,唯一允许的函数是tputs、tgoto、tgetstr、tgetnum、tgetflag.

解决方案

有几个问题:

  • 规范模式是缓冲(见下文)

  • read 是在标准输出的文件描述符上完成的(这可能碰巧工作—有时—但不要指望它)

  • read 没有读取足够的字符来获得典型的响应

  • 响应将有两个十进制整数,用分号分隔 ;

  • 响应将有一个最终字符(如果 read 实际上要求足够的字符,这将成为一个问题...)

进一步阅读:

<块引用>

在规范模式输入处理中,终端输入以行为单位进行处理.一行由换行符 (NL)、文件结束符 (EOF) 或行结束符 (EOL) 字符.有关 EOFEOL 的更多信息,请参阅特殊字符.这意味着 read 请求将返回,直到输入整行或接收到信号.此外,无论在 read() 调用中请求多少字节,最多返回一行.然而,没有必要一次阅读整行;可以在 read() 中请求任意数量的字节,甚至是一个字节,而不会丢失信息.

<前>CSI Ps n 设备状态报告 (DSR).Ps = 5 -> 状态报告.结果(OK")是 CSI 0 nPs = 6 -> 报告光标位置 (CPR) [行;列].结果是 CSI r ;cR

也就是说,你的程序应该准备好读取Escape[后跟两个十进制整数(长度没有固定限制),以及另外两个字符 ;R.

顺便说一下,termcap 本身对您的解决方案几乎没有帮助.虽然 ncurses 在终端数据库中定义了一些相关功能:

# u9 终端查询字符串(相当于 ANSI/ECMA-48 DA)# u8 终端应答描述# u7 光标位置请求(相当于 VT100/ANSI/ECMA-48 DSR 6)# u6 光标位置报告(相当于 ANSI/ECMA-48 CPR)

很少有程序使用这些,而且无论如何您都会发现在 termcap 应用程序中使用光标位置报告很困难.

I would like to know how to get the cursor position (x, y) in my program, without writing anything on the screen neither tracking it all the time.

I found out a way to get its position with this function (I don't check the return of read, write, etc here to write a smaller code on this subject but I do it in my program):

void get_cursor_position(int *col, int *rows)
{
    int a = 0;
    int i = 0;
    char buf[4];

    write(1, "33[6n", 4); // string asking for the cursor position
    read(1, buf, 4);

    while (buf[i])
    {
        if (buf[i] >= 48 && buf[i] <= 57)
        {
            if (a == 0)
                *rows = atoi(&buf[i]) - 1;
            else
                *col = atoi(&buf[i]) - 1;
            a++;
        }
        i++;
    }
}

This function gives me the exact cursor position (*rows = y, *col = x), but it writes on the screen.

How can I get the cursor position without writing anything on the screen?
(If the cursor is on one of the printed characters, it will overwrite it.)
Should echo be toggled before and after sending the escape sequence?

This is a school project, so I only can use termcap, I can't use ncurses functions, the only allowed functions are tputs, tgoto, tgetstr, tgetnum, tgetflag.

解决方案

There are several problems:

  • canonical mode is buffered (see below)

  • the read is done on the file-descriptor for standard output (that may happen to work — sometimes — but don't count on it)

  • the read does not read enough characters to get a typical response

  • the response would have two decimal integers, separated by semicolon ;

  • the response would have a final character (which would become an issue if the read actually asked for enough characters...)

Further reading:

In canonical mode input processing, terminal input is processed in units of lines. A line is delimited by a newline character (NL), an end-of-file character (EOF), or an end-of-line (EOL) character. See Special Characters for more information on EOF and EOL. This means that a read request will not return until an entire line has been typed or a signal has been received. Also, no matter how many bytes are requested in the read() call, at most one line will be returned. It is not, however, necessary to read a whole line at once; any number of bytes, even one, may be requested in a read() without losing information.

    CSI Ps n  Device Status Report (DSR).
                Ps = 5  -> Status Report.
              Result ("OK") is CSI 0 n
                Ps = 6  -> Report Cursor Position (CPR) [row;column].
              Result is CSI r ; c R

That is, your program should be prepared to read Escape[ followed by two decimal integers (with no fixed limit on their length), and two other characters ; and R.

By the way, termcap by itself will do little for your solution. While ncurses has some relevant capabilities defined in the terminal database:

#       u9      terminal enquire string (equiv. to ANSI/ECMA-48 DA)
#       u8      terminal answerback description
#       u7      cursor position request (equiv. to VT100/ANSI/ECMA-48 DSR 6)
#       u6      cursor position report (equiv. to ANSI/ECMA-48 CPR)

few programs use those, and in any case you would find it difficult to use the cursor position report in a termcap application.

这篇关于如何使用termcap获取C程序中的光标位置,而不写字符?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆