定制命令行窗口

定制命令行窗口

 By MikeFeng, QQ 76848502

 
用过FTERM没?用过TELNET没?是不是对上面彩色的文字和命令行式的操作记忆犹新?今天写了基于命令行的程序,因为以前没有用到过类似的API,所以决定写这篇没有含金量的文章,以免以后忘记了还要重头学起。
话说需求是这样的:实现一个类似于windows启动菜单一样的界面,可以上下选择,也可以回车执行操作。首先在MSDN里大海捞针,却一无所获。后来想起.NET Framework中有个System.Console的类,于是再次翻出Reflactor,在mscorlib.dll里找到了相关实现。发现了SetConsole*和GetConsole*的Windows API。最后终于在MSDN的DLLs, Processes, and Threads中找到了相关资料。
 
一个命令行窗口有两种显示模式,一种是全屏,一种是窗口。这个用SetConsoleDisplayMode可以设置。另外,从数据的输入输出方面来说,命令行窗口有一下5中模式:
ENABLE_ECHO_INPUT:可以用ReadFile和ReadConsole函数来获得输入。这个必须和ENABLE_LINE_INPUT一起使用
ENABLE_INSERT_MODE:必须和ENABLE_EXTENDED_FLAGS一起使用,它可以在光标位置插入文本。如果这个标志没有开启,那么光标后面的文本将被覆盖。
ENABLE_LINE_INPUT:仅当回车被侦测到时ReadFile和ReadConsole函数才返回处理结果。如果这个标记没有开启,那么只要有输入数据就会进行处理。
ENABLE_MOUSE_INPUT:输入缓冲接受鼠标事件。就算这个标志被设置,这些事件也不会被ReadFile和ReadConsole处理。
ENABLE_PROCESSED_INPUT:象回删,回车,ctrl+c这样的事件不设置这个标志将不会被ReadFile和ReadConsole捕获。
ENABLE_QUICK_EDIT_MODE:必须和ENABLE_EXTENDED_FLAG一起使用。允许用户用鼠标右键选择和编辑文本。
ENABLE_WINDOW_INPUT:必须和ReadConsoleInput函数配套使用。程序可以获得用户交互的事件,例如上下左右箭头的侦测,以及回车等控制字键,也包括鼠标输入,交点的获得与丢失,以及菜单事件等。使用ReadFile和ReadConsole是获得不到这些信息的。
还有一些扩展的模式,没有仔细研究。
 
另外比较重要的就是对于文字属性的设定了,其中有设定将要写入文字的前景和背景色的函数SetConsoleTextAttribute,也有设定屏幕中指定范围文字的前景色和背景色函数FillConsoleOutputAttribute。还有一些设置窗口标题,大小等的函数,就不说了。
 
下面是C写的程序,仅供参考:
 
#include "stdafx.h"
#include 
<windows.h> 

void Init(void);
void NewLine(void); 
void AddEntry(LPCTSTR);
void ScrollScreenBuffer(HANDLE, INT); 
void SetColor(int);
void Work(int);

HANDLE hStdout, hStdin; 
CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 
WORD wOldColorAttrs;
WORD wColor 
= BACKGROUND_RED | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; 
INT currentLine 
= 0;
INT totalLine 
= 0;
DWORD fdwOldMode;

void main(void

    Init();

    DWORD dwRead;
    COORD coord; 
    INPUT_RECORD chBuffer;

    coord.X 
= 0;                // start at first cell 
    coord.Y = currentLine;      //       of first row 

    BOOL fSuccess 
= FillConsoleOutputAttribute( 
        hStdout,          
// screen buffer handle 
        wColor,           // color to fill with 
        80,            // number of cells to fill 
        coord,            // first cell to write to 
        NULL);       // actual number written 
    
    
while (1
    

        
        
//if (! ReadFile(hStdin, chBuffer, 1, &cRead, NULL)) 
        
//    break; 
        if (! ReadConsoleInput( 
            hStdin,      
// input buffer handle 
            &chBuffer,     // buffer to read into 
            1,         // size of read buffer 
            &dwRead) ) // number of records read 
        continue;

        
switch(chBuffer.EventType) 
        

            
case KEY_EVENT: // keyboard input 
                if ( chBuffer.Event.KeyEvent.bKeyDown )
                
{
                    
// up arrow is pressed
                    if (chBuffer.Event.KeyEvent.wVirtualKeyCode == 38)
                    
{
                        
if (currentLine == 0continue;
                        
else 
                        
{
                            SetColor(
--currentLine);
                        }

                    }

                    
// down arrow is pressed
                    else if (chBuffer.Event.KeyEvent.wVirtualKeyCode == 40)
                    
{
                        
if (currentLine == totalLine-1continue;
                        
else 
                        
{
                            SetColor(
++currentLine);
                        }

                    }

                    
// enter is pressed
                    else if (chBuffer.Event.KeyEvent.wVirtualKeyCode == 13)
                    
{
                        Work(currentLine);
                    }

                    
// press q to exit
                    else if (chBuffer.Event.KeyEvent.uChar.AsciiChar == 'q')
                    
{
                        
return;
                    }

                    
//else if (chBuffer.Event.KeyEvent)
                }

                
                
break

            
//case MOUSE_EVENT: // mouse input 
            
//    printf("%d",KEY_EVENT); 
            
//    //MouseEventProc(chBuffer.Event.MouseEvent); 
            
//    break; 

            
case WINDOW_BUFFER_SIZE_EVENT: // scrn buf. resizing 
                printf("%d",KEY_EVENT); 
                
//ResizeEventProc( 
                    
//irInBuf[i].Event.WindowBufferSizeEvent); 
                break

            
//case FOCUS_EVENT:  // disregard focus events 
            
//    printf("%d",KEY_EVENT); 
            
//    break;

            
//case MENU_EVENT:   // disregard menu events 
            
//    printf("%d",KEY_EVENT);
            
//    break; 

            
default:  
                
break
        }
 

    }
 

    
// Restore the original console mode. 
    SetConsoleMode(hStdin, fdwOldMode);

    
// Restore the original text colors. 
    SetConsoleTextAttribute(hStdout, wOldColorAttrs);

}


void Init()
{
    DWORD fdwMode; 

    
// Get handles to STDIN and STDOUT. 
    hStdin = GetStdHandle(STD_INPUT_HANDLE); 
    hStdout 
= GetStdHandle(STD_OUTPUT_HANDLE); 
    
if (hStdin == INVALID_HANDLE_VALUE || 
        hStdout 
== INVALID_HANDLE_VALUE) 
    
{
        MessageBox(NULL, 
"GetStdHandle""Console Error", MB_OK);
        
return;
    }


    
// Save the current text colors. 

    
if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) 
    
{
        MessageBox(NULL, 
"GetConsoleScreenBufferInfo"
            
"Console Error", MB_OK); 
        
return;
    }


    wOldColorAttrs 
= csbiInfo.wAttributes; 

    
// Turn off the line input mode, and echo the input mode. 

    
if (! GetConsoleMode(hStdin, &fdwOldMode)) 
    
{
        MessageBox(NULL, 
"GetConsoleMode""Console Error", MB_OK); 
        
return;
    }


    fdwMode 
= fdwOldMode && ENABLE_WINDOW_INPUT ;
    
if (! SetConsoleMode(hStdin, fdwMode)) 
    
{
        MessageBox(NULL, 
"SetConsoleMode""Console Error", MB_OK); 
        
return;
    }

    
    AddEntry(TEXT(
"Line 1"));
    AddEntry(TEXT(
"Line 2"));
    AddEntry(TEXT(
"Line 3"));
    AddEntry(TEXT(
"Line 4"));
    AddEntry(TEXT(
"Line 5"));
    AddEntry(TEXT(
"Line 6"));
    AddEntry(TEXT(
"Line 7"));
    AddEntry(TEXT(
"Line 8"));
    AddEntry(TEXT(
"Line 8"));
    printf(
" Press q to exit. ");
}


void AddEntry(LPCTSTR lpszPrompt)
{
    DWORD cWritten;
    
if ( WriteFile( 
        hStdout,              
// output handle 
        lpszPrompt,               // prompt string 
        lstrlen(lpszPrompt),  // string length 
        &cWritten,            // bytes written 
        NULL )) 
    
{
        totalLine
++;
        NewLine();
    }

}


void SetColor(int i)
{
    COORD coord; 

    coord.X 
= 0;            // start at first cell 
    coord.Y = i;            //       of first row 

    BOOL fSuccess 
= FillConsoleOutputAttribute( 
        hStdout,          
// screen buffer handle 
        wColor,           // color to fill with 
        80,            // number of cells to fill 
        coord,            // first cell to write to 
        NULL);       // actual number written 

    
if ( i > 0 )
    
{
        coord.X 
= 0;            // start at first cell 
        coord.Y = i-1;            //       of first row 

        BOOL fSuccess 
= FillConsoleOutputAttribute( 
            hStdout,          
// screen buffer handle 
            wOldColorAttrs,    // color to fill with 
            80,               // number of cells to fill 
            coord,            // first cell to write to 
            NULL);            // actual number written 
    }


    
if ( i < totalLine )
    
{
        coord.X 
= 0;            // start at first cell 
        coord.Y = i+1;            //       of first row 

        BOOL fSuccess 
= FillConsoleOutputAttribute( 
            hStdout,          
// screen buffer handle 
            wOldColorAttrs,    // color to fill with 
            80,               // number of cells to fill 
            coord,            // first cell to write to 
            NULL);            // actual number written 
    }

}


void Work(int workNumber)
{
    
switch(workNumber) 
    
{
    
case 0:
        
break;
    
case 1:
        
break;
    
case 2:
        
break;
    
default:
        
break;
    }

    printf(
"Work %d finished! ", workNumber+1);
}


// The NewLine function handles carriage returns when the processed 
// input mode is disabled. It gets the current cursor position 
// and resets it to the first cell of the next row. 
 
void NewLine(void

    
if (! GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) 
    
{
        MessageBox(NULL, 
"GetConsoleScreenBufferInfo"
            
"Console Error", MB_OK); 
        
return;
    }


    csbiInfo.dwCursorPosition.X 
= 0

    
// If it is the last line in the screen buffer, scroll 
    
// the buffer up. 

    
if ((csbiInfo.dwSize.Y-1== csbiInfo.dwCursorPosition.Y) 
    

        ScrollScreenBuffer(hStdout, 
1); 
    }
 

    
// Otherwise, advance the cursor to the next line. 

    
else csbiInfo.dwCursorPosition.Y += 1
 
    
if (! SetConsoleCursorPosition(hStdout, 
        csbiInfo.dwCursorPosition)) 
    
{
        MessageBox(NULL, 
"SetConsoleCursorPosition""Console Error"
            MB_OK); 
        
return;
    }

}
 

void ScrollScreenBuffer(HANDLE h, INT x)
{
    SMALL_RECT srctScrollRect, srctClipRect;
    CHAR_INFO chiFill;
    COORD coordDest;

    srctScrollRect.Left 
= 0;
    srctScrollRect.Top 
= 1;
    srctScrollRect.Right 
= csbiInfo.dwSize.X - x; 
    srctScrollRect.Bottom 
= csbiInfo.dwSize.Y - x; 
 
    
// The destination for the scroll rectangle is one row up. 
 
    coordDest.X 
= 0
    coordDest.Y 
= 0
 
    
// The clipping rectangle is the same as the scrolling rectangle. 
    
// The destination row is left unchanged. 
 
    srctClipRect 
= srctScrollRect; 
 
    
// Set the fill character and attributes. 
 
    chiFill.Attributes 
= FOREGROUND_RED|FOREGROUND_INTENSITY; 
    chiFill.Char.AsciiChar 
= (char)' '
 
    
// Scroll up one line. 
 
    ScrollConsoleScreenBuffer( 
        h,               
// screen buffer handle 
        &srctScrollRect, // scrolling rectangle 
        &srctClipRect,   // clipping rectangle 
        coordDest,       // top left destination cell 
        &chiFill);       // fill character and color 
}

效果如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值