📄 consolecontrol.cs
字号:
using System;
using System.ComponentModel;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Windows.Forms;
namespace ICSharpCode.ConsolePad
{
public class ConsoleControl : UserControl
{
#region Declarations
private IntPtr hStdOut;
private IntPtr hWndConsole;
private Font font;
private Process cmdProcess;
private Timer drawingTimer;
private VScrollBar scrollbar;
private ConsoleCursor cursor;
private TextSelection textSelection;
private Rectangle rectSelection;
private Point coordSelOrigin = Point.Empty;
private Point mouseCursorOffset = Point.Empty;
private Color selectionColor = Color.FromArgb(120, 228, 230, 238);
private int rows = 50;
private int cols = 50;
private int bufferRows = 70;
private int rowOffset = 0;
private int charHeight = 13;
private int charWidth = 8;
private Win32Interop.CHAR_INFO[] pScreenBuffer;
private Win32Interop.COORD maxSize;
private Color[] consoleColors;
private static Win32Interop.HandlerRoutine ctrlHandlerDelegate = new Win32Interop.HandlerRoutine(ctrlHandler);
#endregion
#region Startup
public ConsoleControl()
{
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.Selectable, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.UserPaint, true);
TabStop = true;
scrollbar = new VScrollBar();
scrollbar.Minimum = 0;
scrollbar.Maximum = bufferRows - rows - 6;
scrollbar.Dock = DockStyle.Right;
scrollbar.Scroll += new ScrollEventHandler(vScrolled);
Controls.Add(scrollbar);
textSelection = TextSelection.None;
font = new Font(FontFamily.GenericMonospace, 8, FontStyle.Regular);
cursor = new ConsoleCursor();
#region Colors
consoleColors = new Color[16];
consoleColors[0] = ColorTranslator.FromWin32(0x000000);
consoleColors[1] = ColorTranslator.FromWin32(0x800000);
consoleColors[2] = ColorTranslator.FromWin32(0x008000);
consoleColors[3] = ColorTranslator.FromWin32(0x808000);
consoleColors[4] = ColorTranslator.FromWin32(0x000080);
consoleColors[5] = ColorTranslator.FromWin32(0x800080);
consoleColors[6] = ColorTranslator.FromWin32(0x008080);
consoleColors[7] = ColorTranslator.FromWin32(0xC0C0C0);
consoleColors[8] = ColorTranslator.FromWin32(0x808080);
consoleColors[9] = ColorTranslator.FromWin32(0xFF0000);
consoleColors[10] = ColorTranslator.FromWin32(0x00FF00);
consoleColors[11] = ColorTranslator.FromWin32(0xFFFF00);
consoleColors[12] = ColorTranslator.FromWin32(0x0000FF);
consoleColors[13] = ColorTranslator.FromWin32(0xFF00FF);
consoleColors[14] = ColorTranslator.FromWin32(0x00FFFF);
consoleColors[15] = ColorTranslator.FromWin32(0xFFFFFF);
#endregion
if(startShellProcess())
{
drawingTimer = new Timer();
drawingTimer.Interval = 1000;
drawingTimer.Tick += new EventHandler(drawingTimerTick);
drawingTimer.Enabled = true;
}
}
protected override void Dispose(bool dispose)
{
drawingTimer.Enabled = false;
drawingTimer.Dispose();
font.Dispose();
cursor.Dispose();
Win32Interop.CloseHandle(hStdOut);
cmdProcess.Kill();
Win32Interop.FreeConsole();
base.Dispose(dispose);
}
protected override void OnResize(EventArgs e)
{
resizeConsoleWindow();
base.OnResize(e);
}
private bool startShellProcess()
{
string title = Guid.NewGuid().ToString();
string command = Environment.GetEnvironmentVariable("COMSPEC");
Win32Interop.AllocConsole();
hWndConsole = Win32Interop.GetConsoleWindow();
Win32Interop.SetConsoleTitle(title);
hStdOut = Win32Interop.GetStdHandle(Win32Interop.STD_OUTPUT_HANDLE);
maxSize = Win32Interop.GetLargestConsoleWindowSize(hStdOut);
Win32Interop.SetConsoleCtrlHandler(ctrlHandlerDelegate, true );
resizeConsoleWindow();
hideConsole();
Win32Interop.STARTUPINFO si = new Win32Interop.STARTUPINFO();
si.cb = System.Runtime.InteropServices.Marshal.SizeOf(si);
Win32Interop.PROCESS_INFORMATION pi = new Win32Interop.PROCESS_INFORMATION();
bool result = Win32Interop.CreateProcess(command, null, IntPtr.Zero, IntPtr.Zero, true, Win32Interop.NORMAL_PRIORITY_CLASS, IntPtr.Zero, null, ref si, ref pi);
cmdProcess = Process.GetProcessById(pi.dwProcessId);
return true;
}
void hideConsole()
{
Win32Interop.ShowWindowAsync(hWndConsole, Win32Interop.SW_HIDE);
}
#endregion
#region Output routines
public void ChangeDirectory(string directory)
{
Output("cd \"" + directory + "\"", false, true);
}
public void Output(string text, bool showText, bool execute)
{
Win32Interop.COORD pos = new Win32Interop.COORD();
if(showText && execute) {
throw new ArgumentException("Only showText or execute allowed");
}
if(! showText) {
pos = rememberPosition();
}
foreach(char c in text)
{
outputChar(c);
}
if(execute) {
outputChar('\r');
}
if( !showText ) {
restorePosition( pos, true );
}
}
private void outputChar(char c)
{
IntPtr hIn = Win32Interop.GetStdHandle(Win32Interop.STD_INPUT_HANDLE);
int cnt;
Win32Interop.KEY_INPUT_RECORD r = new Win32Interop.KEY_INPUT_RECORD();
r.bKeyDown = true;
r.wRepeatCount = 1;
r.wVirtualKeyCode = 0;
r.wVirtualScanCode = 0;
r.UnicodeChar = c;
r.dwControlKeyState = 0;
Win32Interop.WriteConsoleInput( hIn ,r, 1, out cnt);//key down event
r.bKeyDown = false;
Win32Interop.WriteConsoleInput( hIn ,r, 1, out cnt);//key up
}
private Win32Interop.COORD rememberPosition()
{
Win32Interop.CONSOLE_SCREEN_BUFFER_INFO csbi = new Win32Interop.CONSOLE_SCREEN_BUFFER_INFO();
Win32Interop.GetConsoleScreenBufferInfo(hStdOut, ref csbi);
return csbi.dwCursorPosition;
}
private void restorePosition(Win32Interop.COORD pos, bool erase)
{
Win32Interop.CONSOLE_SCREEN_BUFFER_INFO csbi = new Win32Interop.CONSOLE_SCREEN_BUFFER_INFO();
Win32Interop.GetConsoleScreenBufferInfo(hStdOut, ref csbi);
Win32Interop.SetConsoleCursorPosition(hStdOut, pos);
if(erase)
{
int written;
int num = (csbi.dwSize.x) * (csbi.dwCursorPosition.y - pos.y) + pos.x - csbi.dwCursorPosition.x;
Win32Interop.WriteConsole(hStdOut, new String(' ',num), num, out written, IntPtr.Zero);
Win32Interop.SetConsoleCursorPosition(hStdOut, pos);
}
}
#endregion
#region Input handling
static bool ctrlHandler(Win32Interop.CtrlTypes eventId)
{
if(eventId == Win32Interop.CtrlTypes.CTRL_C_EVENT) {
return true;
}
return false;
}
protected override bool IsInputKey(Keys key)
{
switch(key)
{
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Left:
return true;
}
return base.IsInputKey(key);
}
protected override void WndProc(ref Message msg)
{
switch(msg.Msg) {
case Win32Interop.WM_KEYDOWN:
case Win32Interop.WM_KEYUP:
Win32Interop.PostMessage(hWndConsole, (uint)msg.Msg, msg.WParam, msg.LParam);
Invalidate();
return;
case Win32Interop.WM_SYSKEYDOWN:
case Win32Interop.WM_SYSKEYUP:
Win32Interop.TranslateMessage(ref msg);
Win32Interop.PostMessage(hWndConsole, (uint)msg.Msg, msg.WParam, msg.LParam);
Invalidate();
return;
}
base.WndProc(ref msg);
}
#endregion
#region Window handling and painting
void resizeConsoleWindow()
{
Win32Interop.CONSOLE_SCREEN_BUFFER_INFO csbi = new Win32Interop.CONSOLE_SCREEN_BUFFER_INFO();
Win32Interop.GetConsoleScreenBufferInfo(hStdOut, ref csbi);
cols = Math.Min((this.Width - scrollbar.Width) / charWidth, maxSize.x);
rows = Math.Min(this.Height / charHeight, maxSize.y);
cols = Math.Max(cols, 1);
rows = Math.Max(rows, 1);
Win32Interop.COORD coordConsoleSize;
coordConsoleSize.x = (short)cols;
coordConsoleSize.y = (short)bufferRows;
Win32Interop.SMALL_RECT srConsoleRect;
srConsoleRect.Top = 0;
srConsoleRect.Left = 0;
srConsoleRect.Right = (short)(cols - 1);
srConsoleRect.Bottom = (short)(rows - 1);
if(csbi.dwSize.x * csbi.dwSize.y >= cols * bufferRows)
{
if (csbi.dwSize.y > bufferRows)
{
coordConsoleSize.y = (short)csbi.dwSize.y;
bufferRows = (short)csbi.dwSize.y;
scrollbar.Maximum = bufferRows - rows - 6;
}
Win32Interop.SetConsoleWindowInfo(hStdOut, true, ref srConsoleRect);
Win32Interop.SetConsoleScreenBufferSize(hStdOut, coordConsoleSize);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -