diff --git a/main/ttyescape/APKBUILD b/main/ttyescape/APKBUILD
new file mode 100644
index 0000000000000000000000000000000000000000..e59c891e143621a4d88e41bce8098ee75d137eba
--- /dev/null
+++ b/main/ttyescape/APKBUILD
@@ -0,0 +1,28 @@
+# Maintainer: Caleb Connolly <caleb@connolly.tech>
+pkgname=ttyescape
+pkgver=0.1
+pkgrel=0
+pkgdesc="Daemon to allow users to escape to a tty"
+url="https://postmarketos.org"
+arch="all"
+license="GPL-3.0-or-later"
+depends="triggerhappy fbkeyboard terminus-font kbd"
+install="$pkgname.post-install"
+source="
+	togglevt.sh
+	ttyescape-triggerhappy.conf.example
+"
+options="!check"
+
+package() {
+	install -Dm755 "$srcdir"/togglevt.sh \
+		"$pkgdir"/usr/bin/togglevt.sh
+	
+	install -Dm755 "$srcdir"/ttyescape-triggerhappy.conf.example \
+		"$pkgdir"/etc/triggerhappy/triggers.d/ttyescape.conf.example
+}
+
+sha512sums="
+6a497c0ad6f51edfae2940edd8768cd756f5bc629011f0248f6638415dada5473ae8cc016ce2d8bab438b59f36283c41226e9c5236ed456c12a1783f01bb78d6  togglevt.sh
+f8bf3273cf87392ab2092a005417bc58cb3ae6ad25b9118b76c68481d9d8fc7d964a9d16fc7645f6f9ff0676dccd381be3b846464b2e60a6452b8c883bffb6f1  ttyescape-triggerhappy.conf.example
+"
diff --git a/main/ttyescape/togglevt.sh b/main/ttyescape/togglevt.sh
new file mode 100644
index 0000000000000000000000000000000000000000..6ea27817937e9ff51a9a58567b316410b24673fd
--- /dev/null
+++ b/main/ttyescape/togglevt.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# Toggle between tty1 and tty2, launching fbkeyboard when on tty2
+# THIS SCRIPT MUST BE RUN AS ROOT
+# usage:
+# togglevt.sh <state>
+# where <state> is an optional arg to require that a counter be incremented before the action
+# is performed. The default configuration will perform the switch when the power button has
+# been pressed 3 times whilst the volume down button is being held.
+# if no arguments are specified the switch will occur immediately.
+
+# default font, override this by setting it in /etc/conf.d/ttyescape.conf
+FONT=/usr/share/consolefonts/ter-128n.psf.gz
+# amount of times power must be pressed to trigger
+PRESSCOUNT=3
+TMPFILE="/tmp/ttyescape.tmp"
+
+# shellcheck disable=SC1091
+test -f /etc/conf.d/ttyescape.conf && . /etc/conf.d/ttyescape.conf
+
+if [ ! -e /dev/uinput ]; then
+	if ! modprobe -q uinput; then
+		echo "uinput module not available, please enable it in your kernel"
+	fi
+fi
+
+switchtty() {
+	currentvt=$(cat /sys/devices/virtual/tty/tty0/active)
+
+	if [ "$currentvt" = "tty2" ]; then # switch to tty1 with normal UI
+		chvt 1
+		killall fbkeyboard
+	else # Switch to tty2 with fbkeyboard
+		setfont $FONT -C /dev/tty2
+		chvt 2
+		# sometimes fbkeyboard can be running already, we shouldn't start it in that case
+		[ "$(pgrep fbkeyboard)" ] || nohup fbkeyboard -r "$(cat /sys/class/graphics/fbcon/rotate)" &
+	fi
+}
+
+if [ "$1" = "" ]; then
+	switchtty
+	exit 0
+fi
+
+if [ "$1" != "start" ] && [ ! -f "$TMPFILE" ]; then
+	echo "EXITING"
+	exit 0
+elif [ "$1" = "start" ]; then
+	echo "0" > "$TMPFILE"
+	exit 0
+elif [ "$1" = "reset" ]; then
+	rm "$TMPFILE"
+	exit 0
+elif [ "$1" = "inc" ]; then
+	val="$(cat "$TMPFILE")"
+	val=$((val+1))
+	if [ $val -eq $PRESSCOUNT ]; then
+		rm "$TMPFILE"
+		switchtty
+	else
+		echo "$val" > "$TMPFILE"
+		exit 0
+	fi
+fi
diff --git a/main/ttyescape/ttyescape-triggerhappy.conf.example b/main/ttyescape/ttyescape-triggerhappy.conf.example
new file mode 100644
index 0000000000000000000000000000000000000000..ae37533f77f7194b207cd918f2af85f206a0e1eb
--- /dev/null
+++ b/main/ttyescape/ttyescape-triggerhappy.conf.example
@@ -0,0 +1,5 @@
+KEY_POWER+KEY_VOLUMEDOWN  0   /usr/bin/togglevt.sh inc
+KEY_VOLUMEDOWN            1   /usr/bin/togglevt.sh start
+KEY_VOLUMEDOWN            0   /usr/bin/togglevt.sh reset
+# noop to prevent garbage being typed in console
+KEY_VOLUMEDOWN            2   /bin/true
diff --git a/main/ttyescape/ttyescape.post-deinstall b/main/ttyescape/ttyescape.post-deinstall
new file mode 100644
index 0000000000000000000000000000000000000000..5dd35a9414638fc497350e3832b03ee7c79ec441
--- /dev/null
+++ b/main/ttyescape/ttyescape.post-deinstall
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+CONF_NAME="/etc/triggerhappy/triggers.d/ttyescape.conf"
+
+# Only delete the config if it's still a symlink to the example config
+if [ "$(readlink "$CONF_NAME")" = "$CONF_NAME.example" ]; then
+    rm "$CONF_NAME"
+fi
\ No newline at end of file
diff --git a/main/ttyescape/ttyescape.post-install b/main/ttyescape/ttyescape.post-install
new file mode 100644
index 0000000000000000000000000000000000000000..f490bf3aafbe9805a1336e09f789d15d77c94501
--- /dev/null
+++ b/main/ttyescape/ttyescape.post-install
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+rc-update -q add triggerhappy default
+
+# Create symlink for triggerhappy config, done here so it can be overriden without breaking world
+ln -s /etc/triggerhappy/triggers.d/ttyescape.conf.example /etc/triggerhappy/triggers.d/ttyescape.conf
\ No newline at end of file