def _get_track_map(self, track_type, session=False): """Return dictionary of tracks along with top resolution and range of values. TODO: Test sum of arrays vs length of arrays to get top resolution """ start_time = self['Ticks']['Session'][track_type] if session else 0 top_resolution = None max_records = 0 min_value = float('inf') max_value = -float('inf') result = {} for resolution, maps in get_items(self['Resolution']): array = numpy.max(maps[track_type] - start_time, 0) num_records = numpy.count(array) if num_records: result[resolution] = array #Find resolution with most data if num_records > max_records: max_records = num_records top_resolution = resolution #Find the highest and lowest recorded values min_value = min(min_value, numpy.min(array)) max_value = max(max_value, numpy.max(array)) if not result: return None return top_resolution, (int(min_value), int(max_value)), result
def _iterate(self, maps, command, extra=None): for key in maps.keys(): if isinstance(key, str): self._iterate(maps[key], command, extra) elif command == 'separate': array = maps[key] maps[key] = len(self._map_list) self._map_list.append(array) elif command == 'join': index = maps[key] maps[key] = extra[index] elif command == 'convert': array = maps[key] width, height = key numpy_array = numpy.array((width, height), create=True, dtype='int64') for x, y in array: numpy_array[y][x] = array[(x, y)] maps[key] = numpy_array elif command == 'trim': if key == (0, 0): del maps[key] #Delete any empty maps #Disabled for now as groups currently need each resolution to exist if False and not numpy.count(maps[key]): del maps[key]
def get_clicks(self, double_click=False, session=False): session = 'Session' if session else 'All' click_type = 'Double' if double_click else 'Single' top_resolution = None max_records = 0 min_value = float('inf') max_value = -float('inf') result = {} for resolution, maps in get_items(self['Resolution']): click_maps = (maps['Clicks'][session][click_type]['Left'], maps['Clicks'][session][click_type]['Middle'], maps['Clicks'][session][click_type]['Right']) #Get information on array contains_data = False for array in click_maps: num_records = numpy.count(array) if num_records: contains_data = True #Find resolution with most data if num_records > max_records: max_records = num_records top_resolution = resolution #Find the highest and lowest recorded values min_value = min(min_value, numpy.min(array)) max_value = max(max_value, numpy.max(array)) if contains_data: result[resolution] = click_maps if not result: return None return top_resolution, (int(min_value), int(max_value)), result
def _generate(self, resolution, data): if numpy.count(data) < CONFIG['GenerateCSV']['MinimumPoints']: return None output = numpy.set_type(data, str) return '\n'.join(','.join(row) for row in output)
def background_process(q_recv, q_send): """Function to handle all the data from the main thread.""" try: NOTIFY(START_THREAD) NOTIFY.send(q_send) store = {'Data': load_data(), 'LastProgram': None, 'Resolution': None, 'ResolutionTemp': None, 'Offset': (0, 0), 'LastResolution': None, 'ActivitySinceLastSave': False, 'SavesSkipped': 0, 'CustomResolution': None, 'LastClick': None, 'KeyTrack': {'LastKey': None, 'Time': None, 'Backspace': False} } NOTIFY(DATA_LOADED) try: NOTIFY(QUEUE_SIZE, q_recv.qsize()) except NotImplementedError: pass NOTIFY.send(q_send) while True: received_data = q_recv.get() check_resolution = False #Increment the amount of time the script has been running for if 'Ticks' in received_data: store['Data']['Ticks']['Total'] += received_data['Ticks'] #Save the data if 'Save' in received_data: if store['ActivitySinceLastSave']: _save_wrapper(q_send, store['LastProgram'], store['Data'], False) store['ActivitySinceLastSave'] = False store['SavesSkipped'] = 0 try: NOTIFY(QUEUE_SIZE, q_recv.qsize()) except NotImplementedError: pass else: store['SavesSkipped'] += 1 try: NOTIFY(SAVE_SKIP, CONFIG['Save']['Frequency'] * store['SavesSkipped'], q_recv.qsize()) except NotImplementedError: pass q_send.put({'SaveFinished': None}) #Check for new program loaded if 'Program' in received_data: current_program = received_data['Program'] if current_program != store['LastProgram']: if current_program is None: NOTIFY(APPLICATION_LOADING) else: NOTIFY(APPLICATION_LOADING, current_program) NOTIFY.send(q_send) #Save old profile _save_wrapper(q_send, store['LastProgram'], store['Data'], True) #Load new profile store['LastProgram'] = current_program store['Data'] = load_data(current_program) store['ActivitySinceLastSave'] = False #Check new resolution try: store['CustomResolution'] = received_data['CustomResolution'] except AttributeError: pass if store['CustomResolution'] is None: _check_resolution(store['Data']['Maps'], store['Resolution']) else: _check_resolution(store['Data']['Maps'], store['CustomResolution'][1]) if store['Data']['Ticks']['Total']: NOTIFY(DATA_LOADED) else: NOTIFY(DATA_NOTFOUND) try: NOTIFY(QUEUE_SIZE, q_recv.qsize()) except NotImplementedError: pass NOTIFY.send(q_send) if 'CustomResolution' in received_data: store['CustomResolution'] = received_data['CustomResolution'] if store['CustomResolution'] is not None: _check_resolution(store['Data']['Maps'], store['CustomResolution'][1]) if 'Resolution' in received_data: store['Resolution'] = received_data['Resolution'] _check_resolution(store['Data']['Maps'], store['Resolution']) if 'MonitorLimits' in received_data: store['ResolutionTemp'] = received_data['MonitorLimits'] #Record key presses if 'KeyPress' in received_data: store['ActivitySinceLastSave'] = True for key in received_data['KeyPress']: _record_keypress(store['Data']['Keys'], 'Pressed', key) #Record mistakes if key == 'BACK': last = store['KeyTrack']['LastKey'] if last is not None and last != 'BACK': store['KeyTrack']['Backspace'] = last else: store['KeyTrack']['Backspace'] = False elif store['KeyTrack']['Backspace']: _record_keypress(store['Data']['Keys'], 'Mistakes', store['KeyTrack']['Backspace'], key) store['KeyTrack']['Backspace'] = False #Record interval between key presses if store['KeyTrack']['Time'] is not None: time_difference = store['Data']['Ticks']['Total'] - store['KeyTrack']['Time'] _record_keypress(store['Data']['Keys'], 'Intervals', 'Total', time_difference) _record_keypress(store['Data']['Keys'], 'Intervals', 'Individual', store['KeyTrack']['LastKey'], key, time_difference) store['KeyTrack']['LastKey'] = key store['KeyTrack']['Time'] = store['Data']['Ticks']['Total'] #Record time keys are held down if 'KeyHeld' in received_data: store['ActivitySinceLastSave'] = True for key in received_data['KeyHeld']: _record_keypress(store['Data']['Keys'], 'Held', key) #Calculate and track mouse movement if 'MouseMove' in received_data: store['ActivitySinceLastSave'] = True resolution = 0 _resolution = -1 start, end = received_data['MouseMove'] #distance = find_distance(end, start) #Calculate the pixels in the line if end is None: raise TypeError('debug - mouse moved without coordinates') if start is None: mouse_coordinates = [end] else: mouse_coordinates = [start] + calculate_line(start, end) + [end] #Make sure resolution exists in data if store['CustomResolution'] is not None: _check_resolution(store['Data']['Maps'], store['CustomResolution'][1]) elif MULTI_MONITOR: try: #Don't bother calculating offset for each pixel #if both start and end are on the same monitor resolution, (x_offset, y_offset) = monitor_offset(start, store['ResolutionTemp']) _resolution = monitor_offset(end, store['ResolutionTemp'])[0] except TypeError: if not resolution: mouse_coordinates = [] else: _check_resolution(store['Data']['Maps'], resolution) if resolution != _resolution: _check_resolution(store['Data']['Maps'], resolution) _resolutions = [resolution, _resolution] #Write each pixel to the dictionary for (x, y) in mouse_coordinates: try: (x, y), resolution = _find_resolution_offset(x, y, store) except TypeError: continue store['Data']['Maps']['Tracks'][resolution][y][x] = store['Data']['Ticks']['Tracks'] store['Data']['Ticks']['Tracks'] += 1 #Compress tracks if the count gets too high max_track_value = CONFIG['Advanced']['CompressTrackMax'] if not max_track_value: max_track_value = MAX_INT if store['Data']['Ticks']['Tracks'] > max_track_value: compress_multplier = CONFIG['Advanced']['CompressTrackAmount'] NOTIFY(TRACK_COMPRESS_START, 'track') NOTIFY.send(q_send) tracks = store['Data']['Maps']['Tracks'] for resolution in tracks.keys(): tracks[resolution] = numpy.divide(tracks[resolution], compress_multplier, as_int=True) if not numpy.count(tracks[resolution]): del tracks[resolution] NOTIFY(TRACK_COMPRESS_END, 'track') try: NOTIFY(QUEUE_SIZE, q_recv.qsize()) except NotImplementedError: pass store['Data']['Ticks']['Tracks'] //= compress_multplier store['Data']['Ticks']['Session']['Tracks'] //= compress_multplier store['Data']['Ticks']['Tracks'] = int(store['Data']['Ticks']['Tracks']) store['Data']['Ticks']['Session']['Tracks'] = int(store['Data']['Ticks']['Session']['Tracks']) #Record mouse clicks if 'MouseClick' in received_data: store['ActivitySinceLastSave'] = True for mouse_button_index, (x, y) in received_data['MouseClick']: try: (x, y), resolution = _find_resolution_offset(x, y, store) except TypeError: continue mouse_button = ['Left', 'Middle', 'Right'][mouse_button_index] store['Data']['Maps']['Click']['Single'][mouse_button][resolution][y][x] += 1 store['Data']['Maps']['Session']['Click']['Single'][mouse_button][resolution][y][x] += 1 #Record double clicks if 'DoubleClick' in received_data: store['ActivitySinceLastSave'] = True for mouse_button_index, (x, y) in received_data['DoubleClick']: try: (x, y), resolution = _find_resolution_offset(x, y, store) except TypeError: continue mouse_button = ['Left', 'Middle', 'Right'][mouse_button_index] store['Data']['Maps']['Click']['Double'][mouse_button][resolution][y][x] += 1 store['Data']['Maps']['Session']['Click']['Double'][mouse_button][resolution][y][x] += 1 store['Data']['Ticks']['Recorded'] += 1 if 'Quit' in received_data or 'Exit' in received_data: break NOTIFY.send(q_send) #Exit process (this shouldn't happen for now) NOTIFY(THREAD_EXIT) NOTIFY.send(q_send) _save_wrapper(q_send, store['LastProgram'], store['Data'], False) except Exception as e: q_send.put(traceback.format_exc()) except KeyboardInterrupt: pass