Mapping characters to keycodes for international keysets
Asked Answered
C

4

13

so I built a pi zero keyboard emulator as mentioned here:

https://www.rmedgar.com/blog/using-rpi-zero-as-keyboard-setup-and-device-definition

I make it type text that it reads from a local text-file (everything developed in java - for reasons :) ).
My problem now is that the configured keysets on the various computers my pi zero is attached to differ very much (german, english, french, ...). Depending on the computer this leads to several typing mistakes (e.g., z instead of y).

So I now built some "translation tables" that map characters to the keycodes fitting to the computer. Such a table looks like this:

public scancodes_en_us() {
    //We have (Character, (scancode, modifier))
    table.put("a",Pair.create("4","0"));
    table.put("b",Pair.create("5","0"));
    table.put("c",Pair.create("6","0"));
    table.put("d",Pair.create("7","0"));
    table.put("e",Pair.create("8","0"));
    table.put("f",Pair.create("9","0"));
    table.put("g",Pair.create("10","0"));
    table.put("h",Pair.create("11","0"));
    table.put("i",Pair.create("12","0"));
    table.put("j",Pair.create("13","0"));
    table.put("k",Pair.create("14","0"));
    table.put("l",Pair.create("15","0"));
    table.put("m",Pair.create("16","0"));
    table.put("n",Pair.create("17","0"));
    table.put("o",Pair.create("18","0"));
    table.put("p",Pair.create("19","0"));
    table.put("q",Pair.create("20","0"));
    table.put("r",Pair.create("21","0"));
    table.put("s",Pair.create("22","0"));
    table.put("t",Pair.create("23","0"));
    table.put("u",Pair.create("24","0"));
    table.put("v",Pair.create("25","0"));
    table.put("w",Pair.create("26","0"));
    table.put("x",Pair.create("27","0"));
    table.put("y",Pair.create("28","0"));
    table.put("z",Pair.create("29","0"));
    table.put("A",Pair.create("4","2"));
    table.put("B",Pair.create("5","2"));
    table.put("C",Pair.create("6","2"));
    table.put("D",Pair.create("7","2"));
    table.put("E",Pair.create("8","2"));
    table.put("F",Pair.create("9","2"));
    table.put("G",Pair.create("10","2"));
    table.put("H",Pair.create("11","2"));
    table.put("I",Pair.create("12","2"));
    table.put("J",Pair.create("13","2"));
    table.put("K",Pair.create("14","2"));
    table.put("L",Pair.create("15","2"));
    table.put("M",Pair.create("16","2"));
    table.put("N",Pair.create("17","2"));
    table.put("O",Pair.create("18","2"));
    table.put("P",Pair.create("19","2"));
    table.put("Q",Pair.create("20","2"));
    table.put("R",Pair.create("21","2"));
    table.put("S",Pair.create("22","2"));
    table.put("V",Pair.create("25","2"));
    table.put("W",Pair.create("26","2"));
    table.put("X",Pair.create("27","2"));
    table.put("Y",Pair.create("28","2"));
    table.put("Z",Pair.create("29","2"));
    table.put("1",Pair.create("30","0"));
    table.put("2",Pair.create("31","0"));
    table.put("5",Pair.create("34","0"));
    table.put("6",Pair.create("35","0"));
    table.put("7",Pair.create("36","0"));
    table.put("8",Pair.create("37","0"));
    table.put("9",Pair.create("38","0"));
    table.put("0",Pair.create("39","0"));
    table.put("!",Pair.create("30","2"));
    table.put("@",Pair.create("31","2"));
    table.put("#",Pair.create("32","2"));
    table.put("$",Pair.create("33","2"));
    table.put("%",Pair.create("34","2"));
    table.put("^",Pair.create("35","2"));
    table.put("&",Pair.create("36","2"));
    table.put("*",Pair.create("37","2"));
    table.put("(",Pair.create("38","2"));
    table.put(")",Pair.create("39","2"));
    table.put(" ",Pair.create("44","0"));
    table.put("-",Pair.create("45","0"));
    table.put("=",Pair.create("46","0"));
    table.put("[",Pair.create("47","0"));
    table.put("]",Pair.create("48","0"));
    table.put("\\",Pair.create("49","0"));
    table.put(";",Pair.create("51","0"));
    table.put("'",Pair.create("52","0"));
    table.put("`",Pair.create("53","0"));
    table.put(",",Pair.create("54","0"));
    table.put(".",Pair.create("55","0"));
    table.put("/",Pair.create("56","0"));
    table.put("_",Pair.create("45","2"));
    table.put("+",Pair.create("46","2"));
    table.put("{",Pair.create("47","2"));
    table.put("}",Pair.create("48","2"));
    table.put("|",Pair.create("49","2"));
    table.put(":",Pair.create("51","2"));
    table.put("\"",Pair.create("52","2"));
    table.put("~",Pair.create("53","2"));
    table.put("<",Pair.create("54","2"));
    table.put(">",Pair.create("55","2"));
    table.put("?",Pair.create("56","2"));

Having such a table for many different keyboard layouts is a pain. Is there some more clever version to map a character to the scancode for a specific keyboard layout?

If not - is there some kind of archive where I can find such a character to scancode mapping for many different keyboard layouts?

Thank you very much

Conceptualize answered 7/6, 2018 at 14:56 Comment(1)
Not a direct answer, but Linux, FreeBSD or x11.org (as well as other OS vendors) all have that multiple keyboards problem. Looking in their sources should give you an exhaustive lists of all currently known keyboard. BTW, they are not specific to a locale, for example dvorak is an alternative for standard qwerty layout for the same us-en (or other) locale.Falciform
A
11

Look at how localization works, they all share the same approach: Create a special version for each localization as a property file, then have an abstract class to load the property based on locale.

You will develop a loader class like this:

public scancodes(Locale locale) {
    // load locale property file or download if missing
    // read the property and store to the table
    ResourceBundle scanCodes = ResourceBundle.getBundle("codes",locale);
}

And your codes_locale looks like:

codes_de.properties

a=4,0
b=5,0

By doing this, you separate the locale specific character with your logic code, and you don't need to bundle all keyboards in side your app. You can download them as needed.

You can access a tutorial here

Ascanius answered 20/6, 2018 at 12:41 Comment(0)
H
3

If I understood what you are trying to do correctly then you don't have to map anything at all, just use a pre-made format (like unicode which works for all languages I know of), just send a char code and translate it to it's matching char.

Example file reader - char interpreter:

JFileChooser fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.showOpenDialog(null);

File textFile = fc.getSelectedFile();

if(textFile.getName().endsWith(".txt")) {
    System.out.println(textFile.getAbsolutePath());
    FileInputStream input = new FileInputStream(textFile);
    BufferedReader reader = new BufferedReader(new InputStreamReader(input, "UNICODE"));
    char[] buffer = new char[input.available() / 2 - 1];
    System.out.println("Bytes left: " + input.available());
    int read = reader.read(buffer);
    System.out.println("Read " + read + " characters");
    for(int i = 0; i < read; i++) {
        System.out.print("The letter is: " + buffer[i]);
        System.out.println(", The key code is: " + (int) buffer[i]);
    }
}

you can later use the key code to emulate a key press on your computer

Hirundine answered 24/6, 2018 at 12:42 Comment(0)
M
1

For scan-code mappings you can visit following sites:

  1. Keyboard scancodes
  2. Scan Codes Demystified
Muticous answered 20/6, 2018 at 12:56 Comment(0)
G
1

My solution is to determine the list of keycode on runtime, it'll save you a lot of caffeine and headache

package test;

import java.util.HashMap;
import java.util.Map;

import javax.swing.KeyStroke;

public class Keycode {

    /**
     * List of chars, can be stored in file 
     * @return
     */
    public String getCharsets() {
        return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSVWXYZ12567890!@#$%^&*() -=[]\\;'`,./_+{}|:\\~<>?";
    }

    /**
     * Determines the keycode on runtime
     * @return
     */
    public Map<Character, Integer> getScancode() {
        Map<Character, Integer> table = new HashMap<>();
        String charsets = this.getCharsets();
        for( int index = 0 ; index < charsets.length() ; index++ ) {
            Character currentChar = charsets.charAt(index); 
            KeyStroke keyStroke   = KeyStroke.getKeyStroke(currentChar.charValue(), 0);
            // only for example i've used Map, but you should populate it by your table
            // table.put("a",Pair.create("4","0"));
            table.put(currentChar, keyStroke.getKeyCode());
        }
        return table;
    }

    public static void main(String[] args) {
        System.out.println(new Keycode().getScancode());
    }

}
Gouge answered 20/6, 2018 at 13:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.