简体   繁体   English

如何在 C# 控制台应用程序中获取光标处的字符?

[英]How can I get the character at the cursor in a C# console application?

I know how to set the cursor to a specific point in the console with SetCursorPosition or CursorLeft and CursorTop together.我知道如何使用SetCursorPositionCursorLeftCursorTop将光标设置到控制台中的特定点。 That's not a problem.那不是问题。

But , how can I get the value of that point?但是,我怎样才能得到那个点的价值呢? Isn't there a thing like Console.Cursor ?没有像Console.Cursor这样的东西吗? So I can get the character at that position?所以我可以得到那个位置的角色? Maybe something like:也许是这样的:

char c = Console.GetCharAtCursor();

No luck?没运气?

AFAIK, you have to read the entire console buffer as a two dimensional buffer, and use the cursor's X and Y coordinates as an index into that buffer. AFAIK,您必须将整个控制台缓冲区作为二维缓冲区读取,并使用光标的 X 和 Y 坐标作为该缓冲区的索引。 See:看:

[DllImport("kernel32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
public static extern bool GetConsoleScreenBufferInfo(
    IntPtr consoleHandle,
    out CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo);

You can read about the buffer structure here:您可以在此处阅读有关缓冲区结构的信息:

http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx

Update:更新:

If you're interested in using console APIs for game writing, someone wrote space invaders for the console (actually powershell) but all of the APIs are managed code, not script.如果您对使用控制台 API 进行游戏编写感兴趣,有人为控制台编写了空间入侵者(实际上是 powershell),但所有 API 都是托管代码,而不是脚本。 He has sprite/path routines etc - the source is over on http://ps1.soapyfrog.com/2007/08/26/grrr-source-code-including-invaders/他有精灵/路径例程等 - 来源在http://ps1.soapyfrog.com/2007/08/26/grrr-source-code-including-invaders/

According the answer from the MSDN forum :根据MSDN 论坛的回答:

[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GetStdHandle(int nStdHandle);

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadConsoleOutputCharacter(
    IntPtr hConsoleOutput, 
    [Out] StringBuilder lpCharacter, 
    uint length, 
    COORD bufferCoord, 
    out uint lpNumberOfCharactersRead);

[StructLayout(LayoutKind.Sequential)]
public struct COORD
{
    public short X;
    public short Y;
}

public static char ReadCharacterAt(int x, int y)
{
    IntPtr consoleHandle = GetStdHandle(-11);
    if (consoleHandle == IntPtr.Zero)
    {
        return '\0';
    }
    COORD position = new COORD
    {
        X = (short)x,
        Y = (short)y
    };
    StringBuilder result = new StringBuilder(1);
    uint read = 0;
    if (ReadConsoleOutputCharacter(consoleHandle, result, 1, position, out read))
    {
        return result[0];
    }
    else
    {
        return '\0';
    }
}

Applied it looks like this:应用它看起来像这样:

class Program
{
    static void Main(string[] args)
    {
        Console.Clear();

        Console.CursorLeft = 0;
        Console.CursorTop = 1;
        Console.Write("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");

        char first = ReadCharacterAt(10, 1);
        char second = ReadCharacterAt(20, 1);

        Console.ReadLine();
    }
}

I did not like the long answers posted here for my simple application, so I figured a workaround for this – I stored the entire console buffer in a 2D array and then just indexed in the array.我不喜欢这里为我的简单应用程序发布的长答案,所以我想了一个解决方法 - 我将整个控制台缓冲区存储在一个二维数组中,然后在数组中建立索引。 Worked for my application (generating icicles in console):为我的应用程序工作(在控制台中生成冰柱):

            char[,] array = new char[20, Console.BufferWidth];

            for (int i = 0; i < array.GetLength(0); i++)
            {
                for (int j = 0; j < array.GetLength(1); j++)
                {
                    if (i > 0 && array[i - 1, j] == ' ')
                    {
                        array[i, j] = ' ';
                        Console.Write(' ');
                    }
                    else
                    {
                        int x = getRandom.Next(10);

                        switch (x)
                        {
                            case 0:
                                array[i, j] = ' ';
                                Console.Write(array[i, j]);
                                break;

                            default:
                                array[i, j] = 'x';
                                Console.Write(array[i, j]);
                                break;
                        }
                    }
                }

                Console.WriteLine();
            }

'CursorLeft' 和 'CursorTop' 有 getter,所以你可以直接阅读它们: var cleft = Console.CursorLeft

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM