Skip to content

Commit

Permalink
Rename/reorganization
Browse files Browse the repository at this point in the history
  • Loading branch information
doughsay committed Dec 10, 2019
1 parent 0ebe3db commit d75c6ba
Show file tree
Hide file tree
Showing 35 changed files with 293 additions and 288 deletions.
2 changes: 2 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# MIT License

Copyright 2019 Chris Dosé

Permission is hereby granted, free of charge, to any person obtaining a copy of
Expand Down
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ First, you define a keymap:
keymap = [
# Layer 0 (default)
%{
k001: AFK.Keycodes.Key.new(:a),
k002: AFK.Keycodes.Modifier.new(:left_control),
k003: AFK.Keycodes.Layer.new(:hold, 1),
k004: AFK.Keycodes.Key.new(:caps_lock)
k001: AFK.Keycode.Key.new(:a),
k002: AFK.Keycode.Modifier.new(:left_control),
k003: AFK.Keycode.Layer.new(:hold, 1),
k004: AFK.Keycode.Key.new(:caps_lock)
},
# Layer 1
%{
k001: AFK.Keycodes.Key.new(:z),
k002: AFK.Keycodes.Modifier.new(:right_super),
k003: AFK.Keycodes.None.new(),
k004: AFK.Keycodes.Transparent.new()
k001: AFK.Keycode.Key.new(:z),
k002: AFK.Keycode.Modifier.new(:right_super),
k003: AFK.Keycode.None.new(),
k004: AFK.Keycode.Transparent.new()
}
]
```
Expand Down Expand Up @@ -70,10 +70,10 @@ AFK.State.to_hid_report(state)
It's intended to eventually support N-key rollover, but for now it just supports
basic 6-key rollover.

It may eventually also support more complex interactions, such as combo keys,
macros, leader keys, and tap-dance. These features require a lot more thinking
though, as they will require a process that emits an event stream as opposed to
the current data structure approach.
It may eventually also support more complex interactions, such as sticky keys,
macros, leader keys, etc. These features require a lot more thinking though, as
they will require a process that emits an event stream as opposed to the current
data structure approach.

## Docs

Expand Down
2 changes: 1 addition & 1 deletion lib/afk.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule AFK do
@moduledoc """
A library for modeling the internal state of a computer keyboard.
See `AFK.Keycodes` and `AFK.Keymap` to learn how to create keymaps with
See `AFK.Keycode` and `AFK.Keymap` to learn how to create keymaps with
layers. Then see `AFK.State` to see how to initialize and manipulate the
state.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defprotocol AFK.State.ApplyKeycode do
defprotocol AFK.ApplyKeycode do
@moduledoc false

def apply_keycode(keycode, state, key)
Expand Down
14 changes: 14 additions & 0 deletions lib/afk/keycode.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule AFK.Keycode do
@moduledoc """
A keycode represents a key that when pressed affects the keyboard state in
some way.
The currently supported keycode types are:
* `AFK.Keycode.Key` - A basic keyboard key
* `AFK.Keycode.Layer` - A key that can activate other layers
* `AFK.Keycode.Modifier` - A basic keyboard modifier
* `AFK.Keycode.None` - A keycode that does nothing
* `AFK.Keycode.Transparent` - A key that is transparent to its layer
"""
end
47 changes: 40 additions & 7 deletions lib/afk/keycodes/key.ex → lib/afk/keycode/key.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule AFK.Keycodes.Key do
defmodule AFK.Keycode.Key do
@moduledoc """
Represents a basic keyboard keycode, like letters, numbers, etc.
Expand Down Expand Up @@ -95,18 +95,51 @@ defmodule AFK.Keycodes.Key do
## Examples
iex> new(:a)
%AFK.Keycodes.Key{key: :a}
%AFK.Keycode.Key{key: :a}
iex> new(:up)
%AFK.Keycodes.Key{key: :up}
%AFK.Keycode.Key{key: :up}
"""
for {_value, key} <- AFK.Scancodes.keyboard() do
for {_value, key} <- AFK.Scancode.keyboard() do
def new(unquote(key)), do: struct!(__MODULE__, key: unquote(key))
end

defimpl AFK.Keycodes.HIDValue do
for {value, key} <- AFK.Scancodes.keyboard() do
def hid_value(%AFK.Keycodes.Key{key: unquote(key)}), do: unquote(value)
defimpl AFK.Scancode.Protocol do
for {value, key} <- AFK.Scancode.keyboard() do
def scancode(%AFK.Keycode.Key{key: unquote(key)}), do: unquote(value)
end
end

defimpl AFK.ApplyKeycode do
def apply_keycode(keycode, state, key) do
keycode_used? =
Enum.any?(state.six_keys, fn
nil -> false
{_, kc} -> kc == keycode
end)

if keycode_used? do
state
else
{six_keys, _} =
Enum.map_reduce(state.six_keys, keycode, fn
x, nil -> {x, nil}
nil, kc -> {{key, kc}, nil}
x, kc -> {x, kc}
end)

%{state | six_keys: six_keys}
end
end

def unapply_keycode(keycode, state, key) do
six_keys =
Enum.map(state.six_keys, fn
{^key, ^keycode} -> nil
x -> x
end)

%{state | six_keys: six_keys}
end
end
end
81 changes: 81 additions & 0 deletions lib/afk/keycode/layer.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
defmodule AFK.Keycode.Layer do
@moduledoc """
Represents a key that can activate other layers on and off in various ways.
Layers can be activated in 3 ways:
* `:hold` - Temporarily activates a layer while being held
* `:toggle` - Toggles a layer on or off when pressed
* `:default` - Sets a layer as the default layer
"""

@enforce_keys [:type, :layer]
defstruct [:type, :layer]

@doc """
Creates a layer activation keycode.
The valid types are:
* `:hold` - Activates a layer while being held
* `:toggle` - Toggles a layer on or off when pressed
* `:default` - Sets a layer as the default layer
## Examples
iex> new(:hold, 1)
%AFK.Keycode.Layer{layer: 1, type: :hold}
iex> new(:hold, 2)
%AFK.Keycode.Layer{layer: 2, type: :hold}
iex> new(:toggle, 1)
%AFK.Keycode.Layer{layer: 1, type: :toggle}
iex> new(:default, 2)
%AFK.Keycode.Layer{layer: 2, type: :default}
"""
def new(type, layer) when type in ~w(hold toggle default)a and is_integer(layer) and layer >= 0 do
struct!(__MODULE__,
type: type,
layer: layer
)
end

defimpl AFK.ApplyKeycode do
alias AFK.Keycode.Layer
alias AFK.State.Keymap

def apply_keycode(%Layer{type: :hold} = keycode, state, key) do
keymap = Keymap.add_activation(state.keymap, keycode, key)

%{state | keymap: keymap}
end

def apply_keycode(%Layer{type: :toggle} = keycode, state, key) do
keymap = Keymap.toggle_activation(state.keymap, keycode, key)

%{state | keymap: keymap}
end

def apply_keycode(%Layer{type: :default} = keycode, state, key) do
keymap = Keymap.set_default(state.keymap, keycode, key)

%{state | keymap: keymap}
end

def unapply_keycode(%Layer{type: :hold} = keycode, state, key) do
keymap = Keymap.remove_activation(state.keymap, keycode, key)

%{state | keymap: keymap}
end

def unapply_keycode(%Layer{type: :toggle}, state, _key) do
state
end

def unapply_keycode(%Layer{type: :default}, state, _key) do
state
end
end
end
71 changes: 71 additions & 0 deletions lib/afk/keycode/modifier.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
defmodule AFK.Keycode.Modifier do
@moduledoc """
Represents a basic modifier keycode, like control, shift, etc.
All standard modifiers on a keyboard can be represented by `Modifier`
keycodes. The following is a list of all supported modifiers:
* `:left_control`
* `:left_shift`
* `:left_alt`
* `:left_super`
* `:right_control`
* `:right_shift`
* `:right_alt`
* `:right_super`
"""

@enforce_keys [:modifier]
defstruct [:modifier]

@doc """
Creates a basic modifier keycode.
## Examples
iex> new(:left_control)
%AFK.Keycode.Modifier{modifier: :left_control}
iex> new(:right_super)
%AFK.Keycode.Modifier{modifier: :right_super}
"""
for {_value, modifier} <- AFK.Scancode.modifiers() do
def new(unquote(modifier)), do: struct!(__MODULE__, modifier: unquote(modifier))
end

defimpl AFK.Scancode.Protocol do
for {value, modifier} <- AFK.Scancode.modifiers() do
def scancode(%AFK.Keycode.Modifier{modifier: unquote(modifier)}), do: unquote(value)
end
end

defimpl AFK.ApplyKeycode, for: AFK.Keycode.Modifier do
def apply_keycode(keycode, state, key) do
modifier_used? =
Enum.any?(state.modifiers, fn
{_key, ^keycode} -> true
_ -> false
end)

if modifier_used? do
state
else
modifiers = Map.put(state.modifiers, key, keycode)

%{state | modifiers: modifiers}
end
end

def unapply_keycode(keycode, state, key) do
modifiers =
state.modifiers
|> Enum.filter(fn
{^key, ^keycode} -> false
_ -> true
end)
|> Map.new()

%{state | modifiers: modifiers}
end
end
end
22 changes: 22 additions & 0 deletions lib/afk/keycode/none.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule AFK.Keycode.None do
@moduledoc """
Represents a key that does nothing when pressed.
"""

defstruct []

@doc """
Creates a `None` keycode.
"""
def new, do: %__MODULE__{}

defimpl AFK.ApplyKeycode do
def apply_keycode(_keycode, state, _key) do
state
end

def unapply_keycode(_keycode, state, _key) do
state
end
end
end
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule AFK.Keycodes.Transparent do
defmodule AFK.Keycode.Transparent do
@moduledoc """
Represents a key that is transparent to its layer.
Expand Down
14 changes: 0 additions & 14 deletions lib/afk/keycodes.ex

This file was deleted.

5 changes: 0 additions & 5 deletions lib/afk/keycodes/hid_value.ex

This file was deleted.

44 changes: 0 additions & 44 deletions lib/afk/keycodes/layer.ex

This file was deleted.

Loading

0 comments on commit d75c6ba

Please sign in to comment.