The officially official Devuan Forum!

You are not logged in.

#101 Off-topic » how to automatically get xinput id of keyboard? [SOLVED] » 2019-09-13 17:46:24

GNUser
Replies: 17

I've written a shell script that needs to know the xinput id of the keyboard being used. In the case of my Devuan box the id happens to be 9. However, in my OpenBSD box the id is 6.

I want to make the script portable and don't want to bother myself or other users with having to run xinput --list and then manually editing the keyboard id in the script. Is there a way to determine the id automatically? If the script has to wait for user to press a key so that script can find the id, that would be fine.

I've checked what xdotooland xev but neither one seems able to help. grepping output of xinput --list for "keyboard" won't work because there's more than one line with that word in it. Also, I don't want to assume that the system language is English.

Any ideas?

#102 Re: Off-topic » What other distro are you using (besides devuan)? » 2019-07-18 19:38:46

OpenBSD and Tiny Core Linux

I dual boot Devuan and OpenBSD on my Libreboot laptop, which one I use on a given day depends on my mood.
Tiny Core Linux on my netbook-turned-router/fileserver/webserver

#103 Re: Installation » The most secure hardened kernel » 2019-06-20 19:05:43

For what it's worth, I find FSF/GNU and OpenBSD folks equally trustworthy. They bicker a lot over licensing, style, and other fine points, but the fact that both camps insist on source code being available tells me they have nothing to hide.

Unless a person decides he will become an island to himself and use only his own products, we have no choice but to trust others. So the question is not whether to trust, but who to trust. When it comes to software, I completely trust the FSF/GNU and OpenBSD folks (unless they are talking about each other smile).

#104 Re: Hardware & System Configuration » Listing Services On System » 2019-06-18 18:37:40

Welcome, nullr00t!

To see the init scripts that run at boot (which presumably are your "services"), do ls /etc/rcS.d and ls /etc/rc2.d

Another way is sudo service --status-all. The output of this command also shows which services are running vs. not running vs. status unknown. For the services that report status unknown, you can try pgrep -fa foo

#105 Re: Installation » The most secure hardened kernel » 2019-06-14 11:31:40

alupoj, if you care this much about your hardware not having backdoors (as I do and as we all should), then you need to use a computer that does not have proprietary BIOS or, even worse, Intel Management Engine or (AMD's) Platform Security Processor. See https://www.fsf.org/blogs/sysadmin/the- … rs-freedom

If you don't already, you should be using a computer with Libreboot (i.e., no proprietary BIOS and Intel Management Engine completely disabled). You can get a laptop with Libreboot on Minifree, Technoethical, or Vikings. They may be more vendors, but these are the ones I know of. I have been happily using a T400 with Libreboot (on which I dual-boot Devuan and OpenBSD) for several years. Everything works perfectly except for virtualization, which I have had to sacrifice. The choice between security and convenience affects everybody.

I second HoaS's plug for OpenBSD. Devuan is one of the the best GNU/Linuxen around, but GNU/Linux in general is not about being "most secure". If most secure is what you're looking for, that's what OpenBSD does by default--no need to swap key software components or tweak configuration settings.

#106 Re: Hardware & System Configuration » Create new service from systemd x11vnc.service » 2019-05-24 13:53:36

Hi, ea4170. I did some copy and pasting and came up with this. It is untested, but something to get you started:

#!/bin/sh
### BEGIN INIT INFO
# Provides:		x11vnc
# Required-Start:
# Required-Stop:
# Should-Start:	     
# Should-Stop:       
# X-Start-After:	lightdm
# Default-Start:	2 3 4 5
# Default-Stop:		0 1 6		
# Short-Description:	VNC Server for X11
# Description:		VNC Server for X11 
### END INIT INFO

case "$1" in
  start)
	while true; do
		/usr/bin/x11vnc -xkb -repeat -allow 127.0.0.1 -display :0 -auth guess -rfbauth /etc/X11/x11vnc.passwd -rfbport 5900 -forever -loop -o /var/log/x11vnc.log
	done
	;;
  stop)
	pkill x11vnc
	sleep 1
	pkill -KILL x11vnc
	;;
esac

exit 0

To test it:
1. Replace lightdm if appropriate (run # service --status-all or $ ls /etc/init.d to find the name of your display manager service)
2. Name the above script x11vnc, put it in /etc/init.d/, and make it executable
3. # update-rc.d x11vnc defaults

Good luck. Let me know how it goes.

P.S. I haven't used any vnc applications in a long time. If -forever -loop already gives you automatic restarting, delete the while true; do and done lines from my script.

#107 Re: Hardware & System Configuration » unreliable wireless network printer after power off/on cycle [SOLVED] » 2019-05-24 13:11:47

TL;DR version:
    This HP printer's dhcp client is flaky. If the printer's dhcp lease expires while printer is off, the printer cannot reliably get back on the network after being powered on--despite what its friendly beeps and lights might lead one to believe. Configuring router's dhcp server (dnsmasq) to give the printer a non-expiring ("infinite") lease solved the problem.

-----

Detailed version:
    I was able to consistently reproduce the problem by turning printer off, revoking printer's dhcp lease (in router: # pkill dnsmasq,  delete the line in /var/lib/misc/dnsmasq.leases that shows printer's lease, # dnsmasq), then turning printer back on. After printer fully powers on, its blue network light blinks for a little while then printer makes a friendly beep and blue light goes steady to indicate it has a network connection--which I found to be a big lie. In my experiments I found one of three things to always be true:

1. Printer takes a long time to negotiate a new dhcp lease--no new lease shows up in router's dnsmasq.leases (and printer is not reachable by ping or traceroute) until several minutes after printer's blue light is steady
2. Printer does not negotiate a new dhcp lease at all until I push some buttons on its little screen asking it to display its network settings
or
3. Printer never actually negotiates a new dhcp lease and reports that it has an ip address that is not even on my network (169.254.227.111)

Explaining the problems I was experiencing:
    Sometimes the kids turn off the printer and it is off for a few days until we find ourselves having to print again, by which time the printer's 24-hour dhcp lease has certainly expired. Those times it seemed that I needed to reboot my laptop before I could print again were probably due to situation #1 above--me rebooting was simply giving the printer enough time to finish negotiating a new lease with my router.

The solution:
    Configure printer to do as little as possible network-wise (in its settings, choose "get address automatically", provide the wireless network password, and that's it) and let the router not only assign the desired static IP but also make the lease non-expiring. This line in dnsmasq.conf takes care of both things: dhcp-host=aa:bb:cc:11:22:33,192.168.10.7,infinite (where aa:bb:cc:11:22:33 is the printer's MAC address, of course).
    Now when I turn the printer off and back on, it quickly gets on the network (can be reached by ping and traceroute) and can print reliably.

I hope this helps someone. I've been scratching my head on and off because of this for well over a year at this point.

#108 Re: Off-topic » dhclient - how to never ask for prior address? [SOLVED] » 2019-05-19 19:14:13

I have a good-enough solution. It involves A) some changes in router (dhcp server side) and B) some changes in laptop (dhcp client side).

A. In router (assuming you, like me, are using dnsmasq as the dhcp server):

# pkill dnsmasq
# rm /var/lib/misc/dnsmasq.leases
# echo "dhcp-sequential-ip" >> /etc/dnsmasq.conf
# dnsmasq

B. In my Devuan ASCII laptop (which unfortunately uses network-manager, which runs dhclient when appropriate):

# vi /etc/init.d/network-manager
add this line under the 'start)' line: rm /var/lib/NetworkManager/dhclient*
# service network-manager restart

Now, even with the default dhclient settings in my Devuan laptop, DHCP is working in a way that seems intuitive. Namely:
1. router leases out the first available IP
2. router keeps track of leases and repeatedly gives a particular IP to a particular machine only during life of the lease
3. when network-manager starts or restarts on a client machine, dhclient cannot ask for an old IP because there is no record

Problem solved smile

P.S. Since I know Head_on_a_Stick likes both Devuan and OpenBSD (I'm brudan on daemonforums.org, by the way), for an OpenBSD laptop/desktop, part B is simply adding !rm /var/db/dhclient.leases.\$if to the top of your /etc/hostname.if file.

#109 Re: Off-topic » dhclient - how to never ask for prior address? [SOLVED] » 2019-05-19 12:12:54

Thank you, Head_on_a_Stick. It seems NetworkManager parses /etc/dhcp/dhclient.conf then appends a few lines, to produce /var/lib/NetworkManager/dhclient-wlan0.conf. The latter file already contains request;. This is what the complete /var/lib/NetworkManager/dhclient-wlan0.conf looks like:

# Created by NetworkManager
# Merged from /etc/dhcp/dhclient.conf

# Configuration file for /sbin/dhclient.
#
# This is a sample configuration file for dhclient. See dhclient.conf's
#    man page for more information about the syntax of this file
#    and a more comprehensive list of the parameters understood by
#    dhclient.
#
# Normally, if the DHCP server provides reasonable information and does
#    not leave anything out (like the domain name, for example), then
#    few changes must be made to this file, if any.
#
option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
#send dhcp-client-identifier 1:0:a0:24:ab:fb:9c;
#send dhcp-lease-time 3600;
#supersede domain-name "fugue.com home.vix.com";
#prepend domain-name-servers 127.0.0.1;
#require subnet-mask, domain-name-servers;
#timeout 60;
#retry 60;
#reboot 10;
#select-timeout 5;
#initial-interval 2;
#script "/sbin/dhclient-script";
#media "-link0 -link1 -link2", "link0 link1";
#reject 192.33.137.209;
#alias {
#  interface "eth0";
#  fixed-address 192.5.5.213;
#  option subnet-mask 255.255.255.255;
#}
#lease {
#  interface "eth0";
#  fixed-address 192.33.137.200;
#  medium "link0 link1";
#  option host-name "andare.swiftmedia.com";
#  option subnet-mask 255.255.255.0;
#  option broadcast-address 192.33.137.255;
#  option routers 192.33.137.250;
#  option domain-name-servers 127.0.0.1;
#  renew 2 2000/1/12 00:00:01;
#  rebind 2 2000/1/12 00:00:01;
#  expire 2 2000/1/12 00:00:01;
#}
send host-name "thinkpad"; # added by NetworkManager

option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;
option ms-classless-static-routes code 249 = array of unsigned integer 8;
option wpad code 252 = string;

request; # override dhclient defaults
also request subnet-mask;
also request broadcast-address;
also request time-offset;
also request routers;
also request domain-name;
also request domain-name-servers;
also request domain-search;
also request host-name;
also request dhcp6.name-servers;
also request dhcp6.domain-search;
also request dhcp6.fqdn;
also request dhcp6.sntp-servers;
also request netbios-name-servers;
also request netbios-scope;
also request interface-mtu;
also request rfc3442-classless-static-routes;
also request ntp-servers;
also request ms-classless-static-routes;
also request static-routes;
also request wpad;

Any idea what needs to be changed in order to achieve the desired behavior?

#110 Re: Off-topic » dhclient - how to never ask for prior address? [SOLVED] » 2019-05-19 04:08:45

Alas, things are never as simple as they seem. Not only do we need 1) dhcp server sequential ip flag and 2) delete server's lease file, but there are also considerations on the client side.

It seems that dhclient is hardwired to ask for the last IP address it got. This from dhclient.conf's man page:

When the client is restarted, it first tries to reacquire the last address it had. This is called the INIT-REBOOT state. If it is still attached to the same network it was attached to when it last ran, this is the quickest way to get started. The reboot statement sets the time that must elapse after the client first tries to reacquire its old address before it gives up and tries to discover a new address. By default, the reboot timeout is ten seconds.

I tried putting reboot 0; in my computer's /etc/dhcp/dhclient.conf, but it has no effect. So I had to do this:
3) # rm /var/lib/NetworkManager/dhclient*

With 1-3 above I finally got the expected behavior of my computer getting the lowest-available IP address from the router.

But I'm not satisfied because step 3 is a hack. What I really want is a way of telling dhclient not to try to reacquire the last address it had. Any idea how to accomplish this?

#111 Re: Off-topic » dhclient - how to never ask for prior address? [SOLVED] » 2019-05-18 22:45:28

The dnsmasq man page solved the mystery of dhcp always giving particular computers particular IP addresses:

Dnsmasq  is  designed  to  choose  IP addresses for DHCP clients
using a hash of the client's MAC address. This normally allows a
client's  address to remain stable long-term, even if the client
sometimes allows its DHCP lease to expire.

The --dhcp-sequential-ip flag causes dnsmasq's behavior to be what I expected. Hope this helps anyone who finds themselves doing some head-scratching as I was smile

#112 Off-topic » dhclient - how to never ask for prior address? [SOLVED] » 2019-05-18 17:17:14

GNUser
Replies: 7

I'm doing some network troubleshooting and am surprised that the machines on my wireless network always get the same "random" IP address from my router, even after I delete all the leases in /var/lib/misc/dnsmasq.leases.

The router has a startup job that creates /tmp/dnsmasq.conf and then launches dnsmasq with this command: dnsmasq -C /tmp/dnsmasq.conf. This is what /tmp/dnsmasq.conf looks like:

listen-address=192.168.10.1
bind-dynamic
dhcp-range=192.168.10.100,192.168.10.200,255.255.255.0,24h
dhcp-option-force=option:router,192.168.10.1
dhcp-option-force=option:dns-server,192.168.10.1
dhcp-option-force=option:mtu,1500

How come machines get the same IP addresses even after I manually delete /var/lib/misc/dnsmasq.leases and reboot the router? All the machines are configured to use DHCP, not a static local ip. There must be a record of prior IP addresses somewhere. Does dnsmasq have some kind of IP address cache? Maybe the Devuan ASCII computers somehow remember their prior IP address and ask for the same address again during DHCP negotiation?

Bottomline: How do I purge all memory of prior IP addresses so that all machines in my wireless network get new addresses the next time they talk to the router?

#113 Re: Hardware & System Configuration » unreliable wireless network printer after power off/on cycle [SOLVED] » 2019-05-18 13:50:11

Hmm, I was curious about the ?zc= suffix in the printer's URI. An internet search tells me the zc stands for zeroconf and is related to avahi-daemon.

https://bugs.launchpad.net/hplip/+bug/521909

The strange thing is that avahi-daemon is not running on my machines because I disabled it (it is privacy-unfriendly). (Maybe I disabled avahi-daemon after installing the printer? I installed ASCII and setup the printer a long time ago and can't remember.) Maybe the ?zc= suffix has something to do with the flaky connection to the printer. I'll try re-creating the printer with the ?ip= suffix in its URL followed by its local ip address.

UPDATE:
I reconfigured the printer:

eileen@vaio:~$ lpstat -s
system default destination: HPWireless
device for HPWireless: hp:/net/Photosmart_7520_series?ip=192.168.10.7

Not sure if the new URI will cause the printer to be reachable more consistently, but it sure looks better!

#114 Re: Hardware & System Configuration » unreliable wireless network printer after power off/on cycle [SOLVED] » 2019-05-18 13:28:53

Thank you, ralph.ronnquist. That's an interesting theory. Next time I can't print, I'll try just disconnecting/reconnecting the computer from the wireless network instead of rebooting the computer. I'll report the results.

#115 Re: Hardware & System Configuration » unreliable wireless network printer after power off/on cycle [SOLVED] » 2019-05-18 02:35:27

Here is some basic printer information:

eileen@vaio:~$ lpstat -s
system default destination: HPWireless
device for HPWireless: hp:/net/Photosmart_7520_series?zc=HPA0D3C1E1E36F

Ping and traceroute can't reach the printer when the problem occurs. Strangely, I cannot reproduce the problem at will--it seems to happen randomly.

Here are results when I can print:

eileen@vaio:~$ ping -c 1 -W 2 192.168.10.7
PING 192.168.10.7 (192.168.10.7) 56(84) bytes of data.
64 bytes from 192.168.10.7: icmp_seq=1 ttl=255 time=1.86 ms

--- 192.168.10.7 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.861/1.861/1.861/0.000 ms

eileen@vaio:~$ traceroute 192.168.10.7
traceroute to 192.168.10.7 (192.168.10.7), 30 hops max, 60 byte packets
 1  HPE1E36F (192.168.10.7)  4.685 ms  4.918 ms  4.886 ms

Here are results when I cannot print:

eileen@vaio:~$ ping -c 1 -W 2 192.168.10.7
PING 192.168.10.7 (192.168.10.7) 56(84) bytes of data.

--- 192.168.10.7 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

eileen@vaio:~$ traceroute 192.168.10.7
traceroute to 192.168.10.7 (192.168.10.7), 30 hops max, 60 byte packets
 1  192.168.10.187 (192.168.10.187)  1069.930 ms !H  1069.884 ms !H  1069.869 ms !H

Why is it that I need to reboot the computer (not the printer) in order to be able to print again?

#116 Hardware & System Configuration » unreliable wireless network printer after power off/on cycle [SOLVED] » 2019-05-17 13:37:03

GNUser
Replies: 5

All my Devuan ASCII computers at home print to an HP printer on my wireless network. The printer is always at the same local IP address.

I have noticed that if the printer reconnects to the network for any reason (e.g., one of my kids turns it off and I have to turn it back on), sometimes none of the Devuan computers can print unless I first reboot them. It's difficult to reproduce.

I have tried restarting cups on the computers after the printer reconnects to the network, but it makes no difference. Some other service or daemon probably needs to be restarted, but I have no idea which one.

So here is my question, fellow VUAs: Short of rebooting the computer, what can I do in order for a Devuan machine to able to print to a wireless printer (via CUPS) after the printer has gone through a network disconnect-reconnect?

#117 DIY » basic keylogger/hotstrings shell script (e.g., for Esperanto input) » 2019-05-17 00:24:56

GNUser
Replies: 0

For any Esperantists out there: There are various ways of entering Esperanto characters in GNU/Linux, but I couldn't find how to do it with the x-system. Therefore, I cooked up a barebones shell script that does the job. As long as the script is running, you can use the x input method.

For example, if you type ehxosxangxocxiujxauxde, you get eĥoŝanĝoĉiuĵaŭde

Feel free to use my shell script below, which I hereby release into the public domain. Simply name the script "iksilo", make it executable, and run!

The script is tested and working in Devuan ASCII and OpenBSD 6.5, but should work in any UNIX-like OS using the X window system. (To use it in OpenBSD, simply change stdbuf to gstdbuf.)

#!/bin/sh

# Deps: coreutils, xdotool, dzen2
# Usage: iksilo start|stop

keyboard_id=9 # use 'xinput list' to find your keyboard's id. uzu 'xinput list' por trovi la id-numeron de via klavaro.

# 1. die gracefully 
dzen2_pid_file=/tmp/iksilo-dzen2-pid
die() { setxkbmap -option; kill $(cat $dzen2_pid_file); pkill -KILL -f iksilo; }
trap die INT HUP TERM; [ "$1" = "stop" ] && die

# 2. add the necessary keyboard options 
setxkbmap -option lv3:ralt_switch,esperanto:qwerty

# 3. simulate an array using variable names: mappings_38=a mappings_39=s mappings_40=d etc.
xmodmap -pke >/tmp/keymap
while read line; do
	keycode="$(echo $line | cut -d' ' -f 2)"
	key="$(echo $line | cut -d' ' -f 4)"
	eval mappings_"$keycode"="$key"
done </tmp/keymap
rm /tmp/keymap

# 4. create indicator
echo "IKSO" | dzen2 -fg "white" -bg "green" -w 40 -h 20 -x 1235 -y 755 -p -e '' & echo $! >$dzen2_pid_file

# 5. go!
replace() { xdotool key BackSpace BackSpace "$1"; }
memory="--"

xinput test $keyboard_id | stdbuf -oL awk '/press/ {print $3}' | while read keycode; do
	key=$(eval echo \$mappings_$keycode)
	memory=$(echo "${memory}${key}" | grep -o '..$')
	case $memory in
		cx) replace ISO_Level3_Shift+c ;;
		gx) replace ISO_Level3_Shift+g ;;
		hx) replace ISO_Level3_Shift+h ;;
		jx) replace ISO_Level3_Shift+j ;;
		sx) replace ISO_Level3_Shift+s ;;
		ux) replace ISO_Level3_Shift+u ;;
	esac
done

Karaj samideanoj, nomu la supran programeton "iksilo", igu ĝin rulebla, kaj rulu ĝin. Dum la programeto rulas, vi povas uzi la ikso-sistemon por tajpi esperantajn literojn ie ajn ene de X.org.  Nur certigu (per la eligaĵo de xinput list), ke la numero post keyboard_id= estas korekta por vi--ĉe mia komputilo, X.org vidas la klavaron kiel enigilo id=9, sed eble ĉe vi la numero estas alia. Por uzi la programeton en OpenBSD, simple ŝanĝu stdbuf al gstdbuf.

#118 Re: Off-topic » limit on number of pipes after long-running command? [SOLVED] » 2019-05-16 16:11:06

It was a buffering issue. I found this helpful thread:
https://unix.stackexchange.com/question … ng-in-pipe

I can confirm that either of these pipelines work as expected:

xinput test 9 | stdbuf -o0 grep release | awk '{print $3}'
xinput test 9 | unbuffer -p grep release | awk '{print $3}'

#119 Re: Off-topic » limit on number of pipes after long-running command? [SOLVED] » 2019-05-16 15:47:01

For example, here is what I get if I type devuan after the command:

$ xinput test 9 | awk '/press/ {print $3}'
40
26
55
30
38
57

Why does the following produce no output when I type devuan, even though there is an n in there?

$ xinput test 9 | awk '/press/ {print $3}' | grep 57

That's what I'm trying to understand: Why is there no output at all when I use a second pipe, even when output is expected? Is it a buffering issue?

#120 Re: Off-topic » limit on number of pipes after long-running command? [SOLVED] » 2019-05-16 15:42:28

That works, of course. But if I add a pipe after that, again: No output even when output is expected.

#121 Off-topic » limit on number of pipes after long-running command? [SOLVED] » 2019-05-16 15:39:07

GNUser
Replies: 4

I'm trying to create a minimal, crude keylogger for X using only a shell script. I was quickly stumped: Why do these two commands entered in a terminal emulator produce output when I press some keys on my keyboard:

$ xinput test 9 | grep press
$ xinput test 9 | awk '{print $3}'

...but this command produces no output:

$ xinput test 9 | grep press | awk '{print $3}'

?

It seems after the first command I can use only one pipe--if I add a second pipe, I get no output even when output is expected. What gives?

(BTW, 9 is the id of my keyboard, which I found by running xinput list. My shell is bash version 4.4.12)

#122 Re: Desktop and Multimedia » Mozilla Firefox unacceptable tactics - PLEASE ADVISE » 2019-05-07 02:29:53

Installing hotfix-update-xpi-signing-intermediate.xpi did not work for me, neither did setting xpinstall.signatures.required=false in about:config. Also, making extensions.json read-only or immutable was only partly successful--my addons are enabled every time firefox starts, but get switched to disabled in the middle of every browsing session. I'm on ASCII running an AppImage of more recent version of Firefox than what's in ASCII repository, so don't know if my experience is predictive/generalizable.

At any rate, in the end I just decided to jump ship. Chromium has all the plugins I use. I mitigated my unease of using a browser made by Google by turning off all the "call-home" settings and running chromium in a sandbox by using firejail, either via $ firejail chromium or # ln -s /usr/bin/firejail /usr/local/bin/chromium.

I found that all the info on firejail in Arch Linux's wiki is applicable to Devuan:
https://wiki.archlinux.org/index.php/Firejail

#123 Re: DIY » customizable Unicode international keyboard » 2019-03-24 11:05:23

I forgot to mention that the scripts assumes you are using a UTF-8 locale. The script just won't work if it finds itself in a non-UTF-8 environment. Here is a quick tutorial on locales:

To see your current locale, run locale

To see locales that are ready to use on your machine, run locale -a

If you want to switch to a locale that is not ready to use on your machine, you have to generate it:
manually edit /etc/locale.gen and uncomment the locale you want, then run locale-gen as root

To change your locale, put the one you want in /etc/default/locale (for example, LANG=en_US.UTF-8) then reboot.

#124 DIY » customizable Unicode international keyboard » 2019-03-24 03:15:25

GNUser
Replies: 1

I like using my own custom "hotstrings" for invoking Unicode characters (e.g., cx for ĉ, a' for á, c,, for ç) so I decided to create a python3 script that does this easily for me. Thought I'd post my solution here in case it is useful to anyone.

To use the script you need to install a few dependencies (some packages and two python3 modules). Run these two commands in a terminal to get all the dependencies:

$ sudo apt install python3 python3-pip x11-xserver-utils procps libnotify-bin xclip yad
$ pip3 install pynput Xlib --user

After that, all you need is the script and a config file.

Here is the script:

#!/usr/bin/env python3

# klavaro 2.0
# Copyright (c) 2019 Bruno "GNUser" Dantas <klavaro@dantas.airpost.net>
# This is free software, released under the terms of the ISC license:
# Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby
# granted, provided that the above copyright notice and this permission notice appear in all copies.
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
# INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE 
# FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 
# ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 

from pynput import keyboard
from pynput import mouse
keyboard0 = keyboard.Controller()
mouse0 = mouse.Controller()
import os
import sys
import time

def log_it(keystroke):
	"""High level function that logs keystroke, checks if last keystrokes 
	match a hotsring/trigger, replaces trigger with corresponding Unicode character"""
	global mappings
	global last_strokes
	del last_strokes[0]
	last_strokes.append(keystroke)
	last_strokes_str = ''.join(last_strokes)
	#print("last strokes = " + last_strokes_str) # for debugging
	for trigger in mappings.keys():
		if last_strokes_str.endswith(trigger):
			character = mappings[trigger]
			backspaces = len(trigger)
			#print("replacing " + trigger + " with " + character) # for debugging
			while backspaces > 0:
				keyboard0.press(keyboard.Key.backspace)
				keyboard0.release(keyboard.Key.backspace)
				backspaces -= 1
			os.system('''xclip -o -selection clipboard | xclip -selection secondary''') # save clipboard contents to secondary
			os.system('''printf %s | xclip -selection clipboard''' % character) # feed unicode character to clipboard
			keyboard0.press(keyboard.Key.ctrl) # press Ctrl+v to paste from clipboard
			keyboard0.press('v')
			keyboard0.release('v')
			keyboard0.release(keyboard.Key.ctrl)
			time.sleep(0.5) # don't restore clipboard too quickly (some applications, e.g. qterminal, need a moment to react to Ctrl+v)
			os.system('''xclip -o -selection secondary | xclip -selection clipboard''') # restore clipboard contents from secondary

def on_press(key): 
	"""Keylogger runs this function on each keyboard event"""
	global capslock_in_effect
	output = str(key)
	if output == 'Key.caps_lock': # if capslock pressed, toggle capslock state
		capslock_in_effect = not capslock_in_effect
	if not output.startswith('Key'): # pynput calls special keys 'Key.foo'
		output = output[1:-1] # remove quotes around alphanumeric key names
		if capslock_in_effect:
			output = output.swapcase() 
			# .swapcase and not .upper because pressing Shift during CapsLock should log a lowercase letter
	if not output.startswith('Key.shift'): # log all keystrokes except shift (e.g., so that a~ is logged without an intervening Shift)
		if output.startswith('Key.'): # log special keystrokes as a space
			output=' '
		log_it(output)

def on_click(x, y, button, pressed):
	"""Keylogger runs this function on each mouse event"""
	button = str(button)
	if pressed and button == 'Button.left': # log left clicks as a space
		log_it(' ')

def start():
	# 1. Build mappings from klavaro.conf
	global mappings
	mappings = {}
	abspath=os.path.realpath(sys.argv[0])
	dirname=os.path.dirname(abspath)

	with open('%s/klavaro.conf' % dirname) as f:
		for line in f:
			(trigger, character) = line.split()
			mappings[trigger] = character

	# 2. Initialize an empty list to hold last few keystrokes
	global last_strokes
	last_strokes = [ '' ] * 5 
	
	# 3. Create taskbar icon
	os.system('''yad --notification --image=keyboard --text="Klavaro" --no-middle --menu="Exit!klavaro stop!application-exit" --listen & echo $! >/tmp/klavaro-icon-pid''')
	
	# 4. Get initial CapsLock state
	global capslock_in_effect
	exit_code = os.system('''xset q | grep -q 'Caps Lock:[[:space:]]*on' ''')
	if exit_code == 0:
		capslock_in_effect = True
	else:
		capslock_in_effect = False

	# 5. Finally, start keylogger
	with mouse.Listener(on_click=on_click) as listener:
		with keyboard.Listener(on_press=on_press) as listener:
			listener.join()
	
#####

def stop():
	os.system('''kill $(cat /tmp/klavaro-icon-pid); rm /tmp/klavaro-icon-pid''')
	os.system('''pkill -f klavaro''')

#####

if sys.argv[1] == "start":
	try:
		os.stat('/tmp/klavaro-icon-pid')
	except: 
		start()
	else: 
		os.system('''notify-send -i dialog-warning -t 2000 "Klavaro" "Klavaro is already running"''')
		sys.exit()

elif sys.argv[1] == "stop":
	stop()

Here is my config file, which lists my hotstrings and corresponding Unicode characters (modify* it to suit your needs):

A` À
a` à
A' Á
a' á
A^ Â
a^ â
A~ Ã
a~ ã
A:: Ä
a:: ä
E` È
e` è
E' É
e' é
E^ Ê
e^ ê
E~ Ẽ
e~ ẽ
E:: Ë
e:: ë
I` Ì
i` ì
I' Í
i' í
I^ Î
i^ î
I~ Ĩ
i~ ĩ
I:: Ï
i:: ï
O` Ò
o` ò
O' Ó
o' ó
O^ Ô
o^ ô
O~ Õ
o~ õ
O:: Ö
o:: ö
U` Ù
u` ù
U' Ú
u' ú
U^ Û
u^ û
U~ Ũ
u~ ũ
U:: Ü
u:: ü
C,, Ç
c,, ç
Cx Ĉ
CX Ĉ
cx ĉ
Gx Ĝ
GX Ĝ
gx ĝ
Hx Ĥ
HX Ĥ
hx ĥ
Jx Ĵ
JX Ĵ
jx ĵ
Sx Ŝ
SX Ŝ
sx ŝ
Ux Ŭ
UX Ŭ
ux ŭ

To use the script, save it as klavaro (it means "keyboard" in Esperanto), make it executable, and put it somewhere in your PATH. Save the config file as klavaro.conf and put it in the same directory as the script.

To start the script:

$ klavaro start &

To end the script:

$ klavaro stop

While the script is running, hotstrings will magically be converted to their corresponding Unicode character in any application that supports Control+v to paste from clipboard. (For the magic to happen in a terminal emulator, you may need to go to emulator's settings and change the paste shortcut from Shift+Control+v to Control+v.)

The script is tested and working (hard and on a daily basis) on Devuan ASCII and OpenBSD 6.4, but should work on any Unix-like OS. I love this script so much, I wish I had cooked it up years ago. Hopefully others will also find it useful smile

-------------------------------

How it works
Script waits for you to type one of the hotstrings. When you do, the script very quickly does the following:
1. Presses appropriate number of backspaces to erase the hotstring
2. Saves current clipboard** contents
3. Puts Unicode character in clipboard
4. Pastes Unicode character at cursor position
5. Restores clipboard contents

-------------------------------

Footnotes

* Adding new Unicode characters to klavaro.conf may seem like a "chicken and the egg" problem, but it isn't hard. First, find the code point for the character you want here (for example, the code for ĉ is 0109). Then, open klavaro.conf in a GUI text editor that supports the Shift+Control+u method of inserting Unicode characters (pluma, gedit, and geany support this, among many others). For my example, pressing Shift+Control+u, then typing 0109, then pressing Enter creates ĉ. Easy peasy!

** Using the clipboard was a workaround due to the fact that all the "typing" utilities I explored (xdotool, xvkbd, pynput) either had no Unicode support or only partial support. The X clipboard, on the other hand, can handle everything.

#125 Re: DIY » automatic mac address spoofer » 2019-03-11 11:42:33

@freenet_bro: You're welcome, glad I could help. It was also good to make the script more general and less complicated.

Board footer

Forum Software