Keypad behaviour (keypad v0.3.0) View Source

keypad is implemented as a __using__ macro so that you can put it in any module you want to handle the keypress events. Because it is small GenServer, it accepts the same options for supervision to configure the child spec and passes them along to GenServer:

defmodule MyModule do
  use Keypad, restart: :transient, shutdown: 10_000
end

It also has its own set of options to pass to configure the keypad connections. At a minimum, you must pass either :size or a custom matrix with :matrix:

  • :size - If supplied without :matrix it will select the default matrix for the specified size. The delaration is row x col, so :one_by_four would be 1 row, 4 columns.
    • :four_by_four or "4x4" - Standard 12-digit keypad with A, B, C, and D keys
    • :four_by_three or "4x3" - Standard 12-digit keypad
    • :one_by_four or "1x4"
  • :matrix - A custom matrix to use for mapping keypresses to. Will take precedence over :size if supplied
    • Typically, these are binary values. However, these values are pulled from List and in theory can be anything you want. i.e. atom, integer, or even annonymous function
  • :row_pins - List of integers which map to corresponding GPIO to set as INPUT pins for keypard rows
    • On raspberry pi, these will also set the internal resistor to PULL_UP and inactive HIGH. For all other hardware, you will probably need to make sure to place some 10K resistors between your pin and ground. see Setup doc for some examples
    • defaults to [17, 27, 23, 24]
  • :col_pins - List of integers which map to corresponding GPIO to as OUTPUT pins for keypad columns
    • defaults to [5, 6, 13, 26]

Link to this section Summary

Callbacks

Required callback to handle keypress events based on defined matrix values.

Link to this section Callbacks

Link to this callback

handle_keypress(key, map)

View Source

Specs

handle_keypress(key :: any(), map()) :: map()

Required callback to handle keypress events based on defined matrix values.

It's first argument will be the result of the keypress according to the defined matrix (most typically a binary string, though you can use anything you'd like). The second argument is the state of the keypad GenServer. You are required to return the state in this function.

There is an optional field in the state called :input which is initialized as an empty string "". You can use this to keep input events from keypresses and build them as needed, such as putting multiple keypresses together to determine a password. Note: You will be responsible for resetting this input as needed.

This is not required and you can optionally use other measures to keep rolling state, such as Agent.

defmodule MyKeypad do
  use Keypad

  require Logger

  @impl true
  def handle_keypress(key, %{input: ""} = state) do
    Logger.info("First Keypress: #{key}")
    Process.send_after(self(), :reset, 5000) # Reset input after 5 seconds
    %{state | input: key}
  end

  @impl true
  def handle_keypress(key, %{input: input} = state) do
    Logger.info("Keypress: #{key}")
    %{state | input: input <> key}
  end

  @impl true
  def handle_info(:reset, state) do
    {:noreply, %{state | input: ""}}
  end
end