[{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eRecently for the Fruitjam-286 emulator, I needed to create a good mapping from USB HID codes to XT codes.\u003c/p\u003e\n\u003cp\u003eThere are many resources online including \u003ca href=\"https://www.scs.stanford.edu/10wi-cs140/pintos/specs/kbd/scancodes-9.html#correspondence\"\u003eKeyboard Scancodes (Andries Brouwer)\u003c/a\u003e which is a nice HTML table.\u003c/p\u003e\n\u003cp\u003eI converted the table into a \u003ca href=\"https://gist.github.com/jepler/674a841d690b91837f8d77cd7312b9af\"\u003ecsv file\u003c/a\u003e, and then used a bespoke Python program to convert it to a format for the emulator.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eFirst, my program opens the csv file and checks its structure\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"import csv\nwith open(\"keymaps.csv\") as f:\n    rows = [[el.strip() for el in row] for row in csv.reader(f)]\n    header = rows[0]\n    del rows[0]\n\nassert header[1] == \"USB\"\nassert header[2] == \"Set 1\"\nassert header[-1] == \"keycap\"","metadata":{"language":"auto","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eIt defines a function to convert an XT keycode sequence like (hex) 49 or (hex) e0-1c into a C string for the \"make\" sequence and a second C string for a \"break\" sequence (the two always differ by setting the 0x80 bit of the last byte, or at least I assumed so).\u003c/p\u003e\n      \n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"code","content":"dq = \"\\\"\"\n\ndef tohexstr(dashed):\n    hexes = [int(x, 16) for x in dashed.split(\"-\")]\n    s1 = dq + \"\".join(f\"\\\\x{x:02x}\" for x in hexes) + dq\n    hexes[-1] |= 0x80\n    s2 = dq + \"\".join(f\"\\\\x{x:02x}\" for x in hexes) + dq\n    return f\"{{ {s1:\u003c16}, {s2:\u003c16} }}\"","metadata":{"language":"auto","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n        \u003cp\u003eThen I just have to print some declarations and then output one line of C code for each row in the table with an associated USB keycode. There's even an untested special-case for the Pause key, which per documentation emits a 6 byte press sequence and no release sequence.\u003c/p\u003e\n      \n\n\n","metadata":{}},{"element_type":"code","content":"print(\"typedef struct { const char *press, const char *release } usb_to_xt;\")\nprint(\"static const usb_to_xt conversion[] = {\")\nfor row in rows:\n    u = int(row[1])\n    if u == 0: continue\n    x = tohexstr(row[2])\n    c = row[-1]\n    if c == \"Pause\":\n        x = '{ \"\\\\xe1\\\\x1d\\\\x45\\\\xe1\\\\x9d\\\\xc5\", \"\"     }'\n\n    print(f\"    [{u:3d}] = {x}, // {c}\")\nprint(\"};\")","metadata":{"language":"auto","linenums":false,"filename":""}},{"element_type":"text","content":"\n  \n  \n  \n  \n        \u003cp\u003eThis same table could be useful as one part of a variety of converters, such as XT-\u0026gt;USB, USB-\u0026gt;PS/2, etc.\u003c/p\u003e\n      \n\n\n\n","metadata":{}},{"element_type":"text","content":"\n        \u003cp\u003eThe resulting table looks something like this. I just pasted it into my source file and made some manual edits there. A better person would have put the csv file \u0026amp; python script under revision control, and arranged to build a C header from the Python script as a part of the build process:\u003c/p\u003e\n      ","metadata":{}},{"element_type":"code","content":"typedef struct { const char *d[2]; } usb_to_xt;\nstatic const usb_to_xt conversion[] = {\n    [ 53] = { \"\\x29\"          , \"\\xa9\"           }, // ` ~\n    [ 30] = { \"\\x02\"          , \"\\x82\"           }, // 1 !\n    [ 31] = { \"\\x03\"          , \"\\x83\"           }, // 2 @\n    [ 32] = { \"\\x04\"          , \"\\x84\"           }, // 3 #\n    [ 33] = { \"\\x05\"          , \"\\x85\"           }, // 4 $\n    [ 34] = { \"\\x06\"          , \"\\x86\"           }, // 5 % E\n    [ 35] = { \"\\x07\"          , \"\\x87\"           }, // 6 ^\n    [ 36] = { \"\\x08\"          , \"\\x88\"           }, // 7 \u0026\n    [ 37] = { \"\\x09\"          , \"\\x89\"           }, // 8 *\n    [ 38] = { \"\\x0a\"          , \"\\x8a\"           }, // 9 (\n    [ 39] = { \"\\x0b\"          , \"\\x8b\"           }, // 0 )\n    [ 45] = { \"\\x0c\"          , \"\\x8c\"           }, // - _\n    [ 46] = { \"\\x0d\"          , \"\\x8d\"           }, // = +\n    [ 42] = { \"\\x0e\"          , \"\\x8e\"           }, // Backspace","metadata":{"language":"auto","linenums":false,"filename":""}}]