Files
michaelschiemer/tests/Framework/Console/Helpers/MockKeyboard.php
Michael Schiemer 8f3c15ddbb fix(console): comprehensive TUI rendering fixes
- Fix Enter key detection: handle multiple Enter key formats (\n, \r, \r\n)
- Reduce flickering: lower render frequency from 60 FPS to 30 FPS
- Fix menu bar visibility: re-render menu bar after content to prevent overwriting
- Fix content positioning: explicit line positioning for categories and commands
- Fix line shifting: clear lines before writing, control newlines manually
- Limit visible items: prevent overflow with maxVisibleCategories/Commands
- Improve CPU usage: increase sleep interval when no events processed

This fixes:
- Enter key not working for selection
- Strong flickering of the application
- Menu bar not visible or being overwritten
- Top half of selection list not displayed
- Lines being shifted/misaligned
2025-11-10 11:06:07 +01:00

164 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Framework\Console\Helpers;
/**
* Mock keyboard input for testing interactive menus and TUI components
*/
final class MockKeyboard
{
private array $keySequence = [];
private int $currentIndex = 0;
/**
* ANSI escape sequences for common keys
*/
public const KEY_UP = "\033[A";
public const KEY_DOWN = "\033[B";
public const KEY_RIGHT = "\033[C";
public const KEY_LEFT = "\033[D";
public const KEY_ENTER = "\n";
public const KEY_ESCAPE = "\033";
public const KEY_TAB = "\t";
public const KEY_BACKSPACE = "\x08";
public const KEY_DELETE = "\033[3~";
public const KEY_HOME = "\033[H";
public const KEY_END = "\033[F";
public const KEY_PAGE_UP = "\033[5~";
public const KEY_PAGE_DOWN = "\033[6~";
public function __construct(array $keySequence = [])
{
$this->keySequence = $keySequence;
}
/**
* Add a key press to the sequence
*/
public function pressKey(string $key): self
{
$this->keySequence[] = $key;
return $this;
}
/**
* Add multiple key presses
*/
public function pressKeys(array $keys): self
{
foreach ($keys as $key) {
$this->pressKey($key);
}
return $this;
}
/**
* Add arrow up key
*/
public function arrowUp(): self
{
return $this->pressKey(self::KEY_UP);
}
/**
* Add arrow down key
*/
public function arrowDown(): self
{
return $this->pressKey(self::KEY_DOWN);
}
/**
* Add arrow left key
*/
public function arrowLeft(): self
{
return $this->pressKey(self::KEY_LEFT);
}
/**
* Add arrow right key
*/
public function arrowRight(): self
{
return $this->pressKey(self::KEY_RIGHT);
}
/**
* Add enter key
*/
public function enter(): self
{
return $this->pressKey(self::KEY_ENTER);
}
/**
* Add escape key
*/
public function escape(): self
{
return $this->pressKey(self::KEY_ESCAPE);
}
/**
* Add tab key
*/
public function tab(): self
{
return $this->pressKey(self::KEY_TAB);
}
/**
* Get next key in sequence
*/
public function getNextKey(): ?string
{
if ($this->currentIndex >= count($this->keySequence)) {
return null;
}
$key = $this->keySequence[$this->currentIndex];
$this->currentIndex++;
return $key;
}
/**
* Reset to beginning
*/
public function reset(): void
{
$this->currentIndex = 0;
}
/**
* Check if there are more keys
*/
public function hasMoreKeys(): bool
{
return $this->currentIndex < count($this->keySequence);
}
/**
* Get all remaining keys
*/
public function getRemainingKeys(): array
{
return array_slice($this->keySequence, $this->currentIndex);
}
/**
* Get the full sequence
*/
public function getSequence(): array
{
return $this->keySequence;
}
}