0

Update / Note:

If anyone is doing this or something similar, note that it looks like xdotool does some more underlying work. I have not checked the source for how it actually types. But the case is that with with the below procedure one get some quirks. For example:

              setxkbmap ru   no change in kbmap
Кбалта-ABC      Кбалта-abc           Кбалта-ABC

So some is lost when changing kbmap. (Here lower-case for latin ABC)


Original Post:

Is there some existing tool that can detect keyboard layout needed from string?

As in not language, but layout.

The case

I use xdotool to paste text into an application that does not accept paste.

That is: I use xdotool type … on the text in clipboard.

When I paste for example Russian xdotool detects which layout to use and changes this automatically (from the looks of it).

The detection method is very slow though. The longer the text, the worse.

A string of 130 letters for example takes over 30 seconds when layout needs to be changed.


setxkbmap

I have found that changing the keyboard before using xdotool speeds things up to the normal. For this reason I added a simple layout detection method. It is very crude and is set up only to detect the languages I paste in (beside English).

orig_lang=$(setxkbmap -query | awk '/^layout:/{printf $2}')
lang=$(language "$text")

if [ ! -z "$lang" ] && [[ "$lang" != "$cur_lang" ]]; then
    printf "Changing kbmap to %s\n" "$lang" >&2
    setxkbmap $lang
fi
xdotool type --delay 52 "$text"
if [ ! -z "$lang" ]; then
    setxkbmap $orig_lang
fi

``

Where the language function for now is:

language()
{
    local -i found=1
    local lan
    local letters
    local letter
    local -i len
    local -i i
    # Note: AaOoPp etc. in ru is not the same as in English
    local -A dd=(
        [ru]="АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛл†МмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя"
        [no]="ÆØÅæøå"
        [de]="ßüÜäÄÖö"
    )

    [ -z "$1" ] && return 1

    for lan in ${!dd[@]}; do
        letters=${dd[$lan]}
        len=${#letters}
        for (( i = 0; i < len; ++i)); do
            letter="${letters:$i:1}"
            if [ -z "${1##*$letter*}" ]; then
                printf $lan
                found=0
                break 2
            fi
        done
    done
    return $found
}

Alternative?

Is there a better existing alternative for this?

Optionally another tool then xdotool which uses another way of detecting or sending keystrokes?

I have tried guess_language and the like.

Issue is that they are language and not alphabet oriented. As such I get possible false results and single words or short sentences return unknown.

  • Can't thing of a much better alternative, even though I would use your strings in regular expressions (for instance, russian would be something like .*[АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛл†МмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя].*. – xenoid Sep 9 at 22:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.