diff --git a/.github/workflows/upload_component.yml b/.github/workflows/upload_component.yml
new file mode 100644
index 0000000..6533d0d
--- /dev/null
+++ b/.github/workflows/upload_component.yml
@@ -0,0 +1,24 @@
+name: Publish to ESP Component Registry
+
+# Publishes the component to https://components.espressif.com whenever a
+# release tag (e.g. v3.1.0) is pushed. Requires an IDF_COMPONENT_API_TOKEN
+# secret created from your Espressif registry account.
+on:
+ push:
+ tags:
+ - "v*"
+ workflow_dispatch:
+
+jobs:
+ upload:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Upload component
+ uses: espressif/upload-components-ci-action@v2
+ with:
+ name: "ps2keyboard"
+ namespace: "lahirunirmalx"
+ api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9c83f28
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+# ESP-IDF / PlatformIO build artifacts
+build/
+.pio/
+managed_components/
+dependencies.lock
+
+# Per-project IDF config (defaults live in sdkconfig.defaults)
+sdkconfig
+sdkconfig.old
+
+# Component archive produced by `compote component pack`
+dist/
+*.tgz
+
+# Editor / OS noise
+.vscode/
+.idea/
+.DS_Store
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..28c7f87
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,23 @@
+# Changelog
+
+All notable changes to this component are documented here. This project
+adheres to [Semantic Versioning](https://semver.org/).
+
+## [3.1.0] - 2026-05
+
+### Added
+- Native ESP-IDF port: pure `driver/gpio` + `esp_timer`, IRAM ISR, plain C API.
+- ESP Component Registry packaging (manifest metadata, examples, LICENSE).
+
+### Notes
+- Supersedes the Arduino-only line for ESP-IDF projects.
+
+## [3.0.0] - 2026-01
+
+### Added
+- ESP32 / ESP8266 (Arduino) support.
+- Caps / Num / Scroll Lock LED control.
+
+## [2.x]
+
+- Multi-platform Arduino library (Uno, Mega, Due, Teensy).
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..7287023
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,10 @@
+idf_component_register(
+ SRCS
+ "src/ps2keyboard.c"
+ "src/ps2keymap_us.c"
+ INCLUDE_DIRS
+ "include"
+ REQUIRES
+ driver
+ esp_timer
+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f6683e7
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,501 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ 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, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ , 1 April 1990
+ Moe Ghoul, President of Vice
+
+That's all there is to it!
diff --git a/PS2Keyboard.cpp b/PS2Keyboard.cpp
deleted file mode 100644
index 53bfa1a..0000000
--- a/PS2Keyboard.cpp
+++ /dev/null
@@ -1,711 +0,0 @@
-/*
- PS2Keyboard.cpp - PS2Keyboard library
- Copyright (c) 2007 Free Software Foundation. All right reserved.
- Written by Christian Weichel
-
- ** Mostly rewritten Paul Stoffregen 2010, 2011
- ** Modified for use beginning with Arduino 13 by L. Abraham Smith, *
- ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan **
-
- for more information you can read the original wiki in arduino.cc
- at http://www.arduino.cc/playground/Main/PS2Keyboard
- or http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html
-
- Version 2.4 (March 2013)
- - Support Teensy 3.0, Arduino Due, Arduino Leonardo & other boards
- - French keyboard layout, David Chochoi, tchoyyfr at yahoo dot fr
-
- Version 2.3 (October 2011)
- - Minor bugs fixed
-
- Version 2.2 (August 2011)
- - Support non-US keyboards - thanks to Rainer Bruch for a German keyboard :)
-
- Version 2.1 (May 2011)
- - timeout to recover from misaligned input
- - compatibility with Arduino "new-extension" branch
- - TODO: send function, proposed by Scott Penrose, scooterda at me dot com
-
- Version 2.0 (June 2010)
- - Buffering added, many scan codes can be captured without data loss
- if your sketch is busy doing other work
- - Shift keys supported, completely rewritten scan code to ascii
- - Slow linear search replaced with fast indexed table lookups
- - Support for Teensy, Arduino Mega, and Sanguino added
-
- 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 "PS2Keyboard.h"
-
-#define BUFFER_SIZE 45
-static volatile uint8_t buffer[BUFFER_SIZE];
-static volatile uint8_t head, tail;
-static uint8_t DataPin;
-static uint8_t CharBuffer=0;
-static uint8_t UTF8next=0;
-static const PS2Keymap_t *keymap=NULL;
-
-// 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(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;
- }
-}
-
-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;
-}
-
-// http://www.quadibloc.com/comp/scan.htm
-// http://www.computer-engineering.org/ps2keyboard/scancodes2.html
-
-// These arrays provide a simple key map, to turn scan codes into ISO8859
-// output. If a non-US keyboard is used, these may need to be modified
-// for the desired output.
-//
-
-const PROGMEM PS2Keymap_t PS2Keymap_US = {
- // without shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '`', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
- 0, 0, 'z', 's', 'a', 'w', '2', 0,
- 0, 'c', 'x', 'd', 'e', '4', '3', 0,
- 0, ' ', 'v', 'f', 't', 'r', '5', 0,
- 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
- 0, 0, 'm', 'j', 'u', '7', '8', 0,
- 0, ',', 'k', 'i', 'o', '0', '9', 0,
- 0, '.', '/', 'l', ';', 'p', '-', 0,
- 0, 0, '\'', 0, '[', '=', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '\\', 0, 0,
- 0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- // with shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '~', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
- 0, 0, 'Z', 'S', 'A', 'W', '@', 0,
- 0, 'C', 'X', 'D', 'E', '$', '#', 0,
- 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
- 0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
- 0, 0, 'M', 'J', 'U', '&', '*', 0,
- 0, '<', 'K', 'I', 'O', ')', '(', 0,
- 0, '>', '?', 'L', ':', 'P', '_', 0,
- 0, 0, '"', 0, '{', '+', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '|', 0, 0,
- 0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- 0
-};
-
-
-const PROGMEM PS2Keymap_t PS2Keymap_German = {
- // without shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '^', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
- 0, 0, 'y', 's', 'a', 'w', '2', 0,
- 0, 'c', 'x', 'd', 'e', '4', '3', 0,
- 0, ' ', 'v', 'f', 't', 'r', '5', 0,
- 0, 'n', 'b', 'h', 'g', 'z', '6', 0,
- 0, 0, 'm', 'j', 'u', '7', '8', 0,
- 0, ',', 'k', 'i', 'o', '0', '9', 0,
- 0, '.', '-', 'l', PS2_o_DIAERESIS, 'p', PS2_SHARP_S, 0,
- 0, 0, PS2_a_DIAERESIS, 0, PS2_u_DIAERESIS, '\'', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, '#', 0, 0,
- 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- // with shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_DEGREE_SIGN, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
- 0, 0, 'Y', 'S', 'A', 'W', '"', 0,
- 0, 'C', 'X', 'D', 'E', '$', PS2_SECTION_SIGN, 0,
- 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
- 0, 'N', 'B', 'H', 'G', 'Z', '&', 0,
- 0, 0, 'M', 'J', 'U', '/', '(', 0,
- 0, ';', 'K', 'I', 'O', '=', ')', 0,
- 0, ':', '_', 'L', PS2_O_DIAERESIS, 'P', '?', 0,
- 0, 0, PS2_A_DIAERESIS, 0, PS2_U_DIAERESIS, '`', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, '\'', 0, 0,
- 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- 1,
- // with altgr
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, '@', 0, 0,
- 0, 0, 0, 0, 0, 0, PS2_SUPERSCRIPT_TWO, 0,
- 0, 0, 0, 0, PS2_CURRENCY_SIGN, 0, PS2_SUPERSCRIPT_THREE, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, PS2_MICRO_SIGN, 0, 0, '{', '[', 0,
- 0, 0, 0, 0, 0, '}', ']', 0,
- 0, 0, 0, 0, 0, 0, '\\', 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '~', 0, '#', 0, 0,
- 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 }
-};
-
-
-const PROGMEM PS2Keymap_t PS2Keymap_French = {
- // without shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_SUPERSCRIPT_TWO, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'a', '&', 0,
- 0, 0, 'w', 's', 'q', 'z', PS2_e_ACUTE, 0,
- 0, 'c', 'x', 'd', 'e', '\'', '"', 0,
- 0, ' ', 'v', 'f', 't', 'r', '(', 0,
- 0, 'n', 'b', 'h', 'g', 'y', '-', 0,
- 0, 0, ',', 'j', 'u', PS2_e_GRAVE, '_', 0,
- 0, ';', 'k', 'i', 'o', PS2_a_GRAVE, PS2_c_CEDILLA, 0,
- 0, ':', '!', 'l', 'm', 'p', ')', 0,
- 0, 0, PS2_u_GRAVE, 0, '^', '=', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '$', 0, '*', 0, 0,
- 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- // with shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'A', '1', 0,
- 0, 0, 'W', 'S', 'Q', 'Z', '2', 0,
- 0, 'C', 'X', 'D', 'E', '4', '3', 0,
- 0, ' ', 'V', 'F', 'T', 'R', '5', 0,
- 0, 'N', 'B', 'H', 'G', 'Y', '6', 0,
- 0, 0, '?', 'J', 'U', '7', '8', 0,
- 0, '.', 'K', 'I', 'O', '0', '9', 0,
- 0, '/', PS2_SECTION_SIGN, 'L', 'M', 'P', PS2_DEGREE_SIGN, 0,
- 0, 0, '%', 0, PS2_DIAERESIS, '+', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, PS2_POUND_SIGN, 0, PS2_MICRO_SIGN, 0, 0,
- 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- 1,
- // with altgr
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 0, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, '@', 0, 0,
- 0, 0, 0, 0, 0, 0, '~', 0,
- 0, 0, 0, 0, 0 /*PS2_EURO_SIGN*/, '{', '#', 0,
- 0, 0, 0, 0, 0, 0, '[', 0,
- 0, 0, 0, 0, 0, 0, '|', 0,
- 0, 0, 0, 0, 0, '`', '\\', 0,
- 0, 0, 0, 0, 0, '@', '^', 0,
- 0, 0, 0, 0, 0, 0, ']', 0,
- 0, 0, 0, 0, 0, 0, '}', 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, PS2_CURRENCY_SIGN, 0, '#', 0, 0,
- 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 }
-};
-
-const PROGMEM PS2Keymap_t PS2Keymap_Spanish = {
- // without shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_MASCULINE_ORDINAL, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
- 0, 0, 'z', 's', 'a', 'w', '2', 0,
- 0, 'c', 'x', 'd', 'e', '4', '3', 0,
- 0, ' ', 'v', 'f', 't', 'r', '5', 0,
- 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
- 0, 0, 'm', 'j', 'u', '7', '8', 0,
- 0, ',', 'k', 'i', 'o', '0', '9', 0,
- 0, '.', '-', 'l', 'n', 'p', '\'', 0,
- 0, 0, PS2_ACUTE_ACCENT, 0, '`', PS2_INVERTED_EXCLAMATION, 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, PS2_c_CEDILLA, 0, 0,
- 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- // with shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_FEMININE_ORDINAL, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
- 0, 0, 'Z', 'S', 'A', 'W', '\"', 0,
- 0, 'C', 'X', 'D', 'E', '$', PS2_MIDDLE_DOT, 0,
- 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
- 0, 'N', 'B', 'H', 'G', 'Y', '&', 0,
- 0, 0, 'M', 'J', 'U', '/', '(', 0,
- 0, ';', 'K', 'I', 'O', '=', ')', 0,
- 0, ':', '_', 'L', 'N', 'P', '?', 0,
- 0, 0, PS2_DIAERESIS, 0, '^', PS2_INVERTED_QUESTION_MARK, 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, PS2_C_CEDILLA, 0, 0,
- 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- 1,
- // with altgr
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '\\', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '|', 0,
- 0, 0, 'z', 's', 'a', 'w', '@', 0,
- 0, 'c', 'x', 'd', PS2_EURO_SIGN, '~', '#', 0,
- 0, ' ', 'v', 'f', 't', 'r', '5', 0,
- 0, 'n', 'b', 'h', 'g', 'y', PS2_NOT_SIGN, 0,
- 0, 0, 'm', 'j', 'u', '7', '8', 0,
- 0, ',', 'k', 'i', 'o', '0', '9', 0,
- 0, '.', '-', 'l', 'n', 'p', '\'', 0,
- 0, 0, '{', 0, '[', PS2_INVERTED_EXCLAMATION, 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '}', 0, 0,
- 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 }
-};
-
-const PROGMEM PS2Keymap_t PS2Keymap_Italian = {
- // without shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '\\', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
- 0, 0, 'z', 's', 'a', 'w', '2', 0,
- 0, 'c', 'x', 'd', 'e', '4', '3', 0,
- 0, ' ', 'v', 'f', 't', 'r', '5', 0,
- 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
- 0, 0, 'm', 'j', 'u', '7', '8', 0,
- 0, ',', 'k', 'i', 'o', '0', '9', 0,
- 0, '.', '-', 'l', PS2_o_GRAVE, 'p', '\'', 0,
- 0, 0, PS2_a_GRAVE, 0, PS2_e_GRAVE, PS2_i_GRAVE, 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '+', 0, PS2_u_GRAVE, 0, 0,
- 0, '<', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- // with shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '|', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
- 0, 0, 'Z', 'S', 'A', 'W', '\"', 0,
- 0, 'C', 'X', 'D', 'E', '$', PS2_POUND_SIGN, 0,
- 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
- 0, 'N', 'B', 'H', 'G', 'Y', '&', 0,
- 0, 0, 'M', 'J', 'U', '/', '(', 0,
- 0, ';', 'K', 'I', 'O', '=', ')', 0,
- 0, ':', '_', 'L', PS2_c_CEDILLA, 0, '?', 0,
- 0, 0, PS2_DEGREE_SIGN, 0, PS2_e_ACUTE, '^', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '*', 0, PS2_SECTION_SIGN, 0, 0,
- 0, '>', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- 1,
- // with altgr
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, PS2_NOT_SIGN, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', PS2_SUPERSCRIPT_ONE, 0,
- 0, 0, 'z', 's', 'a', 'w', PS2_SUPERSCRIPT_TWO, 0,
- 0, 'c', 'x', 'd', PS2_EURO_SIGN, PS2_FRACTION_ONE_QUARTER, PS2_SUPERSCRIPT_THREE, 0,
- 0, ' ', 'v', 'f', 't', 'r', PS2_FRACTION_ONE_HALF, 0,
- 0, 'n', 'b', 'h', 'g', 'y', PS2_NOT_SIGN, 0,
- 0, 0, 'm', 'j', 'u', '{', '[', 0,
- 0, ',', 'k', 'i', 'o', '}', ']', 0,
- 0, '.', '-', 'l', '@', 'p', '\'', 0,
- 0, 0, '#', 0, '[', '~', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, 0, 0, 0,
- 0, PS2_LEFT_DOUBLE_ANGLE_QUOTE, 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 }
-};
-
-const PROGMEM PS2Keymap_t PS2Keymap_UK = {
-// https://github.com/PaulStoffregen/PS2Keyboard/issues/15
- // without shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '`', 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
- 0, 0, 'z', 's', 'a', 'w', '2', 0,
- 0, 'c', 'x', 'd', 'e', '4', '3', 0,
- 0, ' ', 'v', 'f', 't', 'r', '5', 0,
- 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
- 0, 0, 'm', 'j', 'u', '7', '8', 0,
- 0, ',', 'k', 'i', 'o', '0', '9', 0,
- 0, '.', '/', 'l', ';', 'p', '-', 0,
- 0, 0, '\'', 0, '[', '=', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, ']', 0, '#', 0, 0,
- 0, '\\', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- // with shift
- {0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
- 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, 172 /* ¬ */, 0,
- 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
- 0, 0, 'Z', 'S', 'A', 'W', '"', 0,
- 0, 'C', 'X', 'D', 'E', '$', 163 /* £ */, 0,
- 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
- 0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
- 0, 0, 'M', 'J', 'U', '&', '*', 0,
- 0, '<', 'K', 'I', 'O', ')', '(', 0,
- 0, '>', '?', 'L', ':', 'P', '_', 0,
- 0, 0, '@', 0, '{', '+', 0, 0,
- 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER /*Enter*/, '}', 0, '~', 0, 0,
- 0, '|', 0, 0, 0, 0, PS2_BACKSPACE, 0,
- 0, '1', 0, '4', '7', 0, 0, 0,
- '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
- PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
- 0, 0, 0, PS2_F7 },
- 0
-};
-
-#define BREAK 0x01
-#define MODIFIER 0x02
-#define SHIFT_L 0x04
-#define SHIFT_R 0x08
-#define ALTGR 0x10
-
-static char get_iso8859_code(void)
-{
- static uint8_t state=0;
- uint8_t s;
- char c;
-
- while (1) {
- s = get_scan_code();
- if (!s) return 0;
- if (s == 0xF0) {
- state |= BREAK;
- } else if (s == 0xE0) {
- state |= MODIFIER;
- } else {
- if (state & BREAK) {
- if (s == 0x12) {
- state &= ~SHIFT_L;
- } else if (s == 0x59) {
- state &= ~SHIFT_R;
- } else if (s == 0x11 && (state & MODIFIER)) {
- state &= ~ALTGR;
- }
- // CTRL, ALT & WIN keys could be added
- // but is that really worth the overhead?
- state &= ~(BREAK | MODIFIER);
- continue;
- }
- if (s == 0x12) {
- state |= SHIFT_L;
- continue;
- } else if (s == 0x59) {
- state |= SHIFT_R;
- continue;
- } else if (s == 0x11 && (state & MODIFIER)) {
- state |= ALTGR;
- }
- c = 0;
- if (state & MODIFIER) {
- switch (s) {
- case 0x70: c = PS2_INSERT; break;
- case 0x6C: c = PS2_HOME; break;
- case 0x7D: c = PS2_PAGEUP; break;
- case 0x71: c = PS2_DELETE; break;
- case 0x69: c = PS2_END; break;
- case 0x7A: c = PS2_PAGEDOWN; break;
- case 0x75: c = PS2_UPARROW; break;
- case 0x6B: c = PS2_LEFTARROW; break;
- case 0x72: c = PS2_DOWNARROW; break;
- case 0x74: c = PS2_RIGHTARROW; break;
- case 0x4A: c = '/'; break;
- case 0x5A: c = PS2_ENTER; break;
- default: break;
- }
- } else if ((state & ALTGR) && pgm_read_byte(keymap->uses_altgr)) {
- if (s < PS2_KEYMAP_SIZE)
- c = pgm_read_byte(keymap->altgr + s);
- } else if (state & (SHIFT_L | SHIFT_R)) {
- if (s < PS2_KEYMAP_SIZE)
- c = pgm_read_byte(keymap->shift + s);
- } else {
- if (s < PS2_KEYMAP_SIZE)
- c = pgm_read_byte(keymap->noshift + s);
- }
- state &= ~(BREAK | MODIFIER);
- if (c) return c;
- }
- }
-}
-
-bool PS2Keyboard::available() {
- if (CharBuffer || UTF8next) return true;
- CharBuffer = get_iso8859_code();
- if (CharBuffer) return true;
- return false;
-}
-
-void PS2Keyboard::clear() {
- CharBuffer = 0;
- UTF8next = 0;
-}
-
-uint8_t PS2Keyboard::readScanCode(void)
-{
- return get_scan_code();
-}
-
-int PS2Keyboard::read() {
- uint8_t result;
-
- result = UTF8next;
- if (result) {
- UTF8next = 0;
- } else {
- result = CharBuffer;
- if (result) {
- CharBuffer = 0;
- } else {
- result = get_iso8859_code();
- }
- if (result >= 128) {
- UTF8next = (result & 0x3F) | 0x80;
- result = ((result >> 6) & 0x1F) | 0xC0;
- }
- }
- if (!result) return -1;
- return result;
-}
-
-int PS2Keyboard::readUnicode() {
- int result;
-
- result = CharBuffer;
- if (!result) result = get_iso8859_code();
- if (!result) return -1;
- UTF8next = 0;
- CharBuffer = 0;
- return result;
-}
-
-PS2Keyboard::PS2Keyboard() {
- // nothing to do here, begin() does it all
-}
-
-void PS2Keyboard::begin(uint8_t data_pin, uint8_t irq_pin, const PS2Keymap_t &map) {
- uint8_t irq_num=255;
-
- DataPin = data_pin;
- keymap = ↦
-
- // initialize the pins
-#ifdef INPUT_PULLUP
- pinMode(irq_pin, INPUT_PULLUP);
- pinMode(data_pin, INPUT_PULLUP);
-#else
- pinMode(irq_pin, INPUT);
- digitalWrite(irq_pin, HIGH);
- pinMode(data_pin, INPUT);
- digitalWrite(data_pin, HIGH);
-#endif
-
-#ifdef CORE_INT_EVERY_PIN
- irq_num = irq_pin;
-
-#else
- switch(irq_pin) {
- #ifdef CORE_INT0_PIN
- case CORE_INT0_PIN:
- irq_num = 0;
- break;
- #endif
- #ifdef CORE_INT1_PIN
- case CORE_INT1_PIN:
- irq_num = 1;
- break;
- #endif
- #ifdef CORE_INT2_PIN
- case CORE_INT2_PIN:
- irq_num = 2;
- break;
- #endif
- #ifdef CORE_INT3_PIN
- case CORE_INT3_PIN:
- irq_num = 3;
- break;
- #endif
- #ifdef CORE_INT4_PIN
- case CORE_INT4_PIN:
- irq_num = 4;
- break;
- #endif
- #ifdef CORE_INT5_PIN
- case CORE_INT5_PIN:
- irq_num = 5;
- break;
- #endif
- #ifdef CORE_INT6_PIN
- case CORE_INT6_PIN:
- irq_num = 6;
- break;
- #endif
- #ifdef CORE_INT7_PIN
- case CORE_INT7_PIN:
- irq_num = 7;
- break;
- #endif
- #ifdef CORE_INT8_PIN
- case CORE_INT8_PIN:
- irq_num = 8;
- break;
- #endif
- #ifdef CORE_INT9_PIN
- case CORE_INT9_PIN:
- irq_num = 9;
- break;
- #endif
- #ifdef CORE_INT10_PIN
- case CORE_INT10_PIN:
- irq_num = 10;
- break;
- #endif
- #ifdef CORE_INT11_PIN
- case CORE_INT11_PIN:
- irq_num = 11;
- break;
- #endif
- #ifdef CORE_INT12_PIN
- case CORE_INT12_PIN:
- irq_num = 12;
- break;
- #endif
- #ifdef CORE_INT13_PIN
- case CORE_INT13_PIN:
- irq_num = 13;
- break;
- #endif
- #ifdef CORE_INT14_PIN
- case CORE_INT14_PIN:
- irq_num = 14;
- break;
- #endif
- #ifdef CORE_INT15_PIN
- case CORE_INT15_PIN:
- irq_num = 15;
- break;
- #endif
- #ifdef CORE_INT16_PIN
- case CORE_INT16_PIN:
- irq_num = 16;
- break;
- #endif
- #ifdef CORE_INT17_PIN
- case CORE_INT17_PIN:
- irq_num = 17;
- break;
- #endif
- #ifdef CORE_INT18_PIN
- case CORE_INT18_PIN:
- irq_num = 18;
- break;
- #endif
- #ifdef CORE_INT19_PIN
- case CORE_INT19_PIN:
- irq_num = 19;
- break;
- #endif
- #ifdef CORE_INT20_PIN
- case CORE_INT20_PIN:
- irq_num = 20;
- break;
- #endif
- #ifdef CORE_INT21_PIN
- case CORE_INT21_PIN:
- irq_num = 21;
- break;
- #endif
- #ifdef CORE_INT22_PIN
- case CORE_INT22_PIN:
- irq_num = 22;
- break;
- #endif
- #ifdef CORE_INT23_PIN
- case CORE_INT23_PIN:
- irq_num = 23;
- break;
- #endif
- }
-#endif
-
- head = 0;
- tail = 0;
- if (irq_num < 255) {
- attachInterrupt(irq_num, ps2interrupt, FALLING);
- }
-}
-
-
diff --git a/PS2Keyboard.h b/PS2Keyboard.h
deleted file mode 100644
index 4931e37..0000000
--- a/PS2Keyboard.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- PS2Keyboard.h - PS2Keyboard library
- Copyright (c) 2007 Free Software Foundation. All right reserved.
- Written by Christian Weichel
-
- ** Mostly rewritten Paul Stoffregen , June 2010
- ** Modified for use with Arduino 13 by L. Abraham Smith, *
- ** Modified for easy interrup pin assignement on method begin(datapin,irq_pin). Cuningan **
-
- 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
-
-#if defined(ARDUINO) && ARDUINO >= 100
-#include "Arduino.h" // for attachInterrupt, FALLING
-#else
-#include "WProgram.h"
-#endif
-
-#include "utility/int_pins.h"
-
-// Every call to read() returns a single byte for each
-// keystroke. These configure what byte will be returned
-// for each "special" key. To ignore a key, use zero.
-#define PS2_TAB 9
-#define PS2_ENTER 13
-#define PS2_BACKSPACE 127
-#define PS2_ESC 27
-#define PS2_INSERT 0
-#define PS2_DELETE 127
-#define PS2_HOME 0
-#define PS2_END 0
-#define PS2_PAGEUP 25
-#define PS2_PAGEDOWN 26
-#define PS2_UPARROW 11
-#define PS2_LEFTARROW 8
-#define PS2_DOWNARROW 10
-#define PS2_RIGHTARROW 21
-#define PS2_F1 0
-#define PS2_F2 0
-#define PS2_F3 0
-#define PS2_F4 0
-#define PS2_F5 0
-#define PS2_F6 0
-#define PS2_F7 0
-#define PS2_F8 0
-#define PS2_F9 0
-#define PS2_F10 0
-#define PS2_F11 0
-#define PS2_F12 0
-#define PS2_SCROLL 0
-#define PS2_EURO_SIGN 0
-
-#define PS2_INVERTED_EXCLAMATION 161 // ¡
-#define PS2_CENT_SIGN 162 // ¢
-#define PS2_POUND_SIGN 163 // £
-#define PS2_CURRENCY_SIGN 164 // ¤
-#define PS2_YEN_SIGN 165 // ¥
-#define PS2_BROKEN_BAR 166 // ¦
-#define PS2_SECTION_SIGN 167 // §
-#define PS2_DIAERESIS 168 // ¨
-#define PS2_COPYRIGHT_SIGN 169 // ©
-#define PS2_FEMININE_ORDINAL 170 // ª
-#define PS2_LEFT_DOUBLE_ANGLE_QUOTE 171 // «
-#define PS2_NOT_SIGN 172 // ¬
-#define PS2_HYPHEN 173
-#define PS2_REGISTERED_SIGN 174 // ®
-#define PS2_MACRON 175 // ¯
-#define PS2_DEGREE_SIGN 176 // °
-#define PS2_PLUS_MINUS_SIGN 177 // ±
-#define PS2_SUPERSCRIPT_TWO 178 // ²
-#define PS2_SUPERSCRIPT_THREE 179 // ³
-#define PS2_ACUTE_ACCENT 180 // ´
-#define PS2_MICRO_SIGN 181 // µ
-#define PS2_PILCROW_SIGN 182 // ¶
-#define PS2_MIDDLE_DOT 183 // ·
-#define PS2_CEDILLA 184 // ¸
-#define PS2_SUPERSCRIPT_ONE 185 // ¹
-#define PS2_MASCULINE_ORDINAL 186 // º
-#define PS2_RIGHT_DOUBLE_ANGLE_QUOTE 187 // »
-#define PS2_FRACTION_ONE_QUARTER 188 // ¼
-#define PS2_FRACTION_ONE_HALF 189 // ½
-#define PS2_FRACTION_THREE_QUARTERS 190 // ¾
-#define PS2_INVERTED_QUESTION_MARK 191 // ¿
-#define PS2_A_GRAVE 192 // À
-#define PS2_A_ACUTE 193 // Á
-#define PS2_A_CIRCUMFLEX 194 // Â
-#define PS2_A_TILDE 195 // Ã
-#define PS2_A_DIAERESIS 196 // Ä
-#define PS2_A_RING_ABOVE 197 // Å
-#define PS2_AE 198 // Æ
-#define PS2_C_CEDILLA 199 // Ç
-#define PS2_E_GRAVE 200 // È
-#define PS2_E_ACUTE 201 // É
-#define PS2_E_CIRCUMFLEX 202 // Ê
-#define PS2_E_DIAERESIS 203 // Ë
-#define PS2_I_GRAVE 204 // Ì
-#define PS2_I_ACUTE 205 // Í
-#define PS2_I_CIRCUMFLEX 206 // Î
-#define PS2_I_DIAERESIS 207 // Ï
-#define PS2_ETH 208 // Ð
-#define PS2_N_TILDE 209 // Ñ
-#define PS2_O_GRAVE 210 // Ò
-#define PS2_O_ACUTE 211 // Ó
-#define PS2_O_CIRCUMFLEX 212 // Ô
-#define PS2_O_TILDE 213 // Õ
-#define PS2_O_DIAERESIS 214 // Ö
-#define PS2_MULTIPLICATION 215 // ×
-#define PS2_O_STROKE 216 // Ø
-#define PS2_U_GRAVE 217 // Ù
-#define PS2_U_ACUTE 218 // Ú
-#define PS2_U_CIRCUMFLEX 219 // Û
-#define PS2_U_DIAERESIS 220 // Ü
-#define PS2_Y_ACUTE 221 // Ý
-#define PS2_THORN 222 // Þ
-#define PS2_SHARP_S 223 // ß
-#define PS2_a_GRAVE 224 // à
-#define PS2_a_ACUTE 225 // á
-#define PS2_a_CIRCUMFLEX 226 // â
-#define PS2_a_TILDE 227 // ã
-#define PS2_a_DIAERESIS 228 // ä
-#define PS2_a_RING_ABOVE 229 // å
-#define PS2_ae 230 // æ
-#define PS2_c_CEDILLA 231 // ç
-#define PS2_e_GRAVE 232 // è
-#define PS2_e_ACUTE 233 // é
-#define PS2_e_CIRCUMFLEX 234 // ê
-#define PS2_e_DIAERESIS 235 // ë
-#define PS2_i_GRAVE 236 // ì
-#define PS2_i_ACUTE 237 // í
-#define PS2_i_CIRCUMFLEX 238 // î
-#define PS2_i_DIAERESIS 239 // ï
-#define PS2_eth 240 // ð
-#define PS2_n_TILDE 241 // ñ
-#define PS2_o_GRAVE 242 // ò
-#define PS2_o_ACUTE 243 // ó
-#define PS2_o_CIRCUMFLEX 244 // ô
-#define PS2_o_TILDE 245 // õ
-#define PS2_o_DIAERESIS 246 // ö
-#define PS2_DIVISION 247 // ÷
-#define PS2_o_STROKE 248 // ø
-#define PS2_u_GRAVE 249 // ù
-#define PS2_u_ACUTE 250 // ú
-#define PS2_u_CIRCUMFLEX 251 // û
-#define PS2_u_DIAERESIS 252 // ü
-#define PS2_y_ACUTE 253 // ý
-#define PS2_thorn 254 // þ
-#define PS2_y_DIAERESIS 255 // ÿ
-
-
-#define PS2_KEYMAP_SIZE 136
-
-typedef struct {
- uint8_t noshift[PS2_KEYMAP_SIZE];
- uint8_t shift[PS2_KEYMAP_SIZE];
- unsigned int uses_altgr;
- /*
- * "uint8_t uses_altgr;" makes the ESP8266 - NodeMCU modules crash.
- * So, I replaced it with an int and... It works!
- * I think it's because of the 32-bit architecture of the ESP8266
- * and the use of the flash memory to store the keymaps.
- * Maybe I'm wrong, it remains a hypothesis.
- */
- uint8_t altgr[PS2_KEYMAP_SIZE];
-} PS2Keymap_t;
-
-
-extern const PROGMEM PS2Keymap_t PS2Keymap_US;
-extern const PROGMEM PS2Keymap_t PS2Keymap_German;
-extern const PROGMEM PS2Keymap_t PS2Keymap_French;
-extern const PROGMEM PS2Keymap_t PS2Keymap_Spanish;
-extern const PROGMEM PS2Keymap_t PS2Keymap_Italian;
-extern const PROGMEM PS2Keymap_t PS2Keymap_UK;
-
-
-/**
- * Purpose: Provides an easy access to PS2 keyboards
- * Author: Christian Weichel
- */
-class PS2Keyboard {
- public:
- /**
- * This constructor does basically nothing. Please call the begin(int,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.
- */
- static void begin(uint8_t dataPin, uint8_t irq_pin, const PS2Keymap_t &map = PS2Keymap_US);
-
- /**
- * Returns true if there is a char to be read, false if not.
- */
- static bool available();
-
- /* Discards any received data, sets available() to false without a call to read()
- */
- static void clear();
-
- /**
- * Retutns ps2 scan code.
- */
- static uint8_t readScanCode(void);
-
- /**
- * Returns the char last read from the keyboard.
- * If there is no char available, -1 is returned.
- */
- static int read();
- static int readUnicode();
-};
-
-#endif
diff --git a/README.md b/README.md
index 931f685..3928ad1 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,149 @@
-#PS/2 Keyboard Library#
+# ps2keyboard - ESP-IDF Component
-PS2Keyboard allows you to use a keyboard for user input.
+[](https://www.gnu.org/licenses/lgpl-2.1)
+[](https://github.com/lahirunirmalx/PS2Keyboard)
-http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html
+A native ESP-IDF component for reading from a PS/2 keyboard on the ESP32
+family. Ported from the long-standing Arduino `PS2Keyboard` library.
-
+## Features
+
+- Pure ESP-IDF: uses `driver/gpio`, `esp_timer` and the IDF GPIO ISR service
+- Interrupt-driven scan-code capture (`IRAM_ATTR` ISR, runs from IRAM)
+- ISO-8859-1 character decoding with Shift / AltGr / Caps / Num / Scroll Lock
+- LED control (Caps / Num / Scroll Lock) by bit-banging the host-to-device line
+- Plain C API, no C++ runtime required
+- Supports any ESP32 variant (S2 / S3 / C3 / C6 / H2 / classic)
+
+## Installation
+
+### ESP-IDF Component Manager (recommended)
+
+Install from the [ESP Component Registry](https://components.espressif.com/components/lahirunirmalx/ps2keyboard):
+
+```bash
+idf.py add-dependency "lahirunirmalx/ps2keyboard^3.1.0"
+```
+
+Or declare it in your project's `idf_component.yml`:
+
+```yaml
+dependencies:
+ lahirunirmalx/ps2keyboard: "^3.1.0"
+```
+
+### Drop-in component
+
+Alternatively, clone (or submodule) this repository under your project's
+`components/` directory:
+
+```bash
+mkdir -p components
+git clone https://github.com/lahirunirmalx/PS2Keyboard.git components/ps2keyboard
+```
+
+## Wiring
+
+| PS/2 Pin | Signal | Connect To |
+|----------|--------|-------------------------------------|
+| 1 | DATA | `data_pin` GPIO |
+| 3 | GND | GND |
+| 4 | VCC | 5 V (PS/2 keyboards expect 5 V) |
+| 5 | CLOCK | `clock_pin` GPIO (interrupt source) |
+
+> **Note:** ESP32 GPIOs are 3.3 V. PS/2 keyboards are 5 V open-collector with
+> internal pull-ups; in practice the lines idle high and the keyboard sinks
+> them low, so most modern ESP32 boards work directly. For long-term
+> reliability use a level shifter or a series resistor + clamping diode.
+
+## Quick Start
+
+```c
+#include "ps2keyboard.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#define PS2_DATA_PIN GPIO_NUM_18
+#define PS2_CLOCK_PIN GPIO_NUM_19
+
+void app_main(void)
+{
+ ESP_ERROR_CHECK(ps2keyboard_begin(PS2_DATA_PIN, PS2_CLOCK_PIN, NULL));
+
+ while (1) {
+ if (ps2keyboard_available()) {
+ int c = ps2keyboard_read();
+ if (c == PS2_ENTER) printf("\n");
+ else if (c == PS2_TAB) printf("[Tab]");
+ else if (c == PS2_ESC) printf("[ESC]");
+ else if (c > 0) putchar(c);
+ fflush(stdout);
+ } else {
+ vTaskDelay(pdMS_TO_TICKS(5));
+ }
+ }
+}
+```
+
+A complete buildable example lives in [examples/simple_test](examples/simple_test/).
+Build it with:
+
+```bash
+cd examples/simple_test
+idf.py set-target esp32
+idf.py build flash monitor
+```
+
+## API Reference
+
+```c
+esp_err_t ps2keyboard_begin(gpio_num_t data_pin,
+ gpio_num_t clock_pin,
+ const ps2_keymap_t *keymap);
+void ps2keyboard_end(void);
+
+bool ps2keyboard_available(void);
+void ps2keyboard_clear(void);
+
+uint8_t ps2keyboard_read_scancode(void); /* raw scan code */
+int ps2keyboard_read(void); /* UTF-8 byte */
+int ps2keyboard_read_unicode(void); /* code point */
+```
+
+Pass `NULL` as the keymap to use the bundled `ps2_keymap_us`. Custom layouts
+can be supplied as `const ps2_keymap_t` instances.
+
+### Special key constants
+
+`PS2_ENTER`, `PS2_TAB`, `PS2_ESC`, `PS2_BACKSPACE`, `PS2_DELETE`, `PS2_INSERT`,
+`PS2_HOME`, `PS2_END`, `PS2_PAGEUP`, `PS2_PAGEDOWN`, `PS2_UPARROW`,
+`PS2_DOWNARROW`, `PS2_LEFTARROW`, `PS2_RIGHTARROW`, `PS2_F1`..`PS2_F12`,
+`PS2_SCROLL`.
+
+## Notes on the GPIO ISR service
+
+`ps2keyboard_begin()` calls `gpio_install_isr_service(ESP_INTR_FLAG_IRAM)`. If
+your application has already installed the service with different flags this
+call returns `ESP_ERR_INVALID_STATE`, which is treated as success - the
+existing service is reused.
+
+## Version History
+
+- **v3.1.0** (May 2026) — Native ESP-IDF port (this branch)
+- **v3.0.0** (January 2026) — ESP32 / ESP8266 (Arduino) support, Lock-key LEDs
+- **v2.x** — Multi-platform Arduino library (Uno, Mega, Due, Teensy)
+
+## Credits
+
+Original library by [PJRC](http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html).
+
+- Christian Weichel — original author
+- Paul Stoffregen — major rewrite
+- L. Abraham Smith — Arduino 13 modifications
+- Cuningan — flexible pin assignment
+- Lahiru Nirmal — ESP32 / ESP8266 (Arduino) port and ESP-IDF port
+
+## License
+
+GNU Lesser General Public License v2.1
+([LGPL-2.1](https://www.gnu.org/licenses/lgpl-2.1.html)).
diff --git a/examples/International/International.ino b/examples/International/International.ino
deleted file mode 100644
index 48fba5f..0000000
--- a/examples/International/International.ino
+++ /dev/null
@@ -1,34 +0,0 @@
-/* PS2Keyboard library, International Keyboard Layout Example
- http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html
-
- keyboard.begin() accepts an optional 3rd parameter to
- configure the PS2 keyboard layout. Uncomment the line for
- your keyboard. If it doesn't exist, you can create it in
- PS2Keyboard.cpp and email paul@pjrc.com to have it included
- in future versions of this library.
-*/
-
-#include
-
-const int DataPin = 8;
-const int IRQpin = 5;
-
-PS2Keyboard keyboard;
-
-void setup() {
- //keyboard.begin(DataPin, IRQpin, PS2Keymap_US);
- keyboard.begin(DataPin, IRQpin, PS2Keymap_German);
- //keyboard.begin(DataPin, IRQpin, PS2Keymap_French);
- //keyboard.begin(DataPin, IRQpin, PS2Keymap_Spanish);
- //keyboard.begin(DataPin, IRQpin, PS2Keymap_Italian);
- //keyboard.begin(DataPin, IRQpin, PS2Keymap_UK);
- Serial.begin(9600);
- Serial.println("International Keyboard Test:");
-}
-
-void loop() {
- if (keyboard.available()) {
- char c = keyboard.read();
- Serial.print(c);
- }
-}
diff --git a/examples/Simple_Test/Simple_Test.ino b/examples/Simple_Test/Simple_Test.ino
deleted file mode 100644
index bd28b4b..0000000
--- a/examples/Simple_Test/Simple_Test.ino
+++ /dev/null
@@ -1,75 +0,0 @@
-/* PS2Keyboard library example
-
- PS2Keyboard now requries both pins specified for begin()
-
- keyboard.begin(data_pin, irq_pin);
-
- Valid irq pins:
- Arduino Uno: 2, 3
- Arduino Due: All pins, except 13 (LED)
- Arduino Mega: 2, 3, 18, 19, 20, 21
- Teensy 3.0: All pins, except 13 (LED)
- Teensy 2.0: 5, 6, 7, 8
- Teensy 1.0: 0, 1, 2, 3, 4, 6, 7, 16
- Teensy++ 2.0: 0, 1, 2, 3, 18, 19, 36, 37
- Teensy++ 1.0: 0, 1, 2, 3, 18, 19, 36, 37
- Sanguino: 2, 10, 11
-
- for more information you can read the original wiki in arduino.cc
- at http://www.arduino.cc/playground/Main/PS2Keyboard
- or http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html
-
- Like the Original library and example this is under LGPL license.
-
- Modified by Cuninganreset@gmail.com on 2010-03-22
- Modified by Paul Stoffregen June 2010
-*/
-
-#include
-
-const int DataPin = 8;
-const int IRQpin = 5;
-
-PS2Keyboard keyboard;
-
-void setup() {
- delay(1000);
- keyboard.begin(DataPin, IRQpin);
- Serial.begin(9600);
- Serial.println("Keyboard Test:");
-}
-
-void loop() {
- if (keyboard.available()) {
-
- // read the next key
- char c = keyboard.read();
-
- // check for some of the special keys
- if (c == PS2_ENTER) {
- Serial.println();
- } else if (c == PS2_TAB) {
- Serial.print("[Tab]");
- } else if (c == PS2_ESC) {
- Serial.print("[ESC]");
- } else if (c == PS2_PAGEDOWN) {
- Serial.print("[PgDn]");
- } else if (c == PS2_PAGEUP) {
- Serial.print("[PgUp]");
- } else if (c == PS2_LEFTARROW) {
- Serial.print("[Left]");
- } else if (c == PS2_RIGHTARROW) {
- Serial.print("[Right]");
- } else if (c == PS2_UPARROW) {
- Serial.print("[Up]");
- } else if (c == PS2_DOWNARROW) {
- Serial.print("[Down]");
- } else if (c == PS2_DELETE) {
- Serial.print("[Del]");
- } else {
-
- // otherwise, just print all normal characters
- Serial.print(c);
- }
- }
-}
diff --git a/examples/TypeToDisplay/TypeToDisplay.ino b/examples/TypeToDisplay/TypeToDisplay.ino
deleted file mode 100644
index 2b28f15..0000000
--- a/examples/TypeToDisplay/TypeToDisplay.ino
+++ /dev/null
@@ -1,218 +0,0 @@
-/* TypeToDisplay - PS2Keyboard keystrokes show on a standard LCD Display
-
- Lcd support added 18/2/2018 D.R.Patterson
- lcd character set:
- http://forum.arduino.cc/index.php?topic=19002.0
-
- Tested on a mega with a Keypad Shield for Arduino
-
- PS2Keyboard now requries both pins specified for begin()
- keyboard.begin(data_pin, irq_pin);
-
- Valid irq pins:
- Arduino Uno: 2, 3
- Arduino Due: All pins, except 13 (LED)
- Arduino Mega: 2, 3, 18, 19, 20, 21
- Teensy 2.0: All pins, except 13 (LED)
- Teensy 2.0: 5, 6, 7, 8
- Teensy 1.0: 0, 1, 2, 3, 4, 6, 7, 16
- Teensy++ 2.0: 0, 1, 2, 3, 18, 19, 36, 37
- Teensy++ 1.0: 0, 1, 2, 3, 18, 19, 36, 37
- Sanguino: 2, 10, 11
-
- for more information you can read the original wiki in arduino.cc
- at http://www.arduino.cc/playground/Main/PS2Keyboard
- or http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html
-
- Like the Original library and example this is under LGPL license.
-
- Modified by Cuninganreset@gmail.com on 2010-03-22
- Modified by Paul Stoffregen June 2010
-*/
-
-#include
-const int DataPin = 19;
-const int IRQpin = 18;
-PS2Keyboard keyboard;
-
-#include
-// LCD Keypad Shield for Arduino
-// http://www.hobbytronics.co.uk/lcd/lcd-displays-5v/arduino-lcd-keypad-shield
-
-//set constants for number of rows and columns to match your LCD
-const int numRows = 2;
-const int numCols = 16;
-// initialize the library with the numbers of the interface pins
-LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
-
-byte x, y; // track lcd position
-
-// custom pound using https://omerk.github.io/lcdchargen/
-byte customPound[8] = {
- 0b01100,
- 0b10010,
- 0b01000,
- 0b11100,
- 0b01000,
- 0b01000,
- 0b11110,
- 0b00000
-};
-const char pound = 1;
-
-byte customkey[8] = { // ¬
- 0b00000,
- 0b00000,
- 0b00000,
- 0b00000,
- 0b11111,
- 0b00001,
- 0b00001,
- 0b00000
-};
-const char custom = 2;
-
-byte customslash[8] = { // backslash
- 0b00000,
- 0b00000,
- 0b10000,
- 0b01000,
- 0b00100,
- 0b00010,
- 0b00001,
- 0b00000
-};
-const char backslash = 3;
-
-char c;
-
-// currently un-used:
-#define is_printable(c) (!(c&0x80)) // don't print if top bit is set
-
-void setup() {
- delay(1000);
- keyboard.begin(DataPin, IRQpin);
- Serial.begin(115200);
- while (!Serial) yield();
- lcd.begin(numRows, numCols);
- delay(250);
- lcd.clear();
- // create a new custom character
- lcd.createChar(pound, customPound);
- lcd.createChar(custom, customkey);
- lcd.createChar(backslash, customslash);
- lcd.cursor(); // Enable Cursor
- //lcd.blink(); // Blinking cursor
- lcd.clear();
-
- lcd.print(F("Keyboard Test:"));
- lcd.setCursor(0, 1);
- lcd.print(F("Esc to clear LCD"));
- Serial.println(F("Keyboard Test:"));
- unsigned long t = millis();
- do {
- if (keyboard.available()) {
- c = keyboard.read();
- if (c == PS2_ESC) break;
- }
- } while ((millis() - t) < 8000);
- lcd.clear();
-}
-
-void loop() {
-
- if (keyboard.available()) {
- // read the next key
- c = keyboard.read();
-
- // check for some of the special keys
- if (c == PS2_ENTER) {
- Serial.println();
- x = 0;
- y += 1;
- if (y == numRows) {
- y = 0;
- lcd.clear();
- }
- lcd.setCursor(x, y);
-
- } else if (c == PS2_TAB) {
- lcdprint(F("[Tab]"));
-
- } else if (c == PS2_ESC) {
- Serial.println(F("\n[ESC]\n"));
- lcd.clear();
- x = 0; y = 0;
- lcd.setCursor(x, y);
-
- } else if (c == PS2_PAGEDOWN) {
- lcdprint(F("[PgDn]"));
-
- } else if (c == PS2_PAGEUP) {
- lcdprint(F("[PgUp]"));
-
- } else if (c == PS2_LEFTARROW) {
- lcdprint(F("[Left]"));
-
- } else if (c == PS2_RIGHTARROW) {
- lcdprint(F("[Right]"));
-
- } else if (c == PS2_UPARROW) {
- lcdprint(F("[Up]"));
-
- } else if (c == PS2_DOWNARROW) {
- lcdprint(F("[Down]"));
-
- } else if (c == PS2_DELETE) {
- lcdprint(F("[Del]"));
-
- } else if (c == PS2_BACKSPACE) {
- lcdprint(F("[Back]"));
-
- } else {
- // otherwise, just print all normal characters
- lcdprintChar(c);
- }
- }
-}
-
-void lcdprintChar(char t) { // display char on lcd and Serial
- byte test = byte(t);
- if (test == 194) return; // this char appears as an indicator of special keys
-
- if (x > (numCols - 1) ) {
- x = 0;
- if (y == (numRows - 1)) {
- lcd.clear();
- Serial.println();
- y = 0;
- } else y += 1;
- Serial.println();
- lcd.setCursor(x, y);
- }
-
- if (test == 126) lcd.write(243); // 126 ~
- else if (test == 163) lcd.write(pound); // 163 £
- else if (test == 172) lcd.write(custom); // 194 172 ¬
- else if (test == 92) lcd.write(backslash); // 92 backslash
- else lcd.print(t);
- Serial.print(t);
- x += 1;
-}
-
-void lcdprint(String t) { // display string on lcd and Serial
- byte L = t.length();
- if (x > (numCols - L) ) {
- x = 0;
- if (y == (numRows - 1)) {
- lcd.clear();
- Serial.println();
- y = 0;
- } else y += 1;
- Serial.println();
- lcd.setCursor(x, y);
- }
- lcd.print(t);
- Serial.print(t);
- x += L;
-}
diff --git a/examples/simple_test/CMakeLists.txt b/examples/simple_test/CMakeLists.txt
new file mode 100644
index 0000000..cb7e69d
--- /dev/null
+++ b/examples/simple_test/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 3.16)
+
+# Pull the parent directory in as an extra component so the example can
+# reference `ps2keyboard` without having to be installed via the Component
+# Manager.
+set(EXTRA_COMPONENT_DIRS "${CMAKE_CURRENT_LIST_DIR}/../..")
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(ps2keyboard_simple_test)
diff --git a/examples/simple_test/main/CMakeLists.txt b/examples/simple_test/main/CMakeLists.txt
new file mode 100644
index 0000000..b4c0552
--- /dev/null
+++ b/examples/simple_test/main/CMakeLists.txt
@@ -0,0 +1,5 @@
+idf_component_register(
+ SRCS "main.c"
+ INCLUDE_DIRS "."
+ REQUIRES ps2keyboard
+)
diff --git a/examples/simple_test/main/main.c b/examples/simple_test/main/main.c
new file mode 100644
index 0000000..c6c7c88
--- /dev/null
+++ b/examples/simple_test/main/main.c
@@ -0,0 +1,60 @@
+/*
+ PS/2 Keyboard ESP-IDF Example - simple_test
+
+ Wiring:
+ PS/2 DATA -> CONFIG_PS2_DATA_PIN (default GPIO 18)
+ PS/2 CLOCK -> CONFIG_PS2_CLOCK_PIN (default GPIO 19)
+ PS/2 VCC -> 5V (level-shift to 3.3V if your board cannot tolerate 5V on GPIOs)
+ PS/2 GND -> GND
+
+ License: LGPL v2.1
+*/
+
+#include
+
+#include "esp_err.h"
+#include "esp_log.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include "ps2keyboard.h"
+
+#define PS2_DATA_PIN GPIO_NUM_18
+#define PS2_CLOCK_PIN GPIO_NUM_19
+
+static const char *TAG = "ps2_example";
+
+void app_main(void)
+{
+ vTaskDelay(pdMS_TO_TICKS(1000));
+
+ ESP_ERROR_CHECK(ps2keyboard_begin(PS2_DATA_PIN, PS2_CLOCK_PIN, NULL));
+ ESP_LOGI(TAG, "PS/2 keyboard ready - type to begin:");
+
+ while (1) {
+ if (ps2keyboard_available()) {
+ int c = ps2keyboard_read();
+
+ switch (c) {
+ case PS2_ENTER: printf("\n"); break;
+ case PS2_TAB: printf("[Tab]"); break;
+ case PS2_ESC: printf("[ESC]"); break;
+ case PS2_PAGEDOWN: printf("[PgDn]"); break;
+ case PS2_PAGEUP: printf("[PgUp]"); break;
+ case PS2_LEFTARROW: printf("[Left]"); break;
+ case PS2_RIGHTARROW: printf("[Right]"); break;
+ case PS2_UPARROW: printf("[Up]"); break;
+ case PS2_DOWNARROW: printf("[Down]"); break;
+ case PS2_DELETE: printf("[Del]"); break;
+ default:
+ if (c > 0) {
+ putchar(c);
+ }
+ break;
+ }
+ fflush(stdout);
+ } else {
+ vTaskDelay(pdMS_TO_TICKS(5));
+ }
+ }
+}
diff --git a/examples/simple_test/sdkconfig.defaults b/examples/simple_test/sdkconfig.defaults
new file mode 100644
index 0000000..8e326e3
--- /dev/null
+++ b/examples/simple_test/sdkconfig.defaults
@@ -0,0 +1,2 @@
+CONFIG_FREERTOS_HZ=1000
+CONFIG_ESP_TASK_WDT_INIT=n
diff --git a/idf_component.yml b/idf_component.yml
new file mode 100644
index 0000000..1dc4f3f
--- /dev/null
+++ b/idf_component.yml
@@ -0,0 +1,19 @@
+version: "3.1.0"
+description: "PS/2 keyboard driver for ESP-IDF (ESP32 family). Provides scan code reading, ISO-8859 character translation, modifier handling and Caps/Num/Scroll Lock LED control."
+url: "https://github.com/lahirunirmalx/PS2Keyboard"
+repository: "https://github.com/lahirunirmalx/PS2Keyboard.git"
+documentation: "https://github.com/lahirunirmalx/PS2Keyboard#readme"
+issues: "https://github.com/lahirunirmalx/PS2Keyboard/issues"
+license: "LGPL-2.1-or-later"
+maintainers:
+ - "Lahiru "
+tags:
+ - ps2
+ - keyboard
+ - input
+ - hid
+dependencies:
+ idf:
+ version: ">=4.4"
+examples:
+ - path: ./examples/simple_test
diff --git a/include/ps2keyboard.h b/include/ps2keyboard.h
new file mode 100644
index 0000000..f6bd979
--- /dev/null
+++ b/include/ps2keyboard.h
@@ -0,0 +1,227 @@
+/*
+ ps2keyboard.h - PS/2 keyboard driver for ESP-IDF
+ Copyright (c) 2007 Free Software Foundation. All rights reserved.
+
+ Originally written by Christian Weichel .
+ Mostly rewritten by Paul Stoffregen , June 2010.
+ Modified for Arduino 13 by L. Abraham Smith .
+ Modified for easy interrupt pin assignment by Cuningan .
+ Modified for ESP32/ESP8266 (Arduino) by Lahiru .
+ Ported to native ESP-IDF by Lahiru , 2026.
+
+ 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.
+*/
+
+#ifndef PS2KEYBOARD_H
+#define PS2KEYBOARD_H
+
+#include
+#include
+
+#include "driver/gpio.h"
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Special key codes returned by ps2keyboard_read(). Set to 0 to ignore. */
+#define PS2_TAB 9
+#define PS2_ENTER 13
+#define PS2_BACKSPACE 127
+#define PS2_ESC 27
+#define PS2_INSERT 0
+#define PS2_DELETE 127
+#define PS2_HOME 0
+#define PS2_END 0
+#define PS2_PAGEUP 25
+#define PS2_PAGEDOWN 26
+#define PS2_UPARROW 11
+#define PS2_LEFTARROW 8
+#define PS2_DOWNARROW 10
+#define PS2_RIGHTARROW 21
+#define PS2_F1 0
+#define PS2_F2 0
+#define PS2_F3 0
+#define PS2_F4 0
+#define PS2_F5 0
+#define PS2_F6 0
+#define PS2_F7 0
+#define PS2_F8 0
+#define PS2_F9 0
+#define PS2_F10 0
+#define PS2_F11 0
+#define PS2_F12 0
+#define PS2_SCROLL 0
+#define PS2_EURO_SIGN 0
+
+/* ISO-8859-1 (Latin-1) symbols, available via shift / AltGr in some keymaps. */
+#define PS2_INVERTED_EXCLAMATION 161
+#define PS2_CENT_SIGN 162
+#define PS2_POUND_SIGN 163
+#define PS2_CURRENCY_SIGN 164
+#define PS2_YEN_SIGN 165
+#define PS2_BROKEN_BAR 166
+#define PS2_SECTION_SIGN 167
+#define PS2_DIAERESIS 168
+#define PS2_COPYRIGHT_SIGN 169
+#define PS2_FEMININE_ORDINAL 170
+#define PS2_LEFT_DOUBLE_ANGLE_QUOTE 171
+#define PS2_NOT_SIGN 172
+#define PS2_HYPHEN 173
+#define PS2_REGISTERED_SIGN 174
+#define PS2_MACRON 175
+#define PS2_DEGREE_SIGN 176
+#define PS2_PLUS_MINUS_SIGN 177
+#define PS2_SUPERSCRIPT_TWO 178
+#define PS2_SUPERSCRIPT_THREE 179
+#define PS2_ACUTE_ACCENT 180
+#define PS2_MICRO_SIGN 181
+#define PS2_PILCROW_SIGN 182
+#define PS2_MIDDLE_DOT 183
+#define PS2_CEDILLA 184
+#define PS2_SUPERSCRIPT_ONE 185
+#define PS2_MASCULINE_ORDINAL 186
+#define PS2_RIGHT_DOUBLE_ANGLE_QUOTE 187
+#define PS2_FRACTION_ONE_QUARTER 188
+#define PS2_FRACTION_ONE_HALF 189
+#define PS2_FRACTION_THREE_QUARTERS 190
+#define PS2_INVERTED_QUESTION_MARK 191
+#define PS2_A_GRAVE 192
+#define PS2_A_ACUTE 193
+#define PS2_A_CIRCUMFLEX 194
+#define PS2_A_TILDE 195
+#define PS2_A_DIAERESIS 196
+#define PS2_A_RING_ABOVE 197
+#define PS2_AE 198
+#define PS2_C_CEDILLA 199
+#define PS2_E_GRAVE 200
+#define PS2_E_ACUTE 201
+#define PS2_E_CIRCUMFLEX 202
+#define PS2_E_DIAERESIS 203
+#define PS2_I_GRAVE 204
+#define PS2_I_ACUTE 205
+#define PS2_I_CIRCUMFLEX 206
+#define PS2_I_DIAERESIS 207
+#define PS2_ETH 208
+#define PS2_N_TILDE 209
+#define PS2_O_GRAVE 210
+#define PS2_O_ACUTE 211
+#define PS2_O_CIRCUMFLEX 212
+#define PS2_O_TILDE 213
+#define PS2_O_DIAERESIS 214
+#define PS2_MULTIPLICATION 215
+#define PS2_O_STROKE 216
+#define PS2_U_GRAVE 217
+#define PS2_U_ACUTE 218
+#define PS2_U_CIRCUMFLEX 219
+#define PS2_U_DIAERESIS 220
+#define PS2_Y_ACUTE 221
+#define PS2_THORN 222
+#define PS2_SHARP_S 223
+#define PS2_a_GRAVE 224
+#define PS2_a_ACUTE 225
+#define PS2_a_CIRCUMFLEX 226
+#define PS2_a_TILDE 227
+#define PS2_a_DIAERESIS 228
+#define PS2_a_RING_ABOVE 229
+#define PS2_ae 230
+#define PS2_c_CEDILLA 231
+#define PS2_e_GRAVE 232
+#define PS2_e_ACUTE 233
+#define PS2_e_CIRCUMFLEX 234
+#define PS2_e_DIAERESIS 235
+#define PS2_i_GRAVE 236
+#define PS2_i_ACUTE 237
+#define PS2_i_CIRCUMFLEX 238
+#define PS2_i_DIAERESIS 239
+#define PS2_eth 240
+#define PS2_n_TILDE 241
+#define PS2_o_GRAVE 242
+#define PS2_o_ACUTE 243
+#define PS2_o_CIRCUMFLEX 244
+#define PS2_o_TILDE 245
+#define PS2_o_DIAERESIS 246
+#define PS2_DIVISION 247
+#define PS2_o_STROKE 248
+#define PS2_u_GRAVE 249
+#define PS2_u_ACUTE 250
+#define PS2_u_CIRCUMFLEX 251
+#define PS2_u_DIAERESIS 252
+#define PS2_y_ACUTE 253
+#define PS2_thorn 254
+#define PS2_y_DIAERESIS 255
+
+#define PS2_KEYMAP_SIZE 136
+
+typedef struct {
+ uint8_t noshift[PS2_KEYMAP_SIZE];
+ uint8_t shift[PS2_KEYMAP_SIZE];
+ uint32_t uses_altgr;
+ uint8_t altgr[PS2_KEYMAP_SIZE];
+} ps2_keymap_t;
+
+/* US keyboard layout (default). */
+extern const ps2_keymap_t ps2_keymap_us;
+
+/**
+ * @brief Initialise the PS/2 keyboard driver.
+ *
+ * Configures the data and clock GPIO pins, installs the GPIO ISR service
+ * (if not already installed) and attaches the falling-edge interrupt on the
+ * clock pin.
+ *
+ * @param data_pin GPIO connected to the PS/2 DATA line.
+ * @param clock_pin GPIO connected to the PS/2 CLOCK line (interrupt source).
+ * @param keymap Keymap to use (e.g. &ps2_keymap_us). Pass NULL for default.
+ *
+ * @return ESP_OK on success, otherwise an esp_err_t code from the GPIO driver.
+ */
+esp_err_t ps2keyboard_begin(gpio_num_t data_pin,
+ gpio_num_t clock_pin,
+ const ps2_keymap_t *keymap);
+
+/**
+ * @brief Release ISR resources and reset internal state.
+ */
+void ps2keyboard_end(void);
+
+/**
+ * @brief Returns true if at least one decoded character is ready.
+ */
+bool ps2keyboard_available(void);
+
+/**
+ * @brief Discard any buffered character without returning it.
+ */
+void ps2keyboard_clear(void);
+
+/**
+ * @brief Pop one raw PS/2 scan code from the receive buffer.
+ *
+ * @return Scan code (0x00..0xFF), or 0 if the buffer is empty.
+ */
+uint8_t ps2keyboard_read_scancode(void);
+
+/**
+ * @brief Read the next decoded character, expanding non-ASCII to UTF-8.
+ *
+ * @return The byte read (0x00..0xFF), or -1 if no character is available.
+ */
+int ps2keyboard_read(void);
+
+/**
+ * @brief Read the next decoded character as a single Unicode code point.
+ *
+ * @return The code point (ISO-8859-1 range), or -1 if none available.
+ */
+int ps2keyboard_read_unicode(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PS2KEYBOARD_H */
diff --git a/keywords.txt b/keywords.txt
deleted file mode 100644
index bd2c18a..0000000
--- a/keywords.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-#######################################
-# Syntax Coloring Map For PS2Keyboard
-#######################################
-
-#######################################
-# Datatypes (KEYWORD1)
-#######################################
-
-PS2Keyboard KEYWORD1
-
-#######################################
-# Methods and Functions (KEYWORD2)
-#######################################
-
-#######################################
-# Constants (LITERAL1)
-#######################################
-
-PS2_KC_BREAK LITERAL1
-PS2_KC_ENTER LITERAL1
-PS2_KC_ESC LITERAL1
-PS2_KC_KPLUS LITERAL1
-PS2_KC_KMINUS LITERAL1
-PS2_KC_KMULTI LITERAL1
-PS2_KC_NUM LITERAL1
-PS2_KC_BKSP LITERAL1
diff --git a/library.json b/library.json
deleted file mode 100644
index 77cc9c1..0000000
--- a/library.json
+++ /dev/null
@@ -1,42 +0,0 @@
-{
- "name": "PS2Keyboard",
- "keywords": "keyboard, emulation",
- "description": "PS2Keyboard (PS/2) allows you to use a keyboard for user input",
- "authors":
- [
- {
- "name": "Paul Stoffregen",
- "email": "paul@pjrc.com",
- "url": "http://www.pjrc.com",
- "maintainer": true
- },
- {
- "name": "Christian Weichel",
- "email": "info@32leaves.net"
- },
- {
- "name": "L. Abraham Smith",
- "email": "n3bah@microcompdesign.com"
- },
- {
- "name": "Cuningan",
- "email": "cuninganreset@gmail.com"
- }
- ],
- "repository":
- {
- "type": "git",
- "url": "https://github.com/PaulStoffregen/PS2Keyboard.git"
- },
- "version": "2.4",
- "homepage": "http://www.pjrc.com/teensy/td_libs_PS2Keyboard.html",
- "frameworks": "arduino",
- "platforms":
- [
- "atmelavr",
- "teensy"
- ],
- "examples": [
- "examples/*/*.pde"
- ]
-}
diff --git a/library.properties b/library.properties
deleted file mode 100644
index 340d0ba..0000000
--- a/library.properties
+++ /dev/null
@@ -1,10 +0,0 @@
-name=PS2Keyboard
-version=2.4
-author=Christian Weichel, Paul Stoffregen, L. Abraham Smith, Cuningan
-maintainer=Paul Stoffregen
-sentence=Use a PS/2 Keyboard for input
-paragraph=
-category=Signal Input/Output
-url=https://github.com/PaulStoffregen/PS2Keyboard
-architectures=*
-
diff --git a/src/ps2keyboard.c b/src/ps2keyboard.c
new file mode 100644
index 0000000..4976001
--- /dev/null
+++ b/src/ps2keyboard.c
@@ -0,0 +1,509 @@
+/*
+ ps2keyboard.c - PS/2 keyboard driver for ESP-IDF.
+
+ Originally derived from the Arduino PS2Keyboard library by
+ Christian Weichel, Paul Stoffregen, L. Abraham Smith, Cuningan and
+ Lahiru Nirmal. Ported to native ESP-IDF, 2026.
+
+ Released under the GNU Lesser General Public License v2.1.
+*/
+
+#include "ps2keyboard.h"
+
+#include
+
+#include "driver/gpio.h"
+#include "esp_attr.h"
+#include "esp_err.h"
+#include "esp_log.h"
+#include "esp_timer.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+static const char *TAG = "ps2keyboard";
+
+#define PS2_BUFFER_SIZE 45
+#define PS2_LED_CONTROL 0xED
+
+/* State machine flags for scan-code processing. */
+#define PS2_BREAK 0x01
+#define PS2_MODIFIER 0x02
+#define PS2_SHIFT_L 0x04
+#define PS2_SHIFT_R 0x08
+#define PS2_ALTGR 0x10
+
+/* LED state bit flags (PS/2 LED command payload). */
+#define PS2_LED_SCROLL 0x01
+#define PS2_LED_NUM 0x02
+#define PS2_LED_CAPS 0x04
+
+static volatile uint8_t s_buffer[PS2_BUFFER_SIZE];
+static volatile uint8_t s_head;
+static volatile uint8_t s_tail;
+
+/*
+ ISR frame state lives at file scope (rather than function-local statics)
+ so that ps2_send_byte() can clear it after re-enabling the clock-line
+ interrupt. Otherwise a stale bit_count from before the bit-bang can
+ corrupt the first scan code that follows an LED update.
+*/
+static volatile uint8_t s_isr_bit_count;
+static volatile uint8_t s_isr_incoming;
+static volatile uint32_t s_isr_prev_us;
+
+static gpio_num_t s_data_pin = GPIO_NUM_NC;
+static gpio_num_t s_clock_pin = GPIO_NUM_NC;
+
+static const ps2_keymap_t *s_keymap;
+
+static uint8_t s_char_buffer;
+static uint8_t s_utf8_next;
+
+static bool s_caps_lock_on;
+static bool s_num_lock_on;
+static bool s_scroll_lock_on;
+static uint8_t s_led_state;
+
+static bool s_isr_service_installed;
+static bool s_isr_handler_added;
+
+/* ---------- low-level pin helpers ---------- */
+
+static inline int ps2_read_pin(gpio_num_t pin)
+{
+ return gpio_get_level(pin);
+}
+
+static inline void ps2_write_pin(gpio_num_t pin, int level)
+{
+ gpio_set_level(pin, level);
+}
+
+static inline void ps2_pin_input_pullup(gpio_num_t pin)
+{
+ gpio_set_direction(pin, GPIO_MODE_INPUT);
+ gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY);
+}
+
+static inline void ps2_pin_output(gpio_num_t pin)
+{
+ gpio_set_direction(pin, GPIO_MODE_OUTPUT);
+}
+
+static void ps2_busy_wait_us(uint32_t us)
+{
+ int64_t start = esp_timer_get_time();
+ while ((esp_timer_get_time() - start) < (int64_t)us) {
+ /* spin */
+ }
+}
+
+/* Spin-wait until `pin` reaches `target_level`, or until `timeout_us` elapses.
+ Returns true on success, false on timeout. */
+static bool ps2_wait_for_level(gpio_num_t pin, int target_level, uint32_t timeout_us)
+{
+ int64_t deadline = esp_timer_get_time() + (int64_t)timeout_us;
+ while (gpio_get_level(pin) != target_level) {
+ if (esp_timer_get_time() > deadline) {
+ return false;
+ }
+ }
+ return true;
+}
+
+/* ---------- PS/2 command transmit (host -> keyboard) ---------- */
+
+static bool ps2_parity_odd(uint16_t data)
+{
+ uint8_t count = 0;
+ for (int i = 0; i < 10; i++) {
+ count += (data >> i) & 1U;
+ }
+ return (count % 2U) != 0U;
+}
+
+/*
+ Bit-bangs one byte (with parity + stop) to the keyboard. The clock-line
+ ISR is disabled for the duration so the device-driven clock doesn't
+ fire our scan-code handler with garbage.
+
+ Reference: https://karooza.net/how-to-interface-a-ps2-keyboard
+*/
+/* PS/2 host-to-device framing tops out around 70us per clock half-cycle.
+ 10ms per transition is comfortably generous and lets us bail out without
+ hanging the consumer task if the device stops clocking. */
+#define PS2_TX_PIN_TIMEOUT_US 10000U
+
+static esp_err_t ps2_send_byte(uint8_t cmd_byte)
+{
+ uint16_t cmd = cmd_byte;
+ if (!ps2_parity_odd(cmd)) {
+ cmd |= 0x0100; /* odd parity bit */
+ }
+ cmd |= 0x0200; /* stop bit */
+
+ gpio_intr_disable(s_clock_pin);
+
+ /* Pull clock low for ~100us to request transmission. */
+ ps2_pin_output(s_clock_pin);
+ ps2_pin_output(s_data_pin);
+ ps2_write_pin(s_clock_pin, 0);
+ ps2_busy_wait_us(100);
+
+ /* Start bit: pull data low, then release clock. */
+ ps2_write_pin(s_data_pin, 0);
+ ps2_busy_wait_us(20);
+ ps2_pin_input_pullup(s_clock_pin);
+
+ esp_err_t err = ESP_OK;
+
+ /* 8 data bits + parity + stop bit. */
+ for (int i = 0; i < 10; i++) {
+ if (!ps2_wait_for_level(s_clock_pin, 0, PS2_TX_PIN_TIMEOUT_US)) {
+ err = ESP_ERR_TIMEOUT;
+ goto out;
+ }
+ ps2_write_pin(s_data_pin, cmd & 0x0001);
+ cmd >>= 1;
+ if (!ps2_wait_for_level(s_clock_pin, 1, PS2_TX_PIN_TIMEOUT_US)) {
+ err = ESP_ERR_TIMEOUT;
+ goto out;
+ }
+ }
+
+ /* Release data line for the device-driven ack. */
+ ps2_pin_input_pullup(s_data_pin);
+
+ /* Wait for keyboard ACK: clock low + data low. */
+ if (!ps2_wait_for_level(s_clock_pin, 0, PS2_TX_PIN_TIMEOUT_US) ||
+ !ps2_wait_for_level(s_data_pin, 0, PS2_TX_PIN_TIMEOUT_US)) {
+ err = ESP_ERR_TIMEOUT;
+ }
+
+out:
+ ps2_pin_input_pullup(s_clock_pin);
+ ps2_pin_input_pullup(s_data_pin);
+
+ /* The device-driven clock cycles during this bit-bang were masked, so
+ any stale bit_count carried over would corrupt the next genuine scan
+ code. Reset before re-arming the ISR. */
+ s_isr_bit_count = 0;
+ s_isr_incoming = 0;
+ s_isr_prev_us = (uint32_t)esp_timer_get_time();
+
+ gpio_intr_enable(s_clock_pin);
+ return err;
+}
+
+static void ps2_update_leds(uint8_t leds)
+{
+ if (ps2_send_byte(PS2_LED_CONTROL) != ESP_OK) {
+ return;
+ }
+ (void)ps2_send_byte(leds);
+}
+
+/* ---------- ISR: clock-line falling edge ---------- */
+
+static void IRAM_ATTR ps2_isr_handler(void *arg)
+{
+ (void)arg;
+
+ /* 32-bit time math is enough for the 250ms timeout and is cheaper on
+ the LX6 than the int64_t subtraction esp_timer_get_time() returns.
+ Wraparound (every ~71 minutes) is handled by unsigned subtraction. */
+ uint32_t now_us = (uint32_t)esp_timer_get_time();
+ int val = gpio_get_level(s_data_pin);
+
+ if ((uint32_t)(now_us - s_isr_prev_us) > 250000U) {
+ s_isr_bit_count = 0;
+ s_isr_incoming = 0;
+ }
+ s_isr_prev_us = now_us;
+
+ /* On the start-bit call, bit_count is 0 and (0 - 1) underflows to 0xFF
+ which fails the <=7 check. Subsequent calls land bits 0..7 into
+ incoming. */
+ uint8_t bit_pos = (uint8_t)(s_isr_bit_count - 1);
+ if (bit_pos <= 7) {
+ s_isr_incoming |= (uint8_t)(val << bit_pos);
+ }
+ s_isr_bit_count++;
+
+ if (s_isr_bit_count == 11) {
+ uint8_t i = (uint8_t)(s_head + 1);
+ if (i >= PS2_BUFFER_SIZE) {
+ i = 0;
+ }
+ if (i != s_tail) {
+ s_buffer[i] = s_isr_incoming;
+ s_head = i;
+ }
+ s_isr_bit_count = 0;
+ s_isr_incoming = 0;
+ }
+}
+
+static inline uint8_t ps2_get_scancode(void)
+{
+ uint8_t i = s_tail;
+ if (i == s_head) {
+ return 0;
+ }
+ i++;
+ if (i >= PS2_BUFFER_SIZE) {
+ i = 0;
+ }
+ uint8_t c = s_buffer[i];
+ s_tail = i;
+ return c;
+}
+
+/* ---------- scan-code -> ISO-8859-1 decoder ---------- */
+
+static uint8_t ps2_decode_iso8859(void)
+{
+ static uint8_t state = 0;
+
+ /* Bail safely if a caller polled before ps2keyboard_begin() ran. */
+ if (s_keymap == NULL) {
+ return 0;
+ }
+
+ while (1) {
+ uint8_t scan = ps2_get_scancode();
+ if (!scan) {
+ return 0;
+ }
+
+ if (scan == 0xF0) {
+ state |= PS2_BREAK;
+ continue;
+ }
+ if (scan == 0xE0) {
+ state |= PS2_MODIFIER;
+ continue;
+ }
+
+ if (state & PS2_BREAK) {
+ if (scan == 0x12) {
+ state &= ~PS2_SHIFT_L;
+ } else if (scan == 0x59) {
+ state &= ~PS2_SHIFT_R;
+ } else if (scan == 0x11 && (state & PS2_MODIFIER)) {
+ state &= ~PS2_ALTGR;
+ }
+ state &= ~(PS2_BREAK | PS2_MODIFIER);
+ continue;
+ }
+
+ if (scan == 0x12) {
+ state |= PS2_SHIFT_L;
+ continue;
+ }
+ if (scan == 0x59) {
+ state |= PS2_SHIFT_R;
+ continue;
+ }
+ if (scan == 0x11 && (state & PS2_MODIFIER)) {
+ state |= PS2_ALTGR;
+ } else if (scan == 0x58) {
+ s_caps_lock_on = !s_caps_lock_on;
+ s_led_state = s_caps_lock_on
+ ? (s_led_state | PS2_LED_CAPS)
+ : (s_led_state & (uint8_t)~PS2_LED_CAPS);
+ ps2_update_leds(s_led_state);
+ } else if (scan == 0x77) {
+ s_num_lock_on = !s_num_lock_on;
+ s_led_state = s_num_lock_on
+ ? (s_led_state | PS2_LED_NUM)
+ : (s_led_state & (uint8_t)~PS2_LED_NUM);
+ ps2_update_leds(s_led_state);
+ } else if (scan == 0x7E) {
+ s_scroll_lock_on = !s_scroll_lock_on;
+ s_led_state = s_scroll_lock_on
+ ? (s_led_state | PS2_LED_SCROLL)
+ : (s_led_state & (uint8_t)~PS2_LED_SCROLL);
+ ps2_update_leds(s_led_state);
+ }
+
+ uint8_t ch = 0;
+ if (state & PS2_MODIFIER) {
+ switch (scan) {
+ case 0x70: ch = PS2_INSERT; break;
+ case 0x6C: ch = PS2_HOME; break;
+ case 0x7D: ch = PS2_PAGEUP; break;
+ case 0x71: ch = PS2_DELETE; break;
+ case 0x69: ch = PS2_END; break;
+ case 0x7A: ch = PS2_PAGEDOWN; break;
+ case 0x75: ch = PS2_UPARROW; break;
+ case 0x6B: ch = PS2_LEFTARROW; break;
+ case 0x72: ch = PS2_DOWNARROW; break;
+ case 0x74: ch = PS2_RIGHTARROW; break;
+ case 0x4A: ch = '/'; break;
+ case 0x5A: ch = PS2_ENTER; break;
+ default: break;
+ }
+ } else if ((state & PS2_ALTGR) && s_keymap->uses_altgr) {
+ if (scan < PS2_KEYMAP_SIZE) {
+ ch = s_keymap->altgr[scan];
+ }
+ } else if (scan < PS2_KEYMAP_SIZE) {
+ /* Caps Lock only inverts shift for alphabetic keys (a-z); for
+ everything else (digits, punctuation, function keys), Shift
+ is the sole modifier. Detect "letter" by inspecting the
+ unshifted entry rather than carrying a parallel flag table. */
+ bool shift_active = (state & (PS2_SHIFT_L | PS2_SHIFT_R)) != 0;
+ uint8_t ns = s_keymap->noshift[scan];
+ bool is_alpha = (ns >= 'a' && ns <= 'z');
+ bool effective_shift = shift_active ^ (is_alpha && s_caps_lock_on);
+ ch = effective_shift ? s_keymap->shift[scan] : ns;
+ }
+
+ state &= ~(PS2_BREAK | PS2_MODIFIER);
+
+ if (ch) {
+ return ch;
+ }
+ }
+}
+
+/* ---------- public API ---------- */
+
+esp_err_t ps2keyboard_begin(gpio_num_t data_pin,
+ gpio_num_t clock_pin,
+ const ps2_keymap_t *keymap)
+{
+ if (!GPIO_IS_VALID_GPIO(data_pin) || !GPIO_IS_VALID_GPIO(clock_pin)) {
+ return ESP_ERR_INVALID_ARG;
+ }
+
+ s_data_pin = data_pin;
+ s_clock_pin = clock_pin;
+ s_keymap = (keymap != NULL) ? keymap : &ps2_keymap_us;
+ s_head = 0;
+ s_tail = 0;
+ s_char_buffer = 0;
+ s_utf8_next = 0;
+ s_caps_lock_on = false;
+ s_num_lock_on = false;
+ s_scroll_lock_on = false;
+ s_led_state = 0;
+ s_isr_bit_count = 0;
+ s_isr_incoming = 0;
+ s_isr_prev_us = 0;
+
+ gpio_config_t data_cfg = {
+ .pin_bit_mask = (1ULL << data_pin),
+ .mode = GPIO_MODE_INPUT,
+ .pull_up_en = GPIO_PULLUP_ENABLE,
+ .pull_down_en = GPIO_PULLDOWN_DISABLE,
+ .intr_type = GPIO_INTR_DISABLE,
+ };
+ esp_err_t err = gpio_config(&data_cfg);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "gpio_config(data) failed: %s", esp_err_to_name(err));
+ return err;
+ }
+
+ gpio_config_t clk_cfg = {
+ .pin_bit_mask = (1ULL << clock_pin),
+ .mode = GPIO_MODE_INPUT,
+ .pull_up_en = GPIO_PULLUP_ENABLE,
+ .pull_down_en = GPIO_PULLDOWN_DISABLE,
+ .intr_type = GPIO_INTR_NEGEDGE,
+ };
+ err = gpio_config(&clk_cfg);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "gpio_config(clock) failed: %s", esp_err_to_name(err));
+ return err;
+ }
+
+ if (!s_isr_service_installed) {
+ err = gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
+ if (err == ESP_OK) {
+ s_isr_service_installed = true;
+ } else if (err != ESP_ERR_INVALID_STATE) {
+ ESP_LOGE(TAG, "gpio_install_isr_service failed: %s", esp_err_to_name(err));
+ return err;
+ }
+ }
+
+ err = gpio_isr_handler_add(clock_pin, ps2_isr_handler, NULL);
+ if (err != ESP_OK) {
+ ESP_LOGE(TAG, "gpio_isr_handler_add failed: %s", esp_err_to_name(err));
+ return err;
+ }
+ s_isr_handler_added = true;
+
+ return ESP_OK;
+}
+
+void ps2keyboard_end(void)
+{
+ if (s_isr_handler_added && s_clock_pin != GPIO_NUM_NC) {
+ gpio_isr_handler_remove(s_clock_pin);
+ s_isr_handler_added = false;
+ }
+ s_char_buffer = 0;
+ s_utf8_next = 0;
+ s_head = 0;
+ s_tail = 0;
+}
+
+bool ps2keyboard_available(void)
+{
+ if (s_char_buffer || s_utf8_next) {
+ return true;
+ }
+ s_char_buffer = (uint8_t)ps2_decode_iso8859();
+ return s_char_buffer != 0;
+}
+
+void ps2keyboard_clear(void)
+{
+ s_char_buffer = 0;
+ s_utf8_next = 0;
+}
+
+uint8_t ps2keyboard_read_scancode(void)
+{
+ return ps2_get_scancode();
+}
+
+int ps2keyboard_read(void)
+{
+ uint8_t result = s_utf8_next;
+ if (result) {
+ s_utf8_next = 0;
+ } else {
+ result = s_char_buffer;
+ if (result) {
+ s_char_buffer = 0;
+ } else {
+ result = (uint8_t)ps2_decode_iso8859();
+ }
+ if (result >= 128) {
+ s_utf8_next = (uint8_t)((result & 0x3F) | 0x80);
+ result = (uint8_t)(((result >> 6) & 0x1F) | 0xC0);
+ }
+ }
+ if (!result) {
+ return -1;
+ }
+ return result;
+}
+
+int ps2keyboard_read_unicode(void)
+{
+ int result = s_char_buffer;
+ if (!result) {
+ result = (uint8_t)ps2_decode_iso8859();
+ }
+ if (!result) {
+ return -1;
+ }
+ s_utf8_next = 0;
+ s_char_buffer = 0;
+ return result;
+}
diff --git a/src/ps2keymap_us.c b/src/ps2keymap_us.c
new file mode 100644
index 0000000..fc01a82
--- /dev/null
+++ b/src/ps2keymap_us.c
@@ -0,0 +1,54 @@
+/*
+ ps2keymap_us.c - US keymap for the PS/2 keyboard ESP-IDF component.
+
+ Scan code references:
+ http://www.quadibloc.com/comp/scan.htm
+ http://www.computer-engineering.org/ps2keyboard/scancodes2.html
+*/
+
+#include "ps2keyboard.h"
+
+const ps2_keymap_t ps2_keymap_us = {
+ /* without shift */
+ {
+ 0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
+ 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '`', 0,
+ 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'q', '1', 0,
+ 0, 0, 'z', 's', 'a', 'w', '2', 0,
+ 0, 'c', 'x', 'd', 'e', '4', '3', 0,
+ 0, ' ', 'v', 'f', 't', 'r', '5', 0,
+ 0, 'n', 'b', 'h', 'g', 'y', '6', 0,
+ 0, 0, 'm', 'j', 'u', '7', '8', 0,
+ 0, ',', 'k', 'i', 'o', '0', '9', 0,
+ 0, '.', '/', 'l', ';', 'p', '-', 0,
+ 0, 0, '\'', 0, '[', '=', 0, 0,
+ 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER, ']', 0, '\\', 0, 0,
+ 0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
+ 0, '1', 0, '4', '7', 0, 0, 0,
+ '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
+ PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
+ 0, 0, 0, PS2_F7
+ },
+ /* with shift */
+ {
+ 0, PS2_F9, 0, PS2_F5, PS2_F3, PS2_F1, PS2_F2, PS2_F12,
+ 0, PS2_F10, PS2_F8, PS2_F6, PS2_F4, PS2_TAB, '~', 0,
+ 0, 0 /*Lalt*/, 0 /*Lshift*/, 0, 0 /*Lctrl*/, 'Q', '!', 0,
+ 0, 0, 'Z', 'S', 'A', 'W', '@', 0,
+ 0, 'C', 'X', 'D', 'E', '$', '#', 0,
+ 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
+ 0, 'N', 'B', 'H', 'G', 'Y', '^', 0,
+ 0, 0, 'M', 'J', 'U', '&', '*', 0,
+ 0, '<', 'K', 'I', 'O', ')', '(', 0,
+ 0, '>', '?', 'L', ':', 'P', '_', 0,
+ 0, 0, '"', 0, '{', '+', 0, 0,
+ 0 /*CapsLock*/, 0 /*Rshift*/, PS2_ENTER, '}', 0, '|', 0, 0,
+ 0, 0, 0, 0, 0, 0, PS2_BACKSPACE, 0,
+ 0, '1', 0, '4', '7', 0, 0, 0,
+ '0', '.', '2', '5', '6', '8', PS2_ESC, 0 /*NumLock*/,
+ PS2_F11, '+', '3', '-', '*', '9', PS2_SCROLL, 0,
+ 0, 0, 0, PS2_F7
+ },
+ 0, /* uses_altgr */
+ { 0 },
+};
diff --git a/utility/int_pins.h b/utility/int_pins.h
deleted file mode 100644
index 9621721..0000000
--- a/utility/int_pins.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// interrupt pins for known boards
-
-// Teensy and maybe others automatically define this info
-#if !defined(CORE_INT0_PIN) && !defined(CORE_INT1_PIN) && !defined(CORE_INT2_PIN)&& !defined(CORE_INT3_PIN)
-
-// Arduino Mega
-#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Arduino Mega
- #define CORE_INT0_PIN 2
- #define CORE_INT1_PIN 3
- #define CORE_INT2_PIN 21
- #define CORE_INT3_PIN 20
- #define CORE_INT4_PIN 19
- #define CORE_INT5_PIN 18
-
-// Arduino Due (untested)
-#elif defined(__SAM3X8E__)
- #define CORE_INT_EVERY_PIN
- #ifndef PROGMEM
- #define PROGMEM
- #endif
- #ifndef pgm_read_byte
- #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
- #endif
-
-// Arduino Leonardo (untested)
-#elif defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY)
- #define CORE_INT0_PIN 3
- #define CORE_INT1_PIN 2
- #define CORE_INT2_PIN 0
- #define CORE_INT3_PIN 1
-
-// Sanguino (untested)
-#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) // Sanguino
- #define CORE_INT0_PIN 10
- #define CORE_INT1_PIN 11
- #define CORE_INT2_PIN 2
-
-// Chipkit Uno32 (untested)
-#elif defined(__PIC32MX__) && defined(_BOARD_UNO_)
- #define CORE_INT0_PIN 38
- #define CORE_INT1_PIN 2
- #define CORE_INT2_PIN 7
- #define CORE_INT3_PIN 8
- #define CORE_INT4_PIN 35
-
-// Chipkit Mega32 (untested)
-#elif defined(__PIC32MX__) && defined(_BOARD_MEGA_)
- #define CORE_INT0_PIN 3
- #define CORE_INT1_PIN 2
- #define CORE_INT2_PIN 7
- #define CORE_INT3_PIN 21
- #define CORE_INT4_PIN 20
-
-// http://hlt.media.mit.edu/?p=1229
-#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
- #define CORE_INT0_PIN 2
-
-#elif defined(__AVR_ATtiny84__)
- #define CORE_INT0_PIN 8
-
-//ESP8266 - NodeMCU 0.9 (ESP-12 Module) / NodeMCU 1.0 (ESP-12E Module)
-#elif defined(ESP8266)
- #define CORE_INT_EVERY_PIN
-
-//ESP32 support
-#elif defined(ESP32)
- #define CORE_INT_EVERY_PIN
-
-//STM32F1 support
-#elif defined(__STM32F1__)
- #define CORE_INT_EVERY_PIN
-
-// Arduino Uno, Duemilanove, LilyPad, Mini, Fio, etc...
-#else
- #define CORE_INT0_PIN 2
- #define CORE_INT1_PIN 3
-
-#endif
-#endif
-