]> granicus.if.org Git - nethack/commitdiff
adjustment of win32 console colours (trunk only)
authornethack.allison <nethack.allison>
Sun, 3 Sep 2006 04:17:09 +0000 (04:17 +0000)
committernethack.allison <nethack.allison>
Sun, 3 Sep 2006 04:17:09 +0000 (04:17 +0000)
Allow config file entries to adjust win32 console colours.

The following entries in a config file are examples:
OPTIONS=palette:black-0-0-0
OPTIONS=palette:red-210-0-0
OPTIONS=palette:green-80-200-0
OPTIONS=palette:brown-180-100-0
OPTIONS=palette:blue-0-0-200
OPTIONS=palette:magenta-128-0-128
OPTIONS=palette:cyan-50-180-180
OPTIONS=palette:gray-192-192-192
OPTIONS=palette:dark gray-100-100-100
OPTIONS=palette:orange-255-128-0
OPTIONS=palette:bright green-0-255-0
OPTIONS=palette:yellow-255-255-0
OPTIONS=palette:bright blue-100-100-240
OPTIONS=palette:bright magenta-255-0-255
OPTIONS=palette:bright cyan-0-255-255
OPTIONS=palette:white-255-255-255

This uses an undocumented way to adjust the console
colours in a win32 console application. The method and
code snippet used comes from www.catch22.net by James Brown.

This page:
      http://www.catch22.net/about.asp
states the following:
"you do not have to pay anything to use the software, and there are no
 licencing terms for any sourcecode that you may download from this site.
This means you can freely use any sourcecode or portions of code in
your applications, whether they be free software or professional, retail
products."

include/ntconf.h
src/options.c
sys/winnt/defaults.nh
sys/winnt/nttty.c

index faeb6aad85378d2b4e5282544c594b45dc8f697f..8323af5970f6bd390f0763bf9769f17b543be837 100644 (file)
@@ -26,6 +26,7 @@
 #define USER_SOUNDS
 
 #ifdef WIN32CON
+#define CHANGE_COLOR           /* allow palette changes in win32 console */
 #define SELECTSAVED            /* Provide menu of saved games to choose from at start */
 #endif
 
@@ -231,6 +232,9 @@ extern int FDECL(set_win32_option, (const char *, const char *));
 #define RIGHTBUTTON RIGHTMOST_BUTTON_PRESSED
 #define MIDBUTTON   FROM_LEFT_2ND_BUTTON_PRESSED
 #define MOUSEMASK (LEFTBUTTON | RIGHTBUTTON | MIDBUTTON)
+#ifdef CHANGE_COLOR
+extern int FDECL(alternative_palette, (char *));
+#endif
 #endif /* WIN32CON */
 
 #endif /* NTCONF_H */
index cddb16faf13efb6c52138108d66292c3dfe4c8bf..21ac556890d7171110255d244bfe87d2bd1b2fba 100644 (file)
@@ -311,8 +311,14 @@ static struct Comp_Opt
        { "packorder", "the inventory order of the items in your pack",
                                                MAXOCLASSES, SET_IN_GAME },
 #ifdef CHANGE_COLOR
-       { "palette",  "palette (00c/880/-fff is blue/yellow/reverse white)",
+       { "palette",
+# ifndef WIN32CON
+                       "palette (00c/880/-fff is blue/yellow/reverse white)",
                                                15 , SET_IN_GAME },
+# else
+                       "palette (adjust an RGB color in palette (color-R-G-B)",
+                                               15 , SET_IN_FILE },
+# endif
 # if defined(MAC)
        { "hicolor",  "same as palette, only order is reversed",
                                                15, SET_IN_FILE },
@@ -1445,7 +1451,9 @@ boolean tinitial, tfrom_file;
                                                        ) {
            int color_number, color_incr;
 
+#ifndef WIN32CON
            if (duplicate) complain_about_duplicate(opts,1);
+#endif
 # ifdef MAC
            if (match_optname(opts, "hicolor", 3, TRUE)) {
                if (negated) {
@@ -1466,6 +1474,10 @@ boolean tinitial, tfrom_file;
            }
 # endif
            if ((op = string_for_opt(opts, FALSE)) != (char *)0) {
+# ifdef WIN32CON
+               if (!alternative_palette(op))
+                       badoption(opts);
+# else
                char *pt = op;
                int cnt, tmp, reverse;
                long rgb;
@@ -1481,21 +1493,21 @@ boolean tinitial, tfrom_file;
                    }
                    while (cnt-- > 0) {
                        if (*pt && *pt != '/') {
-# ifdef AMIGA
+#  ifdef AMIGA
                            rgb <<= 4;
-# else
+#  else
                            rgb <<= 8;
-# endif
+#  endif
                            tmp = *(pt++);
                            if (isalpha(tmp)) {
                                tmp = (tmp + 9) & 0xf;  /* Assumes ASCII... */
                            } else {
                                tmp &= 0xf;     /* Digits in ASCII too... */
                            }
-# ifndef AMIGA
+#  ifndef AMIGA
                            /* Add an extra so we fill f -> ff and 0 -> 00 */
                            rgb += tmp << 4;
-# endif
+#  endif
                            rgb += tmp;
                        }
                    }
@@ -1505,6 +1517,7 @@ boolean tinitial, tfrom_file;
                    change_color(color_number, rgb, reverse);
                    color_number += color_incr;
                }
+# endif        /* !WIN32CON */
            }
            if (!initial) {
                need_redraw = TRUE;
index b0cfe015c8a942fc8675053be1809537b7b42350..be1d53ef78332476cbe7be3c548a88a70187cf83 100644 (file)
@@ -125,6 +125,27 @@ OPTIONS=hilite_pet,!toptenwin
 #OPTIONS=subkeyvalue:184/91
 #OPTIONS=subkeyvalue:188/124
 
+#
+# Some versions of Windows allow you to adjust the win32 console port 
+# colors using R-G-B settings.
+#
+#OPTIONS=palette:black-0-0-0
+#OPTIONS=palette:red-210-0-0
+#OPTIONS=palette:green-80-200-0
+#OPTIONS=palette:brown-180-100-0
+#OPTIONS=palette:blue-0-0-200
+#OPTIONS=palette:magenta-128-0-128
+#OPTIONS=palette:cyan-50-180-180
+#OPTIONS=palette:gray-192-192-192
+#OPTIONS=palette:dark gray-100-100-100
+#OPTIONS=palette:orange-255-128-0
+#OPTIONS=palette:bright green-0-255-0
+#OPTIONS=palette:yellow-255-255-0
+#OPTIONS=palette:bright blue-100-100-240
+#OPTIONS=palette:bright magenta-255-0-255
+#OPTIONS=palette:bright cyan-0-255-255
+#OPTIONS=palette:white-255-255-255
+
 #
 # *** CHARACTER GRAPHICS ***
 #
index fc4be4451e341a2ffb03abe59cdd4a0b88825a38..9f7885d1fdaec1c11c0d41054a8571958e3501f3 100644 (file)
@@ -37,6 +37,7 @@ int FDECL(process_keystroke, (INPUT_RECORD *, boolean *,
  * ReadConsoleInput
  * WriteConsoleOutputCharacter
  * FillConsoleOutputAttribute
+ * GetConsoleOutputCP
  */
 
 /* Win32 Console handles for input and output */
@@ -74,6 +75,26 @@ typedef int (__stdcall * PROCESS_KEYSTROKE)(
     int
 );
 
+#ifdef CHANGE_COLOR
+static void NDECL(adjust_palette);
+static int FDECL(match_color_name, (const char *));
+static boolean altered_palette;
+static COLORREF UserDefinedColors[CLR_MAX];
+static COLORREF NetHackColors[CLR_MAX] = {
+       0x00000000,0x00c80000,0x0000c850,0x00b4b432,
+       0x000000d2,0x00800080,0x000064b4,0x00c0c0c0,
+       0x00646464,0x00f06464,0x0000ff00,0x00ffff00,
+       0x000000ff,0x00ff00ff,0x0000ffff,0x00ffffff
+    };
+static COLORREF DefaultColors[CLR_MAX] = {
+        0x00000000, 0x00800000, 0x00008000, 0x00808000,
+        0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
+        0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
+        0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
+    };
+
+#endif
+
 typedef int (__stdcall * NHKBHIT)(
     HANDLE,
     INPUT_RECORD *
@@ -166,6 +187,9 @@ const char *s;
 void
 setftty()
 {
+#ifdef CHANGE_COLOR
+       if (altered_palette) adjust_palette();
+#endif
        start_screen();
 }
 
@@ -973,4 +997,346 @@ synch_cursor()
 {
        really_move_cursor();
 }
+
+# ifdef CHANGE_COLOR
+void tty_change_color(color_number, rgb, reverse)
+int color_number, reverse;
+long rgb;
+{
+       /* Map NetHack color index to NT Console palette index */
+       int idx, win32_color_number[] = {
+                0, /* CLR_BLACK           0 */
+                4, /* CLR_RED             1 */
+                2, /* CLR_GREEN           2 */
+                6, /* CLR_BROWN           3 */
+                1, /* CLR_BLUE            4 */
+                5, /* CLR_MAGENTA         5 */
+                3, /* CLR_CYAN            6 */
+                7, /* CLR_GRAY            7 */
+                8, /* NO_COLOR            8 */
+               12, /* CLR_ORANGE          9 */
+               10, /* CLR_BRIGHT_GREEN   10 */
+               14, /* CLR_YELLOW         11 */
+                9, /* CLR_BRIGHT_BLUE    12 */
+               13, /* CLR_BRIGHT_MAGENTA 13 */
+               11, /* CLR_BRIGHT_CYAN    14 */
+               15  /* CLR_WHITE          15 */
+       };
+       int k;
+       if (color_number < 0) { /* indicates OPTIONS=palette with no value */
+               /* copy the NetHack palette into UserDefinedColors */
+               for (k=0; k < CLR_MAX; k++)
+                       UserDefinedColors[k] = NetHackColors[k];
+               return;
+       } else if (color_number >= 0 && color_number < CLR_MAX) {
+               idx = win32_color_number[color_number];
+               UserDefinedColors[idx] = rgb;
+       }
+       altered_palette = TRUE;
+}
+
+char *tty_get_color_string()
+{
+       return "";
+}
+
+int
+match_color_name(c)
+const char *c;
+{
+       const struct others {
+               int idx;
+               const char *colorname;
+       } othernames[] = {
+               {CLR_MAGENTA, "purple"},
+               {CLR_BRIGHT_MAGENTA, "bright purple"},
+               {NO_COLOR, "dark gray"},
+               {NO_COLOR, "dark grey"},
+               {CLR_GRAY, "grey"},
+       };
+
+       int cnt;
+       for (cnt = 0; cnt < CLR_MAX; ++cnt) {
+               if (!strcmpi(c, c_obj_colors[cnt]))
+                       return cnt;
+       }
+       for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
+               if (!strcmpi(c, othernames[cnt].colorname))
+                       return othernames[cnt].idx;
+       }
+       return -1;
+}
+
+/*
+ * Returns 0 if badoption syntax
+ */
+int
+alternative_palette(op)
+char *op;
+{      
+       /*
+        *      palette:color-R-G-B
+        *      OPTIONS=palette:green-4-3-1, palette:0-0-0-0
+        */
+       int fieldcnt, color_number, rgb, red, green, blue;
+       char *fields[4], *cp;
+
+       if (!op) {
+               change_color(-1,0,0);   /* indicates palette option with
+                                          no value meaning "load an entire
+                                          hard-coded NetHack palette." */
+               return 1;
+       }
+
+       cp = fields[0] = op;
+       for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
+               cp = index(cp, '-');
+               if (!cp) return 0;
+               fields[fieldcnt] = cp;
+               cp++;
+       }
+       for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
+               *(fields[fieldcnt]) = '\0';
+               ++fields[fieldcnt];
+       }
+       rgb = 0;
+       for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) {
+           if (fieldcnt == 0 && isalpha(*(fields[0]))) {
+                   color_number = match_color_name(fields[0]);
+                   if (color_number == -1) return 0;
+           } else {
+               int dcount = 0, cval = 0;
+               cp = fields[fieldcnt];
+               if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
+                   const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
+
+                   cp++;
+                   if (*cp == 'x' || *cp == 'X')
+                       for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
+                               cval = (int)((cval * 16) + (dp - hex) / 2);
+                   else if (*cp == 'o' || *cp == 'O')
+                       for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++)
+                               cval = (cval * 8) + (*cp - '0');
+                   else
+                       return 0;
+               } else {
+                   for (; *cp && (index("0123456789",*cp)) && (dcount++ < 3); cp++)
+                               cval = (cval * 10) + (*cp - '0');
+               }
+               switch(fieldcnt) {
+                   case 0:
+                               color_number = cval;
+                               break;
+                   case 1:
+                               red = cval;
+                               break;
+                   case 2:
+                               green = cval;
+                               break;
+                   case 3:
+                               blue = cval;
+                               break;
+               }
+           }
+       }
+       rgb = RGB(red,green,blue);
+       if (color_number >= 0 && color_number < CLR_MAX)
+               change_color(color_number, rgb, 0);
+       return 1;
+}
+
+/* 
+ *  This uses an undocumented method to set console attributes
+ *  at runtime including console palette
+ * 
+ *     VOID WINAPI SetConsolePalette(COLORREF palette[16])
+ * 
+ *  Author: James Brown at www.catch22.net
+ * 
+ *  Set palette of current console.
+ *  Palette should be of the form:
+ *
+ *     COLORREF DefaultColors[CLR_MAX] = 
+ *     {
+ *             0x00000000, 0x00800000, 0x00008000, 0x00808000,
+ *             0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0, 
+ *             0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
+ *             0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
+ *      };
+ */
+
+#pragma pack(push, 1)
+
+/*
+ *     Structure to send console via WM_SETCONSOLEINFO
+ */ 
+typedef struct _CONSOLE_INFO
+{
+       ULONG           Length;
+       COORD           ScreenBufferSize;
+       COORD           WindowSize;
+       ULONG           WindowPosX;
+       ULONG           WindowPosY;
+
+       COORD           FontSize;
+       ULONG           FontFamily;
+       ULONG           FontWeight;
+       WCHAR           FaceName[32];
+
+       ULONG           CursorSize;
+       ULONG           FullScreen;
+       ULONG           QuickEdit;
+       ULONG           AutoPosition;
+       ULONG           InsertMode;
+       
+       USHORT          ScreenColors;
+       USHORT          PopupColors;
+       ULONG           HistoryNoDup;
+       ULONG           HistoryBufferSize;
+       ULONG           NumberOfHistoryBuffers;
+       
+       COLORREF        ColorTable[16];
+
+       ULONG           CodePage;
+       HWND            Hwnd;
+
+       WCHAR           ConsoleTitle[0x100];
+} CONSOLE_INFO;
+
+#pragma pack(pop)
+
+BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
+static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
+VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
+
+void
+adjust_palette(VOID_ARGS)
+{ 
+    SetConsolePalette(UserDefinedColors); 
+    altered_palette = 0;
+}
+
+/*
+/* only in Win2k+  (use FindWindow for NT4) */
+HWND WINAPI GetConsoleWindow();
+
+/*  Undocumented console message */
+#define WM_SETCONSOLEINFO                      (WM_USER+201)
+
+
+VOID WINAPI SetConsolePalette(COLORREF palette[16])
+{
+       CONSOLE_INFO ci = { sizeof(ci) };
+       int i;
+        HWND hwndConsole = GetConsoleWindow();
+
+       /* get current size/position settings rather than using defaults.. */
+       GetConsoleSizeInfo(&ci);
+
+       /* set these to zero to keep current settings */
+       ci.FontSize.X                           = 0; /* def = 8  */
+       ci.FontSize.Y                           = 0; /* def = 12 */
+       ci.FontFamily                           = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */
+       ci.FontWeight                           = 0; /* 0x400;   */
+       /* lstrcpyW(ci.FaceName, L"Terminal"); */
+       ci.FaceName[0]                          = L'\0';
+
+       ci.CursorSize                           = 25;
+       ci.FullScreen                           = FALSE;
+       ci.QuickEdit                            = TRUE;
+       ci.AutoPosition                         = 0x10000;
+       ci.InsertMode                           = TRUE;
+       ci.ScreenColors                         = MAKEWORD(0x7, 0x0);
+       ci.PopupColors                          = MAKEWORD(0x5, 0xf);
+       
+       ci.HistoryNoDup                         = FALSE;
+       ci.HistoryBufferSize            = 50;
+       ci.NumberOfHistoryBuffers       = 4;
+
+       // colour table
+       for(i = 0; i < 16; i++)
+               ci.ColorTable[i] = palette[i];
+
+       ci.CodePage     = GetConsoleOutputCP();
+       ci.Hwnd         = hwndConsole;
+
+       lstrcpyW(ci.ConsoleTitle, L"");
+
+       SetConsoleInfo(hwndConsole, &ci);
+}
+
+/*
+ *  Wrapper around WM_SETCONSOLEINFO. We need to create the
+ *  necessary section (file-mapping) object in the context of the
+ *  process which owns the console, before posting the message
+ */
+BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
+{
+       DWORD   dwConsoleOwnerPid;
+       HANDLE  hProcess;
+       HANDLE  hSection, hDupSection;
+       PVOID   ptrView = 0;
+       HANDLE  hThread;
+       
+       /*
+        *      Open the process which "owns" the console
+        */     
+       GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
+       hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
+
+       /*
+        * Create a SECTION object backed by page-file, then map a view of
+        * this section into the owner process so we can write the contents 
+        * of the CONSOLE_INFO buffer into it
+        */
+       hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0, pci->Length, 0);
+
+       /*
+        *      Copy our console structure into the section-object
+        */
+       ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE|FILE_MAP_READ, 0, 0, pci->Length);
+       memcpy(ptrView, pci, pci->Length);
+       UnmapViewOfFile(ptrView);
+
+       /*
+        *      Map the memory into owner process
+        */
+       DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection,
+                       0, FALSE, DUPLICATE_SAME_ACCESS);
+
+       /*  Send console window the "update" message */
+       SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM)hDupSection, 0);
+
+       /*
+        * clean up
+        */
+       hThread = CreateRemoteThread(hProcess, 0, 0, (LPTHREAD_START_ROUTINE)CloseHandle,
+                                       hDupSection, 0, 0);
+
+       CloseHandle(hThread);
+       CloseHandle(hSection);
+       CloseHandle(hProcess);
+
+       return TRUE;
+}
+
+/*
+ *  Fill the CONSOLE_INFO structure with information
+ *  about the current console window
+ */
+static void GetConsoleSizeInfo(CONSOLE_INFO *pci)
+{
+       CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+       HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
+
+       GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
+
+       pci->ScreenBufferSize = csbi.dwSize;
+       pci->WindowSize.X     = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+       pci->WindowSize.Y     = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+       pci->WindowPosX       = csbi.srWindow.Left;
+       pci->WindowPosY       = csbi.srWindow.Top;
+}
+# endif /*CHANGE_COLOR*/
 #endif /* WIN32CON */