singrdk/base/Drivers/LegacyKeyboard/LegacyKeyboard.sg

804 lines
31 KiB
Plaintext
Raw Permalink Normal View History

2008-03-05 09:52:00 -05:00
///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: LegacyKeyboard.cs
//
// Note:
// /pnp/PNP0303: A0=IO:0060[1] A1=IO:0064[1] A2=IRQ:01
//
// Useful refs:
// http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/keyboard/atkeyboard.html
// http://members.tripod.com/~oldboard/assembly/keyboard_commands.html
// http://members.tripod.com/~oldboard/assembly/8042.html
//
//#define DEBUG_DISPATCH_IO
//#define DEBUG_IO
using System;
using System.Text;
using System.Threading;
using System.Runtime.CompilerServices; //StructAlign attribute
using System.Runtime.InteropServices; //structLayout attribute
using System.GCs;
using Microsoft.SingSharp;
2008-11-17 18:29:00 -05:00
using Microsoft.SingSharp.Reflection;
2008-03-05 09:52:00 -05:00
using Microsoft.Singularity;
using Microsoft.Singularity.Channels;
using Microsoft.Singularity.Extending;
using Microsoft.Singularity.Directory;
using Microsoft.Singularity.Io;
using Microsoft.Singularity.Io.Keyboard;
using Microsoft.Singularity.Configuration;
using Microsoft.Singularity.V1.Services;
using Microsoft.Singularity.V1.Threads;
2008-11-17 18:29:00 -05:00
using Microsoft.Singularity.Drivers;
[assembly: Transform(typeof(DriverResourceTransform))]
2008-03-05 09:52:00 -05:00
namespace Microsoft.Singularity.Drivers.LegacyKeyboard
{
// Should also support PNP0F13: PS/2 Mouse
// [Signature("/pnp/PNP0F13")]
// [IoIrqRange(0, Default = 0x0c)]
// [Follows("/pnp/PNP0303")]
2008-11-17 18:29:00 -05:00
// create the resource object for CTR to fill in
2008-03-05 09:52:00 -05:00
[DriverCategory]
[Signature("/pnp/PNP0303")]
internal class KeyboardResources : DriverCategoryDeclaration
{
[IoPortRange(0, Default = 0x0060, Length = 0x01)]
2008-11-17 18:29:00 -05:00
internal readonly IoPortRange keyboard;
2008-03-05 09:52:00 -05:00
[IoPortRange(1, Default = 0x0064, Length = 0x01)]
2008-11-17 18:29:00 -05:00
internal readonly IoPortRange controller;
2008-03-05 09:52:00 -05:00
[IoIrqRange(2, Default = 0x01)]
2008-11-17 18:29:00 -05:00
internal readonly IoIrqRange irq;
2008-03-05 09:52:00 -05:00
[ExtensionEndpoint]
internal TRef<ExtensionContract.Exp:Start> ec;
[ServiceEndpoint(typeof(KeyboardDeviceContract))]
internal TRef<ServiceProviderContract.Exp:Start> kbdsp;
2008-11-17 18:29:00 -05:00
internal int DriverMain(string instance) {
return KeyboardControl.DriverMain(this);
2008-03-05 09:52:00 -05:00
}
}
public class KeyboardControl
{
private static Keyboard8042 device;
2008-11-17 18:29:00 -05:00
internal static int DriverMain(KeyboardResources! resources)
2008-03-05 09:52:00 -05:00
{
// Create the device.
2008-11-17 18:29:00 -05:00
device = new Keyboard8042(resources);
2008-03-05 09:52:00 -05:00
if (!device.Initialize()) {
return 1;
}
// get the endpoints and set up the main switch receive
2008-11-17 18:29:00 -05:00
ExtensionContract.Exp ec = resources.ec.Acquire();
ServiceProviderContract.Exp sp = resources.kbdsp.Acquire();
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Audit, "Registered");
ec.SendSuccess();
try {
for (bool run = true; run;) {
switch receive {
// Listen for new connections
case sp.Connect(candidate):
KeyboardDeviceContract.Exp newClient = candidate as KeyboardDeviceContract.Exp;
2008-11-17 18:29:00 -05:00
if (newClient == null) {
Tracing.Log(Tracing.Debug, "Keyboard driver rejected connect with wrong endpoint type.");
sp.SendNackConnect(candidate);
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
else if (KeyboardChannel.InstanceCount >= 1) {
Tracing.Log(Tracing.Debug, "Keyboard driver rejected connect as already connected.");
2008-03-05 09:52:00 -05:00
sp.SendNackConnect(candidate);
}
2008-11-17 18:29:00 -05:00
else {
KeyboardChannel.CreateThread(device, newClient);
sp.SendAckConnect();
}
2008-03-05 09:52:00 -05:00
break;
// Listen for extension parent
case ec.Shutdown():
ec.SendAckShutdown();
run = false;
break;
case sp.ChannelClosed():
Tracing.Log(Tracing.Debug, "Keyboard driver no longer needed.");
run = false;
break;
}
}
}
finally {
delete sp;
Tracing.Log(Tracing.Debug, "Keyboard finished message pump.");
}
// Close the device
device.Finalize();
Tracing.Log(Tracing.Audit, "Shutdown");
delete ec;
return 0;
}
}
//////////////////////////////////////////////////////////////////////////
//
// This worker thread processes incoming play requests.
//
2008-11-17 18:29:00 -05:00
// A single instance of this class is allowed to run at any given point
// in time.
2008-03-05 09:52:00 -05:00
public class KeyboardChannel
{
2008-11-17 18:29:00 -05:00
private static int instanceCount = 0;
private static object instanceLock = new object();
2008-03-05 09:52:00 -05:00
private TRef<KeyboardDeviceContract.Exp:Start> epStart;
private Keyboard8042! device;
2008-11-17 18:29:00 -05:00
public static int InstanceCount
{
get {
lock (instanceLock) {
return instanceCount;
}
}
}
2008-03-05 09:52:00 -05:00
public static void CreateThread(Keyboard8042! device,
[Claims] KeyboardDeviceContract.Exp:Start! ep)
{
2008-11-17 18:29:00 -05:00
lock (instanceLock) {
DebugStub.Assert(instanceCount == 0);
instanceCount++;
}
2008-03-05 09:52:00 -05:00
KeyboardChannel! channel = new KeyboardChannel(device, ep);
Thread! thread = new Thread(new ThreadStart(channel.MessagePump));
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Audit, "KeyboardChannel starting thread {0:x}",
AppRuntime.AddressOf(thread));
thread.Start();
}
private KeyboardChannel(Keyboard8042! device,
[Claims] KeyboardDeviceContract.Exp:Start! ep)
{
this.device = device;
this.epStart = new TRef<KeyboardDeviceContract.Exp:Start>(ep);
base();
}
private void MessagePump()
{
Tracing.Log(Tracing.Debug, "KeyboardChannel.Run entered.");
KeyboardDeviceContract.Exp! ep = epStart.Acquire();
epStart = null;
try {
ep.SendSuccess();
for (bool run = true; run;) {
uint key;
switch receive {
case ep.GetKey():
Tracing.Log(Tracing.Debug, "GetKey()");
key = device.WaitForKey();
Tracing.Log(Tracing.Debug, "GetKey() => {0:x8}", key);
ep.SendAckKey(key);
break;
case ep.ChannelClosed():
Tracing.Log(Tracing.Debug, "peer closed channel.");
run = false;
break;
}
}
}
finally {
delete ep;
2008-11-17 18:29:00 -05:00
lock (instanceLock) {
DebugStub.Assert(instanceCount == 1);
instanceCount--;
}
2008-03-05 09:52:00 -05:00
}
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Debug, "KeyboardChannel exiting.");
}
}
//////////////////////////////////////////////////////////////////////////
//
// Underlying device implementation.
//
public class Keyboard8042
{
internal Keyboard8042(KeyboardResources! res)
{
keyboardPort = res.keyboard.PortAtOffset(0, 1, Access.ReadWrite);
controllerPort = res.controller.PortAtOffset(0, 1, Access.ReadWrite);
irq = res.irq.IrqAtOffset(0);
}
private IoIrq irq;
private IoPort keyboardPort;
private IoPort controllerPort;
private byte lastCtrl = 0;
private bool keyboardWorks = false;
private bool mouseWorks = false;
public bool Initialize()
{
2008-11-17 18:29:00 -05:00
bool iflag = PrivilegedGate.DisableInterrupts();
2008-03-05 09:52:00 -05:00
try {
Tracing.Log(Tracing.Debug, "Registering Interrupt");
irq.RegisterInterrupt();
Tracing.Log(Tracing.Debug, "Initializing Keyboard");
byte data;
// Run a keyboard self test.
Tracing.Log(Tracing.Debug, "Running controller self test.");
Write8042Ctrl(0xaa);
data = ReadData();
Tracing.Log(Tracing.Debug, "ctrl={0:x} data={1:x}",
lastCtrl, data);
if (data != 0x55) {
Tracing.Log(Tracing.Debug, "Controller self test failed: {0:x}",
data);
return false;
}
// Enable the keyboard.
Tracing.Log(Tracing.Debug, "Enabling keyboard.");
Write8042Ctrl(0xae);
Empty8042();
// Test the keyboard.
Tracing.Log(Tracing.Debug, "Running controller self test.");
Write8042Ctrl(0xab);
Thread.SpinWait(10);
data = ReadData();
Tracing.Log(Tracing.Debug, "Keyboard test: {0:x}", data);
if (data != 0xff) {
keyboardWorks = true;
}
// Reset keyboard, but disable scanning.
Tracing.Log(Tracing.Debug, "Resetting keyboard.");
Empty8042();
// Write8042Ctrl(0xd2);
Write8042Data(0xf5);
Thread.SpinWait(10);
// Write the LEDs.
Write8042Data(0xed);
Write8042Data(0x07);
// Set to scan set 2.
Write8042Data(0xf0);
Write8042Data(0x02);
Thread.SpinWait(10);
data = ReadData();
Tracing.Log(Tracing.Debug, "select scanset: {0:x}", data);
#if DONT_MOUSE
Tracing.Log(Tracing.Debug, "identify keyboard");
byte[] mouse = new byte[10];
Write8042Data(0xf2);
ReadAndPrintData(mouse);
#endif
// Enable IBM Scancode translation
//
// Under all Microsoft operating systems, all keyboards
// actually transmit Scan Code Set 2 values down the wire
// from the keyboard to the keyboard port. These values
// are translated to Scan Code Set 1 by the i8042 port chip.
// The rest of the operating system, and all applications
// that handle scan codes expect the values to be from
// Scan Code Set 1. Scan Code Set 3 is not used or
// for operation of Microsoft operating systems.
Write8042Ctrl(0x60);
#if DONT_USE_INTERRUPTS
Write8042Data(0x40);
#else
Write8042Data(0x41); // Send an interrupt as well.
#endif
Empty8042();
#if DONT_MOUSE
// Enable the mouse.
Write8042Ctrl(0xa8);
Empty8042();
// Test the mouse.
Write8042Ctrl(0xa9);
Thread.SpinWait(10);
data = ReadData();
Tracing.Log(Tracing.Debug, "Mouse test: {0:x}", data);
if (data != 0xff) {
mouseWorks = true;
}
// Get Mouse settings.
Write8042Ctrl(0xd4);
Write8042Data(0xe9);
ReadAndPrintData(mouse);
// Enable the mouse.
Write8042Ctrl(0xd4);
Write8042Data(0xf4);
Tracing.Log(Tracing.Debug, "Mouse stat={0:x} res={1:x} rate={2:x}",
mouse[0], mouse[1], mouse[2]);
#endif
// Enable keyboard scan.
Empty8042();
Write8042Data(0xf4);
Thread.SpinWait(10);
// Write the LEDs.
Write8042Data(0xed);
Write8042Data(0x01);
for (int i = 0; i < 10; i++) {
PollRaw();
}
}
finally {
2008-11-17 18:29:00 -05:00
PrivilegedGate.RestoreInterrupts(iflag);
2008-03-05 09:52:00 -05:00
}
return keyboardWorks;
}
public void Finalize()
{
irq.ReleaseInterrupt();
}
private void Empty8042()
{
while (((lastCtrl = controllerPort.Read8()) & 0x01) != 0) {
keyboardPort.Read8();
}
lastCtrl = controllerPort.WaitClear8(0x01);
}
private void Write8042Prep()
{
lastCtrl = controllerPort.WaitClear8(0x02);
Empty8042();
Thread.SpinWait(50);
}
private void Write8042Ctrl(byte value)
{
Write8042Prep();
controllerPort.Write8(value);
}
private void Write8042Data(byte value)
{
Write8042Prep();
keyboardPort.Write8(value);
}
private byte ReadData()
{
if (((lastCtrl = controllerPort.Read8()) & 0x01) == 0) {
Tracing.Log(Tracing.Debug, "Waiting for data ready: {0:x}", lastCtrl);
lastCtrl = controllerPort.WaitSet8(0x01);
}
Thread.SpinWait(50);
return keyboardPort.Read8();
}
internal void ReadAndPrintData(byte[]! data)
{
if (((lastCtrl = controllerPort.Read8()) & 0x01) == 0) {
Tracing.Log(Tracing.Debug, "Waiting for data ready to print: {0:x}", lastCtrl);
lastCtrl = controllerPort.WaitSet8(0x01);
}
for (int i = 0; i < data.Length; i++) {
if (((lastCtrl = controllerPort.Read8()) & 0x01) == 0) {
Tracing.Log(Tracing.Debug, "Ctrl {0:x}", lastCtrl);
break;
}
else {
Tracing.Log(Tracing.Debug, "Ctrl {0:x} : ", lastCtrl);
}
Thread.SpinWait(200);
data[i] = keyboardPort.Read8();
unchecked {
Tracing.Log(Tracing.Debug, "Data[{0}]: {1:x}",
(UIntPtr)(uint)i,
data[i]);
}
}
}
[Flags]
public enum Modifiers
{
CAPS_LOCK = 0x00000001,
NUM_LOCK = 0x00000002,
SHIFT_LEFT = 0x00000100,
SHIFT_RIGHT = 0x00000200,
SHIFT_ALL = SHIFT_LEFT | SHIFT_RIGHT,
CTRL_LEFT = 0x00000400,
CTRL_RIGHT = 0x00000800,
CTRL_ALL = CTRL_LEFT | CTRL_RIGHT,
ALT_LEFT = 0x00001000,
ALT_RIGHT = 0x00002000,
ALT_ALL = ALT_LEFT | ALT_RIGHT,
WINDOWS_LEFT = 0x00004000,
WINDOWS_RIGHT = 0x00008000,
WINDOWS_ALL = WINDOWS_LEFT | WINDOWS_RIGHT,
}
private uint keyModifiers = 0;
private void SetModifier(Modifiers bit, Qualifiers shared, Modifiers all, uint data)
{
if ((data & (uint)Qualifiers.KEY_UP) != 0) {
keyModifiers &= ~(uint)bit;
if ((keyModifiers & (uint)all) == 0) {
keyModifiers &= (uint)~shared;
}
}
else {
keyModifiers |= (uint)bit | (uint)shared;
}
}
private void SetModifier(Modifiers bit, uint data)
{
if ((data & (uint)Qualifiers.KEY_UP) != 0) {
keyModifiers &= ~(uint)bit;
}
else {
keyModifiers |= (uint)bit;
}
}
private byte PollRawOneByte()
{
lastCtrl = controllerPort.WaitSet8(0x01);
Thread.SpinWait(50);
byte value = keyboardPort.Read8();
#if DEBUG_IO
Tracing.Log(Tracing.Debug, "Data {0:x} [modifiers={1:x}]", value, keyModifiers);
#endif
Thread.SpinWait(50);
return value;
}
private uint PollRaw()
{
if (((lastCtrl = controllerPort.Read8()) & 0x01) == 0) {
return 0;
}
2008-11-17 18:29:00 -05:00
if ((lastCtrl & 0x20) != 0) { // Mouse
2008-03-05 09:52:00 -05:00
uint md = PollRawOneByte();
md |= (uint)PollRawOneByte() << 8;
md |= (uint)PollRawOneByte() << 16;
return (uint)((uint)Qualifiers.KEY_MOUSE | md);
}
else {
uint data = PollRawOneByte();
2008-11-17 18:29:00 -05:00
if (data >= 0x00 && data <= 0x5f) { // Key Down
2008-03-05 09:52:00 -05:00
return (uint)((uint)(data & 0x7f));
}
else if (data >= 0x80 && data <= 0xdf) { // Key Up
return (uint)((uint)Qualifiers.KEY_UP | (data & 0x7f));
}
2008-11-17 18:29:00 -05:00
else if (data == 0xe0) { // Extended
2008-03-05 09:52:00 -05:00
data = PollRawOneByte();
if ((data & 0x80) != 0) {
return (uint)((uint)0x80 |
(uint)Qualifiers.KEY_UP |
(uint)Qualifiers.KEY_EXTENDED |
(data & 0x7f));
}
else {
return (uint)((uint)0x80 |
(uint)Qualifiers.KEY_EXTENDED |
(data & 0x7f));
}
}
2008-11-17 18:29:00 -05:00
else if (data == 0xe1) { // Extended
2008-03-05 09:52:00 -05:00
data = PollRawOneByte();
if ((data & 0x80) != 0) {
return (uint)((uint)0x80 |
(uint)Qualifiers.KEY_UP |
(uint)Qualifiers.KEY_EXTENDED |
(data & 0x7f));
}
else {
return (uint)((uint)0x80 |
(uint)Qualifiers.KEY_EXTENDED |
(data & 0x7f));
}
}
else {
return data;
}
}
}
public void GetPosition(out int x, out int y)
{
x = mouseX;
y = mouseY;
}
public uint WaitForKey()
{
uint key = 0;
2008-11-17 18:29:00 -05:00
while ((key = Poll()) == 0) {
2008-03-05 09:52:00 -05:00
#if DEBUG_DISPATCH_IO
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("::: Waiting for Keyboard interrupt.");
2008-03-05 09:52:00 -05:00
#endif
2008-11-17 18:29:00 -05:00
irq.WaitForInterrupt();
2008-03-05 09:52:00 -05:00
Tracing.Log(Tracing.Audit, "Keyboard IRQ");
2008-11-17 18:29:00 -05:00
irq.AckInterrupt();
}
2008-03-05 09:52:00 -05:00
#if DEBUG_DISPATCH_IO
2008-11-17 18:29:00 -05:00
DebugStub.WriteLine("::: Keyboard poll: {0:x8}", __arglist(key));
2008-03-05 09:52:00 -05:00
#endif
2008-11-17 18:29:00 -05:00
2008-03-05 09:52:00 -05:00
return key;
}
public uint Poll()
{
uint data = PollRaw();
if (data == 0) {
return 0;
}
// Update the Modifier Flags
switch (data & ~(uint)Qualifiers.KEY_UP) {
case 0x3a: // Caps-Lock
SetModifier(Modifiers.CAPS_LOCK, data);
break;
case 0x45: // Num Lock
SetModifier(Modifiers.NUM_LOCK, data);
break;
case 0x2a: // Left Shift
SetModifier(Modifiers.SHIFT_LEFT,
Qualifiers.KEY_SHIFT,
Modifiers.SHIFT_ALL, data);
break;
case 0x36: // Right Shift
SetModifier(Modifiers.SHIFT_RIGHT,
Qualifiers.KEY_SHIFT,
Modifiers.SHIFT_ALL, data);
break;
case 0x1d: // Left Control
SetModifier(Modifiers.CTRL_LEFT,
Qualifiers.KEY_CTRL,
Modifiers.CTRL_ALL, data);
break;
case 0x9d: // Right Control
SetModifier(Modifiers.CTRL_RIGHT,
Qualifiers.KEY_CTRL,
Modifiers.CTRL_ALL, data);
break;
case 0x38: // Left Alt
SetModifier(Modifiers.ALT_LEFT,
Qualifiers.KEY_ALT,
Modifiers.ALT_ALL, data);
break;
case 0xb8: // Right Alt
SetModifier(Modifiers.ALT_RIGHT,
Qualifiers.KEY_ALT,
Modifiers.ALT_ALL, data);
break;
case 0xdb: // Left Windows
SetModifier(Modifiers.WINDOWS_LEFT,
Qualifiers.KEY_WINDOWS,
Modifiers.WINDOWS_ALL, data);
break;
case 0xdc: // Right Windows
SetModifier(Modifiers.WINDOWS_RIGHT,
Qualifiers.KEY_WINDOWS,
Modifiers.WINDOWS_ALL, data);
break;
}
// Encode the modifier flags into the data.
data |= (keyModifiers & (uint)Qualifiers.KEY_MODIFIERS);
if ((data & (uint)Qualifiers.KEY_MOUSE) != 0) {
// Update the cursor position.
// The statements here are somewhat complex because the
// hardware returns two 9-bit signed integers.
int x = ((int)unchecked((sbyte)((data & 0x10) << 3)) & ~0xff)
| (int)((data >> 8) & 0xff);
int y = ((int)unchecked((sbyte)((data & 0x20) << 2)) & ~0xff)
| (int)((data >> 16) & 0xff);
mouseX = Math.Min(Math.Max(0, mouseX + x), mouseMaxX);
mouseY = Math.Min(Math.Max(0, mouseY - y), mouseMaxY);
// Process the buttons.
uint buttons = (data & (uint)Qualifiers.MOUSE_BUTTON_ALL);
if (mouseButtons != buttons) {
// Button positions changed.
uint up = mouseButtons & (buttons ^ (uint)Qualifiers.MOUSE_BUTTON_ALL);
uint dn = (mouseButtons ^ (uint)Qualifiers.MOUSE_BUTTON_ALL) & buttons;
mouseButtons = buttons;
if (dn != 0) {
data = (uint)Qualifiers.KEY_DOWN | (uint)Qualifiers.KEY_MOUSE | (uint)dn;
}
else if (up != 0) {
data = (uint)Qualifiers.KEY_UP | (uint)Qualifiers.KEY_MOUSE | (uint)up;
}
}
return data;
}
else {
if ((data & (uint)Qualifiers.KEY_UP) == 0) {
data |= (uint)Qualifiers.KEY_DOWN;
}
uint scan = 0;
if ((data & (uint)Qualifiers.KEY_SHIFT) != 0) {
scan = scanShift[data & 0xff];
}
if (scan == 0) {
scan = scanNormal[data & 0xff];
}
if (scan == 0) {
Tracing.Log(Tracing.Warning, "Unmapped key: {0:x}", data & 0xff);
}
2008-11-17 18:29:00 -05:00
uint output = unchecked(data & (uint)~0xff) | scan;
2008-03-05 09:52:00 -05:00
#if DEBUG_IO
Tracing.Log(Tracing.Debug, "output {0:x}", output);
#endif
return output;
}
}
private uint mouseButtons = 0;
private int mouseX = 0;
private int mouseY = 0;
private int mouseMaxX = 1024;
private int mouseMaxY = 768;
private char[] scanNormal = new char [0x100]
{
// 0 1 2 3 4 5 6 7
// 8 9 a b c d e f
'\0', (char)Keys.ESCAPE, '1', '2', '3', '4', '5', '6', // 0x00..0x07
'7' , '8', '9', '0', '-', '=', '\b', '\t', // 0x08..0x0f
'q' , 'w', 'e', 'r', 't', 'y', 'u', 'i', // 0x10..0x17
'o' , 'p', '[', ']', '\n', (char)Keys.LEFT_CTRL, 'a', 's', // 0x18..0x1f
'd' , 'f', 'g', 'h', 'j', 'k', 'l', ';', // 0x20..0x27
'\'', '`', (char)Keys.LEFT_SHIFT, '\\', 'z', 'x', 'c', 'v', // 0x28..0x2f
'b' , 'n', 'm', ',', '.', '/', (char)Keys.RIGHT_SHIFT, '\0', // 0x30..0x37
(char)Keys.LEFT_ALT, ' ', (char)Keys.CAPS_LOCK, (char)Keys.F1,
(char)Keys.F2, (char)Keys.F3, (char)Keys.F4, (char)Keys.F5, // 0x38..0x3f
(char)Keys.F6, (char)Keys.F7, (char)Keys.F8, (char)Keys.F9,
(char)Keys.F10, (char)Keys.NUM_LOCK, '\0', (char)Keys.HOME, // 0x40..0x47
(char)Keys.UP_ARROW, (char)Keys.PAGE_UP, '\0', (char)Keys.LEFT_ARROW,
'\0', (char)Keys.RIGHT_ARROW, '\0', (char)Keys.END, // 0x48..0x4f
(char)Keys.DOWN_ARROW, (char)Keys.PAGE_DOWN, (char)Keys.INSERT, (char)Keys.DELETE,
(char)Keys.SYS_REQ, '\0', '\0', (char)Keys.F11, // 0x50..0x57
(char)Keys.F12, '\0', '\0', '\0',
'\0', '\0', '\0', '\0', // 0x58..0x5f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x60..0x67
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x68..0x6f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x70..0x77
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x78..0x7f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x80..0x87
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x88..0x8f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x90..0x97
'\0', '\0', '\0', '\0', '\n', (char)Keys.RIGHT_CTRL, '\0', '\0', // 0x98..0x9f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xa0..0xa7
'\0', '\0', (Char)0xfff0, '\0', '\0', '\0', '\0', '\0', // 0xa8..0xaf
'\0', '\0', '\0', '\0', '\0', '/', '\0', '*', // 0xb0..0xb7
(char)Keys.RIGHT_ALT, '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xb8..0xbf
'\0', '\0', '\0', '\0',
'\0', (char)Keys.NUM_LOCK, '\0', (char)Keys.HOME, // 0xc0..0xc7
(char)Keys.UP_ARROW, (char)Keys.PAGE_UP, '\0', (char)Keys.LEFT_ARROW,
'\0', (char)Keys.RIGHT_ARROW, '\0', (char)Keys.END, // 0xc8..0xcf
(char)Keys.DOWN_ARROW, (char)Keys.PAGE_DOWN, (char)Keys.INSERT, (char)Keys.DELETE,
'\0', '\0', '\0', '\0', // 0xd0..0xd7
'\0', '\0', '\0', (char)Keys.LEFT_WINDOWS,
(char)Keys.RIGHT_WINDOWS, (char)Keys.MENU, '\0', '\0', // 0xd8..0xdf
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xe0..0xe7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xe8..0xef
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xf0..0xf7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xf8..0xff
};
private char[] scanShift = new char [0x100]
{
// 0 1 2 3 4 5 6 7
// 8 9 a b c d e f
'\0', '\0', '!', '@', '#', '$', '%', '^', // 0x00..0x07
'&' , '*', '(', ')', '_', '+', '\b', '\t', // 0x08..0x0f
'Q' , 'W', 'E', 'R', 'T', 'Y', 'U', 'I', // 0x10..0x17
'O' , 'P', '{', '}', '\n', '\0', 'A', 'S', // 0x18..0x1f
'D' , 'F', 'G', 'H', 'J', 'K', 'L', ':', // 0x20..0x27
'\"', '~', '\0', '|', 'Z', 'X', 'C', 'V', // 0x28..0x2f
'B' , 'N', 'M', '<', '>', '?', '\0', '\0', // 0x30..0x37
'\0', ' ', '\0', '\0', '\0', '\0', '\0', '\0', // 0x38..0x3f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x40..0x47
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x48..0x4f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x50..0x57
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x58..0x5f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x60..0x67
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x68..0x6f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x70..0x77
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x78..0x7f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x80..0x87
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x88..0x8f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x90..0x97
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0x98..0x9f
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xa0..0xa7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xa8..0xaf
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xb0..0xb7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xb8..0xbf
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xc0..0xc7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xc8..0xcf
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xd0..0xd7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xd8..0xdf
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xe0..0xe7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xe8..0xef
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xf0..0xf7
'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', // 0xf8..0xff
};
}
}