Показывать ввод с клавиатуры в режиме реального времени по мере ввода (консольное приложение C #) - PullRequest
1 голос
/ 20 сентября 2019

Я сейчас пытаюсь создать базовую программу, которая отображает вводимые данные по мере их ввода.Пример вывода будет выглядеть примерно так:

Текущие входы: CTRL ALT SV SPACE

(Обратите внимание, что это будут удерживаемые ключи. Если пользователь отпустилКлавиша CTRL, этот ввод исчезнет).Я создал пример кода здесь.Это довольно грубо, но это моя лучшая попытка в этом.Он находится внутри более крупной программы (которую я использую как песочницу), но единственный контекст, который должен быть необходим, это то, что using System; находится вверху программы

    public static void KeypressTest()
    {
        char[] keys = new char[10];
        int x;
        while (1==1)
        {
            for (x = 0; x < 10; x++) //All the loops attempt to fill the array if possible. I figured this was the easiest way to store multiple characters at once
            {
                keys[x] = Convert.ToChar(ConsoleKey.MediaStop); //I don't know how to set it to blank, so I picked a character that isn't likely to be used
            }
            for (x = 0; x < 10; x++)
            {
                if (keys[x] != Convert.ToChar(ConsoleKey.MediaStop)) { x += 1; } //This skips the key if it is not the default (MediaStop). This is temporary and will be altered once I can figure out how to register a key has been lifted
                else { keys[x] = Console.ReadKey().KeyChar; }
            }
            Console.Write("\rCurrent inputs: \n");
            for (x = 0; x < 10; x++)
            { Console.Write(Convert.ToString(keys[x])); }
            Console.WriteLine();
        }
    }

Сам код имеет проблемуожидание всех 10 входов, затем отображение набранных клавиш и игнорирование отпускания клавиш.Похоже, он действует скорее как кейлоггер, чем как цель показа удерживаемых в данный момент клавиш.Пример вывода будет выглядеть следующим образом, если пользователь введет «Привет всем !!!!!»:

Текущие входы:

Привет когда-либо

Текущие входы:

yone !!!!!

Цель будет показывать каждую клавишу в момент удержания и не будет показывать ее после отпускания (но я понятия не имею, как это сделатьоб этом).

Проблема в том, что я довольно новичок в C # и не нашел способа обновлять вводимые данные по мере их ввода (мне известно о Console.ReadKey (), но я неЯ не знаю, как заставить его работать в фоновом режиме. Я знаю, что такое многопоточность, но не знаю, как это сделать, поэтому любые советы будут оценены. Спасибо!

1 Ответ

0 голосов
/ 20 сентября 2019

Я изменил свой ответ, это ближе к тому, что вы хотели.Я нашел реализацию события keydown в этом потоке (внутренний класс NativeKeyboard): Ввод с помощью стрелки C # для консольного приложения

Решение заключается в том, что несколько таймеров потоков проверяют значения или условия совместно.Основной поток программы находится в цикле, пока не будет выполнено условие выхода (нажатие клавиши ESC).Есть таймер подсказки, который печатает кэш значений, обозначающий список нажатых клавиш, в ту же строку после того, как строка очищается с пробелами.Для каждого перечисления ConsoleKey создается таймер и отображается дуэт с ключом таймера.Всякий раз, когда нажимается клавиша, отображенный таймер этой клавиши сможет определить, какая конкретная клавиша нажата, и обновит список значением / строкой клавиши.Когда ключ освобождается, список также обновляется пустым строковым значением для этого ключа.

Мне пришлось добавить перечисление LocalModifiers в качестве кодов клавиш для ALT, CTRL, SHIFT и CAPS LOCK.

Мне пришлось использовать lock (), чтобы все эти таймеры могли работать без проблем с параллелизмом.

Когда я выполнил код, выходные данные были очень близки к тому, что вы описали.Иногда некоторые из нажатых клавиш не отображаются в случае нажатия 7-8 клавиш.

Вот мой код:

 class Program
{
    public static Dictionary<int, String> inputMap = new Dictionary<int, string>();
    public static Dictionary<Timer, ConsoleKey> TimerKeyMap = new Dictionary<Timer, ConsoleKey>();
    public static Dictionary<Timer, LocalModifiers> TimerModifierMap = new Dictionary<Timer, LocalModifiers>();
    public static bool continueLoop = true;
    public static object locker = new object();
    static void Main(string[] args)
    {
        Program program = new Program();
        program.run();
    }
    public enum LocalModifiers :int
    {
        SHIFT = 0x10,
        CTL = 0x11,
        ALT = 0x12,
        CAPS_LOCK = 0x14
    }
    public void run()
    {
        Timer keyPressedPrompter = new Timer();
        keyPressedPrompter.Interval = 60;
        keyPressedPrompter.Elapsed += new ElapsedEventHandler(KeyPressedPrompterEvent);
        keyPressedPrompter.Enabled = true;
        foreach (ConsoleKey key in Enum.GetValues(typeof(ConsoleKey)))
        {
            Timer timer = new Timer();
            TimerKeyMap[timer] = key;
            timer.Interval = 60;
            timer.Elapsed += new ElapsedEventHandler(KeyPressedCheckerEvent);
            timer.Enabled = true;
        }
        foreach (LocalModifiers key in Enum.GetValues(typeof(LocalModifiers)))
        {
            Timer timer = new Timer();
            TimerModifierMap[timer] = key;
            timer.Interval = 60;
            timer.Elapsed += new ElapsedEventHandler(ModifierPressedCheckerEvent);
            timer.Enabled = true;
        }
        Console.WriteLine("Current inputs:");
        while (continueLoop) { }
    }
    public static void ModifierPressedCheckerEvent(object source, EventArgs e)
    {
        lock (locker)
        {
            if (NativeKeyboard.IsKeyDown((int)TimerModifierMap[(Timer)source]))
            {
                //Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString()+ " pressed");
                inputMap[(int)TimerModifierMap[(Timer)source]] = TimerModifierMap[(Timer)source].ToString() + " ";
            }
            else
            {
                // Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString() + " released");
                inputMap[(int)TimerModifierMap[(Timer)source]] = "";

            }
        }
    }
    public static void KeyPressedCheckerEvent(object source, EventArgs e)
    {
        lock (locker)
        {
            if (NativeKeyboard.IsKeyDown((int)TimerKeyMap[(Timer)source]))
            {
                if (TimerKeyMap[(Timer)source] == ConsoleKey.Escape)
                    continueLoop = false;
                //Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString()+ " pressed");
                inputMap[(int)TimerKeyMap[(Timer)source]] = TimerKeyMap[(Timer)source].ToString() + " ";
            }
            else
            {
                // Console.WriteLine(KeyTimerMapReverse[(Timer)source].ToString() + " released");
                inputMap[(int)TimerKeyMap[(Timer)source]] = "";

            }
        }
    }
    public static void KeyPressedPrompterEvent(object source, EventArgs e)
    {
        Console.Write("                                             ");//clear the line - -  can be extended
        Console.Write("\r");

        lock (locker)
        {
            foreach (KeyValuePair<int, String> entry in inputMap)
            {
                // do something with entry.Value or entry.Key
                Console.Write(entry.Value);
            }
        }

    }
}

/// <summary>
/// Provides keyboard access.
/// </summary>
internal static class NativeKeyboard
{
    /// <summary>
    /// A positional bit flag indicating the part of a key state denoting
    /// key pressed.
    /// </summary>
    private const int KeyPressed = 0x8000;

    /// <summary>
    /// Returns a value indicating if a given key is pressed.
    /// </summary>
    /// <param name="key">The key to check.</param>
    /// <returns>
    /// <c>true</c> if the key is pressed, otherwise <c>false</c>.
    /// </returns>
    public static bool IsKeyDown(int key)
    {
        return (GetKeyState((int)key) & KeyPressed) != 0;
    }

    /// <summary>
    /// Gets the key state of a key.
    /// </summary>
    /// <param name="key">Virtuak-key code for key.</param>
    /// <returns>The state of the key.</returns>
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern short GetKeyState(int key);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...