ncurses only reporting mouse movement when bstate is non-zero - c

I'm following along with the code from
https://gist.github.com/sylt/93d3f7b77e7f3a881603
Here it is, in case of 404
#include <curses.h>
#include <stdio.h>
int main()
{
initscr();
cbreak();
noecho();
// Enables keypad mode. This makes (at least for me) mouse events getting
// reported as KEY_MOUSE, instead as of random letters.
keypad(stdscr, TRUE);
// Don't mask any mouse events
mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
printf("\033[?1003h\n"); // Makes the terminal report mouse movement events
fflush(stdout);
for (;;) {
int c = wgetch(stdscr);
// Exit the program on new line fed
if (c == '\n')
break;
char buffer[512];
size_t max_size = sizeof(buffer);
if (c == ERR) {
snprintf(buffer, max_size, "Nothing happened.");
}
else if (c == KEY_MOUSE) {
MEVENT event;
if (getmouse(&event) == OK) {
snprintf(buffer, max_size, "Mouse at row=%d, column=%d bstate=0x%08lx",
event.y, event.x, event.bstate);
}
else {
snprintf(buffer, max_size, "Got bad mouse event.");
}
}
else {
snprintf(buffer, max_size, "Pressed key %d (%s)", c, keyname(c));
}
move(0, 0);
insertln();
addstr(buffer);
clrtoeol();
move(0, 0);
}
printf("\033[?1003l\n"); // Disable mouse movement events, as l = low
endwin();
return 0;
}
When I put that into a file and compile it (gcc -o test test.c -lncurses), in xterm, mouse movements are reported without a button press. In gnome-terminal and Konsole, the movement events are only reported if a button on my mouse is pressed!
I would usually say it's just a compatibility/ standards thing BUT when I execute:
printf '\033[?1003h' on gnome-terminal or konsole, I can see all the mouse movements reported without any buttons pressed!
So what's going on here? How do I persuade gnome-terminal and konsole to behave like xterm? Or even to behave like themselves when they are in bash mode?
EDIT: Additional clues:
It appears this code works on all terminals if I scroll my mouse wheel. It's more than likely that this is what happened when I originally tested in xterm, as even xterm requires either a button pressed or the mouse to be scrolled for this to work.
Therefore: my question becomes why does the terminal only report mouse movement after the bstate has been modified in some way, even when the terminal reports escape sequences in bash mode?

Related

C - How to use halfdelay(i) in the ncurses library

I am trying to create a snake game in C using the ncurses library. I would like my program to detect user input at a constant tick speed. If there is no input after a certain amount of time I would like my program to continue along (ie. update game).
This is what I wrote to test out the halfdelay(i) function:
#include <ncurses.h>
int main(void)
{
initscr();
halfdelay(5);
int user_input;
do
{
user_input = getch();
if (user_input != -1)
{
clear();
printw("Key pressed: %d\n", user_input);
}
else
{
//printf("Timeout.\n");
printw("Timeout.\n");
}
} while (user_input != ESC);
endwin();
return 0;
}
EDIT #1:
I would like to see
Timeout.
Timeout.
Timeout.
Code used:
#include <ncurses.h>
int main(void)
{
initscr();
halfdelay(5);
int in;
do
{
timeout(1);
in = getch();
if (in != -1)
{
clear();
printw("Key pressed: %d\n", in);
}
else
{
//printf("Timeout.\n");
printw("Timeout.\n");
}
refresh();
} while (in != 27);
endwin();
return 0;
}
Some history first.
Traditionally, the ESC key value has been used as the prefix for escape sequences, which denote special sequences of characters that can be interpreted as a non-graphic character (e.g., an arrow key, a function key, etc.)
Due to (n)curses focus on portability (and telecommunication), out of the box it supports this notion of escape sequences, and as such pressing the ESC key can have some side effects. Notably, when keypad is enabled, there is an inbuilt delay as the program waits to decide if the user simply pressed ESC or if it needs to wait for some more information to complete the escape sequence. This timing can be adjusted via the ESCDELAY environment variable, or the set_escdelay function.
All this is important as you work forward, as given its a game you may want to enable the functionality of the keypad eventually, which will create some extra steps when using the ESC key.
And because of all this, there is no ESC or KEY_ESC macro for for the escape key. Instead, its raw code is 27 (or the octal 033).
Your use of the halfdelay function seems perfectly fine to me, just know that the argument is in tenths of a second, so 5 is half a second. Tenths of a second may not achieve the desired effect in a game, so consider using the timeout function instead, which allows for higher precision.
A simple, working example:
#include <ncurses.h>
int main(void) {
initscr();
halfdelay(5);
int user_input;
while ((user_input = getch()) != 27) {
clear();
if (user_input == ERR)
printw("Timeout.");
else
printw("Key pressed: %d\n", user_input);
refresh();
}
endwin();
}
Your updated program "works", it just doesn't clear the screen properly. Note that you probably don't want to mix calls to printw and printf as it creates a strange mess of the screen.
Also, you should use halfdelay or timeout, but not both. Remember that timeout takes its argument in milliseconds, which is 1/1000 of a second, and it sets the blocking delay for a window (timeout for stdscr, wtimeout for specific windows). It's not a "sleep" style function.
Use one delay function at a time, move clear to outside the if statement, and use printw. This is functionally the same program to the one posted above, just with a do ... while loop.
#include <ncurses.h>
int main(void) {
initscr();
/*
noecho();
scrollok(stdscr, TRUE);
*/
timeout(500);
int in;
do {
in = getch();
clear();
if (in != ERR)
printw("Key pressed: %d\n", in);
else
printw("Timeout.\n");
refresh();
} while (in != 27);
endwin();
}
If you are expecting the display of this program to be something along the lines of
Timeout.
Timeout.
Key pressed: 65
Timeout.
...
like a more traditional terminal, then you simply want to remove clear all together, and un-comment noecho and scrollok.

Capturing Mouse in Virtual Terminal with ANSI Escape

I've started to learn about ANSI escape sequences online through the magic of Google. It is neat being able to position the cursor \e[row;colH on the screen and set the colors of the outputs (ie: \e[31m).
Next I would like try and see how the mouse able to be captured in a virtual terminal. I realize this code is not portable, and I know I can use ncurses or some other curses library, but the goal here is to learn how it works, not write production code with it.
I have tried \e[?1003h and it starts to fill the screen with mouse events. (Pretty cool!) However, how do I capture these in a C or C++ program?
I saw an example of what I would like to do in PHP: https://stackoverflow.com/a/58390575/1770034
However, when I try to port the code over to something in C it just locks up in the while loop. (Tested with GDB to find that out.)
#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
}
I have also tried scanf and it just locks up until I hit enter, and I'm not convinced it is seeing the mouse events.
Edit
I now have some working code that spits out the mouse events.
Here is the updated code from applying the accepted answer to this question:
#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;
}
Two problems:
printf is (using stdout) buffered, so there's no guarantee that the escape sequences got to the terminal before attempting to read.
stdin isn't necessarily the terminal (though it might be). Again, fread is buffered (and you may not get the result as promptly as you wish).
Since stderr is not buffered, it would help to send the escape sequences with that stream. Rather than using fread, it can help to use read, e.g.,
read(fileno(stdin), buffer, 16)

Recognizing special keys without taking over the screen

In a program that uses the curses or ncurses library, the getch() function can recognize either an ordinary character (like 'x') or the escape sequence sent by the arrow and function keys. For example, typing the up arrow key might send the sequence (Escape, '[', 'A'), but getch() will return the int value KEY_UP. It even uses timing information to distinguish between an Escape character sent by itself and an Escape character that's part of a sequence.
To use getch() successfully, you first have to call initscr(), which clears the screen so that curses can control what's displayed.
Is there a convenient way to recognize special keys without taking over the screen? Ideally I'd like to call getch() without first calling initscr(), and have it return the same value it would have returned if I had called initscr(), but experiment indicates that doesn't work.
Here's a non-working example of what I'm trying to do. The program prompts the user to enter Up, Down, Escape, Left, Right, and conforms that the correct keys were entered.
Running the program with -c invokes initscr() and allows it to work correctly. Running it without -c calls getch() without first calling initscr(); all the getch() calls fail without waiting for input, returning ERR (-1).
// gcc arrows.c -o arrows -lncurses
#include <term.h>
#include <stdio.h>
#include <curses.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int use_curses = 0;
if (argc == 2 && strcmp(argv[1], "-c") == 0) {
use_curses = 1;
}
else if (argc != 1) {
fprintf(stderr, "Usage: %s [-c]\n", argv[0]);
exit(EXIT_FAILURE);
}
WINDOW *win;
if (use_curses) {
win = initscr();
cbreak();
noecho();
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
mvaddstr(0, 0, "Press UP, DOWN, Escape, LEFT, RIGHT");
}
else {
puts("Press UP, DOWN, Escape, LEFT, RIGHT");
}
int keys[5];
for (int i = 0; i < 5; i ++) {
keys[i] = getch();
}
int ok;
if (keys[0] == KEY_UP &&
keys[1] == KEY_DOWN &&
keys[2] == '\x1b' &&
keys[3] == KEY_LEFT &&
keys[4] == KEY_RIGHT)
{
ok = 1;
if (use_curses) {
mvaddstr(2, 0, "OK");
}
else {
puts("OK");
}
}
else {
ok = 0;
char message[100];
sprintf(message,
"Incorrect input: (%d, %d, %d, %d, %d)",
keys[0], keys[1], keys[2], keys[3], keys[4]);
if (use_curses) {
mvaddstr(2, 0, message);
}
else {
puts(message);
}
}
if (use_curses) {
mvaddstr(4, 0, "Press any key to quit ");
(void)getch();
endwin();
}
exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
}
The output without the -c option (on Ubuntu 17.04 x86_64) is:
Press UP, DOWN, Escape, LEFT, RIGHT
Incorrect input: (-1, -1, -1, -1, -1)
UPDATE: A solution using something other than curses would be fine. It would have to use terminfo, directly or indirectly, to know what input sequences to look for. (It seems to me that recognizing special key inputs should be straightforward and not intimately tied to taking over the entire screen.)
The filter function, called before initscr, tells curses to use a single line (rather than the whole screen). There is an example of its use (named "filter") in ncurses-examples, which consists of a command-prompt.
getch updates at least part of the screen, e.g., when it echoes the input. That update can affect either just a line (using filter), or the whole screen. If you're clever, you can turn off echo, and (since filter suppresses the screen erasure), pretend that it updates nothing at all. For example, you could redirect the output to /dev/null by initializing curses with newterm.
Echoing input is only part of the story: curses does initialize the screen, and the associated refresh done by getch would make that hard to avoid in a portable way. There's an ncurses-specific option in the sample program which works around unwanted switching between normal/alternate screens, which could occur during screen-initialization.
Here's a screenshot of "filter", demonstrating that it does not take over the whole screen. The inverse video is due to ncurses initializing colors (white-on-black), but as the help-message indicates, that's configurable. Without making a movie, it's hard to demonstrate that it handles special keys, but reading the source code should be enough.

Trying to get a process running running without an SDL (percieved) crash C

Okay so I'm pretty new to programming, so I thought as my first real programming challenge I would make a chess program to teach openings. Inside my game game loop I have everything I need, except at some point in the game loop I want to stop for input from the user, and wait to process that information before drawing the screen and continuing the loop. However when I do that, if the user waits to long to input(~8 seconds)(btw the input in console input for now, that will change later) then the game just crashes and I get the standard ubuntu "do you want to force quit or wait" message. I would like to keep this message from popping up, but I don’t know how.
Here's my code btw:
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "SDL2/SDL.h"
void drawBoard(SDL_Renderer *renderer)
{}
void drawPieces(char fen[100])
{}
int processEvents(SDL_Window *window)
{}
I'm leaving these functions out because the are long and not super important(if you want me to I’ll put them up later)
void next_move(char firstmove[10], char response[10])
{
int cont = 0;
char move[6];
printf("%s\n>>", firstmove);
while(cont == 0)
{
scanf("%s", move);
if(strcmp(move, response) == 0)
cont = 1;
else
printf("Incorrect.\n%s\n>>", firstmove);
}
}
void caro_kann()
{
printf("YOU HAVE SELECTED The Caro Kann Opening ( main line )\n");
next_move("1. e4", "c6");
next_move("2. d4", "d5");
next_move("3. Nc6", "dxe4");
next_move("4. Nxe4", "Bf5");
next_move("5. Ng3", "Bg6");
next_move("6. h4", "h6");
next_move("7. Nf3", "Nd7");
printf("success\n");
}
int main()
{
int done = 0;
SDL_Event event;
SDL_Window *window;
SDL_Renderer *renderer;
//initialize everything
SDL_Init(SDL_INIT_VIDEO);
//setting up the window
window = SDL_CreateWindow("PlatoChess ALPHA 1.0",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800,
800,
0);
//Setting up the renderer
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
//setting up the program loop
while(!done)
{
if(processEvents(window) == 1)
done = 1;
caro_kann();
drawBoard(renderer);
SDL_Delay(10); //to cap the FPS
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
Any help would be much appreciated!
First of all, "do you want to force quit or wait" is not a crash. All it means is that your program isn't processing events (which is true - you're in a blocking scanf and doing nothing). Even if you're waiting for something to happen, you still should process window events and update display if necessary, otherwise user can't close your program and if it gets overshadowed by another program (or just minimised) its display will be completely wrong.
Basically you shouldn't block in wait for input. Your options are (sorted by ascending difficulty, based entirely on my opinion):
change input scheme (e.g. use keyboard events that SDL gives you instead of stdin)
perform nonblocking read from stdin when input is available
use separate input thread (requires sync)

Using 'CLS' command in C causes screen blink

I am trying to clear my console each time I am going to printf something in it (Windows environment with GCC compiler). I am using CygWin and the only way I could manage to do it was with system("cmd /c cls");. That works fine but it causes the screen to blink for a fraction of a second which is obviously annoying.
Is there any alternative way of clearing console screen?
First thing I'd do is stop using cmd to do it. CygWin, assuming you're running somewhere within the shell and not a Windows console, has a "native" option in that you can use either of:
clear
tput clear
to clear the screen, without invoking the external cmd interpreter.
So, from within a program running in CygWin, you can clear the screen with a simple:
system("clear");
Of course, if you don't want to run any external executables, you can achieve the same end with curses. By way of example, the following program clears the screen for you (make sure you include -lcurses at the end of the compilation command):
#include <curses.h>
int main (void) {
WINDOW *w = initscr();
clear(); refresh(); sleep(2);
endwin();
return 0;
}
Don't get hung up on the fact that it's restored on exit, you wouldn't be using this program as a screen clearing stand-alone thing. Instead, the statements would be incorporated into your own program, between the initscr() and endwin() calls, something like:
#include <curses.h>
int main (void) {
char buf[2],
*msg = "Now is the time for all good men to come to lunch.";
WINDOW *w = initscr();
buf[1] = '\0';
clear();
refresh();
while (*msg != '\0') {
buf[0] = *msg++; addstr(buf);
if ((buf[0] == ' ') || (buf[0] == '.')) {
refresh();
sleep(1);
}
}
endwin();
return 0;
}
This program clears the screen using curses then outputs a message in word-sized chunks.
this web page:
http://man7.org/linux/man-pages/man4/console_codes.4.html
contains the common ESC sequences for handling the terminal screen/cursor position, etc
this part of the linked info is probably what you want to implement.
These escape sequences can be placed at the beginning of the buffer that you are using to output your data/text
Of special interest is ESC [ 2 j: which erases the whole screen
J ED Erase display (default: from cursor to end of display).
ESC [ 1 J: erase from start to cursor.
ESC [ 2 J: erase whole display.
ESC [ 3 J: erase whole display including scroll-back
buffer (since Linux 3.0).

Resources