How to poll input from Linux /dev/input/eventX - c++

I'm working on a project that requires me to get a touchscreen working on Scientific Linux 6.4 (Linux kernel 2.6.32). Although the kernel does not support the touchscreen fully, I am able to see multi-touch events being generated in the /dev/input/eventX location for the touchscreen when I touch the screen.
I'm trying to write a simple C++ program to read the data from the /dev/input/eventX file and parse it so I can manually deal with the multi-touch events, since that seems the only way I'll get this working.
So I wrote the following program:
std::ifstream input("/dev/input/event10");
if(input.is_open()) {
while(input.good()) {
int header;
input >> header;
cout << std::hex << header << " ";
int data[16] = {};
for(int i = 0; i < 16; i++) {
input >> data[i];
cout << std::hex << data[i] << " ";
}
cout << endl;
}
input.close();
} else cout << "Unable to open event handler for input polling..." << endl;
Now, I don't exactly know if my method of reading and parsing the input itself is correct, but when I use the following command in bash:
sudo cat /dev/input/event10 | hexdump -C
I get the input data in the form of a number of lines beginning with an 8-digit hex value followed by 16 2-digit hex values (bytes).
The problem I'm having though is that I always get the message "Unable to open event handler for input polling..." suggesting an issue with opening the file. At first, I thought maybe that because nothing is in that file until an event is generated, it might not be able to be opened as an ifstream. I also tried running the program as sudo just in case it was a permissions issue and got the same message, so I believe it has to do with how I'm opening the file.
Does anyone know the proper way to open and read from these files?
EDIT: My question is regarding why the file is unable to be opened, not necessarily just how to parse the data. The suggested "duplicate" questions don't provide any helpful information in this regard.

Nevermind... there was a trailing space in my filename (which was detected rather than hard-coded). I added a trim function and now it opens just fine.

Related

I can't get the ofstream function to work

Hello and sorry if the answer is clear to those out there. I am still fairly new to programming and ask for some guidance.
This function should write just one of the three string parameters it takes in to the txt file I have already generated. When I run the program the function seems to work fine and the cout statement shows the info is in the string and does get passes successfully. The issue is after running the program I go to check the txt file and find it is still blank.
I am using C++17 on visual studio professional 2015.
void AddNewMagicItem(const std::string & ItemKey,
const std::string & ItemDescription,
const std::string &filename)
{
const char* ItemKeyName = ItemKey.c_str();
const char* ItemDescriptionBody = ItemDescription.c_str();
const char* FileToAddItemTo = filename.c_str();
std::ofstream AddingItem(FileToAddItemTo);
std::ifstream FileCheck(FileToAddItemTo);
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
if (_access(FileToAddItemTo, 0) == 0)
{
if (FileCheck.is_open())
{
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
}
AddingItem.close(); // not sure these are necessary
FileCheck.close(); //not sure these are necessary
}
This should print out a message onto a .txt file when you pass a string into the ItemKey parameter.
Thank you very much for your help and again please forgive me as I am also new to stackoverflow and might have made some mistakes in formatting this question or not being clear enough.
ADD ON: Thank you everyone who has answered this question and for all your help. I appreciate the help and would like to personally thank you all for your help, comments, and input on this topic. May your code compile every time and may your code reviews always be commented.
As mentioned by previous commenters/answerers, your code can be simplified by letting the destructor of the ofstream object close the file for you, and by refraining from using the c_str() conversion function.
This code seems to do what you wanted, on GCC v8 at least:
#include <string>
#include <fstream>
#include <iostream>
void AddNewMagicItem(const std::string& ItemKey,
const std::string& ItemDescription,
const std::string& fileName)
{
std::ofstream AddingItem{fileName, std::ios::app};
if (AddingItem) { // if file successfully opened
AddingItem << ItemKey;
std::cout << ItemKey << std::endl;
}
else {
std::cerr << "Could not open file " << fileName << std::endl;
}
// implicit close of AddingItem file handle here
}
int main(int argc, char* argv[])
{
std::string outputFileName{"foobar.txt"};
std::string desc{"Description"};
// use implicit conversion of "key*" C strings to std::string objects:
AddNewMagicItem("key1", desc, outputFileName);
AddNewMagicItem("key2", desc, outputFileName);
AddNewMagicItem("key3", desc, outputFileName);
return 0;
}
Main Problem
std::ofstream AddingItem(FileToAddItemTo);
opened the file. Opening it again with
AddingItem.open(FileToAddItemTo, std::ios::out | std::ios::app);
caused the stream to fail.
Solution
Move the open modes into the constructor (std::ofstream AddingItem(FileToAddItemTo, std::ios::app);) and remove the manual open.
Note that only the app open mode is needed. ofstream implies the out mode is already set.
Note: If the user does not have access to the file, the file cannot be opened. There is no need to test for this separately. I find testing for an open file followed by a call to perror or a similar target-specific call to provide details on the cause of the failure to be a useful feature.
Note that there are several different states the stream could be in and is_open is sort of off to the side. You want to check all of them to make sure an IO transaction succeeded. In this case the file is open, so if is_open is all you check, you miss the failbit. A common related bug when reading is only testing for EOF and winding up in a loop of failed reads that will never reach the end of the file (or reading past the end of the file by checking too soon).
AddingItem << ItemKey;
becomes
if (!(AddingItem << ItemKey))
{
//handle failure
}
Sometimes you will need better granularity to determine exactly what happened in order to properly handle the error. Check the state bits and possibly perror and target-specific
diagnostics as above.
Side Problem
Opening a file for simultaneous read and write with multiple fstreams is not recommended. The different streams will provide different buffered views of the same file resulting in instability.
Attempting to read and write the same file through a single ostream can be done, but it is exceptionally difficult to get right. The standard rule of thumb is read the file into memory and close the file, edit the memory, and the open the file, write the memory, close the file. Keep the in-memory copy of the file if possible so that you do not have to reread the file.
If you need to be certain a file was written correctly, write the file and then read it back, parse it, and verify that the information is correct. While verifying, do not allow the file to be written again. Don't try to multithread this.
Details
Here's a little example to show what went wrong and where.
#include <iostream>
#include <fstream>
int main()
{
std::ofstream AddingItem("test");
if (AddingItem.is_open()) // test file is open
{
std::cout << "open";
}
if (AddingItem) // test stream is writable
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
AddingItem.open("test", std::ios::app);
if (AddingItem.is_open())
{
std::cout << "open";
}
if (AddingItem)
{
std::cout << " and writable\n";
}
else
{
std::cout << " and NOT writable\n";
}
}
Assuming the working directory is valid and the user has permissions to write to test, we will see that the program output is
open and writable
open and NOT writable
This shows that
std::ofstream AddingItem("test");
opened the file and that
AddingItem.open("test", std::ios::app);
left the file open, but put the stream in a non-writable error state to force you to deal with the potential logic error of trying to have two files open in the same stream at the same time. Basically it's saying, "I'm sorry Dave, I'm afraid I can't do that." without Undefined Behaviour or the full Hal 9000 bloodbath.
Unfortunately to get this message, you have to look at the correct error bits. In this case I looked at all of them with if (AddingItem).
As a complement of the already given question comments:
If you want to write data into a file, I do not understand why you have used a std::ifstream. Only std::ofstream is needed.
You can write data into a file this way:
const std::string file_path("../tmp_test/file_test.txt"); // path to the file
std::string content_to_write("Something\n"); // content to be written in the file
std::ofstream file_s(file_path, std::ios::app); // construct and open the ostream in appending mode
if(file_s) // if the stream is successfully open
{
file_s << content_to_write; // write data
file_s.close(); // close the file (or you can also let the file_s destructor do it for you at the end of the block)
}
else
std::cout << "Fail to open: " << file_path << std::endl; // write an error message
As you said being quite new to programming, I have explicitly commented each line to make it more understandable.
I hope it helps.
EDIT:
For more explanation, you tried to open the file 3 times (twice in writing mode and once in reading mode). This is the cause of your problems. You only need to open the file once in writing mode.
Morever, checking that the input stream is open will not tell you if the output stream is open too. Keep in mind that you open a file stream. If you want to check if it is properly open, you have to check it over the related object, not over another one.

How can I use C++ to write to an opened terminal?

I am trying to communicate with a program (xfoil) and read and write to its command line. Xfoil can take many parameters in its built in terminal.
I can open the program using system("path") but how do I input more commands to the opened xfoil terminal? Once I can do that I can do all that I need to do with the terminal commands.
Tiny Process Library is a good library for interacting with processes.
Checkout example 6 and 7 for giving commands to a process. https://gitlab.com/eidheim/tiny-process-library/blob/master/examples.cpp
How can I use C++ to write to an opened terminal
On linux, there are 7+ steps:
1) open a terminal
I find ctrl-alt t most convenient
press and hold ctrl and alt, then press t
There is also a selection LXTerminal on a mouse menu
Note - There is a way for your program to open a 'default' terminal,
and c++ can use the technique, but it is not c++, and I always seem to
need to change the defaults for my use.
2) using the terminal, you manually find the name of the terminal by:
type the command "tty" into the terminal
Typical response on my system:
hostname#username:~$ tty
/dev/pts/1
The terminal name is always of the form "/dev/pts/x" on my Linux system, where x is a number.
3) For my programs (that use a second terminal), my code accepts the x portion (of the terminal response) as command parameter 1, and uses that parameter to create a path file name (PFN) to the terminal.
std::string aTermPFN = "/dev/pts/"; // partial address
aTermPFN += argv[1]; // ouput tty identified by argv[1]
// creating /dev/pts/<argv[1]>
// thus creating PFN of "/dev/pts/1"
4) My code typically provides a confirmation of the number during creation. (recommended)
std::cout << "accessing '" << aTermPFN
<< "' with std::ofstream " << std::endl;
5) and then creates (or attempts to create) the ofstream object
std::ofstream* ansiTerm = new std::ofstream(aTermPFN);
6) and perform a few checks on it ...
if (!ansiTerm->is_open())
{
std::cerr << "Can not access '" << aTermPFN << "'" << std::endl;
assert(0); // abort
}
7) When done with term, be sure to clean up
ansiTerm->close();
delete ansiTerm;
// you can avoid the delete if you use an appropriate smart pointer.
Now all output to that 2nd terminal uses the 'ansiTerm' object, I happen to use a more generic term in that code (not a pointer, but reference) : "termRef".
Examples of use
// mostly, in the app where these sample exist, I output text at computed
// screen locations
// ansi terminals provide goto row col ansi functions
// the style is simply position the cursor,
termRef << m_ansi.gotoRC(3, col) << ss.str() << std::flush;
// then output text-----------------^^^^^^^^ (ss is stringstream)
// ansi terminals can clear
void clearScr() { termRef << m_ansi.clrscr() << std::flush; }
// ansi terminals can draw simple borders (not-fancy)
{ // across top gotoRC (int row, int col )
termRef << m_ansi.gotoRC ( tlcRow, tlcCol+1);
for ( int i=0; i<borderWidth; ++i) termRef << m_acs.HLINE;
termFlush();
}

why I cant read a file to an integer vector?

well! I have a text file including some integer values and non-integers like character strings and white spaces so I want only to read integers values so I used a vector of integers but when I read the file the opining is ok but it seems the first input fails thus breaks the loop!!!
here is my main example:
ifstream in("file.txt");
if(in.fail())
cout << "opening failed!" << endl;
//opening is fine!
int value;
vector<int> v;
while(in >> value) // the problem here; it fails why?
{
cout << "ok"; // not printed
v.push_back(value);
}
cout << v.size() << endl; // 0??!!
this is the content of file.txt:
32 43 24 32
15 23
57
77 81
if I make a vector of chars it's ok but I want only to use one of integers
*** I already used a code like this and worked fine but now I don't know what happened??!!! it's really annoting
any help, comment, tip is welcome and appreciated
This line:
while(in >> value)
says while I can read integers...
But in the post this may not be true - you are not handling this case.
Either read stuff that is not integers and handle it. Or just read strings and then decide what to do.
In addition
cout << "ok"; // not printed
is because it is buffered.
Do this
cout << "ok" << flush; // printed
excuse me first for annoying you with nonsense question. finally I managed to discover the error:
in my main folder of project I unintentionally created a winrar file input.rar then I didn't remove it but rename it to input.txt it's ok I opened it manually and removed some unreadable characters. then I put inside it the content above of integers then my c++ application succeeds in opening it but can't read it.
*now I removed it input.txt which was input.rar and created a new document text input.txt and now everything is good!!!
thank you for your collaboration. and this post may help someone else.
* don't create rar file or other formats then rename them to be text files and try to read them via your c++ fstream because it'll fail in fact it'll produce an error-prone which looks impossible to solve

ifstream / ofstream issue with c++?

I have been having a very hard time writing to a binary file and reading back. I am basically writing records of this format
1234|ABCD|efgh|IJKL|ABC
Before writing this record, I would write the length of this entire record ( using string.size()) and then I write the record to the binary file using ofstream as follows:
int size;
ofstream studentfile;
studentfile.open( filename.c_str(),ios::out|ios::binary );
studentfile.write((char*)&size,sizeof(int));
studentfile.write(data.c_str(),(data.size()*(sizeof(char))));
cout << "Added " << data << " to " << filename << endl;
studentfile.close();
And I read this data at some other place
ifstream ifile11;
int x;
std::string y;
ifile11.open("student.db", ios::in |ios::binary);
ifile11.read((char*)&x,sizeof(int));
ifile11.read((char*)&y,x);
cout << "X " << x << " Y " << y << endl;
first I read the length of the record into the variable x, and then read the record into string y. The problem is, the output shows x as being '0' and 'y' is empty.
I am not able figure this out. Someone who can look into this problem and provide some insight will be thanked very much.
Thank you
You can't read a string that way, as a std::string is really only a pointer and a size member. (Try doing std::string s; sizeof(s), the size will be constant no matter what you set the string to.)
Instead read it into a temporary buffer, and then convert that buffer into a string:
int length;
ifile11.read(reinterpret_cast<char*>(&length), sizeof(length));
char* temp_buffer = new char[length];
ifile11.read(temp_buffer, length);
std::string str(temp_buffer, length);
delete [] temp_buffer;
I know I am answering my own question, but I strictly feel this information is going to help everyone. For most part, Joachim's answer is correct and works. However, there are two main issues behind my problem :
1. The Dev-C++ compiler was having a hard time reading binary files.
2. Not passing strings properly while writing to the binary file, and also reading from the file. For the reading part, Joachim's answer fixed it all.
The Dev-C++ IDE didn't help me. It wrongly read data from the binary file, and it did it without me even making use of a temp_buffer. Visual C++ 2010 Express has correctly identified this error, and threw run-time exceptions and kept me from being misled.
As soon as I took all my code into a new VC++ project, it appropriately provided me with error messages, so that I could fix it all.
So, please do not use Dev-C++ unless you want to run into real troubles like thiis. Also, when trying to read strings, Joachim's answer would be the ideal way.

Why does my output go to cout rather than to file?

I am doing some scientific work on a system with a queue. The cout gets output to a log file with name specified with command line options when submitting to the queue. However, I also want a separate output to a file, which I implement like this:
ofstream vout("potential.txt"); ...
vout<<printf("%.3f %.5f\n",Rf*BohrToA,eval(0)*hatocm);
However it gets mixed in with the output going to cout and I only get some cryptic repeating numbers in my potential.txt. Is this a buffer problem? Other instances of outputting to other files work... maybe I should move this one away from an area that is cout heavy?
You are sending the value returned by printf in vout, not the string.
You should simply do:
vout << Rf*BohrToA << " " << eval(0)*hatocm << "\n";
You are getting your C and C++ mixed together.
printf is a function from the c library which prints a formatted string to standard output. ofstream and its << operator are how you print to a file in C++ style.
You have two options here, you can either print it out the C way or the C++ way.
C style:
FILE* vout = fopen("potential.txt", "w");
fprintf(vout, "%.3f %.5f\n",Rf*BohrToA,eval(0)*hatocm);
C++ style:
#include <iomanip>
//...
ofstream vout("potential.txt");
vout << fixed << setprecision(3) << (Rf*BohrToA) << " ";
vout << setprecision(5) << (eval(0)*hatocm) << endl;
If this is on a *nix system, you can simply write your program to send its output to stdout and then use a pipe and the tee command to direct the output to one or more files as well. e.g.
$ command parameters | tee outfile
will cause the output of command to be written to outfile as well as the console.
You can also do this on Windows if you have the appropriate tools installed (such as GnuWin32).