code cũ anh đang đọc lại :V
cách này hạn chế ở chỗ mình phải tự xử lý ký tự nhập vào, có thể là phím mũi tên hoặc nút HOME/END, backspace, del, v.v… rồi in ra tương ứng. Vì phải tự xóa dòng rồi in ra lại mỗi lần có keyboard input nên hàm timedLineInput
phải hạn chế số lượng ký tự nhập vào để ko có xuống dòng trong console :V
#include <iostream>
#include <iomanip>
#include <string>
#include <chrono>
#include <conio.h>
#include <windows.h>
std::string timedLineInput(std::chrono::milliseconds waitDuration, size_t maxLen = 60, bool showTimer = true,
DWORD sleepDurationPerFrame = 30);
int main() {
std::string s = timedLineInput(std::chrono::seconds(5), 10);
std::cout << s << "\n";
}
std::string timedLineInput(std::chrono::milliseconds waitDuration, size_t maxLen, bool showTimer,
DWORD sleepDurationPerFrame) {
std::string buff;
size_t cursorIndex = 0;
using namespace std::chrono;
const auto deadline = steady_clock::now() + waitDuration;
bool dirty = true;
for (;; Sleep(sleepDurationPerFrame)) {
if (steady_clock::now() >= deadline) { // time's up
if (showTimer) std::cout << "\r" << std::fixed << std::setprecision(2) << std::setw(5) << 0.0;
break;
}
if (showTimer) dirty = true;
if (_kbhit()) {
dirty = true;
int ch = _getch();
if (ch == '\r' || ch == '\n') break; // break at \r or \n
if (ch == '\b') { // backspace
if (!buff.empty()) { // there is character to delete
buff.erase(--cursorIndex, 1);
printf("\b \b"); // delete last character on screen (a hack)
}
} else if (ch == 0xE0) { // DEL, arrow keys, ... emits 2 characters 0xE0
ch = _getch(); // and this character
if (ch == 0x53) { // DEL
if (!buff.empty()) {
if (cursorIndex == buff.size()) {
buff.erase(--cursorIndex);
printf("\b \b");
} else {
buff.erase(cursorIndex, 1);
}
}
} else if (ch == 0x4b) { // left arrow
if (cursorIndex > 0) cursorIndex--;
} else if (ch == 0x4d) { // right arrow
if (cursorIndex < buff.size()) cursorIndex++;
} else if (ch == 0x47) { // Home
cursorIndex = 0;
} else if (ch == 0x4f) { // End
cursorIndex = buff.size();
}
} else if (buff.size() < maxLen) {
buff.insert(cursorIndex++, 1, ch);
}
}
if (dirty) {
std::cout << "\r" << std::string(10 + maxLen, ' ') << '\r'; // clear line
if (showTimer) {
const duration<double> timeLeft = deadline - steady_clock::now();
std::cout << std::fixed << std::setprecision(2) << std::setw(5) << timeLeft.count() << "s ";
}
std::cout << buff;
std::cout << std::string(buff.size() - cursorIndex, '\b');
std::cout << std::flush;
}
dirty = false;
}
std::cout << "\n";
return buff;
}
edit: code cũ cũ nữa ko xài <chrono>
:
#include <conio.h>
#include <windows.h>
#include <string>
#include <iostream>
#include <cstdio>
///////////////////////////////////////////////////////////////////////
/// \brief Input with time limit.
/// Prevent user from inserting more input after time limit has been spent.
/// \param timeLeft Time limit, in milliseconds.
/// \param maxLen Maximum input length (to prevent long input that
/// causes a new line).
/// \return Input string.
///////////////////////////////////////////////////////////////////////
std::string timedLineInput(unsigned int timeLeft, size_t maxLen = 40);
int main()
{
std::string s = timedLineInput(11000);
std::cout << s << "\n";
}
std::string timedLineInput(unsigned int timeLeft, size_t maxLen)
{
std::string buff;
size_t cursorIndex = 0;
DWORD deadline = GetTickCount() + timeLeft;
while (1)
{
DWORD now = GetTickCount();
timeLeft = deadline < now ? 0 : deadline - now;
if (!timeLeft) break;
if (kbhit())
{
int ch = getch();
if (ch == '\r' || ch == '\n') break;
if (ch == '\b') //backspace
{
if (!buff.empty()) //there is character to delete
{
buff.erase(--cursorIndex, 1);
printf("\b \b"); //delete last character on screen (a hack)
}
}
else if (ch == 0xE0) //DEL, arrow keys, ... emits 2 characters 0xE0
{
ch = getch(); //and this character
if (ch == 0x53) //DEL
{
if (!buff.empty())
{
if (cursorIndex == buff.size())
{
buff.erase(--cursorIndex);
printf("\b \b");
}
else
{
buff.erase(cursorIndex, 1);
}
}
}
else if (ch == 0x4b) //left arrow
{
if (cursorIndex > 0) cursorIndex--;
}
else if (ch == 0x4d) //right arrow
{
if (cursorIndex < buff.size()) cursorIndex++;
}
else if (ch == 0x47) //Home
{
cursorIndex = 0;
}
else if (ch == 0x4f) //End
{
cursorIndex = buff.size();
}
}
else if (buff.size() < maxLen)
{
buff.insert(cursorIndex++, 1, ch);
}
}
printf("\r%79s", ""); //clear line
//5 is magic number for time limit < 100s.
//For 100s < time limit < 1000s use 6, or convert to minutes...
printf("\r%5.2fs %s", timeLeft / 1000.0, buff.c_str());
//set cursor position without gotoxy...
printf("\r%5.2fs %s", timeLeft / 1000.0, buff.substr(0, cursorIndex).c_str());
Sleep(64); //decrease this number until there is no blinking on screen
}
printf("\r%5.2fs %s\n", timeLeft / 1000.0, buff.c_str());
return buff;
}
xài <chrono>
đẹp hơn ở chỗ nhập vào seconds
hay milliseconds
gì nó cũng rõ ràng =]