Skip to content
xfangfang edited this page Apr 8, 2025 · 9 revisions

How Does This Plugin Work

By hooking certain functions, remotePad makes the game believe that additional controllers are connected to your console. It simulates the behavior of real controllers by transmitting controller data via WebSocket or USB.

---
config:
  look: handDrawn
---
flowchart TB
 subgraph s1["Clients"]
        n6["Web"]
        n7["..."]
  end
    n2["Game"] <--> n3["RemotePad"]
    n3 <--> n1["PS4 System"] & s1
    n6@{ shape: rounded}
    n7@{ shape: rounded}
    n2@{ shape: rounded}
    n3@{ shape: rounded}
    n1@{ shape: rounded}
    style n2 stroke:#000000,fill:transparent
    style n1 fill:transparent,stroke:#000000
Loading

Adapting to More Clients

remotePad uses JSON-RPC over WebSocket as its communication protocol and provides a simple webpage by default to simulate a controller.

Here is an example of a WebSocket message. You can use any WebSocket-enabled client to send this message to simulate a controller:

Send gamepad data

{"method":"u","params":[0,0,128,128,128,128,0,0,0]}

The 9 numbers in the params array represent:

No. Item Description
1 Controller Index 0, 1, 2, 3
2 Controller Button Values Refer to orbis/_types/pad.h. If multiple buttons are pressed simultaneously, add their values together.
3 Left Stick's X Coordinate Range: 0~255, with 0 representing the left position.
4 Left Stick's Y Coordinate Range: 0~255, with 0 representing the top position.
5 Right Stick's X Coordinate Range: 0~255, with 0 representing the left position.
6 Right Stick's Y Coordinate Range: 0~255, with 0 representing the top position.
7 L2 Button Pressing State Range: 0~255, with 0 representing not pressed and 255 representing fully pressed.
8 R2 Button Pressing State Range: 0~255, with 0 representing not pressed and 255 representing fully pressed.
9 Touch Data Count Range: 0~2. When the count is 0, it indicates no touch. When the count is N, it is followed by N sets of touch data. Each set of touch data consists of three numbers: touch ID (0~127), X coordinate (0~1919), and Y coordinate (0~941).

Note: When pressing trigger buttons (L2/R2), you need to set the controller button values simultaneously; otherwise, the game might not recognize it correctly.

Send notifications

Display a system notification on the PS4.

{"method":"notify","params":["hello world"]}

Get Information

To obtain information about the plugin, you can retrieve details such as the current plugin version after establishing the connection.

  • sent to server
{"id": 1, "method":"info","params":[]}
  • received from server
{"id": 1, "result": {"version": "1.2.0"} }

Get vibration data

It is recommended to set a timeout for each data to avoid the inability to stop the vibration due to packet loss.

  • received from server
{"method":"v","params":[0, 0, 0]}

The three numbers in the params array represent: Controller index (0,1,2,3), Vibration for the large motor (0-255), Vibration for the small motor (0-255)

Get light bar data

  • received from server
{"method":"l","params":[0, 0, 0, 0]}

The four numbers in the params array represent: Controller index (0,1,2,3), R, G, B

Reset light bar

  • received from server
{"method":"rl","params":[0]}

The number in the params array represent: Controller index (0,1,2,3)

When a request to reset the controller's light bar color is received, restore the light bar to its default color. 0 for Blue, 1 for Red, 2 for Green, and 3 for Pink


Now you can easily create a RemotePad client on devices like the Switch, PS Vita, 3DS, etc., or modify the existing web client to implement some interesting control methods. Feel free to submit an issue to share your creations with the community.

Adapting to Other Protocols

remotePad separates the protocol part into what it calls a "driver." You can easily implement a new driver to adapt to other protocols. Here's an example:

For instance, if you want to implement a UDP-based protocol to minimize controller latency as much as possible:

  1. Copy src/pad/dummy.c to src/pad/udp.c.
  2. Rename the dummyDriver variable to udpDriver. Similarly, change other function names to have a udp prefix.
  3. Implement your UDP service in the udpInit function. (Note that you need to create a new thread to run the UDP service.)
  4. Refer to ws.c to implement the remaining functions.
  5. Add your udpDriver to the padDrivers list in pad.c.
  6. Configure remote_pad.ini to use your driver.

Note1: You don't need to implement every function. All unimplemented functions will default to calling the corresponding functions in the dummy driver. For example, you don't need to implement read and readState, but simply call pushPadData(...) when gamepad data comes. This makes the implementation of the new driver much simpler. Basically, you only need to write the code related to communication.

Note2: All functions that need to be implemented may be called by different threads, but other parts of remotePad ensure that they are mutually exclusive. You don't need to set up mutexes yourself.