diff --git a/src/conio/x_cio.c b/src/conio/x_cio.c
index 51a8daabd5df07f9191ffba87ea41d5d36d29817..fd37e0fda86c4e72214c0d0dd47be7c7951b6752 100644
--- a/src/conio/x_cio.c
+++ b/src/conio/x_cio.c
@@ -514,6 +514,10 @@ int x_initciolib(int mode)
 		xp_dlclose(dl);
 		return(-1);
 	}
+	if((x11.XLookupKeysym=xp_dlsym(dl,XLookupKeysym))==NULL) {
+		xp_dlclose(dl);
+		return(-1);
+	}
 #ifdef WITH_XRENDER
 	xrender_found = true;
 	if ((dl2 = xp_dlopen(libnames2,RTLD_LAZY,1)) == NULL)
diff --git a/src/conio/x_events.c b/src/conio/x_events.c
index 8cd43e61984eb3aebe3c523147424d6d4f90f4ea..21535d4c23dd9dc3e650df50c105af1e7d2ce6ac 100644
--- a/src/conio/x_events.c
+++ b/src/conio/x_events.c
@@ -1106,7 +1106,7 @@ static int init_window()
 	gcv.graphics_exposures = False;
 	gc=x11.XCreateGC(dpy, win, GCFunction | GCForeground | GCBackground | GCGraphicsExposures, &gcv);
 
-	x11.XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask
+	x11.XSelectInput(dpy, win, KeyReleaseMask | KeyPressMask | KeyReleaseMask
 		     | ExposureMask | ButtonPressMask | PropertyChangeMask
 		     | ButtonReleaseMask | PointerMotionMask
 		     | StructureNotifyMask | FocusChangeMask);
@@ -1651,9 +1651,42 @@ handle_configuration(int w, int h, bool map, bool se)
 		got_first_resize = true;
 }
 
+static void
+handle_bios_key(uint32_t *bios_key, bool *bios_key_parsing, bool *zero_first)
+{
+	uint8_t ch;
+
+	if (*bios_key > 0 && *bios_key_parsing) {
+		if (*zero_first) {
+			// Unicode character
+			ch = cpchar_from_unicode_cpoint(getcodepage(), *bios_key, 0);
+			if (ch == 0)
+				x11.XBell(dpy, 100);
+			else {
+				write(key_pipe[1], &ch, 1);
+				if (ch == 0xe0)
+					write(key_pipe[1], &ch, 1);
+			}
+		}
+		else {
+			// Codepage character
+			ch = *bios_key;
+			write(key_pipe[1], &ch, 1);
+			if (ch == 0xe0)
+				write(key_pipe[1], &ch, 1);
+		}
+	}
+	*bios_key = 0;
+	*bios_key_parsing = false;
+	*zero_first = false;
+}
+
 static void
 x11_event(XEvent *ev)
 {
+	static uint32_t bios_key = 0;
+	static bool bios_key_parsing = false;
+	static bool zero_first = false;
 	bool resize;
 	int x, y, w, h;
 
@@ -1959,6 +1992,18 @@ x11_event(XEvent *ev)
 			break;
 
 		/* Keyboard Events */
+		case KeyRelease:
+			{
+				if (bios_key_parsing) {
+					KeySym ks = x11.XLookupKeysym((XKeyEvent *)ev, 0);
+					// If Mod1 (ie: ALT) is released, *and* the only bytes were KP numbers, do the BIOS thing.
+					if (ks == XK_Alt_L || ks == XK_Alt_R) {
+						handle_bios_key(&bios_key, &bios_key_parsing, &zero_first);
+					}
+				}
+			}
+			break;
+
 		case KeyPress:
 			{
 				static char buf[128];
@@ -1970,6 +2015,7 @@ x11_event(XEvent *ev)
 				int cnt;
 				int i;
 				uint8_t ch;
+				bool terminate_bios = false;
 
 				if (ic)
 					cnt = x11.XwcLookupString(ic, (XKeyPressedEvent *)ev, wbuf, sizeof(wbuf)/sizeof(wbuf[0]), &ks, &lus);
@@ -1978,6 +2024,45 @@ x11_event(XEvent *ev)
 					lus = XLookupKeySym;
 				}
 
+				if (bios_key_parsing) {
+					if (ks >= XK_KP_0 && ks <= XK_KP_9) {
+						if (bios_key == 0 && ks == XK_KP_0)
+							zero_first = true;
+						else {
+							if (zero_first) {
+								if (bios_key >= 429496730 ||
+								    (bios_key == 429496729 && ks > XK_KP_5)) {
+									terminate_bios = true;
+								}
+							}
+							else {
+								if (bios_key >= 26 ||
+								    (bios_key == 25 && ks > XK_KP_5)) {
+									terminate_bios = true;
+								}
+							}
+							if (terminate_bios) {
+								handle_bios_key(&bios_key, &bios_key_parsing, &zero_first);
+							}
+							else {
+								bios_key *= 10;
+								bios_key += (ks - XK_KP_0);
+								break;
+							}
+						}
+					}
+					else {
+						handle_bios_key(&bios_key, &bios_key_parsing, &zero_first);
+					}
+				}
+
+				if (ks == XK_Alt_L || ks == XK_Alt_R) {
+					bios_key = 0;
+					bios_key_parsing = true;
+					zero_first = false;
+					break;
+				}
+
 				switch(lus) {
 					case XLookupNone:
 						ks = 0xffff;
diff --git a/src/conio/x_events.h b/src/conio/x_events.h
index 51b5b3cd228a494dbd5705b377519c2e68ae47e7..6e4c6b8bed5385e2d5a2ff23cb8c2aee2b6ea3b2 100644
--- a/src/conio/x_events.h
+++ b/src/conio/x_events.h
@@ -119,6 +119,7 @@ struct x11 {
 	int (*XMoveWindow)(Display *, Window, int, int);
 	Status (*XGetWMNormalHints)(Display*, Window, XSizeHints*, long*);
 	int (*XMoveResizeWindow)(Display*, Window, int, int, unsigned int, unsigned int);
+	KeySym (*XLookupKeysym)(XKeyEvent *, int);
 #ifndef DefaultDepth
 	int (*DefaultDepth)(Display *, int);
 #endif