I was looking for a way to capture all movements in part of a game and convert this capture to a macro so I could play back this 'recording' several times, using the Gimx adapter. Maybe this could help others
So this is what I did:
I used a DS4 controller, connected to a pc (Windows). And the GIMX adapter between my pc and my PS4.
Used the normal Dualshock4.xml and the GIMX adapter flashed with firmware for DS4.
I used the GIMX software (7.15) to record everything to a log file (Messages: log file)
Some lines of the log.txt file:
0 1565734741.205656, lstick x (-57), lstick y (-126), rstick x (-128), rstick y (33), l3 (255)
0 1565734741.215656, lstick x (-56), lstick y (-127), rstick x (29), rstick y (-10), l3 (255)
0 1565734741.225656, lstick x (-57), lstick y (-127), rstick x (1), rstick y (-5), l3 (255)
0 1565734741.245656, lstick x (-57), lstick y (-128), rstick x (1), rstick y (-5), l3 (255)
0 1565734741.255656, lstick x (-56), lstick y (-128), rstick x (1), rstick y (-5)
What I found out:
- The time difference between two lines is 0.01 second (or 10 ms) (in my case, I think this can differ with other hardware, platforms, usb / bt
- If no key was pressed / released or the position of the axis / stick(s) didn't change during 10 ms, there was no line in log.txt, for example 1565734741.235 is missing
- When a button is (still) pressed, it is logged, for example L3 (255)
- When a button is released, it isn't logged
I used this bash script to convert the log.txt to a sqlite file / csv file.
The log.txt needs to be in the same dir as the script.
How to use:
copy this code to a file (Linux / OSX), for example script.sh
set -x to make script executable with:
Code: Select all
chmod 770 script.sh
start script with:
Code: Select all
script.sh [replace with name of logfile]
for example
Code: Select all
script.sh log.txt
script.sh:
Code: Select all
#!/bin/sh
# check if dir exists
if [ ! -d ./out ]; then
mkdir ./out
fi
if [ ! -d ./temp ]; then
mkdir ./temp
fi
# cleanup
rm -f ./temp/*
rm -f ./out/$1.db
rm -f ./out/$1.csv
# filter only 2nd part of log.txt
cat $1 | grep "^0 15" | sed 's/^0 //' > ./temp/temp
# max 9 fields, change if more
cat ./temp/temp | cut -d\, -f1,2 | grep , > ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f1,3 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f1,4 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f5 | grep -v "^$" | wc -l
cat ./temp/temp | cut -d\, -f1,5 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f6 | grep -v "^$" | wc -l
cat ./temp/temp | cut -d\, -f1,6 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f7 | grep -v "^$" | wc -l
cat ./temp/temp | cut -d\, -f1,7 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f8 | grep -v "^$" | wc -l
cat ./temp/temp | cut -d\, -f1,8 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f9 | grep -v "^$" | wc -l
cat ./temp/temp | cut -d\, -f1,9 | grep , >> ./temp/temp.$1.csv
cat ./temp/temp | cut -d\, -f1 > ./out/$1.tijdstippen.csv
# split axis , buttons
cat ./temp/temp.$1.csv | grep lstick\ x > ./temp/$1.lstickx
cat ./temp/temp.$1.csv | grep lstick\ y > ./temp/$1.lsticky
cat ./temp/temp.$1.csv | grep rstick\ x > ./temp/$1.rstickx
cat ./temp/temp.$1.csv | grep rstick\ y > ./temp/$1.rsticky
cat ./temp/temp.$1.csv | grep l2 > ./temp/$1.l2
cat ./temp/temp.$1.csv | grep r2 > ./temp/$1.r2
cat ./temp/temp.$1.csv | grep -v lstick | grep -v rstick | grep -v l2 | grep -v r2 > ./temp/$1.overig
# create sqlite db
sqlite3 ./out/$1.db << EOF
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
EOF
# insert all timevalues
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text);
.separator ","
.import ./out/$1.tijdstippen.csv _csv_import
INSERT INTO data (tijd) SELECT tijdtemp
FROM _csv_import WHERE 1;
DROP TABLE _csv_import;
EOF
# fill db with values from log
rm -f ./temp/input.csv
cat ./temp/$1.lstickx | sed 's/\ //g' | sed 's/lstickx//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
# import csv
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text, waarde INTEGER);
.separator ","
.import ./temp/input.csv _csv_import
EOF
# all rights for user / group
chmod 770 ./out/$1.db
# import lstickx values
sqlite3 ./out/$1.db << EOF
CREATE TABLE TEST AS
SELECT a.tijd AS tijd, _csv_import.waarde AS ra0,a.ra1,a.ra2,a.ra3,a.ra4,a.ra5,a.ra6,a.ra7,a.aa0,a.aa1,a.aa2,a.aa3,a.aa4,a.aa5,a.aa6,a.aa7,a.aa8,a.aa9,a.aa10,a.aa11,a.aa12,a.aa13,a.aa14,a.aa15,a.aa16,a.aa17,a.aa18,a.aa19
FROM data a LEFT JOIN
_csv_import
ON a.tijd = _csv_import.tijdtemp;
DROP TABLE data;
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
INSERT INTO data (tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17) SELECT tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17
FROM TEST WHERE 1;
DROP TABLE TEST;
DROP TABLE _csv_import;
EOF
# same for lsticky, i am sure this can be done with less code :)
rm -f ./temp/input.csv
cat ./temp/$1.lsticky | sed 's/\ //g' | sed 's/lsticky//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text, waarde INTEGER);
.separator ","
.import ./temp/input.csv _csv_import
EOF
sqlite3 ./out/$1.db << EOF
CREATE TABLE TEST AS
SELECT a.tijd AS tijd,a.ra0,_csv_import.waarde AS ra1,a.ra2,a.ra3,a.ra4,a.ra5,a.ra6,a.ra7,a.aa0,a.aa1,a.aa2,a.aa3,a.aa4,a.aa5,a.aa6,a.aa7,a.aa8,a.aa9,a.aa10,a.aa11,a.aa12,a.aa13,a.aa14,a.aa15,a.aa16,a.aa17,a.aa18,a.aa19
FROM data a LEFT JOIN
_csv_import
ON a.tijd = _csv_import.tijdtemp;
DROP TABLE data;
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
INSERT INTO data (tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17) SELECT tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17
FROM TEST WHERE 1;
DROP TABLE TEST;
DROP TABLE _csv_import;
EOF
# rstickx
rm -f ./temp/input.csv
cat ./temp/$1.rstickx | sed 's/\ //g' | sed 's/rstickx//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text, waarde INTEGER);
.separator ","
.import ./temp/input.csv _csv_import
EOF
sqlite3 ./out/$1.db << EOF
CREATE TABLE TEST AS
SELECT a.tijd AS tijd,a.ra0,a.ra1,_csv_import.waarde AS ra2,a.ra3,a.ra4,a.ra5,a.ra6,a.ra7,a.aa0,a.aa1,a.aa2,a.aa3,a.aa4,a.aa5,a.aa6,a.aa7,a.aa8,a.aa9,a.aa10,a.aa11,a.aa12,a.aa13,a.aa14,a.aa15,a.aa16,a.aa17,a.aa18,a.aa19
FROM data a LEFT JOIN
_csv_import
ON a.tijd = _csv_import.tijdtemp;
DROP TABLE data;
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
INSERT INTO data (tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17) SELECT tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17
FROM TEST WHERE 1;
DROP TABLE TEST;
DROP TABLE _csv_import;
EOF
# rsticky
rm -f ./temp/input.csv
cat ./temp/$1.rsticky | sed 's/\ //g' | sed 's/rsticky//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text, waarde INTEGER);
.separator ","
.import ./temp/input.csv _csv_import
EOF
sqlite3 ./out/$1.db << EOF
CREATE TABLE TEST AS
SELECT a.tijd AS tijd,a.ra0,a.ra1,a.ra2,_csv_import.waarde AS ra3,a.ra4,a.ra5,a.ra6,a.ra7,a.aa0,a.aa1,a.aa2,a.aa3,a.aa4,a.aa5,a.aa6,a.aa7,a.aa8,a.aa9,a.aa10,a.aa11,a.aa12,a.aa13,a.aa14,a.aa15,a.aa16,a.aa17,a.aa18,a.aa19
FROM data a LEFT JOIN
_csv_import
ON a.tijd = _csv_import.tijdtemp;
DROP TABLE data;
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
INSERT INTO data (tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17) SELECT tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17
FROM TEST WHERE 1;
DROP TABLE TEST;
DROP TABLE _csv_import;
EOF
# L2
rm -f ./temp/input.csv
cat ./temp/$1.l2 | sed 's/\ //g' | sed 's/l2//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text, waarde INTEGER);
.separator ","
.import ./temp/input.csv _csv_import
EOF
sqlite3 ./out/$1.db << EOF
CREATE TABLE TEST AS
SELECT a.tijd AS tijd,a.ra0,a.ra1,a.ra2,ra3,a.ra4,a.ra5,a.ra6,a.ra7,a.aa0,a.aa1,a.aa2,a.aa3,a.aa4,a.aa5,a.aa6,a.aa7,a.aa8,a.aa9,a.aa10,a.aa11,a.aa12,_csv_import.waarde AS aa13,a.aa14,a.aa15,a.aa16,a.aa17,a.aa18,a.aa19
FROM data a LEFT JOIN
_csv_import
ON a.tijd = _csv_import.tijdtemp;
DROP TABLE data;
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
INSERT INTO data (tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17) SELECT tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17
FROM TEST WHERE 1;
DROP TABLE TEST;
DROP TABLE _csv_import;
EOF
# R2
rm -f ./temp/input.csv
cat ./temp/$1.r2 | sed 's/\ //g' | sed 's/r2//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
sqlite3 ./out/$1.db << EOF
CREATE TABLE _csv_import (tijdtemp text, waarde INTEGER);
.separator ","
.import ./temp/input.csv _csv_import
EOF
sqlite3 ./out/$1.db << EOF
CREATE TABLE TEST AS
SELECT a.tijd AS tijd,a.ra0,a.ra1,a.ra2,ra3,a.ra4,a.ra5,a.ra6,a.ra7,a.aa0,a.aa1,a.aa2,a.aa3,a.aa4,a.aa5,a.aa6,a.aa7,a.aa8,a.aa9,a.aa10,a.aa11,a.aa12,a.aa13,_csv_import.waarde AS aa14,a.aa15,a.aa16,a.aa17,a.aa18,a.aa19
FROM data a LEFT JOIN
_csv_import
ON a.tijd = _csv_import.tijdtemp;
DROP TABLE data;
create table data (id INTEGER PRIMARY KEY,tijd TEXT,ra0 INTEGER,ra1 INTEGER,ra2 INTEGER,ra3 INTEGER,ra4 INTEGER,ra5 INTEGER,ra6 INTEGER,ra7 INTEGER,aa0 INTEGER,aa1 INTEGER,aa2 INTEGER,aa3 INTEGER,aa4 INTEGER,aa5 INTEGER,aa6 INTEGER,aa7 INTEGER,aa8 INTEGER,aa9 INTEGER,aa10 INTEGER,aa11 INTEGER,aa12 INTEGER,aa13 INTEGER,aa14 INTEGER,aa15 INTEGER,aa16 INTEGER,aa17 INTEGER,aa18 INTEGER,aa19 INTEGER);
INSERT INTO data (tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17) SELECT tijd,ra0,ra1,ra2,ra3,ra4,ra5,ra6,ra7,aa0,aa1,aa2,aa3,aa4,aa5,aa6,aa7,aa8,aa9,aa10,aa11,aa12,aa13,aa14,aa15,aa16,aa17
FROM TEST WHERE 1;
DROP TABLE TEST;
DROP TABLE _csv_import;
EOF
# allbuttons
knopnr=0
for knop in share options PS up right down left triangle circle cross square l1 r1 l3 r3
do
if [ $knopnr -eq 13 ]
then
knopnr=$[$knopnr+2]
fi
rm -f ./temp/input.csv
cat ./temp/$1.overig | sed 's/\ //g' | grep $knop | sed 's/'"$knop"'//' | sed 's/(//' | sed 's/)//' > ./temp/input.csv
for regel in `cat ./temp/input.csv`
do
tijd=`echo $regel | cut -d\, -f1`
waarde=`echo $regel | cut -d\, -f2`
sqlite3 ./out/$1.db "update data set aa$knopnr='$waarde' where tijd='$tijd';"
tijd=""
waarde=""
done
knopnr=$[$knopnr+1]
done
rm -f ./temp/*
rm -f ./out/$1.tijdstippen.csv
# write all to csv
sqlite3 ./out/$1.db << EOF
.head on
.mode csv
.output ./out/$1.csv
select tijd,
ra0 as lstickx,
ra1 as lsticky,
ra2 as rstickx,
ra3 as rsticky,
aa0 as share,
aa1 as options,
aa2 as PS,
aa3 as up,
aa4 as right,
aa5 as down,
aa6 as left,
aa7 as triangle,
aa8 as circle,
aa9 as cross,
aa10 as square,
aa11 as l1,
aa12 as r1,
aa13 as l2,
aa14 as r2,
aa15 as l3,
aa16 as r3
from data;
.quit
EOF
After this I opened the csv file (in the dir named 'out') with Excel.
For the axis values (lstick x/y, rstick x/y, L2, R2) I "filled down" values when they were empty (copy value from previous line).
Used the following formulas to convert -255 .. 255 and -128 .. 128 (from log.txt) to -32768 .. 32767 (in macro)
For AXIS lstickx / lstick y / rstick x / rstick y:
Code: Select all
min([ref to cell with value from log.txt]*256;32767)
For L2 / R2:
Code: Select all
MIN([ref to cell with value from log.txt]×128+127;32767)
Now combine JAXIS [id] with new calculated values using (ID=0 for lstick x):
Code: Select all
="JAXIS 0 " & [ref to new calculated value]
When you use Dualshock4.xml
- lstickx: JAXIS 0
- lsticky: JAXIS 1
- rstickx: JAXIS 2
- rsticy: JAXIS 3
- L2: JAXIS 4
- R2: JAXIS 5
I used VBA for Excel to fill all values, formulas and convert all code to one line per command. I will post the code for VBA later.
For Buttons, at first line with 255 use:
Code: Select all
JBUTTONDOWN [id]
and for the line right after where 255 ends :
Code: Select all
JBUTTONUP [id]
Finally for every line use:
Code: Select all
DELAY 10
When you want to test parts of your macro always end your macro with:
Code: Select all
DELAY 10
JAXIS 0 0
JAXIS 1 0
JAXIS 2 0
JAXIS 3 0
JAXIS 4 0
JAXIS 5 0
So the few lines given earlier as an example from log.txt will be converted to a macro, like this:
Code: Select all
JAXIS 0 -14592
JAXIS 1 -32256
JAXIS 2 -32768
JAXIS 3 8448
JBUTTONDOWN 7
DELAY 10
JAXIS 0 -14336
JAXIS 1 -32512
JAXIS 2 7424
JAXIS 3 -2560
DELAY 10
JAXIS 0 -14592
JAXIS 1 -32512
JAXIS 2 256
JAXIS 3 -1280
DELAY 10
# copy from previous line because nothing changed (xxx.235)
# maybe DELAY 20 will work too
# not tested
JAXIS 0 -14592
JAXIS 1 -32512
JAXIS 2 256
JAXIS 3 -1280
DELAY 10
JAXIS 0 -14592
JAXIS 1 -32768
JAXIS 2 256
JAXIS 3 -1280
DELAY 10
JAXIS 0 -14336
JAXIS 1 -32768
JAXIS 2 256
JAXIS 3 -1280
JBUTTONUP 7