Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PSX code Gamepad code.md
2025-04-20 14:00:47 +05:00

4.8 KiB
Raw Blame History

Да, ваша структура s_gamePad вполне подходит для работы с геймпадами PlayStation 1, но требует некоторых доработок для корректной работы с PsyQ SDK. Вот полное решение:

1. Улучшенная структура геймпада

#include <sys/types.h>
#include <psxpad.h>

#pragma pack(push, 1)  // Выравнивание 1 байт
typedef struct {
    uint8_t stat;       // 0x00 - статус (0 = данные готовы)
    
    union {
        struct {
            uint8_t recvSize:4;  // Размер полученных данных (4/8 байт)
            uint8_t type:4;      // Тип контроллера (4=Digital, 5=Analog)
        };
        uint8_t bConfig;         // Объединение для удобства доступа
    };
    
    // Кнопки (битовая маска, 1=не нажата, 0=нажата)
    union {
        struct {
            uint16_t select:1;   // 0x0001
            uint16_t :1;         // Не используется
            uint16_t :1;         // Не используется
            uint16_t start:1;    // 0x0008
            uint16_t up:1;       // 0x0010
                uint16_t right:1;    // 0x0020
                uint16_t down:1;     // 0x0040
                uint16_t left:1;     // 0x0080
                uint16_t l2:1;       // 0x0100
                uint16_t r2:1;       // 0x0200
                uint16_t l1:1;       // 0x0400
                uint16_t r1:1;       // 0x0800
                uint16_t triangle:1; // 0x1000
                uint16_t circle:1;   // 0x2000
                uint16_t cross:1;    // 0x4000
                uint16_t square:1;   // 0x8000
        };
        uint16_t buttons;        // Полное слово кнопок
    };
    
    // Аналоговые данные (для DualShock)
    uint8_t rightJoyX;   // 0x03 Правый джойстик X
    uint8_t rightJoyY;   // 0x04 Правый джойстик Y
    uint8_t leftJoyX;    // 0x05 Левый джойстик X
    uint8_t leftJoyY;    // 0x06 Левый джойстик Y
} s_gamePad;
#pragma pack(pop)  // Восстановление выравнивания

static s_gamePad gamePads[2];  // Буферы для двух геймпадов

2. Функция инициализации

#define PAD_BUFFER_SIZE 34

void GamePadInit(void) {
    static uint8_t padData[2][PAD_BUFFER_SIZE] __attribute__((aligned(64)));
    
    // Инициализация буферов
    PadInitDirect(padData[0], padData[1]);
    
    // Начало опроса геймпадов
    PadStartCom();
    
    // Очистка структур
    memset(gamePads, 0, sizeof(gamePads));
}

3. Функция чтения состояния

void GamePadRead(void) {
    // Чтение сырых данных
    uint8_t* padRaw = (uint8_t*)PadRead(0);  // Чтение порта 0
    
    // Копирование и преобразование данных
    memcpy(&gamePads[0], padRaw, sizeof(s_gamePad));
    
    // Инвертирование битов кнопок (в оригинале 1=не нажата)
    gamePads[0].buttons ^= 0xFFFF;
    
    // Аналогично для второго геймпада (порт 1)
    padRaw = (uint8_t*)PadRead(1);
    memcpy(&gamePads[1], padRaw, sizeof(s_gamePad));
    gamePads[1].buttons ^= 0xFFFF;
}

4. Пример использования

void Update(void) {
    GamePadRead();
    
    if (gamePads[0].cross) {
        // Кнопка X нажата на первом геймпаде
    }
    
    if (gamePads[1].type == 5) {  // Аналоговый геймпад
        int stickX = gamePads[1].leftJoyX - 128;  // -128..127
    }
}

Ключевые особенности:

  1. Битовые поля - Позволяют удобно обращаться к каждой кнопке
  2. Union - Даёт доступ как к отдельным кнопкам, так и ко всему слову
  3. Аналоговые данные - Поддержка DualShock
  4. Выравнивание - #pragma pack(push, 1) гарантирует правильный layout структуры
  5. Инверсия битов - В PS1 1=не нажато, поэтому делаем XOR

Совместимость:

  • Работает с Digital (SCPH-1080) и Analog (SCPH-1150) контроллерами
  • Поддерживает DualShock (аналоговые стики)
  • Корректно работает с PsyQ SDK 4.7 и новее

Такой подход более типобезопасен и удобен для чтения, чем оригинальный вариант с прямым доступом к памяти.