Key pressed and key released interrupts in C - keyboard

Is there a way to catch the KEY PRESSED and KEY RELEASED events in while (1) loop in simple C program on Linux running from a terminal window.
kbhit() will return true if a key was pressed, getch() returns the character that was pressed.
How do I catch the RELEASE event?

You cannot do this in a portable manner. Terminals (and emulators of those such as xterm) give you only the key that was pressed, not the release events. Graphical user interfaces often provide the ability to receive separate press- and release-events.
Terminal emulators running in a graphical environment compose those events into individual characters. As read in the graphical environment, those are key symbols, which may contain characters. In addition to the press- and release-events for the key events themselves, you can have modifiers such as shift-, control- and meta-modifiers which are separate events. If you run xev, you can see these separate events.
After composing these events into a character, the terminal emulator may send it to your application as a series of data bytes, e.g., in UTF-8 encoding. When you use getch(), the ncurses library reads those bytes, and puts it together again into a character. In between those two (the terminal emulator and application) are the pseudo-terminal and its translation, which both terminal emulator and application must manipulate.
If you are not running in a graphical environment, there are (not always) other ways than graphical applications such as xev which can read directly the key press/release events. The Linux console supports that. See for example the links cited in Receiving key press and key release events in Linux terminal applications?

This works for me with xterm and the openbox window manager:
xinput test-xi2 --root |
awk -v id="$(
xwininfo -children -id "$WINDOWID" |
awk '$1 == "Parent" {print $4}'
)" '
$1 == "EVENT"{e = $NF}
$1 == "detail:" {k = $2}
$6 == "child" && $7 == id && e ~ /Key/ {print e, k}'
Outputs something like:
(KeyRelease) 36
(KeyPress) 38
a(KeyRelease) 38
s(KeyPress) 39
d(KeyPress) 40
(KeyRelease) 39
(KeyRelease) 40
(those a, s, d are the local echo for the characters that xterm wrote to the master side of the pseudo-terminal upon handling those KeyPress events and are not part of the output).
xinput test-xi2 --root will report every X Window event for the current $DISPLAY including but not limited to keypress and keyrelease events in a format similar to:
EVENT type 2 (KeyPress)
device: 14 (14)
detail: 54
flags:
root: 795.06/645.66
event: 795.06/645.66
buttons:
modifiers: locked 0 latched 0 base 0x4 effective: 0x4
group: locked 0 latched 0 base 0 effective: 0
valuators:
windows: root 0x252 event 0x252 child 0x1c0015b
From my limited testing, I find that the child field in there seems to match the id of the parent of the terminal emulator main window (which most terminal emulators make available in the $WINDOWID environment variable) which receives those events. I suspect that window id is somewhat belongs to the window manager.
So, here, we retrieve that id from the xwininfo -children command output, and use that to filter the events reported by xinput.
To translate those key codes to key labels, check this other answer.
Now, you'll want to check the source code of xinput or play with ltrace (if on Linux) to do the same thing directly in C without the help of those utilities.

Related

Invoking keyboard keys, through proc - procedure (function) in tcl

In front of the internet, I could only find so far, just the reverse where the key-related event is associated with the front-end button, not the front-end button that invokes a key. Understood ?! Look:
#!/usr/bin/env wish
button .b1 -text Hello -underline 0
button .b2 -text World -underline 0
bind . {.b1 flash; .b1 invoke}
bind . {.b2 flash; .b2 invoke}
pack .b1 .b2
Explanation - If you press a H button, the Hello button will blink. And the same effect happens with W; World
I want the Front-end [GUI] button to simulate the keystroke, for example - F1
This Print Screen software is mp3blaster - learn more..
This Print Screen is a GUI what are developer are work:
I asked that question a week or two ago. Since I did not get any
plausible answer, I do not know if it is possible, or no one knows, or
nobody cares.
I want to send a non tcl / tk application under UNIX GNU / Linux some keys
for a very simple toolbar control. For the application must be
the same as if these keys were hit on the keyboard. In VisualBasic
The function is called SendKey. Is it possible to do this with tcl / tk?
I will describe how to do this using Windows Script Host and tcom:
Windows Script Host 2.0 beta (which you can download from
http://msdn.microsoft.com/scripting/windowshost/beta/) includes a COM
object that implements a SendKeys function.
tcom 1.7 (available at http://www.vex.net/~cthuang/tcom/) is a
Windows-specific Tcl extension that allows Tcl scripts to access
COM objects.
In this example, the Tcl script starts Notepad and sends keys to the application.
package requires tcom
configure wshShell [:: tcom :: bind "WScript.Shell"]
set taskId [$ wshShell Run "notepad.exe"]
$ wshShell AppActivate $ taskId
after 500
$ wshShell SendKeys "The quick brown fox jumped \ n"
$ wshShell SendKeys "{TAB} about the lazy dog."
:: tcom :: release $ wshShell
On UNIX; Linux how to accomplish this ??? It would be by focus method, inverse bind or third party application xvkbd, xbindkeys, xkeycaps, xev, xjoypad etc ... Which to use and how to use if tcl/tk does not have one built-in command?!
If somebody knows and/or can clarify me, I'll be grateful.
xdotool (http://www.semicomplete.com/projects/xdotool/) could help with that task.
Here's a short snippet that sends Ctrl+Tab to Chrome when clicking a Tk button:
#!/usr/bin/env wish
#
# Focus window named $window_name and send the specified key sequence.
#
proc send_key {window_name key_sequence} {
foreach wid [exec xdotool search --name $window_name] {
if {![catch {exec xdotool windowfocus $wid}]} {
exec xdotool key $key_sequence
}
}
}
button .f1 \
-text "Send Ctrl+Tab to Chrome (cycle through browser tabs)" \
-command {send_key chrome ctrl+Tab}
pack .f1
It's a bit problematic that you have to focus the window before you can send key sequences to it.
To generate a key, you need the event generate command.
event generate $w <KeyPress-F1> -x $x -y $y
You probably want to direct the event to the focus window, and the X and Y locations ought to be set to 0,0 if you don't have a better place (or alternatively use the -rootx and -rooty options and the winfo pointerxy command to use global coordinates).
There are many other fields you can set for a key-press event, but most of them aren't commonly used. (In particular, I think it's easier to set up the state field using modifiers to the event being generated rather than explicitly setting the -state option.)

xterm dump of full scrollable window content

I want to know if anyone does know a way to dump or copy the whole lot of viewable messages in a xterm window on linux. The very important thing is I don't want to know how to send a command out and kapture its output for stream 1 and 2 as well as the input, as this is well known to me.
I may explain for what this is needed. You do something and expect not any complications but than you got pages of msg's als err msg or normal output. To be able to see later after it you should be able to get them in a file and as long as you are able to scroll that all back and forther with your mouse it is sure the data is there some where. But the time may be not to scroll and screenshot and scroll ....
I would be glad to help me out in such cases and it would be fine to have the full view including all your own typing and all the msg's in same order as you watch it when you scroll it back.
I don't really know where this is stored and how you could get that saved. I know that I could dump the whole lot of Memory and search it for a part of the xterm window, but that is a bit over the top I think.
There is a control sequence, which I had forgotten. This question reminded me. In XTerm Control Sequences, it is noted "print all pages":
CSI ? Pm i
Media Copy (MC, DEC-specific).
Ps = 1 -> Print line containing cursor.
Ps = 4 -> Turn off autoprint mode.
Ps = 5 -> Turn on autoprint mode.
Ps = 1 0 -> Print composed display, ignores DECPEX.
Ps = 1 1 -> Print all pages.
That dates from 1999 (patch #119), so you likely have it in your xterm. You could do this in a shell command like this:
printf '\033[?11i'
A comment mentions the page Hidden gems of xterm, which uses the corresponding action print-everything (something that can be executed via the translations resource). It is in the manual page, of course. The same comment points to Extra characters in XTerm printerCommand output, which mentions the resource printAttributes. By default, the control sequences for the printer tell xterm to send extra control characters (to reconstruct video attributes). The resource can be modified (set to 0) to suppress that. That is even older (patch #74).
Without that — Conceivably one could construct an application which used the X SendEvent protocol to construct a series of events which would be interpreted as xterm actions to scroll back, select text and copy it chunk-by-chunk via the clipboard. You could even write it in Perl (there is a module for X protocol). But seriously, no.
If you want to capture text which was written to xterm, you can do this by preparing before the text is needed by different methods (see manual):
turn on the xterm logging feature (not that user-friendly because it generates the filename). This can be enabled using the "Log to File (logging)" menu entry.
use the printer control sequences to write lines as they are written (again, not that friendly, though there is a menu entry to turn it on and off, "Redirect to Printer (print-redir)")
use script to capture all output to the terminal. I use this, because it works with any terminal on any POSIX-like system (even Cygwin).
Each of these methods produces a file containing escape/control sequences, which requires filtering out. The hypothetical program using SendEvent could in principle eliminate that.

how to get terminal properties

I very frequently work on multiple items in parallel and end up running some long tests or regression after working on something. I usually add a mail -s "foo" id < /dev/null at the end to know when a task ends so that I don't have to baby sit a long test or regression.
I was trying to automate this, where in I don't have to type the mail every time, just call a script (alias this to fewer characters - optimizing on how much I type) and the script figures out the test/regression from the cwd and sends an email. I thought it would be useful to send the terminal title or the screen session name in the email. Is there a way I can extract the terminal title or Linux screen window name?
You can find the screen session name, when attached, in $STY (the window number is available in $WINDOW if you need it):
$ echo "$STY"
6367.sessionname
You can find the uniquely identifying tty/pty device with tty:
$ tty
/dev/pts/34
Titles and such are features of xterm and not of the terminal itself, so terminals programs have a hard time deducing it.
Here's an example using both of the above to show the screen name if any, or the tty device otherwise:
mail -s "${STY:-$(tty)} done" < /dev/null
Screen also has a "wait for silence" feature where you can get a notification when processes in other screen windows have stopped outputting.

"freeze" terminal output (/dev/tty1)

I'm writing an application (in java) that directly operates on the framebuffer (/dev/fb0).
When I start my app, the cursor of the currently active console still blinks and if i use keyboard-keys like up/down the console will display the recently used commands and overwrite the framebuffer's content.
I was only able to stop the cursor from blinking:
setterm -cursor off > /dev/tty1
Is there a way to totally freeze (and later unfreeze) the console?
It seems like an X-Server does the same thing. If the boot-process runs on GraphicsCard-1 and the X-Server on GraphicsCard-2, the output on GraphicsCard-1 will stop (no blinking cursor) immediately when X starts. I guess mplayer does this, too if setting video-out to the framebuffer.
thanks for any ideas :)
Strictly speaking, the behaviour that you've observed is more of a bug than a feature. It's down to the fact that Linux isn't properly multi-head. What you're seeing is an effect of the X server switching its own, allocated, virtual terminal onto the console. This of course — because only one virtual terminal can be active at a time system-wide — switches out the virtual terminal that was being displayed, even though it was being displayed on another display adapter entirely.
You have to do some of what the X server is doing, and switch your own virtual terminal onto the console.
openvt(1) allows you to open a program in a new virtual terminal, and chvt(1) allows you to switch to another virtual terminal.
it was a little bit more tricky to get what i exactly wanted:
I have to execute (from shell) 2 commands to get the terminal quiet:
chvt 9
setterm -cursor > /dev/tty9
later one can switch back to terminal 1:
setterm cursor > /dev/tty9
chvt 1
I choose terminal number 9 but any number above 7 should be fine. These calls also work if they are executed from within the java application (as JdeBP said, only one virtual terminal system-wide). Only the setterm command requires some additional steps to pipe the output to /dev/tty9:
Runtime.getRuntime().exec("chvt 9");
pipe("setterm -cursor off", "/dev/tty9");
private static void pipe(String cmd, String file) {
FileOutputStream fos = new FileOutputStream(file);
Process p = Runtime.getRuntime().exec(cmd);
InputStream is = p.getInputStream();
int i;
while ( (i = is.read()) != -1 ) {fos.write(i);}
p.waitFor();
fos.close();
is.close();
}
maybe the pipe() method is not optimal, but it worked for me the way it is.

The GNU screen is unresponsive, seems blocked

GNU Screen seems to freeze. Unable to enter user input.
I was using GNU screen and when I pressed the screen it became unresponsive. I can execute all the GNU screen commands, but can't enter user input. I don't want to kill this screen as I have important work and I don't want to lose it.
In the commands below, replace Ctrl with whatever your escape key is for screen commands.
Try Ctrl+a q, which is the sequence to unblock scrolling.
Ctrl+a s is the sequence that blocks scrolling, which makes screen seem like it freezes.
When using PuTTY, you can get an apparently freezed screen if you press Ctrl+s.
This sends an Xoff signal blocking the terminal's output.
The solution is to press Ctrl+q to send the Xon signal.
The above works great if that is your issue.
This could also happen if you're ssh'd into another machine and haven't been to the window in awhile, then when you go back it's frozen. To fix this, you can try the following:
1) Create a new window
Ctrl-a c
2) ssh into the box where you ssh'd into the box in the window that's frozen.
3) Find the process the ssh is running under:
ps aux | grep <remote_box_on_frozen_screen>
or
ps aux | grep <your_user_id>
4) Kill the process
kill <process_id>
When you do screen -ls the first number of the screen name is the process id. So if the output is
There is a screen on:
21605.pts-0.Random-server (11/12/2017 11:44:15 PM) (Detached)
1 Socket in /var/run/screen/S-kg.
Then this will kill it:
kill 21605
Notice the number for the kill command is the same as in the screen -ls output.
If you are using backtick commands in status line - that is, if your .screenrc has something like this:
backtick 1 0 60 /some/script.sh
then you want to be sure that the script is fast: apparently backtick execution blocks all IO to screen.
If you make changes to the config, you'll need to restart the screen session (as the config applies only to new sessions).

Resources