1 /*-----------------------------------------------------------------------------
3 *-----------------------------------------------------------------------------
4 * Copyright (c) 2005 Kazuo Ishii <k-ishii@wb4.so-net.ne.jp>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *---------------------------------------------------------------------------*/
25 /*****************************************************************************/
27 HANDLE gStdIn = NULL; /* console */
28 HANDLE gStdOut = NULL;
29 HANDLE gStdErr = NULL;
32 HANDLE gChild = NULL; /* child process */
34 LOGFONT gFontLog; /* font IME */
35 HFONT gFont; /* font */
36 DWORD gFontW; /* char width */
37 DWORD gFontH; /* char height */
39 DWORD gWinW; /* window columns */
40 DWORD gWinH; /* window rows */
42 RECT gFrame; /* window frame size */
43 HBITMAP gBgBmp = NULL; /* background image */
44 HBRUSH gBgBrush = NULL;/* background brush */
45 DWORD gBorderSize = 0;/* internal border */
46 DWORD gLineSpace = 0; /* line space */
47 BOOL gVScrollHide = FALSE;
49 BOOL gImeOn = FALSE; /* IME-status */
51 /* screen buffer - copy */
52 CONSOLE_SCREEN_BUFFER_INFO* gCSI = NULL;
53 CHAR_INFO* gScreen = NULL;
54 wchar_t* gTitle = NULL;
59 typedef struct _CONSOLE_FONT {
62 } CONSOLE_FONT, *PCONSOLE_FONT;
64 typedef BOOL (WINAPI *GetConsoleFontInfoT)( HANDLE,BOOL,DWORD,PCONSOLE_FONT );
65 typedef DWORD (WINAPI *GetNumberOfConsoleFontsT)( VOID );
66 typedef BOOL (WINAPI *SetConsoleFontT)( HANDLE, DWORD );
68 GetConsoleFontInfoT GetConsoleFontInfo;
69 GetNumberOfConsoleFontsT GetNumberOfConsoleFonts;
70 SetConsoleFontT SetConsoleFont;
75 kColor1, kColor2, kColor3,
76 kColor4, kColor5, kColor6, kColor7,
77 kColor8, kColor9, kColor10, kColor11,
78 kColor12, kColor13, kColor14, kColor15,
86 COLORREF gColorTable[ kColorMax ];
89 /*****************************************************************************/
93 void trace(const char *msg)
102 /*****************************************************************************/
104 BOOL WINAPI ReadConsoleOutput_Unicode(HANDLE con, CHAR_INFO* buffer,
105 COORD size, COORD pos, SMALL_RECT *sr)
107 if(!ReadConsoleOutputA(con, buffer, size, pos, sr))
110 CHAR_INFO* s = buffer;
111 CHAR_INFO* e = buffer + (size.X * size.Y);
112 DWORD codepage = GetConsoleOutputCP();
117 ch[0] = s->Char.AsciiChar;
119 if(s->Attributes & COMMON_LVB_LEADING_BYTE) {
120 if((s+1) < e && ((s+1)->Attributes & COMMON_LVB_TRAILING_BYTE)) {
121 ch[1] = (s+1)->Char.AsciiChar;
122 if(MultiByteToWideChar(codepage, 0, (LPCSTR)ch, 2, &wch, 1)) {
123 s->Char.UnicodeChar = wch;
125 s->Char.UnicodeChar = wch;
132 if(MultiByteToWideChar(codepage, 0, (LPCSTR)ch, 1, &wch, 1)) {
133 s->Char.UnicodeChar = wch;
135 s->Attributes &= ~(COMMON_LVB_LEADING_BYTE | COMMON_LVB_TRAILING_BYTE);
141 /*****************************************************************************/
144 inline void __draw_invert_char_rect(HDC hDC, RECT& rc)
152 BitBlt(hDC, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, NULL,0,0, DSTINVERT);
156 static void __draw_selection(HDC hDC)
159 if(!selectionGetArea(sel))
162 if(gCSI->srWindow.Top <= sel.Top && sel.Top <= gCSI->srWindow.Bottom)
164 else if(gCSI->srWindow.Top <= sel.Bottom && sel.Bottom <= gCSI->srWindow.Bottom)
166 else if(sel.Top < gCSI->srWindow.Top && gCSI->srWindow.Bottom < sel.Bottom)
173 if(sel.Top == sel.Bottom) {
175 rc.left = sel.Left - gCSI->srWindow.Left;
176 rc.right = sel.Right-1 - gCSI->srWindow.Left;
178 rc.bottom = sel.Top - gCSI->srWindow.Top;
179 __draw_invert_char_rect(hDC, rc);
184 if(gCSI->srWindow.Top <= sel.Top && sel.Top <= gCSI->srWindow.Bottom) {
186 rc.left = sel.Left - gCSI->srWindow.Left;
187 rc.right = gCSI->srWindow.Right - gCSI->srWindow.Left;
189 rc.bottom = sel.Top - gCSI->srWindow.Top;
190 __draw_invert_char_rect(hDC, rc);
192 if(sel.Top+1 <= sel.Bottom-1) {
195 rc.right = gCSI->srWindow.Right - gCSI->srWindow.Left;
197 if(gCSI->srWindow.Top <= sel.Top+1)
198 rc.top = sel.Top+1 - gCSI->srWindow.Top;
202 if(gCSI->srWindow.Bottom >= sel.Bottom-1)
203 rc.bottom = sel.Bottom-1 - gCSI->srWindow.Top;
205 rc.bottom = gCSI->srWindow.Bottom - gCSI->srWindow.Top;
206 __draw_invert_char_rect(hDC, rc);
208 if(gCSI->srWindow.Top <= sel.Bottom && sel.Bottom <= gCSI->srWindow.Bottom) {
211 rc.right = sel.Right-1 - gCSI->srWindow.Left;
213 rc.bottom = sel.Bottom - gCSI->srWindow.Top;
214 __draw_invert_char_rect(hDC, rc);
219 static void __draw_screen(HDC hDC)
225 CHAR_INFO* ptr = gScreen;
226 int work_color_fg = -1;
227 int work_color_bg = -1;
228 wchar_t* work_text = new wchar_t[ CSI_WndCols(gCSI) ];
229 wchar_t* work_text_ptr;
230 INT* work_width = new INT[ CSI_WndCols(gCSI) ];
235 for(y = gCSI->srWindow.Top ; y <= gCSI->srWindow.Bottom ; y++) {
238 work_text_ptr = work_text;
239 work_width_ptr = work_width;
240 for(x = gCSI->srWindow.Left ; x <= gCSI->srWindow.Right ; x++) {
242 if(ptr->Attributes & COMMON_LVB_TRAILING_BYTE) {
248 color_fg = ptr->Attributes & 0xF;
249 color_bg = (ptr->Attributes>>4) & 0xF;
251 if(color_fg != work_color_fg ||
252 color_bg != work_color_bg) {
253 if(work_text_ptr > work_text) {
254 ExtTextOut(hDC, work_pntX, pntY, 0, NULL,
256 (UINT)(work_text_ptr - work_text),
259 work_text_ptr = work_text;
260 work_width_ptr = work_width;
262 work_color_fg = color_fg;
263 work_color_bg = color_bg;
264 SetTextColor(hDC, gColorTable[work_color_fg]);
265 SetBkColor( hDC, gColorTable[work_color_bg]);
266 SetBkMode(hDC, (work_color_bg) ? OPAQUE : TRANSPARENT);
269 if(ptr->Attributes & COMMON_LVB_LEADING_BYTE) {
270 *work_text_ptr++ = ptr->Char.UnicodeChar;
271 *work_width_ptr++ = gFontW * 2;
274 *work_text_ptr++ = ptr->Char.UnicodeChar;
275 *work_width_ptr++ = gFontW;
281 if(work_text_ptr > work_text) {
282 ExtTextOut(hDC, work_pntX, pntY, 0, NULL,
284 (UINT)(work_text_ptr - work_text),
292 __draw_selection(hDC);
295 if(gCSI->srWindow.Top <= gCSI->dwCursorPosition.Y &&
296 gCSI->srWindow.Bottom >= gCSI->dwCursorPosition.Y &&
297 gCSI->srWindow.Left <= gCSI->dwCursorPosition.X &&
298 gCSI->srWindow.Right >= gCSI->dwCursorPosition.X) {
299 color_fg = (gImeOn) ? kColorCursorImeFg : kColorCursorFg;
300 color_bg = (gImeOn) ? kColorCursorImeBg : kColorCursorBg;
301 SetTextColor(hDC, gColorTable[ color_fg ]);
302 SetBkColor( hDC, gColorTable[ color_bg ]);
303 SetBkMode(hDC, OPAQUE);
304 pntX = gCSI->dwCursorPosition.X - gCSI->srWindow.Left;
305 pntY = gCSI->dwCursorPosition.Y - gCSI->srWindow.Top;
306 ptr = gScreen + CSI_WndCols(gCSI) * pntY + pntX;
309 *work_width = (ptr->Attributes & COMMON_LVB_LEADING_BYTE) ? gFontW*2 : gFontW;
310 ExtTextOut(hDC, pntX, pntY, 0, NULL,
311 &ptr->Char.UnicodeChar, 1, work_width);
314 delete [] work_width;
319 void onPaint(HWND hWnd)
322 HDC hDC = BeginPaint(hWnd, &ps);
324 GetClientRect(hWnd, &rc);
326 HDC hMemDC = CreateCompatibleDC(hDC);
327 HBITMAP hBmp = CreateCompatibleBitmap(hDC, rc.right-rc.left, rc.bottom-rc.top);
328 HGDIOBJ oldfont = SelectObject(hMemDC, gFont);
329 HGDIOBJ oldbmp = SelectObject(hMemDC, hBmp);
331 FillRect(hMemDC, &rc, gBgBrush);
333 if(gScreen && gCSI) {
334 SetWindowOrgEx(hMemDC, -(int)gBorderSize, -(int)gBorderSize, NULL);
335 __draw_screen(hMemDC);
336 SetWindowOrgEx(hMemDC, 0, 0, NULL);
339 BitBlt(hDC,rc.left,rc.top, rc.right-rc.left, rc.bottom-rc.top, hMemDC,0,0, SRCCOPY);
341 SelectObject(hMemDC, oldfont);
342 SelectObject(hMemDC, oldbmp);
350 static void __set_console_window_size(LONG cols, LONG rows)
352 CONSOLE_SCREEN_BUFFER_INFO csi;
353 GetConsoleScreenBufferInfo(gStdOut, &csi);
358 if(cols == CSI_WndCols(&csi) && rows == CSI_WndRows(&csi))
361 //SMALL_RECT tmp = { 0,0,0,0 };
362 //SetConsoleWindowInfo(gStdOut, TRUE, &tmp);
364 csi.dwSize.X = (SHORT)cols;
365 csi.srWindow.Left = 0;
366 csi.srWindow.Right = (SHORT)(cols -1);
368 if(csi.dwSize.Y < rows || csi.dwSize.Y == CSI_WndRows(&csi))
369 csi.dwSize.Y = (SHORT)rows;
371 csi.srWindow.Bottom += (SHORT)(rows - CSI_WndRows(&csi));
372 if(csi.dwSize.Y <= csi.srWindow.Bottom) {
373 csi.srWindow.Top -= csi.srWindow.Bottom - csi.dwSize.Y +1;
374 csi.srWindow.Bottom = csi.dwSize.Y -1;
377 SetConsoleScreenBufferSize(gStdOut, csi.dwSize);
378 SetConsoleWindowInfo(gStdOut, TRUE, &csi.srWindow);
382 void onSizing(HWND hWnd, DWORD side, LPRECT rc)
385 LONG fw = (gFrame.right - gFrame.left) + (gBorderSize * 2);
386 LONG fh = (gFrame.bottom - gFrame.top) + (gBorderSize * 2);
387 LONG width = rc->right - rc->left;
388 LONG height = rc->bottom - rc->top;
391 width -= width % gFontW;
395 height -= height % gFontH;
398 if(side==WMSZ_LEFT || side==WMSZ_TOPLEFT || side==WMSZ_BOTTOMLEFT)
399 rc->left = rc->right - width;
401 rc->right = rc->left + width;
403 if(side==WMSZ_TOP || side==WMSZ_TOPLEFT || side==WMSZ_TOPRIGHT)
404 rc->top = rc->bottom - height;
406 rc->bottom = rc->top + height;
410 void onWindowPosChange(HWND hWnd, WINDOWPOS* wndpos)
412 trace("onWindowPosChange\n");
413 if(!(wndpos->flags & SWP_NOSIZE) && !IsIconic(hWnd)) {
414 LONG fw = (gFrame.right - gFrame.left) + (gBorderSize * 2);
415 LONG fh = (gFrame.bottom - gFrame.top) + (gBorderSize * 2);
416 LONG width = wndpos->cx;
417 LONG height = wndpos->cy;
418 width = (width - fw) / gFontW;
419 height = (height - fh) / gFontH;
421 __set_console_window_size(width, height);
423 wndpos->cx = width * gFontW + fw;
424 wndpos->cy = height * gFontH + fh;
428 static void __set_ime_position(HWND hWnd)
430 if(!gImeOn || !gCSI) return;
431 HIMC imc = ImmGetContext(hWnd);
432 LONG px = gCSI->dwCursorPosition.X - gCSI->srWindow.Left;
433 LONG py = gCSI->dwCursorPosition.Y - gCSI->srWindow.Top;
435 cf.dwStyle = CFS_POINT;
436 cf.ptCurrentPos.x = px * gFontW + gBorderSize;
437 cf.ptCurrentPos.y = py * gFontH + gBorderSize;
438 ImmSetCompositionWindow(imc, &cf);
439 ImmReleaseContext(hWnd, imc);
443 void onTimer(HWND hWnd)
445 if(WaitForSingleObject(gChild, 0) != WAIT_TIMEOUT) {
446 PostMessage(hWnd, WM_CLOSE, 0,0);
451 if(gStdOut) CloseHandle(gStdOut);
452 gStdOut = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE,
453 FILE_SHARE_READ|FILE_SHARE_WRITE,
454 NULL, OPEN_EXISTING, 0, NULL);
457 static int timer_count = 0;
458 if((++timer_count & 0xF) == 1) {
459 wchar_t *str = new wchar_t[256];
460 GetConsoleTitle(str, 256);
461 if(gTitle && !wcscmp(gTitle, str)) {
467 SetWindowText(hWnd, gTitle);
471 CONSOLE_SCREEN_BUFFER_INFO* csi = new CONSOLE_SCREEN_BUFFER_INFO;
474 GetConsoleScreenBufferInfo(gStdOut, csi);
475 size.X = CSI_WndCols(csi);
476 size.Y = CSI_WndRows(csi);
478 /* copy screen buffer */
479 DWORD nb = size.X * size.Y;
480 CHAR_INFO* buffer = new CHAR_INFO[nb];
481 CHAR_INFO* ptr = buffer;
483 COORD pos = { 0, 0 };
485 /* ReadConsoleOuput - maximum read size 64kByte?? */
486 size.Y = 0x8000 / sizeof(CHAR_INFO) / size.X;
487 sr.Left = csi->srWindow.Left;
488 sr.Right = csi->srWindow.Right;
489 sr.Top = csi->srWindow.Top;
491 sr.Bottom = sr.Top + size.Y -1;
492 if(sr.Bottom > csi->srWindow.Bottom) {
493 sr.Bottom = csi->srWindow.Bottom;
494 size.Y = sr.Bottom - sr.Top +1;
496 ReadConsoleOutput_Unicode(gStdOut, ptr, size, pos, &sr);
497 ptr += size.X * size.Y;
498 sr.Top = sr.Bottom +1;
499 } while(sr.Top <= csi->srWindow.Bottom);
502 if(gScreen && gCSI &&
503 !memcmp(csi, gCSI, sizeof(CONSOLE_SCREEN_BUFFER_INFO)) &&
504 !memcmp(buffer, gScreen, sizeof(CHAR_INFO) * nb)) {
512 if(gScreen) delete [] gScreen;
513 if(gCSI) delete gCSI;
518 InvalidateRect(hWnd, NULL, TRUE);
520 /* set vertical scrollbar status */
523 si.cbSize = sizeof(si);
524 si.fMask = SIF_DISABLENOSCROLL | SIF_POS | SIF_PAGE | SIF_RANGE;
525 si.nPos = gCSI->srWindow.Top;
526 si.nPage = CSI_WndRows(gCSI);
528 si.nMax = gCSI->dwSize.Y-1;
529 SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
533 __set_ime_position(hWnd);
536 int w = CSI_WndCols(gCSI);
537 int h = CSI_WndRows(gCSI);
538 if(gWinW != w || gWinH != h) {
539 w = (w * gFontW) + (gBorderSize * 2) + (gFrame.right - gFrame.left);
540 h = (h * gFontH) + (gBorderSize * 2) + (gFrame.bottom - gFrame.top);
541 SetWindowPos(hWnd, NULL, 0,0,w,h, SWP_NOMOVE|SWP_NOZORDER);
545 /*****************************************************************************/
547 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
552 HIMC imc = ImmGetContext(hWnd);
553 ImmSetCompositionFontW(imc, &gFontLog);
554 ImmReleaseContext(hWnd, imc);
556 SetTimer(hWnd, 0x3571, 10, NULL);
559 KillTimer(hWnd, 0x3571);
561 if(WaitForSingleObject(gChild, 0) == WAIT_TIMEOUT)
562 TerminateProcess(gChild, 0);
575 onSizing(hWnd, (DWORD)wp, (LPRECT)lp);
577 case WM_WINDOWPOSCHANGING:
578 case WM_WINDOWPOSCHANGED:
579 onWindowPosChange(hWnd, (WINDOWPOS*)lp);
580 selectionClear(hWnd);
583 onLBtnDown(hWnd, (short)LOWORD(lp), (short)HIWORD(lp));
586 onLBtnUp(hWnd, (short)LOWORD(lp), (short)HIWORD(lp));
589 onMouseMove(hWnd, (short)LOWORD(lp),(short)HIWORD(lp));
590 // scroll when mouse is outside (craftware)
592 short x = (short)LOWORD(lp);
593 short y = (short)HIWORD(lp);
596 GetClientRect(hWnd, &rc);
599 PostMessage(gConWnd, WM_MOUSEWHEEL, WHEEL_DELTA<<16, y<<16|x );
601 else if(y>=rc.bottom) {
602 PostMessage(gConWnd, WM_MOUSEWHEEL, -WHEEL_DELTA<<16, y<<16|x );
608 onPasteFromClipboard(hWnd);
611 onDropFile((HDROP)wp);
614 case WM_IME_STARTCOMPOSITION:
615 __set_ime_position(hWnd);
616 return( DefWindowProc(hWnd, msg, wp, lp) );
618 if(wp == IMN_SETOPENSTATUS) {
619 HIMC imc = ImmGetContext(hWnd);
620 gImeOn = ImmGetOpenStatus(imc);
621 ImmReleaseContext(hWnd, imc);
622 InvalidateRect(hWnd, NULL, TRUE);
624 return( DefWindowProc(hWnd, msg, wp, lp) );
627 if(!onSysCommand(hWnd, (DWORD)wp))
628 return( DefWindowProc(hWnd, msg, wp, lp) );
632 /* throw console window */
633 PostMessage(gConWnd, msg, wp, lp);
637 PostMessage(gConWnd, msg, wp, lp);
640 selectionClear(hWnd);
645 if(wp != VK_RETURN) /* alt+enter */
646 PostMessage(gConWnd, msg, wp, lp);
650 if((wp == VK_NEXT || wp == VK_PRIOR ||
651 wp == VK_HOME || wp == VK_END) &&
652 (GetKeyState(VK_SHIFT) & 0x8000)) {
653 if(msg == WM_KEYDOWN) {
654 WPARAM sb = SB_PAGEDOWN;
655 if(wp == VK_PRIOR) sb = SB_PAGEUP;
656 else if(wp == VK_HOME) sb = SB_TOP;
657 else if(wp == VK_END) sb = SB_BOTTOM;
658 PostMessage(gConWnd, WM_VSCROLL, sb, 0);
661 else if(wp == VK_INSERT &&
662 (GetKeyState(VK_SHIFT) & 0x8000)) {
663 if(msg == WM_KEYDOWN)
664 onPasteFromClipboard(hWnd);
667 PostMessage(gConWnd, msg, wp, lp);
671 return( DefWindowProc(hWnd, msg, wp, lp) );
676 /*****************************************************************************/
680 static BOOL create_window(ckOpt& opt)
682 trace("create_window\n");
684 HINSTANCE hInstance = GetModuleHandle(NULL);
685 LPWSTR className = L"CkwWindowClass";
686 const char* conf_title;
689 DWORD style = WS_OVERLAPPEDWINDOW;
690 DWORD exstyle = WS_EX_ACCEPTFILES;
694 if(opt.isTranspColor() ||
695 (0 < opt.getTransp() && opt.getTransp() < 255))
696 exstyle |= WS_EX_LAYERED;
698 if(opt.isScrollRight())
699 exstyle |= WS_EX_RIGHTSCROLLBAR;
701 exstyle |= WS_EX_LEFTSCROLLBAR;
704 exstyle |= WS_EX_TOPMOST;
706 if(opt.isScrollHide() || opt.getSaveLines() < 1)
712 style |= WS_MINIMIZE;
714 conf_title = opt.getTitle();
715 if(!conf_title || !conf_title[0]){
718 title = new wchar_t[ strlen(conf_title)+1 ];
719 ZeroMemory(title, sizeof(wchar_t) * (strlen(conf_title)+1));
720 MultiByteToWideChar(CP_ACP, 0, conf_title, (int)strlen(conf_title), title, (int)(sizeof(wchar_t) * (strlen(conf_title)+1)) );
723 /* calc window size */
724 CONSOLE_SCREEN_BUFFER_INFO csi;
725 GetConsoleScreenBufferInfo(gStdOut, &csi);
727 AdjustWindowRectEx(&gFrame, style, FALSE, exstyle);
729 gFrame.right += GetSystemMetrics(SM_CXVSCROLL);
731 gWinW = width = csi.srWindow.Right - csi.srWindow.Left + 1;
732 gWinH = height = csi.srWindow.Bottom - csi.srWindow.Top + 1;
735 width += gBorderSize * 2;
736 height += gBorderSize * 2;
737 width += gFrame.right - gFrame.left;
738 height += gFrame.bottom - gFrame.top;
742 SystemParametersInfo(SPI_GETWORKAREA,0,(LPVOID)&rc,0);
743 posx = opt.getWinPosX();
744 if(posx < 0) posx = rc.right - (width - posx -1);
745 else posx += rc.left;
746 if(posx < rc.left) posx = rc.left;
747 if(posx > rc.right-5) posx = rc.right -5;
748 posy = opt.getWinPosY();
749 if(posy < 0) posy = rc.bottom - (height - posy -1);
751 if(posy < rc.top) posy = rc.top;
752 if(posy > rc.bottom-5) posy = rc.bottom -5;
755 posx = CW_USEDEFAULT;
756 posy = CW_USEDEFAULT;
760 memset(&wc, 0, sizeof(wc));
761 wc.cbSize = sizeof(wc);
763 wc.lpfnWndProc = WndProc;
766 wc.hInstance = hInstance;
767 wc.hIcon = LoadIcon(hInstance, (LPCTSTR)IDR_ICON);
768 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
769 wc.hbrBackground = CreateSolidBrush(gColorTable[0]);
770 wc.lpszMenuName = NULL;
771 wc.lpszClassName = className;
773 if(! RegisterClassEx(&wc))
776 HWND hWnd = CreateWindowEx(exstyle, className, title, style,
777 posx, posy, width, height,
778 NULL, NULL, hInstance, NULL);
786 if(0 < opt.getTransp() && opt.getTransp() < 255)
787 SetLayeredWindowAttributes(hWnd, 0, opt.getTransp(), LWA_ALPHA);
788 else if(opt.isTranspColor())
789 SetLayeredWindowAttributes(hWnd, opt.getTranspColor(), 255, LWA_COLORKEY);
791 ShowWindow(hWnd, SW_SHOW);
796 static BOOL create_child_process(const char* cmd, const char* curdir)
798 trace("create_child_process\n");
802 if(!cmd || !cmd[0]) {
803 buf = new char[32768];
805 if(!GetEnvironmentVariableA("COMSPEC", buf, 32768))
806 strcpy(buf, "cmd.exe");
809 buf = new char[ strlen(cmd)+1 ];
813 PROCESS_INFORMATION pi;
815 memset(&si, 0, sizeof(si));
817 si.dwFlags = STARTF_USESTDHANDLES;
818 si.hStdInput = gStdIn;
819 si.hStdOutput = gStdOut;
820 si.hStdError = gStdErr;
823 if (char *p = strstr((char*)curdir, ":\""))
826 if(! CreateProcessA(NULL, buf, NULL, NULL, TRUE,
827 0, NULL, curdir, &si, &pi)) {
832 CloseHandle(pi.hThread);
833 gChild = pi.hProcess;
838 static BOOL create_font(const char* name, int height)
840 trace("create_font\n");
842 memset(&gFontLog, 0, sizeof(gFontLog));
843 gFontLog.lfHeight = -height;
844 gFontLog.lfWidth = 0;
845 gFontLog.lfEscapement = 0;
846 gFontLog.lfOrientation = 0;
847 gFontLog.lfWeight = FW_NORMAL;
848 gFontLog.lfItalic = 0;
849 gFontLog.lfUnderline = 0;
850 gFontLog.lfStrikeOut = 0;
851 gFontLog.lfCharSet = DEFAULT_CHARSET;
852 gFontLog.lfOutPrecision = OUT_DEFAULT_PRECIS;
853 gFontLog.lfClipPrecision = CLIP_DEFAULT_PRECIS;
854 gFontLog.lfQuality = DEFAULT_QUALITY;
855 gFontLog.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
857 MultiByteToWideChar(CP_ACP,0, name, -1, gFontLog.lfFaceName, LF_FACESIZE);
860 gFont = CreateFontIndirect(&gFontLog);
863 HDC hDC = GetDC(NULL);
864 HGDIOBJ oldfont = SelectObject(hDC, gFont);
866 INT width1[26], width2[26], width = 0;
868 GetTextMetrics(hDC, &met);
869 GetCharWidth32(hDC, 0x41, 0x5A, width1);
870 GetCharWidth32(hDC, 0x61, 0x7A, width2);
871 SelectObject(hDC, oldfont);
872 ReleaseDC(NULL, hDC);
874 for(int i = 0 ; i < 26 ; i++) {
879 gFontW = width; /* met.tmAveCharWidth; */
880 gFontH = met.tmHeight + gLineSpace;
885 // for Windows SDK v7.0
\83G
\83\89\81[
\82ª
\94
\90¶
\82·
\82é
\8fê
\8d\87\82Í
\83R
\83\81\83\93\83g
\83A
\83E
\83g
\81B
887 #include <winternl.h>
891 static void __hide_alloc_console()
893 bool bResult = false;
896 * Open Console Window
897 * hack StartupInfo.wShowWindow flag
902 INT_PTR peb = *(INT_PTR*)((INT_PTR)NtCurrentTeb() + 0x60);
903 INT_PTR param = *(INT_PTR*) (peb + 0x20);
904 DWORD* pflags = (DWORD*) (param + 0xa4);
905 WORD* pshow = (WORD*) (param + 0xa8);
908 INT_PTR peb = *(INT_PTR*)((INT_PTR)NtCurrentTeb() + 0x30);
909 INT_PTR param = *(INT_PTR*) (peb + 0x10);
911 // for Windows SDK v7.0
912 PPEB peb = *(PPEB*)((INT_PTR)NtCurrentTeb() + 0x30);
913 PRTL_USER_PROCESS_PARAMETERS param = peb->ProcessParameters;
916 DWORD* pflags = (DWORD*)((INT_PTR)param + 0x68);
917 WORD* pshow = (WORD*)((INT_PTR)param + 0x6C);
921 INT_PTR peb = *(INT_PTR*)((INT_PTR)NtCurrentTeb() + 0x30);
922 PRTL_USER_PROCESS_PARAMETERS param = *(PRTL_USER_PROCESS_PARAMETERS*)(peb + 0x10);
923 DWORD* pflags = (DWORD*)&(param->dwFlags);
924 WORD* pshow = (WORD*)&(param->wShowWindow);
927 DWORD backup_flags = *pflags;
928 WORD backup_show = *pshow;
934 if(si.dwFlags == backup_flags && si.wShowWindow == backup_show) {
935 //
\8fÚ
\8d×
\82Í
\95s
\96¾
\82¾
\82ªSTARTF_TITLEISLINKNAME
\82ª
\97§
\82Á
\82Ä
\82¢
\82é
\82Æ
\81A
936 // Console
\91\8b\89B
\82µ
\82É
\8e¸
\94s
\82·
\82é
\82Ì
\82Å
\8f\9c\8b\8e(Win7-64bit)
937 if (*pflags & STARTF_TITLEISLINKNAME) {
938 *pflags &= ~STARTF_TITLEISLINKNAME;
940 *pflags |= STARTF_USESHOWWINDOW;
948 *pflags = backup_flags;
949 *pshow = backup_show;
951 while((gConWnd = GetConsoleWindow()) == NULL) {
956 while (!IsWindowVisible(gConWnd)) {
959 while(IsWindowVisible(gConWnd)) {
960 ShowWindow(gConWnd, SW_HIDE);
967 BOOL WINAPI sig_handler(DWORD n)
972 static BOOL create_console(ckOpt& opt)
974 const char* conf_title;
977 conf_title = opt.getTitle();
978 if(!conf_title || !conf_title[0]){
981 title = new wchar_t[ strlen(conf_title)+1 ];
982 ZeroMemory(title, sizeof(wchar_t) * (strlen(conf_title)+1));
983 MultiByteToWideChar(CP_ACP, 0, conf_title, (int)strlen(conf_title), title, (int)(sizeof(wchar_t) * (strlen(conf_title)+1)) );
986 __hide_alloc_console();
988 SetConsoleTitle(title);
990 SetConsoleCtrlHandler(sig_handler, TRUE);
992 SECURITY_ATTRIBUTES sa;
993 sa.nLength = sizeof(sa);
994 sa.lpSecurityDescriptor = NULL;
995 sa.bInheritHandle = TRUE;
997 gStdIn = CreateFile(L"CONIN$", GENERIC_READ|GENERIC_WRITE,
998 FILE_SHARE_READ|FILE_SHARE_WRITE,
999 &sa, OPEN_EXISTING, 0, NULL);
1000 gStdOut = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE,
1001 FILE_SHARE_READ|FILE_SHARE_WRITE,
1002 &sa, OPEN_EXISTING, 0, NULL);
1003 gStdErr = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE,
1004 FILE_SHARE_READ|FILE_SHARE_WRITE,
1005 &sa, OPEN_EXISTING, 0, NULL);
1007 if(!gConWnd || !gStdIn || !gStdOut || !gStdErr)
1011 hLib = LoadLibraryW( L"KERNEL32.DLL" );
1015 #define GetProc( proc ) \
1017 proc = (proc##T)GetProcAddress( hLib, #proc ); \
1021 GetProc( GetConsoleFontInfo );
1022 GetProc( GetNumberOfConsoleFonts );
1023 GetProc( SetConsoleFont );
1027 CONSOLE_FONT font[MAX_FONTS];
1029 fonts = GetNumberOfConsoleFonts();
1030 if (fonts > MAX_FONTS)
1033 GetConsoleFontInfo(gStdOut, 0, fonts, font);
1034 CONSOLE_FONT minimalFont = { 0, {0, 0}};
1035 for(DWORD i=0;i<fonts;i++){
1036 if(minimalFont.dim.X < font[i].dim.X && minimalFont.dim.Y < font[i].dim.Y)
1037 minimalFont = font[i];
1039 SetConsoleFont(gStdOut, minimalFont.index);
1042 FreeLibrary( hLib );
1045 /* set buffer & window size */
1047 SMALL_RECT sr = {0,0,0,0};
1048 SetConsoleWindowInfo(gStdOut, TRUE, &sr);
1049 size.X = opt.getWinCharW();
1050 size.Y = opt.getWinCharH() + opt.getSaveLines();
1051 SetConsoleScreenBufferSize(gStdOut, size);
1053 sr.Right = opt.getWinCharW()-1;
1054 sr.Top = size.Y - opt.getWinCharH();
1055 sr.Bottom = size.Y-1;
1056 SetConsoleWindowInfo(gStdOut, TRUE, &sr);
1059 SetConsoleCursorPosition(gStdOut, size);
1064 BOOL init_options(ckOpt& opt)
1068 LPWSTR* wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
1069 char** argv = new char*[argc+1];
1071 for(i = 0 ; i < argc ; i++) {
1072 DWORD wlen = (DWORD) wcslen(wargv[i]);
1073 DWORD alen = wlen * 2 + 16;
1074 argv[i] = new char[alen];
1075 alen = WideCharToMultiByte(CP_ACP, 0, wargv[i],wlen, argv[i],alen,NULL,NULL);
1079 opt.loadXdefaults();
1080 bool result = opt.set(argc, argv);
1082 for(i = 0 ; i < argc ; i++)
1086 if(!result) return(FALSE);
1089 for(i = kColor0 ; i <= kColor15 ; i++)
1090 gColorTable[i] = opt.getColor(i);
1091 gColorTable[kColor7] = opt.getColorFg();
1092 gColorTable[kColor0] = opt.getColorBg();
1094 gColorTable[kColorCursorBg] = opt.getColorCursor();
1095 gColorTable[kColorCursorFg] = ~gColorTable[kColorCursorBg] & 0xFFFFFF;
1096 gColorTable[kColorCursorImeBg] = opt.getColorCursorIme();
1097 gColorTable[kColorCursorImeFg] = ~gColorTable[kColorCursorImeBg] & 0xFFFFFF;
1099 gBorderSize = opt.getBorderSize();
1100 gLineSpace = opt.getLineSpace();
1102 if(opt.getBgBmp()) {
1103 gBgBmp = (HBITMAP)LoadImageA(NULL, opt.getBgBmp(),
1104 IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
1106 if(gBgBmp) gBgBrush = CreatePatternBrush(gBgBmp);
1107 if(!gBgBrush) gBgBrush = CreateSolidBrush(gColorTable[0]);
1113 static BOOL initialize()
1117 if(! ime_wrap_init()) {
1118 trace("ime_wrap_init failed\n");
1121 if(! init_options(opt)) {
1124 if(! create_console(opt)) {
1125 trace("create_console failed\n");
1128 if(! create_font(opt.getFont(), opt.getFontSize())) {
1129 trace("create_font failed\n");
1132 if(! create_child_process(opt.getCmd(), opt.getCurDir())) {
1133 trace("create_child_process failed\n");
1136 if(! create_window(opt)) {
1137 trace("create_window failed\n");
1142 wchar_t path[MAX_PATH+1];
1143 GetSystemDirectory(path, MAX_PATH);
1144 SetCurrentDirectory(path);
1149 #define SAFE_CloseHandle(handle) \
1150 if(handle) { CloseHandle(handle); handle = NULL; }
1152 #define SAFE_DeleteObject(handle) \
1153 if(handle) { DeleteObject(handle); handle = NULL; }
1156 static void _terminate()
1171 SAFE_CloseHandle(gStdIn);
1172 SAFE_CloseHandle(gStdOut);
1173 SAFE_CloseHandle(gStdErr);
1174 SAFE_CloseHandle(gChild);
1175 SAFE_DeleteObject(gFont);
1176 SAFE_DeleteObject(gBgBrush);
1177 SAFE_DeleteObject(gBgBmp);
1186 int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR lpCmdLine, int nCmdShow)
1189 char *a = new char[1];
1191 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF |
1192 _CRTDBG_LEAK_CHECK_DF |
1193 /*_CRTDBG_CHECK_ALWAYS_DF |*/
1194 _CRTDBG_DELAY_FREE_MEM_DF);
1195 _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
1196 _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
1197 _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
1198 _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
1199 _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
1200 _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
1205 while(GetMessage(&msg, NULL, 0,0)) {
1206 TranslateMessage(&msg);
1207 DispatchMessage(&msg);
1214 /*
\90V
\8bK
\83E
\83C
\83\93\83h
\83E
\82Ì
\8dì
\90¬ */
1215 void makeNewWindow()
1217 LPWSTR cd = new TCHAR[MAX_PATH+1];
1218 GetCurrentDirectory(MAX_PATH, cd);
1221 ZeroMemory(&si, sizeof(si));
1224 PROCESS_INFORMATION pi;
1225 ZeroMemory(&pi, sizeof(pi));
1226 if(CreateProcess(NULL, GetCommandLine(), NULL, NULL, FALSE, 0,
1227 NULL, NULL, &si, &pi)){
1228 //
\8eg
\97p
\82µ
\82È
\82¢
\82Ì
\82Å
\81C
\82·
\82®
\82É
\83N
\83\8d\81[
\83Y
\82µ
\82Ä
\82æ
\82¢
1229 CloseHandle(pi.hProcess);
1230 CloseHandle(pi.hThread);