Этот вопрос закрыт для ответов, так как повторяет вопрос Как получить код нажатой клавиши в linux?
@OtryvnoyKalendar

Как реализовать GetKeyState() на Linux (язык Си)?

Всем привет!

У меня Ubuntu 22.04. В процессе прохождения уроков по языку С мне нужно было написать консольную игру платформер. Возникла проблема с реализацией управления, так как стандартными способами считывается только один символ, а мне нужно считывать нажатие нескольких клавиш одновременно. В Windows эту роль выполняла функция GetKeyState() из winuser.h.

Как я понял, в curses.h и termios.h такого нет, а подключать SFML, SDL и прочие библиотеки бессмысленно, так как они создают отдельное окно и я не смог воспользоваться их функционалом из консоли.

С помощью ИИ я решил проблему, но меня не устраивает:
1. игру нужно запускать от root
2. нажатия считываются даже тогда, когда окно консоли не активно
3. когда я делал управление с помощью SFML, изображение игры не съезжало вбок, а теперь съезжает

Подскажите пожалуйста, чем можно заменить мой код!

Файл key.h с костыльной реализацией управления:
#ifndef KEYS_H
#define KEYS_H

// перед закрытием игры
void BeforeCloseGame();

// одновременное нажатие клавиш
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <linux/kernel.h>

#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
#define BITS_PER_BYTE 8
#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))

static inline int is_bit_set(unsigned long *array, int bit) {
    return (array[bit / (sizeof(long) * 8)] & (1UL << (bit % (sizeof(long) * 8)))) != 0;
}

int fd, ret;
unsigned long key_state[BITS_TO_LONGS(KEY_CNT)];

// Методы для начала работы с библиотекой и завершением работы
void OpenKeysMode() {
	fd = open("/dev/input/by-path/platform-i8042-serio-0-event-kbd", O_RDONLY);
	if (fd == -1)
		ErrorCloseGame("не получилось открыть устройство клавиатуры");
}

void CloseKeysMode() {
	close(fd);
}

// Получаем состояние клавиатуры
void RefreshKeyboardStatus() {
	ret = ioctl(fd, EVIOCGKEY(sizeof(key_state)), key_state);
	if (ret < 0)
		ErrorCloseGame("не получилось получить состояния клавиатуры");
}

int GetKeyState(int Key) {
	return (is_bit_set(key_state, Key));
}

#endif // KEYS_H


Как это выглядит в игре:
#include "keys.h"

void GameControl(tObject *obj) {
	RefreshKeyboardStatus();
	
	if(menu == GAMEMODE_PLAY) {
		float horizonSpeed = 1.0;
		if(GetKeyState(KEY_A))
			horizonMoveMap(horizonSpeed);
		if(GetKeyState(KEY_D))
			horizonMoveMap(-horizonSpeed);
		if(GetKeyState(KEY_SPACE))
			if ((*obj).isFly == 0)
				(*obj).vertSpeed = -1;
		
		if(GetKeyState(KEY_Q))
			menu = GAMEMODE_MENU_PAUSE;
	} else {
		if(GetKeyState(KEY_ESC))
			CloseGame();
		
		if(GetKeyState(KEY_E))
			menu = GAMEMODE_PLAY;
	}
}


Игра на GitHub: ссылка
  • Вопрос задан
  • 178 просмотров
Ваш ответ на вопрос

Вопрос закрыт для ответов и комментариев

Потому что уже есть похожий вопрос.
Похожие вопросы