Skip to content

Instantly share code, notes, and snippets.

@nutbread
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nutbread/e24c9a557de3ecba4bcc to your computer and use it in GitHub Desktop.
Save nutbread/e24c9a557de3ecba4bcc to your computer and use it in GitHub Desktop.
Colored command prompt
// g++ -O3 -DNDEBUG -std=c++11 -o ccmd ccmd.cpp
// For usage info: ccmd -?
// Create a shortcut as: "C:\Windows\System32\cmd.exe" /C "path\to\ccmd.exe" [extra args]
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <cstdint>
#include <cassert>
using namespace std;
// Windows API
// If this gives re-declaration errors, simply un-comment the next line
// /*
// https://code.google.com/p/conemu-maximus5/issues/attachmentText?id=982&aid=9820000000&name=colors_test.cpp
typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX {
ULONG cbSize;
COORD dwSize;
COORD dwCursorPosition;
WORD wAttributes;
SMALL_RECT srWindow;
COORD dwMaximumWindowSize;
WORD wPopupAttributes;
BOOL bFullscreenSupported;
COLORREF ColorTable[16];
} CONSOLE_SCREEN_BUFFER_INFOEX, *PCONSOLE_SCREEN_BUFFER_INFOEX;
extern "C" {
BOOL WINAPI
GetConsoleScreenBufferInfoEx(
HANDLE hConsoleOutput,
PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx
);
BOOL WINAPI
SetConsoleScreenBufferInfoEx(
HANDLE hConsoleOutput,
PCONSOLE_SCREEN_BUFFER_INFOEX lpConsoleScreenBufferInfoEx
);
}
// */
// Data structures
struct ThreadData {
bool active;
CONSOLE_SCREEN_BUFFER_INFOEX* consoleInfo;
HANDLE consoleHandle;
int hue;
int saturation;
int value;
double hueSpeed;
int sleepMs;
};
// Extended WaitForSingleObject
bool
waitForSingleObject2(
HANDLE handle
) {
// WaitForSingleObject(handle, INFINITE);
while (true) {
DWORD ret = MsgWaitForMultipleObjects(
1, // nCount
&handle, // pHandles
false, // bWaitAll
INFINITE, // dwMilliseconds
QS_ALLINPUT // dwWakeMask
);
if (ret == WAIT_OBJECT_0) {
return true;
}
if (ret != WAIT_OBJECT_0 + 1) {
return false;
}
// Message pump
MSG msg;
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
// Color conversion
constexpr int HueMax = 256 * 6;
uint32_t
hsvToRgb(
int hue,
int sat,
int val
) {
assert(hue >= 0);
assert(hue < HueMax);
assert(sat >= 0);
assert(sat < 256);
assert(val >= 0);
assert(val < 256);
unsigned char vMin = val - static_cast<unsigned char>((val / 255.0 * sat / 255.0) * 255);
unsigned char vMax = val;
unsigned char vSpan = vMax - vMin;
int rgb[3];
if (hue < 256 * 1) {
rgb[0] = vMax;
rgb[1] = vMin + ((hue - 0) * vSpan) / 255;
rgb[2] = vMin;
}
else if (hue < 256 * 2) {
rgb[0] = vMax - ((hue - 256) * vSpan) / 255;
rgb[1] = vMax;
rgb[2] = vMin;
}
else if (hue < 256 * 3) {
rgb[0] = vMin;
rgb[1] = vMax;
rgb[2] = vMin + ((hue - 256 * 2) * vSpan) / 255;
}
else if (hue < 256 * 4) {
rgb[0] = vMin;
rgb[1] = vMax - ((hue - 256 * 3) * vSpan) / 255;
rgb[2] = vMax;
}
else if (hue < 256 * 5) {
rgb[0] = vMin + ((hue - 256 * 4) * vSpan) / 255;
rgb[1] = vMin;
rgb[2] = vMax;
}
else {
rgb[0] = vMax;
rgb[1] = vMin;
rgb[2] = vMax - ((hue - 256 * 5) * vSpan) / 255;
}
return (rgb[0] | (rgb[1] << 8) | (rgb[2] << 16));
};
// Color managing thread
DWORD WINAPI
threadFunction(
void* data
) {
ThreadData* tData = static_cast<ThreadData*>(data);
CONSOLE_SCREEN_BUFFER_INFOEX* consoleInfo = tData->consoleInfo;
HANDLE consoleHandle = tData->consoleHandle;
double hue = tData->hue;
double hueSpeed = HueMax / tData->hueSpeed;
int saturation = tData->saturation;
int value = tData->value;
int sleepMs = tData->sleepMs;
int color;
while (tData->active) {
// Update only the text color
color = hsvToRgb(static_cast<int>(hue), saturation, value);
consoleInfo->ColorTable[7] = color; // static_cast<int>((rand() / static_cast<double>(RAND_MAX)) * 0xFFFFFF);
SetConsoleScreenBufferInfoEx(consoleHandle, consoleInfo);
// Change hue
hue += hueSpeed * sleepMs / 1000.0;
while (hue > HueMax) hue -= HueMax;
// Sleep
Sleep(sleepMs);
}
return 0;
}
// Signal handlers
void signalHandler(
int signal
) {
}
BOOL WINAPI signalHandlerCtrlC(
DWORD dwCtrlType
) {
return TRUE;
}
double atofWide(
const wchar_t* string
) {
double v = 0.0;
wistringstream wss;
wss.str(string);
wss >> v;
return v;
}
int atoiWide(
const wchar_t* string
) {
int v = 0;
wistringstream wss;
wss.str(string);
wss >> v;
return v;
}
// Main
int main(
int argc,
char** argv
) {
#ifdef UNICODE
// Setup wchar command line
const TCHAR* cmdLine = GetCommandLine();
if (cmdLine == nullptr) return -1;
int wargc = 0;
WCHAR** wargv = CommandLineToArgvW(cmdLine, &wargc);
#endif
if (wargc > 1 && (wcscmp(wargv[1], L"/?") == 0 || wcscmp(wargv[1], L"-?") == 0)) {
cerr << "Usage:\n"
" ccmd [executable] [hue_speed] [sleep_ms] [hue_start] [saturation_start] [value_start]\n\n"
"Ranges:\n"
" hue_speed: (0,inf)\n"
" sleep_ms: (0,inf)\n"
" hue_start: [0,256*6)\n"
" saturation_start: [0,256)\n"
" value_start: [0,256)\n\n"
"Defaults:\n"
" ccmd cmd.exe 10 100 256 128 220\n";
return -1;
}
// Arguments
ThreadData threadData;
threadData.active = true;
threadData.hue = 256;
threadData.saturation = 128;
threadData.value = 220;
threadData.hueSpeed = 10.0; // seconds it takes to do a full hue cycle
threadData.sleepMs = 100;
int argid = 1;
double vd;
int vi;
const wchar_t* commandLine = L"cmd.exe";
if (argid < wargc) commandLine = wargv[argid++];
if (argid < wargc && (vd = atofWide(wargv[argid++])) > 0.0) threadData.hueSpeed = vd;
if (argid < wargc && (vi = atoiWide(wargv[argid++])) > 0) threadData.sleepMs = vi;
if (argid < wargc && (vi = atoiWide(wargv[argid++])) >= 0 && vi < HueMax) threadData.hue = vi;
if (argid < wargc && (vi = atoiWide(wargv[argid++])) >= 0 && vi < 256) threadData.saturation = vi;
if (argid < wargc && (vi = atoiWide(wargv[argid++])) >= 0 && vi < 256) threadData.value = vi;
// Signals
SetConsoleCtrlHandler(&signalHandlerCtrlC, true);
// Get console info
HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFOEX consoleInfo;
CONSOLE_SCREEN_BUFFER_INFOEX consoleInfoNew;
consoleInfo.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);
GetConsoleScreenBufferInfoEx(consoleHandle, &consoleInfo);
++consoleInfo.srWindow.Right;
++consoleInfo.srWindow.Bottom;
memcpy(&consoleInfoNew, &consoleInfo, sizeof(CONSOLE_SCREEN_BUFFER_INFOEX));
CONSOLE_CURSOR_INFO cursorInfo;
GetConsoleCursorInfo(consoleHandle, &cursorInfo);
threadData.consoleInfo = &consoleInfoNew;
threadData.consoleHandle = consoleHandle;
// Setup new process
SECURITY_ATTRIBUTES processAttr;
processAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
processAttr.lpSecurityDescriptor = nullptr;
processAttr.bInheritHandle = TRUE;
SECURITY_ATTRIBUTES threadAttr;
threadAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
threadAttr.lpSecurityDescriptor = nullptr;
threadAttr.bInheritHandle = TRUE;
STARTUPINFOW startupInfo;
ZeroMemory(&startupInfo, sizeof(STARTUPINFOW));
startupInfo.cb = sizeof(STARTUPINFOW);
PROCESS_INFORMATION processInfo;
ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION));
unsigned int commandLineLength = wcslen(commandLine) + 1;
wchar_t* commandLineTemp = new wchar_t[commandLineLength];
memcpy(commandLineTemp, commandLine, commandLineLength * sizeof(wchar_t));
BOOL b = CreateProcessW(
nullptr, // lpApplicationName
commandLineTemp, // lpCommandLine
&processAttr, // lpProcessAttributes
&threadAttr, // lpThreadAttributes
TRUE, // bInheritHandles
0, // dwCreationFlags
nullptr, // lpEnvironment
nullptr, // lpCurrentDirectory
&startupInfo, // lpStartupInfo
&processInfo // lpProcessInformation
);
delete [] commandLineTemp;
// Failure
if (!b) {
return 1;
}
// Spawn thread
SECURITY_ATTRIBUTES threadAttr2;
threadAttr2.nLength = sizeof(SECURITY_ATTRIBUTES);
threadAttr2.lpSecurityDescriptor = nullptr;
threadAttr2.bInheritHandle = FALSE;
// Create thread
HANDLE threadHandle = CreateThread(
&threadAttr2, // lpThreadAttributes,
0, // dwStackSize,
threadFunction, // lpStartAddress,
static_cast<void*>(&threadData), // lpParameter,
0, // dwCreationFlags,
nullptr // lpThreadId
);
// Failure
if (threadHandle == NULL) {
return 1;
}
// Join
waitForSingleObject2(processInfo.hProcess);
// Join thread
threadData.active = false;
waitForSingleObject2(threadHandle);
// Reset colors
SetConsoleScreenBufferInfoEx(consoleHandle, &consoleInfo);
SetConsoleCursorInfo(consoleHandle, &cursorInfo);
// Done
#ifdef UNICODE
LocalFree(wargv);
#endif
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment