Add analytics support

This commit is contained in:
dualshock-tools 2024-04-22 16:07:45 +02:00
parent b10d6da3e1
commit 0c812c6a4f
2 changed files with 167 additions and 108 deletions

272
core.js
View File

@ -6,6 +6,8 @@ var disable_btn = false;
var lang_orig_text = {};
var lang_cur = {};
var lang_disabled = true;
var gj = 0;
var gu = 0;
var available_langs = {
"zh_cn": { "name": "中文", "file": "zh_cn.json"},
@ -18,12 +20,18 @@ var available_langs = {
"tr_tr": { "name": "Türkçe", "file": "tr_tr.json"},
};
function buf2hex(buffer) {
return [...new Uint8Array(buffer)] .map(x => x.toString(16).padStart(2, '0')) .join('');
}
function dec2hex(i) {
return (i+0x10000).toString(16).substr(-4).toUpperCase();
}
function dec2hex32(i) {
return (i+0x100000000).toString(16).substr(-8).toUpperCase();
}
function dec2hex8(i) {
return (i+0x100).toString(16).substr(-2).toUpperCase();
}
@ -49,11 +57,12 @@ function ds4_hw_to_bm(hw_ver) {
async function ds4_info() {
try {
const view = await device.receiveFeatureReport(0xa3);
const view = lf("ds4_info", await device.receiveFeatureReport(0xa3));
var cmd = view.getUint8(0, true);
if(cmd != 0xa3 || view.buffer.byteLength != 49)
if(cmd != 0xa3 || view.buffer.byteLength != 49) {
return false;
}
var k1 = new TextDecoder().decode(view.buffer.slice(1, 0x10));
var k2 = new TextDecoder().decode(view.buffer.slice(0x10, 0x20));
@ -73,6 +82,7 @@ async function ds4_info() {
const view = await device.receiveFeatureReport(0x81);
ooc = l("original");
} catch(e) {
la("clone");
is_clone = true;
ooc = "<font color='red'><b>" + l("clone") + "</b></font>";
disable_btn = true;
@ -100,6 +110,7 @@ async function ds4_info() {
}
async function ds4_reset() {
la("ds4_reset");
try {
await device.sendFeatureReport(0xa0, alloc_req(0x80, [4,1,0]))
} catch(error) {
@ -107,6 +118,7 @@ async function ds4_reset() {
}
async function ds5_reset() {
la("ds5_reset");
try {
await device.sendFeatureReport(0x80, alloc_req(0x80, [1,1,0]))
} catch(error) {
@ -114,6 +126,7 @@ async function ds5_reset() {
}
async function ds4_calibrate_range_begin(perm_ch) {
la("ds4_calibrate_range_begin", {"p": perm_ch});
var err = l("Range calibration failed: ");
try {
if(perm_ch) {
@ -142,6 +155,7 @@ async function ds4_calibrate_range_begin(perm_ch) {
}
async function ds4_calibrate_range_end(perm_ch) {
la("ds4_calibrate_range_end", {"p": perm_ch});
var err = l("Range calibration failed: ");
try {
// Write
@ -172,6 +186,7 @@ async function ds4_calibrate_range_end(perm_ch) {
}
async function ds4_calibrate_sticks_begin(has_perm_changes) {
la("ds4_calibrate_sticks_begin", {"p": has_perm_changes});
var err = l("Stick calibration failed: ");
try {
if(has_perm_changes) {
@ -202,6 +217,7 @@ async function ds4_calibrate_sticks_begin(has_perm_changes) {
}
async function ds4_calibrate_sticks_sample() {
la("ds4_calibrate_sticks_sample");
var err = l("Stick calibration failed: ");
try {
// Sample
@ -226,6 +242,7 @@ async function ds4_calibrate_sticks_sample() {
}
async function ds4_calibrate_sticks_end(has_perm_changes) {
la("ds4_calibrate_sticks_end", {"p": has_perm_changes});
var err = l("Stick calibration failed: ");
try {
// Write
@ -254,6 +271,7 @@ async function ds4_calibrate_sticks_end(has_perm_changes) {
}
async function ds4_calibrate_sticks() {
la("ds4_calibrate_sticks");
var err = l("Stick calibration failed: ");
try {
set_progress(0);
@ -312,7 +330,7 @@ async function ds4_calibrate_sticks() {
async function ds4_nvstatus() {
await device.sendFeatureReport(0x08, alloc_req(0x08, [0xff,0, 12]))
data = await device.receiveFeatureReport(0x11)
data = lf("ds4_nvstatus", await device.receiveFeatureReport(0x11))
// 1: temporary, 0: permanent
ret = data.getUint8(1, false);
if(ret == 1) {
@ -328,7 +346,7 @@ async function ds4_nvstatus() {
async function ds5_nvstatus() {
try {
await device.sendFeatureReport(0x80, alloc_req(0x80, [3,3]))
data = await device.receiveFeatureReport(0x81)
data = lf("ds5_nvstatus", await device.receiveFeatureReport(0x81))
ret = data.getUint32(1, false);
if(ret == 0x03030201) {
$("#d-nvstatus").html("<font color='green'>" + l("locked") + "</font>");
@ -347,8 +365,9 @@ async function ds5_nvstatus() {
}
async function ds4_getbdaddr() {
la("ds4_getbdaddr");
try {
data = await device.receiveFeatureReport(0x12)
data = await device.receiveFeatureReport(0x12);
out = ""
for(i=0;i<6;i++) {
if(i >= 1) out += ":";
@ -363,9 +382,10 @@ async function ds4_getbdaddr() {
}
async function ds5_getbdaddr() {
la("ds5_getbdaddr");
try {
await device.sendFeatureReport(0x80, alloc_req(0x80, [9,2]))
data = await device.receiveFeatureReport(0x81)
data = await device.receiveFeatureReport(0x81);
out = ""
for(i=0;i<6;i++) {
if(i >= 1) out += ":";
@ -380,15 +400,17 @@ async function ds5_getbdaddr() {
}
async function ds4_nvlock() {
la("ds4_nvlock");
await device.sendFeatureReport(0xa0, alloc_req(0xa0, [10,1,0]))
}
async function ds4_nvunlock() {
la("ds4_nvunlock");
await device.sendFeatureReport(0xa0, alloc_req(0xa0, [10,2,0x3e,0x71,0x7f,0x89]))
}
async function ds5_info() {
const view = await device.receiveFeatureReport(0x20);
const view = lf("ds5_info", await device.receiveFeatureReport(0x20));
var cmd = view.getUint8(0, true);
if(cmd != 0x20 || view.buffer.byteLength != 64)
@ -425,8 +447,8 @@ async function ds5_info() {
}
async function ds5_calibrate_sticks_begin(has_perm_changes) {
la("ds5_calibrate_sticks_begin", {"p": has_perm_changes});
var err = l("Range calibration failed: ");
console.log("::ds5_calibrate_sticks_begin(" + has_perm_changes + ")");
try {
if(has_perm_changes) {
await ds5_nvunlock();
@ -454,8 +476,8 @@ async function ds5_calibrate_sticks_begin(has_perm_changes) {
}
async function ds5_calibrate_sticks_sample() {
la("ds5_calibrate_sticks_sample");
var err = l("Stick calibration failed: ");
console.log("::ds5_calibrate_sticks_sample()");
try {
// Sample
await device.sendFeatureReport(0x82, alloc_req(0x82, [3,1,1]))
@ -476,8 +498,8 @@ async function ds5_calibrate_sticks_sample() {
}
async function ds5_calibrate_sticks_end(has_perm_changes) {
la("ds5_calibrate_sticks_end", {"p": has_perm_changes});
var err = l("Stick calibration failed: ");
console.log("::ds5_calibrate_sticks_end(" + has_perm_changes + ")");
try {
// Write
await device.sendFeatureReport(0x82, alloc_req(0x82, [2,1,1]))
@ -505,6 +527,7 @@ async function ds5_calibrate_sticks_end(has_perm_changes) {
}
async function ds5_calibrate_sticks() {
la("ds5_fast_calibrate_sticks");
var err = l("Stick calibration failed: ");
try {
set_progress(0);
@ -567,6 +590,7 @@ async function ds5_calibrate_sticks() {
}
async function ds5_calibrate_range_begin(perm_ch) {
la("ds5_calibrate_range_begin", {"p": perm_ch});
var err = l("Range calibration failed: ");
try {
if(perm_ch) {
@ -595,6 +619,7 @@ async function ds5_calibrate_range_begin(perm_ch) {
}
async function ds5_calibrate_range_end(perm_ch) {
la("ds5_calibrate_range_end", {"p": perm_ch});
var err = l("Range calibration failed: ");
try {
// Write
@ -626,6 +651,7 @@ async function ds5_calibrate_range_end(perm_ch) {
}
async function ds5_nvlock() {
la("ds5_nvlock");
try {
await device.sendFeatureReport(0x80, alloc_req(0x80, [3,1]))
data = await device.receiveFeatureReport(0x83)
@ -637,19 +663,22 @@ async function ds5_nvlock() {
}
async function ds5_nvunlock() {
try {
await device.sendFeatureReport(0x80, alloc_req(0x80, [3,2, 101, 50, 64, 12]))
data = await device.receiveFeatureReport(0x83)
} catch(e) {
await new Promise(r => setTimeout(r, 500));
close_calibrate_window();
return show_popup(l("NVS Unlock failed: ") + e);
}
la("ds5_nvunlock");
try {
await device.sendFeatureReport(0x80, alloc_req(0x80, [3,2, 101, 50, 64, 12]))
data = await device.receiveFeatureReport(0x83)
} catch(e) {
await new Promise(r => setTimeout(r, 500));
close_calibrate_window();
return show_popup(l("NVS Unlock failed: ") + e);
}
}
async function disconnect() {
la("disconnect");
if(device == null)
return;
gj = 0;
mode = 0;
device.close();
device = null;
@ -662,6 +691,7 @@ async function disconnect() {
}
function handleDisconnectedDevice(e) {
la("disconnected");
console.log("Disconnected: " + e.device.productName)
disconnect();
}
@ -706,11 +736,13 @@ function welcome_modal() {
}
function welcome_accepted() {
la("welcome_accepted");
createCookie("welcome_accepted", "1");
$("#welcomeModal").modal("hide");
}
function gboot() {
gu = crypto.randomUUID();
window.addEventListener('DOMContentLoaded', function() {
lang_init();
welcome_modal();
@ -743,101 +775,104 @@ function alloc_req(id, data=[]) {
}
async function connect() {
try {
$("#btnconnect").prop("disabled", true);
$("#connectspinner").show();
await new Promise(r => setTimeout(r, 100));
let ds4v1 = { vendorId: 0x054c, productId: 0x05c4 };
let ds4v2 = { vendorId: 0x054c, productId: 0x09cc };
let ds5 = { vendorId: 0x054c, productId: 0x0ce6 };
let ds5edge = { vendorId: 0x054c, productId: 0x0df2 };
let requestParams = { filters: [ds4v1,ds4v2,ds5,ds5edge] };
var devices = await navigator.hid.getDevices();
if (devices.length == 0) {
devices = await navigator.hid.requestDevice(requestParams);
}
gj = crypto.randomUUID();
la("begin");
try {
$("#btnconnect").prop("disabled", true);
$("#connectspinner").show();
await new Promise(r => setTimeout(r, 100));
if (devices.length == 0) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
return;
}
if (devices.length > 1) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
show_popup(l("Please connect only one controller at time."));
return;
}
await devices[0].open();
device = devices[0]
var connected = false
if(device.productId == 0x05c4) {
if(await ds4_info()) {
connected = true
mode = 1;
devname = l("Sony DualShock 4 V1");
let ds4v1 = { vendorId: 0x054c, productId: 0x05c4 };
let ds4v2 = { vendorId: 0x054c, productId: 0x09cc };
let ds5 = { vendorId: 0x054c, productId: 0x0ce6 };
let ds5edge = { vendorId: 0x054c, productId: 0x0df2 };
let requestParams = { filters: [ds4v1,ds4v2,ds5,ds5edge] };
var devices = await navigator.hid.getDevices();
if (devices.length == 0) {
devices = await navigator.hid.requestDevice(requestParams);
}
} else if(device.productId == 0x09cc) {
if(await ds4_info()) {
connected = true
mode = 1;
devname = l("Sony DualShock 4 V2");
if (devices.length == 0) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
return;
}
} else if(device.productId == 0x0ce6) {
if(await ds5_info()) {
connected = true
mode = 2;
devname = l("Sony DualSense");
if (devices.length > 1) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
show_popup(l("Please connect only one controller at time."));
return;
}
} else if(device.productId == 0x0df2) {
if(await ds5_info()) {
connected = true
mode = 0;
devname = l("Sony DualSense Edge");
disable_btn = true;
}
} else {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
show_popup(l("Connected invalid device: ") + dec2hex(device.vendorId) + ":" + dec2hex(device.productId))
disconnect();
return;
}
if(connected) {
$("#devname").text(devname + " (" + dec2hex(device.vendorId) + ":" + dec2hex(device.productId) + ")");
$("#offlinebar").hide();
$("#onlinebar").show();
$("#mainmenu").show();
$("#resetBtn").show();
$("#d-nvstatus").text = l("Unknown");
$("#d-bdaddr").text = l("Unknown");
}
if(disable_btn) {
if(device.productId == 0x0df2) {
show_popup(l("Calibration of the DualSense Edge is not currently supported."));
await devices[0].open();
device = devices[0]
la("connect", {"p": device.productId, "v": device.vendorId});
var connected = false
if(device.productId == 0x05c4) {
if(await ds4_info()) {
connected = true
mode = 1;
devname = l("Sony DualShock 4 V1");
}
} else if(device.productId == 0x09cc) {
if(await ds4_info()) {
connected = true
mode = 1;
devname = l("Sony DualShock 4 V2");
}
} else if(device.productId == 0x0ce6) {
if(await ds5_info()) {
connected = true
mode = 2;
devname = l("Sony DualSense");
}
} else if(device.productId == 0x0df2) {
if(await ds5_info()) {
connected = true
mode = 0;
devname = l("Sony DualSense Edge");
disable_btn = true;
}
} else {
show_popup(l("The device appears to be a DS4 clone. All functionalities are disabled."));
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
show_popup(l("Connected invalid device: ") + dec2hex(device.vendorId) + ":" + dec2hex(device.productId))
disconnect();
return;
}
if(connected) {
$("#devname").text(devname + " (" + dec2hex(device.vendorId) + ":" + dec2hex(device.productId) + ")");
$("#offlinebar").hide();
$("#onlinebar").show();
$("#mainmenu").show();
$("#resetBtn").show();
$("#d-nvstatus").text = l("Unknown");
$("#d-bdaddr").text = l("Unknown");
}
if(disable_btn) {
if(device.productId == 0x0df2) {
show_popup(l("Calibration of the DualSense Edge is not currently supported."));
} else {
show_popup(l("The device appears to be a DS4 clone. All functionalities are disabled."));
}
}
$(".ds-btn").prop("disabled", disable_btn);
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
} catch(error) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
show_popup(l("Error: ") + error);
return;
}
$(".ds-btn").prop("disabled", disable_btn);
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
} catch(error) {
$("#btnconnect").prop("disabled", false);
$("#connectspinner").hide();
show_popup(l("Error: ") + error);
return;
}
}
var curModal = null
@ -982,12 +1017,22 @@ function show_popup(text, is_html = false) {
}
function show_faq_modal() {
la("faq_modal");
new bootstrap.Modal(document.getElementById('faqModal'), {}).show()
}
function discord_popup() { show_popup(l("My handle on discord is: the_al")); }
function show_donate_modal() {
la("donate_modal");
new bootstrap.Modal(document.getElementById('donateModal'), {}).show()
}
function discord_popup() {
la("discord_popup");
show_popup(l("My handle on discord is: the_al"));
}
function board_model_info() {
la("bm_info");
l1 = l("This feature is experimental.");
l2 = l("Please let me know if the board model of your controller is not detected correctly.");
l3 = l("Board model detection thanks to") + ' <a href="https://battlebeavercustoms.com/">Battle Beaver Customs</a>.';
@ -1006,6 +1051,7 @@ function close_new_calib() {
}
async function calib_step(i) {
la("calib_step", {"i": i})
if(i < 1 || i > 7) return;
var pc = calib_perm_changes();
@ -1072,6 +1118,7 @@ async function calib_step(i) {
var cur_calib = 0;
async function calib_open() {
la("calib_open");
cur_calib = 0;
reset_calib_perm_changes();
await calib_next();
@ -1079,6 +1126,7 @@ async function calib_open() {
}
async function calib_next() {
la("calib_next");
if(cur_calib == 6) {
close_new_calib()
return;
@ -1089,6 +1137,14 @@ async function calib_next() {
}
}
function la(k,v={}) {
$.ajax({type: 'POST', url:"https://the.al/ds4_a/l",
data: JSON.stringify( {"u": gu, "j": gj, "k": k, "v": v}),
contentType: "application/json", dataType: 'json'});
}
function lf(k, f) { la(k, buf2hex(f.buffer)); return f; }
function lang_init() {
var id_iter = 0;
var items = document.getElementsByClassName('ds-i18n');
@ -1110,6 +1166,7 @@ function lang_init() {
var nlang = navigator.language.replace('-', '_').toLowerCase();
var ljson = available_langs[nlang];
if(ljson !== undefined) {
la("lang_init", {"l": nlang});
lang_translate(ljson["file"], nlang);
}
}
@ -1128,6 +1185,7 @@ function lang_init() {
}
function lang_set(l, skip_modal=false) {
la("lang_set", {"l": l})
if(l == "en_us") {
lang_reset_page();
} else {

View File

@ -162,6 +162,7 @@
<ul>
<li class="ds-i18n">This website is not affiliated with Sony, PlayStation &amp; co.</li>
<li class="ds-i18n">This service is provided without warranty. Use at your own risk.</li>
<li class="ds-i18n">This website uses analytics to improve the service.</li>
<li class="ds-i18n">Keep the internal battery of the controller connected and ensure it is well charged. If the battery dies during operations, the controller will be damaged and rendered unusable.</li>
<li class="ds-i18n">Before doing the permanent calibration, try the temporary one to ensure that everything is working well.</li>
</ul>
@ -437,7 +438,7 @@
<div class="container">
<footer>
<div class="d-flex flex-column flex-sm-row justify-content-between py-4 my-4 border-top" id="footbody">
<p><span class="ds-i18n">Version</span> 0.7 (2024-04-21) - <a href="#" class="ds-i18n" data-bs-toggle="modal" data-bs-target="#donateModal">Support this project</a>&nbsp;<span id="authorMsg"></span></p>
<p><span class="ds-i18n">Version</span> 0.7 (2024-04-21) - <a href="#" class="ds-i18n" onclick="show_donate_modal();">Support this project</a>&nbsp;<span id="authorMsg"></span></p>
<ul class="list-unstyled d-flex">
<li class="ms-3"><a class="link-body-emphasis" href="mailto:ds4@the.al" target="_blank"><svg class="bi" width="24" height="24"><use xlink:href="#mail"/></svg></a></li>