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));
593 onPasteFromClipboard(hWnd);
596 onDropFile((HDROP)wp);
599 case WM_IME_STARTCOMPOSITION:
600 __set_ime_position(hWnd);
601 return( DefWindowProc(hWnd, msg, wp, lp) );
603 if(wp == IMN_SETOPENSTATUS) {
604 HIMC imc = ImmGetContext(hWnd);
605 gImeOn = ImmGetOpenStatus(imc);
606 ImmReleaseContext(hWnd, imc);
607 InvalidateRect(hWnd, NULL, TRUE);
609 return( DefWindowProc(hWnd, msg, wp, lp) );
612 if(!onSysCommand(hWnd, (DWORD)wp))
613 return( DefWindowProc(hWnd, msg, wp, lp) );
617 /* throw console window */
618 PostMessage(gConWnd, msg, wp, lp);
622 PostMessage(gConWnd, msg, wp, lp);
625 selectionClear(hWnd);
630 if(wp != VK_RETURN) /* alt+enter */
631 PostMessage(gConWnd, msg, wp, lp);
635 if((wp == VK_NEXT || wp == VK_PRIOR ||
636 wp == VK_HOME || wp == VK_END) &&
637 (GetKeyState(VK_SHIFT) & 0x8000)) {
638 if(msg == WM_KEYDOWN) {
639 WPARAM sb = SB_PAGEDOWN;
640 if(wp == VK_PRIOR) sb = SB_PAGEUP;
641 else if(wp == VK_HOME) sb = SB_TOP;
642 else if(wp == VK_END) sb = SB_BOTTOM;
643 PostMessage(gConWnd, WM_VSCROLL, sb, 0);
646 else if(wp == VK_INSERT &&
647 (GetKeyState(VK_SHIFT) & 0x8000)) {
648 if(msg == WM_KEYDOWN)
649 onPasteFromClipboard(hWnd);
652 PostMessage(gConWnd, msg, wp, lp);
656 return( DefWindowProc(hWnd, msg, wp, lp) );
661 /*****************************************************************************/
665 static BOOL create_window(ckOpt& opt)
667 trace("create_window\n");
669 HINSTANCE hInstance = GetModuleHandle(NULL);
670 LPWSTR className = L"CkwWindowClass";
671 const char* conf_title;
674 DWORD style = WS_OVERLAPPEDWINDOW;
675 DWORD exstyle = WS_EX_ACCEPTFILES;
679 if(opt.isTranspColor() ||
680 (0 < opt.getTransp() && opt.getTransp() < 255))
681 exstyle |= WS_EX_LAYERED;
683 if(opt.isScrollRight())
684 exstyle |= WS_EX_RIGHTSCROLLBAR;
686 exstyle |= WS_EX_LEFTSCROLLBAR;
689 exstyle |= WS_EX_TOPMOST;
691 if(opt.isScrollHide() || opt.getSaveLines() < 1)
697 style |= WS_MINIMIZE;
699 conf_title = opt.getTitle();
700 if(!conf_title || !conf_title[0]){
703 title = new wchar_t[ strlen(conf_title)+1 ];
704 ZeroMemory(title, sizeof(wchar_t) * (strlen(conf_title)+1));
705 MultiByteToWideChar(CP_ACP, 0, conf_title, strlen(conf_title), title, sizeof(wchar_t) * (strlen(conf_title)+1));
708 /* calc window size */
709 CONSOLE_SCREEN_BUFFER_INFO csi;
710 GetConsoleScreenBufferInfo(gStdOut, &csi);
712 AdjustWindowRectEx(&gFrame, style, FALSE, exstyle);
714 gFrame.right += GetSystemMetrics(SM_CXVSCROLL);
716 gWinW = width = csi.srWindow.Right - csi.srWindow.Left + 1;
717 gWinH = height = csi.srWindow.Bottom - csi.srWindow.Top + 1;
720 width += gBorderSize * 2;
721 height += gBorderSize * 2;
722 width += gFrame.right - gFrame.left;
723 height += gFrame.bottom - gFrame.top;
727 SystemParametersInfo(SPI_GETWORKAREA,0,(LPVOID)&rc,0);
728 posx = opt.getWinPosX();
729 if(posx < 0) posx = rc.right - (width - posx -1);
730 else posx += rc.left;
731 if(posx < rc.left) posx = rc.left;
732 if(posx > rc.right-5) posx = rc.right -5;
733 posy = opt.getWinPosY();
734 if(posy < 0) posy = rc.bottom - (height - posy -1);
736 if(posy < rc.top) posy = rc.top;
737 if(posy > rc.bottom-5) posy = rc.bottom -5;
740 posx = CW_USEDEFAULT;
741 posy = CW_USEDEFAULT;
745 memset(&wc, 0, sizeof(wc));
746 wc.cbSize = sizeof(wc);
748 wc.lpfnWndProc = WndProc;
751 wc.hInstance = hInstance;
752 wc.hIcon = LoadIcon(hInstance, (LPCTSTR)IDR_ICON);
753 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
754 wc.hbrBackground = CreateSolidBrush(gColorTable[0]);
755 wc.lpszMenuName = NULL;
756 wc.lpszClassName = className;
757 wc.hIconSm = wc.hIcon;
758 if(! RegisterClassEx(&wc))
761 HWND hWnd = CreateWindowEx(exstyle, className, title, style,
762 posx, posy, width, height,
763 NULL, NULL, hInstance, NULL);
771 if(0 < opt.getTransp() && opt.getTransp() < 255)
772 SetLayeredWindowAttributes(hWnd, 0, opt.getTransp(), LWA_ALPHA);
773 else if(opt.isTranspColor())
774 SetLayeredWindowAttributes(hWnd, opt.getTranspColor(), 255, LWA_COLORKEY);
776 ShowWindow(hWnd, SW_SHOW);
781 static BOOL create_child_process(const char* cmd, const char* curdir)
783 trace("create_child_process\n");
787 if(!cmd || !cmd[0]) {
788 buf = new char[32768];
790 if(!GetEnvironmentVariableA("COMSPEC", buf, 32768))
791 strcpy(buf, "cmd.exe");
794 buf = new char[ strlen(cmd)+1 ];
798 PROCESS_INFORMATION pi;
800 memset(&si, 0, sizeof(si));
802 si.dwFlags = STARTF_USESTDHANDLES;
803 si.hStdInput = gStdIn;
804 si.hStdOutput = gStdOut;
805 si.hStdError = gStdErr;
808 if (char *p = strstr((char*)curdir, ":\""))
811 if(! CreateProcessA(NULL, buf, NULL, NULL, TRUE,
812 0, NULL, curdir, &si, &pi)) {
817 CloseHandle(pi.hThread);
818 gChild = pi.hProcess;
823 static BOOL create_font(const char* name, int height)
825 trace("create_font\n");
827 memset(&gFontLog, 0, sizeof(gFontLog));
828 gFontLog.lfHeight = -height;
829 gFontLog.lfWidth = 0;
830 gFontLog.lfEscapement = 0;
831 gFontLog.lfOrientation = 0;
832 gFontLog.lfWeight = FW_NORMAL;
833 gFontLog.lfItalic = 0;
834 gFontLog.lfUnderline = 0;
835 gFontLog.lfStrikeOut = 0;
836 gFontLog.lfCharSet = DEFAULT_CHARSET;
837 gFontLog.lfOutPrecision = OUT_DEFAULT_PRECIS;
838 gFontLog.lfClipPrecision = CLIP_DEFAULT_PRECIS;
839 gFontLog.lfQuality = DEFAULT_QUALITY;
840 gFontLog.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
842 MultiByteToWideChar(CP_ACP,0, name, -1, gFontLog.lfFaceName, LF_FACESIZE);
845 gFont = CreateFontIndirect(&gFontLog);
848 HDC hDC = GetDC(NULL);
849 HGDIOBJ oldfont = SelectObject(hDC, gFont);
851 INT width1[26], width2[26], width = 0;
853 GetTextMetrics(hDC, &met);
854 GetCharWidth32(hDC, 0x41, 0x5A, width1);
855 GetCharWidth32(hDC, 0x61, 0x7A, width2);
856 SelectObject(hDC, oldfont);
857 ReleaseDC(NULL, hDC);
859 for(int i = 0 ; i < 26 ; i++) {
864 gFontW = width; /* met.tmAveCharWidth; */
865 gFontH = met.tmHeight + gLineSpace;
871 static void __hide_alloc_console()
874 * Open Console Window
875 * hack StartupInfo.wShowWindow flag
877 DWORD* pflags = (DWORD*) 0x00020068; /* private memory */
878 WORD* pshow = (WORD*) 0x0002006C;
880 DWORD backup_flags = *pflags;
881 WORD backup_show = *pshow;
887 if(si.dwFlags == backup_flags && si.wShowWindow == backup_show) {
888 *pflags |= STARTF_USESHOWWINDOW;
895 *pflags = backup_flags;
896 *pshow = backup_show;
900 BOOL WINAPI sig_handler(DWORD n)
905 static BOOL create_console(ckOpt& opt)
907 const char* conf_title;
910 conf_title = opt.getTitle();
911 if(!conf_title || !conf_title[0]){
914 title = new wchar_t[ strlen(conf_title)+1 ];
915 ZeroMemory(title, sizeof(wchar_t) * (strlen(conf_title)+1));
916 MultiByteToWideChar(CP_ACP, 0, conf_title, strlen(conf_title), title, sizeof(wchar_t) * (strlen(conf_title)+1));
919 __hide_alloc_console();
921 while((gConWnd = GetConsoleWindow()) == NULL) {
924 //
\82±
\82Ì
\83\8b\81[
\83v
\82ð
\92Ç
\89Á
925 for(int i=0;!IsWindowVisible(gConWnd) && i<100;i++)
929 while(IsWindowVisible(gConWnd)) {
930 ShowWindow(gConWnd, SW_HIDE);
934 ShowWindow(gConWnd, SW_HIDE);
936 SetConsoleTitle(title);
938 SetConsoleCtrlHandler(sig_handler, TRUE);
940 SECURITY_ATTRIBUTES sa;
941 sa.nLength = sizeof(sa);
942 sa.lpSecurityDescriptor = NULL;
943 sa.bInheritHandle = TRUE;
945 gStdIn = CreateFile(L"CONIN$", GENERIC_READ|GENERIC_WRITE,
946 FILE_SHARE_READ|FILE_SHARE_WRITE,
947 &sa, OPEN_EXISTING, 0, NULL);
948 gStdOut = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE,
949 FILE_SHARE_READ|FILE_SHARE_WRITE,
950 &sa, OPEN_EXISTING, 0, NULL);
951 gStdErr = CreateFile(L"CONOUT$", GENERIC_READ|GENERIC_WRITE,
952 FILE_SHARE_READ|FILE_SHARE_WRITE,
953 &sa, OPEN_EXISTING, 0, NULL);
955 if(!gConWnd || !gStdIn || !gStdOut || !gStdErr)
959 hLib = LoadLibraryW( L"KERNEL32.DLL" );
963 #define GetProc( proc ) \
965 proc = (proc##T)GetProcAddress( hLib, #proc ); \
969 GetProc( GetConsoleFontInfo );
970 GetProc( GetNumberOfConsoleFonts );
971 GetProc( SetConsoleFont );
975 CONSOLE_FONT font[MAX_FONTS];
977 fonts = GetNumberOfConsoleFonts();
978 if (fonts > MAX_FONTS)
981 GetConsoleFontInfo(gStdOut, 0, fonts, font);
982 CONSOLE_FONT minimalFont = { 0, {0, 0}};
983 for(DWORD i=0;i<fonts;i++){
984 if(minimalFont.dim.X < font[i].dim.X && minimalFont.dim.Y < font[i].dim.Y)
985 minimalFont = font[i];
987 SetConsoleFont(gStdOut, minimalFont.index);
993 /* set buffer & window size */
995 SMALL_RECT sr = {0,0,0,0};
996 SetConsoleWindowInfo(gStdOut, TRUE, &sr);
997 size.X = opt.getWinCharW();
998 size.Y = opt.getWinCharH() + opt.getSaveLines();
999 SetConsoleScreenBufferSize(gStdOut, size);
1001 sr.Right = opt.getWinCharW()-1;
1002 sr.Top = size.Y - opt.getWinCharH();
1003 sr.Bottom = size.Y-1;
1004 SetConsoleWindowInfo(gStdOut, TRUE, &sr);
1007 SetConsoleCursorPosition(gStdOut, size);
1012 BOOL init_options(ckOpt& opt)
1016 LPWSTR* wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
1017 char** argv = new char*[argc+1];
1019 for(i = 0 ; i < argc ; i++) {
1020 DWORD wlen = (DWORD) wcslen(wargv[i]);
1021 DWORD alen = wlen * 2 + 16;
1022 argv[i] = new char[alen];
1023 alen = WideCharToMultiByte(CP_ACP, 0, wargv[i],wlen, argv[i],alen,NULL,NULL);
1027 opt.loadXdefaults();
1028 bool result = opt.set(argc, argv);
1030 for(i = 0 ; i < argc ; i++)
1034 if(!result) return(FALSE);
1037 for(i = kColor0 ; i <= kColor15 ; i++)
1038 gColorTable[i] = opt.getColor(i);
1039 gColorTable[kColor7] = opt.getColorFg();
1040 gColorTable[kColor0] = opt.getColorBg();
1042 gColorTable[kColorCursorBg] = opt.getColorCursor();
1043 gColorTable[kColorCursorFg] = ~gColorTable[kColorCursorBg] & 0xFFFFFF;
1044 gColorTable[kColorCursorImeBg] = opt.getColorCursorIme();
1045 gColorTable[kColorCursorImeFg] = ~gColorTable[kColorCursorImeBg] & 0xFFFFFF;
1047 gBorderSize = opt.getBorderSize();
1048 gLineSpace = opt.getLineSpace();
1050 if(opt.getBgBmp()) {
1051 gBgBmp = (HBITMAP)LoadImageA(NULL, opt.getBgBmp(),
1052 IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
1054 if(gBgBmp) gBgBrush = CreatePatternBrush(gBgBmp);
1055 if(!gBgBrush) gBgBrush = CreateSolidBrush(gColorTable[0]);
1061 static BOOL initialize()
1065 if(! ime_wrap_init()) {
1066 trace("ime_wrap_init failed\n");
1069 if(! init_options(opt)) {
1072 if(! create_console(opt)) {
1073 trace("create_console failed\n");
1076 if(! create_font(opt.getFont(), opt.getFontSize())) {
1077 trace("create_font failed\n");
1080 if(! create_child_process(opt.getCmd(), opt.getCurDir())) {
1081 trace("create_child_process failed\n");
1084 if(! create_window(opt)) {
1085 trace("create_window failed\n");
1089 wchar_t path[MAX_PATH+1];
1090 GetSystemDirectory(path, MAX_PATH);
1091 SetCurrentDirectory(path);
1095 #define SAFE_CloseHandle(handle) \
1096 if(handle) { CloseHandle(handle); handle = NULL; }
1098 #define SAFE_DeleteObject(handle) \
1099 if(handle) { DeleteObject(handle); handle = NULL; }
1102 static void _terminate()
1117 SAFE_CloseHandle(gStdIn);
1118 SAFE_CloseHandle(gStdOut);
1119 SAFE_CloseHandle(gStdErr);
1120 SAFE_CloseHandle(gChild);
1121 SAFE_DeleteObject(gFont);
1122 SAFE_DeleteObject(gBgBrush);
1123 SAFE_DeleteObject(gBgBmp);
1131 int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR lpCmdLine, int nCmdShow)
1134 char *a = new char[1];
1136 _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF |
1137 _CRTDBG_LEAK_CHECK_DF |
1138 /*_CRTDBG_CHECK_ALWAYS_DF |*/
1139 _CRTDBG_DELAY_FREE_MEM_DF);
1140 _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
1141 _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
1142 _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
1143 _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
1144 _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
1145 _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
1150 while(GetMessage(&msg, NULL, 0,0)) {
1151 TranslateMessage(&msg);
1152 DispatchMessage(&msg);