VOGONS


PCEm. Another PC emulator.

Topic actions

  • This topic is locked. You cannot reply or edit posts.

Reply 480 of 1046, by truth_deleted

User metadata

HalfMinute's suggestion is a good one. I was about to post the same. Output from dosbox and pcem may be generated by the equivalent of printf statements, especially powerful given dosbox works with DOS/V.

I should re-read your posts to see the meaning of the /HS parameter. Also, perhaps there is an internet post about the changes to dosbox (or another emulator) so that DOS/V works. However, I haven't read that another has to boot a disk to start DOS/V: https://sites.google.com/site/csmth96/dosvondosbox.

"I think that's because it uses a 640x475 mode (since it uses a 8x19 font for the single-byte SBCS characters) that PCem doesn't recognize. Therefore, it seems PCem's hardware scrolling doesn't work well in that mode."

Is this video mode implemented by the previously mentioned driver? Do any of the emulators include a line to natively implement this mode?

Reply 481 of 1046, by Battler

User metadata
Rank Member
Rank
Member

Yeah, the floppy-less solution exists too for DOSBox, but it uses some third-party DBCS display driver that isn't well-compatible with things like Windows 3.1 Japanese. And Microsoft's DBCS display driver doesn't work on DOSBox because it needs COUNTRY support which DOSBox still doesn't offer.
Also, /HS controls whether hardware scrolling is used or not, and what mode is using.
As for the 640x475 mode, it's pretty much implemented on top of VGA's 640x480 mode, and in a way that is compatible with any graphics adapter following at least the VGA standard. And evidentely, whatever hardware scrolling mode JDISP.SYS uses by default, is I guess not well-documented and therefore apparently not supported by anything other than real graphics cards, DOSBox, Virtual PC, and VMWare Workstation 7 and higher.

Also, while I'm already fixing bugs in PCem, I decided to rewrite the Windows keyboard handler too. Not only it used DirectInput which Microsoft themselves advise against use it because it, as I confirmed with my own testing too, epicly fails on all non-US keyboards and keyboard layouts, but it also used it incorrectly (converting DIK_ key codes to scan codes with a lookup table, when DIK_ key codes are already scan codes). I rewrote it using GetKeyState and MapVirtualKey, which now causes non-US keys such as the one after left Shift (scan code 0x56) to get passed properly, but it still epicly fails on non-US keyboard layouts - when I switch to Japanese keyboard layout in Windows, PCem (but Virtual PC too!) sees the keys all wrong, the Yen key (scan code 0x7D) comes into PCem as 0x2B (regular backslash key). I need to see if win-keyboard.cc can be rewritten even further, to use the raw input Windows messages, so I can then have it just pass the raw scan codes to the emulated machine. That should then fix all the problems.
However, Microsoft are the ones to blame for the keyboard mess, since the Windows keyboard API set is just bad.

Reply 484 of 1046, by Battler

User metadata
Rank Member
Rank
Member

Well, I'd say Microsoft's own DOS/V drivers are the standard in this case. The only problem is, we obviously doesn't have the source code of Microsoft's JDISP.SYS. If we did, everything would be much simpler, since we'd just need to look there to see what it does.

Reply 485 of 1046, by Battler

User metadata
Rank Member
Rank
Member
HalfMinute wrote:

PcEm is compiled to use ASCII layout. You may try to either compile it with UNICODE define, or switch to DIrectInput8 and pass IID_IDirectInput8W as parameter in DIrectInput8Create function.
msdn.microsoft.com/en-us/library/window ... s.85).aspx

Where do I change the ASCII/UNICODE define?

Edit: Nevermind. I now managed to make PCem listen to the windows WM_INPUT message for raw keyboard input and use that. Works like a charm. But alas, this completely bypassed Windows key remappings too (the ones done with a certain Registry key, that is), so I need to look into reading the Registry in C so I can read the relevant key myself and remap accordingly. Also, for some reason I now get a DirectInput-related crash if I enable the mouse stuff, so I am keeping that disabled until I can fix it.
Or maybe I could add a config setting for key remapping.

Still looking into the S3 Trio64 problems too. Any 32-bit color render is screwed up, even in low resolutions, and it insists at reporting 2 MB of its own memory even though the CRTC is patched to the 4 MB value in the relevant init procedure to the correct option. So time to find what all can affect that. It reports 2 MB video RAM even in a ROM I specifically patched to write in the 4 MB RAM value into the CRTC (something I originally did for Virtual PC 2007 but is coming in useful here too).

And of course, the investigation in what causes DOS/V to black-screen and freeze is on-going too.

Reply 486 of 1046, by Windows95Fan

User metadata
Rank Newbie
Rank
Newbie

I got the virtual Tseng Labs ET4000AX to work in true color mode by opening the vid_unk_ramdac.c file and replacing the following lines:

case 0: case 1: case 2: case 3:
svga->bpp = 8;
break;
case 6: case 7:
svga->bpp = 24;
break;
case 8: case 9: case 0xA: case 0xB:
svga->bpp = 15;
break;
case 0xC: case 0xD: case 0xE: case 0xF:
svga->bpp = 16;
break;

by these ones:

case 0: case 1: case 2: case 3:
svga->bpp = 8;
break;
case 6: case 7:
svga->bpp = 15;
break;
case 8: case 9: case 0xA: case 0xB:
svga->bpp = 16;
break;
case 0xC: case 0xD: case 0xE: case 0xF:
svga->bpp = 24;
break;

Reply 487 of 1046, by Battler

User metadata
Rank Member
Rank
Member

Keyboard handling rewrite is done, it even respects the mapping at "ScanCode" at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout now, and I also made it pass on scan codes 0xF1 (make, no break) and 0xF2 (make, no break) correctly (these are the Hancha and HanYong keys found on Korean keyboards). Now the OS inside PCem sees all keys correctly. Now I need to get mouse working again.

Still working on the two video problems, though.

Reply 489 of 1046, by Windows95Fan

User metadata
Rank Newbie
Rank
Newbie
SarahWalker wrote:
Windows95Fan wrote:

I got the virtual Tseng Labs ET4000AX to work in true color mode by opening the vid_unk_ramdac.c file and replacing the following lines:

Yes, but do you know what RAMDAC it's now emulating?

According to the first three lines of the vid_unk_ramdac.c file:

/*It is unknown exactly what RAMDAC this is
It is possibly a Sierra 1502x
It's addressed by the TLIVESA1 driver for ET4000*/

Reply 491 of 1046, by Battler

User metadata
Rank Member
Rank
Member

Forked out the S3 Trio64 a bit, now there's 3 of them:
- 9FX Vision Trio64: 9FX BIOS, 1 MB VRAM, identifies as Trio64;
- Phoenix S3 Trio64: Phoenix Trio64 BIOS, 4 MB VRAM, identifies as Trio64;
- Phoenix S3 Trio32: Phoenix Trio32 BIOS, 2 MB VRAM, identifies as Trio32.
Now to get back to fixing the 32-bit color mode renderer for the Trio. I am comparing the PCem Trio source code with DOSBox's to see where they differ. Will do the same with generic VGA to see why DOS/V on PCem puts PCem into 320x480(!) mode and freezes, while works fine in DOSBox.

Reply 492 of 1046, by SarahWalker

User metadata
Rank Member
Rank
Member
Windows95Fan wrote:
According to the first three lines of the vid_unk_ramdac.c file: […]
Show full quote

According to the first three lines of the vid_unk_ramdac.c file:

/*It is unknown exactly what RAMDAC this is
It is possibly a Sierra 1502x
It's addressed by the TLIVESA1 driver for ET4000*/

Yes, but can you confirm this? Those notes are merely me guessing.

Reply 493 of 1046, by Battler

User metadata
Rank Member
Rank
Member

Whew, did more work on the keyboard handling. Made all known escaped keys (those beginning with E0) sent, and even devised a way to disambiguate eg. E0 71 from F1 and E0 F1, and so on. Also noticed it was incorrectly passing E0 8A as the break code of E0 2A (fake shift issued by some keys) instead of the correct E0 AA, so I just fixed that.

Still haven't figured out a solution to the two video problems, but I'm working on that.

Reply 495 of 1046, by Battler

User metadata
Rank Member
Rank
Member

This is it: http://goput.it/v/hmmf.png . Colors are completely screwed up, and fonts aren't rendering correctly.

Also, found another bug, on all video adapters - in some 256-color modes, only the top quarter of the screen is rendered. This is an example: http://goput.it/v/6782.png .

Reply 496 of 1046, by SarahWalker

User metadata
Rank Member
Rank
Member

In the top quarter issue, could you tell me what is running so I have a chance of reproducing it?

In fact, as a general request to everyone, could bug reports please come with as much detail as possible? What program triggers the issue (what version if possible), what OS is running, what drivers (eg in this case VESA driver looks relevant), what system configuration in the emulator, what version of the emulator (normal release, or what revision off the source repo, or something you've been hacking with).

Reply 497 of 1046, by Battler

User metadata
Rank Member
Rank
Member

- SarahWalker: About the top quarter issue, what's running it Little Big Adventure 2, a game from 1997 for DOS and Windows 95, this is specifically the DOS version running that uses DOS4GW. The OS is MS-DOS 6.00. System Configuration: Award VX430 with WinChip 240. S3 Trio64 card (but the problem also happens with any other card, such as ATI Mach). PCem version 8.1 latest revision.

Reply 498 of 1046, by Battler

User metadata
Rank Member
Rank
Member

By the way, this is the changes I did to the keyboard handling:

  • In WIN.C:
    • I added this:
      #define  _WIN32_WINNT 0x0501
      In the very beginning.
    • Near the beginning, I also added this:
      RAWINPUTDEVICE device;
    • I added these two procedures before WinMain:
      UINT16 convert_scan_code(UINT16 scan_code) {
      switch(scan_code) {
      // This is so we can disambiguate scan codes that would otherwise conflict and get passed on incorrectly.
      case 0xE001:
      return 0xF001;
      case 0xE002:
      return 0xF002;
      case 0xE005:
      return 0xF005;
      case 0xE006:
      return 0xF006;
      case 0xE007:
      return 0xF007;
      case 0xE071:
      return 0xF008;
      case 0xE072:
      return 0xF009;
      case 0xE07F:
      return 0xF00A;
      case 0xE0E1:
      return 0xF00B;
      case 0xE0EE:
      return 0xF00C;
      case 0xE0F1:
      return 0xF00D;
      case 0xE0FE:
      return 0xF00E;
      case 0xE0EF:
      return 0xF00F;
      default:
      return scan_code;
      }
      }

      void get_registry_key_map() {
      char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout";
      char *valueName = "Scancode Map";
      char *buf = malloc(32768);
      LPDWORD bufSize;
      HKEY hKey;
      int j = 0;
      int k = 0;
      int l = 0;
      int m = 0;
      UINT16 *bufEx;
      UINT32 *bufEx2;

      pclog("Preparing unaltered scan code map list... ");
      for (j = 0; j < 65536; j++) {
      ScanCodeMap[j] = convert_scan_code(j);
      }
      pclog("done!\n");

      bufSize = (LPDWORD) malloc(4);
      *bufSize = 32768;
      pclog("Preparing scan code map list...\n");
      if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) {
      if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, bufSize) == ERROR_SUCCESS) {
      bufEx2 = (UINT32 *) buf;
      scMapCount = bufEx2[2];
      Show last 19 lines
      			pclog("%lu scan code mappings found!\n", scMapCount);
      if ((bufSize != 0) && (scMapCount != 0)) {
      pclog("More than zero scan code mappings found, processing...\n");
      bufEx = (UINT16 *) (buf + 12);
      for (j = 0; j < scMapCount; j++) {
      k = j * 2;
      l = bufEx[k + 1];
      m = bufEx[k];
      m = convert_scan_code(m);
      ScanCodeMap[l] = m;
      pclog("Scan code mapping %u detected: %X -> %X\n", j, l, ScanCodeMap[l]);
      }
      pclog("Done processing!\n");
      }
      }
      RegCloseKey(hKey);
      }
      pclog("Done preparing!\n");
      }
    • Changed this:
              /* Make the window visible on the screen */
      ShowWindow (hwnd, nFunsterStil);

      // win_set_window(hwnd);

      ghwnd=hwnd;
      To this:
              /* Make the window visible on the screen */
      ShowWindow (hwnd, nFunsterStil);

      // win_set_window(hwnd);
      memset(rawinputkey, 0, sizeof(rawinputkey));
      device.usUsagePage = 0x01;
      device.usUsage = 0x06;
      device.dwFlags = RIDEV_NOLEGACY;
      device.hwndTarget = hwnd;
      e = RegisterRawInputDevices(&device, 1, sizeof(device));
      if (e)
      pclog("Raw input registered!\n");
      else
      pclog("Raw input registration failed!\n");

      get_registry_key_map();

      ghwnd=hwnd;
    • In WindowProcedure, I first added this:
      	int c, d, e, f, g;
      char buffer[sizeof(RAWINPUT)] = {};
      UINT size = sizeof(RAWINPUT);
      char *tempmsg = (char *) malloc(256);
      in the beginning.
      Then, I added this:
      		case WM_INPUT:
      GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, buffer, &size, sizeof(RAWINPUTHEADER));

      RAWINPUT* raw = (RAWINPUT*)(buffer);
      if (raw->header.dwType == RIM_TYPEKEYBOARD)
      {
      const RAWKEYBOARD rawKB = raw->data.keyboard;

      c = rawKB.MakeCode;
      d = rawKB.VKey;
      e = rawKB.Flags;
      pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e);

      if (d == VK_SHIFT)
      {
      d = MapVirtualKeyW(c, 3);
      }
      else if (d == VK_NUMLOCK)
      {
      c = (MapVirtualKey(d, 0) | 0x100);
      }
      if (!(e & 4)) {
      if (!(e & 1)) f = 0x80;
      if (e & 1) f = 0;
      if (e & 2) c |= 0xE000;
      c = ScanCodeMap[c];
      g = c & 0xFF00;
      if (g == 0xF000)
      c |= 0x100;
      else if (g == 0xE000)
      c |= 0x80;
      c &= 0x1FF;
      g &= 0xF00;
      if (!g) rawinputkey[c] = f;
      }
      }
      break;
      Before the case WM_SETFOCUS .
  • Changed WIN_KEYBOARD.CC to:
    #define UNICODE
    #include <stdio.h>
    #include <string.h>
    #include <stdint.h>
    #define BITMAP WINDOWS_BITMAP
    #undef BITMAP
    #include "plat-keyboard.h"
    #include "win.h"
    #include "video.h"

    extern "C" int key[272];

    extern "C" void fatal(const char *format, ...);
    extern "C" void pclog(const char *format, ...);

    extern "C" void keyboard_init();
    extern "C" void keyboard_close();
    extern "C" void keyboard_poll();

    LPDIRECTINPUT lpdi = NULL;
    LPDIRECTINPUTDEVICE lpdi_key = NULL;

    void keyboard_init()
    {
    atexit(keyboard_close);

    memset(key, 0, sizeof(key));
    pclog("Keyboard initialized!\n");
    }

    void keyboard_close()
    {
    }

    void keyboard_poll_host()
    {
    int c, d, e, f;
    pclog("Keyboard polling started!\n");

    for (c = 0; c < 272; c++) {
    key[c] = rawinputkey[c];
    if (key[c]) pclog("Key down %i %02X\n", c, c);
    }

    pclog("Keyboard polling ended!\n");
    }
  • PLAT_KEYBOARD.C now looks like this:
    #ifdef __cplusplus
    extern "C" {
    #endif
    void keyboard_init();
    void keyboard_close();
    void keyboard_poll_host();
    int key[272];
    int rawinputkey[272];
    int scMapCount;
    // This is for easier searching
    unsigned short int ScanCodeMap[65536];

    #define KEY_LCONTROL 0x1d
    #define KEY_RCONTROL (0x1d | 0x80)
    #define KEY_END (0x4f | 0x80)
    #ifdef __cplusplus
    }
    #endif
  • In WIN_MOUSE.CC, added this:
    #define DIRECTINPUT_VERSION	0x0800
    in the beginning, and this:
            if (FAILED(DirectInput8Create(hinstance, (DWORD) DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID *) &lpdi, NULL)))
    fatal("install_keyboard : DirectInput8Create failed\n");
    Before:
            if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL)))
    fatal("mouse_init : CreateDevice failed\n");
  • KEYBOARD.C now looks like this:
    #include "ibm.h"
    #include "plat-keyboard.h"
    #include "keyboard.h"

    int keybsendcallback = 0;

    typedef struct
    {
    int scancodes_make[8];
    int scancodes_break[8];
    } scancode;

    // 272 = 256 + 16 fake interim scan-codes for disambiguation purposes.
    // Note: I also changed all instances of E0 8A as break code of E0 2A (fake shift) to the correct E0 AA.
    static scancode scancode_set1[272] =
    {
    { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
    { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
    { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
    { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
    { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
    { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
    { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
    { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
    { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
    { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
    { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
    { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
    { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
    { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
    { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
    { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
    { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
    { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
    { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
    { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
    { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
    { {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} },
    { {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} },
    { {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} },
    { {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} },
    { {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} },
    { {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} },
    { {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} },
    { {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} },
    { {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} },
    { {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} },
    { {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} },

    { {0x80, -1}, {-1} }, { {0x81, -1}, {-1} }, { {0x82, -1}, {-1} }, { {0xe0, 0x03, -1}, {0xe0, 0x83, -1} }, /*80*/
    { {0xe0, 0x04, -1}, {0xe0, 0x84, -1} }, { {0x85, -1}, {-1} }, { {0x86, -1}, {-1} }, { {0x87, -1}, {-1} }, /*84*/
    { {0xe0, 0x08, -1}, {0xe0, 0x88, -1} }, { {0xe0, 0x09, -1}, {0xe0, 0x89, -1} }, { {0xe0, 0x0a, -1}, {0xe0, 0x8a, -1} }, { {0xe0, 0x0b, -1}, {0xe0, 0x8b, -1} }, /*88*/
    { {0xe0, 0x0c, -1}, {0xe0, 0x8c, -1} }, { {-1}, {-1} }, { {0xe0, 0x0e, -1}, {0xe0, 0x8e, -1} }, { {0xe0, 0x0f, -1}, {0xe0, 0x8f, -1} }, /*8c*/
    { {0xe0, 0x10, -1}, {0xe0, 0x90, -1} }, { {0xe0, 0x11, -1}, {0xe0, 0x91, -1} }, { {0xe0, 0x12, -1}, {0xe0, 0x92, -1} }, { {0xe0, 0x13, -1}, {0xe0, 0x93, -1} }, /*90*/
    { {0xe0, 0x14, -1}, {0xe0, 0x94, -1} }, { {0xe0, 0x15, -1}, {0xe0, 0x95, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0x96, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0x97, -1} }, /*94*/
    { {0xe0, 0x18, -1}, {0xe0, 0x98, -1} }, { {0xe0, 0x19, -1}, {0xe0, 0x99, -1} }, { {0xe0, 0x1a, -1}, {0xe0, 0x9a, -1} }, { {0xe0, 0x1b, -1}, {0xe0, 0x9b, -1} }, /*98*/
    { {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {0xe0, 0x1e, -1}, {0xe0, 0x9e, -1} }, { {0xe0, 0x1f, -1}, {0xe0, 0x9f, -1} }, /*9c*/
    { {0xe0, 0x20, -1}, {0xe0, 0xa0, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xa1, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xa2, -1} }, { {0xe0, 0x23, -1}, {0xe0, 0xa3, -1} }, /*a0*/
    { {0xe0, 0x24, -1}, {0xe0, 0xa4, -1} }, { {0xe0, 0x25, -1}, {0xe0, 0xa5, -1} }, { {0xe0, 0x26, -1}, {0xe0, 0xa6, -1} }, { {-1}, {-1} }, /*a4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x2a, -1}, {0xe0, 0xaa, -1} }, { {-1}, {-1} }, /*a8*/
    Show last 234 lines
            { {0xe0, 0x2c, -1}, {0xe0, 0xac, -1} }, { {0xe0, 0x2d, -1}, {0xe0, 0xad, -1} }, { {0xe0, 0x2e, -1}, {0xe0, 0xae, -1} }, { {0xe0, 0x2f, -1}, {0xe0, 0xaf, -1} }, /*ac*/
    { {0xe0, 0x30, -1}, {0xe0, 0xb0, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xb1, -1} }, { {0xe0, 0x32, -1}, {0xe0, 0xb2, -1} }, { {-1}, {-1} }, /*b0*/
    { {0xe0, 0x34, -1}, {0xe0, 0xb4, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xb6, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/
    { {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1}, {-1} }, { {0xe0, 0x3a, -1}, {0xe0, 0xba, -1} }, { {0xe0, 0x3b, -1}, {0xe0, 0xbb, -1} }, /*b8*/
    { {0xe0, 0x3c, -1}, {0xe0, 0xbc, -1} }, { {0xe0, 0x3d, -1}, {0xe0, 0xbd, -1} }, { {0xe0, 0x3e, -1}, {0xe0, 0xbe, -1} }, { {0xe0, 0x3f, -1}, {0xe0, 0xbf, -1} }, /*bc*/
    { {0xe0, 0x40, -1}, {0xe0, 0xc0, -1} }, { {0xe0, 0x41, -1}, {0xe0, 0xc1, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xc2, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xc3, -1} }, /*c0*/
    { {0xe0, 0x44, -1}, {0xe0, 0xc4, -1} }, { {-1}, {-1} }, { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0x47, -1}, {0xe0, 0xc7, -1} }, /*c4*/
    { {0xe0, 0x48, -1}, {0xe0, 0xc8, -1} }, { {0xe0, 0x49, -1}, {0xe0, 0xc9, -1} }, { {-1}, {-1} }, { {0xe0, 0x4b, -1}, {0xe0, 0xcb, -1} }, /*c8*/
    { {0xe0, 0x4c, -1}, {0xe0, 0xcc, -1} }, { {0xe0, 0x4d, -1}, {0xe0, 0xcd, -1} }, { {0xe0, 0x4e, -1}, {0xe0, 0xce, -1} }, { {0xe0, 0x4f, -1}, {0xe0, 0xcf, -1} }, /*cc*/
    { {0xe0, 0x50, -1}, {0xe0, 0xd0, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xd1, -1} }, { {0xe0, 0x52, -1}, {0xe0, 0xd2, -1} }, { {0xe0, 0x53, -1}, {0xe0, 0xd3, -1} }, /*d0*/
    { {0xd4, -1}, {-1} }, { {0xe0, 0x55, -1}, {0xe0, 0xd5, -1} }, { {-1}, {-1} }, { {0xe0, 0x57, -1}, {0xe0, 0xd7, -1} }, /*d4*/
    { {0xe0, 0x58, -1}, {0xe0, 0xd8, -1} }, { {0xe0, 0x59, -1}, {0xe0, 0xd9, -1} }, { {0xe0, 0x5a, -1}, {0xe0, 0xaa, -1} }, { {0xe0, 0x5b, -1}, {0xe0, 0xdb, -1} }, /*d8*/
    { {0xe0, 0x5c, -1}, {0xe0, 0xdc, -1} }, { {0xe0, 0x5d, -1}, {0xe0, 0xdd, -1} }, { {0xe0, 0x5e, -1}, {0xe0, 0xee, -1} }, { {0xe0, 0x5f, -1}, {0xe0, 0xdf, -1} }, /*dc*/
    { {-1}, {-1} }, { {0xe0, 0x61, -1}, {0xe0, 0xe1, -1} }, { {0xe0, 0x62, -1}, {0xe0, 0xe2, -1} }, { {0xe0, 0x63, -1}, {0xe0, 0xe3, -1} }, /*e0*/
    { {0xe0, 0x64, -1}, {0xe0, 0xe4, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xe5, -1} }, { {0xe0, 0x66, -1}, {0xe0, 0xe6, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xe7, -1} }, /*e4*/
    { {0xe0, 0x68, -1}, {0xe0, 0xe8, -1} }, { {0xe0, 0x69, -1}, {0xe0, 0xe9, -1} }, { {0xe0, 0x6a, -1}, {0xe0, 0xea, -1} }, { {0xe0, 0x6b, -1}, {0xe0, 0xeb, -1} }, /*e8*/
    { {0xe0, 0x6c, -1}, {0xe0, 0xec, -1} }, { {0xe0, 0x6d, -1}, {0xe0, 0xed, -1} }, { {0xe0, 0x6e, -1}, {0xe0, 0xee, -1} }, { {-1}, {-1} }, /*ec*/
    { {0xe0, 0x70, -1}, {0xe0, 0xf0, -1} }, { {0xf1, -1}, {-1} }, { {0xf2, -1}, {-1} }, { {0xe0, 0x73, -1}, {0xe0, 0xf3, -1} }, /*f0*/
    { {0xe0, 0x74, -1}, {0xe0, 0xf4, -1} }, { {0xe0, 0x75, -1}, {0xe0, 0xf5, -1} }, { {-1}, {-1} }, { {0xe0, 0x77, -1}, {0xe0, 0xf7, -1} }, /*f4*/
    { {0xe0, 0x78, -1}, {0xe0, 0xf8, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xf9, -1} }, { {0xe0, 0x7a, -1}, {0xe0, 0xfa, -1} }, { {0xe0, 0x7b, -1}, {0xe0, 0xfb, -1} }, /*f8*/
    { {0xe0, 0x7c, -1}, {0xe0, 0xfc, -1} }, { {0xe0, 0x7d, -1}, {0xe0, 0xfd, -1} }, { {0xe0, 0x7e, -1}, {0xe0, 0xfe, -1} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, -1}, {-1} }, /*fc*/
    { {-1}, {-1} }, { {0xe0, 0x01, -1}, {0xe0, 0x81, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0x82, -1} }, { {-1}, {-1} }, /*100*/
    { {-1}, {-1} }, { {0xe0, 0x05, -1}, {0xe0, 0x85, -1} }, { {0xe0, 0x06, -1}, {0xe0, 0x86, -1} }, { {0xe0, 0x07, -1}, {0xe0, 0x87, -1} }, /*104*/
    { {0xe0, 0x71, -1}, {0xe0, 0xf1, -1} }, { {0xe0, 0x72, -1}, {0xe0, 0xf2, -1} }, { {0xe0, 0x7f, -1}, {0xe0, 0xff, -1} }, { {0xe0, 0xe1, -1}, {-1} }, /*108*/
    { {0xe0, 0xee, -1}, {-1} }, { {0xe0, 0xf1, -1}, {-1} }, { {0xe0, 0xfe, -1}, {-1} }, { {0xe0, 0xff, -1}, {-1} } /*10c*/
    };

    /*XT keyboard has no escape scancodes, and no scancodes beyond 53*/
    static scancode scancode_xt[272] =
    {
    { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
    { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
    { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
    { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
    { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
    { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
    { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
    { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
    { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
    { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
    { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} },
    { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
    { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
    { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
    { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
    { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
    { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
    { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
    { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
    { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
    { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} },
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/

    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
    { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0xaa, -1} }, { {-1}, {-1} }, /*a8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
    { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/
    { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/
    { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*c8*/
    { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/
    { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*100*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*104*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*108*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/
    };

    /*Tandy keyboard has slightly different scancodes to XT*/
    static scancode scancode_tandy[272] =
    {
    { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} },
    { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} },
    { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} },
    { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} },
    { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} },
    { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} },
    { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} },
    { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} },
    { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} },
    { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} },
    { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} },
    { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} },
    { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} },
    { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} },
    { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} },
    { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} },
    { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} },
    { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} },
    { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} },
    { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} },
    { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} },
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/

    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/
    { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0xaa, -1} }, { {-1}, {-1} }, /*a8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/
    { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/
    { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/
    { {0x29, -1}, {0xa9, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x2b, -1}, {0xab, -1} }, /*c8*/
    { {-1}, {-1} }, { {0x4e, -1}, {0xce, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/
    { {0x4a, -1}, {0xca, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*100*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*104*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*108*/
    { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/
    };
    static int oldkey[272];
    static int keydelay[272];

    void (*keyboard_send)(uint8_t val);
    void (*keyboard_poll)();
    int keyboard_scan = 1;

    void keyboard_process()
    {
    int c;
    int d;
    scancode *scancodes = (AT) ? scancode_set1 : scancode_xt;
    if (!keyboard_scan) return;
    if (TANDY) scancodes = scancode_tandy;

    for (c = 0; c < 272; c++)
    {
    if (key[c]) keydelay[c]++;
    else keydelay[c] = 0;
    }

    for (c = 0; c < 272; c++)
    {
    if (key[c] != oldkey[c])
    {
    oldkey[c] = key[c];
    if ( key[c] && scancodes[c].scancodes_make[0] == -1)
    continue;
    if (!key[c] && scancodes[c].scancodes_break[0] == -1)
    continue;
    // pclog("Key %02X start\n", c);
    d = 0;
    if (key[c])
    {
    while (scancodes[c].scancodes_make[d] != -1)
    keyboard_send(scancodes[c].scancodes_make[d++]);
    }
    else
    {
    while (scancodes[c].scancodes_break[d] != -1)
    keyboard_send(scancodes[c].scancodes_break[d++]);
    }
    }
    }

    for (c = 0; c < 272; c++)
    {
    if (keydelay[c] >= 30)
    {
    keydelay[c] -= 10;
    if (scancode_set1[c].scancodes_make[0] == -1)
    continue;

    d = 0;

    while (scancode_set1[c].scancodes_make[d] != -1)
    keyboard_send(scancode_set1[c].scancodes_make[d++]);
    }
    }
    }

Yes, it may look strange that I made it process 272 possible scan codes, but I'm using key states 0x100 to 0x10F to disambiguate some escaped codes from conflicting scan codes (eg. E0 71 from F1 and E0 F1).