Skip to content

Handling Keyboard Inputs with Active Patterns

MIkE edited this page Sep 19, 2018 · 6 revisions

An active pattern lets you define match expressions with different number of Keys to analyse keyboard input.

Define active pattern:

let (|ContainsKeys|_|) (keys : List<Keys>) (pressedKeys : Set<Keys>) : unit option =
    match containsKeys pressedKeys keys with
    | true ->  Some ()
    | false -> None

Match expression:

match pressedKeys with
| ContainsKeys [ Keys.P; Keys.LeftCtrl ]
| ContainsKeys [ Keys.P; Keys.RightCtrl ] -> ()
| ContainsKey Keys.OemPeriod -> ()
| ContainsKeys [ Keys.LeftCtrl; Keys.LeftAlt; Keys.Delete ] -> ()

Future Improvements

Boolean Queries

With boolean expressions, the active pattern could analyse even more complex inputs, like:

| Fulfills (Keys.X && Keys.c && (Keys.LeftShift || Keys.RightShift)) ->

Infix functions seem not to work with pattern matching, but member functions should allow following code:

| Fulfills (Keys.X .And Keys.c .And (Keys.LeftShift .Or Keys.RightShift)) ->

The query tree structure could look like this:

type Node =
  | Key of Keys
  | And of Node * Node
  | Or  of Node * Node

let rec fulfills (keys : Set<Keys>) (query : Node) : bool =
    match query with
    | Key k -> keys |> Set.contains k
    | And (k1, k2) -> (fulfills keys k1) && (fulfills keys k2)
    | Or  (k1, k2) -> (fulfills keys k1) || (fulfills keys k2)

let (|Fulfills|_|) (query : Node) (keys : Set<Keys>) : unit option =
    match fulfills keys query with
    | true  -> Some ()
    | false -> None

List to keep KeyPress order

By using List instead of Set for the pressed keys you can make queries on the order of pressed keys, like:

| [ Keys.V; Keys.X ] -> ()
| [ Keys.X; Keys.V ] -> ()
Clone this wiki locally