t2:gpc_scripting:usb_hid

USB HID

The Output Protocol “USB Multi Interface HID” is a bit special.
It allows the Output to be send as keyboard, mouse and gamepad controls. The connect console/PC on the T2 Output Port will see the T2 as a keyboard/mouse.

This requires different scripting approaches than the usual console controller output protocols. Instead of “set_val” you have to use mouse_set (for mouse output) or key_set (for keyboard output).

Utilizing this “USB Multi Interface HID” Output Protocol you can do scripting with the T2 for the PC. Pablosscripts created a forum post with some information about it: Pablo's Beginners Guide to Scripting for PC

You can find a few scripts for this protocol in the Online Resource within GTuner IV: Search for “usb-hid”.
Some USB HID Script specific links:
Universal HID Gamepack (USB Multi Interface HID)
USB-HID Anti Recoil (USB Multi Interface HID)
USB-HID Gamepad 2 Keyboard+Mouse (USB Multi Interface HID)

GPC functions

Important GPC functions for USB HID protocol usage:
Keyboard: keymapping key_passthru key_check key_status key_get key_set
Mouse: mousemapping mouse_passthru mouse_status mouse_get mouse_set

When you want to forward mouse input or keyboard input use the corresponding _passthru function.
As soon as you want to alter the input before outputting it you need to be careful:

Combination of mouse_passthru() with mouse_set() : The first function will overwrite the output buffer with the latest data received from the connected mouse

More information:
mouse_passthru and mouse_set
mouse_set: always set all mouse ouputs -> X/Y/Wheel/Buttons

Examples

Basic

A very basic example to forward all mouse and keyboard input to the output port will look like this:

init{
  mousemapping(); // clears defaultt T2 mouse mappings
  keymapping(); // clears default T2 keyboard mappings
}
main{
  mouse_passthru(); // forward mouse input to output
  key_passthru(); // forward keyboard input to output
}

Anti Recoil

When mouse button 1 is pressed the anti recoil will be applied.

#include <mouse.gph>
 
// configuration 
// note: when a value of 1 is still to strong anti recoil try a higher value for mouse_speed
const int mouse_speed = 10; // <- should be around 10 or higher, a value too low can stop the mouse from working
int AntiRecoil_X = 0; // anti recoil horizontal
int AntiRecoil_Y = 1; // anti recoil vertical
 
 
// internal
int32 X, Y, WHEEL;
int32 RX, RY;
 
init {
  keymapping();
  mousemapping();
}
 
main {
  key_passthru();
 
  RX = 0; RY = 0;
  X = 0; Y = 0; WHEEL = 0;
 
  if(mouse_status(MREPORT_UPDATED)) {
      mouse_passthru(); // only passthru when there is data to send
      X = mouse_status(MOUSE_X);
      Y = mouse_status(MOUSE_Y);
      WHEEL = mouse_status(MOUSE_WHEEL);
  }
 
  if(mouse_status(MBUTTON_1))
  {
    if(!(system_time()%mouse_speed)) {
        RX = AntiRecoil_X;
        RY = AntiRecoil_Y;
        mouse_set(MOUSE_X, X+RX);
        mouse_set(MOUSE_Y, Y+RY);
        mouse_set(MOUSE_WHEEL,WHEEL);
    }
  }
}

Anti Recoil Decimal

When mouse button 1 is pressed the anti recoil will be applied, supporting decimal/fix32 values.

#include <mouse.gph>
 
// configuration 
fix32 antirecoil_X = 0.0; // anti recoil horizontal
fix32 antirecoil_Y = 0.5; // anti recoil vertical
 
// advanced configuration
const int MOUSE_SPEED = 10; // <- should be around 10 or higher, a value too low can stop the mouse from working
 
// internal
uint32 ARTIMER;
int32 X, Y, WHEEL;
int32 RX, RY;
fix32 ARX, ARY;
 
init {
    keymapping();
    mousemapping();
}
 
main {
    key_passthru();
 
    X = 0; Y = 0; WHEEL = 0; 
    RX = 0; RY = 0;
 
    if(mouse_status(MREPORT_UPDATED)) {
        mouse_passthru(); // only passthru when there is data to send
        X = mouse_status(MOUSE_X);
        Y = mouse_status(MOUSE_Y);
        WHEEL = mouse_status(MOUSE_WHEEL);
    }
 
    if(mouse_status(MBUTTON_1))
    {
        ARTIMER += elapsed_time();
 
        if(!(ARTIMER%MOUSE_SPEED)) {
            ARX += (fix32)(antirecoil_X);
            ARY += (fix32)(antirecoil_Y);
 
            if (antirecoil_X < 0.0) RX += (int)ceil((ARX));
            else if (antirecoil_X > 0.0) RX += (int)floor((ARX));
 
            if (antirecoil_Y < 0.0) RY += (int)ceil((ARY));
            else if (antirecoil_Y > 0.0) RY += (int)floor((ARY));
 
            mouse_set(MOUSE_X, X+RX);
            mouse_set(MOUSE_Y, Y+RY);
            mouse_set(MOUSE_WHEEL,WHEEL);
            ARX = mod(ARX,1.0);
            ARY = mod(ARY,1.0);
        }
    } else {
        ARTIMER = MOUSE_SPEED;
        ARX = 0.0; ARY = 0.0;
    }
}

Controller to Keyboard

Mapping controller input to keyboard HID output.

Basic version

#include <keyboard.gph>
#include <mouse.gph>
 
init {
    keymapping();
    mousemapping();
}
main {
    key_passthru();
    if(mouse_status(MREPORT_UPDATED)) {
        mouse_passthru();
    }
 
    // dpad up mapping to key E
    if(is_active(BUTTON_10)) key_set(KEY_E, TRUE);
}

Extended version

To make sure the key is released on release of the button as using KMG capture the key may not be reported as released automatically.

#include <keyboard.gph>
#include <mouse.gph>
 
init {
    keymapping();
    mousemapping();
}
main {
    key_passthru();
    if(mouse_status(MREPORT_UPDATED)) {
        mouse_passthru();
    }
 
    // dpad up mapping to key E
    if(is_active(BUTTON_10)) { 
        keySet(KEY_E, TRUE); // press
    }
    if (event_release(BUTTON_10)) {
        keySet(KEY_E, FALSE); // release
    }
}
 
void keySet(uint8 key, bool flag) {
    if (key_get(key) != flag) {
        key_set(key, flag);
    }
}

Keyboard to Keyboard

Mapping keyboard input to keyboard HID output. Useful for some games where you can't change the key assigned to actions.

#include <keyboard.gph>
#include <mouse.gph>
 
init {
    port_connect(PORT_USB_C, PROTOCOL_HID);
    keymapping();
    mousemapping();
}
 
 
main {
    key_passthru();
    if(mouse_status(MREPORT_UPDATED)) {
        mouse_passthru();
    }
 
    // shift <-> ctrl
    keyMap(KEY_LEFTSHIFT, KEY_LEFTCONTROL);
    keyMap(KEY_LEFTCONTROL, KEY_LEFTSHIFT, FALSE, KEY_LEFTSHIFT); // <-- for circular mapping
 
    // additional shift mapping : alt -> shift
    keyMap(KEY_LEFTALT, KEY_LEFTSHIFT, TRUE); // <-- for additional key to same destination
 
    // caps -> alt
    keyMap(KEY_CAPSLOCK, KEY_LEFTALT);
 
    // left-> page down
    keyMap(KEY_LEFTARROW, KEY_PAGEDOWN);
 
    // right-> page up
    keyMap(KEY_RIGHTARROW, KEY_PAGEUP);
}
 
 
void keyMap(uint8 keySrc, uint8 keyDst, bool noset, uint8 keyCheck) {
    if (key_status(keySrc)) {
        if (!keyCheck) key_set(keySrc, FALSE);
        else if (!key_status(keyCheck)) key_set(keySrc, FALSE);
        keySet(keyDst, TRUE);
    }
    else if (!noset) key_set(keyDst, FALSE);
}
 
void keySet(uint8 key, bool flag) {
    if (key_get(key) != flag) {
        key_set(key, flag);
    }
}
t2/gpc_scripting/usb_hid.txt · Last modified: 2021/03/27 05:53 by scachi