This document will guide you through the process of setting up 2Keys.
Please note raspberry pi and detector are used interchangeably.
2Keys is divided into 2 parts:
- The server, where hotkeys will be run
- The detector, which will have the keyboards plugged into it. It'll detect keypresses and forward them to the server, where the hotkeys will be run via AutoHotkey
As such, you'll need:
- A Raspberry Pi Model 2 B or higher (A Model 3 B+ is probably better as it has built-in wifi, so a USB port doesn't have to be taken up by a dongle. However, I haven't tested 2Keys on one of them) running Raspian. This will be the detector.
- A 64-bit Windows PC to act as the server. Please note 2Keys has only been tested on Windows 10
- The keyboards you want to use with 2Keys, plus USB hubs if required
When you connect to a network, the router automatically assigns an IP address (a way of a router knowing where to send data) to your computer. 2Keys uses this to identify which device the server (the part where hotkeys are executed) is and to send requests to it. Unfortunately, these addresses usually change, meaning the config on the detector would have to be updated everytime your IP address changed. As such, we're going to set a special type of IP address, called a static IP address.
On Windows 10: Settings > Network and Internet > Change Connection Properties
On Windows 8.1 or lower: Control Panel > Network and Internet > Network and Sharing Centre > Change Adapter Settings
Find the adapter corresponding to your internet connection. For me this is the Network Bridge
, for you it may be one labelled Ethernet. Ignore anywhere the 3rd line is something like Hyper-V
or Virtual Box
. Right-click the adapter and select Properties
. You should see something like this:
Highlight Internet Protocol Version 4 (TCP/IPv4)
and select properties. Then select Use the following IP address
.
Now open a command prompt admin windows (search for cmd
then right click and select Run as Administrator
) and run ipconfig
. Find the network adapter you selected in 0.1.1.2 and copy the IPv4 address and subnet mask into their corresponding fields in the properties window you opened at the end of 0.1.1.2.
Then click OK
then OK
again then close the properties window, control panel and command prompt window.
In order to use 2Keys, you'll need NodeJS. Make sure to download the LTS release (at the time of writing 10.x.x
).
Download the installer from the site and run it. During install don't tick the box to automatically install the tools for native modules (see below); we'll use a Microsoft provided tool for that.
Once installed, go to the directory you want to install 2Keys in and then go File > Open Windows Powershell/Command Prompt as Administrator. If you're running Windows 7 or below, search for cmd
in the start menu, right click cmd.exe
and then select Run as Administrator
Once inside, run npm install --global windows-build-tools
. This will install a Microsoft provided tool to install dependencies to build native addons. Native addons are bits of code not written in JavaScript (what NodeJS runs), such as code that interfaces with Windows functions (i.e. opening a DLL). 2Keys uses native modules for its executor of AutoHotkey code, by using a special version of AutoHotkey, AutoHotkey_H, that provides a DLL version of AutoHotkey that 2Keys can interface with.
For this tutorial, you'll need ssh
(I'll explain what this is in 0.2.1). This can be found with Git Bash for Windows. Go to https://git-scm.com/downloads and download the latest release. During install ensure that you select the option to add the tools to PATH
.
Please note it's assumed you've already installed Raspian and set it up (i.e. running sudo apt update
and sudo apt upgrade
) (By the way apt
is just a better version of apt-get
).
There are tutorials on this out on the web.
If you already know how to use pi-config, just ensure SSH is enabled and that auto-login to the desktop is enabled. If you don't know how to do any of those, follow below, else, skip to 0.2.2
These steps should be carried out on the raspberry pi's GUI (i.e. with it plugged into a screen), instead of via SSH (we'll get to what that is soon).
Wait, what's SSH? SSH (Secure Shell) is a secure way for us to remotely open a command shell on a different machine, in this case the raspberry pi, and access it from our PC. It's useful as it means we can still use our main computer whilst running a task on the raspberry pi (or any other machine with SSH)
- Open pi config by running
sudo raspi-config
. Use the arrow keys to change the highlighted option and enter to select the highlighted option. - Select
Interfacing Options
- Select
SSH
- Select
Yes
- Hit enter once done
- It's also highly advised now to change the default password. Select
Change User Password
and follow the onscreen instructions to enter a new password (Enter new UNIX password:
). Note that the lack of anything showing what you're typing (or if you're typing at all) is purposeful. - Now set statup options. Select
Boot Options
thenDesktop/CLI
thenDesktop Autologin
- Now just select finish.
DO NOT REBOOT THE RASPBERRY PI JUST YET. We are first going to setup a static IP address for the raspberry pi
Run ip route | grep default
. Copy down the first IP address shown, this is the default gateway.
Run ip route | grep wlan0
if using wireless networking or ip route | grep eth0
if using ethernet. Copy down the IP address shown at the start of the line shown, including the /xx
part. This is what we will set as your IP address.
Run sudo nano /etc/dhcpcd.conf
to open an editor
At the bottom of the file, add this (pay attention to the comments, text starting with #
):
interface wlan0 # Replace wlan0 with eth0 if using ethernet
static routers=192.168.0.1 # Replace with what you got for the default gateway
static ip_address=192.168.0.2/24 # Replace with the other IP you got in 0.2.2.1
static domain_name_servers=1.1.1.1 1.0.0.1 192.168.0.1 # Replace the last IP address with the default gateway. The 2 address before is Cloudflare's DNS.
Now reboot your raspberry pi with sudo reboot
Now we can SSH into the raspberry pi. Open a Git Bash window and type ssh pi@0.0.0.0
, replacing 0.0.0.0
with the IP you set in 0.2.2.2, minus the /xx
bit. Enter your password when prompted.
From now on i'll assume you'll run commands on the raspberry pi through SSH.
Run these commands on the detector:
$ python3 --version
$ python3 -m pip --version
$ pip3 --version
NOTE: the $
at the start is not part of the command, and represents what comes before the command input (i.e. for CMD this could be something like C:\>
)
If all commands work skip this section.
If only the last command returns with a command not found, when you see pip3
use python3 -m pip
instead and skip this section
If command 2 fails but command 3 does not, you can safely skip this section.
Else, follow along with this section.
Run:
$ sudo apt update
$ sudo apt install python3 python3-pip
Use the commands in 0.2.3.1 to verify you have python3
and pip3
Go to the folder that you want to setup your 2Keys project in, and holding SHIFT right-click in an empty space. Select "Open PowerShell window here" or "Open command window here".
Then run the following command:
$ npm install --global twokeys-server
This will, using node's built-in package manager npm
, download 2Keys from the internet and install it for use via CMD or PowerShell (specified by the --global
flag).
You can verify 2Keys was installed by running 2Keys --version
which should print the version of 2Keys installed, i.e.:
$ 2Keys --version
0.3.0
Now it's time to create a 2Keys project! Run the following command:
$ 2Keys init
Optionally you can run:
$ 2Keys init -d path/to/a/folder
to setup the project in a folder of your choice.
This command also sets up 2Keys to start at startup for this project. You can choose not to do this by running:
$ 2Keys init --no-startup
Note that this will still create files that allow 2Keys to be run in the background.
Answer the questions as they come up. The stuff in brackets after the questions is the default value, which can be used by entering nothing as input.
When asked which IP address to select, select the IP/network that corresponds to the static IP you set in 0.1.1.
Once you're done, you can run the 2Keys server by running:
$ 2Keys serve
2Keys sever: The server that handles execution of hotkeys, by taking requests for which hotkey on which keyboard from the detector. Later, we'll see how this works in 3.1.
A daemon is a background process, in the case the 2Keys server when running in daemon mode. I'll be referring to running 2Keys in the background as the 2Keys daemon.
As was just mentioned, 2Keys automatically sets itself up for startup, specifically in daemon mode (in the background). This is done without a command window or anything. Go to File Explorer and type shell:startup
into the address bar. The file 2Keys-Foo.vbs
should be there (assuming you're project is called Foo); this is the file the start the 2Keys daemon.
You can find logs in the .2Keys
folder in your project root. You'll also see a file called daemon.vbs
; this is the daemon starter file that was linked to in shell:startup
.
Go into shell:startup
(by typing it into Windows Explorer's address bar) and delete the .vbs
file. This won't remove the daemon itself, but stops it from running on startup.
Note: Where KeyboardOfMacros
is will be the name of the 2Keys project.
It's highly recommended to not delete the .2Keys
folder in the project root, as otherwise, you can never start 2Keys in daemon mode.
TODO. Not necessary for the first release, may be added as a feature later.
The simple answer is to create a shortcut to .2Keys/daemon.vbs
in shell:startup
.
Startup is made up of 3 parts:
daemon.vbs
(the actual daemon)daemon.js
(a wrapper)- The 2Keys server, ran by
daemon.js
with2Keys serve
daemon.vbs
starts daemon.js
using node in cmd, but doesn't show the window (runs in the background).
daemon.js
is a wrapper around the 2Keys server that is run by daemon.vbs
that handles logging and management of the daemon
The 2Keys server is the actual server that handles hotkey execution.
The 2Keys daemon stores logs in the .2Keys
project root.
You may notice more verbose output in the logs. To achieve this directly running 2Keys serve
, set the environment variable in your shell DEBUG
to *
(this differs for each shell, so i'm not going to try to explain it here.)
You can manually control the daemon using 2Keys
. In the project root, you can use these commands:
To start the daemon:
$ 2Keys start
To stop it:
$ 2Keys stop
To restart it:
$ 2Keys restart
The 2Keys daemon sometimes doesn't stop correctly (see #12).
If you end up with a log file like this when attempting to restart the 2Keys daemon:
events.js:167
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE: address already in use :::8181
at Server.setupListenHandle [as _listen2] (net.js:1290:14)
at listenInCluster (net.js:1338:12)
at Server.listen (net.js:1425:7)
...a bunch of other stuff
...it means the server is still running (that was supposed to be terminated on restart). Open Task Manager and find these two tasks:
These processes correspond to the daemon wrapper and server. Terminate them both.
Simple run, via SSH:
$ sudo pip3 install 2Keys
This will install 2Keys using python's package manager, pip
for use with python 3. It will also add 2Keys to the command line.
You can verify 2Keys was installed by running 2Keys --version
which should print the version of 2Keys installed, i.e.:
$ 2Keys --version
0.3.0
First, make sure the 2Keys server is running. Then, create a new directory to store your project in, in a location of your choice (mkdir path/to/dir
) and enter it (cd path/to/dir
), replacing path/to/dir
with a path to the directory (folder) to set 2Keys up in.
Note: The command mkdir
makes a new directory (folder) and cd
sets the current dir (directory) to the path specified
Then, run:
$ 2Keys init
Answer the questions as they come up, supplying the same values for port and IP Address as you did in 1.2.
You can see your 2Keys project is setup by running:
$ ls
Output:
config.yml
You can watch a keyboard and start watching for keypresses and sending them to the server with:
$ 2Keys watch keyboard
Where keyboard
is the keyboard name in the config.
If you make a config change on the server, sync it to the pi using:
$ 2Keys sync
DON'T update the config directly on the Pi, as it will be overwritten at the next sync.
On the detector we can't automatically add 2Keys to startup, as such you'll need to run the following command:
$ sudo bash ./.2Keys/register.sh register
This adds a systemd script for each keyboard (found in .2Keys
on the detector) that start 2Keys when the detector starts.
register.sh
has some useful commands. Run sudo bash ./.2Keys/register.sh help
for information.
2Keys will effectively lock the keyboard it's watching, which means only 2Keys can use it. This is so you don't accidentally type things into the detector (i.e. accidentally running commands in a terminal) and there is no escape key from this (see #6).
Ok, so your 2Keys project is now setup, time to write some hotkeys
2Keys works like so:
- Detector watches and keeps track of keys pressed, and when a combo matches a hotkey it sends a request to the server telling it which keyboard the press was on and which hotkey to fire.
- Server receives this request and directly links to AutoHotkey and runs the following:
#Include path/to/root.ahk ; I.e keyboard_1/index.ahk
MyFunction() ; The function you want to execute that runs the macro/hotkey
As such, your macros must exist as functions.
Go ahead and open the index.ahk
in one of your keyboard dirs that you setup in 1.2. For simplicity, i'm going to assume the keyboard dir and name is keyboard_1
. Read what's written in index.ahk
As is a tradition in programming, we're going to write a simple Hello World program. Create a new file called hello.ahk
in keyboard_1
and add the following contents:
HelloWorld() {
MsgBox "Hello World!"
}
Note: I recommend writing your hotkeys like this, in separate files with functions for each hotkey. If multiple hotkeys can be grouped together (i.e. hotkeys that run for a specific application) put them in a subfolder together.
Now, open index.ahk
and find these lines:
; Include all your AutoHotkey scripts here
; i.e. #Include "run-apps.ahk"
Underneath import hello.ahk
:
; Include all your AutoHotkey scripts here
; i.e. #Include "run-apps.ahk"
#Include hello.ahk
Note: Since 2Keys uses AutoHotkey V2, relative imports are allowed.
This will add hello.ahk
to the root, which is loaded by 2Keys, thus allowing the hotkey function to be assigned.
Hotkeys are assigned in the hotkeys
section of config in the format:
key_code: FunctionName
# For example
A: HelloWorld # Runs our hello world function when the A key is pressed
Additionally, you can specify whether the hotkey should fire on up or down of a key, like so:
C:
type: up # Default: down
func: HelloWorld
Which would run our HelloWorld function when the C key goes up (is unpressed)
For the list of key codes & additional information (such as how to use ctrl
etc. or keys such as the ones on the numpad) see MAPPING.md
:
https://github.com/Gum-Joe/2Keys/blob/master/docs/MAPPINGS.md
Now, open config.yml
and find the hotkeys line:
keyboards:
keyboard_1:
# ...rest of config...
hotkeys: {}
We're going to remap HelloWorld
to the H
key:
keyboards:
keyboard_1:
# ...rest of config...
hotkeys:
H: HelloWorld
You can test if the hotkey works by running:
$ 2Keys fire keyboard_1 H
Note: 2Keys fire
is very useful command for testing hotkeys with the format 2Keys fire <keyboard> <key_code>
. Note that in shells such as PowerShell keycodes may not be communicated correctly and escape characters may need to be used.
You've just gone and written and assigned your first hotkey. However, as the detector is a separate computer it doesn't know about the assignment as the detector runs on a separate computer. Go ahead and ssh into your raspberry pi and go to the directory that you setup 2Keys in. Run these commands:
$ 2Keys sync
$ sudo bash ./.2Keys/register.sh restart
The first downloads the updated config from the server and the second restarts the 2Keys daemon on the detector.
Now, just hit H
on keyboard_1
and you should see the following:
Note: when AutoHotkey (from 2Keys) creates a window of any kind it will now show up as this icon in the taskbar (the one highlighted):
Just run the script using AHK V1 (installed and set to the default program for .ahk
files) directly:
MyFunction() {
Run "path/to/the/authotkey/script.ahk"
}
I'll be adding support for AHK v1 later, via a method similar to this (AutoHotkey_H V1 doesn't play nice with 2Keys)
Since the detector is on a separate computer, functions such as GetKeyState
won't work. As such, I plan to implement helpers to replace these function. See #2