OS X - Keypress in an if statement - c++

I am quite new to C++ programming and using Mac as a computer.
I've been searching around the internet for a while now but I can't still find a good solution for my problem.
I am making a project with the Keyboard Arrows, but I don't know how to make the Keypress function in an if statement.
So the solution I am searching for is:
if (up arrow is pressed) {
std::cout << it worked! << std::endl;
}
Information:
LLVM Compiler, Xcodes command line tool, Unix, OS X-Sierra
Thank you for the help.

Well I couldn't get the code in the other answer to work, not sure what's different since I'm also running Sierra. But I converted it to using tcsetattr. The point of that call is to put the terminal in raw mode, such that it sends key presses directly. If you don't do that it won't send anything until you press enter.
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
static struct termios savemodes;
static int havemodes = 0;
int tty_break(void)
{
struct termios modmodes;
if (tcgetattr(STDIN_FILENO, &savemodes) < 0)
return -1;
havemodes = 1;
modmodes = savemodes;
cfmakeraw(&modmodes);
return tcsetattr(STDIN_FILENO, TCSANOW, &modmodes);
}
int tty_getchar(void)
{
return getchar();
}
int tty_fix(void)
{
if(!havemodes)
return 0;
return tcsetattr(STDIN_FILENO, TCSANOW, &savemodes);
}
int
main(int argc, char *argv[])
{
int i;
if(tty_break() != 0)
return 1;
for(i = 0; i < 10; i++)
printf(" = %d\n", tty_getchar());
tty_fix();
return 0;
}

I have put the code which I linked to in the comments together into a single program so you can see how it works.
#include <stdio.h>
#include <sgtty.h>
static struct sgttyb savemodes;
static int havemodes = 0;
int tty_break()
{
struct sgttyb modmodes;
if(ioctl(fileno(stdin), TIOCGETP, &savemodes) < 0)
return -1;
havemodes = 1;
modmodes = savemodes;
modmodes.sg_flags |= CBREAK;
return ioctl(fileno(stdin), TIOCSETN, &modmodes);
}
int tty_getchar()
{
return getchar();
}
int tty_fix()
{
if(!havemodes)
return 0;
return ioctl(fileno(stdin), TIOCSETN, &savemodes);
}
main()
{
int i;
if(tty_break() != 0)
return 1;
for(i = 0; i < 10; i++)
printf(" = %d\n", tty_getchar());
tty_fix();
return 0;
}
You can compile it simply with:
clang main.c -o main
and run it with:
./main
You will see that the ↑ (Up Arrow) key causes the following codes:
27 (Escape)
91
65
Note the code is not mine - it is entirely extracted from the C-FAQ I mentioned above.

Related

How to find the PID of any process in Mac OSX C++

I need to find the PID of a certain program on Mac OSX using C++ and save it as an variable. I have been looking for the answer for this question for a while, and I can't find a detailed one, or one that works. If anyone has an idea on how to do this, please reply.
Thanks!
You can use proc_listpids in conjunction with proc_pidinfo:
#include <libproc.h>
#include <stdio.h>
#include <string.h>
void find_pids(const char *name)
{
pid_t pids[2048];
int bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
int n_proc = bytes / sizeof(pids[0]);
for (int i = 0; i < n_proc; i++) {
struct proc_bsdinfo proc;
int st = proc_pidinfo(pids[i], PROC_PIDTBSDINFO, 0,
&proc, PROC_PIDTBSDINFO_SIZE);
if (st == PROC_PIDTBSDINFO_SIZE) {
if (strcmp(name, proc.pbi_name) == 0) {
/* Process PID */
printf("%d [%s] [%s]\n", pids[i], proc.pbi_comm, proc.pbi_name);
}
}
}
}
int main()
{
find_pids("bash");
return 0;
}

How can I interrupt a loop with a key press in C++ on OS X?

I would like to do the following in a command-line application on OS X:
while (true) {
// do some task
if (user_has_pressed('x')) {
// break out of the loop and do something different
}
}
For clarity, I don't want the program to block waiting for user input. I'm running a numerical simulation that takes many hours to run, and I want to press a key to print detailed statistics on its progress, or interrupt it and change parameters, etc.
There are some existing similar questions, but the answers either suggest a windows-only getch function, or they switch the terminal into a different input mode. I don't want to do that, because I need to retain the ability to interrupt with ctrl-c without messing up the terminal.
I don't want to build a Cocoa application, and I don't care about being cross-platform. I'm just looking for the simplest quick-and-dirty way to do it in a command line app that will only ever be run on my own machine.
I guess one option is to use ncurses. From a brief bit of reading it seems like a heavier option than I'd like - but if somebody would post a simple minimal example that accomplishes the above task that would be really helpful.
Are you looking for the following behavior?
#include <pthread.h>
#include <iostream>
static volatile bool keep_running = true;
static void* userInput_thread(void*)
{
while(keep_running) {
if (std::cin.get() == 'q')
{
//! desired user input 'q' received
keep_running = false;
}
}
}
int main()
{
pthread_t tId;
(void) pthread_create(&tId, 0, userInput_thread, 0);
while ( keep_running )
{
//! this will run until you press 'q'
}
(void) pthread_join(tId, NULL);
return 0;
}
The basic idea is to use poll, but the terminal would normally wait for an enter key before it sends the key press to stdin. So we need disable the canonial mode first.
#include <poll.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <string.h>
#include <termios.h>
#include <iostream>
void disable_canonical(){
struct termios old = {0};
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag &= ~ICANON;
old.c_lflag &= ~ECHO;
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
}
void enable_canonical(){
struct termios old = {0};
if (tcgetattr(0, &old) < 0)
perror("tcsetattr()");
old.c_lflag |= ICANON;
old.c_lflag |= ECHO;
old.c_cc[VMIN] = 1;
old.c_cc[VTIME] = 0;
if (tcsetattr(0, TCSANOW, &old) < 0)
perror("tcsetattr ICANON");
}
bool key_pressed(char c){
struct pollfd fds[1];
fds[0].fd = 0;
fds[0].events = POLLIN;
fds[0].revents = 0;
int r = poll(fds, 1, 1);
if(r > 0){
if(fds[0].revents & POLLIN || fds[0].revents & POLLRDBAND || fds[0].revents & POLLRDNORM){
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
int n = read(0, buffer, sizeof(buffer) -1);
for(int i = 0; i < n; ++i){
if(buffer[i] == c){
return true;
}
}
}
}
return false;
}
int main(){
disable_canonical();
while(true){
if(key_pressed('x')){
break;
}
usleep(500);
//std::cout << "looping...\n";
}
enable_canonical();
}
P.S. the tcsetattr code is borrowed from https://stackoverflow.com/a/912796/573789
I believe what you are looking for is how to break out of the loop but keep the program still running.
One of the solution for your problem can be the use of the goto C++ keyword. Please look at the following code:
while(true)
{
char pressKeyToQuit = 'q';
cin >> pressKeyToQuit;
if(pressKeyToQuit == 'q')
{
goto getOffTheLoop; //to do something different
}
getOffTheLoop:
//do something different
cout << "Processing!\n";
}
Hope I helped! :D
The following can help:
#include <iostream>
using namespace std;
int main() {
while (cin.get() != 'x') {
cout << "I am running." << endl;
}
return 0;
}
But if you don't want your program to stop, use a thread as mentioned in this answer.
As a hack( dirty but fast ) solution consider a file that interrupts execution of the loop...
#include <fstream>
#include <iostream>
#include <unistd.h>
int main()
{
while( 1 )
{
std::cout << "start" << std::endl;
std::ifstream ifs( "stop" );
if( ifs.good() )
{
std::cout << "exit" << std::endl;
ifs.close();
break;
}
ifs.close();
ifs.open( "pause" );
while( ifs.good() )
{
usleep( 100 );
ifs.close();
ifs.open( "pause" );
}
std::cout << "end" << std::endl;
}
}
For the given program above, to pause it, create a pause file in the same folder as your executable
touch pause
or
> pause (in mac os)
To unpause,
rm pause
To stop,
> stop (don't forget to rm stop before you run executable again)
Use aliases to reduce number of chars to type
alias p='touch ..path_to_executable../pause'
alias s='touch ..path_to_executable../stop'
alias run='if [ -f "..path_to_executable../pause"] ; then rm "..path_to_executable../pause" fi;if [ -f "..path_to_executable../stop"] ; then rm "..path_to_executable../stop" fi; ..path_to_executable../..executable..'
You can use the POSIX signals:
#include <signal.h>
static volatile bool keep_continue = true;
int main()
{
signal(SIGINT, [](int) { keep_continue = false; });
while (keep_continue)
{
// run until you press ctrl-c
}
}
Have you tried the non-blocking read?
#include <unistd.h>
#include <fcntl.h>
int main()
{
int flags = fcntl(0, F_GETFL, 0); // we get the current flags applying on input file descriptor
fcntl(0, F_SETFL, flags | O_NONBLOCK); // add the non-blocking flag to input file descriptor
while (read(0, NULL, 0u) < 0)
{
// run until you press ENTER key
}
}
The program exits when you press ENTER. It works on Debian 9, but I have no OS X within easy reach to test on it.
I think you should see the article on - http://cc.byexamples.com/2007/04/08/non-blocking-user-input-in-loop-without-ncurses/
I would have commented this, but I don't have enough reputation.

NCURSES and Linux Input Device

I wrote a getSample(devicePath) function that reads raw input events from keyboard, however after running this function, ncurses doesn't display anything.
includes
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <ncurses.h>
#include <vector>
#include <string>
getSample
const int KEY_PRESSED = 1;
const int KEY_RELEASED = 0;
std::vector<input_event> getSample(std::string devicePath) {
std::vector<input_event> events;
int fileDescriptor = open(devicePath.c_str(), O_RDONLY);
while (true) {
struct input_event event;
read(fileDescriptor, &event, sizeof(struct input_event));
if (event.type == EV_KEY)
if (event.value == KEY_PRESSED || event.value == KEY_RELEASED) {
if (event.code == 28 && event.value == KEY_PRESSED)
break;
events.push_back(event);
}
}
close(fileDescriptor);
return events;
}
main
int main() {
std::string devicePath = "/dev/input/by-id/"
"usb-Microsft_Microsoft_Wireless_Desktop_Receiver_3."
"1-event-kbd";
std::vector<input_event> sample = getSample(devicePath);
initscr();
printw("Hello World!");
refresh();
getch();
endwin();
return 0;
}
Is there a way to fix it?
Tip
Function getSample works correctly, because when I replace ncurses code with simple printf(), everything works fine
int main() {
std::string devicePath = "/dev/input/by-id/"
"usb-Microsft_Microsoft_Wireless_Desktop_Receiver_3."
"1-event-kbd";
std::vector<input_event> sample = getSample(devicePath);
for (unsigned int i = 0; i < sample.size(); i++)
printf("%d | %3d | %ld.%06ld\n", sample[i].value, sample[i].code,
(long)sample[i].time.tv_sec, (long)sample[i].time.tv_usec);
return 0;
}

How can i clear particular text in text mode in c++ "not whole screen"?

system("cls") - #include <stdlib.h> STANDARD HEADER FILE
clrscr() - #include <conio.h> NON-STANDARD HEADER FILE
These two functions clear whole screen.
I wanted to clear or we can using the concept of BACKSLASH '\b' for a particular character or string without effecting the other content.At the time of inserting any number.
For Example : hellow
as i typing this 'hellow' at the same time it goes back to 'o'.
Both of the following C programs work in bash on Debian:
#include <stdio.h>
int main()
{
printf("xxxHellow\bxxx\n");
return 0;
}
or
#include <stdlib.h>
int main() { return system("echo 'xxxHellow\bxxx'"); }
Both produce the result you'd expect:
thomas#yozu-thomas:~/Programming$ gcc -o main main.c
thomas#yozu-thomas:~/Programming$ ./main
xxxHelloxxx
thomas#yozu-thomas:~/Programming$
This will probably work on Mac OSX too (since it also uses bash), but I don't know about Windows cmd.exe or PowerShell.
You can use the SetConsoleCursorPos() function that is inside the windows.h library and overwrite a character or more characters with blank characters/spaces through calling a text printing function.
#include <windows.h>
#include <stdio.h>
void clearScreen(int from_x, int to_x, int from_y, int to_y) // this function clears a block of text
{
HANDLE conHandle = GetStdHandle(STD_OUTPUT_HANDLE);
for(int i = 0; i<to_y-from_y; i++)
{
COORD pos;
pos.Y = from_y+i;
pos.X = from_x;
SetConsoleCursorPosition(conHandle, pos);
for(int j = 0; j<to_x-from_x; j++)
{
printf(" ");
}
}
return;
}
int main()
{
for(int i = 0; i<10; i++)
{
for(int j = 0; j<10; j++)
{
printf("a");
}
printf("\n");
}
clearScreen(1, 3, 4, 6);
return 0;
}

tone generation with sdl_mixer exits with segmentation fault in ubuntu 12.04 64 bit

I have to write a simple sinthesizer at university which uses sdl_mixer to generate sine waves. I got a code from my teacher which work on windows correctly, but in ubuntu it exits with segmentation fault.
I installed both sdl_mixer1.2-dev and sdl1.2-dev packages.
I tried a code that generates tone with sdl_audio. It worked fine, but I heard that for multi-channel playback, sdl_mixer is the solution.
The getch() part of the code is working well, the problem is with the sound manager part.
Can somebody help me to solve this problem?
Here is my code:
#include <iostream>
#include <termios.h>
#include <stdio.h>
#include<cmath>
#include <SDL/SDL_mixer.h>
#include<vector>
using namespace std;
class SoundManager
{
int channelnum;
vector<Mix_Chunk*> chunks;
public:
void init()
{
if (Mix_OpenAudio(48000,AUDIO_S16, 2, 1024) == -1)
{
cerr << "audio hiba" << endl;
exit(1);
}
}
SoundManager(int asked_channelnum=64)
{
channelnum = Mix_AllocateChannels(asked_channelnum);
chunks.assign(channelnum, (Mix_Chunk*)0);
}
int get_channelnum() const
{
return channelnum;
}
void play_stereo(const vector<short int>& v, int volume=128)
{
const short int *p = &(v[0]);
// short int * p = new short int[v.size()];
// for (size_t i=0;i<v.size();i++) {
// p[i]=v[i];
// }
Mix_Chunk * ownsample = new Mix_Chunk;
ownsample->alen = v.size()*2;
ownsample->abuf = (Uint8*)p;
ownsample->allocated = 1;
ownsample->volume = volume;
int playchannel = Mix_PlayChannel(-1, ownsample, 0);
if (playchannel != -1 && chunks[playchannel])
{
delete[] chunks[playchannel]->abuf;
Mix_FreeChunk(chunks[playchannel]);
}
if (playchannel != -1)
chunks[playchannel] = ownsample;
}
};
Mix_Chunk *ownsample = 0;
Mix_Chunk *samples = 0;
void hang()
{
if (Mix_OpenAudio(48000,AUDIO_S16, 2, 1024) == -1)
{
cerr << "audio hiba" << endl;
exit(1);
}
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
samples = Mix_LoadWAV("ding.wav");
ownsample = new Mix_Chunk;
ownsample->alen = s.size()*2;
ownsample->abuf =(unsigned char*) &(s[0]);
ownsample->allocated = 0;
ownsample->volume = 128;
cout << samples->alen << endl;
if (!samples)
{
cerr << "wav 'ding.wav' open error" << endl;
exit(1);
}
int channelnum = Mix_AllocateChannels(64);
if (channelnum != 64)
{
cerr << "warning: not as many channels are reserved as attended"<<endl;
}
if (Mix_PlayChannel(-1, ownsample, 0)==-1 )
{
cerr << "error on play" << endl;
}
// if (Mix_PlayChannel(-1, samples, 0)==-1 ) {
// cerr << "error on play" << endl;
// }
}
void pitty(SoundManager &sm)
{
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
sm.play_stereo(s);
}
static struct termios old, New;
/* Initialize New terminal i/o settings */
void initTermios(int echo)
{
tcgetattr(0, &old); /* grab old terminal i/o settings */
New = old; /* make New settings same as old settings */
New.c_lflag &= ~ICANON; /* disable buffered i/o */
New.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &New); /* use these New terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void)
{
tcsetattr(0, TCSANOW, &old);
}
/* Read 1 character - echo defines echo mode */
char getch_(int echo)
{
int ch;
initTermios(echo);
ch = getchar();
resetTermios();
return ch;
}
/* Read 1 character without echo */
int getch(void)
{
return getch_(o);
}
/* Read 1 character with echo */
int getche(void)
{
return getch_(1);
}
int main(void)
{
SoundManager sm(16);
sm.init();
vector<short> s(48000*2,0);
for (int i=0; i<s.size()/2; i++)
{
s[i*2] = sin(i/10.0+i*i/10000.0)*32000*(1/sqrt(i/100.0));
s[i*2+1] = sin(i/10.0)*32000*(1/sqrt(i/100.0));
}
int c;
while (1)
{
c = getch();
cout <<"keycode:\n";
cout <<c;
sm.play_stereo(s);
}
return 0;
}
Thank you for your help in advance.
Greetings,
Istvan Velegi
(1) if you are getting a segmentation fault can you recompile the code with debugging symbols on (if you are using g++ or clang++); use -g3.
(2) run the program using a debugger and get a stack trace of where the code segmentation faults (use gdb).
This looks absolutely, totally bogus:
void play_stereo(const vector<short int>& v, int volume=128)
{
const short int *p = &(v[0]);
//...
ownsample->abuf = (Uint8*)p;
//...
delete[] chunks[playchannel]->abuf;
Yes, I realize chunks[playchannel] isn't ownsample yet, but you do put ownsample into the chunks queue, so eventually you will come back around and try to delete[] the internal array storage of a vector<short int>.
That's very bad.
This commented-out code actually seems to be the correct thing to have in place of const short int *p = &(v[0]):
// short int * p = new short int[v.size()];
// for (size_t i=0;i<v.size();i++) {
// p[i]=v[i];
// }