using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Cosmos.Hardware { public delegate void HandleKeyboardDelegate(byte aScanCode, bool aReleased); public class Keyboard : Device { protected Core.IOGroup.Keyboard IO = Core.Global.BaseIOGroups.Keyboard; private HandleKeyboardDelegate mHandleKeyboardKey; public void Initialize(HandleKeyboardDelegate aHandleKeyboardKeyDelegate) { mHandleKeyboardKey = aHandleKeyboardKeyDelegate; } public Keyboard() { mBuffer = new Queue(BufferSize); Initialize(HandleScancode); Core.INTs.SetIrqHandler(0x01, HandleIRQ); // TODO: Need to add support for mult keyboards. ie one in PS2 and one in USB, or even more if (mKeys == null) { CreateDefaultKeymap(); } } public void HandleIRQ(ref Core.INTs.IRQContext aContext) { if (mHandleKeyboardKey != null) { byte xScanCode = IO.Port60.Byte; bool xReleased = (xScanCode & 0x80) == 0x80; if (xReleased) { xScanCode = (byte)(xScanCode ^ 0x80); } mHandleKeyboardKey(xScanCode, xReleased); } } private Queue mBuffer; private const int BufferSize = 64; private bool mEscaped; private List mKeys; private bool mShiftState; private bool mCtrlState; private bool mAltState; public bool ShiftPressed { get { return mShiftState; } } public bool CtrlPressed { get { return mCtrlState; } } public bool AltPressed { get { return mAltState; } } protected void HandleScancode(byte aScancode, bool aReleased) { uint xTheScancode = aScancode; if (mEscaped) { xTheScancode = (ushort)(xTheScancode << 8); mEscaped = false; } switch (xTheScancode) { case 0x36: case 0x2A: { mShiftState = !aReleased; break; } case 0x1D: { mCtrlState = !aReleased; break; } case 0x38: { mAltState = !aReleased; break; } default: { if ((mCtrlState) && (mAltState) && (xTheScancode == 0x53)) { Console.WriteLine("Detected Ctrl-Alt-Delete! Rebooting System..."); Core.Global.CPU.Reboot(); } if (mShiftState) { xTheScancode = xTheScancode << 16; } if (mBuffer.Count < BufferSize) { if (!aReleased) { char xTheChar; if (!GetCharValue(xTheScancode, out xTheChar)) { //DebugUtil.SendError("Keyboard", "error while getting scancode character!"); } else { //DebugUtil.SendDoubleNumber("Keyboard", "Scancode and Char", xTheScancode, 32, xTheChar, 16); } mBuffer.Enqueue(xTheScancode); } } break; } } } // Can merge HandleScancode after we remove old code // Remove the static.. Make it a real class protected void ByteReceived(byte aValue) { bool xReleased = (aValue & 0x80) == 0x80; if (xReleased) { aValue = (byte)(aValue ^ 0x80); } mHandleKeyboardKey(aValue, xReleased); } private void CreateDefaultKeymap() { mKeys = new List(164); //TODO: fn (for laptops) #region Letters AddKey(0x10, 'q', ConsoleKey.Q); AddKey(0x100000, 'Q', ConsoleKey.Q); AddKey(0x11, 'w', ConsoleKey.W); AddKey(0x110000, 'W', ConsoleKey.W); AddKey(0x12, 'e', ConsoleKey.E); AddKey(0x120000, 'E', ConsoleKey.E); AddKey(0x13, 'r', ConsoleKey.R); AddKey(0x130000, 'R', ConsoleKey.R); AddKey(0x14, 't', ConsoleKey.T); AddKey(0x140000, 'T', ConsoleKey.T); AddKey(0x15, 'y', ConsoleKey.Y); AddKey(0x150000, 'Y', ConsoleKey.Y); AddKey(0x16, 'u', ConsoleKey.U); AddKey(0x160000, 'U', ConsoleKey.U); AddKey(0x17, 'i', ConsoleKey.I); AddKey(0x170000, 'I', ConsoleKey.I); AddKey(0x18, 'o', ConsoleKey.O); AddKey(0x180000, 'O', ConsoleKey.O); AddKey(0x19, 'p', ConsoleKey.P); AddKey(0x190000, 'P', ConsoleKey.P); AddKey(0x1E, 'a', ConsoleKey.A); AddKey(0x1E0000, 'A', ConsoleKey.A); AddKey(0x1F, 's', ConsoleKey.S); AddKey(0x1F0000, 'S', ConsoleKey.S); AddKey(0x20, 'd', ConsoleKey.D); AddKey(0x200000, 'D', ConsoleKey.D); AddKey(0x21, 'f', ConsoleKey.F); AddKey(0x210000, 'F', ConsoleKey.F); AddKey(0x22, 'g', ConsoleKey.G); AddKey(0x220000, 'G', ConsoleKey.G); AddKey(0x23, 'h', ConsoleKey.H); AddKey(0x230000, 'H', ConsoleKey.H); AddKey(0x24, 'j', ConsoleKey.J); AddKey(0x240000, 'J', ConsoleKey.J); AddKey(0x25, 'k', ConsoleKey.K); AddKey(0x250000, 'K', ConsoleKey.K); AddKey(0x26, 'l', ConsoleKey.L); AddKey(0x260000, 'L', ConsoleKey.L); AddKey(0x2C, 'z', ConsoleKey.Z); AddKey(0x2C0000, 'Z', ConsoleKey.Z); AddKey(0x2D, 'x', ConsoleKey.X); AddKey(0x2D0000, 'X', ConsoleKey.X); AddKey(0x2E, 'c', ConsoleKey.C); AddKey(0x2E0000, 'C', ConsoleKey.C); AddKey(0x2F, 'v', ConsoleKey.V); AddKey(0x2F0000, 'V', ConsoleKey.V); AddKey(0x30, 'b', ConsoleKey.B); AddKey(0x300000, 'B', ConsoleKey.B); AddKey(0x31, 'n', ConsoleKey.N); AddKey(0x310000, 'N', ConsoleKey.N); AddKey(0x32, 'm', ConsoleKey.M); AddKey(0x320000, 'M', ConsoleKey.M); #endregion #region digits //AddKey(0x1, '`'); //AddKey(0x10000, '~'); AddKey(0x29, '`', ConsoleKey.NoName); AddKey(0x290000, '~', ConsoleKey.NoName); AddKey(0x2, '1', ConsoleKey.D1); AddKey(0x20000, '!', ConsoleKey.D1); AddKey(0x3, '2', ConsoleKey.D2); AddKey(0x30000, '@', ConsoleKey.D2); AddKey(0x4, '3', ConsoleKey.D3); AddKey(0x40000, '#', ConsoleKey.D3); AddKey(0x5, '4', ConsoleKey.D4); AddKey(0x50000, '$', ConsoleKey.D5); AddKey(0x6, '5', ConsoleKey.D5); AddKey(0x60000, '%', ConsoleKey.D5); AddKey(0x7, '6', ConsoleKey.D6); AddKey(0x70000, '^', ConsoleKey.D6); AddKey(0x8, '7', ConsoleKey.D7); AddKey(0x80000, '&', ConsoleKey.D7); AddKey(0x9, '8', ConsoleKey.D8); AddKey(0x90000, '*', ConsoleKey.D8); AddKey(0xA, '9', ConsoleKey.D9); AddKey(0xA0000, '(', ConsoleKey.D9); AddKey(0xB, '0', ConsoleKey.D0); AddKey(0xB0000, ')', ConsoleKey.D0); #endregion #region Special AddKeyWithShift(0x0E, '\u0968', ConsoleKey.Backspace); //Backspace AddKeyWithShift(0x0F, '\t', ConsoleKey.Tab); //Tabulator AddKeyWithShift(0x1C, '\n', ConsoleKey.Enter); //Enter AddKeyWithShift(0x39, ' ', ConsoleKey.Spacebar); //Space AddKeyWithShift(0x4b, '\u2190', ConsoleKey.LeftArrow); //Left arrow AddKeyWithShift(0x48, '\u2191', ConsoleKey.UpArrow); //Up arrow AddKeyWithShift(0x4d, '\u2192', ConsoleKey.RightArrow); //Right arrow AddKeyWithShift(0x50, '\u2193', ConsoleKey.DownArrow); //Down arrow AddKeyWithShift(0x5b, ConsoleKey.LeftWindows); AddKeyWithShift(0x5c, ConsoleKey.RightWindows); //AddKey(0x5d, ConsoleKey.NoName); //Context Menu AddKeyWithShift(0x52, ConsoleKey.Insert); AddKeyWithShift(0x47, ConsoleKey.Home); AddKeyWithShift(0x49, ConsoleKey.PageUp); AddKeyWithShift(0x53, ConsoleKey.Delete); AddKeyWithShift(0x4f, ConsoleKey.End); AddKeyWithShift(0x51, ConsoleKey.PageDown); AddKeyWithShift(0x37, ConsoleKey.PrintScreen); //AddKeyWithShift(0x46, ConsoleKey.NoName); //Scroll Lock //AddKeyWithShift(0x3a, ConsoleKey.NoName); //Caps Lock AddKeyWithShift(0x45, ConsoleKey.Pause); AddKeyWithShift(0x3b, ConsoleKey.F1); AddKeyWithShift(0x3c, ConsoleKey.F2); AddKeyWithShift(0x3d, ConsoleKey.F3); AddKeyWithShift(0x3e, ConsoleKey.F4); AddKeyWithShift(0x3f, ConsoleKey.F5); AddKeyWithShift(0x40, ConsoleKey.F6); AddKeyWithShift(0x41, ConsoleKey.F7); AddKeyWithShift(0x42, ConsoleKey.F8); AddKeyWithShift(0x43, ConsoleKey.F9); AddKeyWithShift(0x44, ConsoleKey.F10); AddKeyWithShift(0x57, ConsoleKey.F11); AddKeyWithShift(0x58, ConsoleKey.F12); AddKeyWithShift(0x1, ConsoleKey.Escape); #endregion #region Punctuation and Signs AddKey(0x27, ';', ConsoleKey.NoName); AddKey(0x270000, ':', ConsoleKey.NoName); AddKey(0x28, '\'', ConsoleKey.NoName); AddKey(0x280000, '"', ConsoleKey.NoName); AddKey(0x2B, '\\', ConsoleKey.NoName); AddKey(0x2B0000, '|', ConsoleKey.NoName); AddKey(0x33, ',', ConsoleKey.OemComma); AddKey(0x330000, '<', ConsoleKey.OemComma); AddKey(0x34, '.', ConsoleKey.OemPeriod); AddKey(0x340000, '>', ConsoleKey.OemPeriod); AddKey(0x35, '/', ConsoleKey.Divide); AddKey(0x350000, '?', ConsoleKey.Divide); //AddKey(0x4A, '-'); AddKey(0x0C, '-', ConsoleKey.Subtract); AddKey(0x0C0000, '_', ConsoleKey.Subtract); AddKey(0x0D, '=', ConsoleKey.OemPlus); AddKey(0x0D0000, '+', ConsoleKey.OemPlus); //AddKey(0x4E, '+'); AddKey(0x1A, '[', ConsoleKey.NoName); AddKey(0x1A0000, '{', ConsoleKey.NoName); AddKey(0x1B, ']', ConsoleKey.NoName); AddKey(0x1B0000, '}', ConsoleKey.NoName); AddKeyWithShift(0x4c, '5', ConsoleKey.NumPad5); AddKeyWithShift(0x4a, '-', ConsoleKey.OemMinus); AddKeyWithShift(0x4e, '+', ConsoleKey.OemPlus); AddKeyWithShift(0x37, '*', ConsoleKey.Multiply); #endregion } private uint KeyCount = 0; private void AddKey(uint p, char p_2, ConsoleKey p_3) { mKeys.Add(new KeyMapping(p, p_2, p_3)); KeyCount++; } private void AddKeyWithShift(uint p, char p_2, ConsoleKey p_3) { AddKey(p, p_2, p_3); AddKey(p << 16, p_2, p_3); } private void AddKey(uint p, ConsoleKey p_3) { AddKey(p, '\0', p_3); } private void AddKeyWithShift(uint p, ConsoleKey p_3) { AddKeyWithShift(p, '\0', p_3); } public void ChangeKeyMap(List aKeys) { mKeys = aKeys; } public bool GetCharValue(uint aScanCode, out char aValue) { for (int i = 0; i < mKeys.Count; i++) { //if (i == 0) { // Console.Write("ScanCode in KeyMapping: "); // Interrupts.WriteNumber(mKeys[i].Scancode, 32); // Console.WriteLine(""); //} if (mKeys[i].Scancode == aScanCode) { if (mKeys[i].Value != '\0') { aValue = mKeys[i].Value; return true; } break; } } aValue = '\0'; return false; } public bool GetKeyValue(uint aScanCode, out ConsoleKey aValue) { for (int i = 0; i < mKeys.Count; i++) { if (mKeys[i].Scancode == aScanCode) { aValue = mKeys[i].Key; return true; } } aValue = ConsoleKey.NoName; return false; } public bool GetKeyMapping(uint aScanCode, out KeyMapping aValue) { for (int i = 0; i < mKeys.Count; i++) { if (mKeys[i].Scancode == aScanCode) { aValue = mKeys[i]; return true; } } aValue = null; return false; } public char ReadChar() { char xResult = '\0'; while (mBuffer.Count == 0 || !GetCharValue(mBuffer.Dequeue(), out xResult)) { //Global.Sleep(10); //ToDo optimize value Core.Global.CPU.Halt(); } return xResult; } public bool GetChar(out char c) { c = '\0'; if (mBuffer.Count > 0) { GetCharValue(mBuffer.Dequeue(), out c); return true; } else { return false; } } public ConsoleKey ReadKey() { ConsoleKey xResult = ConsoleKey.NoName; while (mBuffer.Count == 0 || !GetKeyValue(mBuffer.Dequeue(), out xResult)) { //Global.Sleep(10); //ToDo optimize value Core.Global.CPU.Halt(); } return xResult; } public bool GetKey(out ConsoleKey c) { c = ConsoleKey.NoName; if (mBuffer.Count > 0) { GetKeyValue(mBuffer.Dequeue(), out c); return true; } else { return false; } } public KeyMapping ReadMapping() { KeyMapping xResult = null; while (mBuffer.Count == 0 || !GetKeyMapping(mBuffer.Dequeue(), out xResult)) { //Global.Sleep(10); //ToDo optimize value Core.Global.CPU.Halt(); } return xResult; } public bool GetMapping(out KeyMapping c) { c = null; if (mBuffer.Count > 0) { GetKeyMapping(mBuffer.Dequeue(), out c); return true; } else { return false; } } public uint ReadScancode() { while (mBuffer.Count == 0) { Core.Global.CPU.Halt(); } return mBuffer.Dequeue(); } public bool GetScancode(out uint c) { if (mBuffer.Count > 0) { c = mBuffer.Dequeue(); return true; } else { c = 0; return false; } } public class KeyMapping { public uint Scancode; public char Value; public ConsoleKey Key; public KeyMapping(uint aScanCode, char aValue, ConsoleKey aKey) { Scancode = aScanCode; Value = aValue; Key = aKey; } public KeyMapping(uint aScanCode, ConsoleKey aKey) { Scancode = aScanCode; Value = '\0'; Key = aKey; } } } }