Загрузка данных
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace KeyboardTrainer
{
public partial class MainWindow : Window
{
// Словарь: клавиша -> кнопка на экране
private Dictionary<Key, Button> keyButtons = new Dictionary<Key, Button>();
// Тренировочные данные
private string targetText = "";
private string userInput = "";
private int errorCount = 0;
private DateTime startTime;
private bool sessionActive = false;
public MainWindow()
{
InitializeComponent();
CreateKeyboardLayout();
}
/// <summary>
/// Создание визуальной клавиатуры
/// </summary>
private void CreateKeyboardLayout()
{
// Раскладка клавиш по рядам
string[][] keyboardRows = new string[][]
{
new string[] { "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "Backspace" },
new string[] { "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\" },
new string[] { "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter" },
new string[] { "Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Shift" },
new string[] { "Ctrl", "Win", "Alt", "Space", "Alt", "Win", "Ctrl" }
};
keyboardPanel.Children.Clear();
keyButtons.Clear();
foreach (var row in keyboardRows)
{
StackPanel rowPanel = new StackPanel
{
Orientation = Orientation.Horizontal,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(0, 0, 0, 5)
};
foreach (string keyName in row)
{
Button btn = new Button
{
Content = keyName,
Width = GetKeyWidth(keyName),
Height = 45,
Margin = new Thickness(2),
IsEnabled = false, // Неинтерактивная клавиатура — только для подсветки
Background = Brushes.LightGray
};
// Сохраняем соответствие реальной клавиши и кнопки
Key mappedKey = MapKeyNameToKey(keyName);
if (mappedKey != Key.None)
keyButtons[mappedKey] = btn;
rowPanel.Children.Add(btn);
}
keyboardPanel.Children.Add(rowPanel);
}
}
/// <summary>
/// Определение ширины кнопки в зависимости от названия клавиши
/// </summary>
private double GetKeyWidth(string keyName)
{
return keyName switch
{
"Space" => 300,
"Backspace" => 100,
"Tab" => 80,
"CapsLock" => 95,
"Enter" => 95,
"Shift" => 110,
"Ctrl" => 70,
"Alt" => 70,
"Win" => 70,
_ => 55
};
}
/// <summary>
/// Преобразование названия кнопки в значение перечисления Key
/// </summary>
private Key MapKeyNameToKey(string name)
{
return name switch
{
"Backspace" => Key.Back,
"Tab" => Key.Tab,
"CapsLock" => Key.CapsLock,
"Enter" => Key.Enter,
"Shift" => Key.LeftShift,
"Ctrl" => Key.LeftCtrl,
"Alt" => Key.LeftAlt,
"Win" => Key.LWin,
"Space" => Key.Space,
_ when name.Length == 1 && char.IsLetterOrDigit(name[0]) =>
(Key)Enum.Parse(typeof(Key), name.ToUpper(), true),
_ => Key.None
};
}
/// <summary>
/// Генерация случайной строки по уровню сложности
/// </summary>
private string GenerateRandomString()
{
Random rnd = new Random();
int difficulty = cmbDifficulty.SelectedIndex; // 0-Easy, 1-Medium, 2-Hard
int length = difficulty switch
{
0 => 10,
1 => 20,
2 => 35,
_ => 15
};
string chars = difficulty switch
{
0 => "abcdefghijklmnopqrstuvwxyz ",
1 => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ",
2 => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?- ",
_ => "abcdefghijklmnopqrstuvwxyz "
};
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[rnd.Next(s.Length)]).ToArray());
}
/// <summary>
/// Старт тренировки
/// </summary>
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
targetText = GenerateRandomString();
txtTargetText.Text = targetText;
userInput = "";
errorCount = 0;
txtUserInput.Text = "";
txtUserInput.IsEnabled = true;
txtUserInput.Focus();
startTime = DateTime.Now;
sessionActive = true;
UpdateStats();
}
/// <summary>
/// Обработка ввода текста
/// </summary>
private void TxtUserInput_TextChanged(object sender, TextChangedEventArgs e)
{
if (!sessionActive) return;
userInput = txtUserInput.Text;
// Подсчёт ошибок (позиционное сравнение)
int newErrorCount = 0;
for (int i = 0; i < userInput.Length; i++)
{
if (i >= targetText.Length || userInput[i] != targetText[i])
newErrorCount++;
}
errorCount = newErrorCount;
// Проверка завершения
if (userInput.Length >= targetText.Length)
{
sessionActive = false;
txtUserInput.IsEnabled = false;
MessageBox.Show($"Тренировка завершена!\nОшибок: {errorCount}\n" +
$"Скорость: {CalculateSpeed()} зн/мин", "Результат");
}
UpdateStats();
// Подсветка текущей позиции в целевой строке
HighlightCurrentPosition();
}
/// <summary>
/// Подсветка текущего символа для ввода
/// </summary>
private void HighlightCurrentPosition()
{
if (string.IsNullOrEmpty(targetText)) return;
int pos = userInput.Length;
if (pos < targetText.Length)
{
string highlighted = targetText.Substring(0, pos) +
"→" + targetText[pos] + "←" +
targetText.Substring(pos + 1);
txtTargetText.Text = highlighted;
}
else
{
txtTargetText.Text = targetText;
}
}
/// <summary>
/// Обновление статистики
/// </summary>
private void UpdateStats()
{
txtErrors.Text = errorCount.ToString();
txtSpeed.Text = $"{CalculateSpeed()} зн/мин";
}
/// <summary>
/// Расчёт скорости набора (знаков в минуту)
/// </summary>
private int CalculateSpeed()
{
if (!sessionActive || startTime == DateTime.MinValue) return 0;
double minutes = (DateTime.Now - startTime).TotalMinutes;
if (minutes <= 0) return 0;
int correctChars = Math.Max(0, userInput.Length - errorCount);
return (int)(correctChars / minutes);
}
/// <summary>
/// Подсветка нажатой клавиши
/// </summary>
private void Window_KeyDown(object sender, KeyEventArgs e)
{
// Основная клавиша
if (keyButtons.ContainsKey(e.Key))
{
keyButtons[e.Key].Background = Brushes.LightGreen;
}
// Обработка модификаторов
if (e.KeyboardDevice.IsKeyDown(Key.LeftShift) && keyButtons.ContainsKey(Key.LeftShift))
keyButtons[Key.LeftShift].Background = Brushes.LightGreen;
if (e.KeyboardDevice.IsKeyDown(Key.RightShift) && keyButtons.ContainsKey(Key.RightShift))
keyButtons[Key.RightShift].Background = Brushes.LightGreen;
if (e.KeyboardDevice.IsKeyDown(Key.LeftCtrl) && keyButtons.ContainsKey(Key.LeftCtrl))
keyButtons[Key.LeftCtrl].Background = Brushes.LightGreen;
if (e.KeyboardDevice.IsKeyDown(Key.LeftAlt) && keyButtons.ContainsKey(Key.LeftAlt))
keyButtons[Key.LeftAlt].Background = Brushes.LightGreen;
}
/// <summary>
/// Сброс подсветки клавиши
/// </summary>
private void Window_KeyUp(object sender, KeyEventArgs e)
{
if (keyButtons.ContainsKey(e.Key))
{
keyButtons[e.Key].Background = Brushes.LightGray;
}
if (!e.KeyboardDevice.IsKeyDown(Key.LeftShift) && keyButtons.ContainsKey(Key.LeftShift))
keyButtons[Key.LeftShift].Background = Brushes.LightGray;
if (!e.KeyboardDevice.IsKeyDown(Key.RightShift) && keyButtons.ContainsKey(Key.RightShift))
keyButtons[Key.RightShift].Background = Brushes.LightGray;
if (!e.KeyboardDevice.IsKeyDown(Key.LeftCtrl) && keyButtons.ContainsKey(Key.LeftCtrl))
keyButtons[Key.LeftCtrl].Background = Brushes.LightGray;
if (!e.KeyboardDevice.IsKeyDown(Key.LeftAlt) && keyButtons.ContainsKey(Key.LeftAlt))
keyButtons[Key.LeftAlt].Background = Brushes.LightGray;
}
}
}