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:

The last value set for a mouse filed is kept between main() iterations. Unless mouse_passthru() is called, which will overwrite the value set by the script.

Meaning:

If you use mouse_set() function to alter the mouse status (moving mouse/ pressing buttons) you need to always set all inputs each time (x,y,button,wheels) for the mouse to get no unwanted mouse movements/states.

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: 2024/04/07 03:00 by Scachi

(This work is NOT endorsed by, sponsored by, or affiliated with any game publisher or trademark holder. All trademarks are the property of their respective owners. Some game publishers may restrict the use of third-party peripherals; please refer to the applicable game's Terms of Use. Users are responsible for ensuring their compliance with any applicable game rules or restrictions.)