1111 * Vix.cpp
1212 *
1313 */
14+ #if defined(_WIN32)
15+ #include < vix/platform/windows.hpp>
16+ #endif
17+
1418#include < vix/cli/commands/NewCommand.hpp>
1519#include < vix/cli/Style.hpp>
1620#include < vix/cli/Utils.hpp>
21+ #include < vix/utils/Env.hpp>
1722
1823#include < algorithm>
1924#include < atomic>
@@ -178,13 +183,13 @@ int main()
178183
179184 static bool is_noninteractive_env ()
180185 {
181- if (const char *v = std::getenv (" VIX_NONINTERACTIVE" ))
186+ if (const char *v = vix::utils::vix_getenv (" VIX_NONINTERACTIVE" ))
182187 {
183188 const std::string s = v;
184189 if (!s.empty () && s != " 0" && s != " false" && s != " FALSE" )
185190 return true ;
186191 }
187- if (std::getenv (" CI" ) != nullptr )
192+ if (vix::utils::vix_getenv (" CI" ) != nullptr )
188193 return true ;
189194
190195 return false ;
@@ -410,8 +415,82 @@ int main()
410415 static Key read_key ()
411416 {
412417#if defined(_WIN32)
413- // ... (ton code Windows inchangé)
418+ // -------- Windows (Console Input) --------
419+ HANDLE hIn = ::GetStdHandle (STD_INPUT_HANDLE);
420+ if (hIn == INVALID_HANDLE_VALUE || hIn == nullptr )
421+ return Key::None;
422+
423+ while (true )
424+ {
425+ if (g_cancelled.load ())
426+ return Key::CtrlC;
427+
428+ DWORD pending = 0 ;
429+ if (!::GetNumberOfConsoleInputEvents (hIn, &pending))
430+ return Key::None;
431+
432+ if (pending == 0 )
433+ {
434+ ::Sleep (50 ); // keep responsive
435+ continue ;
436+ }
437+
438+ INPUT_RECORD rec{};
439+ DWORD readCount = 0 ;
440+ if (!::ReadConsoleInputW (hIn, &rec, 1 , &readCount) || readCount != 1 )
441+ continue ;
442+
443+ if (rec.EventType != KEY_EVENT)
444+ continue ;
445+
446+ const KEY_EVENT_RECORD &k = rec.Event .KeyEvent ;
447+
448+ // only handle key DOWN
449+ if (!k.bKeyDown )
450+ continue ;
451+
452+ // Ctrl+C detection (either control state or ascii 3)
453+ const bool ctrlDown = (k.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0 ;
454+
455+ // Virtual keys first (arrows, enter, escape)
456+ switch (k.wVirtualKeyCode )
457+ {
458+ case VK_UP:
459+ return Key::Up;
460+ case VK_DOWN:
461+ return Key::Down;
462+ case VK_RETURN:
463+ return Key::Enter;
464+ case VK_ESCAPE:
465+ return Key::Escape;
466+ default :
467+ break ;
468+ }
469+
470+ // Character-based mapping
471+ const wchar_t ch = k.uChar .UnicodeChar ;
472+
473+ if (ctrlDown && (ch == L' c' || ch == L' C' ))
474+ return Key::CtrlC;
475+
476+ if (ch == 3 ) // ETX (rare here, but safe)
477+ return Key::CtrlC;
478+
479+ if (ch == L' ' )
480+ return Key::Space;
481+
482+ if (ch == L' a' || ch == L' A' )
483+ return Key::ToggleAll;
484+
485+ if (ch == L' q' || ch == L' Q' )
486+ return Key::Quit;
487+
488+ // unknown key -> ignore
489+ return Key::None;
490+ }
491+ return Key::None;
414492#else
493+ // -------- Unix (poll/read) --------
415494 while (true )
416495 {
417496 if (g_cancelled.load ())
@@ -421,11 +500,9 @@ int main()
421500 pfd.fd = STDIN_FILENO;
422501 pfd.events = POLLIN;
423502
424- // timeout 50ms to stay responsive to Ctrl+C
425503 const int r = ::poll (&pfd, 1 , 50 );
426504 if (r < 0 )
427505 {
428- // EINTR: interrupted by signal -> treat as cancel if SIGINT
429506 if (g_cancelled.load ())
430507 return Key::CtrlC;
431508 continue ;
@@ -456,7 +533,6 @@ int main()
456533 unsigned char s1 = 0 ;
457534 unsigned char s2 = 0 ;
458535
459- // If escape alone -> return Escape quickly (do NOT block)
460536 pollfd p2{};
461537 p2.fd = STDIN_FILENO;
462538 p2.events = POLLIN;
0 commit comments