📄 usbkeyboardlib.c
字号:
** RETURNS: TRUE if <key> is present in the <keyArray> passed by the* caller, else returns FALSE.*/LOCAL BOOL isKeyPresent ( pUINT16 pKeyArray, UINT16 key ) { UINT16 i; for (i = 0; i < BOOT_RPT_KEYCOUNT; i++) if (key == pKeyArray [i]) return TRUE; return FALSE; }/***************************************************************************** setLedReport - Issues a SET_REPORT to change a keyboard's LEDs** RETURNS: N/A*/LOCAL VOID setLedReport ( pUSB_KBD_SIO_CHAN pSioChan, UINT8 ledReport ) { UINT8 * pLedReport = OSS_CALLOC (sizeof (UINT8)); if (pLedReport == NULL) return; *pLedReport = ledReport; usbHidReportSet (usbdHandle, pSioChan->nodeId, pSioChan->interface, USB_HID_RPT_TYPE_OUTPUT, 0, pLedReport, sizeof (ledReport)); OSS_FREE (pLedReport); }/***************************************************************************** changeKeyState - changes keyboard state** <key> is CAPLOCK, SCRLOCK, or NUMLOCK. If <key> is not already * active, then, toggle the current keyboard state for the corresponding item.** RETURNS: N/A*/LOCAL VOID changeKbdState ( pUSB_KBD_SIO_CHAN pSioChan, UINT16 scanCode, /* not used */ pBOOL pKeyState ) { UINT8 ledReport; /* The scancode is newly active, toggle the corresponding keyboard state. */ *pKeyState = !(*pKeyState); /* Update the keyboard LEDs */ ledReport = (pSioChan->capsLock) ? RPT_LED_CAPS_LOCK : 0; ledReport |= (pSioChan->scrLock) ? RPT_LED_SCROLL_LOCK : 0; ledReport |= (pSioChan->numLock) ? RPT_LED_NUM_LOCK : 0; setLedReport (pSioChan, ledReport); }/***************************************************************************** interpScanCode - interprets keyboard scan code** Interprets the <scanCode> according to the <modifiers>. This function* handles any special requirements, such as turning an LED ON or OFF in* response to a keypress.** RETURNS: N/A.*/LOCAL void interpScanCode ( pUSB_KBD_SIO_CHAN pSioChan, UINT16 scanCode, UINT16 modifiers ) { /* If the key is already active, ignore it. */ if (isKeyPresent (pSioChan->activeScanCodes, scanCode)) return; /* Determine if special handling is required for the key */ switch (scanCode) { case CAPLOCK: /* key is CAPLOCK */ case CAPLOCK_LOCKING: /* key is CAPLOCK */ changeKbdState (pSioChan, scanCode, &pSioChan->capsLock); break; case SCRLOCK: /* key is SCRLOCK */ case SCRLOCK_LOCKING: /* key is SCRLOCK */ changeKbdState (pSioChan, scanCode, &pSioChan->scrLock); break; case NUMLOCK: /* key is NUMLOCK */ case NUMLOCK_LOCKING: /* key is NUMLOCK */ changeKbdState (pSioChan, scanCode, &pSioChan->numLock); break; case NOTKEY: /* no valid scan code mapping */ default: /* an ASCII character */ break; } }/***************************************************************************** putInChar - puts a character into channel's input queue** RETURNS: N/A*/LOCAL VOID putInChar ( pUSB_KBD_SIO_CHAN pSioChan, char putChar ) { if (pSioChan->inQueueCount < KBD_Q_DEPTH) { pSioChan->inQueue [pSioChan->inQueueIn] = putChar; if (++pSioChan->inQueueIn == KBD_Q_DEPTH) pSioChan->inQueueIn = 0; pSioChan->inQueueCount++; } }/***************************************************************************** nextInChar - returns next character from input queue** Returns the next character from the channel's input queue and updates* the queue pointers. The caller must ensure that at least one character* is in the queue prior to calling this function.** RETURNS: next char in queue*/LOCAL char nextInChar ( pUSB_KBD_SIO_CHAN pSioChan ) { char inChar = pSioChan->inQueue [pSioChan->inQueueOut]; if (++pSioChan->inQueueOut == KBD_Q_DEPTH) pSioChan->inQueueOut = 0; pSioChan->inQueueCount--; return inChar; }/***************************************************************************** updateTypematic - generates typematic characters for channel if appropriate** RETURNS: N/A*/LOCAL VOID updateTypematic ( pUSB_KBD_SIO_CHAN pSioChan ) { UINT32 diffTime; UINT32 repeatCount; /* If the given channel is active and a typematic character is * indicated, then update the typematic state. */ if (pSioChan->connected && pSioChan->typematicChar != 0) { diffTime = OSS_TIME () - pSioChan->typematicTime; /* If the typematic delay has passed, then it is time to start * injecting characters into the queue. */ if (diffTime >= TYPEMATIC_DELAY) { diffTime -= TYPEMATIC_DELAY; repeatCount = diffTime / TYPEMATIC_PERIOD + 1; /* Inject characters into the queue. If the queue is * full, putInChar() dumps the character, but we increment * the typematicCount anyway. This keeps the queue from * getting too far ahead of the user. */ while (repeatCount > pSioChan->typematicCount) { if( ISEXTENDEDKEYCODE(pSioChan->typematicChar) ) { if(pSioChan->inQueueCount < KBD_Q_DEPTH-1) { putInChar (pSioChan, (char) 0); putInChar (pSioChan, (char) pSioChan->typematicChar & 0xFF); } } else { putInChar (pSioChan, pSioChan->typematicChar); } pSioChan->typematicCount++; } /* invoke receive callback */ while (pSioChan->inQueueCount > 0 && pSioChan->putRxCharCallback != NULL && pSioChan->mode == SIO_MODE_INT) { (*pSioChan->putRxCharCallback) (pSioChan->putRxCharArg, nextInChar (pSioChan)); } } } }/***************************************************************************** interpKbdReport - interprets USB keyboard BOOT report** Interprets a keyboard boot report and updates channel state as* appropriate. Operates in one of two modes: ASCII or RAW. In ASCII mode* it inserts the ascii character into the character buffer and implements* typematic repeat. In RAW mode it always inserts the modifier byte* regardless of change, it inserts any keypresses that are currently active* and it inserts a terminating byte of 0xff into the charater buffer.** RETURNS: N/A*/LOCAL VOID interpKbdReport ( pUSB_KBD_SIO_CHAN pSioChan ) { pHID_KBD_BOOT_REPORT pReport = pSioChan->pBootReport; UINT16 keyCode; UINT16 newTypematicChar; UINT16 activeCount; UINT16 i; /* * interpret each key position in a keyboard boot report * (handles CAPS/SCROLL/NUM lock). */ for (i = 0; i < BOOT_RPT_KEYCOUNT; i++) interpScanCode (pSioChan, pReport->scanCodes [i], pReport->modifiers); /* Raw mode has been set, handle accordingly */ if (pSioChan->scanMode == SIO_KYBD_MODE_RAW) { /* The first byte is any modifier keys, CTRL, SHIFT, ALT, GUI */ putInChar (pSioChan, pReport->modifiers); for (i = 0; i < BOOT_RPT_KEYCOUNT; i++) if (pReport->scanCodes [i]) /* Any depressed keys */ putInChar (pSioChan, pReport->scanCodes [i]); /* trailing byte */ putInChar (pSioChan, 0xff); } /* then pSioChan->scanMode must = SIO_KYBD_MODE_ASCII */ else { /* insert newly activated keys into the input queue for the keyboard */ newTypematicChar = 0; activeCount = 0; for (i = 0; i < BOOT_RPT_KEYCOUNT; i++) { if (pReport->scanCodes [i]) { keyCode = cvtScanCodeToKeyCode (pSioChan, pReport->scanCodes [i], pReport->modifiers); if (!isKeyPresent (pSioChan->activeScanCodes, pReport->scanCodes [i])) { /* If there is room in the input queue, enqueue the key, * else discard it. * For extended keyCodes, make sure there is room for two * chars - the 0 and the ext key. */ if( ISEXTENDEDKEYCODE(keyCode) ) { if(pSioChan->inQueueCount < KBD_Q_DEPTH-1) { putInChar (pSioChan, (char) 0); putInChar (pSioChan, (char) keyCode & 0xFF); } } else { if(keyCode) putInChar (pSioChan, (char) keyCode & 0xFF); } } newTypematicChar = keyCode; activeCount++; } } /* * If newTypematicChar is 0, then no keys were received in * this report - so no keys are being held down. If * newTypematicChar matches the previous typematic char, * then allow the typematic timer to continue. If * newTypematicChar is different (but non-zero), then start * a new timer. In all cases, only one key may be active * for typematic repeat to be enabled. */ if (activeCount != 1) newTypematicChar = 0; if (newTypematicChar != pSioChan->typematicChar) { pSioChan->typematicChar = newTypematicChar; if (newTypematicChar != 0) { pSioChan->typematicTime = OSS_TIME (); pSioChan->typematicCount = 0; } } updateTypematic (pSioChan); } /* invoke receive callback */ while (pSioChan->inQueueCount > 0 && pSioChan->putRxCharCallback != NULL && pSioChan->mode == SIO_MODE_INT) { (*pSioChan->putRxCharCallback) (pSioChan->putRxCharArg, nextInChar (pSioChan)); } /* * Copy the current list of active keys to the channel * structure, overwriting the previous list. */ for (i = 0; i < BOOT_RPT_KEYCOUNT; i++) pSioChan->activeScanCodes [i] = pReport->scanCodes [i]; }/***************************************************************************** usbKeyboardIoctl - special device control** This routine is largely a no-op for the usbKeyboardLib. The only ioctls* which are used by this module are the SIO_AVAIL_MODES_GET and SIO_MODE_SET.** RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed* request.*/LOCAL int usbKeyboardIoctl ( SIO_CHAN *pChan, /* device to control */ int request, /* request code */ void *someArg /* some argument */ ) { pUSB_KBD_SIO_CHAN pSioChan = (pUSB_KBD_SIO_CHAN) pChan; int arg = (int) someArg; switch (request) { case SIO_BAUD_SET: /* baud rate has no meaning for USB. We store the desired * baud rate value and return OK. */ pSioChan->baudRate = arg; return OK; case SIO_BAUD_GET: /* Return baud rate to caller */ *((int *) arg) = pSioChan->baudRate; return OK; case SIO_MODE_SET: /* Set driver operating mode: interrupt or polled */ if (arg != SIO_MODE_POLL && arg != SIO_MODE_INT) return EIO; pSioChan->mode = arg; return OK; case SIO_MODE_GET: /* Return current driver operating mode for channel */ *((int *) arg) = pSioChan->mode; return OK; case SIO_AVAIL_MODES_GET: /* Return modes supported by driver. */ *((int *) arg) = SIO_MODE_INT | SIO_MODE_POLL; return OK; case SIO_OPEN: /* Channel is always open. */ return OK; case SIO_KYBD_MODE_SET: switch (arg) { case SIO_KYBD_MODE_RAW: case SIO_KYBD_MODE_ASCII: break; case SIO_KYBD_MODE_UNICODE: return ENOSYS; /* usb doesn't support unicode */ } pSioChan->scanMode = arg; return OK; case SIO_KYBD_MODE_GET: *(int *)someArg = pSioChan->scanMode; return OK; case SIO_KYBD_LED_SET: { UINT8 ledReport; /* update the channel's information about the LED state */ pSioChan->numLock = (arg & SIO_KYBD_LED_NUM) ? SIO_KYBD_LED_NUM : 0; pSioChan->capsLock = (arg & SIO_KYBD_LED_CAP) ? SIO_KYBD_LED_CAP : 0; pSioChan->scrLock = (arg & SIO_KYBD_LED_SCR) ? SIO_KYBD_LED_SCR : 0; /* * We are relying on the SIO_KYBD_LED_X macros matching the USB * LED equivelants. */ ledReport = arg; /* set the LED's */ setLedReport (pSioChan, ledReport); return OK; } case SIO_KYBD_LED_GET: { int tempArg; tempArg = (pSioChan->capsLock) ? SIO_KYBD_LED_CAP : 0; tempArg |= (pSioChan->scrLock) ? SIO_KYBD_LED_SCR : 0; tempArg |= (pSioChan->numLock) ? SIO_KYBD_LED_NUM : 0; *(int *) someArg = tempArg; return OK; } case SIO_HW_OPTS_SET: /* optional, not supported */ case SIO_HW_OPTS_GET: /* optional, not supported */ case SIO_HUP: /* hang up is not supported */ default: /* unknown/unsupported command. */ return ENOSYS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -