Is it possible to determine whether there is a numeric keypad connected to the system? Desktop keyboards typically have numpads, while laptops typically don't (though they put numpad keys in the normal keyboard, activated with Num Lock). Does the operating system know whether the numpad keys are physically separate? And if so, is that information exposed to programs somehow?
It would be useful to know this to determine appropriate default key-bindings. If it's not available then I'll either have to pick a conservative default (not using the numpad), which means a slightly irritating extra configuration step to get nicer behaviour for people with separate numpads, or I'll have to pick a non-conservative default and irritate the people without numpads...
I don't believe you can query for keyboard capabilities but iirc there is a "numpad" key. ;)
You should be able to query if Num is on or off, but it being off won't be a foolproof way to know that there is no numeric keypad.
What you could probably do is detect keys being pressed on a numpad and subliminaly trick the user into doing so, which would identify said characteristic.
install these packages
sudo apt-get install -y numlockx xdotool x11-utils
then use a script like this
#!/bin/bash
cd
numlockx off &
rm -f s1.sh s2.sh out
echo -e "#\041/bin/bash
sleep 2
xdotool key KP_5 | xev > out
exit 0" >> s1.sh
chmod +x s1.sh
echo -e "#\041/bin/bash
sleep 9
killall -9 xev
sleep 5
xdotool key BackSpace
exit 0" >> s2.sh
chmod +x s2.sh
bash s1.sh &
bash s2.sh
rm -f s1.sh s2.sh
if [[ "$(cat out | grep "keycode 84" | grep "KP_Begin" )" != "" ]]; then
echo "Separated Numpad Detected!"
fi
rm out
exit 0
because KP_Begin is the keycode for the numpad key KP_5 when numlock isn't active, in a real keyboard with a real keypad.
Tested on 3 PCs, one with a separated keypad e 2 without it.
Related
I am using a Raspberry pi.
I need to turn on a LED whenever I'm connected to the net and turn off the LED if the connection ever fails. I want to use a cron job running once per minute to do this.
I wrote and compiled two programs in 'C' (ledon, ledoff) that handles the GPIO pin. Those programs work.
I am logged in as 'pi'.
I used crontab -e to write the following:
*/1 * * * * /home/pi/cron_scripts/nettest
I was informed by someone that the first asterisk must have '/1' in order to run properly at the once-per-minute rate that I want. There is no space to the left of the first '/1' and one space after the '1' and each '*' thereafter.
FOR TESTING ONLY, The contents of /home/pi/cron_scripts/nettest is -
#!/bin/bash
ping -c 1 -q 8.8.8.8
if [ "$?" -eq 0 ]; then
printf "%s\n\n" "SUCCESS\n"
else
printf "%s\n\n" "FAIL\n"
fi
exit 0
I used sudo chmod +x /home/pi/cron_scripts/nettest
to make the script executable.
I will replace the printf lines with "ledon" and "ledoff" for the final version.
BUT IT WILL NOT RUN!
echo $(ping -c 1 -q 8.8.8.8)
etc.
I've been using i3-wm for about six months now, and I had to switch to GNOME because Discord was crashing a lot in i3. I had previously used the i3-msg command in my bashrc to make sure the borders of the terminal wouldn't be visible, as to use the entire screen space for the terminal. The specific command I run is:
i3-msg -q border toggle
The problem is, when I use GNOME and I open up a terminal, the i3-msg command runs, and causes an error message evidently caused by the fact that i3 isn't running. The ideal scenario would be to add an if statement that checks if i3 is running, and if it is, then run the i3-msg command.
My question: What is the most convenient way to determine which window manager / Desktop Environment is currently running in my system?
When i3 is active, there should be a proces called "i3". You could check that with pgrep.
if pgrep -x "i3" > /dev/null
then
echo "i3 is running"
fi
-x is short for --exact – without it the if clause would still work, as long as no non-i3 process' name contains i3.
Omitting > /dev/null would print out the pid(s) found by pgrep.
Instead of pgrep you could also use pidof or ps -C. Instead of idiomatic if-then-fi you could also just use && like pidof i3 > /dev/null && echo "i3 is running" || echo "i3 is not running"
I'm trying to write an xmonad.hs which, at startup, launches some apps on some workspaces. Several of these apps (e.g., atop) will run within a terminal (urxvt being my preference).
This has been asked a few times before, e.g, here, here, and is obliquely touched on on the XMonad FAQ.
However, these rely on:
using spawnOn from XMonad.Actions.SpawnOn, which flat doesn't work (testing with urxvt, and also xclock as a simple example); it gets sent to the current workspace.
using spawn prog >> windows $ greedyView <workspace>, which kinda works, but has major timing issues - e.g., if you run two in succession, with different workspaces, both progs end up on the latter workspace. FWIW, I experimented with using threaddelay to assist; it didn't make any discernable difference, even with a 10s delay between spawns (I remembered that threadDelay is in microseconds, and so used 10000000).
rely on using general hooks for programs - meaning that whenever I start them up, they'll get sent to the given workspace. That's not what I want; I just want them placed there at startup.
Relatedly, it surprises me that the API doesn't let me start up an app and then give me a reference to that app/window (potentially with a timeout); so that I can confidently send that app/window to a workspace.
Any help would be greatly appreciated.
Install wmctrl
sudo apt install wmctrl
And create a script (in this example thunderbird on the second workspace (-t 1)):
#!/bin/sh
(thunderbird &) & sleep 5 &&
sh -c "wmctrl -i -r `wmctrl -l | grep Thunderbird` -t 1"
To know your application name on wmctrl you can view it by taping on your terminal :
wmctrl -l
And replace it with the correct name in the script.
Be carrefull with the capital letter ("Thunderbird" not "thunderbird") !!
Other example with firefox on the 3d workspace (-t 2):
#!/bin/sh
(firefox &) & sleep 5 &&
sh -c "wmctrl -i -r `wmctrl -l | grep Firefox` -t 2"
Bonus :
Here is the command to execute at start-up :
sh -c "thunderbird & sleep 5 && wmctrl -i -r `wmctrl -l | grep Thunderbird` -t 1"
Work on Debain 10 with Cinnamon. But should work for all
You can spawn the app via startupHook and then use a manageHook to handle window placement.
manageHook such as:
, className =? "deluge" --> doShift ( myWorkspaces !! 3 )
The above will actually spawn deluge on Workspace 4. In my startupHook I have
spawnOnce "deluge-gtk" to launch the app on start-up.
You would want to import XMonad.Util.SpawnOnce. doShift comes from the default XMonad.ManageHooks You could also take a look at XMonad.Actions.SpawnOn but I only use manageSpawn from that module.
Background
I have a Bash script that requires user input. It can be run by calling it in a terminal or by pressing a keyboard shortcut registered in the i3 (or Sway) config file as follows:
bindsym --release $mod+Shift+t exec /usr/local/bin/myscript
The Problem
I know I can use read -p to prompt in a terminal, but that obviously won't work when the script is triggered through the keybinding. In that case I can use something like Yad to create a GUI, but I'm unable to detect when it's not "in a terminal". Essentially I want to be able to do something like this:
if [ $isInTerminal ]; then
read -rp "Enter your username: " username
else
username=$(yad --entry --text "Enter your username:")
fi
How can I (automatically) check if my script was called from the keybinding, or is running in a terminal? Ideally this should be without user-specified command-line arguments. Others may use the script and as such, I'd like to avoid introducing any possibility of user error via "forgotten flags".
Attempted "Solution"
This question suggests checking if stdout is going to a terminal, so I created this test script:
#!/usr/bin/env bash
rm -f /tmp/detect.log
logpass() {
echo "$1 IS opened on a terminal" >> /tmp/detect.log
}
logfail() {
echo "$1 IS NOT opened on a terminal" >> /tmp/detect.log
}
if [ -t 0 ]; then logpass stdin; else logfail stdin; fi
if [ -t 1 ]; then logpass stdout; else logfail stdout; fi
if [ -t 2 ]; then logpass stderr; else logfail stderr; fi
However, this doesn't solve my problem. Regardless of whether I run ./detect.sh in a terminal or trigger it via keybind, output is always the same:
$ cat /tmp/detect.log
stdin IS opened on a terminal
stdout IS opened on a terminal
stderr IS opened on a terminal
It seems like the easiest way to solve your actual problem would be to change the i3 bind to
bindsym --release $mod+Shift+t exec /usr/local/bin/myscript fromI3
and do
if [[ -n "$1" ]]; then
echo "this was from a keybind"
else
echo "this wasn't from a keybind"
fi
in your script.
False Positive
As most results on Google would suggest, you could use tty which would normally return "not a tty" when it's not running in a terminal. However, this seems to differ with scripts called via bindsym exec in i3/Sway:
/dev/tty1 # From a keybind
/dev/pts/6 # In a terminal
/dev/tty2 # In a console
While tty | grep pts would go part way to answering the question, it is unable to distinguish between running in a console vs from a keybinding which you won't want if you're trying to show a GUI.
"Sort of" Solution
Triggering via keybinding seems to always have systemd as the parent process. With that in mind, something like this could work:
{
[ "$PPID" = "1" ] && echo "keybind" || echo "terminal"
} > /tmp/detect.log
It is likely a safe assumption that the systemd process will always have 1 as its PID, but there's no guarantee that every system using i3 will also be using systemd so this is probably best avoided.
Better Solution
A more robust way would be using ps. According to PROCESS STATE CODES in the man page:
For BSD formats and when the stat keyword is used, additional characters may be displayed:
< high-priority (not nice to other users)
N low-priority (nice to other users)
L has pages locked into memory (for real-time and custom IO)
s is a session leader
l is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)
+ is in the foreground process group
The key here is + on the last line. To check that in a terminal you can call ps -Sp <PID> which will have a STAT value of Ss when running "interactively", or S+ if it's triggered via keybinding.
Since you only need the STATE column, you can further clean that up with -o stat= which will also remove the headers, then pipe through grep to give you the following:
is_interactive() {
ps -o stat= -p $$ | grep -q '+'
}
if is_interactive; then
read -rp "Enter your username: " username
else
username=$(yad --entry --text "Enter your username:")
fi
This will work not only in a terminal emulator and via an i3/Sway keybinding, but even in a raw console window, making it a much more reliable option than tty above.
I am working on a CentOS box.
What I expect: To run my own CLI/setup on startup instead of login prompt on serial console (telnet).
What I did so far:-
I changed call to "agetty" command in serial.conf and serial-ttyUSB0.conf files under /etc/init/, as follows:-
exec /sbin/agetty -n -l <path-to-my-custom-script> ........
My custom.sh script is:-
#!/bin/bash
LOOP_FLAG=0
while [ $LOOP_FLAG -eq 0 ]; do
for TTY in /dev/ttyS0 /dev/tty0; do
echo "Please choose to enter in 'setup' or 'cli'. (s/c)? " > $TTY
done
read sc
case $sc in
[Ss]* ) LOOP_FLAG=1; <some-executable-cli-file-path>; break;;
[Cc]* ) LOOP_FLAG=1; <some-executable-setup-file-path>; break;;
* ) for TTY in /dev/ttyS0 /dev/tty0; do
echo "Please press 's' or 'c'." >$TTY
done;;
esac
done
But when system boots, on a telnet session, I could only see the "Please choose to enter.." question on screen and after that I couldn't able to type anything on console.
One more update:
If I run the above agetty command on shell prompt as it is (say from ssh session), then it works fine on serial console (telnet). But, from the above startup scripts, it doesn't work.
Can anybody help me out with this?
Thanks in advance.
-Neo
Sorry I'm a few years late. Hopefully this will be of help for people searching for solution to this problem in the future.
The issue lies here:
-n, --skip-login Do not prompt the user for a login name. This can be used in connection with -l option to invoke a non-standard login
process such as a BBS system. Note that with the -n option, agetty
gets no input from user who logs in and therefore won't be able to
figure out parity, character size, and newline processing of the
connection. It defaults to space parity, 7 bit characters, and ASCII
CR (13) end-of-line character. Beware that the program that agetty
starts (usually /bin/login) is run as root.
So you need to initialize the terminal yourself in the script you are replacing the login prompt with. I found the settings below work well:
/bin/stty -F /dev/ttyO0 115200 cs8 sane
Remember to replace the baud rate and terminal name to your own.