Compare commits

..

No commits in common. "master" and "1.3" have entirely different histories.
master ... 1.3

12 changed files with 174 additions and 469 deletions

View file

@ -1,2 +1,2 @@
# This allows users in group input to use dotool without root permissions.
KERNEL=="uinput", GROUP="input", MODE="0620", OPTIONS+="static_node=uinput"
KERNEL=="uinput", GROUP="input", MODE="0660", OPTIONS+="static_node=uinput"

View file

@ -2,38 +2,14 @@
Notable changes to dotool will be documented in this file.
## [1.5](https://git.sr.ht/~geb/dotool/refs/1.5)
### Fixed
- The selecting of the fewest modifiers for simulating keys.
## [1.4](https://git.sr.ht/~geb/dotool/refs/1.4)
### Added
- A manpage, requiring scdoc.
- Heuristic support for dead keys.
- Support for altgr.
- $DOTOOL_KEYBOARD_NAME to set the virtual keyboard's name.
- More verbose --list-keys output.
### Changed
- Replaced ./install.sh with ./build.sh.
### Fixed
- Now prefers the fewest modifiers for simulating keys. (UPDATE: see 1.5)
## [1.3](https://git.sr.ht/~geb/dotool/refs/1.3)
### Added
## Added
- Support for keyboard layouts.
- hwheel for horizontal scrolling.
### Changed
## Changed
- Now depends on the xkbcommon library.
- XKB key names are now case-sensitive.

View file

@ -1,42 +1,65 @@
# dotool
dotool reads actions from stdin and simulates keyboard/mouse input using
Linux's uinput module. It works systemwide and supports keyboard layouts.
## Install From Packages
Packages of dotool are available on:
- [Alpine](https://pkgs.alpinelinux.org/packages?name=dotool)
- [Arch (AUR)](https://aur.archlinux.org/packages?SeB=n&K=dotool)
- [Nix](https://search.nixos.org/packages?channel=unstable&type=packages&query=dotool)
- [Void](https://voidlinux.org/packages/?q=dotool)
and potentially other platforms.
dotool reads commands from stdin and simulates keyboard and pointer events.
It works everywhere on Linux, including in X11, Wayland and TTYs.
## Install From Source
With `go`, `libxkbcommon-dev` and `scdoc` installed, run:
With `go` and `libxkbcommon-dev` installed, run:
./build.sh && sudo ./build.sh install
sudo ./install.sh
And to trigger the udev rule, run:
## Permission
sudo udevadm control --reload && sudo udevadm trigger
dotool requires permission to `/dev/uinput` to create the virtual input
devices, and a udev rule grants this to users in group input.
You could try:
echo type hello | dotool
and if need be, you can run:
sudo groupadd -f input
sudo usermod -a -G input $USER
and re-login and trigger the udev rule or just reboot.
## Usage
See the [manpage](doc/dotool.1.scd).
See `dotool --help`, but this greets the world:
echo 'type Sup, Lads!' | dotool
and this screams for three seconds:
{ echo keydown A; sleep 3; echo key H shift+1; } | dotool
There is an initial delay registering the virtual devices, but you can
keep writing commands to the same instance or use the daemon and client,
`dotoold` and `dotoolc`.
dotoold &
echo type super | dotoolc
echo type speedy | dotoolc
## Keyboard Layouts
dotool will type gobbledygook if your environment has assigned it a different
keyboard layout than it's simulating keycodes for. You can match them up
with the environment variables `DOTOOL_XKB_LAYOUT` and `DOTOOL_XKB_VARIANT`.
echo type azerty | DOTOOL_XKB_LAYOUT=fr dotool
## Numen and Contact
dotool was written for [Numen](https://numenvoice.org), which has a
[chat on Matrix](https://matrix.to/#/#numen:matrix.org) you're welcome to join.
You can also send questions or patches by composing an email to
[~geb/numen@lists.sr.ht](https://lists.sr.ht/~geb/numen).
You can also send questions, thoughts or patches by composing an email to
[~geb/public-inbox@lists.sr.ht](https://lists.sr.ht/~geb/public-inbox).
## Support My Work 👀
## Support Me
[Thank you!](https://liberapay.com/geb)

View file

@ -1,22 +0,0 @@
#!/bin/sh
# ./build.sh ['install']
: "${DOTOOL_VERSION=$(git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 1.5)}"
: "${DOTOOL_DESTDIR=}"
: "${DOTOOL_BINDIR=usr/local/bin}"
: "${DOTOOL_UDEV_RULES_DIR=etc/udev/rules.d}"
if [ "$*" != '' ] && [ "$*" != install ]; then
echo bad usage
exit 1
fi
if ! [ "$1" ]; then
go build -ldflags "-X main.Version=$DOTOOL_VERSION" || exit
echo Built Successfully.
else
install -Dm755 dotool dotoolc dotoold -t "$DOTOOL_DESTDIR/$DOTOOL_BINDIR" || exit
install -Dm644 80-dotool.rules -t "$DOTOOL_DESTDIR/$DOTOOL_UDEV_RULES_DIR" || exit
mkdir -p "$DOTOOL_DESTDIR/usr/share/man/man1" || exit
scdoc < doc/dotool.1.scd > "$DOTOOL_DESTDIR/usr/share/man/man1/dotool.1" || exit
echo Installed Successfully.
fi

View file

@ -1,132 +0,0 @@
dotool(1)
# NAME
*dotool* - uinput tool
# SYNOPSIS
*dotool* < _actions_
# DESCRIPTION
*dotool* reads actions from stdin and simulates keyboard/mouse input using
Linux's uinput module.
# PERMISSION
*dotool* requires write permission to */dev/uinput*, which is granted to
users in group *input* by a udev rule.
You can test:
*echo type hello | dotool*
and if need be, you could add your user to group *input* with:
*groupadd -f input*++
*usermod -a -G input $USER*
and then it's foolproof to reboot to make the group and rule effective.
# KEYBOARD LAYOUTS
*dotool* may type gobbledygook if it's simulating keycodes for a different
keyboard layout than your environment is expecting.
You can specify the layout with the environment variables *DOTOOL_XKB_LAYOUT*
and *DOTOOL_XKB_VARIANT*. For example:
*echo type azerty | DOTOOL_XKB_LAYOUT=fr dotool*
You can also specify the name to give the virtual keyboard with the environment
variable *DOTOOL_KEYBOARD_NAME*, which can be useful making rules for your
environment.
Currently the *type* action has only heuristic support for dead keys.
# OPTIONS
*-h*, *--help*
Print help and exit.
*--list-keys*
Print the possible Linux keys and exit.
*--list-x-keys*
Print the possible XKB keys and exit.
*--version*
Print the version and exit.
# ACTIONS
*key* _CHORD_...++
*keydown* _CHORD_...++
*keyup* _CHORD_...
Press and/or release each _CHORD_. A _CHORD_ is a key or a key with
modifiers, such as *a*, *shift+a* or *ctrl+shift+a*.
The supported modifiers are *super*, *altgr*, *ctrl*, *alt* and *shift*.
Keys can be specified by Linux names, XKB names prefixed with
*x:*, or Linux keycodes prefixed with *k:*. The Linux names are
case-insensitive, except uppercase character keys also simulate
shift. This example types *!!!* with the *us* layout:
*echo key shift+1 x:exclam shift+k:2 | dotool*
*type* _TEXT_
Type _TEXT_.
*click* *left*/*middle*/*right*++
*buttondown* *left*/*middle*/*right*++
*buttonup* *left*/*middle*/*right*
Press and/or release a mouse button.
*wheel* _AMOUNT_++
*hwheel* _AMOUNT_
Scroll a vertical/horizontal mouse wheel by a positive or negative
_AMOUNT_.
*mouseto* _X_ _Y_
Jump the cursor to the position _X_ _Y_, where _X_ and _Y_ are
percentages between 0.0 and 1.0.
*mousemove* _X_ _Y_
Move the cursor relative to its current position.
*keydelay* _MILLISECONDS_++
*keyhold* _MILLISECONDS_++
*typedelay* _MILLISECONDS_++
*typehold* _MILLISECONDS_
Set the delay between/holding each key with the *key*\* actions/*type*
action.
The default *keydelay* and *typedelay* is 2ms, and the default
*keyhold* and *typehold* is 8ms.
# LONG-RUNNING INSTANCE
Each instance of *dotool* has an initial delay registering the virtual
devices, but you can keep writing actions to a long-running instance. The
daemon and client, *dotoold* and *dotoolc*, let you do this with a pipe
behind the scenes, for example:
*dotoold &*++
*echo type super | dotoolc*++
*echo type speedy | dotoolc*
# EXAMPLES
This greets the world:
*echo type hi | dotool*
This screams for roughly three seconds:
*{ echo keydown A; sleep 3; echo key H shift+1; } | dotool*
# AUTHOR
John Gebbie

182
dotool.go
View file

@ -18,9 +18,9 @@ import (
var Version string
func usage() {
fmt.Println(`dotool reads actions from stdin and simulates input using uinput.
fmt.Println(`dotool reads commands from stdin and simulates keyboard and pointer events.
The supported actions are:
The commands are:
key CHORD...
keydown CHORD...
keyup CHORD...
@ -28,20 +28,62 @@ The supported actions are:
click left/middle/right
buttondown left/middle/right
buttonup left/middle/right
wheel AMOUNT
hwheel AMOUNT
wheel AMOUNT (a positive AMOUNT is up, a negative is down)
hwheel AMOUNT (a positive AMOUNT is right, a negative is left)
mouseto X Y (where X and Y are percentages between 0.0 and 1.0)
mousemove X Y (where X and Y are amounts to move)
keydelay MILLISECONDS
keyhold MILLISECONDS
typedelay MILLISECONDS
typehold MILLISECONDS
mousemove X Y (where X and Y are the number of pixels to move)
keydelay MILLISECONDS (default: 2)
keyhold MILLISECONDS (default: 8)
typedelay MILLISECONDS (default: 2)
typehold MILLISECONDS (default: 8)
--list-keys Print the possible Linux keys and exit.
--list-x-keys Print the possible XKB keys and exit.
--version Print the version and exit.
See 'man dotool' for the documentation.`)
dotool is installed with a udev rule to allow users in group input to run
it without root permissions.
You can add yourself to group input by running:
sudo groupadd -f input
sudo usermod -a -G input $USER
It's foolproof to reboot to make the rule effective.
Keys can be specified by Linux names, XKB names prefixed with x:, or Linux
keycodes prefixed with k:. The Linux names are case-insensitive, except
uppercase character keys also simulate shift.
The modifiers are: super, ctrl, alt and shift.
echo key shift+1 x:exclam shift+k:2 | dotool
There is an initial delay registering the virtual devices, but you can keep
writing commands to the same instance or use the daemon and client, dotoold
and dotoolc.
{ echo keydown A; sleep 3; echo key H shift+1; } | dotool
dotoold &
echo type super | dotoolc
echo type speedy | dotoolc
dotool will type gobbledygook if your environment has assigned it a different
keyboard layout than it's simulating keycodes for. You can match them up
with the environment variables DOTOOL_XKB_LAYOUT and DOTOOL_XKB_VARIANT.
echo type azerty | DOTOOL_XKB_LAYOUT=fr dotool
--list-keys
Print the possible Linux keys and exit.
--list-x-keys
Print the possible XKB keys and exit.
--version
Print the version and exit.`)
}
func fatal(a ...any) {
@ -62,8 +104,6 @@ func log(err error) {
type Chord struct {
Super, AltGr, Ctrl, Alt, Shift bool
Key int
level uint32 // just for initKeys
}
func parseChord(keymap *xkb.Keymap, chord string) (Chord, error) {
@ -98,8 +138,6 @@ func parseChord(keymap *xkb.Keymap, chord string) (Chord, error) {
switch strings.ToLower(keys[i]) {
case "super":
c.Super = true
case "altgr":
c.AltGr = true
case "ctrl", "control":
c.Ctrl = true
case "alt":
@ -114,80 +152,55 @@ func parseChord(keymap *xkb.Keymap, chord string) (Chord, error) {
return c, nil
}
func (c Chord) KeyDown(kb uinput.Keyboard) {
func (c *Chord) KeyDown(kb uinput.Keyboard) {
if c.Super {
log(kb.KeyDown(super))
log(kb.KeyDown(uinput.KeyLeftmeta))
}
if c.AltGr {
log(kb.KeyDown(altgr))
log(kb.KeyDown(84))
}
if c.Ctrl {
log(kb.KeyDown(ctrl))
log(kb.KeyDown(uinput.KeyLeftctrl))
}
if c.Alt {
log(kb.KeyDown(alt))
log(kb.KeyDown(uinput.KeyLeftalt))
}
if c.Shift {
log(kb.KeyDown(shift))
log(kb.KeyDown(uinput.KeyLeftshift))
}
log(kb.KeyDown(c.Key))
}
func (c Chord) KeyUp(kb uinput.Keyboard) {
func (c *Chord) KeyUp(kb uinput.Keyboard) {
if c.Super {
log(kb.KeyUp(super))
log(kb.KeyUp(uinput.KeyLeftmeta))
}
if c.AltGr {
log(kb.KeyUp(altgr))
log(kb.KeyUp(84))
}
if c.Ctrl {
log(kb.KeyUp(ctrl))
log(kb.KeyUp(uinput.KeyLeftctrl))
}
if c.Alt {
log(kb.KeyUp(alt))
log(kb.KeyUp(uinput.KeyLeftalt))
}
if c.Shift {
log(kb.KeyUp(shift))
log(kb.KeyUp(uinput.KeyLeftshift))
}
log(kb.KeyUp(c.Key))
}
func (c *Chord) String() string {
var sb strings.Builder
if c.Super {
sb.WriteString("super+")
}
if c.AltGr {
sb.WriteString("altgr+")
}
if c.Ctrl {
sb.WriteString("ctrl+")
}
if c.Alt {
sb.WriteString("alt+")
}
if c.Shift {
sb.WriteString("shift+")
}
sb.WriteString("k:")
sb.WriteString(strconv.Itoa(c.Key))
return sb.String()
}
func listKeys(keymap *xkb.Keymap, keys map[string]Chord) {
var margin int
for code := 1; code < 256; code++ {
for name := range keys {
if len(name) > margin {
margin = len(name)
}
}
}
for code := 1; code < 256; code++ {
for name, chord := range keys {
if chord.Key == code {
fmt.Printf("%-*s %s\n", margin, name, chord.String())
if chord.Key == code && (chord == Chord{Key: code}) {
fmt.Println(name, code)
}
}
for name, chord := range keys {
if chord.Key == code && (chord != Chord{Key: code}) {
fmt.Println(name, code)
}
}
}
@ -232,47 +245,43 @@ func main() {
}
{
o := opt.NewOptSet()
optset := opt.NewOptionSet()
o.FlagFunc("h", func() error {
optset.FlagFunc("h", func() error {
usage()
os.Exit(0)
panic("unreachable")
})
o.Alias("h", "help")
optset.Alias("h", "help")
o.FlagFunc("list-keys", func() error {
optset.FlagFunc("list-keys", func() error {
listKeys(keymap, LinuxKeys)
os.Exit(0)
panic("unreachable")
})
o.FlagFunc("list-x-keys", func() error {
optset.FlagFunc("list-x-keys", func() error {
listKeys(keymap, XKeys)
os.Exit(0)
panic("unreachable")
})
o.FlagFunc("version", func() error {
optset.FlagFunc("version", func() error {
fmt.Println(Version)
os.Exit(0)
panic("unreachable")
})
err := o.Parse(true, os.Args[1:])
err := optset.Parse(true, os.Args[1:])
if err != nil {
fatal(err.Error())
}
if len(o.Args()) > 0 {
if len(optset.Args()) > 0 {
fatal("there should be no arguments, commands are read from stdin")
}
}
keyboardName := []byte(os.Getenv("DOTOOL_KEYBOARD_NAME"))
if len(keyboardName) == 0 {
keyboardName = []byte("dotool keyboard")
}
keyboard, err := uinput.CreateKeyboard("/dev/uinput", keyboardName)
keyboard, err := uinput.CreateKeyboard("/dev/uinput", []byte("dotool keyboard"))
if err != nil {
fatal(err.Error())
}
@ -349,23 +358,18 @@ func main() {
}
} else if s, ok := cutWord(text, "type"); ok {
for _, r := range s {
sym := xkb.Utf32ToKeysym(uint32(r))
if sym == 0 {
if sym := xkb.Utf32ToKeysym(uint32(r)); sym == 0 {
warn("invalid character: " + string(r))
} else if c := getChord(keymap, sym); c.Key != 0 {
c.KeyDown(keyboard)
time.Sleep(typehold)
c.KeyUp(keyboard)
} else if c1, c2 := getDeadChords(keymap, r); c1.Key != 0 {
c1.KeyDown(keyboard)
time.Sleep(typehold)
c1.KeyUp(keyboard)
time.Sleep(typedelay)
c2.KeyDown(keyboard)
time.Sleep(typehold)
c2.KeyUp(keyboard)
} else {
warn("impossible character for layout: " + string(r))
chord := getChord(keymap, sym)
if chord.Key == 0 {
warn("impossible character for layout: " + string(r))
time.Sleep(typehold)
} else {
chord.KeyDown(keyboard)
time.Sleep(typehold)
chord.KeyUp(keyboard)
}
}
time.Sleep(typedelay)
}

17
dotoold
View file

@ -1,15 +1,10 @@
#!/bin/sh
for a; do
case "$a" in
-h|--help)
echo 'dotoold runs dotool reading from a pipe for dotoolc to write to. dotoold
if [ $# != 0 ]; then
echo 'dotoold runs dotool reading from a pipe for dotoolc to write to. dotoold
will exit immediately if the pipe is already being read. The path used
for the pipe is $DOTOOL_PIPE else /tmp/dotool-pipe.' >&2
exit
;;
--) break;;
esac
done
[ "$1" = -h ] || [ "$1" = --help ]; exit
fi
fifo_being_read(){
[ -p "$1" ] && /bin/echo 1<>"$1" >"$1"
@ -25,5 +20,5 @@ fi
rm -f -- "$p" || exit 1
trap 'rm -f -- "$p"; pkill -P $$; trap - EXIT; exit' EXIT INT TERM HUP
mkfifo -m 660 "$p" || exit 1
dotool "$@" <> "$p" &
wait $!
dotool <> "$p" &
wait

4
go.mod
View file

@ -3,6 +3,6 @@ module git.sr.ht/~geb/dotool
go 1.19
require (
git.sr.ht/~geb/opt v0.0.0-20230911153257-e72225a1933c
github.com/bendahl/uinput v1.7.0
git.sr.ht/~geb/opt v0.0.0-20221207200434-dad26d091d71
github.com/bendahl/uinput v1.6.0
)

8
go.sum
View file

@ -1,4 +1,4 @@
git.sr.ht/~geb/opt v0.0.0-20230911153257-e72225a1933c h1:gIC1gnCgoasPHks1x6MB+bgDmIWMxKc5HIJPJrsV5Ck=
git.sr.ht/~geb/opt v0.0.0-20230911153257-e72225a1933c/go.mod h1:S6h1g8P7DyG7i7YIHZ5IpYbC6lzZB9DYIEl8PyXOmsg=
github.com/bendahl/uinput v1.7.0 h1:nA4fm8Wu8UYNOPykIZm66nkWEyvxzfmJ8YC02PM40jg=
github.com/bendahl/uinput v1.7.0/go.mod h1:Np7w3DINc9wB83p12fTAM3DPPhFnAKP0WTXRqCQJ6Z8=
git.sr.ht/~geb/opt v0.0.0-20221207200434-dad26d091d71 h1:jh3Ite7R1ZvdLt6j52e4njO2SS/z5dWOLXllw7inalc=
git.sr.ht/~geb/opt v0.0.0-20221207200434-dad26d091d71/go.mod h1:S6h1g8P7DyG7i7YIHZ5IpYbC6lzZB9DYIEl8PyXOmsg=
github.com/bendahl/uinput v1.6.0 h1:fM6r3OSC17rHh758mizKjSBuqi+XinhiGd4N3pWvZiI=
github.com/bendahl/uinput v1.6.0/go.mod h1:Np7w3DINc9wB83p12fTAM3DPPhFnAKP0WTXRqCQJ6Z8=

17
install.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/sh
# ./install.sh [DESTDIR] [BINDIR]
: "${DOTOOL_VERSION=$(git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 1.3)}"
go build -ldflags "-X main.Version=$DOTOOL_VERSION" || exit
mkdir -p "$1/${2:-usr/local/bin}" || exit
cp -v dotool dotoolc dotoold "$1/${2:-usr/local/bin}" || exit
mkdir -p "$1/etc/udev/rules.d" || exit
cp -v 80-dotool.rules "$1/etc/udev/rules.d" || exit
# Remove files from before the keyboard layout approach changed
rm -f "$1/usr/share/X11/xorg.conf.d/50-dotool.conf"
rm -f "$1/etc/sway/config.d/dotool"
# Make the new/updated udev rule effective
udevadm control --reload
udevadm trigger

165
keys.go
View file

@ -3,11 +3,8 @@ package main
import (
"git.sr.ht/~geb/dotool/xkb"
"github.com/bendahl/uinput"
"unicode"
)
var super, altgr, ctrl, alt, shift int
var LinuxKeys = map[string]Chord{
// Linux Only
"micmute": Chord{Key: uinput.KeyMicmute},
@ -484,137 +481,11 @@ var linuxXSyms = map[string]uint32{
var XKeys = map[string]Chord{}
type DeadKeyResult struct {
DeadKey, Key string
Result rune
}
// this relies on a conventional keymap
// this isn't exhaustive (e.g. acircumflexacute)
var DeadKeyResults = []DeadKeyResult{
{"dead_abovedot", "B", 'Ḃ'},
{"dead_abovedot", "C", 'Ċ'},
{"dead_abovedot", "D", 'Ḋ'},
{"dead_abovedot", "E", 'Ė'},
{"dead_abovedot", "F", 'Ḟ'},
{"dead_abovedot", "G", 'Ġ'},
{"dead_abovedot", "I", 'İ'},
{"dead_abovedot", "M", 'Ṁ'},
{"dead_abovedot", "P", 'Ṗ'},
{"dead_abovedot", "S", 'Ṡ'},
{"dead_abovedot", "T", 'Ṫ'},
{"dead_abovedot", "X", 'Ẋ'},
{"dead_abovedot", "Z", 'Ż'},
{"dead_acute", "A", 'Á'},
{"dead_acute", "C", 'Ć'},
{"dead_acute", "E", 'É'},
{"dead_acute", "I", 'Í'},
{"dead_acute", "L", 'Ĺ'},
{"dead_acute", "N", 'Ń'},
{"dead_acute", "O", 'Ó'},
{"dead_acute", "R", 'Ŕ'},
{"dead_acute", "S", 'Ś'},
{"dead_acute", "U", 'Ú'},
{"dead_acute", "W", 'Ẃ'},
{"dead_acute", "Y", 'Ý'},
{"dead_acute", "Z", 'Ź'},
{"dead_belowdot", "A", 'Ạ'},
{"dead_belowdot", "E", 'Ẹ'},
{"dead_belowdot", "I", 'Ị'},
{"dead_belowdot", "L", 'Ḷ'},
{"dead_belowdot", "O", 'Ọ'},
{"dead_belowdot", "U", 'Ụ'},
{"dead_belowdot", "Y", 'Ỵ'},
{"dead_breve", "A", 'Ă'},
{"dead_breve", "G", 'Ğ'},
{"dead_breve", "I", 'Ĭ'},
{"dead_breve", "U", 'Ŭ'},
{"dead_caron", "C", 'Č'},
{"dead_caron", "D", 'Ď'},
{"dead_caron", "E", 'Ě'},
{"dead_caron", "G", 'Ǧ'},
{"dead_caron", "L", 'Ľ'},
{"dead_caron", "N", 'Ň'},
{"dead_caron", "O", 'Ǒ'},
{"dead_caron", "R", 'Ř'},
{"dead_caron", "S", 'Š'},
{"dead_caron", "T", 'Ť'},
{"dead_caron", "Z", 'Ž'},
{"dead_cedilla", "C", 'Ç'},
{"dead_cedilla", "G", 'Ģ'},
{"dead_cedilla", "K", 'Ķ'},
{"dead_cedilla", "L", 'Ļ'},
{"dead_cedilla", "N", 'Ņ'},
{"dead_cedilla", "R", 'Ŗ'},
{"dead_cedilla", "S", 'Ş'},
{"dead_cedilla", "T", 'Ţ'},
{"dead_circumflex", "A", 'Â'},
{"dead_circumflex", "C", 'Ĉ'},
{"dead_circumflex", "E", 'Ê'},
{"dead_circumflex", "G", 'Ĝ'},
{"dead_circumflex", "H", 'Ĥ'},
{"dead_circumflex", "I", 'Î'},
{"dead_circumflex", "J", 'Ĵ'},
{"dead_circumflex", "O", 'Ô'},
{"dead_circumflex", "S", 'Ŝ'},
{"dead_circumflex", "U", 'Û'},
{"dead_circumflex", "W", 'Ŵ'},
{"dead_circumflex", "Y", 'Ŷ'},
{"dead_diaeresis", "A", 'Ä'},
{"dead_diaeresis", "E", 'Ë'},
{"dead_diaeresis", "I", 'Ï'},
{"dead_diaeresis", "O", 'Ö'},
{"dead_diaeresis", "U", 'Ü'},
{"dead_diaeresis", "W", 'Ẅ'},
{"dead_diaeresis", "Y", 'Ÿ'},
{"dead_doubleacute", "O", 'Ő'},
{"dead_doubleacute", "U", 'Ű'},
{"dead_grave", "A", 'À'},
{"dead_grave", "E", 'È'},
{"dead_grave", "I", 'Ì'},
{"dead_grave", "O", 'Ò'},
{"dead_grave", "U", 'Ù'},
{"dead_grave", "W", 'Ẁ'},
{"dead_grave", "Y", 'Ỳ'},
{"dead_hook", "A", 'Ả'},
{"dead_hook", "E", 'Ẻ'},
{"dead_hook", "I", 'Ỉ'},
{"dead_hook", "O", 'Ỏ'},
{"dead_hook", "U", 'Ủ'},
{"dead_hook", "Y", 'Ỷ'},
{"dead_horn", "O", 'Ơ'},
{"dead_horn", "T", 'Þ'},
{"dead_horn", "U", 'Ư'},
{"dead_macron", "A", 'Ā'},
{"dead_macron", "E", 'Ē'},
{"dead_macron", "I", 'Ī'},
{"dead_macron", "O", 'Ō'},
{"dead_macron", "U", 'Ū'},
{"dead_ogonek", "A", 'Ą'},
{"dead_ogonek", "E", 'Ę'},
{"dead_ogonek", "I", 'Į'},
{"dead_ogonek", "U", 'Ų'},
{"dead_stroke", "D", 'Đ'},
{"dead_stroke", "H", 'Ħ'},
{"dead_stroke", "L", 'Ł'},
{"dead_stroke", "Z", 'Ƶ'},
{"dead_tilde", "A", 'Ã'},
{"dead_tilde", "E", 'Ẽ'},
{"dead_tilde", "I", 'Ĩ'},
{"dead_tilde", "N", 'Ñ'},
{"dead_tilde", "O", 'Õ'},
{"dead_tilde", "U", 'Ũ'},
{"dead_tilde", "Y", 'Ỹ'},
}
func newChord(keymap *xkb.Keymap, code, level uint32) Chord {
func newChord(keymap *xkb.Keymap, mask, code uint32) Chord{
altGrMask := uint32(1) << keymap.ModGetIndex("Mod5")
ctrlMask := uint32(1) << keymap.ModGetIndex(xkb.ModNameCtrl)
altMask := uint32(1) << keymap.ModGetIndex(xkb.ModNameAlt)
shiftMask := uint32(1) << keymap.ModGetIndex(xkb.ModNameShift)
// TODO support layouts other than 0
mask := keymap.KeyGetMod(code, 0, level)
return Chord{
false,
(mask & altGrMask) != 0,
@ -622,7 +493,6 @@ func newChord(keymap *xkb.Keymap, code, level uint32) Chord {
(mask & altMask) != 0,
(mask & shiftMask) != 0,
int(code) - 8,
level,
}
}
@ -632,26 +502,16 @@ func initKeys(keymap *xkb.Keymap) {
numLevels := keymap.NumLevelsForKey(code, 0)
for level := uint32(0); level < numLevels; level++ {
for _, sym := range keymap.KeyGetSymsByLevel(code, 0, level) {
chord := newChord(keymap, code, level)
chord := newChord(keymap, keymap.KeyGetMod(code, 0, level), code)
for name, s := range linuxXSyms {
if s == sym {
if l, ok := LinuxKeys[name]; !ok || level < l.level {
LinuxKeys[name] = chord
}
LinuxKeys[name] = chord
}
}
name := xkb.KeysymGetName(sym)
if x, ok := XKeys[name]; !ok || level < x.level {
XKeys[name] = chord
}
XKeys[xkb.KeysymGetName(sym)] = chord
}
}
}
super = XKeys["Super_L"].Key
altgr = XKeys["ISO_Level3_Shift"].Key
ctrl = XKeys["Control_L"].Key
alt = XKeys["Alt_L"].Key
shift = XKeys["Shift_L"].Key
}
func getChord(keymap *xkb.Keymap, keysym uint32) Chord {
@ -661,25 +521,10 @@ func getChord(keymap *xkb.Keymap, keysym uint32) Chord {
for level := uint32(0); level < numLevels; level++ {
for _, sym := range keymap.KeyGetSymsByLevel(code, 0, level) {
if sym == keysym {
return newChord(keymap, code, level)
return newChord(keymap, keymap.KeyGetMod(code, 0, level), code)
}
}
}
}
return Chord{}
}
func getDeadChords(keymap *xkb.Keymap, result rune) (Chord, Chord) {
r := unicode.ToUpper(result)
for _, d := range DeadKeyResults {
if d.Result == r {
deadKey := XKeys[d.DeadKey]
key := XKeys[d.Key]
if deadKey.Key != 0 && key.Key != 0 {
key.Shift = d.Result == result
return deadKey, key
}
}
}
return Chord{}, Chord{}
}

View file

@ -1,4 +1,3 @@
#!/bin/sh
rm -vf /usr/local/bin/dotool /usr/local/bin/dotoolc /usr/local/bin/dotoold
rm -vf /etc/udev/rules.d/80-dotool.rules
rm -vf /usr/share/man/man1/dotool.1