Usiłuję napisać poprawnie działający kod odczytu stanu przycisków kontrolera (gamepada jak kto woli), podłączonego na USB. Wszystko działa elegancko, jeśli kontroler jest podłączony — tutaj nie mam absolutnie żadnych problemów. Jednak jeśli włączę program, a kontroler nie jest podłączony, sprawdzanie jego stanu (podłączony i jeśli tak, to pobranie stanu przycisków) trwa od 100ms do nawet 300ms, przez co framerate spada z 60fps do 3-4fps, w porywach do 10fps.
Jeśli w takim przypadku podłączę kontroler, framerate wraca do normy. Jeśli znów odłączę kontroler, to nadal wszystko działa prawidłowo — framerate jest w normie i już aż do końca sesji nic się z nim nie stanie. Problem występuje tylko przy rozruchu, jeśli gamepad nie jest podłączony. I problem jest taki, że funkcja pobierająca stan klawiszy i zwracająca kod błędu, po wystartowaniu programu widzi kontroler jako podłączony, pomimo tego, że nie jest. Dopiero podłączenie i odłączenie gamepada sprawia, że jego widoczność jest prawidłowa (jak jest to jest, a jak nie ma to go nie ma).
Stan podłączenia kontrolera oraz pobranie stanu jego przycisków realizuję za pomocą funkcji joyGetPosEx
. Kod wygląda tak:
FStatus := Default(JOYINFOEX);
FStatus.dwSize := SizeOf(FStatus);
FStatus.dwFlags := JOY_RETURNX or JOY_RETURNY or JOY_RETURNBUTTONS;
FConnected := joyGetPosEx(JOYSTICKID1, @FStatus) = JOYERR_NOERROR;
if FConnected then
begin
UpdateArrows();
UpdateButtons();
end
else
Reset();
Niestety joyGetPosEx
domyślnie widzi kontroler jako niepodłączony, zwraca kod JOYERR_PARMS
i ssie, a dopiero po pierwszym podłączeniu zaczyna go prawidłowo widzieć/nie widzieć i już nie ssie — jeśli kontroler jest podłączony to zwraca kod JOYERR_NOERROR
(prawidłowo), a jeśli go znów odłączę, to kod JOYERR_UNPLUGGED
(też prawidłowo).
Moje metody UpdateArrows
i UpdateButtons
jedynie przepisują dane z pola FStatus
do obiektów przycisków — nie mają nic wspólnego z systemem, tak że nawet jeśli FConnected
fałszywie zawiera prawdę, one same nie zamulą programu.
Sprawdziłem też inny kod podany na stronie MSDN:
JOYINFO joyinfo;
UINT wNumDevs, wDeviceID;
BOOL bDev1Attached, bDev2Attached;
if((wNumDevs = joyGetNumDevs()) == 0) return ERR_NODRIVER;
bDev1Attached = joyGetPos(JOYSTICKID1,&joyinfo) != JOYERR_UNPLUGGED;
bDev2Attached = wNumDevs == 2 && joyGetPos(JOYSTICKID2,&joyinfo) != JOYERR_UNPLUGGED;
if(bDev1Attached || bDev2Attached) // decide which joystick to use
wDeviceID = bDev1Attached ? JOYSTICKID1 : JOYSTICKID2;
else
return ERR_NODEVICE;
i przepisałem go na Pascala, podłączając go pod obecny mechanizm:
var
Info: JOYINFO;
DevicesCount: Integer;
var
ControllerID: Integer;
Controller1Attached, Controller2Attached: Boolean;
begin
DevicesCount := joyGetNumDevs();
FConnected := DevicesCount > 0;
if FConnected then
begin
Controller1Attached := joyGetPos(JOYSTICKID1, @Info) <> JOYERR_UNPLUGGED;
Controller2Attached := (DevicesCount = 2) and (joyGetPos(JOYSTICKID2, @Info) <> JOYERR_UNPLUGGED);
FConnected := Controller1Attached or Controller2Attached;
if FConnected then
begin
if Controller1Attached then ControllerID := JOYSTICKID1;
if Controller2Attached then ControllerID := JOYSTICKID2;
FStatus := Default(JOYINFOEX);
FStatus.dwSize := SizeOf(FStatus);
FStatus.dwFlags := JOY_RETURNX or JOY_RETURNY or JOY_RETURNBUTTONS;
joyGetPosEx(ControllerID, @FStatus);
UpdateArrows();
UpdateButtons();
end
else
Reset();
end
else
Reset();
end;
Niestety funkcja joyGetPos
również ssie i tuż po starcie zwraca kod JOYERR_PARMS
, a dopier0 później te prawidłowe. Summa summarum, obie funkcje nie ogarniają czy kontroler jest podłączony czy nie, tuż po starcie. Wszystko sprawdziłem pod debuggerem i jestem na 100% pewny, że po włączeniu programu kody błędów są nieprawidłowe.
Moje pytanie brzmi — w jaki sposób poprawnie (lub inaczej) sprawdzić, czy kontroler jest podłączony?
Wystarczy aby poprawnie określić czy jest podłączony i które ma ID, stan odczytam sobie funkcją joyGetPosEx
, bo mi ona odpowiada. Zależy mi na tym, aby wybrany sposób potrafił rozpoznać dowolny, normalny kontroler (te od XBox i Play Station mam w dupie).
Ciekaw jestem dlaczego domyślnie te funkcje zwracają kod JOYERR_PARMS
zamiast JOYERR_UNPLUGGED
. :/