Diskuze: C# Problém se sleepem / vymazání key bufferu
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Člen
Zobrazeno 9 zpráv z 9.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Kam jsi vlozil ten cyklus na vymazani bufferu? Zkus ho vlozit tesne pod ten switch blok. Melo by to prvni klavesu precist a zbytek zahodit.
Ano, ovšem toto řešení není úplně ideální. Když poté držím klávesu a zmáčknu druhou zatímco první ještě držím, tak tu nastane minimálně 0,5 s pomlka než se začne provádět příkaz jaký má.
Proto hledám nějaké lepší řešení (jestli teda existuje).
Ta pomlka je způsobena běžným Keyboard Repeat Delay http://www.dummies.com/…repeat-rate/
Bohužel v konzolové aplikaci neexistuje rozumný způsob jak to obejít.
Musel bys to udělat alespoň ve WinForms, kde pak můžeš pomocí Timeru
zjišťovat stav klávesy.
Díky za odpověď, ano máš pravdu. Ale možná by šlo tento problém vyřešit jinak.
Když to úplně zobecním, tak problém nastává tehdy, když je vlákno ve sleepu, tak pořád zaznamenává stisk kláves. Přemýšlel jsem jestli třeba nejde to vlákno plně zamčít na určitou dobu (Takový lepší sleep).
Console.Write("Wait");
System.Threading.Thread.Sleep(5000);
Console.Read();
Pokud zde v tech 5s budeme busit do klavesnice, tak se stejne klavesy budou zaznamenavat a vypisi se po sleepu.
Tomu repeat delay se v klasické konzoli nevyhneš. Ještě to můžeš obejít přes platform invoke třeba takto :
class Program
{
private const int KEY_PRESSED = 0x8000;
[DllImport("USER32.dll")]
static extern short GetKeyState(ConsoleKey key);
private static bool IsKeyDown(ConsoleKey key)
{
return (GetKeyState(key) & KEY_PRESSED) > 0;
}
static void Main(string[] args)
{
int x = Console.WindowWidth / 2;
int y = Console.WindowHeight / 2;
while (true)
{
System.Threading.Thread.Sleep(100);
if (IsKeyDown(ConsoleKey.LeftArrow))
x = Math.Max(0, x - 1);
if (IsKeyDown(ConsoleKey.RightArrow))
x = Math.Min(Console.WindowWidth - 1, x + 1);
if (IsKeyDown(ConsoleKey.UpArrow))
y = Math.Max(0, y - 1);
if (IsKeyDown(ConsoleKey.DownArrow))
y = Math.Min(Console.WindowHeight - 1, y + 1);
Console.SetCursorPosition(x, y);
Console.Write('*');
}
}
}
Tvoje řešení mi strašně pomohlo, díky moc! Funguje jak má!
Díky
PS. Trošku tam nechápu ten bitovej AND u
return (GetKeyState(key) & KEY_PRESSED) > 0;
ale to snad přeziju
To jsem rád. Jde o to, že výsledkem WinAPI funkce GetKeyState je hodnota
typu short.
Nás zajímá jen jestli je klávesa zmáčknutá a podle dokumentace ( https://msdn.microsoft.com/…=vs.85).aspx ) to poznáme tak,
že nejvyšší bit vrácené hodnoty je nastaven na 1.
Zavoláním "GetKeyState(key) & 0x8000" si vymaskujeme tento nejvyšší bit
v shortu a zjistíme jestli je nastaven. 0x8000 totiž odpovídá bitům
1000000000000000.
Když zkusíš něco podobného jako toto, zjistíš jak vypadají bity ve
vráceném shortu při stisku levé šipky:
while (true)
{
Console.SetCursorPosition(0, 0);
Console.WriteLine(Convert.ToString(GetKeyState(ConsoleKey.LeftArrow), 2).PadLeft(16, '0'));
}
Děláš dobře že to chceš pochopit a ne jen zkopírovat
Jasný, chápu. Za toto vysvětlení ještě větší dík než za ten zdroják, protože to vysvětlení dá člověku víc.
Je zajímavý jak to funguje, a je dobré vědět, že ten poslední bit může sloužit (on slouží) jako přepínač.
Díky
Zobrazeno 9 zpráv z 9.