Differentiate clipboard event when using read() function in c from stdin - c

I am working on terminal based text editor and stuck at a point where I need to differentiate whether the input text from read() function is a clipboard paste text or a keyboard text input.
#include <unistd.h>
char read_key_input() {
char ch;
int read_count;
while ((read_count = read(STDIN_FILENO, &ch, 1)) != 1)
{
// Handle error if any
}
return ch;
}
...
Edit: Here's what I ended up doing.
void read_key_input(void (*callback)(int)) {
char* text = malloc(UINT8_MAX);
int read_count;
while ((read_count = read(STDIN_FILENO, text, UINT8_MAX)) == -1)
{
// Handle error if any
}
// Handle escape sequences if found and return early
...
if (read_count > 1) {
// It's probably a clipboard text. So change the editor mode to input and loop through all the characters one by one.
else {
// It's a user keyboard text input
}
// Revert back to the original editor mode if changed
}
I updated the code to retrieve more than one byte at a time (as suggested by #AnttiHaapala) and process each byte. Seems to be sufficient for my text editor's need for now. Will post back if I update.

Usually you can differentiate this by counting the number of characters you've received in rapid succession. So if you get the keypresses more rapidly than say 1000 characters per minute, then it is likely a clipboard paste... or nonsense.
Furthermore, if you've set the terminal to raw mode, then you can easily monitor individual keypresses. Also make read accept more than one byte at once - with read that is the maximum number of bytes to receive without blocking when available anyway.
One example of such an interactive terminal program would be IPython - here two lines typed separately:
In [1]: print("Hello")
Hello
In [2]: print("World")
World
And here pasted in one go:
In [3]: print("Hello")
...: print("World")
...:
Hello
World
Notice how the prompt is different, and the program runs only after there has been a separate Enter key hit after a small delay.

AFAIK, you cannot do what you want (reliably).
The clipboard is related (usually) to some display server, e.g. Xorg or Wayland server (Weston). And X11 might have distant clients (hence, a clipboard operation could be slow, if crossing some ocean).
Some Linux machines (perhaps the web server at Stackoverflow) do not run any display server.
You could code a GUI application, e.g. using GTK or Qt.
You could test if your standard input is a terminal with termios(3) functions or isatty(3) (i.e. with isatty(STDIN_FILENO) or isatty(STDOUT_FILENO) for standard output)
If your program is run inside a crontab(1) job, or a unix pipeline, the standard input won't be a terminal, and there might not even be any display server running.
You could take inspiration from the source code of GNU emacs, which does detect when a display server is available (probably using environ(7), e.g. getenv(3) of "DISPLAY"...)
On Linux you might open(2) /dev/tty (see tty(4)) to access your terminal. In some cases, it does not exist.

Hey #jiten not sure if you checked like
its key input detect and check wether it's input is one by one key
or its instant bulk input.

Related

Delete current terminal input line

I am trying to code a little console chat-program in C on linux.
So far I coded it in a way that both chatting partners are only able to alternately send/recv, because these function calls are blocking by default.
Now I would like to modify that program, so that both are able to send and receive simultaneously.
The problem that I find is, that once you typed some input to the terminal, I don't know how to output received messages, without messing up the current input line of the terminal.
If there was a way to delete that current input line, you could temporarily save that line, print the new message and put the input line right back.
However, I was not able to find a solution for this problem on the internet.
Is it possible to delete the current input line, and if not, how else could I achieve what I want?
I think you should look into ncurses as Edd said in his comment.
It would allow you to easily manage contents in your terminal window, which sounds like a good idea for your chat program.
All you'd need to do is store your messages in 2 character arrays:
char incoming[MSG_MAX]
and
char outgoing[MSG_MAX]
Then you can output those messages wherever you want in your terminal window, since ncurses allows you to specify x,y coordinates on where to put your text.
Then a simple wrapper for one of ncurses erase() family functions would allow you to delete characters from specify x,y coordinates in your terminal window.
Edit: MSG_MAX is not an actual ncurses macro.

How to input of a string which contain '\n' in it

I have created an auto typing bot which simulate characters of string given by user.
My code is this:
printf("Enter speed (wpm) (1 to 11750):");
scanf("%d", &speed);
if(speed < 1 || speed > 11750)
{
printf("\nPlease provide CORRECT DATA\n");
return -1;
}
printf("Paste the String : \n");
gets(exaArray);
exaArrayLength = strlen(exaArray);
relation = (int)11750/speed;
printf("typing will start in 2 sec-\n");
Sleep(2000);
i=pos=0;
while(i<=exaArrayLength)
{
Sleep(relation);
if((exaArray[pos]>96) && (exaArray[pos]<123)) //small letters
{
keycode=0x41 + (exaArray[pos]%97);
smallLetter(keycode); //function for key simulation
}
.....
I am taking input using gets function. This program works fine when I paste text which does not contain Enter. So this program works fine with one paragraph.
But if the user provides more than one paragraph, then it simulates only the first paragraph.
Because gets terminates at '\n'. Which function could take multiple paragraph input and assign it to a string.
This is actually a very hard and complex problem, and not easy to solve in an automated way.
It would seem like reading in a loop would be a good solution, but then you come to the point when there is no more input and the reading function just blocks waiting for more input. The easiest way out of this is to have the user enter the "end of file" key combination (CTRL-D on POSIX systems like Linux or OSX, CTRL-Z on Windows), but the user must then be told to do that.
The problem stems from that your program simply have no idea how much data it is expected to read, and there is no function which is able to, basically, read the users mind when the user thinks "that's it, no more data".
Besides the above solution to have the user give an "end of file", you can use other sequences or special keys or even phrases of input to mark the end, but it all comes down to this: Read input in a loop until users says "no more input".
Well, there is no way for the computer to make a difference between the user pressing enter and the "pasted" string containing newlines. (Technically, pasting something into the console is like typing it.)
If you just don't want the problem to exit after one paragraph but continue, you can do it as commenter alk suggested (loop around the reading function) - then you would need Ctrl+C to exit the program and then there would technically still be one paragraph at a time written. Depends on what you further want to do with the program.
On the other hand, if you want a way for the user to input all text at once and only then process it, you would need to define something other than "newline" as "end of input" marker, for example something like ESC.
You would do this by using getchar instead of gets and manually concatenating each char which is entered this way to a string buffer, and if the character has the value 27 (escape key) for instance, you would end the input loop and start outputting.

Outputting to multiple terminals

I'm parsing a large log file. I would like to pull out particular messages based on a severity classification (critical, warning, etc). As I am parsing the log I would like to send messages, based on their severity, to a given, spawned, severity-specific, terminal. The terminals should not close when the main program finishes reading the log file. Environment is solaris 10/gcc 3.4.6. I found the following example that captures what I was thinking of, but doesn't quite work (xterm spawns, but no output is sent to it):
#include <stdio.h>
int main()
{
FILE *output;
int i;
output = popen ("xterm", "w");
for (i = 0; i < 10; i++)
fprintf (output, "%d\n", i);
pclose (output);
}
I'm not married to xterm, I simply used it as handy and I do like the ability to title, color and size them. I sort of get that writing to the handle generated by popen is not the same as writing to the terminal's output (just sort of...). This seems like an easy thing to do.
in general, what can be done is:
1) adjust your application so it can accept a parameter that indicates what level of severity to output to stdout.
2) open three terminals from the keyboard
3) run your application in each terminal, giving each execution the appropriate command line parameter
if your going to open the terminals from your application, for 'xterm' and others, the --hold parameter will stop the terminal from closing when you application exits
The idea of the pipe sounds reasonable, but there are a few problems:
you cannot, of course, simply write to a newly-spawned terminal via a pipe. xterm will ignore that; it is the application running within xterm which reads/writes from the pseudo-terminal.
there is no way to scroll back in the messages sent to a given terminal
the suggested writes to the pty device cannot be captured by a program running in the terminal
Rather than sending to a terminal, you might consider getting xless (a simple X application which might already be part of a package, but is simple enough to build), and structuring your output function to do this:
for each message category, open a pipe to xless once
write the message
do not close the pipe
That would give you windows which do not close. Here is a sample screenshot:
The source can be found on ftp.x.org, as noted in the Debian package description.
Thank you all for the great responses, I do appreciate them!
OK, sounds like a slight re-design is called for =) I did a quick prototype and it looks like it will work. Will write the output to separate severity files, then when complete, pop up an xterm for each file, something like
sprintf (Crit, "xterm <yadda yadda> -e sh -c 'cat <crit-log>; <yadda yadda>');
popen (Crit, "r");
Writing to intermediate log files is actually a bonus should they need to be reviewed at a later time without having to go through the large-log-parsing program again.
Thanks again everyone!

Why can't I read Ctrl+S in C?

I have this program in C that reads the input like this:
cod1 = getch ();
if (kbhit())
cod2 = getch ();
I can read every Ctrl+Char possible sequences, except for Ctrl+C, that closes the program - that is OK, and Ctrl+S, that simple is not catch. But I wanted to make Ctrl+S to be the save function in my program; how could I do that? Furthermore, is it possible to read Alt+Char characters? Because it reads it as a regular character, e.g., Alt+A is read with the same codes as A.
Your problem is that input probably gets eaten by terminal emulator.
For example Alt+<Whatever> is often reserved for menu shortcuts (e.g. Alt+F opens File menu). Matching characters are often hilighted once you hold Alt (F get's underscored in File).
Ctrl+S is reserved for Stops all output on screen (XOFF) (again your terminal emulator does that).
As for using Alt+<...> as shortcuts in your command line application. As far as I'm concerned holding Alt doesn't affect character received, it just sets flags which are hard to access in console. Even in GUI application (in Windows) it's quite tricky and you have to use function like GetAsyncState() to check whether alt was pressed.

What is it meant by Console in windows programming?

I've got a problem with windows consoles... In windows api, does a console always has to be a screen or a keyboard or can it be any character buffer or something like a text file ?
thanx
If I be more specific, SetConsoleMode fnction in windows api has a parameter called hConsoleHandle which has a flag called ENABLE_ECHO_INPUT that can be used to echo every character we read to the screen.. So I thought in windows system programming, Console means something more than it's normal meaning... So am I write and if so what is the true meaning..?
thanx again
No, a "console" implies an application that has a text-based interface.
Win32 Console on Wikipedia says that that label specifies a text mode program that runs under the Windows API, and would use, for example, a function like WriteConsole instead of printf or cout.
So, the console's the same, but the underlying library is different.
As it's well described here
Consoles manage input and output (I/O) for character-mode applications
(applications that do not provide their own graphical user interface).
so you have your answer right there. As asked before, try to explain better your context, your objective and what is your idea, so maybe we can help you out more.
Under Windows, the console is always a window that resembles the Command Prompt window. You can open and read and write from/to that thing in your windows program. It's not a buffer or a text file, but you can write a buffer or text file and then transfer that entity to the console.
Here are the C-language functions you can use when you address the console window:
_cgets, _cgetws, _cgets_s, _cgetws_s
Read string from console
_cprintf, _cwprintf, _cprintf_s, _cprintf_s_l, _cwprintf_s, _cwprintf_s_l
Write formatted data to console
_cputs
Write string to console
_cscanf, _cwscanf, _cscanf_s, _cscanf_s_l, _cwscanf_s, _cwscanf_s_l
Read formatted data from console
_getch, _getwch
Read character from console
_getche, _getwche
Read character from console and echo it
_inp
Read one byte from specified I/O port
_inpd
Read double word from specified I/O port
_inpw
Read 2-byte word from specified I/O port
_kbhit
Check for keystroke at console; use before attempting to read from console
_outp
Write one byte to specified I/O port
_outpd
Write double word to specified I/O port
_outpw
Write word to specified I/O port
_putch, _putwch
Write character to console
_ungetch, _ungetwch
"Unget" last character read from console so it becomes next character read

Resources