You are not logged in.

#1 2017-06-24 23:27:17

Xyne
Administrator/PM
Registered: 2008-08-03
Posts: 6,963
Website

[SOLVED] How to simulate AltGr intl. key combinations with xdotool?

With the AltGr US-International keyboard layout, you can use the right Alt key (AltGr) to type diacritics and special characters, e.g.

"Alt_R+`" followed by "a" yields "à",  "Alt_R+shift+3" followed by "o" yields "ō", etc.

I would like to write a script to simulate different key combinations to systematically discover all allowed combinations. For example, "Alt_R+shift+2" followed by "a" yields nothing, but followed by "o" yields "ő".

I am trying to do this with xdotool but I can't figure it out. I have tried various combinations of key, keydown, keyup with Alt_R, ISO_Level3_Shift, ISO_Level3_Latch and different key presses. I have also tried sending keys reported by xev, such as dead_doubleacute (although that would defeat the purpose of systematically testing key combinations as I would have to know of existing deadkey combinations).

I haven't been able to find any online examples of simulating keypresses to generate diacritic combinations with xdotool. Can anyone help? Please note that I am not looking for a list of all possible combinations of vowels and diacritics (I have already found a table online). I just want to be able to generate such a table automatically, and understand how to type diacritics with AltGr and xdotool.


If anyone wants to test combinations, save the following Bash function (adapted from a StackExchange post):

function relkeys()
{
  local display="${1:-$DISPLAY}"
  sed -nr 's/^#define XK_(\S+?_(L|R|Level\S+))\s.*$/\1/p;' /usr/include/X11/keysymdef.h | DISPLAY="$display" xargs xdotool keyup
}

You can run it from a TTY with the same user as your X sessions to release all key modifiers if they get stuck (and you can't type the required commands because of it). Pass the X display as the first argument, e.g. "relkeys :0" or "relkeys :1". If you can type the command, you can run it from the current X server with no arguments.

Last edited by Xyne (2017-06-25 12:30:32)


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#2 2017-06-25 12:05:45

seth
Member
Registered: 2012-09-03
Posts: 51,046

Re: [SOLVED] How to simulate AltGr intl. key combinations with xdotool?

Don't hold your breath - AltGr is a beast of its own.
xdotool will just use the default map, eg. "xdotool key asciitilde" will result in "]" and "xdotool key backslash" in "-" on a german keyboard where "\" is AltGr+ß (thus "xdotool  key ISO_Level3_Shift+ß" will cause "-" instead of "\" just as much, asciitilde ie "~" is btw. AltGr++)

You'll find the symbol table in /usr/share/X11/xkb/symbols/us

Offline

#3 2017-06-25 12:29:53

Xyne
Administrator/PM
Registered: 2008-08-03
Posts: 6,963
Website

Re: [SOLVED] How to simulate AltGr intl. key combinations with xdotool?

seth wrote:

Don't hold your breath - AltGr is a beast of its own.
xdotool will just use the default map, eg. "xdotool key asciitilde" will result in "]" and "xdotool key backslash" in "-" on a german keyboard where "\" is AltGr+ß (thus "xdotool  key ISO_Level3_Shift+ß" will cause "-" instead of "\" just as much, asciitilde ie "~" is btw. AltGr++)

You'll find the symbol table in /usr/share/X11/xkb/symbols/us

Thanks for the reply. Between the symbol table and understanding that xdotool sends symbols, not key presses, I managed to get it working:

$ xdotool key ISO_Level3_Shift; xdotool key dead_doubleacute; xdotool key o
ő
$ xdotool key ISO_Level3_Shift; xdotool key dead_cedilla; xdotool key c
ç

My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#4 2017-06-25 13:19:36

seth
Member
Registered: 2012-09-03
Posts: 51,046

Re: [SOLVED] How to simulate AltGr intl. key combinations with xdotool?

This works for me only by passing the resulting, final symbol - not by passing the 1st level symbol. Ie. I can

xdotool key ISO_Level3_Shift; xdotool key backslash # \

but not

xdotool key ISO_Level3_Shift; xdotool key ssharp # ß, should be \

Offline

#5 2017-06-25 14:24:56

Xyne
Administrator/PM
Registered: 2008-08-03
Posts: 6,963
Website

Re: [SOLVED] How to simulate AltGr intl. key combinations with xdotool?

I get the same with us-intl:

$ xdotool key ISO_Level3_Shift; xdotool key ssharp
ß

(= AltGr+s)

"ISO_Level3_Shift" is redundant imo if you need to pass the shifted symbol, but oh well.

If anyone wants to play around, here's a script that parses the symbols file and prints out some info about which symbols are attached to different keys. It also generates xdotool commands to test all of the deadkey combinations. Warning: your system may (temporarily?) hang when running thousands of xdotool commands in sequence. Feel free to suggest ways to improve the script.

#!/usr/bin/env python3

import itertools
import re
import subprocess
import shlex

SYMBOLS_FILE = '/usr/share/X11/xkb/symbols/us'
# Select target xkb_symbol maps from the symbols file here.
XKB_SYMBOLS = ('basic', 'euro', 'ibm238l', 'intl', 'altgr-intl')

# Get symbols from e.g. xev.
KEY_SYMBOLS = {
  '_': 'underscore',
  '\n': 'Return',
  '-': 'minus',
  '+': 'plus',
  ' ': 'space'
}

def run_command(cmd, run=False):
  if run:
    subprocess.run(cmd)
  else:
    print(' '.join(shlex.quote(w) for w in cmd))

def type_text(text):
  for c in text:
    try:
      c = KEY_SYMBOLS[c]
    except KeyError:
      pass
    run_command(('xdotool', 'key', c))

def type_deadite(deadite, char, shift=False):
  run_command(('xdotool', 'key', 'ISO_Level3_Shift'))
  run_command(('xdotool', 'key', deadite))
  if shift:
    run_command(('xdotool', 'key', 'shift+{}'.format(char)))
  else:
    run_command(('xdotool', 'key', char))

def key_combo(key, level):
  combo = ''
  if level > 1:
    combo += 'AltGr+'
  if level % 2:
    combo += 'shift+'
  combo += key
  return combo

symbols = dict()
with open (SYMBOLS_FILE, 'r') as f:
  in_xkb_symbols = False
  for line in f:
    m = re.match(r'\s*xkb_symbols\s+"(.+)"', line)
    if m:
      in_xkb_symbols = (m.group(1) in XKB_SYMBOLS)
    elif in_xkb_symbols:
      m = re.match(r'\s*key\s.*?\[([^\]]+)]', line)
      if m:
        ss = tuple(s.strip() for s in m.group(1).split(','))
        symbols[ss[0]] = ss[1:]

keys = set()
deadites = set()
symbols_to_keys = dict()
for a, bcd in sorted(symbols.items()):
  for i, s in enumerate((a,) + bcd):
    if s.startswith('dead_'):
      deadites.add(s)
    else:
      keys.add(s)
    # In case some symbols map to multiple keys.
    if s not in symbols_to_keys:
      symbols_to_keys[s] = (a, i)

keys = sorted(k for k in keys if k)
deadites = sorted(d for d in deadites if d)

for k in keys:
  print('#', k, key_combo(*symbols_to_keys[k]))
for d in deadites:
  print('#', d, key_combo(*symbols_to_keys[d]))

for deadite, symbol in itertools.product(deadites, keys):
  print('#', deadite, symbol)
  type_deadite(deadite, symbol)
  type_text(' {} {}\n'.format(deadite, symbol))

Note that the script is safe to run as-is. You have to save the output to a file and run it as a bash script to execute the xdotool commands. Add a sleep command to the start of the script, then switch to a text editor before it starts "typing".


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

Board footer

Powered by FluxBB