⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keyboard.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <kerninc/kernel.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/SysTimer.hxx>#include <kerninc/AutoConf.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/Thread.hxx>#include <kerninc/Key.hxx>#include <kerninc/Invocation.hxx>#include <kerninc/Machine.hxx>#include <eros/i486/io.h>#include "IDT.hxx"static bool Probe(AutoConf *ac);static bool Attach(AutoConf *ac);struct Driver ac_kbd = {  "kbd", Probe, Attach} ;/* The keyboard interrupt handler is built as a fast-path interrupt * handler for several reasons: *  * 1. It is important that servicing of the console keyboard never be * delayed -- nothing should prevent the system from being rebootable, * for example. *  * 2. The labor done in the typical case -- storing a character in a * buffer -- is minimal. *  * 3. The interrupt line for the keyboard is exclusive and hardwired, * and not reassigned on any current generation PC's. */const uint8_t KbdDataPort    = 0x60u;const uint8_t KbdCtrlPort   = 0x64u;const uint8_t KbdStatusPort = 0x64u;ThreadPile KbdSleepQ;int kbd_polling = 0;struct KeyCmd {  enum {    SetLed = 0xedu,  } ;};struct KbdStatus {  enum {    BufFull = 0x1,    Ready   = 0x2,  };};struct KeyMod {  enum {    /* Note that the first three values correspond to the bitmask for the     * keyboard LED's -- this is not an accident!     */    ScrlLock  = 0x01u,    NumLock   = 0x02u,    AlphaLock = 0x04u,    Shift     = 0x10u,    Ctrl      = 0x20u,    Alt       = 0x40u,    Extended  = 0x100u,		/* key is an "extended" key */    IsAlpha   = 0x200u,		/* key is modified by alpha lock key */    IsPad     = 0x400u,		/* key is modified by num lock key */    Meta      = 0x800u,		/* key can be meta'd */  } ;};static bool AsciiMode = true;#if 0static uint32_t ShiftState = KeyMod::NumLock | KeyMod::ScrlLock;#elsestatic uint32_t ShiftState = 0;#endif#define	KBD_DELAY \	{ u_char x = in8(0x84); (void) x; } \	{ u_char x = in8(0x84); (void) x; } \	{ u_char x = in8(0x84); (void) x; } \	{ u_char x = in8(0x84); (void) x; }/* kbd_wait -- wait for a character to be available from the keyboard. */static void KbdWait(void){  int i = 100;  while (i--) {    if ((inb(KbdStatusPort) & KbdStatus::Ready) == 0)       break;    Machine::SpinWaitUs(10);  }#if 0  printf("KbdWait fails\n");#endif}#if 0static voidWriteKbd(uint8_t c){  KbdWait();  old_outb(KbdDataPort, c);}#endifstatic void KbdCmd(uint8_t command){  int retry = 5;  do {    int i = 100000;    KbdWait();    old_outb(KbdDataPort, command);    while (i--) {      if (inb(KbdStatusPort) & KbdStatus::BufFull) {	int val;	/* DELAY(10); */	val = inb(KbdDataPort);	if (val == 0xfa)	  return;	if (val == 0xfe)	  break;      }    }  } while (retry--);  printf("KbdCmd fails\n");}static boolReadKbd(uint8_t& c){  /* KbdWait(); */  while ( (inb(KbdStatusPort) & KbdStatus::BufFull) == 0 )    return false;    c = inb(KbdDataPort);  return true;}static voidUpdateKbdLeds(){  KbdCmd(KeyCmd::SetLed);  KbdCmd(ShiftState & 0x7u);}	       /* Theoretically, a reboot can be accomplished from the keyboard, but * I wasn't able to make it work.  The following is a bit more crude, * but equally effective: */static voidReboot(){#if 1  Machine::HardReset();#else  old_outb(KbdCtrlPort, 0xd0);	/* "read output port" command */    while ( (inb(KbdStatusPort) & KbdStatus::BufFull) == 0 )    ;    uint8_t c = inb(KbdDataPort);  c |= 0x1;			/* set sysreset bit */  old_outb(KbdCtrlPort, 0xd1);	/* "write output port" command */  KbdWait();  old_outb(KbdDataPort, c);	/* "write output port" command */#endif}	       const uint32_t KbdBufferSz = 256;uint8_t kbdBuffer[KbdBufferSz];uint32_t kbdBufferTop = 0;/* Keyboard interpretation proceeds in two phases.  First, the scan * code is converted into a virtual key code, performing any necessary * keyboard escape translation.  Then the key code translation table * is consulted to decide what character to return and whether to * update the shift state (if at all). */#define NOP 256#define NOCHAR(name) {{ NOP, NOP, NOP, NOP },   0 }#define ALPHA(X) {{ X+32, X, X - 64, X - 64 }, KeyMod::Meta|KeyMod::IsAlpha }#define KEY(X, Y) {{ X, Y, X, Y },   KeyMod::Meta }#define PAD(X, Y) {{ X, Y, X, Y },   KeyMod::IsPad }#define F(X) (X + 256)const uint32_t num_scan = 0x59;struct KeyInfo {  uint16_t value[4];		/* base, shift, ctrl, shift-ctrl */  uint16_t flags;} key_table[num_scan] = {  NOCHAR(None),			/* 0x00 */  KEY('\027', '\027'),		/* 0x01 */  KEY('1', '!'),		/* 0x02 */  { { '2', '@', '\0', '\0'}, 0 }, /* 0x03 -- generate NUL */  KEY('3', '#'),		/* 0x04 */  KEY('4', '$'),		/* 0x05 */  KEY('5', '%'),		/* 0x06 */  KEY('6', '^'),		/* 0x07 */  KEY('7', '&'),		/* 0x08 */  KEY('8', '*'),		/* 0x09 */  KEY('9', '('),		/* 0x0a */  KEY('0', ')'),		/* 0x0b */  KEY('-',  '_'),		/* 0x0c */  KEY('=',  '+'),		/* 0x0d */  KEY(0x08, 0x08),		/* 0x0e */  KEY(0x09, 0x08),		/* 0x0f -- is back tab right? */  ALPHA('Q'),			/* 0x10 */  ALPHA('W'),			/* 0x11 */  ALPHA('E'),			/* 0x12 */  ALPHA('R'),			/* 0x13 */  ALPHA('T'),			/* 0x14 */  ALPHA('Y'),			/* 0x15 */  ALPHA('U'),			/* 0x16 */  ALPHA('I'),			/* 0x17 */  ALPHA('O'),			/* 0x18 */  ALPHA('P'),			/* 0x19 */  KEY('[',  '{'),		/* 0x1a */  KEY(']',  '}'),		/* 0x1b */  KEY('\r',  '\r'),		/* 0x1c -- enter */  { { NOP, NOP, NOP, NOP }, KeyMod::Ctrl }, /* 0x1d -- lctrl */  ALPHA('A'),			/* 0x1e */  ALPHA('S'),			/* 0x1f */  ALPHA('D'),			/* 0x20 */  ALPHA('F'),			/* 0x21 */  ALPHA('G'),			/* 0x22 */  ALPHA('H'),			/* 0x23 */  ALPHA('J'),			/* 0x24 */  ALPHA('K'),			/* 0x25 */  ALPHA('L'),			/* 0x26 */  KEY(';',  ':'),		/* 0x27 */  KEY('\'', '"'),		/* 0x28 */  KEY('`',  '~'),		/* 0x29 */  { { NOP, NOP, NOP, NOP }, KeyMod::Shift }, /* 0x2a -- lshift */  KEY('\\', '|'),		/* 0x2b */  ALPHA('Z'),			/* 0x2c */  ALPHA('X'),			/* 0x2d */  ALPHA('C'),			/* 0x2e */  ALPHA('V'),			/* 0x2f */  ALPHA('B'),			/* 0x30 */  ALPHA('N'),			/* 0x31 */  ALPHA('M'),			/* 0x32 */  KEY(',',  '<'),		/* 0x33 */  KEY('.',  '>'),		/* 0x34 */  KEY('/',  '?'),		/* 0x35 */  { { NOP, NOP, NOP, NOP }, KeyMod::Shift }, /* 0x36 -- rshift */  KEY('*',  '*'),		/* 0x37 */  { { NOP, NOP, NOP, NOP }, KeyMod::Alt }, /* 0x38 -- lalt */  KEY(' ',  ' '),		/* 0x39 -- space */  { { NOP, NOP, NOP, NOP }, KeyMod::AlphaLock }, /* 0x3a -- alpha lock */  KEY( F(1), NOP ),		/* 0x3b -- F1 */  KEY( F(2), NOP ),		/* 0x3c -- F2 */  KEY( F(3), NOP ),		/* 0x3d -- F3 */  KEY( F(4), NOP ),		/* 0x3e -- F4 */  KEY( F(5), NOP ),		/* 0x3f -- F5 */  KEY( F(6), NOP ),		/* 0x40 -- F6 */  KEY( F(7), NOP ),		/* 0x41 -- F7 */  KEY( F(8), NOP ),		/* 0x42 -- F8 */  KEY( F(9), NOP ),		/* 0x43 -- F9 */  KEY( F(10), NOP ),		/* 0x44 -- F10 */  { { NOP, NOP, NOP, NOP }, KeyMod::NumLock }, /* 0x45 -- num lock */  { { NOP, NOP, NOP, NOP }, KeyMod::ScrlLock }, /* 0x46 -- scroll-lock */  /* Keypad character mappings -- these assume that num-lock is NOT set! */  PAD( F(15), '7' ),		/* 0x47 -- keypad 7 */  PAD( F(16), '8' ),		/* 0x48 -- keypad 8 */  PAD( F(17), '9' ),		/* 0x49 -- keypad 9 */  KEY( '-',   NOP ),		/* 0x4a -- keypad - */  PAD( F(19), '4' ),		/* 0x4b -- keypad 4 */  PAD( NOP,   '5' ),		/* 0x4c -- keypad 5 */  PAD( F(20), '6' ),		/* 0x4d -- keypad 6 */  KEY( '+',   '+' ),		/* 0x4e -- keypad + */  PAD( F(22), '1' ),		/* 0x4f -- keypad 1 */  PAD( F(23), '2' ),		/* 0x50 -- keypad 2 */  PAD( F(24), '3' ),		/* 0x51 -- keypad 3 */  PAD( F(25), '0' ),		/* 0x52 -- keypad 0 */  PAD( 0x7f,  '.' ),		/* 0x53 -- keypad ./DEL */  KEY( NOP, NOP ),		/* 0x54 -- unused! */  KEY( NOP, NOP ),		/* 0x55 -- unused! */  KEY( NOP, NOP ),		/* 0x56 -- unused! */  KEY( F(11), NOP ),		/* 0x57 -- F11 */  KEY( F(12), NOP ),		/* 0x58 -- F12 */#if 0  /* CHARACTERS BELOW THIS POINT ARE RECODED!!! */  { { NOP, NOP, NOP, NOP }, KeyMod::Ctrl }, /* 0x59 rctrl */  { { NOP, NOP, NOP, NOP }, KeyMod::Alt }, /* 0x5a ralt */e0,1c	kpd-entere0,1d	rctrl		SUPPRESSEDe0,35	kpd-/e0,37	print-screene0,38   ralt		SUPPRESSEDe0,47	home		e0,48	uparrowe0,49	PgUpe0,4b	left-arrow		e0,4d	right-arrowe0,4f	end		e0,50	downarrowe0,51	PgDne0,52	insert		e0,53	delete		e0,5b	lwindowe0,5c	rwindowe0,5d	menue1,1d,68 pause#endif};voidFetchInputFromKeyboard(){  static uint8_t esc_code = 0;  assert(kbdBufferTop < KbdBufferSz);  uint8_t scanCode = 0;    while ( ReadKbd(scanCode) ) {    /* printf("<kc = %x>", scanCode); */    if (AsciiMode == false) {      if (kbdBufferTop == KbdBufferSz)	fatal("Keyboard buffer overflow\n");      else	kbdBuffer[kbdBufferTop++] = scanCode;    }    else {      bool shift = ShiftState & KeyMod::Shift;      bool alt = ShiftState & KeyMod::Alt;      bool ctrl = ShiftState & KeyMod::Ctrl;            /* If this is a break character, we need to know: */      bool isBreak = scanCode & 0x80u;      uint32_t keyCode = scanCode & 0x7fu;            switch (esc_code) {      case 0x0:	{	  /* printf("esc_code==0\n"); */	  switch (scanCode) {	  case 0xe0:	  case 0xe1:	    esc_code = scanCode;	    continue;	  default:	    if (keyCode >= num_scan) {	      printf("<? 0x0 \\x%x>", keyCode);	      return;	    }	  }	  break;	}      case 0xe0:	{	  switch (keyCode) {	  case 0x2a:		/* shift hack used by some keyboards */				/* for extra keys! */	    shift = ! shift;	  case 0x1c:		/* kpd-enter */	  case 0x1d:		/* rctrl */	  case 0x35:		/* kpd-/ */	  case 0x38:		/* ralt */	  case 0x47:		/* home */	  case 0x48:		/* uparrow */	  case 0x49:		/* pgup */	  case 0x4b:		/* left-arrow */	  case 0x4d:		/* right-arrow */	  case 0x4f:		/* end */	  case 0x50:		/* down-arrow */	  case 0x51:		/* pgdn */	  case 0x52:		/* insert */	  case 0x53:		/* del */	    esc_code = 0;	    break;	  case 0x5b:		/* lwindow */	  case 0x5c:		/* rwindow */	  case 0x5d:		/* menu */	    /* consume these transparently: */	    esc_code = 0;	    return;	  default:	    printf("<? 0xe0 \\x%x>", scanCode);	    esc_code = 0;	    return;	  }	  break;	}      case 0xe1:	{	  if (keyCode == 0x1d) {	    esc_code = scanCode;	    continue;	  }	  else {	    esc_code = 0;	    printf("<? 0xe1 \\x%x>", scanCode);	    return;	  }	  break;	}      case 0x1d:	{	  if (keyCode == 0x68) {	    /* consume transparently */	    esc_code = 0;	    return;	  }	  else {	    printf("<? 0x1d \\x%x>", scanCode);	    esc_code = 0;	    return;	  }	  break;	}      default:	printf("Unknown escape 0x%x\n", esc_code); 	break;      }            /* printf("Key code is %d (0x%x)\n", keyCode, keyCode);  */      KeyInfo& ki = key_table[keyCode];      /* printf("<kf=\\x%x,0x%x>", keyCode, ki.flags); */      if ( (ki.flags & KeyMod::IsAlpha) &&	   (ShiftState & KeyMod::AlphaLock) )	shift = !shift;      if ( (ki.flags & KeyMod::IsPad) &&	   (ShiftState & KeyMod::NumLock) )	shift = !shift;      uint32_t ndx = (shift ? 1 : 0) + (ctrl ? 2 : 0);      uint32_t ascii = ki.value[ndx];      /* keep track of shift, ctrl, alt */      if (isBreak)	ShiftState &= ~ (ki.flags & 0xf0u);      else {	ShiftState |= (ki.flags & 0xf0u);      }      /* keep track of the various lock keys on the break, not the       * keypress - the break doesn't repeat.  These are toggles, thus       * the XOR:       */      if (isBreak && (ki.flags & 0xfu)) {	ShiftState ^= (ki.flags & 0xfu);	UpdateKbdLeds();      }      if (isBreak || ascii >= NOP)	return;      /* Check for three-fingered salute: */      if ( keyCode == 0x53u && ctrl && alt)	Reboot();#ifdef OPTION_DDB      /* Check for kernel debugger: */      if ( keyCode == 0x20u && ctrl && alt)/* 20u == 'd' */	Debugger();#endif#if 1      if (kbdBufferTop == KbdBufferSz)	fatal("Keyboard buffer overflow\n");      else	kbdBuffer[kbdBufferTop++] = ascii;      KbdSleepQ.WakeAll();#else      /* If it's a printing character, just print it, otherwise       * print the hex of it:       */      if (ascii == '\r')	printf("\n");      else if (ascii >= ' ' && ascii < 127)	printf("%c", ascii);      else	printf("\\x%x", ascii);#endif    }  }}voidKeyboardInterrupt(fixregs_t *sa){  uint32_t irq = IRQ_FROM_EXCEPTION(sa->ExceptNo);  assert(irq == 1);  if (kbd_polling)    return;  FetchInputFromKeyboard();  IRQ::Enable(irq);}intGetCharFromKbd(){  assert(kbdBufferTop < KbdBufferSz);    if (kbd_polling) {    while (kbdBufferTop == 0)      FetchInputFromKeyboard();  }  if (kbdBufferTop == 0)    return 0;  int c = kbdBuffer[0];  for (uint32_t i = 1; i < kbdBufferTop; i++)    kbdBuffer[i-1] = kbdBuffer[i];  kbdBufferTop --;  return c;}static boolProbe(struct AutoConf* /* ac */) {#ifdef OPTION_KBD  IRQ::SetHandler(IRQ386::Keyboard, KeyboardInterrupt);  printf("Set up keyboard interrupt handler!\n");#else  printf("Keyboard included for debugger; handler is unbound!\n");#endif  return true;}static boolAttach(struct AutoConf* /* ac */) {#if 0  /* Establish initial keyboard state visibly: */  UpdateKbdLeds();#endif  return true;}#include <eros/Invoke.h>#include <eros/KeyboardKey.h>voidKeyboardKey(Invocation& inv){  switch (inv.entry.code) {  case OC_Keyboard_Get:    {      uint32_t len = inv.entry.w1;      if (KbdBufferSz < len)	len = KbdBufferSz;      assert(kbdBufferTop < KbdBufferSz);            if (kbdBufferTop < len) {	Thread::Current()->SleepOn(KbdSleepQ);	Thread::Current()->Yield();      }#ifndef OPTION_PURE_EXIT_STRINGS      inv.invokee->SetupExitString(inv, len);#endif      COMMIT_POINT();      inv.CopyOut(len, kbdBuffer);            for (uint32_t i = len; i < kbdBufferTop; i++)	kbdBuffer[i-len] = kbdBuffer[i];            kbdBufferTop -= len;      /* Transfer the order code: */      inv.exit.code = RC_OK;      return;    }  default:    COMMIT_POINT();    inv.exit.code = RC_UnknownRequest;    return;  }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -