diff --git a/Makefile b/Makefile
index 81b45c6930490600f0cde946766acf755836d22e..f2f6a37d16175a7878a94987df954db7ea3eb2bc 100644
--- a/Makefile
+++ b/Makefile
@@ -118,7 +118,8 @@ TOOLOBJ = $(SIMOBJ) \
 	  $(TARGET_DIR)/screen.o $(TARGET_DIR)/node.o			\
 	  $(TARGET_DIR)/tool.o $(TARGET_DIR)/utils.o		\
 	  $(TARGET_DIR)/pagewriter.o $(TARGET_DIR)/pagereader.o	\
-	  $(TARGET_DIR)/configreader.o $(TARGET_DIR)/attrs.o
+	  $(TARGET_DIR)/configreader.o $(TARGET_DIR)/attrs.o \
+	  $(TARGET_DIR)/keyboard.o
 
 
 $(TARGET_DIR)/ana/%.o: $(SRC_DIR)/ana/%.c
diff --git a/include/graphics/newci.h b/include/graphics/newci.h
index 1dccde8bcc29fc226cd94ad7d04d60b11fcab8d3..966cac8d2903bf3c084a2fa9d440ac033777657b 100644
--- a/include/graphics/newci.h
+++ b/include/graphics/newci.h
@@ -1,5 +1,6 @@
 #ifndef NEWCI_H
 #define NEWCI_H
+#include <stddef.h>
 
 typedef struct newci_parserec {
 	char switch_[4];
diff --git a/include/keyboard.h b/include/keyboard.h
new file mode 100644
index 0000000000000000000000000000000000000000..8e42de59a640ed2aa65115c9a27d1dae716ef074
--- /dev/null
+++ b/include/keyboard.h
@@ -0,0 +1,14 @@
+#ifndef KEYBOARD_H
+#define HEYBOARD_H
+
+int pollkbd2();
+char testkey2();
+char inkey2();
+void inkey3(char *ch);
+char inkey4();
+void ungetkey2(char ch);
+void waitforkey();
+void trykbd();
+void trykbdscroll();
+
+#endif
diff --git a/include/log.h b/include/log.h
index a99bdaa5cd5cf8220610f0d586ce09c7c2cb16c5..ee0ea4edeb97730d761a176d20647d99bfe6fb7a 100644
--- a/include/log.h
+++ b/include/log.h
@@ -29,9 +29,9 @@ void scroll();
 void doimmedcnffunction();
 void doimmedfunction();
 void docnffunction();
-void trykbd();
-char inkey2();
-int pollkbd2();
+void dofunction ();
+void assertfunc (char *name);
+void refrfunc();
 void confirmsimtype(log_nrec *n);
 void scancn(cnrec *cn, struct LOC_checkcombine *LINK);
 void addblobs(blobrec **blbase, short x1, short y1, short x2, short y2);
diff --git a/include/page.h b/include/page.h
index 8e3125727fadbae9ffd59ebe6834a66125f78666..041225ec90f3ff30c82ec69eda99a7d05f657f00 100644
--- a/include/page.h
+++ b/include/page.h
@@ -4,7 +4,8 @@
 #include "logdef.h"
 #include "gate.h"
 #include "wire.h"
-#include "label.h"
+
+typedef struct log_lrec log_lrec;
 
 typedef struct log_regrec {
   short pagenum;
diff --git a/src/graphics/newkbd.c b/src/graphics/newkbd.c
index e4e73634bc51c05e462846d9b0fc91956c818dd9..ac8a66b5de39db1b77c6469b8fb97158cdf05a52 100644
--- a/src/graphics/newkbd.c
+++ b/src/graphics/newkbd.c
@@ -182,4 +182,3 @@ void nk_settransarray(int mode, nk_keytransinfo ** mat)
   }
 }
 
-
diff --git a/src/keyboard.c b/src/keyboard.c
new file mode 100644
index 0000000000000000000000000000000000000000..832e70b098fb0b6baa3aaf3eec1efaa42ebcd807
--- /dev/null
+++ b/src/keyboard.c
@@ -0,0 +1,217 @@
+#include "keyboard.h"
+
+#include <graphics/newci.h>
+#include "logglobals.h"
+#include "logdef.h"
+#include "log.h"
+#include "screen.h"
+
+/// Return TRUE if a key has been pressed (via keyboard or menu boxes).
+int pollkbd2()
+{
+	return (nk_keybufsize() != 0 || pushedbackkey != '\0');
+}
+
+/// Return the most recently pressed key.
+char testkey2()
+{
+	if (pushedbackkey != '\0')
+		return pushedbackkey;
+	else if (pollkbd2())
+		return (nk_testkey(0));
+	else
+		return ' ';
+}
+
+
+/// Return a keystroke. Key is removed from the buffer.
+char inkey2()
+{
+	char ch;
+
+	do
+	{
+	} while (!pollkbd2());
+	if (pushedbackkey != '\0')
+	{
+		realkey = pushedbackkey;
+		pushedbackkey = '\0';
+	}
+	else
+	{
+		realkey = nk_getkey();
+	}
+	ch = realkey;
+	if ((ch & 255) >= 168 && (ch & 255) <= 239 && nk_capslock)
+	{
+		if ((ch & 255) <= 193)
+		{
+			ch += 46;
+		} else if ((ch & 255) >= 214)
+		{
+			ch -= 46;
+		}
+	}
+	gg.fastspeed = gg.fastmin;
+	return ch;
+}
+
+
+void inkey3(char *ch)
+{
+	*ch = inkey2();
+}
+
+
+char inkey4()
+{
+	/* undo CAPSLOCK key */
+	char ch;
+
+	ch = inkey2();
+	if (!nk_capslock)
+		return ch;
+	if (isupper(ch))
+		ch += 32;
+	else if (islower(ch))
+		ch -= 32;
+	return ch;
+}
+
+
+void ungetkey2(char ch)
+{
+	pushedbackkey = ch;
+}
+
+/// Wait until a key is pressed (but ignore it).
+void waitforkey()
+{
+	char ch;
+
+	while (pollkbd2())
+		ch = inkey2();
+	do
+	{
+		pen();
+	} while (!(pollkbd2() || (gg.t.dn && gg.t.off)));
+	if (pollkbd2())
+		ch = inkey2();
+}
+
+/// Check the keyboard for macros.
+void trykbd()
+{
+	long t;
+	int moving;
+	char ch;
+	macrorec *mp;
+	strlist_t *todo;
+	char TEMP;
+
+	if (gg.t.near_ && !gg.t0.near_ && gg.showpage >= 0)
+	{
+		m_graphics_on();
+		m_alpha_off();
+	}
+	if (thingstodo != NULL)
+	{
+		if (nexttodo == NULL)
+			todo = thingstodo;
+		else
+			todo = nexttodo;
+		nexttodo = todo->next;
+		assertfunc(todo->s);
+		if (nexttodo == NULL)
+			strlist_empty(&thingstodo);
+		return;
+	}
+	if (!pollkbd2())
+		return;
+	norabbits();
+	rabtime = timers_sysclock();
+	ch = inkey4();
+	switch (ch)
+	{
+
+		case '\003':
+			assertfunc("ABORT");
+			break;
+
+		case '\b':
+		case '\034':   /* Scroll horizontally */
+			do
+			{
+				m_graphics_on();
+				m_colormode((long)m_xor);
+				m_color((long)gg.color.scroll);
+				m_drawline(xoff0 - 1, 0L, xoff0 - 1, baseline - 1L);
+				m_drawline(xoff0 + across + 1, 0L, xoff0 + across + 1, baseline - 1L);
+				if (ch == '\b')
+					xoff0 -= gg.scale * hscrollspd;
+				if (ch == '\034')
+					xoff0 += gg.scale * hscrollspd;
+				m_drawline(xoff0 - 1, 0L, xoff0 - 1, baseline - 1L);
+				m_drawline(xoff0 + across + 1, 0L, xoff0 + across + 1, baseline - 1L);
+				m_colormode((long)m_normal);
+				t = timers_sysclock() + knobwait;
+				do {
+				} while (timers_sysclock() <= t && testkey2() == ' ');
+				TEMP = testkey2();
+				moving = ((uchar)TEMP < 32 && ((1L << TEMP) & 0x10000100L) != 0);
+				if (moving)
+					ch = inkey2();
+			} while (moving && labs(xoff0) <= across - 10);
+			refrfunc();
+			break;
+
+		case '\n':
+		case '\037':   /* Scroll vertically */
+			do
+			{
+				m_graphics_on();
+				m_colormode((long)m_xor);
+				m_color((long)gg.color.scroll);
+				if (yoff0 < baseline)
+					m_drawline(0L, yoff0 - 1, (long)across, yoff0 - 1);
+				if (yoff0 < 0)
+					m_drawline(0L, yoff0 + baseline, (long)across, yoff0 + baseline);
+				if (ch == '\n')
+					yoff0 += gg.scale * vscrollspd;
+				if (ch == '\037')
+					yoff0 -= gg.scale * vscrollspd;
+				if (yoff0 < baseline)
+					m_drawline(0L, yoff0 - 1, (long)across, yoff0 - 1);
+				if (yoff0 < 0)
+					m_drawline(0L, yoff0 + baseline, (long)across, yoff0 + baseline);
+				m_colormode((long)m_normal);
+				t = timers_sysclock() + knobwait;
+				do
+				{
+				} while (timers_sysclock() <= t && testkey2() == ' ');
+				TEMP = testkey2();
+				moving = ((uchar)TEMP < 32 && ((1L << TEMP) & 0x80000400L) != 0);
+				if (moving)
+					ch = inkey2();
+			} while (moving && labs(yoff0) <= baseline - 10);
+			refrfunc();
+			break;
+
+		default:
+			mp = macrobase;
+			while (mp != NULL && mp->key != ch)
+				mp = mp->next;
+			if (mp != NULL)
+				assertfunc(mp->name);
+			break;
+	}
+}
+
+void trykbdscroll()
+{
+	immedscroll = true;
+	trykbd();
+	immedscroll = false;
+	scroll();
+}
+
diff --git a/src/label.c b/src/label.c
index 5452f2b638856c36e38f741af590dd2b23cdaaa2..5e87c70c3fc6b47881440c3efe03c578acae07d9 100644
--- a/src/label.c
+++ b/src/label.c
@@ -12,6 +12,7 @@
 #include "page.h"
 #include "screen.h"
 #include "log.h"
+#include "keyboard.h"
 
 
 /**
diff --git a/src/log.c b/src/log.c
index 64a62ca0ef7a5966ce6cf0cfa04f0d3d91ae1f9d..3ed0d430f9c698401415d86c8c9d2166bf8d41f4 100644
--- a/src/log.c
+++ b/src/log.c
@@ -73,6 +73,7 @@
 #include "page.h"
 #include "utils.h"
 #include "tool.h"
+#include "keyboard.h"
 
 #include "pagewriter.h"
 #include "pagereader.h"
@@ -741,13 +742,6 @@ static void show_events()
 }
 
 
-/// Return TRUE if a key has been pressed (via keyboard or menu boxes).
-int pollkbd2()
-{
-	return (nk_keybufsize() != 0 || pushedbackkey != '\0');
-}
-
-
 /** @brief Find the position of the pen.
 			Also draws the cursor, runs logic probe and handles Rabbit mode.
 
@@ -948,93 +942,6 @@ static int justtap()
 	return (!gg.t.depressed);
 }
 
-/// Return the most recently pressed key.
-static char testkey2()
-{
-	if (pushedbackkey != '\0')
-		return pushedbackkey;
-	else if (pollkbd2())
-		return (nk_testkey(0));
-	else
-		return ' ';
-}
-
-
-/// Return a keystroke. Key is removed from the buffer.
-char inkey2()
-{
-	char ch;
-
-	do
-	{
-	} while (!pollkbd2());
-	if (pushedbackkey != '\0')
-	{
-		realkey = pushedbackkey;
-		pushedbackkey = '\0';
-	}
-	else
-	{
-		realkey = nk_getkey();
-	}
-	ch = realkey;
-	if ((ch & 255) >= 168 && (ch & 255) <= 239 && nk_capslock)
-	{
-		if ((ch & 255) <= 193)
-		{
-			ch += 46;
-		} else if ((ch & 255) >= 214)
-		{
-			ch -= 46;
-		}
-	}
-	gg.fastspeed = gg.fastmin;
-	return ch;
-}
-
-
-static void inkey3(char *ch)
-{
-	*ch = inkey2();
-}
-
-
-static char inkey4()
-{
-	/* undo CAPSLOCK key */
-	char ch;
-
-	ch = inkey2();
-	if (!nk_capslock)
-		return ch;
-	if (isupper(ch))
-		ch += 32;
-	else if (islower(ch))
-		ch -= 32;
-	return ch;
-}
-
-
-static void ungetkey2(char ch)
-{
-	pushedbackkey = ch;
-}
-
-/// Wait until a key is pressed (but ignore it).
-static void waitforkey()
-{
-	char ch;
-
-	while (pollkbd2())
-		ch = inkey2();
-	do
-	{
-		pen();
-	} while (!(pollkbd2() || (gg.t.dn && gg.t.off)));
-	if (pollkbd2())
-		ch = inkey2();
-}
-
 
 /// Return TRUE if cursor is inside a certain rectangular area (screen coordinates).
 static int inbox(short x, short y, short x1, short y1)
@@ -2373,9 +2280,6 @@ static void readlnpass(char *s, short mode)
 	}
 }
 
-static void dofunction ();
-
-static void assertfunc (char *name);
 
 static void clearfunc()
 {
@@ -2385,7 +2289,7 @@ static void clearfunc()
 		assertfunc("");
 }
 
-static void refrfunc()
+void refrfunc()
 {
 	if (gg.initdone && !doingcnffunction)
 		assertfunc("REFR");
@@ -2788,7 +2692,7 @@ void doimmedfunction()
 }
 
 
-static void assertfunc(char *name_)
+void assertfunc(char *name_)
 {
 	char name[256];
 	char cmd[17];
@@ -2816,123 +2720,6 @@ static void assertfunc(char *name_)
 }
 
 
-/// Check the keyboard for macros.
-void trykbd()
-{
-	long t;
-	int moving;
-	char ch;
-	macrorec *mp;
-	strlist_t *todo;
-	char TEMP;
-
-	if (gg.t.near_ && !gg.t0.near_ && gg.showpage >= 0)
-	{
-		m_graphics_on();
-		m_alpha_off();
-	}
-	if (thingstodo != NULL)
-	{
-		if (nexttodo == NULL)
-			todo = thingstodo;
-		else
-			todo = nexttodo;
-		nexttodo = todo->next;
-		assertfunc(todo->s);
-		if (nexttodo == NULL)
-			strlist_empty(&thingstodo);
-		return;
-	}
-	if (!pollkbd2())
-		return;
-	norabbits();
-	rabtime = timers_sysclock();
-	ch = inkey4();
-	switch (ch)
-	{
-
-		case '\003':
-			assertfunc("ABORT");
-			break;
-
-		case '\b':
-		case '\034':   /* Scroll horizontally */
-			do
-			{
-				m_graphics_on();
-				m_colormode((long)m_xor);
-				m_color((long)gg.color.scroll);
-				m_drawline(xoff0 - 1, 0L, xoff0 - 1, baseline - 1L);
-				m_drawline(xoff0 + across + 1, 0L, xoff0 + across + 1, baseline - 1L);
-				if (ch == '\b')
-					xoff0 -= gg.scale * hscrollspd;
-				if (ch == '\034')
-					xoff0 += gg.scale * hscrollspd;
-				m_drawline(xoff0 - 1, 0L, xoff0 - 1, baseline - 1L);
-				m_drawline(xoff0 + across + 1, 0L, xoff0 + across + 1, baseline - 1L);
-				m_colormode((long)m_normal);
-				t = timers_sysclock() + knobwait;
-				do {
-				} while (timers_sysclock() <= t && testkey2() == ' ');
-				TEMP = testkey2();
-				moving = ((uchar)TEMP < 32 && ((1L << TEMP) & 0x10000100L) != 0);
-				if (moving)
-					ch = inkey2();
-			} while (moving && labs(xoff0) <= across - 10);
-			refrfunc();
-			break;
-
-		case '\n':
-		case '\037':   /* Scroll vertically */
-			do
-			{
-				m_graphics_on();
-				m_colormode((long)m_xor);
-				m_color((long)gg.color.scroll);
-				if (yoff0 < baseline)
-					m_drawline(0L, yoff0 - 1, (long)across, yoff0 - 1);
-				if (yoff0 < 0)
-					m_drawline(0L, yoff0 + baseline, (long)across, yoff0 + baseline);
-				if (ch == '\n')
-					yoff0 += gg.scale * vscrollspd;
-				if (ch == '\037')
-					yoff0 -= gg.scale * vscrollspd;
-				if (yoff0 < baseline)
-					m_drawline(0L, yoff0 - 1, (long)across, yoff0 - 1);
-				if (yoff0 < 0)
-					m_drawline(0L, yoff0 + baseline, (long)across, yoff0 + baseline);
-				m_colormode((long)m_normal);
-				t = timers_sysclock() + knobwait;
-				do
-				{
-				} while (timers_sysclock() <= t && testkey2() == ' ');
-				TEMP = testkey2();
-				moving = ((uchar)TEMP < 32 && ((1L << TEMP) & 0x80000400L) != 0);
-				if (moving)
-					ch = inkey2();
-			} while (moving && labs(yoff0) <= baseline - 10);
-			refrfunc();
-			break;
-
-		default:
-			mp = macrobase;
-			while (mp != NULL && mp->key != ch)
-				mp = mp->next;
-			if (mp != NULL)
-				assertfunc(mp->name);
-			break;
-	}
-}
-
-
-static void trykbdscroll()
-{
-	immedscroll = true;
-	trykbd();
-	immedscroll = false;
-	scroll();
-}
-
 
 void confirmsimtype(log_nrec *n)
 {
@@ -12120,9 +11907,7 @@ void docnffunction()
 	clearfunc();
 }
 
-
-
-static void dofunction()
+void dofunction()
 {
 	log_tool *tp;
 	char cmd[17];