![image](https://habrastorage.org/getpro/habr/post_images/3b7/bff/ed4/3b7bffed4410cc6e476bc9482dfa37d7.jpg)
Когда я начал писать эту статью, то понял, что глав выйдет на контроллер поболее:
Это сам джойстик, второй джойстик, вибрация и Мультитап (устройство для подключения 4 джойстиков в один порт) – он у меня есть.
Для самого джойстика существует две библиотеки, каждая из которых дает свою информацию.
Я использую 2 оригинальных джойстика Dual Shock 2, однако, у меня есть два не оригинальных джойстика (используются для подключения к компу через спец. Устройство или через мультитап для игры вчетвером), о которых я буду упоминать отдельно.
У каждого контроллера есть так называемый контроллер терминала – это собственно порт, через который вы обращаетесь к контроллеру.
Для управления контроллерами существует специальная библиотека libpad, которая обеспечивает получения данных с кнопок, изменение режима контроллера и вибрацию.
Также существует «обычная» библиотека libmtap. Обе библиотеки могут работать с multitap.
Библиотека поддерживает следующие контроллеры от PS1 и PS2:
Обычный цифровой контроллер (без аналогов): ID = 4;
Dual Shock 1 и Dual Shock 2: ID = 7;
NeGcon контроллер: ID = 2;
Обычный аналоговый джойстик: ID = 5;
Namco пистолет: ID = 6;
Jog контроллер и контроллер рыбалки (сюда, видимо, входит и гитара): Спец. расширенный ID.
Об остальных я буду пополнять информацию по пути.
Порт и слот
Понятия порт и слот – разные вещи в PS2.
Порт указывает на главные контроллеры – те самые для первого и второго джойстика на самой PS2.
Слот используется, в большинстве, когда у вас есть MultiTap. Мультитап нужен для подключения нескольких джойстиков в один порт (максимум — 4). Обычно, в играх это отображается как Joystick 1A, Joystick 1B и т.п.
Если у вас нет мультитапа, то, в принципе, вам и заморачиваться не стоит: порт 0, слот 0 – первый джойстик, порт 1, слот 0 – второй джойстик.
С мультитапом будет по другому: если у вас, скажем, вставлен во второй порт мультитап и к нему подключен джойстик в слот А, то вам требуется обратиться к нему с помощью порт 1, слот 0.
Достаточно подробно это видно на изображении:
![](https://habrastorage.org/getpro/habr/post_images/fdf/97f/721/fdf97f7215b62489c2b0782e4e54a17f.png)
На будущее скажу, что также происходит работа с картами памяти.
Работа с джойстиками
Для использования libpad нужно подключить библиотеку «libpad.a» и заголовочный файл «libpad.h».
Для запуска следует использовать во время старта приложения функцию «sceSifLoadModule()».
В makefile должен быть добавлен параметр «–lpad».
Основные процедуры для использования контроллеров:
scePadInit() – инициализация библиотеки. Параметром является 0.
scePadPortOpen() – открытие порта контроллера. Возвращает Его параметрами являются: порт, слот, буфер, который будет использоваться. Должен быть размером 64 байта. Объявляется видом:
static u_long128 pad_dma_buf[scePadDmaBufferMax] __attribute__((aligned (64)));
Где scePadDmaBufferMax – константа, которую объявлять не надо.
Возвращает функция int, по которому вы можете проверить то, что джойстик вставлен – если его нет, то параметр будет равен 0;
Далее библиотека начинает автоматически общаться с контроллером когда контроллер включен и открыт. Далее есть две функции:
scePadRead() – используется для чтения кнопок.
Функция имеет 3 параметра: порт и слот и буфер для сохранения результата.
Буфер представляет из себя unsigned char buffer[32];
Также функция возвращает результат. И если он равен нулю, то чтение зафейлилось.
Далее нам просто надо читать буфер, хоть на самом деле это не просто.
scePadGetState() – с помощью нее можно проверять находится ли контроллер в спокойном состоянии. Принимает параметрами порт и слот.
Возвращает статус контроллера. Если статус больше и равен нулю, а также меньше или равен 7, то что-то произошло.
Для закрытия контроллеров используется функция scePadPortClose(), где параметры порт и слот, и после scePadEnd() выключает библиотеку. Обычно эти две функции не используются.
Добавлю, что все эти функции также используются для чтения аналогов, только если включен режим.
Самый банальный пример будет выглядеть так:
main(){<br> unsigned char rdata[32];<br> u_long128 pad_dma_buff[scePadDmaBufferMax] __attribute__((aligned(64)));<br> scePadInit();<br> scePadPortOpen(0, 0, pad_dma_buff);<br> while(1) {<br> scePadRead(0,0,rdata);<br> //ваш код<br> }<br> scePadPortClose(0,0);<br> scePadEnd();<br>}<br>* This source code was highlighted with Source Code Highlighter.
Работа с DualShock и чувствительность нажатия кнопок
Для начала требуется включить режим аналогов функцией scePadSetMainMode(). Принимает параметры порт, слот, 1 и 0. Возвращает результат в виде 0 или 1, что значит не включен или включен, соответственно.
Чтобы убедиться, что контроллер действительно DualShock, требуется вызвать функцию scePadInfoPressMode(). Принимает параметры порт и слот, возвращает результат в виде 0 или 1.
Включение самого режима происходит функцией scePadEnterPressMode(). Принимает параметры и возвращает также как и предыдущая функция.
В дальнейшем, через функцию scePadRead() в буфере мы получаем дополнительно еще один байт, в котором степень нажатия кнопок отображены значениями от 0 до 255. Где 0 равен тому, что кнопка не нажата.
Скажу, на заметку, что мой первый джойстик иногда показывает сам силу нажатия до 3.
По спецификации вполне нормальная ошибка движения аналога является плюс-минус 25.
С помощью функции scePadExitPressMode() можно выйти из режима чувствительности клавиш. Принимает он порт и слот. Может понадобиться на переключение в меню.
Если пользователь во время чувствительного режима нажмет на кнопку аналога, то он переключится на обычный цифровой режим без чувствительности. Повторное нажатие на кнопку аналога не переключит джойстик обратно в режим чувствительности.
Вибрация
Вибрация в джойстике достаточно проста и в то же время нет.
Можно подключить для нее отдельную библиотеку, а можно использовать только две функции, которые входят в libpad.
Про другую библиотеку вибрации расскажу в следующий раз, тут же расскажу о достаточно простых двух функциях, это scePadSetActAlign() и scePadSetActDirect(), которые принимают, порт, слот и 6 байт о закручивании.
В первом байте вы указываете сильный мотор или слабый мотор.
Слабый мотор принимает во втором байте значения 0 или 1, что значит остановка или кручение. Сильный мотор принимает во втором байте значение от 1 до 255 или 0, что означает силу кручения или остановка.
Функция scePadSetActDirect() возвращает true или false, говорящие о выполнении операции вибрации. Остальные байты желательно заполнять значением 0xff, если вы их не используете.
После этого джойстик пользователя получит 10 единиц тока для работы вибрации.
Для увеличения количества единиц тока до 20 просто заполните остальные значения 0x00.
Важно!
Надо знать, что каждый порт ограничен максимальным числом единиц тока, равным 60. Если попробовать дать больше 60, то порт может быть заблокирован до перезагрузки консоли (срабатывает внутренний ограничитель).
Таким образом, если у меня стоит мультитап, и на джойстики 1А, 1B и 1C я подам по 20 единиц тока, то на джойстик 1D я не могу уже это сделать, иначе могу заблокировать порт. Поэтому использовать повышенную подачу тока я вам не советую.
Также добавлю, что эти функции не могут использоваться для долгой вибрации.
Асинхронные функции
Следующие функции являются асинхронными. Они могут не вернуть вам результат в тот же момент. В этом случае вы можете получить результат их исполнения через функции scePadGetState() или scePadGetReqState().
scePadSetMainMode – переключение режимов ввода;
scePadSetActAlign – функция вибрации;
scePadEnterPressMode — вход в режим чувствительности нажатия кнопок;
scePadExitPressMode – выход из режима чувствительности нажатия кнопок.
Ближе к концу
Вообще, в принципе, приложение будет дальше работать с портом и слотом, даже если джойстик удален (выключен). Программно проверить что джойстик удален можно с помощью scePadGetState(), которая вернет scePadStateDisconnect.
Перед каждым кадром советуется проверять состояние контроллера, дабы не возникло ситуации, когда джойстик случайно выключился.
Также, в зависимости от версии контроллеров DualShock или DualShock 2, спецификация аналогов может меняться и надеяться на автокалибровку джойстика не стоит. Поэтому чаще всего приходится делать поправки на то, что аналог не остановился в точке 127х127.
На этом все. Увидимся в следующей, более подробной статье о джойстиках.
P.S.: Видя актуальность темы, я писал эту статью пол ночи и утро. Если SDK будет готов к следующей статье, то вместо джойстиков будет описание установки.
Update: Функция scePadInit() нужна только в использовании EE, о котором я и веду речь. IOP инициализирует библиотеку сам.