Загрузка данных
#include <Keyboard.h>
// Пины джойстика
const int JOY_X_PIN = A0;
const int JOY_Y_PIN = A1;
// Пороги срабатывания джойстика
const int THRESHOLD = 400;
const int DEADZONE = 100;
// Переменные для отслеживания состояния
bool wPressed = false;
bool aPressed = false;
bool sPressed = false;
bool dPressed = false;
// Пины кнопок (5-13)
const int buttonPins[] = {5, 6, 7, 8, 9, 10, 11, 12, 13};
const char keys[] = {'Q', 'E', 'R', 'F', 'Z', 'X', 'C', 'V', 'B'};
const int numButtons = 9;
bool buttonStates[numButtons];
// СТАБИЛИЗАЦИЯ: таймеры и сброс состояния
unsigned long lastActivityTime = 0;
const unsigned long RESET_TIMEOUT = 5000; // 5 секунд без активности - полный сброс
unsigned long lastResetCheck = 0;
// Для дебаунса
const int DEBOUNCE_DELAY = 10;
unsigned long lastButtonTime[numButtons];
unsigned long lastJoystickTime = 0;
int lastX = 512, lastY = 512;
void setup() {
Serial.begin(9600);
Keyboard.begin();
for (int i = 0; i < numButtons; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
buttonStates[i] = false;
lastButtonTime[i] = 0;
}
// ПРИНУДИТЕЛЬНЫЙ СБРОС при старте
resetAllKeys();
delay(100);
Serial.println("Джойстик-клавиатура запущена (стабильная версия)");
}
void loop() {
checkAndResetIfNeeded(); // Критически важно!
int xValue = analogRead(JOY_X_PIN);
int yValue = analogRead(JOY_Y_PIN);
processJoystick(xValue, yValue);
processButtons();
delay(5); // Маленькая задержка для стабильности
}
void processJoystick(int x, int y) {
// Дебаунс для джойстика
if (millis() - lastJoystickTime < 20) return;
bool hasActivity = false;
// Вертикаль (W/S)
if (y < 512 - THRESHOLD) {
if (!wPressed) {
Keyboard.press('W');
wPressed = true;
hasActivity = true;
Serial.println("W");
}
} else if (y > 512 + THRESHOLD) {
if (!sPressed) {
Keyboard.press('S');
sPressed = true;
hasActivity = true;
Serial.println("S");
}
} else {
if (wPressed) {
Keyboard.release('W');
wPressed = false;
hasActivity = true;
}
if (sPressed) {
Keyboard.release('S');
sPressed = false;
hasActivity = true;
}
}
// Горизонталь (A/D)
if (x < 512 - THRESHOLD) {
if (!aPressed) {
Keyboard.press('A');
aPressed = true;
hasActivity = true;
Serial.println("A");
}
} else if (x > 512 + THRESHOLD) {
if (!dPressed) {
Keyboard.press('D');
dPressed = true;
hasActivity = true;
Serial.println("D");
}
} else {
if (aPressed) {
Keyboard.release('A');
aPressed = false;
hasActivity = true;
}
if (dPressed) {
Keyboard.release('D');
dPressed = false;
hasActivity = true;
}
}
if (hasActivity) {
lastActivityTime = millis();
}
lastJoystickTime = millis();
}
void processButtons() {
unsigned long now = millis();
bool hasActivity = false;
for (int i = 0; i < numButtons; i++) {
if (now - lastButtonTime[i] < DEBOUNCE_DELAY) continue;
bool currentState = (digitalRead(buttonPins[i]) == LOW);
if (currentState != buttonStates[i]) {
if (currentState) {
Keyboard.press(keys[i]);
Serial.print("Нажата: ");
Serial.println(keys[i]);
} else {
Keyboard.release(keys[i]);
Serial.print("Отпущена: ");
Serial.println(keys[i]);
}
buttonStates[i] = currentState;
lastButtonTime[i] = now;
hasActivity = true;
}
}
if (hasActivity) {
lastActivityTime = now;
}
}
// КРИТИЧЕСКИ ВАЖНАЯ ФУНКЦИЯ - сбрасывает все клавиши
void resetAllKeys() {
// Список всех возможных клавиш, которые могли быть нажаты
const char* allKeys[] = {"W", "A", "S", "D", "Q", "E", "R", "F", "Z", "X", "C", "V", "B"};
for (int i = 0; i < 13; i++) {
Keyboard.release(allKeys[i][0]);
}
// Сброс внутренних состояний
wPressed = false;
aPressed = false;
sPressed = false;
dPressed = false;
for (int i = 0; i < numButtons; i++) {
buttonStates[i] = false;
}
Serial.println("!!! ПОЛНЫЙ СБРОС КЛАВИШ !!!");
}
// Проверка и автоматический сброс при зависании
void checkAndResetIfNeeded() {
unsigned long now = millis();
// Периодическая проверка каждые 100мс
if (now - lastResetCheck < 100) return;
lastResetCheck = now;
// Если нет активности дольше таймаута - сброс
if (now - lastActivityTime > RESET_TIMEOUT) {
// Дополнительная проверка: действительно ли винда зависла?
if (wPressed || aPressed || sPressed || dPressed) {
Serial.println("Обнаружен зависший джойстик - сброс");
resetAllKeys();
lastActivityTime = now;
}
// Проверка кнопок
bool anyPressed = false;
for (int i = 0; i < numButtons; i++) {
if (buttonStates[i]) {
anyPressed = true;
break;
}
}
if (anyPressed) {
Serial.println("Обнаружены зависшие кнопки - сброс");
resetAllKeys();
lastActivityTime = now;
}
}
// АВТОМАТИЧЕСКИЙ СБРОС КАЖДЫЕ 2 МИНУТЫ (страховка)
static unsigned long lastAutoReset = 0;
if (now - lastAutoReset > 120000) { // 2 минуты
Serial.println("Плановый профилактический сброс");
resetAllKeys();
lastAutoReset = now;
lastActivityTime = now;
}
}