diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c
index 3e9d90cb9611dc43e5596be20f53eb1dbd0ee454..04a5a51b7e13c15eb1682880e4ec773ebc38e789 100644
--- a/src/conio/bitmap_con.c
+++ b/src/conio/bitmap_con.c
@@ -23,6 +23,15 @@
 #include "vidmodes.h"
 #include "bitmap_con.h"
 
+struct palette_entry {
+	uint8_t	red;
+	uint8_t	green;
+	uint8_t	blue;
+	time_t	allocated;
+};
+
+static struct palette_entry truecolour_palette[15840];	// Big enough for a unique fg/bg for each cell in a 132x60 window
+
 #if 0
 
 int dbg_pthread_mutex_lock(pthread_mutex_t *lptr, unsigned line)
@@ -1417,6 +1426,35 @@ int bitmap_set_modepalette(uint32_t p[16])
 	return 0;
 }
 
+uint32_t bitmap_map_rgb(uint16_t r, uint16_t g, uint16_t b)
+{
+	time_t oldest;
+	int oldestoff;
+	int i;
+	time_t now = time(NULL);
+
+	oldest = now;
+	r>>=8;
+	g>>=8;
+	b>>=8;
+	for (i=0; i<sizeof(truecolour_palette) / sizeof(truecolour_palette[0]); i++) {
+		if (truecolour_palette[i].allocated == 0)
+			break;
+		if (truecolour_palette[i].allocated < oldest) {
+			oldest = truecolour_palette[i].allocated;
+			oldestoff = i;
+		}
+		if (truecolour_palette[i].red == r && truecolour_palette[i].green == g && truecolour_palette[i].blue == b) {
+			truecolour_palette[i].allocated = now;
+			return i + TOTAL_DAC_SIZE + 512;
+		}
+	}
+
+	ciolib_setpalette(i + TOTAL_DAC_SIZE + 512, r<<8 | r, g<<8 | g, b<<8 | b);
+	truecolour_palette[i].allocated = now;
+	return i + TOTAL_DAC_SIZE + 512;
+}
+
 /***********************/
 /* Called from drivers */
 /***********************/
diff --git a/src/conio/bitmap_con.h b/src/conio/bitmap_con.h
index b58217e63bc35b479a92462c2dbe6576ebbc2001..51b870ac241f4300378178972ec3e82ad2a28c12 100644
--- a/src/conio/bitmap_con.h
+++ b/src/conio/bitmap_con.h
@@ -30,6 +30,7 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_
 struct ciolib_pixels *bitmap_getpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey);
 uint32_t *bitmap_get_modepalette(uint32_t p[16]);
 int bitmap_set_modepalette(uint32_t p[16]);
+uint32_t bitmap_map_rgb(uint16_t r, uint16_t g, uint16_t b);
 #endif
 
 #ifdef BITMAP_CIOLIB_DRIVER
diff --git a/src/conio/ciolib.c b/src/conio/ciolib.c
index 53b26eac61d5e3cb00535cca7a879fe3db8c2676..55fc5ca96dfcefe96d731da7a3844910ee73f196 100644
--- a/src/conio/ciolib.c
+++ b/src/conio/ciolib.c
@@ -189,6 +189,7 @@ int try_sdl_init(int mode)
 		cio_api.setpixels=bitmap_setpixels;
 		cio_api.get_modepalette=bitmap_get_modepalette;
 		cio_api.set_modepalette=bitmap_set_modepalette;
+		cio_api.map_rgb = bitmap_map_rgb;
 		return(1);
 	}
 	return(0);
@@ -243,6 +244,7 @@ int try_x_init(int mode)
 		cio_api.setpixels=bitmap_setpixels;
 		cio_api.get_modepalette=bitmap_get_modepalette;
 		cio_api.set_modepalette=bitmap_set_modepalette;
+		cio_api.map_rgb = bitmap_map_rgb;
 		return(1);
 	}
 	return(0);
@@ -1911,3 +1913,12 @@ CIOLIBEXPORT int CIOLIBCALL ciolib_set_modepalette(uint32_t p[16])
 		return cio_api.set_modepalette(p);
 	return 0;
 }
+
+CIOLIBEXPORT uint32_t CIOLIBCALL ciolib_map_rgb(uint16_t r, uint16_t g, uint16_t b)
+{
+	CIOLIB_INIT();
+
+	if (cio_api.map_rgb)
+		return cio_api.map_rgb(r,g,b);
+	return UINT32_MAX;
+}
diff --git a/src/conio/ciolib.h b/src/conio/ciolib.h
index 60e100b9b5387441933b77c542b70a456dafc3fb..2454ab3ada858621015b255b8d1ed97e8430e05a 100644
--- a/src/conio/ciolib.h
+++ b/src/conio/ciolib.h
@@ -362,6 +362,7 @@ typedef struct {
 	int		(*setpixels)(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_t x_off, uint32_t y_off, struct ciolib_pixels *pixels, void *mask);
 	uint32_t 	*(*get_modepalette)(uint32_t[16]);
 	int	(*set_modepalette)(uint32_t[16]);
+	uint32_t	(*map_rgb)(uint16_t r, uint16_t g, uint16_t b);
 } cioapi_t;
 
 CIOLIBEXPORTVAR cioapi_t cio_api;
@@ -451,6 +452,7 @@ CIOLIBEXPORT int CIOLIBCALL ciolib_restorescreen(struct ciolib_screen *scrn);
 CIOLIBEXPORT void CIOLIBCALL ciolib_setcolour(uint32_t fg, uint32_t bg);
 CIOLIBEXPORT uint32_t * CIOLIBCALL ciolib_get_modepalette(uint32_t[16]);
 CIOLIBEXPORT int CIOLIBCALL ciolib_set_modepalette(uint32_t[16]);
+CIOLIBEXPORT uint32_t CIOLIBCALL ciolib_map_rgb(uint16_t r, uint16_t g, uint16_t b);
 
 /* DoorWay specific stuff that's only applicable to ANSI mode. */
 CIOLIBEXPORT void CIOLIBCALL ansi_ciolib_setdoorway(int enable);
@@ -528,6 +530,7 @@ CIOLIBEXPORT void CIOLIBCALL ansi_ciolib_setdoorway(int enable);
 	#define setcolour(a,b)			ciolib_setcolour(a,b)
 	#define get_modepalette(a)		ciolib_get_modepalette(a)
 	#define set_modepalette(a)		ciolib_set_modepalette(a)
+	#define map_rgb(a,b,c)			ciolib_map_rgb(a,b,c)
 #endif
 
 #ifdef WITH_SDL
diff --git a/src/conio/cterm.c b/src/conio/cterm.c
index 780f820819fbe9bacdc4eeb744cc7fafd94357d2..4db7325e1f690808974ace636e1f91400ed1334f 100644
--- a/src/conio/cterm.c
+++ b/src/conio/cterm.c
@@ -2463,6 +2463,13 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 										cterm->fg_color = seq->param_int[i+2] + 16;
 										i+=2;
 									}
+									else if (i+5 < seq->param_count && seq->param_int[i+1] == 2) {
+										uint32_t nc;
+
+										nc = map_rgb(seq->param_int[i+3]<<8, seq->param_int[i+4]<<8, seq->param_int[i+5]<<8);
+										if (nc != UINT32_MAX)
+											cterm->fg_color = nc;
+									}
 									break;
 								case 37:
 								case 39:
@@ -2515,6 +2522,13 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 										cterm->bg_color = seq->param_int[i+2] + 16;
 										i+=2;
 									}
+									else if (i+5 < seq->param_count && seq->param_int[i+1] == 2) {
+										uint32_t nc;
+
+										nc = map_rgb(seq->param_int[i+3]<<8, seq->param_int[i+4]<<8, seq->param_int[i+5]<<8);
+										if (nc != UINT32_MAX)
+											cterm->bg_color = nc;
+									}
 									break;
 							}
 						}
@@ -2577,6 +2591,22 @@ static void do_ansi(struct cterminal *cterm, char *retbuf, size_t retsize, int *
 						cterm->save_xpos=WHEREX();
 						cterm->save_ypos=WHEREY();
 						break;
+					case 't':
+						if (seq->param_count >= 4) {
+							uint32_t *c = NULL;
+							uint32_t nc;
+
+							if (seq->param_int[0] == 0)
+								c = &cterm->bg_color;
+							else if (seq->param_int[0] == 1)
+								c = &cterm->fg_color;
+							if (c == NULL)
+								break;
+							nc = map_rgb(seq->param_int[1]<<8, seq->param_int[2]<<8, seq->param_int[3]<<8);
+							if (nc != UINT32_MAX)
+								*c = nc;
+						}
+						break;
 					case 'u':
 						if(cterm->save_ypos>0 && cterm->save_ypos<=cterm->height
 								&& cterm->save_xpos>0 && cterm->save_xpos<=cterm->width) {
diff --git a/src/conio/cterm.txt b/src/conio/cterm.txt
index 57ace685fc74dd08a8b3a3d4a37374cb9ad29ab9..3c8d9b728506bfec519fa28a5fb69d622ce380df 100644
--- a/src/conio/cterm.txt
+++ b/src/conio/cterm.txt
@@ -638,7 +638,7 @@ CSI Ps... m
 	35 - Magenta foreground                            X
 	36 - Cyan foreground                               X
 	37 - White foreground                              X
-	38 - Foreground from palette (see note)            X
+	38 - Extended Foreground (see notes)               X
 	39 - Default foreground (same as white)	           X
 	40 - Black background                                 X
 	41 - Red background                                   X
@@ -648,13 +648,16 @@ CSI Ps... m
 	45 - Magenta background                               X
 	46 - Cyan background                                  X
 	47 - White background                                 X
-	48 - Background from palette (see note)            X
+	48 - Extended Background (see notes)                  X
 	49 - Default background (same as black)               X
 
 	All others are ignored.
 
-	Note, For 38 and 48, an additional two parameters are required
-	after that value.  They are considered part of the 38, not separate
+	NOTE: For 38 and 48, two additional formats are supported, a palette
+	selection and a direct colour selection.
+
+	For palette selection, an additional two parameters are required
+	after that value.  They are considered part of the 38/48, not separate
 	values.  The first additional parameter must be a 5.  The second
 	additional parameter specified the palette index to use.  To set the
 	foreground to orange, and the background to a fairly dark grey, you
@@ -664,6 +667,16 @@ CSI Ps... m
 	The default palette is the XTerm 256-colour palette.  See here:
 	https://jonasjacek.github.io/colors/
 
+	For direct colour selection, an additional five parameters are required
+	after that value.  They are considered part of the 38/48, not separate
+	values.  The first additional parameter must be a 2.  The second
+	additional parameter is ignored.  The third, fourth, and fifth specify
+	the R/G/B values respectively. CTerm handles this with an internal
+	temporary palette, so scrollback may not have the correct colours.
+	The internal palette is large enough for all cells in a 132x60 screen
+	to have unique foreground and background colours though, so the current
+	screen should always be as expected.
+
 	SOURCE: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf
 	SOURCE: XTerm
 
@@ -777,6 +790,18 @@ CSI s
 
 	SOURCE: ANSI.SYS
 
+CSI Ps ; Pn1 ; Pn2 ; Pn3 t
+	NON-STANDARD EXTENSION
+	Select a 24-bit colour
+	If Ps is 0, sets the background colour.
+	If Ps is 1, sets the foreground colour.
+	Pn1, Pn2, Pn3 contains the RGB value to set.
+	CTerm handles this with an internal temporary palette, so scrollback
+	may not have the correct colours.  The internal palette is large
+	enough for all cells in a 132x60 screen to have unique foreground
+	and background colours though, so the current screen should always
+	be as expected.
+
 CSI ? Ps...  u
 	NON-STANDARD EXTENSION
 	Restore Mode Setting