Dodona
A framework for constructing keyboards and evaluating their performance with user interaction models.
Install / Use
/learn @sangaline/DodonaREADME
Dodona
Dodona is a framework for constructing keyboards and evaluating their performance with user interaction models. It makes it easy to define a model for inputting text on a keyboard and then do things like optimize the layout of the keyboard. It can be used to perform analyses like the one that led to the Dvorak keyboard but it's also very applicable to modern mobile devices.
If you've ever used T9 word, Swype, or even a phone keyboard with autocorrect then you're probably familiar with the frustrations that can arise when the device misinterprets what you're trying to say. Dodona helps you experiment with these existing input methods by rearranging letters or swapping keys in order to see how that affects things like typing speed and the rate of interpreation errors. It also lets you explore totally new mechanisms that couple any keyboard arrangement you would like with a user interaction model including patterns of touches and swipes.
As you continue on through the README we'll explore some of the basic elements and structure of the library. We hope that you find it as much fun to play with as we do!
Table of Contents
Installation
Dependencies
In order to install and use the Dodana library to fulfill your wildest keyboard analysis fantasies, you'll first need the following dependencies installed.
- CMake version 2.8 or later
- Boost C++ Libraries
- Python 3.2 or later
- FANN: Fast Artificial Neural Network Library version 2.2 (Note: this isn't necessary but is used by certain packages. It is turned off by default, to use it you will need to use a certain flag with cmake, as explained below)
- iPython (Note: this is not necessary to use the library, but it's highly recommended as a way to interact and explore the library)
*Note: it is recommended that a MacPorts or Homebrew be used to manage the dependencies on OSX.
Linux Installation
Clone the repository and compile by running
git clone https://github.com/sangaline/dodona.git
cd /PATHTO/dodona/core
cmake .
make
If you have FANN installed and plan on using it then you can compile the library
with it by replacing the cmake . command above with
cmake -Dfann=ON .
Now the library is compiled and the file core.so is located in the parent
directory, /PATHTO/dodona/
Lastly, to use with Python the path to the /dodona directory must be included
in your PYTHONPATH. You can double check this by running
echo $PYTHONPATH
If you do not see the correct path there then add it with the following command (in bash)
export PYTHONPATH=/PATHTO/:$PYTHONPATH
Where, as before, /PATHTO/ is the path leading to the /dodona/ directory.
Static Compiling
On Linux you also have the option to statically compile the library. This might be necessary if, for example, you need to create a statically linked binary that you want to run on a distributed cluster.
To do this simply run the following instead of the cmake . command listed
above
cmake -Dstatic=ON .
This will create a core.a object that will need to linked at compile time for
your desired binary.
OSX Installation
Clone the repository from github.
git clone https://github.com/sangaline/dodona.git
Open CMakeLists.txt and edit lines 51 and 52 to point to where the appropriate
python files are located on your computer. There location depends on what
package manager, if any, you used to install them. It should look like this
IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
SET(PYTHON_LIBRARY /PATH/TO/PYTHON/LIBRARIES/libpython3.4.dylib)
SET(PYTHON_INCLUDE_DIR /PATH/TO/PTYHON/INCLUDES/python3.4m)
ENDIF()
But make sure that libpython3.4.dylib and python3.4m actually correspond to
the version of python you have. It must be version 3.2 or later.
Once this is properly configured, run the following commands.
cd /PATHTO/dodona/core
cmake .
make
If you have FANN installed and plan on using it then you can compile the library
with it by replacing the cmake . command above with
cmake -Dfann=ON .
Now the library is compiled and the file core.so is located in the parent
directory, /PATHTO/dodona/. However, OSX uses .dylib files instead of .so
so you need to link them by running the following command
ln -s /PATHTO/dodona/core.so /PATHTO/dodona/core.dylib
Lastly, to use with Python the path to the /dodona directory must be included
in your PYTHONPATH. You can double check this by running
echo $PYTHONPATH
If you do not see the correct path there then add it with the following command (in bash)
export PYTHONPATH=/PATHTO/:$PYTHONPATH
Where, as before, /PATHTO/ is the path leading to the /dodona/ directory.
*NOTE: This has not been tested on OSX 10.10 (Yosemite) yet. It should work fine assuming there weren't any major changes to the XCode developer tools
Static Compiling
Static compiling is not possible on OSX
Importing the Library
After compiling dodona it is possible to interact with it using either python or c++. If your're relatively new to the library then we recommend starting out using python and in particular, ipython. The interactivity makes it easier to explore the structure of the framework as we will be doing in this README. The following commands will import everything you need to follow along.
#a couple of ipython specific commands to setup matplotlib and numpy
%pylab
%matplotlib inline
#importing the dodona framework
from dodona import core, keyboards, wordlists
Using matplotlib backend: Qt5Agg
Populating the interactive namespace from numpy and matplotlib
Keyboards
The dodona framework centers around interactions with keyboards. Keyboards are simply a map of ascii characters to polygons in a 2D plane. Polygons themselves are in turn a collection of 2D vertices. We'll show a simple example of constructing a keyboard and then go into more practical examples.
Polygons
Polygons can be constructed by adding the necessary vertices.
square = core.Polygon()
for x, y in [(0,0), (0,1), (1,1), (1,0)]:
square.AddVertex(x, y)
triangle = core.Polygon()
for x, y in [(2,0), (3,0), (2.5,1)]:
triangle.AddVertex(x, y)
They can also be copied and translated, which is very useful when constructing a keyboard where all of the keys share the same shape.
from copy import deepcopy
translated_square = deepcopy(square)
translated_square.Translate(0, 2)
print('The y-coordinates have been shifted by 2:\n', translated_square.VertexList())
The y-coordinates have been shifted by 2:
[(0.0, 2.0), (0.0, 3.0), (1.0, 3.0), (1.0, 2.0), (0.0, 2.0)]
You can plot a collection of polygons to getan idea of how they would look as a keyboard
keyboards.DrawPolygons([square, triangle, translated_square], figsize=(3,3))

and you can quickly check whether a point falls within a polygon
square.IsInside(0.5, 0.5)
True
as well as determine the extremes of each polygon
(triangle.LeftExtreme(), triangle.RightExtreme(),
triangle.BottomExtreme(), triangle.TopExtreme())
(2.0, 3.0, 0.0, 1.0)
which will both be used later in our input models when determining how a user interacts with a key.
Building a Keyboard
To construct a keyboard from a set of polygons we simply add each polygon and assign it a corresponding ascii character.
simple_keyboard = core.Keyboard()
simple_keyboard.AddKey("a", translated_square)
simple_keyboard.AddKey("b", square)
simple_keyboard.AddKey("c", triangle)
We can draw the result as a keyboard, rather than just a collection of polygons, to see each key labeled according to it's corresponding character.
keyboards.DrawKeyboard(simple_keyboard, figsize=(3,3), axis='on')

Included Keyboards
There are a handful of keyboards that you're more likely to be interested in using than our simple abc keyboard that we just made. For convenience we've included routines for constructing these common keyboards. All of these keyboards can be passed a string like 'qwertyuiopasdfghiklzxcvbnm.' to be built with a nonstandard letter arrangement, but we'll just make the defaults here.
Standard QWERTY
The commonest of common. Note that it's made with a '.' key but we choose to remove this key before plotting.
qwerty_keyboard = keyboards.MakeStandardKeyboard()
qwerty_keyboard.RemoveKey('.')
keyboards.DrawKeyboard(qwerty_keyboard, figsize=(8,4))

Dvorak Keyboard
Probably the most common alternative keyboard layout.
dvorak_keyboard = keyboards.MakeDvorakKeyboard()
keyboards.DrawKeyboard(dvorak_keyboard, figsize=(8,4), facecolor='lightpink')

T9 Keyboard
The spiritual predecessor to swipe input methods was undoubtedly T9 word. With a T9 keyboard there is inherent ambiguity due to the reduced number of keys in addition to variations in how a user inputs words.
Related Skills
node-connect
339.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.9kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
339.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.9kCommit, push, and open a PR
