I wrote this simple program on Windows. Since Windows has conio, it worked just fine.
#include <stdio.h>
#include <conio.h>
int main()
{
char input;
for(;;)
{
if(kbhit())
{
input = getch();
printf("%c", input);
}
}
}
Now I want to port it to Linux, and curses/ncurses seems like the right way to do it. How would I accomplish the same using those libraries in place of conio?
#include <stdio.h>
#include <ncurses.h>
int main(int argc, char *argv)
{
char input;
initscr(); // entering ncurses mode
raw(); // CTRL-C and others do not generate signals
noecho(); // pressed symbols wont be printed to screen
cbreak(); // disable line buffering
while (1) {
erase();
mvprintw(1,0, "Enter symbol, please");
input = getch();
mvprintw(2,0, "You have entered %c", input);
getch(); // press any key to continue
}
endwin(); // leaving ncurses mode
return 0;
}
When building your program do not forget to link with ncurses lib (-L lncurses) flag to gcc
gcc -g -o sample sample.c -L lncurses
And here you can see kbhit() implementation for linux.
Related
I'm new to c, so I'm probably stupid.
Here is somewhat my code:
#include <stdio.h>
#include <stdlib.h>
int main() {
int input;
setvbuf(stdout, NULL, _IONBF, 0);
printf("Welcome to example");
printf("\n" "Select an option." "\n" "1. ex1" "\n" "2. ex2" "\n");
scanf("%d", &input);
if (input == 1) {
printf ("You selected ex1.");
system("echo 'testing.'");
}
else if (input == 2) {
printf ("You selected ex2.");
}
return 0;
}
If you're wondering, I'm running the exe in MSYS2 with ./a.exe
If I input 1, then it should execute the command echo. However, it does nothing.
How do I fix this?
Edit: Heres the output
You selected ex1.
And then the program ends.
It could be because system uses command prompt (I'm having issues with command prompt...), so how do I switch it to use MSYS2 as the system terminal?
I have been looking for an equivalent to kbhit() and I have read several forums on this subject, and the majority seem to suggest using ncurses.
How should I go about checking if a key is pressed in C++ using ncurses?
The function getch() provided by ncurses reads a character from the window.
I would like to write a function that only checks if there is a key press and then I want to do getch().
You can use the nodelay() function to turn getch() into a non-blocking call, which returns ERR if no key-press is available. If a key-press is available, it is pulled from the input queue, but you can push it back onto the queue if you like with ungetch().
#include <ncurses.h>
#include <unistd.h> /* only for sleep() */
int kbhit(void)
{
int ch = getch();
if (ch != ERR) {
ungetch(ch);
return 1;
} else {
return 0;
}
}
int main(void)
{
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
scrollok(stdscr, TRUE);
while (1) {
if (kbhit()) {
printw("Key pressed! It was: %d\n", getch());
refresh();
} else {
printw("No key pressed yet...\n");
refresh();
sleep(1);
}
}
}
I am struggling to have ncurses generate KEY_HOME or KEY_END events, instead the raw escape sequence is coming through as a sequence of characters.
The following simple C program illustrates the problem:
#define _XOPEN_SOURCE 700
#include <curses.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
void clean(void)
{
echo();
nl();
nocbreak();
endwin();
}
int main(int argc, char *argv[])
{
setvbuf(stderr, NULL, _IONBF, 0);
initscr();
cbreak();
nonl();
noecho();
atexit(clean);
keypad(stdscr, TRUE);
clear();
refresh();
int ch = getch();
if (ch == ERR)
errx(EXIT_FAILURE, "getch");
warnx("read: %x", ch);
halfdelay(1);
while((ch = getch()) != ERR)
{
warnx("read: %x", ch);
}
exit(EXIT_SUCCESS);
}
Compile with -lncurses, and redirect stderr to a log file.
When pressing HOME:
test: read: 1b
test: read: 5b
test: read: 31
test: read: 7e
When pressing UP
test: read: 103
How come HOME and END (and indeed F1 etc.) are not parsed by ncurses into KEY_HOME?
You probably have set TERM to a value which does not match the terminal's behavior. For instance, the linux terminal description has khome=\E[1~ (which corresponds to the example output), while xterm has khome=\E[OH. You can see this using
infocmp linux xterm | grep khome
If the terminal description does not match the actual behavior, ncurses will not match the incoming bytes, and will behave as shown.
This question already has answers here:
How to read terminal's input buffer immediately after keypress
(2 answers)
Closed 6 years ago.
I have follow situation I have an program make an set of operations on a file continuously and I want, when a specific key is pressed, to stop and do another set of operations.
For this I tryed use scanf of an character with
fcntl(0, F_SETFL, O_NONBLOCK);
and
while(feof(stdin))
but it doesn't work as expected.
I have searched and in some places someone says to use select but I can't find how to use it.
Anyone can advice me somehow?
my main function to provide more information:
int main(int argc, char *argv[])
{
if(argc>1){
char* password;
char* password2;
printf("Password? ");
password = get_password();
printf("Repita a password? ");
password2 = get_password();
if(strcmp(password,password2)!=0){
printf("Passwords diferentes!\n");
exit(1);
}
FILE *fptr;
fptr = fopen("./regist", "r");
if(fptr == NULL) //if file does not exist, create it
{
fptr = fopen("./regist", "w");
}
fclose(fptr);
if(find_username(argv[1])){
printf("Utilizador ja existe\n");
exit(1);
}
add_user_regist(argv[1],password);
printf("Utilizador %s adicionado.\n",argv[1]);
exit(0);
}
char readbuf[250];
/* Create the FIFO if it does not exist */
umask(0);
mknod(FIFO_FILE, S_IFIFO|0666, 0);
printf("Servidor iniciado.\nEm modo de espera de mensagens\n");
fcntl(0, F_SETFL, O_NONBLOCK);
while(1){
char c = getchar();
if(c=='q' || c=='Q')
exit(0);//by now only goes out
fp = fopen(FIFO_FILE, "r");
fgets(readbuf, 250, fp);
fclose(fp);
if(readbuf[0]=='U')
user_access(readbuf);
else if(readbuf[0]=='W')
who_online(readbuf);
else if(readbuf[0]=='R'){
char* tmp;
strtok(readbuf,":");
tmp = strtok(NULL,";");
remove_online(tmp);
printf("# %s fez logout\n",tmp);
}
else if(readbuf[0]=='F'){
process_msg(readbuf);
}
}
return(0);
}
Check out NCurses, the go-to library for any kind of advanced terminal software.
Among other things, it provides you with the tools to do "raw" terminal I/O -- using int getch( void ), made a non-blocking call via int nodelay( WINDOWS * win, bool bf ).
This blocks:
#include <ncurses.h>
int main()
{
initscr();
printw( "Press a key:\n" );
int c = getch();
endwin();
}
This doesn't (returning ERR if there is no input pending):
#include <ncurses.h>
int main()
{
initscr();
printw( "Press a key:\n" );
nodelay( stdscr, TRUE );
int c = getch();
endwin();
}
Note that NCurses comes with its own set of I/O functions, which you will have to use instead of the <stdio.h> ones (check the printw() above).
An alternative to termios/ncurses using GNU Readline:
#include <readline/readline.h>
#include <stdio.h>
static int func(int count, int key)
{
printf ("key pressed: %c\n", key); /* exec your function */
return 0;
}
int main(void)
{
char *line;
rl_bind_key('x', func); /* 'x' is the specific key */
line = readline ("> ");
printf("%s\n", line);
return 0;
}
Compile using -lreadline
I've written a program to encrypt a given message by XOR. It works, but It doesn't end. Here is the code.(I have created 3 files):
encrypt.h :
void encrypt(char *message);
message_hider.c:
#include <stdio.h>
#include "encrypt.h"
int main() {
char msg[80];
while (fgets(msg, 80, stdin)){
encrypt(msg);
printf("%s", msg);
}
return 0;
}
encrypt.c :
#include "encrypt.h"
void encrypt(char *message) {
while (*message) {
*message++ ^= 0x1f;
}
}
As I mentioned above, It works. but I can't stop it. When I pressed Ctrl+D to stop it (in cmd) It encrypts it also.(I need this code stop after it encrypt a message). Please explain me about this case.
When I pressed Ctrl+D to stop it (in cmd)
If that's the cmd from Windows you probably want Ctrl+Z.
Ctrl-D is used for the console EOF on Unix systems.
Ctrl-Z is used for the console EOF on Windows systems.
isprint() can help:
#include <stdio.h>
#include <ctype.h>
void encrypt(char *message)
{
while (*message) {
*message = *message ^ 31;
message++;
}
}
int main(void)
{
char msg[80];
while (fgets(msg, 80, stdin) != NULL) {
if (!isprint((unsigned char)*msg)) break;
encrypt(msg);
printf("%s", msg);
}
return 0;
}
Add an exit condition:
if( c < 0x20 ) break;
You may need to add other checks also to support backspace without encoding it...
http://www.asciitable.com/
Just run
$> kill -l
To see the list of signals in Linux. You will not find SIGKILL (Ctrl + D) signal there :(
Ctrl + D is SIGKILL (0) signal in Linux which is not documented anywhere.
Ctrl + Z is for Windows which tell EOF and we need to press "Enter" to close.