Skip to content

Commit 5626ac5

Browse files
committed
Keyboard reading modified
Signed-off-by: zesk1999 <zesk1999@users.noreply.github.com>
1 parent 3d51e72 commit 5626ac5

1 file changed

Lines changed: 143 additions & 7 deletions

File tree

cpp_utils/src/cpp/event/StdinEventHandler.cpp

Lines changed: 143 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
// limitations under the License.
1414

1515
#include <thread>
16+
#include <cstdio>
1617

1718
#if defined(_WIN32) || defined(_WIN64)
1819
#define NOMINMAX
@@ -28,6 +29,25 @@
2829
#include <cpp_utils/exception/InitializationException.hpp>
2930
#include <cpp_utils/Log.hpp>
3031

32+
namespace {
33+
#if defined(_WIN32) || defined(_WIN64)
34+
inline bool consume_tilde_if_present()
35+
{
36+
// Windows special keys don’t have a trailing '~'
37+
return true;
38+
}
39+
40+
#else
41+
inline bool consume_tilde_if_present()
42+
{
43+
// POSIX: ESC [ <num> ~ → read and verify '~'
44+
int t = ::getchar();
45+
return t == '~';
46+
}
47+
48+
#endif // if defined(_WIN32) || defined(_WIN64)
49+
} // namespace
50+
3151
namespace eprosima {
3252
namespace utils {
3353
namespace event {
@@ -256,19 +276,19 @@ void StdinEventHandler::stdin_listener_thread_routine_() noexcept
256276
std::string read_str;
257277
size_t cursor_index = 0;
258278
#if defined(_WIN32) || defined(_WIN64)
259-
bool use_getchar = GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_PIPE;
279+
bool use_::getchar = GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_PIPE;
260280
#endif // if defined(_WIN32) || defined(_WIN64)
261281
while (true)
262282
{
263283

264284
#if defined(_WIN32) || defined(_WIN64)
265285
int c;
266286
// Read first character
267-
// Use getchar() for pipes to avoid blocking
287+
// Use ::getchar() for pipes to avoid blocking
268288
// Use _getch() for console input to avoid echoing characters
269-
if (use_getchar)
289+
if (use_::getchar)
270290
{
271-
c = getchar();
291+
c = ::getchar();
272292
}
273293
else
274294
{
@@ -282,11 +302,11 @@ void StdinEventHandler::stdin_listener_thread_routine_() noexcept
282302
case 72: // Arrow up
283303
#else
284304
char c;
285-
c = getchar(); // Read first character
305+
c = ::getchar(); // Read first character
286306
if (c == '\033')
287307
{
288-
getchar(); // Ignore next character '['
289-
switch (getchar())
308+
::getchar(); // Ignore next character '['
309+
switch (::getchar())
290310
{
291311
case 'A':
292312
#endif // if defined(_WIN32) || defined(_WIN64)
@@ -375,6 +395,122 @@ void StdinEventHandler::stdin_listener_thread_routine_() noexcept
375395
break;
376396
}
377397

398+
#if defined(_WIN32) || defined(_WIN64)
399+
case 82: // Insert
400+
#else
401+
case '2': // Insert: ESC [ 2 ~
402+
#endif // if defined(_WIN32) || defined(_WIN64)
403+
{
404+
int c3 = ::getchar(); (void)c3; // swallow trailing '~'
405+
// Minimal behavior: do nothing
406+
break;
407+
}
408+
409+
#if defined(_WIN32) || defined(_WIN64)
410+
case 83: // Supr
411+
#else
412+
case '3': // Supr: ESC [ 3 ~
413+
#endif // if defined(_WIN32) || defined(_WIN64)
414+
{
415+
if (consume_tilde_if_present())
416+
{
417+
// delete-forward (char at cursor), if any
418+
if (cursor_index < read_str.size())
419+
{
420+
update_line(">> ", read_str, cursor_index,
421+
[](std::string& line, size_t& index)
422+
{
423+
if (index < line.size())
424+
{
425+
line.erase(line.begin() + index);
426+
}
427+
});
428+
}
429+
}
430+
// do nothing.
431+
break;
432+
}
433+
434+
#if defined(_WIN32) || defined(_WIN64)
435+
case 73: // Page Up
436+
#else
437+
case '5': // Page Up: ESC [ 5 ~ (history prev)
438+
#endif // if defined(_WIN32) || defined(_WIN64)
439+
{
440+
if (consume_tilde_if_present())
441+
{
442+
std::string prev = history_handler_.get_previous_command();
443+
if (!prev.empty())
444+
{
445+
std::string prompt = ">> ";
446+
int term_width = get_terminal_width();
447+
int lines = compute_lines_needed(prompt, read_str, term_width);
448+
clear_lines(lines);
449+
read_str = prev;
450+
cursor_index = read_str.size();
451+
std::cout << "\033[38;5;82m" << prompt << "\033[0m" << read_str << std::flush;
452+
}
453+
}
454+
break;
455+
}
456+
457+
458+
#if defined(_WIN32) || defined(_WIN64)
459+
case 81: // Page Down
460+
#else
461+
case '6': // Page Down: ESC [ 6 ~ (history next)
462+
#endif // if defined(_WIN32) || defined(_WIN64)
463+
{
464+
if (consume_tilde_if_present())
465+
{
466+
std::string next = history_handler_.get_next_command();
467+
std::string prompt = ">> ";
468+
int term_width = get_terminal_width();
469+
int lines = compute_lines_needed(prompt, read_str, term_width);
470+
clear_lines(lines);
471+
if (!next.empty())
472+
{
473+
read_str = next;
474+
cursor_index = read_str.size();
475+
std::cout << "\033[38;5;82m" << prompt << "\033[0m" << read_str << std::flush;
476+
}
477+
else
478+
{
479+
read_str.clear();
480+
cursor_index = 0;
481+
std::cout << "\033[38;5;82m" << prompt << "\033[0m" << std::flush;
482+
}
483+
}
484+
break;
485+
}
486+
487+
#if defined(_WIN32) || defined(_WIN64)
488+
case 71: // Home
489+
#else
490+
case 'H': // Home: ESC [ H
491+
#endif // if defined(_WIN32) || defined(_WIN64)
492+
{
493+
update_line(">> ", read_str, cursor_index,
494+
[](std::string&, size_t& index)
495+
{
496+
index = 0;
497+
});
498+
break;
499+
}
500+
501+
#if defined(_WIN32) || defined(_WIN64)
502+
case 79: // End
503+
#else
504+
case 'F': // End: ESC [ F
505+
#endif // if defined(_WIN32) || defined(_WIN64)
506+
{
507+
update_line(">> ", read_str, cursor_index,
508+
[](std::string& line, size_t& index)
509+
{
510+
index = line.size();
511+
});
512+
break;
513+
}
378514
}
379515
}
380516
else if (c == '\n' || c == '\r')

0 commit comments

Comments
 (0)