#c #terminal #console-application #cross-platform
#c #терминал #консольное приложение #кроссплатформенный
Вопрос:
Есть ли способ принимать пользовательский ввод во время выполнения для консольных приложений?
У меня есть консольное приложение, которое выводит много информации при запуске, я хочу изменить некоторые параметры приложения во время выполнения, не прерывая его. Мне было интересно, может ли окно cmd быть источником ввода, чтобы пользователь мог вводить определенные предопределенные команды для этого.
Например, если я введу «threshold = 10», это изменит значение параметра.
Я много гуглил, но не смог найти ничего, связанного с моим вопросом.
Лучшие
Редактировать:
Я понимаю, что должен быть другой поток, обрабатывающий команды ввода и отправляющий обратно для их выполнения. Мне было интересно, существуют ли кроссплатформенные библиотеки для этой работы.
Представьте окно чата, пользователь может вводить команды в нижней половине окна, а выходные сообщения приложения находятся в верхней половине. Возможно ли, что это может изменить расположение окна вывода?
Редактировать:
На случай, если кто-то все еще заинтересован в этом, я нашел идеальную библиотеку для этой задачи:
Кроссплатформенная библиотека C 14 только для заголовков для интерактивных интерфейсов командной строки (стиль Cisco) https://github.com/daniele77/cli
Комментарии:
1. ДА. Похоже, вам нужен анализатор и, возможно, другой поток для мониторинга ввода во время обработки.
2. Для какого конкретного языка вы хотите получить ответ? C и C сильно отличаются друг от друга
Ответ №1:
Допустим, у вас есть цикл while, в котором выполняются основные команды. Вы можете приостановить его, обнаружив нажатие клавиши, например GetAsyncKeyState()
, а затем разрешить пользователю вводить некоторые команды в виде текста. Вы можете получить их с помощью std::cin
или scanf()
затем проанализировать их с помощью std::string
функций, таких substr
find
replace
как. Затем вы можете использовать system(string.c_str());
, насколько я помню, эти вызовы необходимо использовать с постоянными символами. Я думаю, это сработает. Или, если вы хотите, чтобы консоль запускалась в автоматическом режиме, вы можете использовать WinExec(string.c_str(),SW_HIDE);
. Это устарело, но все еще творит чудеса. Если вы хотите изменить значение переменной во время выполнения, вы можете отобразить ее внутри std::map
, например, используя некоторые map<string,int>
доступные вам переменные во время выполнения.
std::map<std::string,int> mymap;
mymap["playerhealth"]=20;
while(1)
{
//...
if(...) break;
}
std::string string;
std::cout<<"Enter command: ";
std::cin>>string;
std::string vartobechanged=string.substr(0,string.find("="));
mymap[vartobechanged]=atoi(string.substr(string.find("=") 1,string.length()-string.find("=")-1).c_str());
Надеюсь, это дает представление, удачи
Комментарии:
1. Это неплохая идея — вы могли бы даже использовать
SetWindowsHookEx
для фиксации нажатий клавиш и реагировать таким образом.2. Спасибо, я думаю, вы правы насчет этого, но я искал кроссплатформенные библиотеки для этого, поскольку это в целом должно быть фреймворком.
Ответ №2:
Я предполагаю, что вы находитесь в среде Windows, основанной на используемом вами термине «консоль», поэтому я собираюсь использовать здесь конструкции для потоков, специфичные для Windows.
Используя комментарий пользователя 4581301 в качестве ссылки, это можно было бы сделать, поместив std::getline
цикл в другой поток. Например:
#include <windows.h>
#include <iostream>
#include <string>
std::string somevar = "initial value";
HANDLE hMutex = NULL;
DWORD CALLBACK ReadFromStdIn(LPVOID param){
while (true) {
std::string line;
std::getline(std::cin, line);
WaitForSingleObject(hMutex, INFINITE);
somevar = line;
ReleaseMutex(hMutex);
}
}
int main()
{
hMutex = CreateMutex(NULL, FALSE, NULL);
HANDLE hThread = CreateThread(NULL, 0, ReadFromStdIn, NULL, 0, NULL);
for (int i = 0; i < 1000; i) {
WaitForSingleObject(hMutex, INFINITE);
std::cout << somevar << " " << i << std::endl;
ReleaseMutex(hMutex);
Sleep(1000);
}
// TODO: somehow cancel the readline on stdin
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
WaitForSingleObject(hMutex, INFINITE);
CloseHandle(hMutex);
return 0;
}
Это запутанно? Возможно… Самая большая проблема в том, как изящно завершить этот поток? Может быть, вы могли бы std::getline
как-то прервать? Тогда вы могли бы правильно закрыть поток.
Комментарии:
1. Это хорошая идея, безопасен ли cin, cout ad? В общем случае модуль ведения журнала может обрабатываться сторонними библиотеками, которые мне, возможно, придется немного взломать.