/*
    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, usually the x position of the pointer associated with the pointing device at event delivery.\n"
        "'Y' = For 'Type' 1 motion events, usually the y position of the pointer associated with the pointing device at event delivery.\n"
        "If raw event delivery is requested during the call to 'KbQueueCreate', depending on operating system, 'X' and 'Y' may "
        "not always report mouse cursor position, but something else, e.g., raw movement deltas - just like Valuators 1 and 2.\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.\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 encode the equivalent of 'X' and 'Y', but in operating-system + device specific coordinates, ie. "
        "not neccessarily in units of screen pixels. If raw event delivery is requested, those valuators may report "
        "movement deltas instead of absolute positions, e.g., not absolute mouse position but how much the mouse position "
        "has changed since the last reported event.\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);
}
