@@ -72,11 +72,8 @@ pub fn spawn_cursor_recorder(
7272 use cap_utils:: spawn_actor;
7373 use device_query:: { DeviceQuery , DeviceState } ;
7474 use futures:: future:: Either ;
75- use std:: {
76- hash:: { DefaultHasher , Hash , Hasher } ,
77- pin:: pin,
78- time:: Duration ,
79- } ;
75+ use sha2:: { Digest , Sha256 } ;
76+ use std:: { pin:: pin, time:: Duration } ;
8077 use tracing:: { error, info} ;
8178
8279 let stop_token = CancellationToken :: new ( ) ;
@@ -100,7 +97,7 @@ pub fn spawn_cursor_recorder(
10097
10198 let mut last_flush = Instant :: now ( ) ;
10299 let flush_interval = Duration :: from_secs ( CURSOR_FLUSH_INTERVAL_SECS ) ;
103- let mut last_cursor_id = "default" . to_string ( ) ;
100+ let mut last_cursor_id: Option < String > = None ;
104101
105102 loop {
106103 let sleep = tokio:: time:: sleep ( Duration :: from_millis ( 16 ) ) ;
@@ -116,51 +113,57 @@ pub fn spawn_cursor_recorder(
116113 let position = cap_cursor_capture:: RawCursorPosition :: get ( ) ;
117114 let position_changed = position != last_position;
118115
119- let cursor_id = if position_changed {
116+ if position_changed {
120117 last_position = position;
121- if let Some ( data) = get_cursor_data ( ) {
122- let mut hasher = DefaultHasher :: default ( ) ;
123- data. image . hash ( & mut hasher) ;
124- let id = hasher. finish ( ) ;
125-
126- let cursor_id = if let Some ( existing_id) = response. cursors . get ( & id) {
127- existing_id. id . to_string ( )
128- } else {
129- let cursor_id = response. next_cursor_id . to_string ( ) ;
130- let file_name = format ! ( "cursor_{cursor_id}.png" ) ;
131- let cursor_path = cursors_dir. join ( & file_name) ;
132-
133- if let Ok ( image) = image:: load_from_memory ( & data. image ) {
134- let rgba_image = image. into_rgba8 ( ) ;
135-
136- if let Err ( e) = rgba_image. save ( & cursor_path) {
137- error ! ( "Failed to save cursor image: {}" , e) ;
138- } else {
139- info ! ( "Saved cursor {cursor_id} image to: {:?}" , file_name) ;
140- response. cursors . insert (
141- id,
142- Cursor {
143- file_name,
144- id : response. next_cursor_id ,
145- hotspot : data. hotspot ,
146- shape : data. shape ,
147- } ,
148- ) ;
149- response. next_cursor_id += 1 ;
150- }
118+ }
119+
120+ let cursor_id = if let Some ( data) = get_cursor_data ( ) {
121+ let hash_bytes = Sha256 :: digest ( & data. image ) ;
122+ let id = u64:: from_le_bytes (
123+ hash_bytes[ ..8 ]
124+ . try_into ( )
125+ . expect ( "sha256 produces at least 8 bytes" ) ,
126+ ) ;
127+
128+ let cursor_id = if let Some ( existing_id) = response. cursors . get ( & id) {
129+ existing_id. id . to_string ( )
130+ } else {
131+ let cursor_id = response. next_cursor_id . to_string ( ) ;
132+ let file_name = format ! ( "cursor_{cursor_id}.png" ) ;
133+ let cursor_path = cursors_dir. join ( & file_name) ;
134+
135+ if let Ok ( image) = image:: load_from_memory ( & data. image ) {
136+ let rgba_image = image. into_rgba8 ( ) ;
137+
138+ if let Err ( e) = rgba_image. save ( & cursor_path) {
139+ error ! ( "Failed to save cursor image: {}" , e) ;
140+ } else {
141+ info ! ( "Saved cursor {cursor_id} image to: {:?}" , file_name) ;
142+ response. cursors . insert (
143+ id,
144+ Cursor {
145+ file_name,
146+ id : response. next_cursor_id ,
147+ hotspot : data. hotspot ,
148+ shape : data. shape ,
149+ } ,
150+ ) ;
151+ response. next_cursor_id += 1 ;
151152 }
153+ }
152154
153- cursor_id
154- } ;
155- last_cursor_id = cursor_id. clone ( ) ;
156155 cursor_id
157- } else {
158- last_cursor_id . clone ( )
159- }
156+ } ;
157+ last_cursor_id = Some ( cursor_id . clone ( ) ) ;
158+ Some ( cursor_id )
160159 } else {
161160 last_cursor_id. clone ( )
162161 } ;
163162
163+ let Some ( cursor_id) = cursor_id else {
164+ continue ;
165+ } ;
166+
164167 if position_changed {
165168 let cropped_norm_pos = position
166169 . relative_to_display ( display)
0 commit comments