/*
    PsychtoolboxGL/Source/Common/PsychHID/PsychHIDKbQueueCheck.c

    PROJECTS:

        PsychHID only.

    PLATFORMS:

        All.

    AUTHORS:

        rwoods@ucla.edu                 rpw
        mario.kleiner.de@gmail.com      mk

    HISTORY:
        8/19/07  rpw        Created.
        8/23/07  rpw        Added PsychHIDQueueFlush to documentation; removed call to PsychHIDVerifyInit()

*/

#include "PsychHID.h"

PsychError PSYCHHIDKbQueueCheck(void)
{
    static char useString[] = "[keyIsDown, firstKeyPressTimes, firstKeyReleaseTimes, lastKeyPressTimes, lastKeyReleaseTimes]=PsychHID('KbQueueCheck' [, deviceIndex])";
    static char synopsisString[] =
        "Checks a queue for keyboard or button events generated by a device.\n"
        "PsychHID('KbQueueCreate') must be called before this routine "
        "and PsychHID('KbQueueStart') must then be called for any events "
        "to be returned.\n"
        "The optional 'deviceIndex' is the index of the HID input device whose queue should be checked. "
        "If omitted, the queue of the default device will be checked.\n";

    static char seeAlsoString[] = "KbQueueCreate, KbQueueStart, KbQueueStop, KbQueueFlush, KbQueueRelease";

    int deviceIndex;

    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if (PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(5));
    PsychErrorExit(PsychCapNumInputArgs(1));

    deviceIndex = -1;
    PsychCopyInIntegerArg(1, kPsychArgOptional, &deviceIndex);

    PsychHIDOSKbQueueCheck(deviceIndex);

    return(PsychError_none);
}

PsychError PSYCHHIDKbQueueGetEvent(void)
{
    static char useString[] = "[event, navail] = PsychHID('KbQueueGetEvent' [, deviceIndex][, maxWaitTimeSecs=0])";
    static char synopsisString[] =
        "Checks a queue for input events generated by a device.\n"
        "PsychHID('KbQueueCreate') must be called before this routine and PsychHID('KbQueueStart') "
        "must then be called for any events to get recorded into the event buffer.\n"
        "The optional 'deviceIndex' is the index of the HID input device whose queue should be queried. "
        "If omitted, the queue of the default device will be queried.\n"
        "'maxWaitTimeSecs' is an optional maximum wait time for a new event in seconds. "
        "It defaults to zero, which means to just poll for a pending event. A positive value "
        "will wait until either at least one event arrived or the given amount of time elapses, "
        "whatever comes first.\n"
        "If there are any events queued, the oldest one is returned in the struct "
        "'event', otherwise an empty matrix is returned. The number of queued events "
        "remaining in the queue after fetching is returned in 'navail'.\n"
        "The returned 'event' struct, if any, currently contains the following fields:\n\n"
        "'Type' = Event type:\n"
        " 0 = Key/Button press/release on a keyboard, keypad, mouse, joystick, gamepad, digitizer tablet etc.\n"
        " 1 = mouse pointer, joystick, gamepad, digitizer tablet tool motion or change of some other property.\n"
        " 2 = A new touch point shows up on a touch-screen, e.g., finger making contact with surface.\n"
        " 3 = Touch point changes properties, e.g., finger moves, changes pressure, distance or contact area.\n"
        " 4 = Touch point disappears, e.g., finger lifted from touch-screen surface.\n"
        " 5 = Touch sequence failure: Some other higher priority entity has cut us off from the touch data stream. "
        "On reception of this type of event, one should wait a bit, then Flush the event buffer and somehow "
        "handle the failure in data reception, e.g., mark trial invalid, notify experimenter of trouble.\n"
        "'Time' = The GetSecs time when the event was received.\n"
        "'Keycode' = The KbCheck / KbName style keycode of the key, or the number of the button that "
        "triggered this event on non-keyboard devices. The unique touch id of a contact on a touch-screen. "
        "0 for pure motion events or other non-press/release events.\n"
        "'Pressed' = 1 for a key/button/finger press event, 0 for a release event. For non-press/release events, "
        "e.g., mouse or joystick movements, it may report if any button on that device is pressed, but don't count on it.\n"
        "'CookedKey' = Keycode translated into a GetChar() style ASCII character code. Or zero if key "
        "does not have a corresponding character. Or -1 if mapping is unsupported for given event.\n"
        "'ButtonStates' = A binary value whose different bits signal the state of device buttons, ie.\n"
        "bitand (Buttons, 2^i) > 0 menas that the i'th button on the device was pressed at that time. "
        "Currently only the first 32 buttons on a device are reported, and this feature may only work on Linux "
        "with X11 windowing system for some event types like keyboard, mouse/joystick movements, so use of this "
        "is not portable!\n"
        "'Motion' = 1 if this is a motion event, e.g., mouse, joystick, knob, finger motion, 0 otherwise.\n"
        "'X' = For 'Type' 1 motion events, the x position of the pointer associated with the pointing device at event delivery.\n"
        "'Y' = For 'Type' 1 motion events, the y position of the pointer associated with the pointing device at event delivery.\n"
        "For 'Type' 0 events, this may report the location of the mouse pointer when a keyboard key was pressed or "
        "released, at least on Linux with X11 windowing system, but not neccessarily on all operating systems or "
        "windowing systems, so don't rely on it being portable!\n"
        "For 'Type' 2/3/4 events, the location of the touch point, e.g., finger location on a touch-screen, as mapped "
        "to the native display space of the system. On Linux/X11 and MS-Windows these would be absolute screen pixel "
        "coordinates, just like mouse pointer coordinates. On Linux/Wayland these would be pixel coordinates relative "
        "to the top-left corner of the associated onscreen window. Depending on touch device resolution, these can be "
        "fractional pixel locations, ie. more accurate than 1 pixel.\n"
        "'NormX' and 'NormY' are normalized versions of 'X' and 'Y'. These values are not available for all devices, "
        "or all operating systems. They may just return constant zero. Currently only touch devices "
        "under Linux/X11 return meaningful values: Touch devices are normalized to the range 0.0 - 1.0.\n"
        "'Valuators' = For 'Type' 1 motion events, a vector with the values of various device-specific valuators, e.g., extra "
        "axis, levers or knobs on a joystick or gamepad, or the mouse-wheel position on a mouse, or the touch "
        "pressure on a touchpad, or pen pressure, orientation, hovering distance on a digitizer tablet. The first "
        "two valuators entries encode the equivalent of 'X' and 'Y', but in operating-system + device native coordinates, ie. "
        "not neccessarily in units of screen pixels.\n"
        "The meaning of the different remaining elements of the 'Valuators' vector is completely device specific. "
        "The content is also operating system specific for the same device, so scripts making use of these values "
        "may not be portable across different devices or operating systems or even display systems for the same OS+device.\n"
        "For 'Type' 2/3/4 events, additional device and OS specific info about further touch properties, e.g., contact area "
        "of a finger with the surface, contact pressure, finger orientation, etc. Not portable across devices and operating "
        "systems!\n";
    static char seeAlsoString[] = "KbQueueCreate, KbQueueStart, KbQueueStop, KbQueueFlush, KbQueueRelease";

    int deviceIndex;
    unsigned int navail;
    double maxWaitTimeSecs;

    PsychPushHelp(useString, synopsisString, seeAlsoString);
    if (PsychIsGiveHelp()) {PsychGiveHelp(); return(PsychError_none);};

    PsychErrorExit(PsychCapNumOutputArgs(2));
    PsychErrorExit(PsychCapNumInputArgs(2));

    deviceIndex = -1;
    PsychCopyInIntegerArg(1, kPsychArgOptional, &deviceIndex);

    maxWaitTimeSecs = 0;
    PsychCopyInDoubleArg(2, kPsychArgOptional, &maxWaitTimeSecs);

    // Get next event from buffer, return it as 1st return argument:
    navail = PsychHIDReturnEventFromEventBuffer(deviceIndex, 1, maxWaitTimeSecs);
    PsychCopyOutDoubleArg(2, FALSE, (double)navail);

    return(PsychError_none);
}
