aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/shared-bindings/keypad
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/shared-bindings/keypad
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/shared-bindings/keypad')
-rw-r--r--circuitpython/shared-bindings/keypad/Event.c197
-rw-r--r--circuitpython/shared-bindings/keypad/Event.h41
-rw-r--r--circuitpython/shared-bindings/keypad/EventQueue.c152
-rw-r--r--circuitpython/shared-bindings/keypad/EventQueue.h45
-rw-r--r--circuitpython/shared-bindings/keypad/KeyMatrix.c236
-rw-r--r--circuitpython/shared-bindings/keypad/KeyMatrix.h45
-rw-r--r--circuitpython/shared-bindings/keypad/Keys.c168
-rw-r--r--circuitpython/shared-bindings/keypad/Keys.h39
-rw-r--r--circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c172
-rw-r--r--circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h39
-rw-r--r--circuitpython/shared-bindings/keypad/__init__.c108
-rw-r--r--circuitpython/shared-bindings/keypad/__init__.h44
12 files changed, 1286 insertions, 0 deletions
diff --git a/circuitpython/shared-bindings/keypad/Event.c b/circuitpython/shared-bindings/keypad/Event.c
new file mode 100644
index 0000000..380b6b5
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Event.c
@@ -0,0 +1,197 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/supervisor/__init__.h"
+
+//| class Event:
+//| """A key transition event."""
+//| def __init__(self, key_number: int=0, pressed: bool=True, timestamp:Optional[int]=None) -> None:
+//| """Create a key transition event, which reports a key-pressed or key-released transition.
+//|
+//| :param int key_number: The key number.
+//| :param bool pressed: ``True`` if the key was pressed; ``False`` if it was released.
+//| :param int timestamp: The time in milliseconds that the keypress occurred in the `supervisor.ticks_ms` time system. If specified as None, the current value of `supervisor.ticks_ms` is used.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_event_obj_t *self = m_new_obj(keypad_event_obj_t);
+ self->base.type = &keypad_event_type;
+ enum { ARG_key_number, ARG_pressed, ARG_timestamp };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_key_number, MP_ARG_INT, {.u_int = 0} },
+ { MP_QSTR_pressed, MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_timestamp, MP_ARG_OBJ, {.u_obj = mp_const_none} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mp_uint_t key_number =
+ (mp_uint_t)mp_arg_validate_int_min(args[ARG_key_number].u_int, 0, MP_QSTR_key_number);
+
+ mp_obj_t timestamp = args[ARG_timestamp].u_obj;
+ if (timestamp == mp_const_none) {
+ timestamp = supervisor_ticks_ms();
+ }
+
+ (void)mp_obj_get_int_truncated(timestamp); // ensure that timesamp is an integer
+ common_hal_keypad_event_construct(self, key_number, args[ARG_pressed].u_bool, timestamp);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| key_number: int
+//| """The key number."""
+//|
+STATIC mp_obj_t keypad_event_get_key_number(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_event_get_key_number(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_key_number_obj, keypad_event_get_key_number);
+
+MP_PROPERTY_GETTER(keypad_event_key_number_obj,
+ (mp_obj_t)&keypad_event_get_key_number_obj);
+
+//| pressed: bool
+//| """``True`` if the event represents a key down (pressed) transition.
+//| The opposite of `released`.
+//| """
+//|
+STATIC mp_obj_t keypad_event_get_pressed(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_keypad_event_get_pressed(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_pressed_obj, keypad_event_get_pressed);
+
+MP_PROPERTY_GETTER(keypad_event_pressed_obj,
+ (mp_obj_t)&keypad_event_get_pressed_obj);
+
+//| released: bool
+//| """``True`` if the event represents a key up (released) transition.
+//| The opposite of `pressed`.
+//| """
+//|
+STATIC mp_obj_t keypad_event_get_released(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_keypad_event_get_released(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_released_obj, keypad_event_get_released);
+
+MP_PROPERTY_GETTER(keypad_event_released_obj,
+ (mp_obj_t)&keypad_event_get_released_obj);
+
+//| timestamp: int
+//| """The timestamp."""
+//|
+STATIC mp_obj_t keypad_event_get_timestamp(mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return common_hal_keypad_event_get_timestamp(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_event_get_timestamp_obj, keypad_event_get_timestamp);
+
+MP_PROPERTY_GETTER(keypad_event_timestamp_obj,
+ (mp_obj_t)&keypad_event_get_timestamp_obj);
+
+
+//| def __eq__(self, other: object) -> bool:
+//| """Two `Event` objects are equal if their `key_number`
+//| and `pressed`/`released` values are equal.
+//| Note that this does not compare the event timestamps.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_event_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
+ switch (op) {
+ case MP_BINARY_OP_EQUAL:
+ if (mp_obj_is_type(rhs_in, &keypad_event_type)) {
+ keypad_event_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in);
+ keypad_event_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in);
+ return mp_obj_new_bool(
+ (common_hal_keypad_event_get_key_number(lhs) ==
+ common_hal_keypad_event_get_key_number(rhs)) &&
+ (common_hal_keypad_event_get_pressed(lhs) ==
+ common_hal_keypad_event_get_pressed(rhs))
+ );
+ } else {
+ return mp_const_false;
+ }
+
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| def __hash__(self) -> int:
+//| """Returns a hash for the `Event`, so it can be used in dictionaries, etc..
+//|
+//| Note that as events with different timestamps compare equal, they also hash to the same value."""
+//| ...
+//|
+STATIC mp_obj_t keypad_event_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ switch (op) {
+ case MP_UNARY_OP_HASH: {
+ const mp_int_t key_number = common_hal_keypad_event_get_key_number(self);
+ const bool pressed = common_hal_keypad_event_get_pressed(self);
+ return MP_OBJ_NEW_SMALL_INT((pressed << 15) + key_number);
+ }
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+STATIC void keypad_event_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
+ keypad_event_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ mp_printf(print, "<Event: key_number %d %s>",
+ common_hal_keypad_event_get_key_number(self),
+ common_hal_keypad_event_get_pressed(self) ? "pressed" : "released");
+}
+
+STATIC const mp_rom_map_elem_t keypad_event_locals_dict_table[] = {
+ // Properties
+ { MP_ROM_QSTR(MP_QSTR_key_number), MP_ROM_PTR(&keypad_event_key_number_obj) },
+ { MP_ROM_QSTR(MP_QSTR_pressed), MP_ROM_PTR(&keypad_event_pressed_obj) },
+ { MP_ROM_QSTR(MP_QSTR_released), MP_ROM_PTR(&keypad_event_released_obj) },
+ { MP_ROM_QSTR(MP_QSTR_timestamp), MP_ROM_PTR(&keypad_event_timestamp_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(keypad_event_locals_dict, keypad_event_locals_dict_table);
+
+const mp_obj_type_t keypad_event_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_Event,
+ .make_new = keypad_event_make_new,
+ .print = keypad_event_print,
+ .locals_dict = (mp_obj_dict_t *)&keypad_event_locals_dict,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = keypad_event_unary_op,
+ .binary_op = keypad_event_binary_op,
+ ),
+};
diff --git a/circuitpython/shared-bindings/keypad/Event.h b/circuitpython/shared-bindings/keypad/Event.h
new file mode 100644
index 0000000..44e6929
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Event.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
+
+#include "py/obj.h"
+#include "shared-module/keypad/Event.h"
+
+extern const mp_obj_type_t keypad_event_type;
+
+void common_hal_keypad_event_construct(keypad_event_obj_t *self, mp_uint_t key_number, bool pressed, mp_obj_t timestamp);
+mp_int_t common_hal_keypad_event_get_key_number(keypad_event_obj_t *self);
+bool common_hal_keypad_event_get_pressed(keypad_event_obj_t *self);
+bool common_hal_keypad_event_get_released(keypad_event_obj_t *self);
+mp_obj_t common_hal_keypad_event_get_timestamp(keypad_event_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENT__H
diff --git a/circuitpython/shared-bindings/keypad/EventQueue.c b/circuitpython/shared-bindings/keypad/EventQueue.c
new file mode 100644
index 0000000..8e45f7a
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/EventQueue.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/EventQueue.h"
+
+//| class EventQueue:
+//| """A queue of `Event` objects, filled by a `keypad` scanner such as `Keys` or `KeyMatrix`.
+//|
+//| You cannot create an instance of `EventQueue` directly. Each scanner creates an
+//| instance when it is created.
+//| """
+//| ...
+
+//| def get(self) -> Optional[Event]:
+//| """Return the next key transition event. Return ``None`` if no events are pending.
+//|
+//| Note that the queue size is limited; see ``max_events`` in the constructor of
+//| a scanner such as `Keys` or `KeyMatrix`.
+//| If a new event arrives when the queue is full, the event is discarded, and
+//| `overflowed` is set to ``True``.
+//|
+//| :return: The next queued key transition `Event`.
+//| :rtype: Optional[Event]
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_get(mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ return common_hal_keypad_eventqueue_get(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_obj, keypad_eventqueue_get);
+
+//| def get_into(self, event: Event) -> bool:
+//| """Store the next key transition event in the supplied event, if available,
+//| and return ``True``.
+//| If there are no queued events, do not touch ``event`` and return ``False``.
+//|
+//| The advantage of this method over ``get()`` is that it does not allocate storage.
+//| Instead you can reuse an existing ``Event`` object.
+//|
+//| Note that the queue size is limited; see ``max_events`` in the constructor of
+//| a scanner such as `Keys` or `KeyMatrix`.
+//|
+//| :return: ``True`` if an event was available and stored, ``False`` if not.
+//| :rtype: bool
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_get_into(mp_obj_t self_in, mp_obj_t event_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ keypad_event_obj_t *event = MP_OBJ_TO_PTR(mp_arg_validate_type(event_in, &keypad_event_type, MP_QSTR_event));
+
+ return mp_obj_new_bool(common_hal_keypad_eventqueue_get_into(self, event));
+}
+MP_DEFINE_CONST_FUN_OBJ_2(keypad_eventqueue_get_into_obj, keypad_eventqueue_get_into);
+
+//| def clear(self) -> None:
+//| """Clear any queued key transition events. Also sets `overflowed` to ``False``.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_clear(mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_keypad_eventqueue_clear(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_clear_obj, keypad_eventqueue_clear);
+
+//| def __bool__(self) -> bool:
+//| """``True`` if `len()` is greater than zero.
+//| This is an easy way to check if the queue is empty.
+//| """
+//| ...
+//|
+//| def __len__(self) -> int:
+//| """Return the number of events currently in the queue. Used to implement ``len()``."""
+//| ...
+//|
+STATIC mp_obj_t keypad_eventqueue_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ uint16_t len = common_hal_keypad_eventqueue_get_length(self);
+ switch (op) {
+ case MP_UNARY_OP_BOOL:
+ return mp_obj_new_bool(len != 0);
+ case MP_UNARY_OP_LEN:
+ return MP_OBJ_NEW_SMALL_INT(len);
+ default:
+ return MP_OBJ_NULL; // op not supported
+ }
+}
+
+//| overflowed: bool
+//| """``True`` if an event could not be added to the event queue because it was full. (read-only)
+//| Set to ``False`` by `clear()`.
+//| """
+//|
+STATIC mp_obj_t keypad_eventqueue_get_overflowed(mp_obj_t self_in) {
+ keypad_eventqueue_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ return mp_obj_new_bool(common_hal_keypad_eventqueue_get_overflowed(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_eventqueue_get_overflowed_obj, keypad_eventqueue_get_overflowed);
+
+MP_PROPERTY_GETTER(keypad_eventqueue_overflowed_obj,
+ (mp_obj_t)&keypad_eventqueue_get_overflowed_obj);
+
+STATIC const mp_rom_map_elem_t keypad_eventqueue_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&keypad_eventqueue_clear_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&keypad_eventqueue_get_obj) },
+ { MP_ROM_QSTR(MP_QSTR_get_into), MP_ROM_PTR(&keypad_eventqueue_get_into_obj) },
+ { MP_ROM_QSTR(MP_QSTR_overflowed), MP_ROM_PTR(&keypad_eventqueue_overflowed_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_eventqueue_locals_dict, keypad_eventqueue_locals_dict_table);
+
+const mp_obj_type_t keypad_eventqueue_type = {
+ { &mp_type_type },
+ .flags = MP_TYPE_FLAG_EXTENDED,
+ .name = MP_QSTR_EventQueue,
+ MP_TYPE_EXTENDED_FIELDS(
+ .unary_op = keypad_eventqueue_unary_op,
+ ),
+ .locals_dict = (mp_obj_t)&keypad_eventqueue_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/EventQueue.h b/circuitpython/shared-bindings/keypad/EventQueue.h
new file mode 100644
index 0000000..fbbd9df
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/EventQueue.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
+
+#include "shared-module/keypad/Event.h"
+#include "shared-module/keypad/EventQueue.h"
+
+extern const mp_obj_type_t keypad_eventqueue_type;
+
+void common_hal_keypad_eventqueue_construct(keypad_eventqueue_obj_t *self, size_t max_events);
+
+void common_hal_keypad_eventqueue_clear(keypad_eventqueue_obj_t *self);
+size_t common_hal_keypad_eventqueue_get_length(keypad_eventqueue_obj_t *self);
+mp_obj_t common_hal_keypad_eventqueue_get(keypad_eventqueue_obj_t *self);
+bool common_hal_keypad_eventqueue_get_into(keypad_eventqueue_obj_t *self, keypad_event_obj_t *event);
+
+bool common_hal_keypad_eventqueue_get_overflowed(keypad_eventqueue_obj_t *self);
+void common_hal_keypad_eventqueue_set_overflowed(keypad_eventqueue_obj_t *self, bool overflowed);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_EVENTQUEUE_H
diff --git a/circuitpython/shared-bindings/keypad/KeyMatrix.c b/circuitpython/shared-bindings/keypad/KeyMatrix.c
new file mode 100644
index 0000000..9e65471
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/KeyMatrix.c
@@ -0,0 +1,236 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/KeyMatrix.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+//| class KeyMatrix:
+//| """Manage a 2D matrix of keys with row and column pins."""
+//|
+//| def __init__(self, row_pins: Sequence[microcontroller.Pin], column_pins: Sequence[microcontroller.Pin], columns_to_anodes: bool = True, interval: float = 0.020, max_events: int = 64) -> None:
+//| """
+//| Create a `Keys` object that will scan the key matrix attached to the given row and column pins.
+//| There should not be any external pull-ups or pull-downs on the matrix:
+//| ``KeyMatrix`` enables internal pull-ups or pull-downs on the pins as necessary.
+//|
+//| The keys are numbered sequentially from zero. A key number can be computed
+//| by ``row * len(column_pins) + column``.
+//|
+//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
+//|
+//| :param Sequence[microcontroller.Pin] row_pins: The pins attached to the rows.
+//| :param Sequence[microcontroller.Pin] column_pins: The pins attached to the colums.
+//| :param bool columns_to_anodes: Default ``True``.
+//| If the matrix uses diodes, the diode anodes are typically connected to the column pins,
+//| and the cathodes should be connected to the row pins. If your diodes are reversed,
+//| set ``columns_to_anodes`` to ``False``.
+//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
+//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
+//| :param int max_events: maximum size of `events` `EventQueue`:
+//| maximum number of key transition events that are saved.
+//| Must be >= 1.
+//| If a new event arrives when the queue is full, the oldest event is discarded.
+//| """
+//| ...
+
+STATIC mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_keymatrix_obj_t *self = m_new_obj(keypad_keymatrix_obj_t);
+ self->base.type = &keypad_keymatrix_type;
+ enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_column_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_columns_to_anodes, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t row_pins = args[ARG_row_pins].u_obj;
+ // mp_obj_len() will be >= 0.
+ const size_t num_row_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(row_pins));
+
+ mp_obj_t column_pins = args[ARG_column_pins].u_obj;
+ const size_t num_column_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(column_pins));
+
+ const mp_float_t interval =
+ mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
+ const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
+
+ const mcu_pin_obj_t *row_pins_array[num_row_pins];
+ const mcu_pin_obj_t *column_pins_array[num_column_pins];
+
+ validate_no_duplicate_pins_2(row_pins, column_pins, MP_QSTR_row_pins, MP_QSTR_column_pins);
+
+ for (size_t row = 0; row < num_row_pins; row++) {
+ const mcu_pin_obj_t *pin =
+ validate_obj_is_free_pin(mp_obj_subscr(row_pins, MP_OBJ_NEW_SMALL_INT(row), MP_OBJ_SENTINEL));
+ row_pins_array[row] = pin;
+ }
+
+ for (size_t column = 0; column < num_column_pins; column++) {
+ const mcu_pin_obj_t *pin =
+ validate_obj_is_free_pin(mp_obj_subscr(column_pins, MP_OBJ_NEW_SMALL_INT(column), MP_OBJ_SENTINEL));
+ column_pins_array[column] = pin;
+ }
+
+ common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events);
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stop scanning and release the pins."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix_deinit(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ common_hal_keypad_keymatrix_deinit(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_keymatrix_deinit_obj, keypad_keymatrix_deinit);
+
+//| def __enter__(self) -> KeyMatrix:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_keypad_keymatrix_deinit(args[0]);
+ return MP_ROM_NONE;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keymatrix___exit___obj, 4, 4, keypad_keymatrix___exit__);
+
+STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) {
+ if (common_hal_keypad_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+//| def reset(self) -> None:
+//| """Reset the internal state of the scanner to assume that all keys are now released.
+//| Any key that is already pressed at the time of this call will therefore immediately cause
+//| a new key-pressed event to occur.
+//| """
+//| ...
+//|
+
+//| key_count: int
+//| """The number of keys that are being scanned. (read-only)
+//| """
+//|
+
+//| def key_number_to_row_column(self, key_number: int) -> Tuple[int]:
+//| """Return the row and column for the given key number.
+//| The row is ``key_number // len(column_pins)``.
+//| The column is ``key_number % len(column_pins)``.
+//|
+//| :return: ``(row, column)``
+//| :rtype: Tuple[int]
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix_key_number_to_row_column(mp_obj_t self_in, mp_obj_t key_number_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ const mp_uint_t key_number = (mp_uint_t)mp_arg_validate_int_range(
+ mp_obj_get_int(key_number_in),
+ 0, (mp_int_t)common_hal_keypad_generic_get_key_count(self),
+ MP_QSTR_key_number);
+
+ mp_uint_t row;
+ mp_uint_t column;
+ common_hal_keypad_keymatrix_key_number_to_row_column(self, key_number, &row, &column);
+
+ mp_obj_t row_column[2];
+ row_column[0] = MP_OBJ_NEW_SMALL_INT(row);
+ row_column[1] = MP_OBJ_NEW_SMALL_INT(column);
+
+ return mp_obj_new_tuple(2, row_column);
+}
+MP_DEFINE_CONST_FUN_OBJ_2(keypad_keymatrix_key_number_to_row_column_obj, keypad_keymatrix_key_number_to_row_column);
+
+//| def row_column_to_key_number(self, row: int, column: int) -> int:
+//| """Return the key number for a given row and column.
+//| The key number is ``row * len(column_pins) + column``.
+//| """
+//| ...
+//|
+STATIC mp_obj_t keypad_keymatrix_row_column_to_key_number(mp_obj_t self_in, mp_obj_t row_in, mp_obj_t column_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ const mp_uint_t row = (mp_uint_t)mp_arg_validate_int_range(
+ mp_obj_get_int(row_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_row_count(self), MP_QSTR_row);
+
+ const mp_int_t column = (mp_uint_t)mp_arg_validate_int_range(
+ mp_obj_get_int(column_in), 0, (mp_int_t)common_hal_keypad_keymatrix_get_column_count(self), MP_QSTR_column);
+
+ return MP_OBJ_NEW_SMALL_INT(
+ (mp_int_t)common_hal_keypad_keymatrix_row_column_to_key_number(self, row, column));
+}
+MP_DEFINE_CONST_FUN_OBJ_3(keypad_keymatrix_row_column_to_key_number_obj, keypad_keymatrix_row_column_to_key_number);
+
+//| events: EventQueue
+//| """The `EventQueue` associated with this `Keys` object. (read-only)
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t keypad_keymatrix_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keymatrix_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keymatrix___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_number_to_row_column), MP_ROM_PTR(&keypad_keymatrix_key_number_to_row_column_obj) },
+ { MP_ROM_QSTR(MP_QSTR_row_column_to_key_number), MP_ROM_PTR(&keypad_keymatrix_row_column_to_key_number_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_keymatrix_locals_dict, keypad_keymatrix_locals_dict_table);
+
+const mp_obj_type_t keypad_keymatrix_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_KeyMatrix,
+ .make_new = keypad_keymatrix_make_new,
+ .locals_dict = (mp_obj_t)&keypad_keymatrix_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/KeyMatrix.h b/circuitpython/shared-bindings/keypad/KeyMatrix.h
new file mode 100644
index 0000000..bdf77dd
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/KeyMatrix.h
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
+
+#include "py/objlist.h"
+#include "shared-module/keypad/KeyMatrix.h"
+
+extern const mp_obj_type_t keypad_keymatrix_type;
+
+void common_hal_keypad_keymatrix_construct(keypad_keymatrix_obj_t *self, mp_uint_t num_row_pins, const mcu_pin_obj_t *row_pins[], mp_uint_t num_column_pins, const mcu_pin_obj_t *column_pins[], bool columns_to_anodes, mp_float_t interval, size_t max_events);
+
+void common_hal_keypad_keymatrix_deinit(keypad_keymatrix_obj_t *self);
+
+void common_hal_keypad_keymatrix_key_number_to_row_column(keypad_keymatrix_obj_t *self, mp_uint_t key_number, mp_uint_t *row, mp_uint_t *column);
+mp_uint_t common_hal_keypad_keymatrix_row_column_to_key_number(keypad_keymatrix_obj_t *self, mp_uint_t row, mp_uint_t column);
+
+size_t common_hal_keypad_keymatrix_get_column_count(keypad_keymatrix_obj_t *self);
+size_t common_hal_keypad_keymatrix_get_row_count(keypad_keymatrix_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYMATRIX_H
diff --git a/circuitpython/shared-bindings/keypad/Keys.c b/circuitpython/shared-bindings/keypad/Keys.c
new file mode 100644
index 0000000..6ac705e
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Keys.c
@@ -0,0 +1,168 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/Keys.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+//| class Keys:
+//| """Manage a set of independent keys."""
+//|
+//| def __init__(self, pins: Sequence[microcontroller.Pin], *, value_when_pressed: bool, pull: bool = True, interval: float = 0.020, max_events: int = 64) -> None:
+//| """
+//| Create a `Keys` object that will scan keys attached to the given sequence of pins.
+//| Each key is independent and attached to its own pin.
+//|
+//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
+//|
+//| :param Sequence[microcontroller.Pin] pins: The pins attached to the keys.
+//| The key numbers correspond to indices into this sequence.
+//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed.
+//| ``False`` if the pin reads low (is grounded) when the key is pressed.
+//| All the pins must be connected in the same way.
+//| :param bool pull: ``True`` if an internal pull-up or pull-down should be
+//| enabled on each pin. A pull-up will be used if ``value_when_pressed`` is ``False``;
+//| a pull-down will be used if it is ``True``.
+//| If an external pull is already provided for all the pins, you can set ``pull`` to ``False``.
+//| However, enabling an internal pull when an external one is already present is not a problem;
+//| it simply uses slightly more current.
+//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
+//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
+//| :param int max_events: maximum size of `events` `EventQueue`:
+//| maximum number of key transition events that are saved.
+//| Must be >= 1.
+//| If a new event arrives when the queue is full, the oldest event is discarded.
+//| """
+//| ...
+
+STATIC mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_keys_obj_t *self = m_new_obj(keypad_keys_obj_t);
+ self->base.type = &keypad_keys_type;
+ enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
+ { MP_QSTR_pull, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } },
+ { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ mp_obj_t pins = args[ARG_pins].u_obj;
+ validate_no_duplicate_pins(pins, MP_QSTR_row_pins);
+ // mp_obj_len() will be >= 0.
+ const size_t num_pins = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(pins));
+
+ const bool value_when_pressed = args[ARG_value_when_pressed].u_bool;
+ const mp_float_t interval =
+ mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
+ const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
+
+ const mcu_pin_obj_t *pins_array[num_pins];
+
+ for (mp_uint_t i = 0; i < num_pins; i++) {
+ pins_array[i] =
+ validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL));
+ }
+
+ common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stop scanning and release the pins."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keys_deinit(mp_obj_t self_in) {
+ keypad_keys_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_keypad_keys_deinit(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_keys_deinit_obj, keypad_keys_deinit);
+
+//| def __enter__(self) -> Keys:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t keypad_keys___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_keypad_keys_deinit(args[0]);
+ return MP_ROM_NONE;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_keys___exit___obj, 4, 4, keypad_keys___exit__);
+
+
+//| def reset(self) -> None:
+//| """Reset the internal state of the scanner to assume that all keys are now released.
+//| Any key that is already pressed at the time of this call will therefore immediately cause
+//| a new key-pressed event to occur.
+//| """
+//| ...
+//|
+
+//| key_count: int
+//| """The number of keys that are being scanned. (read-only)
+//| """
+//|
+
+//| events: EventQueue
+//| """The `EventQueue` associated with this `Keys` object. (read-only)
+//| """
+//|
+STATIC const mp_rom_map_elem_t keypad_keys_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_keys_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_keys___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_keys_locals_dict, keypad_keys_locals_dict_table);
+
+const mp_obj_type_t keypad_keys_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_Keys,
+ .make_new = keypad_keys_make_new,
+ .locals_dict = (mp_obj_t)&keypad_keys_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/Keys.h b/circuitpython/shared-bindings/keypad/Keys.h
new file mode 100644
index 0000000..eb833b9
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/Keys.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
+
+#include "py/objlist.h"
+#include "shared-module/keypad/Keys.h"
+
+extern const mp_obj_type_t keypad_keys_type;
+
+void common_hal_keypad_keys_construct(keypad_keys_obj_t *self, mp_uint_t num_pins, const mcu_pin_obj_t *pins[], bool value_when_pressed, bool pull, mp_float_t interval, size_t max_events);
+
+void common_hal_keypad_keys_deinit(keypad_keys_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_KEYS_H
diff --git a/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c
new file mode 100644
index 0000000..14ab874
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.c
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "shared/runtime/context_manager_helpers.h"
+#include "py/binary.h"
+#include "py/objproperty.h"
+#include "py/runtime.h"
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/ShiftRegisterKeys.h"
+#include "shared-bindings/microcontroller/Pin.h"
+#include "shared-bindings/util.h"
+
+//| class ShiftRegisterKeys:
+//| """Manage a set of keys attached to an incoming shift register."""
+//|
+//| def __init__(self, *, clock: microcontroller.Pin, data: microcontroller.Pin, latch: microcontroller.Pin, value_to_latch: bool = True, key_count: int, value_when_pressed: bool, interval: float = 0.020, max_events: int = 64) -> None:
+//| """
+//| Create a `Keys` object that will scan keys attached to a parallel-in serial-out shift register
+//| like the 74HC165 or CD4021.
+//| Note that you may chain shift registers to load in as many values as you need.
+//|
+//| Key number 0 is the first (or more properly, the zero-th) bit read. In the
+//| 74HC165, this bit is labeled ``Q7``. Key number 1 will be the value of ``Q6``, etc.
+//|
+//| An `EventQueue` is created when this object is created and is available in the `events` attribute.
+//|
+//| :param microcontroller.Pin clock: The shift register clock pin.
+//| The shift register should clock on a low-to-high transition.
+//| :param microcontroller.Pin data: the incoming shift register data pin
+//| :param microcontroller.Pin latch:
+//| Pin used to latch parallel data going into the shift register.
+//| :param bool value_to_latch: Pin state to latch data being read.
+//| ``True`` if the data is latched when ``latch`` goes high
+//| ``False`` if the data is latched when ``latch`` goes low.
+//| The default is ``True``, which is how the 74HC165 operates. The CD4021 latch is the opposite.
+//| Once the data is latched, it will be shifted out by toggling the clock pin.
+//| :param int key_count: number of data lines to clock in
+//| :param bool value_when_pressed: ``True`` if the pin reads high when the key is pressed.
+//| ``False`` if the pin reads low (is grounded) when the key is pressed.
+//| :param float interval: Scan keys no more often than ``interval`` to allow for debouncing.
+//| ``interval`` is in float seconds. The default is 0.020 (20 msecs).
+//| :param int max_events: maximum size of `events` `EventQueue`:
+//| maximum number of key transition events that are saved.
+//| Must be >= 1.
+//| If a new event arrives when the queue is full, the oldest event is discarded.
+//| """
+//| ...
+
+STATIC mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
+ keypad_shiftregisterkeys_obj_t *self = m_new_obj(keypad_shiftregisterkeys_obj_t);
+ self->base.type = &keypad_shiftregisterkeys_type;
+ enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events };
+ static const mp_arg_t allowed_args[] = {
+ { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_data, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_latch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ },
+ { MP_QSTR_value_to_latch, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} },
+ { MP_QSTR_key_count, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT },
+ { MP_QSTR_value_when_pressed, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_BOOL },
+ { MP_QSTR_interval, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
+ { MP_QSTR_max_events, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 64} },
+ };
+ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
+ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
+
+ const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj);
+ const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj);
+ const mcu_pin_obj_t *latch = validate_obj_is_free_pin(args[ARG_latch].u_obj);
+ const bool value_to_latch = args[ARG_value_to_latch].u_bool;
+
+ const size_t key_count = (size_t)mp_arg_validate_int_min(args[ARG_key_count].u_int, 1, MP_QSTR_key_count);
+ const bool value_when_pressed = args[ARG_value_when_pressed].u_bool;
+ const mp_float_t interval =
+ mp_arg_validate_obj_float_non_negative(args[ARG_interval].u_obj, 0.020f, MP_QSTR_interval);
+ const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events);
+
+ common_hal_keypad_shiftregisterkeys_construct(
+ self, clock, data, latch, value_to_latch, key_count, value_when_pressed, interval, max_events);
+
+ return MP_OBJ_FROM_PTR(self);
+}
+
+//| def deinit(self) -> None:
+//| """Stop scanning and release the pins."""
+//| ...
+//|
+STATIC mp_obj_t keypad_shiftregisterkeys_deinit(mp_obj_t self_in) {
+ keypad_shiftregisterkeys_obj_t *self = MP_OBJ_TO_PTR(self_in);
+
+ common_hal_keypad_shiftregisterkeys_deinit(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_shiftregisterkeys_deinit_obj, keypad_shiftregisterkeys_deinit);
+
+//| def __enter__(self) -> Keys:
+//| """No-op used by Context Managers."""
+//| ...
+//|
+// Provided by context manager helper.
+
+//| def __exit__(self) -> None:
+//| """Automatically deinitializes when exiting a context. See
+//| :ref:`lifetime-and-contextmanagers` for more info."""
+//| ...
+//|
+STATIC mp_obj_t keypad_shiftregisterkeys___exit__(size_t n_args, const mp_obj_t *args) {
+ (void)n_args;
+ common_hal_keypad_shiftregisterkeys_deinit(args[0]);
+ return MP_ROM_NONE;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(keypad_shiftregisterkeys___exit___obj, 4, 4, keypad_shiftregisterkeys___exit__);
+
+//| def reset(self) -> None:
+//| """Reset the internal state of the scanner to assume that all keys are now released.
+//| Any key that is already pressed at the time of this call will therefore immediately cause
+//| a new key-pressed event to occur.
+//| """
+//| ...
+//|
+
+//| key_count: int
+//| """The number of keys that are being scanned. (read-only)
+//| """
+//|
+
+//| events: EventQueue
+//| """The `EventQueue` associated with this `Keys` object. (read-only)
+//| """
+//|
+
+STATIC const mp_rom_map_elem_t keypad_shiftregisterkeys_locals_dict_table[] = {
+ { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&keypad_shiftregisterkeys_deinit_obj) },
+ { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
+ { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&keypad_shiftregisterkeys___exit___obj) },
+
+ { MP_ROM_QSTR(MP_QSTR_events), MP_ROM_PTR(&keypad_generic_events_obj) },
+ { MP_ROM_QSTR(MP_QSTR_key_count), MP_ROM_PTR(&keypad_generic_key_count_obj) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&keypad_generic_reset_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_shiftregisterkeys_locals_dict, keypad_shiftregisterkeys_locals_dict_table);
+
+const mp_obj_type_t keypad_shiftregisterkeys_type = {
+ { &mp_type_type },
+ .name = MP_QSTR_ShiftRegisterKeys,
+ .make_new = keypad_shiftregisterkeys_make_new,
+ .locals_dict = (mp_obj_t)&keypad_shiftregisterkeys_locals_dict,
+};
diff --git a/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h
new file mode 100644
index 0000000..bc91c78
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/ShiftRegisterKeys.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the Micro Python project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
+#define MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
+
+#include "py/objlist.h"
+#include "shared-module/keypad/ShiftRegisterKeys.h"
+
+extern const mp_obj_type_t keypad_shiftregisterkeys_type;
+
+void common_hal_keypad_shiftregisterkeys_construct(keypad_shiftregisterkeys_obj_t *self, const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin, const mcu_pin_obj_t *latch_pin, bool value_to_latch, size_t key_count, bool value_when_pressed, mp_float_t interval, size_t max_events);
+
+void common_hal_keypad_shiftregisterkeys_deinit(keypad_shiftregisterkeys_obj_t *self);
+
+#endif // MICROPY_INCLUDED_SHARED_BINDINGS_KEYPAD_SHIFTREGISTERKEYS_H
diff --git a/circuitpython/shared-bindings/keypad/__init__.c b/circuitpython/shared-bindings/keypad/__init__.c
new file mode 100644
index 0000000..97db750
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/__init__.c
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2011 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/obj.h"
+
+#include "shared-bindings/keypad/__init__.h"
+#include "shared-bindings/keypad/Event.h"
+#include "shared-bindings/keypad/EventQueue.h"
+#include "shared-bindings/keypad/KeyMatrix.h"
+#include "shared-bindings/keypad/Keys.h"
+#include "shared-bindings/keypad/ShiftRegisterKeys.h"
+#include "shared-bindings/util.h"
+
+STATIC void check_for_deinit(keypad_keymatrix_obj_t *self) {
+ if (common_hal_keypad_deinited(self)) {
+ raise_deinited_error();
+ }
+}
+
+STATIC mp_obj_t keypad_generic_reset(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ common_hal_keypad_generic_reset(self);
+ return MP_ROM_NONE;
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_generic_reset_obj, keypad_generic_reset);
+
+STATIC mp_obj_t keypad_generic_get_key_count(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return MP_OBJ_NEW_SMALL_INT(common_hal_keypad_generic_get_key_count(self));
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_generic_get_key_count_obj, keypad_generic_get_key_count);
+
+const mp_obj_property_t keypad_generic_key_count_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&keypad_generic_get_key_count_obj,
+ MP_ROM_NONE,
+ MP_ROM_NONE},
+};
+
+STATIC mp_obj_t keypad_generic_get_events(mp_obj_t self_in) {
+ keypad_keymatrix_obj_t *self = MP_OBJ_TO_PTR(self_in);
+ check_for_deinit(self);
+
+ return common_hal_keypad_generic_get_events(self);
+}
+MP_DEFINE_CONST_FUN_OBJ_1(keypad_generic_get_events_obj, keypad_generic_get_events);
+
+const mp_obj_property_t keypad_generic_events_obj = {
+ .base.type = &mp_type_property,
+ .proxy = {(mp_obj_t)&keypad_generic_get_events_obj,
+ MP_ROM_NONE,
+ MP_ROM_NONE},
+};
+
+
+//| """Support for scanning keys and key matrices
+//|
+//| The `keypad` module provides native support to scan sets of keys or buttons,
+//| connected independently to individual pins,
+//| connected to a shift register,
+//| or connected in a row-and-column matrix.
+//| """
+//|
+
+STATIC mp_rom_map_elem_t keypad_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_keypad) },
+ { MP_ROM_QSTR(MP_QSTR_Event), MP_OBJ_FROM_PTR(&keypad_event_type) },
+ { MP_ROM_QSTR(MP_QSTR_EventQueue), MP_OBJ_FROM_PTR(&keypad_eventqueue_type) },
+ { MP_ROM_QSTR(MP_QSTR_KeyMatrix), MP_OBJ_FROM_PTR(&keypad_keymatrix_type) },
+ { MP_ROM_QSTR(MP_QSTR_Keys), MP_OBJ_FROM_PTR(&keypad_keys_type) },
+ { MP_ROM_QSTR(MP_QSTR_ShiftRegisterKeys), MP_OBJ_FROM_PTR(&keypad_shiftregisterkeys_type) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(keypad_module_globals, keypad_module_globals_table);
+
+const mp_obj_module_t keypad_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t *)&keypad_module_globals,
+};
+
+MP_REGISTER_MODULE(MP_QSTR_keypad, keypad_module, CIRCUITPY_KEYPAD);
diff --git a/circuitpython/shared-bindings/keypad/__init__.h b/circuitpython/shared-bindings/keypad/__init__.h
new file mode 100644
index 0000000..eb3b16a
--- /dev/null
+++ b/circuitpython/shared-bindings/keypad/__init__.h
@@ -0,0 +1,44 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2021 Dan Halbert for Adafruit Industries
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef SHARED_BINDINGS_KEYPAD_H
+#define SHARED_BINDINGS_KEYPAD_H
+
+#include "py/obj.h"
+#include "py/objproperty.h"
+#include "shared-module/keypad/__init__.h"
+
+bool common_hal_keypad_deinited(void *self);
+void common_hal_keypad_generic_reset(void *self);
+size_t common_hal_keypad_generic_get_key_count(void *self);
+mp_obj_t common_hal_keypad_generic_get_events(void *self);
+
+MP_DECLARE_CONST_FUN_OBJ_1(keypad_generic_reset_obj);
+
+extern const mp_obj_property_t keypad_generic_events_obj;
+extern const mp_obj_property_t keypad_generic_key_count_obj;
+
+#endif // SHARED_BINDINGS_KEYPAD_H