Ejemplo n.º 1
0
 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()
Ejemplo n.º 2
0
 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
Ejemplo n.º 3
0
 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()
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
 def __init__(self, profile, data=None):
     if data is None:
         data = load_data(profile, _update_version=False)
     self.profile = profile
     self.data = data
Ejemplo n.º 6
0
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'])
Ejemplo n.º 7
0
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