def __init__(self, program_name, load_profile=False, data=None): self.name = program_name.replace('\\', '').replace('/', '') if data is None and load_profile: data = load_data(data) self.data = data self.file_name = format_name(self.name) self.reload()
def __init__(self, profile, data=None, allow_save=True): self.profile = profile if data is None: self.data = load_data(profile, _update_version=False) else: self.data = data self.name = ImageName(profile, data=self.data) self.save = allow_save
def reload(self, data=None): if data is None: data = load_data(self.name) if self.last_session: self.key_counts = data['Keys']['Session'] self.ticks = data['Ticks']['Total'] - data['Ticks']['Session'][ 'Total'] else: self.key_counts = data['Keys']['All'] self.ticks = data['Ticks']['Total'] self.grid = self._create_grid()
def __init__(self, profile, data=None, allow_save=True): self.profile = profile if data is None: self.data = load_data(profile, _update_version=False, _create_new=False) if self.data is None: raise ValueError('profile doesn\'t exist') else: self.data = data self.name = ImageName(profile, data=self.data) self.save = allow_save
def __init__(self, profile, data=None): if data is None: data = load_data(profile, _update_version=False) self.profile = profile self.data = data
def user_generate(): """Ask for options and generate an image. This seriously needs rewriting. Idea: List of profiles (choose page/type id/type name), shows the file size and last modified date of each profile. (Load profile) Say some stats about the profile Ask for mouse tracks, clicks and key presses For each of those, ask for colour profile and say the file location Ask to open folder (will require image path rewrite for a base path) Loop back to start if required """ all_strings = Language().get_strings() _string = all_strings['string'] string = all_strings['string']['image'] word = all_strings['word'] Message(string['profile']['list'].format(L=word['list'])) profile = input() if profile.lower() == word['list'].lower(): #Read the data folder and format names all_files = list_data_files() if not all_files: Message(string['profile']['empty']) Message(all_strings['exit']) input() sys.exit() programs = {format_name(DEFAULT_NAME): DEFAULT_NAME} app_list = AppList() for program_name in app_list.names: programs[format_name(program_name)] = program_name page = 1 limit = 15 maximum = len(all_files) total_pages = round_up(maximum / limit) sort_date = string['page']['sort']['date'] sort_name = string['page']['sort']['name'] change_sort = [sort_name, 2] #Ask for user input while True: offset = (page - 1) * limit results = all_files[offset:offset + limit] for i, r in enumerate(results): try: program_name = programs[r] except KeyError: program_name = r Message('{}: {}'.format(i + offset + 1, program_name)) Message(string['page']['current'].format(C=page, T=total_pages, P=word['page'])) Message(change_sort[0].format( S='{} {}'.format(word['sort'], change_sort[1]))) Message(string['profile']['number']['input']) profile = input() last_page = page #Change page if profile.lower().startswith('{P} '.format(P=word['page'])): try: page = int(profile.split()[1]) if not 0 < page <= total_pages: raise ValueError except IndexError: Message(string['page']['invalid']) except ValueError: if page > total_pages: page = total_pages else: page = 1 #Shortcut to change page elif profile.endswith('>'): if page < total_pages: page += 1 elif profile.startswith('<'): if page > 1: page -= 1 #Change sorting of profile list elif (profile.lower().startswith('{} '.format(word['sort'])) or profile.lower() == word['sort']): try: sort_level = int(profile.split()[1]) except ValueError: sort_level = 0 except IndexError: sort_level = 1 try: sort_reverse = int(profile.split()[2]) except (ValueError, IndexError): sort_reverse = 0 if sort_level == 1: all_files = list_data_files() change_sort = [sort_name, 2] elif sort_level == 2: all_files = sorted(list_data_files()) change_sort = [sort_date, 1] if sort_reverse: all_files = all_files[::-1] #Select profile else: try: num = int(profile) - 1 if not 0 <= num <= maximum: raise IndexError profile_name = all_files[num] try: profile = programs[all_files[num]] except KeyError: profile = all_files[num] break except ValueError: break except IndexError: Message(string['profile']['number']['nomatch']) try: profile = programs[profile] except KeyError: pass #Load functions Message(_string['import']) from core.image import RenderImage Message(_string['profile']['load'].format(P=profile)) try: r = RenderImage(profile) except ValueError: Message('Error: Selected profile is empty or doesn\'t exist.') return #Check if profile is running try: current_profile = format_name(RunningApplications().check()[0]) except TypeError: pass else: selected_profile = format_name(profile) if current_profile == selected_profile: Message(string['profile']['running']['warning']) save_time = ticks_to_seconds(CONFIG['Save']['Frequency'], 1) metadata = load_data(profile, _metadata_only=True) if metadata['Modified'] is None: Message(string['save']['wait']) Message(string['save']['frequency'].format(T=save_time)) Message(_string['exit']) input() sys.exit() else: last_save_time = time.time() - metadata['Modified'] next_save_time = CONFIG['Save']['Frequency'] - last_save_time last_save = ticks_to_seconds(last_save_time, 1, allow_decimals=False) next_save = ticks_to_seconds(next_save_time, 1, allow_decimals=False) Message(string['save']['next'].format(T1=last_save, T2=next_save)) generate_tracks = False generate_speed = False generate_heatmap = False generate_keyboard = False generate_csv = False default_options = [True, False, True, True, False] kb_string = string['name']['keyboard'] kph = r.keys_per_hour() if kph < 10: default_options[2] = False kb_string = '{} ({})'.format( kb_string, string['name']['low']['keyboard']).format(C=round(kph, 2)) Message(string['option']['generate']) default_option_text = ' '.join( str(i + 1) for i, v in enumerate(default_options) if v) Message(string['option']['select'].format(V=default_option_text)) Message('1: {}'.format(string['name']['track'])) Message('2: {}'.format(string['name']['speed'])) Message('3: {}'.format(string['name']['click'])) Message('4: {}'.format(kb_string)) Message('5: {}'.format(string['name']['csv'])) selection = list(map(int, input().split())) result = value_select(selection, default_options, start=1) if result[0]: generate_tracks = True if result[1]: generate_speed = True if result[2]: generate_heatmap = True Message('Which mouse buttons should be included in the heatmap?.') default_options = [ CONFIG['GenerateHeatmap']['_MouseButtonLeft'], CONFIG['GenerateHeatmap']['_MouseButtonMiddle'], CONFIG['GenerateHeatmap']['_MouseButtonRight'] ] default_option_text = ' '.join( str(i + 1) for i, v in enumerate(default_options) if v) Message(string['option']['select'].format(V=default_option_text)) Message('1: {}'.format(word['mousebutton']['left'])) Message('2: {}'.format(word['mousebutton']['middle'])) Message('3: {}'.format(word['mousebutton']['right'])) selection = list(map(int, input().split())) heatmap_buttons = value_select(selection, default_options, start=1) CONFIG['GenerateHeatmap']['_MouseButtonLeft'] = heatmap_buttons[0] CONFIG['GenerateHeatmap']['_MouseButtonMiddle'] = heatmap_buttons[1] CONFIG['GenerateHeatmap']['_MouseButtonRight'] = heatmap_buttons[2] if not any(heatmap_buttons): generate_heatmap = False if result[3]: generate_keyboard = True if result[4]: generate_csv = True if any((generate_tracks, generate_speed, generate_heatmap, generate_keyboard, generate_csv)): last_session_start = r.data['Ticks']['Session']['Total'] last_session_end = r.data['Ticks']['Total'] all_time = ticks_to_seconds(last_session_end, UPDATES_PER_SECOND) last_session_time = ticks_to_seconds( last_session_end - last_session_start, UPDATES_PER_SECOND) csv_only = generate_csv and not any( (generate_tracks, generate_heatmap, generate_keyboard)) if not last_session_time or last_session_time == all_time or csv_only: last_session = False else: while True: Message(string['option']['session']['select']) Message('1: {} [{}]'.format( string['option']['session']['all'].format(T=all_time), word['default'])) Message('2: {}'.format( string['option']['session']['last'].format( T=last_session_time))) selection = list(map(int, input().split())) result = value_select(selection, [True, False], start=1) if result[0] and result[1]: Message(string['option']['error']['single']) elif result[1]: last_session = True break else: last_session = False break #Generate if generate_tracks: r.tracks(last_session) if generate_speed: r.speed(last_session) if generate_heatmap: r.clicks(last_session) if generate_keyboard: r.keyboard(last_session) if generate_csv: r.csv() if CONFIG['GenerateImages']['OpenOnFinish']: Message(string['option']['open']) open_folder(r.name.generate()) else: Message(string['option']['error']['nothing'])
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