Skip to content

Instantly share code, notes, and snippets.

@houmei
Created July 5, 2012 22:56
Show Gist options
  • Save houmei/3056964 to your computer and use it in GitHub Desktop.
Save houmei/3056964 to your computer and use it in GitHub Desktop.
PS/2Keyboard for Arduino Uno/Leonardo 20120706 test
20120706
・PS/2 Scancode → USB UID変換まで済み。(PrtScn/PauseBrkを除く)
・ソース中にゴミ多数。
□ハードウェア
★マイコン選定(AVR ATmega32U4搭載 Arduino Leonard互換ボード)
 ■Davinci 確認済 http://strawberry-linux.com/catalog/items?code=25005
 ■Arduino Leonardo 確認済 http://www.switch-science.com/products/detail.php?product_id=967
 □32U4ボード 入手済、未確認 http://www.switch-science.com/products/detail.php?product_id=865
 ※sparkfun ATmega32U4モジュール 今回は使わない http://www.switch-science.com/products/detail.php?product_id=982
★PS/2ポートのPullUp抵抗無くせるか 設定確認→出力にもなるので設定は不可、ただし無くても動く
☆ケース組み込み
□ソフトウェア
■構造
 ■PS/2キーボード入出力はArduinoのライブラリとして構成 → arduino.cc playgroundのps2keyboard/ps2keyboardext2を参考
 ■USB HIDキーボード出力はArduinoIDE1.0.1の機能を利用
 ★スキャンコード→USBのコードへの変換はスケッチで行う→ 可変長scancode→固定長USB UIDに変換
■調査
 ★[全角半角]+[Alt]は[全角半角]動作と同じか(Windows日本語キーボード)→ 同じ
・ライブラリ
□PS/2キーボード入力
 ■PS/2キーボードのスキャンコード Type2決め打ちでOK(Type1は古い機種、Type3は特殊で使われない)
 ■スキャンコードを直接扱うrawread()を追加→作成済 Unoで確認済
 ■スキャンコードをFIFOに入れる→キー取りこぼし対策 Unoで確認済
 ■PS2KeyboardExt2をベースにTeensyのPS/2ライブラリの割り込み部分を組み込む
 ★スキャンコード PS/2-US→USB-HID変換
 ★Num/Caps/ScrLock時挙動
 ☆PrintScreen/Alt+PrintScreen
 □Pause(ただしPrintScreenができればたいしたことはない)
 □ステータス保持→スケッチからLockステータスの送信
 □一般向けキー対応表
□PS/2キーボード出力
 □コマンド送出 キーボード本体のLED制御
 □コマンド送出 キーボードリピート設定
・スケッチ
□スキャンコード マルチメディア系の追加キー
☆make/release制御 USBは同時押し6個まで、PS/2は無制限 この調整
/*
http://arduino.cc/playground/Main/PS2Keyboard
http://arduino.cc/playground/Main/PS2KeyboardExt2
http://msdn.microsoft.com/en-us/library/windows/hardware/gg463446.aspx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "Arduino.h"
#include "PS2kybd.h"
#include "binary.h"
#define HID_USAGEPAGE 0x0700
// Scancode FIFO
#define BUFFER_SIZE 64
static volatile uint8_t Buffer[BUFFER_SIZE];
static volatile uint8_t Head, Tail;
// Modifier
#define PS2_MOD_CTRL_R 1
#define PS2_MOD_SHIFT_R 2
#define PS2_MOD_ALT_R 4
#define PS2_MOD_META_R 8
#define PS2_MOD_CTRL_L 16
#define PS2_MOD_SHIFT_L 32
#define PS2_MOD_ALT_L 64
#define PS2_MOD_META_L 128
const uint8_t MODIFIERBIT[8] = {
PS2_MOD_CTRL_L,PS2_MOD_SHIFT_L,PS2_MOD_ALT_L,PS2_MOD_META_L,
PS2_MOD_CTRL_R,PS2_MOD_SHIFT_R,PS2_MOD_ALT_R,PS2_MOD_META_R
} ;
static volatile uint8_t Modifier;
// Lock status
#define PS2_LOCK_CAPS 1
#define PS2_LOCK_NUM 2
#define PS2_LOCK_SCR 4
#define PS2_LOCK_KANA 8
static volatile uint8_t Lock;
// scancode extend,release
static volatile uint8_t Extend;
static volatile uint8_t Release;
static volatile uint8_t PrtScr;
static volatile uint8_t Pause;
int ps2Keyboard_DataPin;
// variables used to remember information about key presses
volatile bool ps2Keyboard_shift; // indicates shift key is pressed
volatile bool ps2Keyboard_ctrl; // indicates the ctrl key is pressed
volatile bool ps2Keyboard_alt; // indicates the alt key is pressed
volatile bool ps2Keyboard_extend; // remembers a keyboard extended char received
volatile bool ps2Keyboard_release; // distinguishes key presses from releases
volatile bool ps2Keyboard_caps_lock; // remembers shift lock has been pressed
// vairables used in sending command bytes to the keyboard, eg caps_lock light
volatile bool cmd_in_progress;
volatile int cmd_count;
uint8_t cmd_value;
volatile uint8_t cmd_ack_value;
uint8_t cmd_parity;
volatile bool cmd_ack_byte_ok;
#define PS2TBLSIZE 256
#define EXTTBLOFFSET 0x80
const uint8_t PS2UID[PS2TBLSIZE] = {
// no Extend 16x9 = 144bytes
0xFF,0x42,0x00,0x3e,0x3c,0x3a,0x3b,0x45,0x68,0x43,0x41,0x3f,0x3d,0x2b,0x35,0x67, // "" F9 "" F5 F3 F1 F2 F12 F13 F10 F8 F6 F4 TAB ` K=
0x69,0xe2,0xe1,0x00,0xe0,0x14,0x1e,0x00,0x6a,0x00,0x1d,0x16,0x04,0x1a,0x1f,0x00, // F14 ALT SFT "" CTRL Q 1 "" F15 Z S A W 2 ""
0x6b,0x06,0x1b,0x07,0x08,0x21,0x20,0x00,0x6c,0x2c,0x19,0x09,0x17,0x15,0x22,0x00, // F16 C X D E 4 3 "" F17 SPC V F T R S ""
0x6d,0x11,0x05,0x0b,0x0a,0x1c,0x23,0x00,0x6e,0x00,0x10,0x0d,0x18,0x24,0x25,0x00, // F18 N B H G Y 6 "" F19 "" M J U 7 8 ""
0x6f,0x36,0x0e,0x0c,0x12,0x27,0x26,0x00,0x70,0x37,0x38,0x0f,0x33,0x13,0x2d,0x00, // F20 ,< K I O 0 9 F21 .> /? L ;: P -_ ""
0x71,0x00,0x34,0x00,0x2f,0x2e,0x00,0x72,0x39,0xe5,0x28,0x30,0x00,0x31,0x00,0x73, // F22 "" '" "" [{ =+ "" F23 Cap RSFT Ret ]} "" | "" F24
0x00,0x00,0x00,0x00,0x00,0x00,0x2a,0x00,0x00,0x59,0x00,0x5c,0x5f,0x00,0x00,0x00, // "" "" "" "" "" "" BS "" "" K1 "" K4 K7 "" "" ""
0x62,0x63,0x5a,0x5d,0x5e,0x60,0x29,0x53,0x44,0x57,0x5b,0x56,0x55,0x61,0x47,0x00, // K0 K. K2 K5 K6 K8 ESC NumLk F11 K+ K3 K- K9 ScrLk
0xFE,0x00,0x00,0x40,0x46,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "" "" "" F7 Alt+PrtScn
// Extend E010 - E07F
0x00,0xE6,0x46,0x00,0xe4,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe3, // "" ALT-R PrtScr(1) "" CTRL-R ... META-L
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe7,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x65, // META-R App
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // KeyboardPower
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x00,0x00,0x00,0x00,0x00, // K/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00, // Enter
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4d,0x00,0x50,0x4a,0x00,0x00,0x00, // End L-arrow Home
0x49,0x4c,0x51,0x00,0x4f,0x52,0x00,0x00,0x00,0x00,0x4e,0x46,0x00,0x4b,0x00,0x48 // Ins Del D-arrow R-arrow U-arrow PD PrtScn(2) UP Break
} ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// subroutines
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// odd parity
uint8_t odd_parity(uint8_t val) {
val ^= val>>4; val ^= val>>2; val ^= val>>1; return (~val) & 1;
}
void v_modifier_initialize() {
Extend = 0;
Release = 0;
Modifier = 0;
PrtScr = 0; // E0 12 E0 7C / E0 F0 7C E0 F0 12
Pause = 0; // Pause - E1 14 77 E1 F0 14 F0 77 (stop keyboard repeat)
Lock = 0; // 0000:Kana:Caps:Num:Scroll
ps2Keyboard_shift = false;
ps2Keyboard_ctrl = false;
ps2Keyboard_alt = false;
ps2Keyboard_extend = false;
ps2Keyboard_release = false;
ps2Keyboard_caps_lock = false;
}
void v_initialize() {
v_modifier_initialize();
// reset all the global variables
cmd_in_progress = false;
cmd_count = 0;
cmd_value = 0;
cmd_ack_value = 1;
}
static inline uint8_t get_scan_code(void) {
uint8_t c, i;
i = Tail;
if (i == Head) return 0;
i++;
if (i >= BUFFER_SIZE) i = 0;
c = Buffer[i];
Tail = i;
return c;
}
// The ISR for the external interrupt
void ps2interrupt(void)
{
static uint8_t bitcount=0;
static uint8_t incoming=0;
static uint32_t prev_ms=0;
uint32_t now_ms;
uint8_t n, val;
val = digitalRead(ps2Keyboard_DataPin);
now_ms = millis();
if (now_ms - prev_ms > 250) {
bitcount = 0;
incoming = 0;
}
prev_ms = now_ms;
n = bitcount - 1;
if (n <= 7) {
incoming |= (val << n);
}
bitcount++;
if (bitcount == 11) {
uint8_t i = Head + 1;
if (i >= BUFFER_SIZE) i = 0;
if (i != Tail) {
Buffer[i] = incoming;
Head = i;
}
bitcount = 0;
incoming = 0;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void set_modifier(uint8_t userid) { // E0-E7 L-CTRL:L-SFT:L-ALT:L-META:R-CTRL:R-SFT:R-ALT:R-META
uint8_t b;
if (userid>=0xe0 && userid<=0xe7) {
b = MODIFIERBIT[userid-0xe0];
Modifier = Release?(Modifier & ~b):(Modifier | b);
}
}
void set_lock(uint8_t userid) { // Caps,Num,Scroll
if (Release) return;
switch(userid) {
case 0x39: {
Lock ^= PS2_LOCK_CAPS;
break;
}
case 0x53: {
Lock ^= PS2_LOCK_NUM;
break;
}
case 0x47: {
Lock ^= PS2_LOCK_SCR;
break;
}
}
}
void kbd_send_command(uint8_t val) {
// stop interrupt routine from receiving characters so that we can use it
// to send a byte
cmd_in_progress = true;
cmd_count = 0;
// set up the byte to shift out and initialise the ack bit
cmd_value = val;
cmd_ack_value = 1; // the kbd will clear this bit on receiving the byte
cmd_parity = odd_parity(val);
// set the data pin as an output, ready for driving
digitalWrite(ps2Keyboard_DataPin, HIGH);
pinMode(ps2Keyboard_DataPin, OUTPUT);
// drive clock pin low - this is going to generate the first
// interrupt of the shifting out process
pinMode(PS2_INT_PIN, OUTPUT);
digitalWrite(PS2_INT_PIN, LOW);
// wait at least one clock cycle (in case the kbd is mid transmission)
delayMicroseconds(60);
// set up the 0 start bit
digitalWrite(ps2Keyboard_DataPin, LOW);
// let go of clock - the kbd takes over driving the clock from here
digitalWrite(PS2_INT_PIN, HIGH);
pinMode(PS2_INT_PIN, INPUT);
// wait for interrupt routine to shift out byte, parity and receive ack bit
while (cmd_ack_value!=0) ;
// switch back to the interrupt routine receiving characters from the kbd
cmd_in_progress = false;
}
// val : bit_3=KANA_lock, bit_2=caps_lock, bit_1=num_lock, bit_0=scroll_lock
void kbd_set_lights(uint8_t val) {
// When setting the lights with the 0xED command the keyboard responds
// with an "ack byte", 0xFA. This is NOT the same as the "ack bit" that
// follows the succesful shifting of each command byte. See this web
// page for a good description of all this:
// http://www.beyondlogic.org/keyboard/keybrd.htm
cmd_ack_byte_ok = false; // initialise the ack byte flag
kbd_send_command(0xED); // send the command byte
while (!cmd_ack_byte_ok) ; // ack byte from keyboard sets this flag
kbd_send_command(val); // now send the data
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// PS2Keyboard
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PS2Keyboard::PS2Keyboard() {
// nothing to do here
}
void PS2Keyboard::reset() {
kbd_send_command(0xFF); // send the kbd reset code to the kbd: 3 lights
// should flash briefly on the kbd
v_initialize();
}
void PS2Keyboard::begin(int dataPin) {
v_initialize();
// Prepare the global variables
ps2Keyboard_DataPin = dataPin;
// initialize the pins
pinMode(PS2_INT_PIN, INPUT);
digitalWrite(PS2_INT_PIN, HIGH);
pinMode(dataPin, INPUT);
digitalWrite(dataPin, HIGH);
attachInterrupt(PS2_INT_NUM, ps2interrupt, FALLING);
#if 0
// Global Enable INT1 interrupt
EIMSK |= ( 1 << INT1);
// Falling edge triggers interrupt
EICRA |= (0 << ISC10) | (1 << ISC11);
#endif
}
bool PS2Keyboard::available() {
if (Tail == Head) return 0;
return 1 ;
}
// This routine allows a calling program to see if other other keys are held
// down when a character is received: ie <ctrl>, <alt>, <shift> or <shift_lock>
// Note that this routine must be called after available() has returned true,
// but BEFORE read(). The read() routine clears the buffer and allows another
// character to be received so these bits can change anytime after the read().
uint8_t PS2Keyboard::read_extra() {
return (ps2Keyboard_caps_lock<<3) | (ps2Keyboard_shift<<2) | (ps2Keyboard_alt<<1) | ps2Keyboard_ctrl;
}
uint8_t PS2Keyboard::rawread() {
return get_scan_code() ;
}
uint8_t PS2Keyboard::modifier() {
return Modifier ;
}
uint8_t PS2Keyboard::lock() {
return Lock ;
}
uint16_t PS2Keyboard::readuid() {
uint8_t c;
uint16_t uid;
uint8_t cc;
uid=0;
while(c=get_scan_code()){
cc=c;
switch(c) {
case 0xF0: { // key Release
Release = 1;
break;
}
case 0xFA: { // command ACK_BYTE
cmd_ack_byte_ok = true;
break;
}
case 0xE0: { // key Extend
Extend = 1;
break;
}
default: { // Lookup Table
if (Extend) c+=EXTTBLOFFSET;
uid=PS2UID[c];
set_modifier(uid); // CTRL,SHIFT,ALT,META status
set_lock(uid); // KANA,Caps,Num,Scroll
// PrtScr E0 12 E0 7C / E0 F0 7C E0 F0 12
// Pause - E1 14 77 E1 F0 14 F0 77 (stop keyboard repeat)
if (Release) uid |= 0x8000;
Extend=0;
Release=0;
return uid?(uid | HID_USAGEPAGE):0x5555 ; // 0x5555:TABLE ERROR(for debug)
}
}
}
return uid?(uid | HID_USAGEPAGE):0 ;
}
uint8_t PS2Keyboard::read() {
uint8_t result;
// result = getfifo() ; // read the raw data from the keyboard
// Use a switch for the code to character conversion.
// This is fast and actually only uses 4 bytes per simple line
switch (result) {
case 0x58:
// setting the keyboard lights is done here. Ideally it would be done
// in the interrupt routine itself and the key codes associated wth
// caps lock key presses would never be passed on as characters.
// However it would make the interrupt routine very messy with lots
// of extra state associated with the control of a caps_lock
// key code causing a cmd byte to transmit, causing an ack_byte to
// be received, then a data byte to transmit. Much easier done here.
// The downside, however, is that the light going on or off at the
// right time relies on the calling program to be checking for
// characters on a regular basis. If the calling program stops
// polling for characters at any point pressing the caps lock key
// will not change the state of the caps lock light while polling
// is not happening.
result = ps2Keyboard_caps_lock? PS2_KC_CLON : PS2_KC_CLOFF;
if (ps2Keyboard_caps_lock) kbd_set_lights(4);
else kbd_set_lights(0);
break;
// Reset the shift counter for unexpected values, to get back into sink
// This allows for hot plugging a keyboard in and out
default: delay(500); // but wait a bit in case part way through a shift
v_modifier_initialize();
} // end switch(result)
// shift a-z chars here (less code than in the switch statement)
if (((result>='a') && (result<='z')) &&
((ps2Keyboard_shift && !ps2Keyboard_caps_lock) ||
(!ps2Keyboard_shift && ps2Keyboard_caps_lock))) {
result = result + ('A'-'a');
}
return(result);
}
/*
PS2Keyboard.h - PS2Keyboard library
Copyright (c) 2007 Free Software Foundation. All right reserved.
Written by Christian Weichel <info@32leaves.net>
** Modified for use with Arduino 13 by L. Abraham Smith, <n3bah@microcompdesign.com> *
** Modified to include: shift, alt, caps_lock and caps_lock light by Bill Oldfield *
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef PS2Keyboard_h
#define PS2Keyboard_h
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
/*
* PS2 keyboard "make" codes to check for certain keys.
*/
// Give these codes that aren't used by anything else
// Making all the control key codes above 0x80 makes it simple to check for
// printable characters at the calling level.
#define PS2_KC_BKSP 0x80
#define PS2_KC_UP 0x81
#define PS2_KC_DOWN 0x82
#define PS2_KC_LEFT 0x83
#define PS2_KC_RIGHT 0x84
#define PS2_KC_PGDN 0x85
#define PS2_KC_PGUP 0x86
#define PS2_KC_END 0x87
#define PS2_KC_HOME 0x88
#define PS2_KC_INS 0x89
#define PS2_KC_DEL 0x8A
#define PS2_KC_ESC 0x8B
#define PS2_KC_CLON 0x8C // caps_lock on
#define PS2_KC_CLOFF 0x8D // caps_lock off
#include "binary.h"
typedef uint8_t boolean;
/*
* This PIN is hardcoded in the init routine later on. If you change this
* make sure you change the interrupt initialization as well.
PS2_INT_PIN 2 / attachInterrupt(0, ps2interrupt, FALLING);
PS2_INT_PIN 3 / attachInterrupt(1, ps2interrupt, FALLING);
*/
// #define PS2_INT_PIN 3
// #define PS2_INT_NUM 1
// for Leonardo IDE1.0.1
#define PS2_INT_PIN 2
#define PS2_INT_NUM 1
/**
* Purpose: Provides an easy access to PS2 keyboards
* Author: Christian Weichel
*/
class PS2Keyboard {
private:
int m_dataPin;
uint8_t m_charBuffer;
public:
/**
* This constructor does basically nothing. Please call the begin(int)
* method before using any other method of this class.
*/
PS2Keyboard();
/**
* Starts the keyboard "service" by registering the external interrupt.
* setting the pin modes correctly and driving those needed to high.
* The propably best place to call this method is in the setup routine.
*/
void begin(int dataPin);
/**
* Returns true if there is a char to be read, false if not.
*/
bool available();
/**
* Sends a reset command to the keyboard and re-initialises all the control
* variables within the PS2Keybaord code.
*/
void reset();
/**
* Returns the char last read from the keyboard. If the user has pressed two
* keys between calls to this method, only the later one will be availble. Once
* the char has been read, the buffer will be cleared.
* If there is no char availble, 0 is returned.
*/
uint8_t read();
uint8_t rawread();
uint8_t modifier();
uint8_t lock();
/**
* Returns the status of the <ctrl> key, the <alt> key, the <shift> key and the
* caps_lock state. Note that shift and caps_lock are handled within the
* Ps2Keyboard code (and the return value from read() is already modified), but
* being able to read them here may be useful.
* This routine is optional BUT MUST ONLY be read after available() has returned
* true and BEFORE read() is called to retrieve the character. Reading it after
* the call to read() will return unpredictable values.
*/
uint8_t read_extra();
uint16_t readuid();
};
#endif
#include <PS2kybd.h>
// Simple test program for new PS2Keyboard library
// Connect a PS2 keyboard to pins 3 & 4 (CLK and DATA respectively) and supply 5V to the keyboard
// For examples, see here: http://www.arduino.cc/playground/ComponentLib/Ps2mouse
// or here: http://www.beyondlogic.org/keyboard/keybrd.htm
// That second article is a great place to start if you want to understand whats going on
//
// When you've compiled the code and uploaded it to the board, start a serial monitor at
// 9600bd. Then press keys on your PS2 keyboard (the one connected to Arduino, not the one
// connected to your computer!) Try using <shift>, <ctrl> and <alt> keys
// and check that the caps_lock key sets the caps_lock light.
// Pressing <esc> key should reset the keyboard and you should see all 3 lights go on briefly.
// DigitalPin3 CLK Leonardo:3 SS_Breakout:10.D0 Davinci:4.PD0
// DigitalPin2 DATA Leonardo:2 SS_Breakout:9.D1 Davinci:5.PD1
// D2 PD1 SDA SDA/INT1
// D3# PD0 PWM8/SCL OC0B/SCL/INT0
#define KBD_CLK_PIN 2
#define KBD_DATA_PIN 3
PS2Keyboard keyboard;
int i=0;
int b;
void setup() {
keyboard.begin(KBD_DATA_PIN);
Serial.begin(9600);
delay(1000);
}
#define is_printable(c) (!(c&0x80)) // don't print if top bit is set
void loop() {
if(b=keyboard.available()) {
byte r = keyboard.read_extra();
// Serial.print(b);
// Serial.print(" ");
// Serial.print(r,HEX);
// Serial.println("");
byte m = keyboard.modifier();
byte l = keyboard.lock();
int c = keyboard.readuid();
// delay(100);
i++;
Serial.print(i);
Serial.print(" L:");
Serial.print(l,HEX);
Serial.print(" M:");
Serial.print(m,HEX);
Serial.print(" ");
Serial.print(c,HEX);
Serial.println("");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment