tracky-mouse 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/face-landmarks-detection.min.js +1 -1
- package/lib/face_mesh/face_mesh.js +1 -1
- package/locales/ar/translation.json +5 -1
- package/locales/ar-EG/translation.json +5 -1
- package/locales/bg/translation.json +5 -1
- package/locales/bn/translation.json +5 -1
- package/locales/ca/translation.json +5 -1
- package/locales/ce/translation.json +5 -1
- package/locales/ceb/translation.json +6 -2
- package/locales/cs/translation.json +5 -1
- package/locales/da/translation.json +5 -1
- package/locales/de/translation.json +5 -1
- package/locales/el/translation.json +5 -1
- package/locales/emoji/emoji-translation-notes.md +1 -0
- package/locales/emoji/translation.json +9 -5
- package/locales/en/translation.json +5 -1
- package/locales/eo/translation.json +5 -1
- package/locales/es/translation.json +5 -1
- package/locales/eu/translation.json +5 -1
- package/locales/fa/translation.json +5 -1
- package/locales/fi/translation.json +5 -1
- package/locales/fr/translation.json +5 -1
- package/locales/gu/translation.json +5 -1
- package/locales/ha/translation.json +5 -1
- package/locales/he/translation.json +5 -1
- package/locales/hi/translation.json +5 -1
- package/locales/hr/translation.json +5 -1
- package/locales/hu/translation.json +5 -1
- package/locales/hy/translation.json +5 -1
- package/locales/id/translation.json +5 -1
- package/locales/it/translation.json +5 -1
- package/locales/ja/translation.json +5 -1
- package/locales/jv/translation.json +6 -2
- package/locales/ko/translation.json +5 -1
- package/locales/mr/translation.json +5 -1
- package/locales/ms/translation.json +5 -1
- package/locales/nan/translation.json +5 -1
- package/locales/nb/translation.json +5 -1
- package/locales/nl/translation.json +5 -1
- package/locales/pa/translation.json +5 -1
- package/locales/pl/translation.json +5 -1
- package/locales/pt/translation.json +5 -1
- package/locales/pt-BR/translation.json +5 -1
- package/locales/ro/translation.json +5 -1
- package/locales/ru/translation.json +5 -1
- package/locales/sk/translation.json +5 -1
- package/locales/sl/translation.json +5 -1
- package/locales/sr/translation.json +5 -1
- package/locales/sv/translation.json +5 -1
- package/locales/sw/translation.json +5 -1
- package/locales/ta/translation.json +5 -1
- package/locales/te/translation.json +5 -1
- package/locales/th/translation.json +5 -1
- package/locales/tl/translation.json +6 -2
- package/locales/tr/translation.json +5 -1
- package/locales/tt/translation.json +5 -1
- package/locales/uk/translation.json +5 -1
- package/locales/ur/translation.json +5 -1
- package/locales/uz/translation.json +5 -1
- package/locales/vi/translation.json +5 -1
- package/locales/war/translation.json +6 -2
- package/locales/zh/translation.json +5 -1
- package/locales/zh-simplified/translation.json +5 -1
- package/package.json +2 -2
- package/{audio.js → src/audio.js} +1 -1
- package/src/autoscroll.js +189 -0
- package/src/input-simulator.js +518 -0
- package/tracky-mouse.css +33 -2
- package/tracky-mouse.js +166 -58
package/tracky-mouse.js
CHANGED
|
@@ -601,7 +601,7 @@ TrackyMouse._initAudio = async function () {
|
|
|
601
601
|
let module;
|
|
602
602
|
try {
|
|
603
603
|
// console.log("Loading audio support...");
|
|
604
|
-
module = await import("./audio.js");
|
|
604
|
+
module = await import("./src/audio.js");
|
|
605
605
|
} catch (e) {
|
|
606
606
|
console.warn("Failed to load audio module, click sounds will be disabled:", e);
|
|
607
607
|
}
|
|
@@ -1672,7 +1672,7 @@ TrackyMouse._initInner = function (div, initOptions, reinit) {
|
|
|
1672
1672
|
<div class="tracky-mouse-controls">
|
|
1673
1673
|
<button class="tracky-mouse-start-stop-button" aria-pressed="false" aria-keyshortcuts="F9">${t("ui.startStopButton.start", { defaultValue: "Start" })}</button>
|
|
1674
1674
|
</div>
|
|
1675
|
-
<div class="tracky-mouse-
|
|
1675
|
+
<div class="tracky-mouse-camera-area">
|
|
1676
1676
|
<div class="tracky-mouse-canvas-container">
|
|
1677
1677
|
<div class="tracky-mouse-canvas-overlay">
|
|
1678
1678
|
<button class="tracky-mouse-use-camera-button">${t("ui.camera.allowAccess", { defaultValue: "Allow Camera Access" })}</button>
|
|
@@ -1697,6 +1697,37 @@ TrackyMouse._initInner = function (div, initOptions, reinit) {
|
|
|
1697
1697
|
let canvasContainer = uiContainer.querySelector('.tracky-mouse-canvas-container');
|
|
1698
1698
|
let desktopAppDownloadMessage = uiContainer.querySelector('.tracky-mouse-desktop-app-download-message');
|
|
1699
1699
|
|
|
1700
|
+
let lastShownErrorDetails = null;
|
|
1701
|
+
function showError(message, error, { warningIcon = true, errorClass = "other" } = {}) {
|
|
1702
|
+
const alreadyShown = !errorMessage.hidden && lastShownErrorDetails?.message === message && lastShownErrorDetails?.error?.name === error?.name && lastShownErrorDetails?.error?.message === error?.message;
|
|
1703
|
+
if (alreadyShown) {
|
|
1704
|
+
// Play CSS animation to indicate repeated errors
|
|
1705
|
+
// but not if they're occurring constantly
|
|
1706
|
+
// Note: for constant errors, with this scheme, it may animate
|
|
1707
|
+
// when returning to the tab due to timer throttling, or due to lag.
|
|
1708
|
+
if (performance.now() > lastShownErrorDetails.time + 100) {
|
|
1709
|
+
errorMessage.style.animation = "none";
|
|
1710
|
+
if (alreadyShown) {
|
|
1711
|
+
void errorMessage.offsetWidth; // trigger reflow to allow restarting animation
|
|
1712
|
+
errorMessage.style.animation = "";
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
} else {
|
|
1716
|
+
if (warningIcon) {
|
|
1717
|
+
errorMessage.textContent = `${t("common.warningIcon", { defaultValue: "⚠️" })} ${message}`;
|
|
1718
|
+
} else {
|
|
1719
|
+
errorMessage.textContent = message;
|
|
1720
|
+
}
|
|
1721
|
+
if (error) {
|
|
1722
|
+
const pre = document.createElement("pre");
|
|
1723
|
+
pre.textContent = error.name + ": " + error.message;
|
|
1724
|
+
errorMessage.appendChild(pre);
|
|
1725
|
+
}
|
|
1726
|
+
errorMessage.hidden = false;
|
|
1727
|
+
}
|
|
1728
|
+
lastShownErrorDetails = { message, error, time: performance.now(), errorClass };
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1700
1731
|
// Settings (initialized later; defaults are defined in settingsCategories)
|
|
1701
1732
|
const s = {};
|
|
1702
1733
|
|
|
@@ -2034,11 +2065,21 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2034
2065
|
type: "button",
|
|
2035
2066
|
visible: () => isDesktopApp,
|
|
2036
2067
|
onClick: async () => {
|
|
2068
|
+
function showToast(message) {
|
|
2069
|
+
const toast = document.createElement("div");
|
|
2070
|
+
toast.className = "tracky-mouse-toast";
|
|
2071
|
+
toast.textContent = message;
|
|
2072
|
+
document.body.appendChild(toast);
|
|
2073
|
+
setTimeout(() => {
|
|
2074
|
+
toast.remove();
|
|
2075
|
+
}, 5000);
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2037
2078
|
let knownCameras = {};
|
|
2038
2079
|
try {
|
|
2039
2080
|
knownCameras = JSON.parse(localStorage.getItem("tracky-mouse-known-cameras")) || {};
|
|
2040
2081
|
} catch (error) {
|
|
2041
|
-
|
|
2082
|
+
showToast(t("openCameraSettings.errors.sharedHeading", { defaultValue: "Failed to open camera settings:" }) + "\n" + t("openCameraSettings.errors.parseKnownCameras", { defaultValue: "Failed to parse known cameras from localStorage:" }) + "\n" + error.name + ": " + error.message);
|
|
2042
2083
|
return;
|
|
2043
2084
|
}
|
|
2044
2085
|
|
|
@@ -2049,10 +2090,10 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2049
2090
|
try {
|
|
2050
2091
|
const result = await window.electronAPI.openCameraSettings(selectedDeviceName);
|
|
2051
2092
|
if (result?.error) {
|
|
2052
|
-
|
|
2093
|
+
showToast(t("openCameraSettings.errors.sharedHeading", { defaultValue: "Failed to open camera settings:" }) + "\n" + result.error);
|
|
2053
2094
|
}
|
|
2054
2095
|
} catch (error) {
|
|
2055
|
-
|
|
2096
|
+
showToast(t("openCameraSettings.errors.sharedHeading", { defaultValue: "Failed to open camera settings:" }) + "\n" + error.name + ": " + error.message);
|
|
2056
2097
|
}
|
|
2057
2098
|
},
|
|
2058
2099
|
// description: t("settings.openCameraSettings.description.alt1", { defaultValue: "Open your camera's system settings window to adjust properties like brightness and contrast." }),
|
|
@@ -2389,7 +2430,7 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2389
2430
|
let debugEyeCanvas = document.createElement("canvas");
|
|
2390
2431
|
debugEyeCanvas.className = "tracky-mouse-debug-eye-canvas";
|
|
2391
2432
|
debugEyeCanvas.style.display = "none";
|
|
2392
|
-
uiContainer.querySelector(".tracky-mouse-
|
|
2433
|
+
uiContainer.querySelector(".tracky-mouse-camera-area").appendChild(debugEyeCanvas);
|
|
2393
2434
|
let debugEyeCtx = debugEyeCanvas.getContext('2d');
|
|
2394
2435
|
|
|
2395
2436
|
let pointerEl = document.createElement('div');
|
|
@@ -2477,6 +2518,18 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2477
2518
|
let lastMouseDownTime = -Infinity;
|
|
2478
2519
|
let mouseNeedsInitPos = true;
|
|
2479
2520
|
|
|
2521
|
+
// Virtual display bounds cache (Electron only); covers all connected monitors.
|
|
2522
|
+
let virtualDisplayBounds = null;
|
|
2523
|
+
if (window.electronAPI?.getVirtualDisplayBounds) {
|
|
2524
|
+
window.electronAPI.getVirtualDisplayBounds().then((bounds) => {
|
|
2525
|
+
virtualDisplayBounds = bounds;
|
|
2526
|
+
});
|
|
2527
|
+
window.electronAPI.onVirtualDisplayBoundsChanged?.((bounds) => {
|
|
2528
|
+
virtualDisplayBounds = bounds;
|
|
2529
|
+
mouseNeedsInitPos = true;
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2480
2533
|
// Other state
|
|
2481
2534
|
let paused = true;
|
|
2482
2535
|
let pointTracker;
|
|
@@ -2548,14 +2601,17 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2548
2601
|
|
|
2549
2602
|
try {
|
|
2550
2603
|
detector = await faceLandmarksDetection.createDetector(model, detectorConfig);
|
|
2604
|
+
if (lastShownErrorDetails?.errorClass === "faceLandmarksDetection.createDetector") {
|
|
2605
|
+
errorMessage.hidden = true;
|
|
2606
|
+
}
|
|
2551
2607
|
} catch (error) {
|
|
2552
2608
|
detector = null;
|
|
2553
|
-
// TODO: avoid alert
|
|
2554
2609
|
console.error("Failed to create facemesh detector:", error);
|
|
2555
|
-
|
|
2610
|
+
showError(t("faceDetectorInitError", { defaultValue: "Failed to create face detector" }), error, { errorClass: "faceLandmarksDetection.createDetector" });
|
|
2556
2611
|
}
|
|
2557
2612
|
|
|
2558
2613
|
facemeshLoaded = true;
|
|
2614
|
+
let loggedDetectorError = false;
|
|
2559
2615
|
facemeshEstimateFaces = async () => {
|
|
2560
2616
|
const imageData = currentCameraImageData;//getCameraImageData();
|
|
2561
2617
|
if (!imageData) {
|
|
@@ -2569,11 +2625,17 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2569
2625
|
}
|
|
2570
2626
|
return faces;
|
|
2571
2627
|
} catch (error) {
|
|
2572
|
-
|
|
2628
|
+
if (!loggedDetectorError) {
|
|
2629
|
+
console.error("Facemesh estimation failed:", error);
|
|
2630
|
+
loggedDetectorError = true;
|
|
2631
|
+
}
|
|
2632
|
+
try {
|
|
2633
|
+
detector?.dispose();
|
|
2634
|
+
} catch (disposeError) {
|
|
2635
|
+
console.error("Failed to dispose facemesh detector after estimation error:", disposeError);
|
|
2636
|
+
}
|
|
2573
2637
|
detector = null;
|
|
2574
|
-
|
|
2575
|
-
console.error("Facemesh estimation failed:", error);
|
|
2576
|
-
alert(error);
|
|
2638
|
+
showError(t("faceDetectorError", { defaultValue: "Face detector error" }), error);
|
|
2577
2639
|
}
|
|
2578
2640
|
return [];
|
|
2579
2641
|
};
|
|
@@ -2808,7 +2870,17 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2808
2870
|
updateStartStopButton();
|
|
2809
2871
|
};
|
|
2810
2872
|
|
|
2811
|
-
|
|
2873
|
+
// Handle monkey-patched alert() replacement in face-landmarks-detection.min.js
|
|
2874
|
+
// (Hm, could make it throw instead. Then we wouldn't need this.)
|
|
2875
|
+
window._TrackyMouse_faceLandmarksDetectionAlert = (message) => {
|
|
2876
|
+
// TODO: i18n (it's just one message; we could check for the string (or not) and translate it)
|
|
2877
|
+
// const isContextCreationMessage = message === "Failed to create WebGL canvas context when passing video frame.";
|
|
2878
|
+
errorMessage.textContent = `${t("common.warningIcon", { defaultValue: "⚠️" })} ${message}`;
|
|
2879
|
+
errorMessage.hidden = false;
|
|
2880
|
+
};
|
|
2881
|
+
|
|
2882
|
+
const cameraAccessSlowWarningDelayMS = 5000;
|
|
2883
|
+
let cameraAccessSlowWarningTimeoutID;
|
|
2812
2884
|
useCameraButton.onclick = TrackyMouse.useCamera = async (optionsOrEvent = {}) => {
|
|
2813
2885
|
// Phases:
|
|
2814
2886
|
// 1. "tryPreferredCamera"
|
|
@@ -2898,8 +2970,15 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2898
2970
|
delete constraints.video.facingMode;
|
|
2899
2971
|
constraints.video.deviceId = { exact: deviceIdToTry };
|
|
2900
2972
|
}
|
|
2973
|
+
clearTimeout(cameraAccessSlowWarningTimeoutID);
|
|
2974
|
+
errorMessage.hidden = true;
|
|
2975
|
+
cameraAccessSlowWarningTimeoutID = setTimeout(() => {
|
|
2976
|
+
errorMessage.textContent = t("video.status.accessTakingLongerThanExpected", { defaultValue: "Accessing the camera is taking longer than expected..." });
|
|
2977
|
+
errorMessage.hidden = false;
|
|
2978
|
+
}, cameraAccessSlowWarningDelayMS);
|
|
2901
2979
|
console.log("TrackyMouse.useCamera phase", phase, "constraints", constraints);
|
|
2902
2980
|
navigator.mediaDevices.getUserMedia(constraints).then(async (stream) => {
|
|
2981
|
+
clearTimeout(cameraAccessSlowWarningTimeoutID);
|
|
2903
2982
|
if (phase === "justGetPermission") {
|
|
2904
2983
|
for (const track of stream.getTracks()) {
|
|
2905
2984
|
track.stop();
|
|
@@ -2922,6 +3001,7 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2922
3001
|
useCameraButton.hidden = true;
|
|
2923
3002
|
errorMessage.hidden = true;
|
|
2924
3003
|
}, async (error) => {
|
|
3004
|
+
clearTimeout(cameraAccessSlowWarningTimeoutID);
|
|
2925
3005
|
console.log("TrackyMouse.useCamera phase", phase, "error", error);
|
|
2926
3006
|
if (
|
|
2927
3007
|
phase === "tryPreferredCamera" &&
|
|
@@ -2933,7 +3013,7 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2933
3013
|
}
|
|
2934
3014
|
if (error.name == "NotFoundError" || error.name == "DevicesNotFoundError") {
|
|
2935
3015
|
// required track is missing
|
|
2936
|
-
|
|
3016
|
+
showError(t("video.errors.noCameraFound", { defaultValue: "No camera found. Please make sure you have a camera connected and enabled." }));
|
|
2937
3017
|
} else if (error.name == "NotReadableError" || error.name == "TrackStartError") {
|
|
2938
3018
|
// webcam is already in use
|
|
2939
3019
|
// or: OBS Virtual Camera is present but OBS is not running with Virtual Camera started
|
|
@@ -2941,18 +3021,18 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2941
3021
|
// (listing devices and showing only the OBS Virtual Camera would also be a good clue in itself;
|
|
2942
3022
|
// though care should be given to make it clear it's a list with one item, with something like "(no more cameras detected)" following the list
|
|
2943
3023
|
// or "1 camera source detected" preceding it)
|
|
2944
|
-
|
|
3024
|
+
showError(t("video.errors.cameraInUse", { defaultValue: "Webcam is already in use. Please make sure you have no other programs using the camera." }));
|
|
2945
3025
|
} else if (error.name === "AbortError") {
|
|
2946
3026
|
// webcam is likely already in use
|
|
2947
3027
|
// I observed AbortError in Firefox 132.0.2 but I don't know it's used exclusively for this case.
|
|
2948
3028
|
// Update: it definitely isn't, but I can't say exactly what it means in other cases.
|
|
2949
3029
|
// Like, it might have to do with permissions being denied outside of a user gesture (distinct from the user denying the permission)
|
|
2950
3030
|
// I really hope that isn't the problem.
|
|
2951
|
-
//
|
|
2952
|
-
|
|
3031
|
+
// showError("Webcam may already be in use. Please make sure you have no other programs using the camera.");
|
|
3032
|
+
showError(t("video.errors.retryAfterClosingOtherPrograms", { defaultValue: "Please make sure no other programs are using the camera and try again." }));
|
|
2953
3033
|
// A more honest/helpful message might be:
|
|
2954
|
-
//
|
|
2955
|
-
//
|
|
3034
|
+
// showError("Please try again and then make sure no other programs are using the camera and try again again.");
|
|
3035
|
+
// showError("Please try again before/after making sure no other programs are using the camera.");
|
|
2956
3036
|
// if it were not to be confusing.
|
|
2957
3037
|
// That is, one could save some time by just hitting the button to try again before trying to figure out of another program is using the camera,
|
|
2958
3038
|
// because sometimes that's enough.
|
|
@@ -2963,36 +3043,27 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
2963
3043
|
// either due to the device not being present, or the ID having changed (don't ask me why that can happen but it can)
|
|
2964
3044
|
// Note: OverconstrainedError has a `constraint` property but not in Firefox so it's not very helpful.
|
|
2965
3045
|
if (constraints.video.deviceId?.exact) {
|
|
2966
|
-
//
|
|
2967
|
-
//
|
|
2968
|
-
//
|
|
2969
|
-
//
|
|
2970
|
-
|
|
3046
|
+
// showError("The previously selected camera is not available. Please select a different camera from the dropdown and try again.");
|
|
3047
|
+
// showError("The previously selected camera is not available. Please mess around with Video > Camera source.");
|
|
3048
|
+
// showError("The previously selected camera is not available. Try changing Video > Camera source.");
|
|
3049
|
+
// showError("The previously selected camera is not available. Please select a camera from the \"Camera source\" dropdown in the Video settings and if it doesn't show up, it might after you select Default.");
|
|
3050
|
+
showError(t("video.errors.previouslySelectedUnavailable", { defaultValue: "The previously selected camera is not available. Try selecting \"Default\" for Video > Camera source, and then select a specific camera if you need to." }));
|
|
2971
3051
|
// It's awkward but that's my best attempt at conveying how you may need to proceed
|
|
2972
3052
|
// without complicated description of how/why the dropdown might be populated with
|
|
2973
3053
|
// fake information until a camera stream is successfully opened.
|
|
2974
3054
|
} else {
|
|
2975
|
-
|
|
3055
|
+
showError(t("video.errors.unsupportedResolution", { defaultValue: "Webcam does not support the required resolution. Please change your settings." }));
|
|
2976
3056
|
}
|
|
2977
3057
|
} else if (error.name == "NotAllowedError" || error.name == "PermissionDeniedError") {
|
|
2978
3058
|
// permission denied in browser
|
|
2979
|
-
|
|
3059
|
+
showError(t("video.errors.permissionDenied", { defaultValue: "Permission denied. Please enable access to the camera." }));
|
|
2980
3060
|
} else if (error.name == "TypeError") {
|
|
2981
3061
|
// empty constraints object
|
|
2982
|
-
|
|
3062
|
+
showError(t("video.errors.accessFailed", { defaultValue: "Something went wrong accessing the camera." }), error);
|
|
2983
3063
|
} else {
|
|
2984
3064
|
// other errors
|
|
2985
|
-
|
|
3065
|
+
showError(t("video.errors.accessFailedRetry", { defaultValue: "Something went wrong accessing the camera. Please try again." }), error);
|
|
2986
3066
|
}
|
|
2987
|
-
errorMessage.textContent = `${t("common.warningIcon", { defaultValue: "⚠️" })} ${errorMessage.textContent}`;
|
|
2988
|
-
errorMessage.hidden = false;
|
|
2989
|
-
// Play CSS animation only on retries
|
|
2990
|
-
errorMessage.style.animation = "none";
|
|
2991
|
-
if (showedCameraError) {
|
|
2992
|
-
void errorMessage.offsetWidth; // trigger reflow to allow restarting animation
|
|
2993
|
-
errorMessage.style.animation = "";
|
|
2994
|
-
}
|
|
2995
|
-
showedCameraError = true;
|
|
2996
3067
|
});
|
|
2997
3068
|
};
|
|
2998
3069
|
useDemoFootageButton.onclick = TrackyMouse.useDemoFootage = () => {
|
|
@@ -4089,8 +4160,10 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
4089
4160
|
pointTracker.draw(debugPointsCtx);
|
|
4090
4161
|
|
|
4091
4162
|
if (update) {
|
|
4092
|
-
const screenWidth = window.electronAPI ? screen.width : innerWidth;
|
|
4093
|
-
const screenHeight = window.electronAPI ? screen.height : innerHeight;
|
|
4163
|
+
const screenWidth = window.electronAPI ? (virtualDisplayBounds?.width ?? screen.width) : innerWidth;
|
|
4164
|
+
const screenHeight = window.electronAPI ? (virtualDisplayBounds?.height ?? screen.height) : innerHeight;
|
|
4165
|
+
const screenOffsetX = window.electronAPI ? (virtualDisplayBounds?.x ?? 0) : 0;
|
|
4166
|
+
const screenOffsetY = window.electronAPI ? (virtualDisplayBounds?.y ?? 0) : 0;
|
|
4094
4167
|
|
|
4095
4168
|
let [movementX, movementY] = pointTracker.getMovement();
|
|
4096
4169
|
|
|
@@ -4220,13 +4293,13 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
4220
4293
|
mouseX -= deltaX * screenWidth;
|
|
4221
4294
|
mouseY += deltaY * screenHeight;
|
|
4222
4295
|
|
|
4223
|
-
mouseX = Math.min(Math.max(
|
|
4224
|
-
mouseY = Math.min(Math.max(
|
|
4296
|
+
mouseX = Math.min(Math.max(screenOffsetX, mouseX), screenOffsetX + screenWidth);
|
|
4297
|
+
mouseY = Math.min(Math.max(screenOffsetY, mouseY), screenOffsetY + screenHeight);
|
|
4225
4298
|
|
|
4226
4299
|
if (mouseNeedsInitPos) {
|
|
4227
4300
|
// TODO: option to get preexisting mouse position instead of set it to center of screen
|
|
4228
|
-
mouseX = screenWidth / 2;
|
|
4229
|
-
mouseY = screenHeight / 2;
|
|
4301
|
+
mouseX = screenOffsetX + screenWidth / 2;
|
|
4302
|
+
mouseY = screenOffsetY + screenHeight / 2;
|
|
4230
4303
|
mouseNeedsInitPos = false;
|
|
4231
4304
|
}
|
|
4232
4305
|
if (window.electronAPI) {
|
|
@@ -4355,6 +4428,15 @@ You may want to turn this off if you're drawing on a canvas, or increase it if y
|
|
|
4355
4428
|
_waitForSettingsLoaded() {
|
|
4356
4429
|
return settingsLoadedPromise;
|
|
4357
4430
|
},
|
|
4431
|
+
get _facemeshPrediction() {
|
|
4432
|
+
return facemeshPrediction;
|
|
4433
|
+
},
|
|
4434
|
+
get _headTilt() {
|
|
4435
|
+
return headTilt;
|
|
4436
|
+
},
|
|
4437
|
+
get _video() {
|
|
4438
|
+
return cameraVideo;
|
|
4439
|
+
},
|
|
4358
4440
|
dispose() {
|
|
4359
4441
|
// TODO: re-structure so that cleanup can succeed even if initialization fails
|
|
4360
4442
|
// OOP would help with this, by storing references in an object, but it doesn't necessarily
|
|
@@ -4449,11 +4531,13 @@ TrackyMouse.init = function (div, opts = {}) {
|
|
|
4449
4531
|
|
|
4450
4532
|
createInner();
|
|
4451
4533
|
|
|
4452
|
-
return {
|
|
4453
|
-
|
|
4454
|
-
inner
|
|
4455
|
-
|
|
4456
|
-
|
|
4534
|
+
return new Proxy({}, {
|
|
4535
|
+
get(_target, prop) {
|
|
4536
|
+
if (prop in inner) {
|
|
4537
|
+
return inner[prop];
|
|
4538
|
+
}
|
|
4539
|
+
}
|
|
4540
|
+
});
|
|
4457
4541
|
|
|
4458
4542
|
};
|
|
4459
4543
|
|
|
@@ -4461,21 +4545,24 @@ TrackyMouse.initScreenOverlay = () => {
|
|
|
4461
4545
|
|
|
4462
4546
|
const template = `
|
|
4463
4547
|
<div class="tracky-mouse-hide-near-cursor">
|
|
4464
|
-
<div
|
|
4465
|
-
<div class="tracky-mouse-
|
|
4466
|
-
<
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
<
|
|
4548
|
+
<div id="tracky-mouse-screen-overlay-work-area">
|
|
4549
|
+
<div class="tracky-mouse-absolute-center">
|
|
4550
|
+
<div class="tracky-mouse-screen-overlay-status-indicator tracky-mouse-manual-takeback-indicator">
|
|
4551
|
+
<img src="${TrackyMouse.dependenciesRoot}/images/manual-takeback.svg" alt="hand reaching for mouse" width="128" height="128">
|
|
4552
|
+
</div>
|
|
4553
|
+
<div class="tracky-mouse-screen-overlay-status-indicator tracky-mouse-head-not-found-indicator">
|
|
4554
|
+
<img src="${TrackyMouse.dependenciesRoot}/images/head-not-found.svg" alt="head not found" width="128" height="128">
|
|
4555
|
+
</div>
|
|
4470
4556
|
</div>
|
|
4557
|
+
<div id="tracky-mouse-screen-overlay-message"></div>
|
|
4471
4558
|
</div>
|
|
4472
|
-
<div id="tracky-mouse-screen-overlay-message"></div>
|
|
4473
4559
|
</div>
|
|
4474
4560
|
`;
|
|
4475
4561
|
const fragment = document.createRange().createContextualFragment(template);
|
|
4476
4562
|
document.body.appendChild(fragment);
|
|
4477
4563
|
|
|
4478
4564
|
const message = document.getElementById("tracky-mouse-screen-overlay-message");
|
|
4565
|
+
const workAreaContainer = document.getElementById("tracky-mouse-screen-overlay-work-area");
|
|
4479
4566
|
message.dir = "auto";
|
|
4480
4567
|
|
|
4481
4568
|
const hideNearCursorEls = document.querySelectorAll(".tracky-mouse-hide-near-cursor");
|
|
@@ -4522,9 +4609,30 @@ TrackyMouse.initScreenOverlay = () => {
|
|
|
4522
4609
|
}
|
|
4523
4610
|
|
|
4524
4611
|
function update(data) {
|
|
4525
|
-
const {
|
|
4526
|
-
|
|
4527
|
-
|
|
4612
|
+
const {
|
|
4613
|
+
messageText,
|
|
4614
|
+
isEnabled,
|
|
4615
|
+
isManualTakeback,
|
|
4616
|
+
inputFeedback,
|
|
4617
|
+
workAreaContainerBounds,
|
|
4618
|
+
bottomOffset,
|
|
4619
|
+
systemMousePosition,
|
|
4620
|
+
} = data;
|
|
4621
|
+
|
|
4622
|
+
if (workAreaContainerBounds) {
|
|
4623
|
+
workAreaContainer.style.left = `${workAreaContainerBounds.x}px`;
|
|
4624
|
+
workAreaContainer.style.top = `${workAreaContainerBounds.y}px`;
|
|
4625
|
+
workAreaContainer.style.width = `${workAreaContainerBounds.width}px`;
|
|
4626
|
+
workAreaContainer.style.height = `${workAreaContainerBounds.height}px`;
|
|
4627
|
+
message.style.bottom = "0px";
|
|
4628
|
+
} else {
|
|
4629
|
+
// bottomOffset was a never-released part of an unstable API.
|
|
4630
|
+
// workAreaContainerBounds could be made required, just like bottomOffset was.
|
|
4631
|
+
workAreaContainer.style.left = "0px";
|
|
4632
|
+
workAreaContainer.style.top = "0px";
|
|
4633
|
+
workAreaContainer.style.width = "100%";
|
|
4634
|
+
workAreaContainer.style.height = `calc(100% - ${bottomOffset ?? 0}px)`;
|
|
4635
|
+
}
|
|
4528
4636
|
|
|
4529
4637
|
// Other diagnostics in the future would be stuff like:
|
|
4530
4638
|
// - head too far away (smaller than a certain size) https://github.com/1j01/tracky-mouse/issues/49
|