From ad87c966ea6551d1f039d7201e9a00a9a7931f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nar=C4=99bski?= Date: Wed, 10 Sep 2025 02:07:27 +0200 Subject: [PATCH 1/5] EyeTracker: Use distinct "remark" for distinct error --- src/main/java/trackers/EyeTracker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/trackers/EyeTracker.java b/src/main/java/trackers/EyeTracker.java index 207026e..13919c0 100644 --- a/src/main/java/trackers/EyeTracker.java +++ b/src/main/java/trackers/EyeTracker.java @@ -224,7 +224,7 @@ public void processRawData(String message) { editorX = editor.getContentComponent().getLocationOnScreen().x; editorY = editor.getContentComponent().getLocationOnScreen().y; } catch (IllegalComponentStateException e) { - gaze.setAttribute("remark", "Fail | No Editor"); + gaze.setAttribute("remark", "Fail | IllegalComponentStateException in Editor"); return; } int relativeX = eyeX - editorX; From 6c8871193b6d3b42fc7df590c32a170aee9684ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nar=C4=99bski?= Date: Wed, 10 Sep 2025 02:15:50 +0200 Subject: [PATCH 2/5] EyeTracker: Introduce isGazeNormalized field This field is to be used in the cases where eye-tracker hardware (or eye-tracker emulation) returns position in pixels, rather than normalized position in the 0.0..1.0 that needs to be rescaled. --- src/main/java/trackers/EyeTracker.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/trackers/EyeTracker.java b/src/main/java/trackers/EyeTracker.java index 13919c0..46bafd6 100644 --- a/src/main/java/trackers/EyeTracker.java +++ b/src/main/java/trackers/EyeTracker.java @@ -61,6 +61,12 @@ public class EyeTracker implements Disposable { String pythonScriptTobii; String pythonScriptMouse; int deviceIndex = 0; + /** + * This variable indicates whether the gaze coordinates are normalized to the screen size, + * that is returned as values between (0, 0) for the upper left corner and (1, 1) for the lower right corner. + * See, for example, 'Coordinate system' page in Tobii Pro SDK documentation + */ + boolean isGazeNormalized = true; /** * This variable indicates whether the real-time data is transmitting. @@ -216,8 +222,14 @@ public void processRawData(String message) { return; } - int eyeX = (int) ((Double.parseDouble(leftGazePointX) + Double.parseDouble(rightGazePointX)) / 2 * screenWidth); - int eyeY = (int) ((Double.parseDouble(leftGazePointY) + Double.parseDouble(rightGazePointY)) / 2 * screenHeight); + int eyeX, eyeY; + if (isGazeNormalized) { + eyeX = (int) ((Double.parseDouble(leftGazePointX) + Double.parseDouble(rightGazePointX)) / 2 * screenWidth); + eyeY = (int) ((Double.parseDouble(leftGazePointY) + Double.parseDouble(rightGazePointY)) / 2 * screenHeight); + } else { + eyeX = (int) ((Double.parseDouble(leftGazePointX) + Double.parseDouble(rightGazePointX)) / 2); + eyeY = (int) ((Double.parseDouble(leftGazePointY) + Double.parseDouble(rightGazePointY)) / 2); + } int editorX, editorY; try { From c6f39f3ec34a09d68233e0de658cfe59a3ca9270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nar=C4=99bski?= Date: Wed, 10 Sep 2025 10:20:53 +0200 Subject: [PATCH 3/5] AvailabilityChecker: Remove hard requirement on tobii_research Now tobii_research [1][2] module does not need to be installed to be able to use mouse emulation. [1]: https://developer.tobiipro.com/python.html [2]: https://pypi.org/project/tobii-research/ This change removes 'import tobii_research as tr' from checkPythonEnvironment() method, and adjusts checkEyeTracker() and getEyeTrackerName() to work correctly even if tobii_research is not installed. Not tested yet. The problem with requiring tobii_research is that it requires specific Python version to be able to be installed: 3.8 or 3.10 [3][4][5] [3]: https://www.tobii.com/products/software/applications-and-developer-kits/tobii-pro-sdk [4]: https://developer.tobiipro.com/tobiiprosdk/platform-and-language.html [5]: https://codegrits.github.io/CodeGRITS/usage-guide/#python-environment --- src/main/java/utils/AvailabilityChecker.java | 29 ++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/utils/AvailabilityChecker.java b/src/main/java/utils/AvailabilityChecker.java index a47f51f..72af8a7 100644 --- a/src/main/java/utils/AvailabilityChecker.java +++ b/src/main/java/utils/AvailabilityChecker.java @@ -19,7 +19,6 @@ public class AvailabilityChecker { */ public static boolean checkPythonEnvironment(String pythonInterpreter) throws IOException, InterruptedException { String pythonScript = """ - import tobii_research as tr from screeninfo import get_monitors import pyautogui import time @@ -41,13 +40,17 @@ public static boolean checkPythonEnvironment(String pythonInterpreter) throws IO */ public static boolean checkEyeTracker(String pythonInterpreter) throws IOException, InterruptedException { String pythonScript = """ - import tobii_research as tr + try: + import tobii_research as tr - found_eyetrackers = tr.find_all_eyetrackers() - if found_eyetrackers == (): + found_eyetrackers = tr.find_all_eyetrackers() + if found_eyetrackers == (): + print('Not Found') + else: + print('Found') + + except ImportError: print('Not Found') - else: - print('Found') """; String line = runPythonScript(pythonInterpreter, pythonScript); @@ -62,13 +65,17 @@ public static boolean checkEyeTracker(String pythonInterpreter) throws IOExcepti */ public static String getEyeTrackerName(String pythonInterpreter) throws IOException, InterruptedException { String pythonScript = """ - import tobii_research as tr + try: + import tobii_research as tr - found_eyetrackers = tr.find_all_eyetrackers() - if found_eyetrackers == (): + found_eyetrackers = tr.find_all_eyetrackers() + if found_eyetrackers == (): + print('Not Found') + else: + print(found_eyetrackers[0].device_name) + + except ImportError: print('Not Found') - else: - print(found_eyetrackers[0].device_name) """; return runPythonScript(pythonInterpreter, pythonScript); From 41d3db261798fc7e78190a5df92043a52b8fb6b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nar=C4=99bski?= Date: Wed, 10 Sep 2025 10:32:28 +0200 Subject: [PATCH 4/5] build.gradle.kts: Bump version, adding "-dev1" suffix --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8b3ed5d..e304ac1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -5,7 +5,7 @@ plugins { } group = "io.github.codegrits" -version = "0.3.2" +version = "0.3.2-dev1" repositories { mavenCentral() From 34e6d887f61a315113e3473c586f82f2d7ee4551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Nar=C4=99bski?= Date: Wed, 10 Sep 2025 11:52:37 +0200 Subject: [PATCH 5/5] EyeTracker: Add "tracker_name" attribute for Tobii eye-tracker This information is available, but was not added to the eye_tracking.xml file generated by CodeGRITS. --- src/main/java/trackers/EyeTracker.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/trackers/EyeTracker.java b/src/main/java/trackers/EyeTracker.java index 46bafd6..beea483 100644 --- a/src/main/java/trackers/EyeTracker.java +++ b/src/main/java/trackers/EyeTracker.java @@ -16,6 +16,7 @@ import org.jetbrains.annotations.NotNull; import org.w3c.dom.Document; import org.w3c.dom.Element; +import utils.AvailabilityChecker; import utils.RelativePathGetter; import utils.XMLWriter; @@ -163,6 +164,14 @@ public void startTracking(Project project) throws IOException { setting.setAttribute("eye_tracker", "Mouse"); } else { setting.setAttribute("eye_tracker", "Tobii Pro Fusion"); + try { + String trackerName = AvailabilityChecker.getEyeTrackerName(pythonInterpreter); + if (trackerName != null && !trackerName.equals("Not Found")) { + setting.setAttribute("tracker_name", trackerName); + } + } catch (InterruptedException | IOException e) { + // just don't add the "tracker_name" attribute + } } setting.setAttribute("sample_frequency", String.valueOf(sampleFrequency)); track();