function result = Gamepad(arg1, arg2, arg3) % result = Gamepad(command [,arg1] [,arg2]) % % Gamepad reads the state of any USB game controller. Gamepad was % previously named "JoyStick", the name has been changed to agree with the % USB Human Interface Device (HID) terminology. % % Gamepad provides built-in help. For usage, enter "Gamepad" alone on the % command line. % % Performance tips: % % As initialization of Gamepad takes significant time, you should call it % once at the beginning of your script before entering the trial loop. % After plugging/unplugging or replugging of any USB devices you *must* % call Gamepad('Unplug') or clear all, so Gamepad can recognize the changed % hardware configuration at next invocation. Actually, a clear all is % recommended, as Gamepad('Unplug') doesn't work reliably on non-OSX systems. % % The subfunctions for state queries of axis, button and hat state are % optimized for low execution time -- suitable for time critical parts of % your trial loop. All other functions, e.g., for query of the number of % buttons etc. are not optimized, so they shouldn't be called in time % critical parts of your loop. % % If you need ultra-fast queries, check the help for 'GetButtonRawMapping', % 'GetAxisRawMapping' and 'GetHatRawMapping' for a slightly inconvenient, % but superfast way to query device state. % % % LINUX: ______________________________________________________________________ % % On Linux/X11, Gamepad() uses the Screen() mex file and its mouse query functions. % % On Linux, gamepads and joysticks are treated as a special type of mouse/pointing % device with multiple extra axes and buttons. You should install the optional % joystick driver, although the evdev driver may also work with suitable configuration. % % On Ubuntu 20.04 LTS or later, the following command should work: % % "sudo apt install xserver-xorg-input-joystick" % % You should also install a custom joystick configuration file to customize the % mapping and behaviour of buttons and axis, and if the Joystick also operates % as a mouse or not. % % An example configuration file with installation instructions is available in % the Psychtoolbox/PsychContributed folder under the name "52-MyLinuxJoystick.conf". % % OSX: ________________________________________________________________________ % % GamePad uses the PsychHID function, which provides a universal interface to % USB HID devices, including keyboards. % % WIN: ________________________________________________________________________ % % Gamepad is not yet supported on Windows. WinJoystickMex() in the % Psychtoolbox/PsychContributed subfolder may serve as a temporary % replacement of more limited functionality. % _____________________________________________________________________________ % % See also: PsychGamepad, PsychHID % HISTORY % 7/21/03 awi Wrote it. % 7/13/04 awi Fixed documentation. % 10/30/07 mk Optimizations: Now 50 times faster due to caching and % restructuring. Also new low-level access commands that % allow another 7x speedup at expense of more complex % usage. % 08/05/11 mk Allow use on Linux as well. % NOTES % 7/21/03 awi Gamepad does not support ball elements because I do not know what those are % and do not have a joystick with ball elements. If someone does, report the % the model of the joystick and I will add the feature. % Note that the SDL source _should_ % internally idenfify the HID usage and usage page numbers for what it calls a % "joystick ball" but it does not, SDL on OSX seems not to support ball % elements. The SDL source always sets the number of ball elements to 0. % TO DO % 7/21/03 awi Check SDL source for other platforms, maybe some version contains the the HID usage % for "joystick ball". % 7/22/03 awi gamepadIndices and deviceStructs variables could be retained between invocations and % cleared with the 'unplug' command. % 10/6/05 awi Note here cosmetic changes by dgp between 7/22/03 and 10/6/05. % 7/06/22 mk help text updates for Ubuntu 20.04/22.04 instead of 16.04/18.04. persistent axisUsagePageValue axisUsageValues hatswitchUsagePageValue hastSwitchUsageValues buttonUsagePageValue allGamepadSubCommands allGamepadHelpRequests joyMin joyMax gamepadIndices deviceStructs gi ei if isempty(deviceStructs) % First call: Don't have cached data. Build all device info % structures by device detection and enumeration. Initialize all % other frequently used data structures... % Check if we're called on a supported OS. Currently Windows is % unsupported: if IsWin error('Sorry, the Gamepad function does not work on Windows yet.'); end % Constants for device page and usage % gamepadUsagePageValue=1; gamepadUsageValue=5; %element page and usage axisUsagePageValue=1; axisUsageValues=[48 49 50 51 52 53]; % sliderUsagePageValue=1; sliderUsageValues=54; % dialUsagePageValue=1; dialUsageValues=55; % wheelUsagePageValue=1; wheelUsageValues=56; hatswitchUsagePageValue=1; hastSwitchUsageValues=57; buttonUsagePageValue=9; %anything on the button usage page is a button joyMin=AxisMin; joyMax=AxisMax; % Subcommand names etc.: oldGamepadSubCommands= {'GetNumJoysticks', 'GetJoystickName', 'GetJoystickNumbersFromName', 'GetNumButtons', ... 'GetNumAxes', 'GetNumBalls', 'GetNumHats', 'GetButton', 'GetAxis', 'GetBall', 'GetHat', 'Unplug'}; newGamepadSubCommands= {'GetNumGamepads', 'GetGamepadNamesFromIndices', 'GetGamepadIndicesFromNames', 'GetNumButtons', ... 'GetNumAxes', 'GetNumBalls', 'GetNumHats', 'GetButton', 'GetAxis', 'GetBall', 'GetHat', 'Unplug', 'GetAxisRawMapping', 'GetButtonRawMapping', 'GetHatRawMapping'}; allGamepadSubCommands=union(oldGamepadSubCommands, newGamepadSubCommands); for i = 1:length(allGamepadSubCommands) allGamepadHelpRequests{i}=[allGamepadSubCommands{i} '?']; end % allPossibleCommands=upper(union(allGamepadHelpRequests, allGamepadSubCommands)); % Device detection and enumeration: [gamepadIndices, gamepadNames] = GetGamepadIndices; if IsLinux % Linux method: Gamepads are treated as slave mouse devices with extra % buttons and axis. Use GetMouse to get info about them: % Query additional per-device configuration info and parameters: for i=1:length(gamepadIndices) [x,y,b,f,v,vi] = GetMouse([], gamepadIndices(i)); deviceStructs(gamepadIndices(i)).buttonIndices = 1:(length(b) - 32); deviceStructs(gamepadIndices(i)).axisIndices = 1:length(v); deviceStructs(gamepadIndices(i)).hatIndices = []; deviceStructs(gamepadIndices(i)).product = char(gamepadNames(i)); deviceStructs(gamepadIndices(i)).buttons = length(b) - 32; deviceStructs(gamepadIndices(i)).axes = length(v); deviceStructs(gamepadIndices(i)).balls = 0; deviceStructs(gamepadIndices(i)).hats = 0; % Populate element properties: elements = []; for j = 1:length(vi) el.rangeMin = vi(j).min; el.rangeMax = vi(j).max; el.label = vi(j).label; if isempty(elements) elements = el; else elements(end+1) = el; end end deviceStructs(gamepadIndices(i)).elements = elements; end end if IsOSX % The following is OS/X only stuff: deviceStructs=PsychHID('Devices'); % Query additional per-device configuration info and parameters: for i=1:length(gamepadIndices) elements = PsychHID('Elements', gamepadIndices(i)); deviceStructs(gamepadIndices(i)).elements = elements; % Get the indices of the button elements. buttonIndices=[]; for j=1:length(elements) if ~isempty(elements(j).usagePageValue) && (elements(j).usagePageValue==buttonUsagePageValue) buttonIndices=[buttonIndices j]; %#ok end end if deviceStructs(gamepadIndices(i)).buttons ~= length(buttonIndices) error('Found more elements of type button than the reported number of buttons'); end deviceStructs(gamepadIndices(i)).buttonIndices = buttonIndices; % Get the indices of the axis elements. axisIndices=[]; for j=1:length(elements) if ~isempty(elements(j).usagePageValue) && (elements(j).usagePageValue==axisUsagePageValue) && any(ismember(elements(j).usageValue, axisUsageValues)) axisIndices=[axisIndices j]; %#ok end end deviceStructs(gamepadIndices(i)).axisIndices = axisIndices; % Get the indices of the hat elements. hatIndices=[]; for j=1:length(elements) if ~isempty(elements(j).usagePageValue) && (elements(j).usagePageValue==hatswitchUsagePageValue) && any(ismember(elements(j).usageValue, hastSwitchUsageValues)) hatIndices=[hatIndices j]; %#ok end end deviceStructs(gamepadIndices(i)).hatIndices = hatIndices; end end % OSX % End of first-time initialization. end % Command dispatch: For speed reasons, we first check for the most % frequently used - and most time critical - configuration, the one % that's most likely to be inside a realtime trial loop: % Step 1: Argument assignment and remapping for compatibility with old % Joystick function... if nargin == 3 % Commands with three arguments perform query of device state: if ischar(arg1) subCommand=upper(arg1); argVal1=arg2; argVal2=arg3; else subCommand=upper(arg2); argVal1=arg1; argVal2=arg3; end else if nargin == 2 % Command with two arguments: Configuration query: argVal2=[]; if ischar(arg1) subCommand=upper(arg1); argVal1=arg2; else subCommand=upper(arg2); argVal1=arg1; end else if nargin == 1 subCommand=upper(arg1); argVal1=[]; argVal2=[]; else if nargin == 0 fprintf('Usage:\n'); fprintf('\n'); fprintf('%%Get information on gamepad availability.\n'); fprintf('numGamepads = Gamepad(''GetNumGamepads'')\n'); fprintf('gamepadName = Gamepad(''GetGamepadNamesFromIndices'', gamepadIndices)\n'); fprintf('gamepadIndices = Gamepad(''GetGamepadIndicesFromNames'', joystickName)\n'); fprintf('\n'); fprintf('%%Get information on gamepad configuration.\n'); fprintf('numButtons = Gamepad(''GetNumButtons'', gamepadIndex)\n'); fprintf('numAxes = Gamepad(''GetNumAxes'', gamepadIndex)\n'); fprintf('numBalls = Gamepad(''GetNumBalls'', gamepadIndex)\n'); fprintf('numHats = Gamepad(''GetNumHats'', gamepadIndex)\n'); fprintf('\n'); fprintf('%%Read gamepad states.\n'); fprintf('buttonState = Gamepad(''GetButton'', gamepadIndex, buttonIndex)\n'); fprintf('axisState = Gamepad(''GetAxis'', gamepadIndex, axisIndex)\n'); fprintf('[deltaX, deltaY] = Gamepad(''GetBall'', gamepadIndex, ballIndex)\n'); fprintf('hatPosition = Gamepad(''GetHat'', gamepadIndex, hatIndex)\n'); fprintf('\n'); fprintf('%%Retrieve low-level handles for fast raw access to elements.\n') fprintf('handles = Gamepad(''GetButtonRawMapping'', gamepadIndex, buttonIndex)\n'); fprintf('handles = Gamepad(''GetAxisRawMapping'', gamepadIndex, axisIndex)\n'); fprintf('handles = Gamepad(''GetHatRawMapping'', gamepadIndex, hatIndex)\n'); fprintf('\n'); fprintf('%%Unplug a gamepad.\n'); fprintf('Gamepad(''Unplug'')\n'); fprintf('\n'); return; else error('Invalid number of arguments (greater than three) provided!'); end end end end % Step 2: Subcommand dispatch. Again, three parameter "realtime" % commands are first - in case this matters for switch-times: switch subCommand case {'GETBUTTON'} % Argument checking is too expensive for realtime-path. We % 'try' if command works. On failure due to invalid params, the % 'catch' pathway will provide post-hoc explanation why it % failed. try gi = gamepadIndices(argVal1); ei = deviceStructs(gi).buttonIndices(argVal2); if IsLinux [d1,d2,b] = GetMouse([], gi); result = b(ei); else result = PsychHID('RawState', gi, ei); end catch if nargin ~= 3 error('incorrect number of arguments supplied'); end if ~isa(argVal1, 'double') || length(argVal1) ~= 1 || ~isa(argVal2, 'double') || length(argVal2) ~= 1 error('1x1 double argument expected'); end if argVal1 > length(gamepadIndices) error('invalid gamepad index'); end if argVal2 > deviceStructs(gamepadIndices(argVal1)).buttons error('invalid button index'); end end return case {'GETAXIS'} try gi = gamepadIndices(argVal1); ei = deviceStructs(gi).axisIndices(argVal2); if IsLinux [d1,d2,d3,d4,v] = GetMouse([], gi); rawState = v(ei); else rawState = PsychHID('RawState', gi, ei); end hidMin=deviceStructs(gi).elements(ei).rangeMin; hidMax=deviceStructs(gi).elements(ei).rangeMax; result = (rawState-hidMin)/(hidMax-hidMin) * (joyMax-joyMin) + joyMin; catch if nargin ~= 3 error('incorrect number of arguments supplied'); end if ~isa(argVal1, 'double') || length(argVal1) ~= 1 || ~isa(argVal2, 'double') || length(argVal2) ~= 1 error('1x1 double arguments expected'); end if argVal1 > length(gamepadIndices) error('invalid gamepad index'); end if argVal2 > deviceStructs(gamepadIndices(argVal1)).axes error('invalid axis index') end end return case {'GETHAT'} try gi = gamepadIndices(argVal1); ei = deviceStructs(gi).hatIndices(argVal2); if IsLinux error('Sorry, GetHat function unsupported on Linux.'); else result = PsychHID('RawState', gi, ei); end catch if nargin ~= 3 error('incorrect number of arguments supplied'); end if ~isa(argVal1, 'double') || length(argVal1) ~= 1 || ~isa(argVal2, 'double') || length(argVal2) ~= 1 error('1x1 double argument expected'); end if argVal1 > length(gamepadIndices) error('invalid gamepad index'); end if argVal2 > deviceStructs(gamepadIndices(argVal1)).hats error('invalid hat index') end end return case {'GETBALL'} if nargin ~= 3 error('incorrect number of arguments supplied'); end if ~isa(argVal1, 'double') || length(argVal1) ~= 1 || ~isa(argVal2, 'double') || length(argVal2) ~= 1 error('1x1 double argument expected'); end if argVal1 > length(gamepadIndices) error('invalid gamepad index'); end %we don't support balls because we do not know what they are. error('Sorry, GetBall function not implemented yet.'); case {'GETAXISRAWMAPPING'} % We call ourselves on the corresponding slow-path recursively. % This will trigger error-checking etc. and store the relevant raw % handles inside gi and ei. x = Gamepad('GetAxis', argVal1, argVal2); % Return the handles: result = [gi ei]; return; case {'GETBUTTONRAWMAPPING'} % We call ourselves on the corresponding slow-path recursively. % This will trigger error-checking etc. and store the relevant raw % handles inside gi and ei. x = Gamepad('GetButton', argVal1, argVal2); % Return the handles: result = [gi ei]; return; case {'GETHATRAWMAPPING'} % We call ourselves on the corresponding slow-path recursively. % This will trigger error-checking etc. and store the relevant raw % handles inside gi and ei. x = Gamepad('GetHat', argVal1, argVal2); % Return the handles: result = [gi ei]; return; case {'GETNUMJOYSTICKS','GETNUMGAMEPADS'} if nargin > 1 error('too many arguments supplied'); end result = length(gamepadIndices); return case {'GETJOYSTICKNAME', 'GETGAMEPADNAMESFROMINDICES'} if nargin ~= 2 error('incorrect number of arguments supplied'); end for i = 1:length(argVal1) if argVal1(i) > length(gamepadIndices) error('invalid gamepad index'); end nameArray{i}=deviceStructs(gamepadIndices(argVal1(i))).product; %#ok end result=nameArray; return case {'GETJOYSTICKNUMBERSFROMNAME', 'GETGAMEPADINDICESFROMNAMES'} if nargin ~= 2 error('incorrect number of arguments supplied'); end if ~(iscell(argVal1) || ischar(argVal1)) error('wrong argument type supplied; type char or cell array expected'); end numList=[]; if ischar(argVal1) argVal1={argVal1}; end %iterate over list of device names for i = 1:length(argVal1) if ~ischar(argVal1{i}) error('supplied cell array argument has wrong element type, char expected'); end %iterate over list of joystick indices for j =1:length(gamepadIndices) if strcmpi(argVal1{i}, deviceStructs(gamepadIndices(j)).product) numList=[numList j]; %#ok end end end result=numList; return case {'GETNUMBUTTONS', 'GETNUMAXES', 'GETNUMBALLS', 'GETNUMHATS'} if nargin ~= 2 error('incorret number of arguments supplied'); end if ~isa(argVal1, 'double') || length(argVal1) ~= 1 error('1x1 double argument expected'); end if argVal1 > length(gamepadIndices) error('invalid gamepad index'); end switch upper(subCommand) case {'GETNUMBUTTONS'} result = length(deviceStructs(gamepadIndices(argVal1)).buttonIndices); case {'GETNUMAXES'} result = length(deviceStructs(gamepadIndices(argVal1)).axisIndices); case {'GETNUMBALLS'} result = 0; %Don't know what are the HID usage and usage page values for what SDL calls a "ball". The OSX SDL source does not say. case {'GETNUMHATS'} result = length(deviceStructs(gamepadIndices(argVal1)).hatIndices); end return case {'UNPLUG'} if IsOctave warning('Tried to call Gamepad(''Unplug''); which is unsupported under Octave. Ignored.'); return; end if IsLinux warning('Called Gamepad(''Unplug''); - On Linx this implies a ''clear Screen'' aka closing all windows.'); clear Screen; end clear PsychHID; clear GamePad; return end %switch % No "action" subcommand detected. Let's check if its a request for % online help instead: %display command-specific help strings and return. This is not the %usual way to provide documenation in .m function, but Gamepad %emulates the old Joystick mex, so we we do this. if ismember(upper(subCommand), upper(allGamepadHelpRequests)) if nargout==1 result=nan; %if invoked by Joystick wrapper end switch upper(subCommand) case{'GETNUMJOYSTICKS?', 'GETNUMGAMEPADS?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('numGamepads = Gamepad(''GetNumGamepads'')\n'); fprintf('\n'); fprintf(' Get the number of gamepads connected to the system. Each gamepad is assigned\n'); fprintf(' an index in the range of 1 to the value returned by ''GetNumGamepads''. Use the\n'); fprintf(' assigned index to refer to a specific gamepad when calling Gamepad subfunctions\n'); fprintf(' which read the gamepad state, such as ''GetButtons''. Assigned indices change when\n'); fprintf(' you unplug or add gamepads, or reboot your computer. Therefore, you should not\n'); fprintf(' code index values into your scripts. Instead, use Gamepad subfunction\n'); fprintf(' ''GetGamepadIndexFromName'' to identify a particular model of gamepad.\n'); fprintf('\n'); return case{'GETJOYSTICKNAME?', 'GETGAMEPADNAMESFROMINDICES?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('GamepadNames = Gamepad(''GetGamepadNamesFromNumbers'', gamepadIndices)\n'); fprintf('\n'); fprintf('Given a vector of gamepad indices return a cell array of gamepad names. The gamepad\n'); fprintf('name is the same as the product field of the HID device structure returned by PsychHID,\n'); fprintf('the name of the device assigned by the manufacturer; Identical joysticks should report\n'); fprintf('the same device name. Gamepads are indexed beginning with 1 up to the number of\n'); fprintf('connected joysticks. Use Gamepad(''GetNumGamepads'') to find the number of connected\n'); fprintf('gamepads.\n'); fprintf('\n'); return case{'GETJOYSTICKNUMBERSFROMNAME?', 'GETGAMEPADINDICESFROMNAMES?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('gamepadIndices = Gamepad(''GetGamepadNumbersFromNames'', gamepadNames)\n'); fprintf('\n'); fprintf('Given string or cell array of strings holding gamepad names return a vector\n'); fprintf('of the indices of all gameads with those names. The gamepad name is the same as the\n'); fprintf('product field of the HID device structure returned by PsychHID, the name of the device \n'); fprintf('assigned by the manufacturer; Identical joysticks should report\n'); fprintf('the same device name.\n'); fprintf('\n'); return case{'GETNUMBUTTONS?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('numButtons = Gamepad(''GetNumButtons'', gamepadIndex)\n'); fprintf('\n'); fprintf('Given a gamepad number return the number of buttons on the gamepad.\n'); fprintf('Gamepad(''GetButton'' will return the state of any button.\n'); fprintf('\n'); return case{'GETNUMAXES?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('\n'); fprintf('numAxes = Gamepad(''GetNumAxes'', gamepadIndex)\n'); fprintf('Given a gamepad index return the number of Axes on the gamepad.\n'); fprintf('Gamepad(''GetAxis'') will return the state of any axis.\n'); fprintf('\n'); return case{'GETNUMBALLS?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('\n'); fprintf('numBalls = Gamepad(''GetNumBalls'', gamepadIndex)\n'); fprintf('Given a gamepad index return the number of balls on the gamepad.\n'); fprintf('Gamepad(''GetBall'') will return the state of any ball.\n'); fprintf('\n'); return case{'GETNUMHATS?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('numHats = Gamepad(''GetNumHats'', gamepadIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index return the number of hats on the gamepad.\n'); fprintf('Gamepad(''GetHat'') will return the state of any hat.\n'); fprintf('\n'); return case{'GETBUTTON?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('buttonState = Gamepad(''GetButton'',gamepadIndex, buttonIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and a button index, return the immediate state of the\n'); fprintf('specified button on the specified gamepad. Use ''GetNumGamepads'' and\n'); fprintf('''GetNumButtons'' to find the maximum legal values for gamepadIndex and\n'); fprintf('buttonIndex arguments. The first gamepad and the first button are index 1. It\n'); fprintf('is an error to call ''GetButton'' if the specified gamepad has no buttons.\n'); fprintf('\n'); return case{'GETAXIS?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('axisState = Gamepad(''GetAxis'', gamepadIndex,axisIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and an axis index, return the immediate state of the\n'); fprintf('specified axis on the specified gamepad. The returned value axisState is an\n'); fprintf('integer (-32768 to 32768) representing the current position of the axis. It\n'); fprintf('might be necessary to impose tolerances on the axisState value to ignore\n'); fprintf('jitter.Use ''GetNumGamepads'' and ''GetNumAxes'' to determine maximum legal values\n'); fprintf('for gamepadIndex and axisIndex arguments. The first gamepad\n'); fprintf('and the first axis are numbered 1. It is an error to call ''GetAxis'' if the\n'); fprintf('specified gamepad has no axes.\n'); fprintf('\n'); return case{'GETAXISRAWMAPPING?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('handles = Gamepad(''GetAxisRawMapping'', gamepadIndex,axisIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and an axis index, returns low-level handles to the \n'); fprintf('specified axis on the specified gamepad.\n'); fprintf('You can query the raw state of the axis via rawState = PsychHID(''RawState'', handles(1), handles(2));\n'); fprintf('on OS/X. On Linux you can call [d1,d2,d3,d4,v] = GetMouse([], handles(1)); rawState = v(handles(2));.\n'); fprintf('This is significantly faster than calling the ''GetAxis'' function, as it bypasses all error-checking\n'); fprintf('and remapping of raw device values to the normalized range of (-32768 to 32768).\n\n'); return case{'GETBUTTONRAWMAPPING?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('handles = Gamepad(''GetButtonRawMapping'', gamepadIndex,axisIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and a button index, returns low-level handles to the \n'); fprintf('specified button on the specified gamepad.\n'); fprintf('You can query the raw state of the button via rawState = PsychHID(''RawState'', handles(1), handles(2));\n'); fprintf('on OS/X. On Linux you can call [d1,d2,b] = GetMouse([], handles(1)); rawState = b(handles(2));.\n'); fprintf('This is significantly faster than calling the ''GetButton'' function, as it bypasses all error-checking\n'); fprintf('and remapping of raw device values.\n\n'); return case{'GETHATRAWMAPPING?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('handles = Gamepad(''GetHatRawMapping'', gamepadIndex,axisIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and a hat index, returns low-level handles to the \n'); fprintf('specified hat on the specified gamepad.\n'); fprintf('You can query the raw state of the hat via rawState = PsychHID(''RawState'', handles(1), handles(2));\n'); fprintf('This is significantly faster than calling the ''GetHat'' function, as it bypasses all error-checking\n'); fprintf('and remapping of raw device values.\n\n'); return case{'GETBALL?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('[deltaX, deltaY] = Gamepad(''GetBall'',gamepadIndex,ballIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and a trackball index, return the change in the\n'); fprintf('trackball X and Y positions since the previous call to ''GetBall''.\n'); fprintf('Use ''GetNumGamepads'' and ''GetNumBalls'' to determine maximum legal values for\n'); fprintf('gamepadIndex and gallIndex arguments. The first gamepad and\n'); fprintf('the first ball are numbered 1. It is an error to call ''GetBall'' if the specified\n'); fprintf('gamepad has no ball elements. On OSX Gamepad does not support ball elements. If\n'); fprintf('you have a gamepad with a ball, report the gamepad model and we will add support.\n'); fprintf('\n'); return case{'GETHAT?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('hatState = Gamepad(''GetHat'',gamepadIndex, hatIndex)\n'); fprintf('\n'); fprintf('Given a gamepad index and a hat index, return the immediate state of the\n'); fprintf('specified hat on the specified gamepad. Use ''GetNumGamepads'' and\n'); fprintf('''GetNumHats'' to find the maximum legal values for gamepadIndex and\n'); fprintf('hatIndex arguments. The first gamepad and the first hat are index 1. It\n'); fprintf('is an error to call ''GetHat'' if the specified gamepad has no hats.\n'); fprintf('hatState is an integer in the range 1-9 indicting at which of eight \n'); fprintf('compass points or center the hat switch is positioned. see "help Gamepad"\n'); fprintf('for a list of functions such as "HatUp" which return constants for named\n'); fprintf('compass points.\n'); fprintf('\n'); return case{'UNPLUG?'} fprintf('Usage:\n'); fprintf('\n'); fprintf('Gamepad(''Unplug'')\n'); fprintf('\n'); fprintf('Resets the internal state of Gamepad function. Call before plugging or\n'); fprintf('unplugging gamepads. Unsupported with GNU/Octave, problematic on Linux!\n'); fprintf('\n'); return end %switch else % No recognized command at all: error('Invalid or unknown/unsupported subcommand. Check for typos!'); end