terminalconin.c

来自「Next BIOS Source code : Extensible Firmw」· C语言 代码 · 共 1,089 行 · 第 1/2 页

C
1,089
字号
}

BOOLEAN
IsEfiKeyFiFoFull (
  TERMINAL_DEV  *TerminalDevice
  )
/*++
    Clarify whether FIFO buffer is full.
--*/  
{
  UINT8   Tail;
  UINT8   Head;

  Tail = TerminalDevice->EfiKeyFiFo.Tail ;
  Head = TerminalDevice->EfiKeyFiFo.Head ;

  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
    
    return TRUE;
  }

  return FALSE;
}

BOOLEAN
UnicodeFiFoInsertOneKey (
  TERMINAL_DEV      *TerminalDevice,
  UINT16            Input
  )
/*++
    Insert one pre-fetched key into the FIFO buffer.
    If FIFO buffer is FULL before key insertion,
    return FALSE, and the key is lost.
--*/  
{
  UINT8 Tail;

  Tail = TerminalDevice->UnicodeFiFo.Tail;
  
  if (IsUnicodeFiFoFull(TerminalDevice)) {
    
    //
    // Unicode FIFO is full
    //
    return FALSE;
  }

  TerminalDevice->UnicodeFiFo.Data[Tail] = Input;

  TerminalDevice->UnicodeFiFo.Tail = (UINT8)((Tail + 1) 
                                     % (FIFO_MAX_NUMBER + 1));

  return TRUE;
}

BOOLEAN
UnicodeFiFoRemoveOneKey (
  TERMINAL_DEV  *TerminalDevice,
  UINT16        *Output
  )
/*++
    Remove one pre-fetched key out of the FIFO buffer.
    If FIFO buffer is empty before remove operation,
    return FALSE.
--*/  
{
  UINT8 Head;
  
  Head = TerminalDevice->UnicodeFiFo.Head;

  if (IsUnicodeFiFoEmpty(TerminalDevice)) {
  
    //
    //  FIFO is empty
    //
    Output = NULL;
    return FALSE;
  }

  *Output = TerminalDevice->UnicodeFiFo.Data[Head] ;

  TerminalDevice->UnicodeFiFo.Head = (UINT8)((Head + 1) 
                                      % (FIFO_MAX_NUMBER + 1)) ;

  return TRUE;
}

BOOLEAN
IsUnicodeFiFoEmpty (
  TERMINAL_DEV  *TerminalDevice
  )
/*++
    Clarify whether FIFO buffer is empty.
--*/  
{
  if (TerminalDevice->UnicodeFiFo.Head == TerminalDevice->UnicodeFiFo.Tail) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

BOOLEAN
IsUnicodeFiFoFull (
  TERMINAL_DEV  *TerminalDevice
  )
/*++
    Clarify whether FIFO buffer is full.
--*/  
{
  UINT8   Tail;
  UINT8   Head;

  Tail = TerminalDevice->UnicodeFiFo.Tail ;
  Head = TerminalDevice->UnicodeFiFo.Head ;

  if (((Tail + 1) % (FIFO_MAX_NUMBER + 1)) == Head) {
    
    return TRUE;
  }

  return FALSE;
}

UINT8
UnicodeFiFoGetKeyCount (
  TERMINAL_DEV    *TerminalDevice
  )
/*++
--*/
{
  UINT8   Tail;
  UINT8   Head;
  
  Tail = TerminalDevice->UnicodeFiFo.Tail ;
  Head = TerminalDevice->UnicodeFiFo.Head ;
  
  if (Tail >= Head) {
    return (UINT8)(Tail - Head);
  } else {
    return (UINT8)(Tail + FIFO_MAX_NUMBER + 1 - Head);
  }
}   

VOID
UnicodeToEfiKeyFlushState (
  IN  TERMINAL_DEV    *TerminalDevice
  )

{
  EFI_INPUT_KEY  Key;

  if (TerminalDevice->InputState & INPUT_STATE_ESC) {
    Key.ScanCode = SCAN_ESC;
    Key.UnicodeChar = 0 ;
    EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
  }

  if (TerminalDevice->InputState & INPUT_STATE_CSI) {
    Key.ScanCode = SCAN_NULL;
    Key.UnicodeChar = CSI;
    EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
  }

  if (TerminalDevice->InputState & INPUT_STATE_LEFTOPENBRACKET) {
    Key.ScanCode = SCAN_NULL;
    Key.UnicodeChar = LEFTOPENBRACKET;
    EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
  }

  if (TerminalDevice->InputState & INPUT_STATE_O) {
    Key.ScanCode = SCAN_NULL;
    Key.UnicodeChar = 'O';
    EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
  }

  if (TerminalDevice->InputState & INPUT_STATE_2) {
    Key.ScanCode = SCAN_NULL;
    Key.UnicodeChar = '2';
    EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
  }

  gBS->SetTimer(
         TerminalDevice->TwoSecondTimeOut,
         TimerCancel,
         0
         );

  TerminalDevice->InputState = INPUT_STATE_DEFAULT;
}


VOID
UnicodeToEfiKey (
  IN  TERMINAL_DEV    *TerminalDevice
  )
/*++
  Routine Description:
  
    Converts a stream of Unicode characters from a terminal input device into EFI Keys that
    can be read through the Simple Input Protocol.  The table below shows the keyboard
    input mappings that this function supports.  If the ESC sequence listed in one of the 
    columns is presented, then it is translated into the coorespoding EFI Scan Code.  If a
    matching sequence is not found, then the raw key strokes are converted into EFI Keys.
    
    2 seconds are allowed for an ESC sequence to be completed.  If the ESC sequence is not 
    completed in 2 seconds, then the raw key strokes of the partial ESC sequence are 
    converted into EFI Keys.
    
    There is one special input sequence that will force the system to reset.  
    This is ESC R ESC r ESC R.
  
  Arguments:

    TerminaDevice : The terminal device to use to translate raw input into EFI Keys
        
  Returns:

    None

Symbols used in table below
===========================
  ESC = 0x1B	
  CSI = 0x9B	
  DEL = 0x7f	
  ^   = CTRL

+=========+======+===========+=========+===========+============+===========+=========+=======+=====+
|         | EFI  | EFI 1.10  |EFI 1.10 |           |            |           |         |       |     |
|         | Scan |           |  ANSI   |           |            |           |         |VT100+ |     |
|   KEY   | Code |  PC ANSI  | X3.64   |           |            |           |         |VTUTF8 |Other|
+=========+======+===========+=========+===========+============+===========+=========+=======+=====+
| NULL    | 0x00 |           |         |           |            |           |         |       |     |
| UP      | 0x01 | ESC [ A   | CSI A   |           |            | ESC O A tlm|         |       |     |
| DOWN    | 0x02 | ESC [ B   | CSI B   |           |            | ESC O B tlm|         |       |     |
| RIGHT   | 0x03 | ESC [ C   | CSI C   |           |            | ESC O C tlm|         |       |     | 
| LEFT    | 0x04 | ESC [ D   | CSI D   |           |            | ESC O D tlm|         |       |     |
| HOME    | 0x05 | ESC [ H   | CSI H   |           |            |           |         | ESC h	|     |
| END     | 0x06 | ESC [ K   | CSI K   |           |            |           |         | ESC k	|     |
| INSERT  | 0x07 | ESC [ @   | CSI @   | ESC [ L   |  CSI L     |           |         | ESC +	|     |
| DELETE  | 0x08 | ESC [ P   | CSI P   |           |            |           |         | ESC - | DEL |
| PG UP   | 0x09 | ESC [ ?   | CSI ?   | ESC [ V   |  CSI V     | ESC [ M   | CSI M   | ESC ?	|     |
| PG DOWN | 0x0A | ESC [ /   | CSI /   | ESC [ U   |  CSI U     | ESC [ 2 J | CSI 2 J | ESC /	|     |
| F1      | 0x0B | ESC [ O P | CSI O P |           |            | ESC O P   |         | ESC 1	|     |
| F2      | 0x0C | ESC [ O Q | CSI O Q |           |            | ESC O Q   |         | ESC 2	|     |
| F3      | 0x0D | ESC [ O w | CSI O w | ESC [ O R |  CSI O R	| ESC O R   |         | ESC 3	|     |
| F4      | 0x0E | ESC [ O x | CSI O x | ESC [ O S |  CSI O S	| ESC O S   |         | ESC 4	|     |
| F5      | 0x0F | ESC [ O t | CSI O t | ESC [ O T |  CSI O T	| ESC O T   |         | ESC 5	|     |
| F6      | 0x10 | ESC [ O u | CSI O u | ESC [ O U |  CSI O U	| ESC O U   |         | ESC 6	|     |
| F7      | 0x11 | ESC [ O q | CSI O q | ESC [ O V |  CSI O V	| ESC O V   |         | ESC 7	|     |
| F8      | 0x12 | ESC [ O r | CSI O r | ESC [ O W |  CSI O W	| ESC O W   |         | ESC 8	|     |
| F9      | 0x13 | ESC [ O p | CSI O p | ESC [ O X |  CSI O X	| ESC O X   |         | ESC 9	|     |
| F10     | 0x14 | ESC [ O M | CSI O M | ESC [ O Y |  CSI O Y	| ESC O Y   |         | ESC 0	|     |
| Escape	| 0x17 | ESC       |         |           |          |           |         |       | ^[  |
+=========+======+===========+=========+===========+==========+===========+=========+=======+=====+

Special Mappings
================
ESC R ESC r ESC R = Reset System
								 
--*/
{
  EFI_STATUS          Status;
  EFI_STATUS          TimerStatus;
  UINT16              UnicodeChar;
  EFI_INPUT_KEY       Key;
  BOOLEAN             SetDefaultResetState;
  
  TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);

  if (!EFI_ERROR (TimerStatus)) {
    UnicodeToEfiKeyFlushState (TerminalDevice);
    TerminalDevice->ResetState = RESET_STATE_DEFAULT;
  }

  while (!IsUnicodeFiFoEmpty(TerminalDevice)) {
    
    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
      //
      // Check to see if the 2 second timer has expired
      //
      TimerStatus = gBS->CheckEvent (TerminalDevice->TwoSecondTimeOut);
      if (!EFI_ERROR (TimerStatus)) {
        UnicodeToEfiKeyFlushState (TerminalDevice);
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
      }
    }

    //
    // Fetch one Unicode character from the Unicode FIFO
    //
    UnicodeFiFoRemoveOneKey (TerminalDevice,&UnicodeChar);

    SetDefaultResetState = TRUE;

    switch (TerminalDevice->InputState) {
    case INPUT_STATE_DEFAULT:

      break;

    case INPUT_STATE_ESC:

      if (UnicodeChar == LEFTOPENBRACKET) {
        TerminalDevice->InputState |= INPUT_STATE_LEFTOPENBRACKET;
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
        continue;
      }

      if (UnicodeChar == 'O') {
        TerminalDevice->InputState |= INPUT_STATE_O;
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
        continue;
      }

      switch (UnicodeChar) {
      case '1': Key.ScanCode = SCAN_F1;         break;
      case '2': Key.ScanCode = SCAN_F2;         break;
      case '3': Key.ScanCode = SCAN_F3;         break;
      case '4': Key.ScanCode = SCAN_F4;         break;
      case '5': Key.ScanCode = SCAN_F5;         break;
      case '6': Key.ScanCode = SCAN_F6;         break;
      case '7': Key.ScanCode = SCAN_F7;         break;
      case '8': Key.ScanCode = SCAN_F8;         break;
      case '9': Key.ScanCode = SCAN_F9;         break;
      case '0': Key.ScanCode = SCAN_F10;        break;
      case 'h': Key.ScanCode = SCAN_HOME;       break;
      case 'k': Key.ScanCode = SCAN_END;        break;
      case '+': Key.ScanCode = SCAN_INSERT;     break;
      case '-': Key.ScanCode = SCAN_DELETE;     break;
      case '/': Key.ScanCode = SCAN_PAGE_DOWN;  break;
      case '?': Key.ScanCode = SCAN_PAGE_UP;    break;
      case 'R': if (TerminalDevice->ResetState == RESET_STATE_DEFAULT) {
                  TerminalDevice->ResetState = RESET_STATE_ESC_R;
                  SetDefaultResetState = FALSE;
                } else if (TerminalDevice->ResetState == RESET_STATE_ESC_R_ESC_r) {
                  gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
                }
                Key.ScanCode = SCAN_NULL;
                break;
      case 'r': if (TerminalDevice->ResetState == RESET_STATE_ESC_R) {
                  TerminalDevice->ResetState = RESET_STATE_ESC_R_ESC_r;
                  SetDefaultResetState = FALSE;
                }
                Key.ScanCode = SCAN_NULL;
                break;
      default : Key.ScanCode = SCAN_NULL;       break;
      }

      if (SetDefaultResetState) {
        TerminalDevice->ResetState = RESET_STATE_DEFAULT;
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    case INPUT_STATE_ESC | INPUT_STATE_O:

      TerminalDevice->ResetState = RESET_STATE_DEFAULT;

      switch (UnicodeChar) {
	  
      case 'D': Key.ScanCode = SCAN_LEFT;       break; //tlm
      case 'A': Key.ScanCode = SCAN_UP;       	break;
      case 'C': Key.ScanCode = SCAN_RIGHT;      break;
      case 'B': Key.ScanCode = SCAN_DOWN;       break;
      case 'P': Key.ScanCode = SCAN_F1;         break;
      case 'Q': Key.ScanCode = SCAN_F2;         break;
      case 'R': Key.ScanCode = SCAN_F3;         break;
      case 'S': Key.ScanCode = SCAN_F4;         break;
      case 'T': Key.ScanCode = SCAN_F5;         break;
      case 'U': Key.ScanCode = SCAN_F6;         break;
      case 'V': Key.ScanCode = SCAN_F7;         break;
      case 'W': Key.ScanCode = SCAN_F8;         break;
      case 'X': Key.ScanCode = SCAN_F9;         break;
      case 'Y': Key.ScanCode = SCAN_F10;        break;
      default : Key.ScanCode = SCAN_NULL;       break;
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET:
    case INPUT_STATE_CSI:

      TerminalDevice->ResetState = RESET_STATE_DEFAULT;

      if (UnicodeChar == 'O') {
        TerminalDevice->InputState |= INPUT_STATE_O;
        continue;
      }

      if (UnicodeChar == '2') {
        TerminalDevice->InputState |= INPUT_STATE_2;
        continue;
      }

      switch (UnicodeChar) {
      case 'A': Key.ScanCode = SCAN_UP;         break;
      case 'B': Key.ScanCode = SCAN_DOWN;       break;
      case 'C': Key.ScanCode = SCAN_RIGHT;      break;
      case 'D': Key.ScanCode = SCAN_LEFT;       break;
      case 'H': Key.ScanCode = SCAN_HOME;       break;
      case 'K': Key.ScanCode = SCAN_END;        break;
      case 'L':   
      case '@': Key.ScanCode = SCAN_INSERT;     break;
      case 'P': Key.ScanCode = SCAN_DELETE;     break;
      case 'M':   
      case 'V':   
      case '?': Key.ScanCode = SCAN_PAGE_UP;    break;
      case 'U':   
      case '/': Key.ScanCode = SCAN_PAGE_DOWN;  break;
      default : Key.ScanCode = SCAN_NULL;       break;
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_2:
    case INPUT_STATE_CSI | INPUT_STATE_2:

      TerminalDevice->ResetState = RESET_STATE_DEFAULT;

      if (UnicodeChar == 'J') {
        Key.ScanCode    = SCAN_PAGE_DOWN;
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    case INPUT_STATE_ESC | INPUT_STATE_LEFTOPENBRACKET | INPUT_STATE_O:
    case INPUT_STATE_CSI | INPUT_STATE_O:

      TerminalDevice->ResetState = RESET_STATE_DEFAULT;

      switch (UnicodeChar) {
      case 'P': Key.ScanCode = SCAN_F1;   break;
      case 'Q': Key.ScanCode = SCAN_F2;   break;
      case 'R': 
      case 'w': Key.ScanCode = SCAN_F3;   break;
      case 'S':
      case 'x': Key.ScanCode = SCAN_F4;   break;
      case 'T':
      case 't': Key.ScanCode = SCAN_F5;   break;
      case 'U':
      case 'u': Key.ScanCode = SCAN_F6;   break;
      case 'V':
      case 'q': Key.ScanCode = SCAN_F7;   break;
      case 'W':
      case 'r': Key.ScanCode = SCAN_F8;   break;
      case 'X':
      case 'p': Key.ScanCode = SCAN_F9;   break;
      case 'Y':
      case 'M': Key.ScanCode = SCAN_F10;  break;
      default : Key.ScanCode = SCAN_NULL; break;
      }

      if (Key.ScanCode != SCAN_NULL) {
        Key.UnicodeChar = 0;
        EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
        TerminalDevice->InputState = INPUT_STATE_DEFAULT;
        UnicodeToEfiKeyFlushState (TerminalDevice);
        continue;
      }

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;

    default:
      //
      // Invalid state. This should never happen.
      //
      ASSERT (FALSE);

      UnicodeToEfiKeyFlushState (TerminalDevice);

      break;
    }

    if (UnicodeChar == ESC) {
      TerminalDevice->InputState = INPUT_STATE_ESC;
    }
    if (UnicodeChar == CSI) {
      TerminalDevice->InputState = INPUT_STATE_CSI;
    }
    if (TerminalDevice->InputState != INPUT_STATE_DEFAULT) {
      Status = gBS->SetTimer(
                      TerminalDevice->TwoSecondTimeOut,
                      TimerRelative,
                      (UINT64)20000000
                      );
      continue;
    }

    if (SetDefaultResetState) {
      TerminalDevice->ResetState = RESET_STATE_DEFAULT;
    }

    if (UnicodeChar == DEL) {
      Key.ScanCode    = SCAN_DELETE;
      Key.UnicodeChar = 0;
    } else {
      Key.ScanCode    = SCAN_NULL;
      Key.UnicodeChar = UnicodeChar;
    }

    EfiKeyFiFoInsertOneKey (TerminalDevice,Key);
  }
}   

⌨️ 快捷键说明

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