Захват мыши в виртуальном терминале с помощью ANSI Escape - PullRequest
0 голосов
/ 22 января 2020

Я начал узнавать о escape-последовательностях ANSI онлайн через магию c Google. Это хорошая возможность позиционировать курсор \e[row;colH на экране и устанавливать цвета выходов (ie: \e[31m).

Далее я хотел бы попытаться увидеть, как мышь способна быть захваченным в виртуальном терминале. Я понимаю, что этот код не переносим, ​​и я знаю, что могу использовать ncurses или какую-либо другую библиотеку curses, но цель здесь - узнать, как это работает, а не писать производственный код с ним.

Я пробовал \e[?1003h и он начинает заполнять экран событиями мыши. (Довольно круто!) Однако, как мне запечатлеть их в программе C или C ++?

Я видел пример того, что я хотел бы сделать в PHP: { ссылка }

Однако, когда я пытаюсь перенести код на что-то в C, он просто блокируется, пока l oop. (Протестировано с помощью GDB, чтобы выяснить это.)

#include <stdio.h> //bring in printf and fread

int main()
{
    system("stty -echo"); //make the terminal not output mouse events
    system("stty -icanon"); //put stdin in raw mode
    printf("\e[?1003h\e[?1015h\e[?1006h"); //start getting mouse events
    char* buffer[255];
    while(fread(buffer, 16, 1, stdin)) // <-- suppose to read in the mouse events
    {
        printf("here"); //Did you actually work?!
    }
    printf("\e[?1000l"); //Turn off mouse events
    system("stty echo"); //Turn echoing of the display back on
    return 0; //end the program in a successful state
}

Я также пытался scanf, и он просто зависал, пока я не нажал enter, и я не уверен, что видит события мыши.

Редактировать

Теперь у меня есть некоторый рабочий код, который выплевывает события мыши.

Вот обновленный код от применения принятого ответа на этот вопрос :

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>

int main()
{
    system("stty -echo"); //don't show mouse events on screen
    system("stty -icanon");
    fprintf(stderr, "\e[?1003h\e[?1015h\e[?1006h"); //use stderr since not buffered turn on mouse event capture
    char buffer[16] = " ";
    char previousBuffer[16] = " ";

    //Make standard in not be blocking
    int flags = fcntl(stdin->_fileno, F_GETFL, 0);
    fcntl(stdin->_fileno, F_SETFL, flags | O_NONBLOCK);

    for (int hunSeconds = 0; hunSeconds < 500; hunSeconds++) //Run for 50 seconds
    {
        read(fileno(stdin), buffer, 16); //read mouse input
        if (strcmp(buffer, previousBuffer) != 0) //only show event if it is different
        {
            fprintf(stderr, "%s", buffer);
            strncpy(previousBuffer, buffer, 16);
        }
        usleep(100); // sleep for .1 seconds
    }
    printf("\e[?1000l"); //turn off mouse events
    system("stty echo"); //turn on screen echo again
    return 0;
}

1 Ответ

1 голос
/ 22 января 2020

Две проблемы:

  • printf (используя stdout ) буферизуется, поэтому нет никакой гарантии, что escape-последовательности дошли до терминала перед попыткой чтения.
  • stdin не обязательно является терминалом (хотя это может быть). Опять же, fread буферизуется (и вы не можете получить результат так же быстро, как вы sh).

, поскольку stderr нет буферизованный, это поможет отправить escape-последовательности с этим потоком. Вместо использования fread это может помочь использовать read, например,

read(fileno(stdin), buffer, 16)
...