When you're listening for global keyboard events, you very likely want to know which key was pressed. Unfortunately different browsers implement the KeyboardEvent
values in different ways, so there is no one-size-fits-all solution.
As of this writing, it seems that the KeyboardEvent
API recommends using key
. It can tell you which symbol was pressed, taking keyboard layout into account. So it will tell you if it was a x
, か
, ø
, β
, etc.
According to the docs, everything else is deprecated. So charCode
, keyCode
, and which
are only useful if you need to support browsers besides these.
The simplest approach is to just decode the string value:
import Json.Decode as Decode
keyDecoder : Decode.Decoder String
keyDecoder =
Decode.field "key" Decode.string
Depending on your scenario, you may want something more elaborate though!
If you are handling user input, maybe you want to distinguish actual characters from all the different key values that may be produced for non-character keys. This way pressing h
then i
then Backspace
does not turn into "hiBackspace"
. You could do this:
import Json.Decode as Decode
type Key
= Character Char
| Control String
keyDecoder : Decode.Decoder Key
keyDecoder =
Decode.map toKey (Decode.field "key" Decode.string)
toKey : String -> Key
toKey string =
case String.uncons string of
Just (char, "") ->
Character char
_ ->
Control string
Note: The
String.uncons
function chomps surrogate pairs properly, so it works with characters outside of the BMP. If that does not mean anything to you, you are lucky! In summary, a tricky character encoding problem of JavaScript is taken care of with this code and you do not need to worry about it. Congratulations!
Or maybe you want to handle left and right arrows specially for a game or a presentation viewer. You could do something like this:
import Json.Decode as Decode
type Direction
= Left
| Right
| Other
keyDecoder : Decode.Decoder Direction
keyDecoder =
Decode.map toDirection (Decode.field "key" Decode.string)
toDirection : String -> Direction
toDirection string =
case string of
"ArrowLeft" ->
Left
"ArrowRight" ->
Right
_ ->
Other
By converting to a specialized Direction
type, the compiler can guarantee that you never forget to handle one of the valid inputs. If it was a String
, new code could have typos or missing branches that would be hard to find.
Hope that helps you write a decoder that works for your scenario!