Exemple #1
0
    def reload_file(self):

        self.applications = read_app_list(self.application_path,
                                          allow_write=True)

        #Download from the internet and combine with the current list
        last_updated = CONFIG['SavedSettings']['AppListUpdate']
        update_frequency = CONFIG['Internet']['UpdateApplications']

        if not CONFIG['Internet']['Enable'] or not update_frequency:
            return

        #Only update if requirements are met
        next_update = time.time() - update_frequency
        if not self.applications or not last_updated or last_updated < next_update:

            if self.q is not None:
                NOTIFY(APPLIST_UPDATE_START)
                NOTIFY.send(self.q)

            if update_app_list(self.applications):

                CONFIG['SavedSettings']['AppListUpdate'] = int(time.time())
                CONFIG.save()
                self.save_file()

                if self.q is not None:
                    NOTIFY(APPLIST_UPDATE_SUCCESS)
            else:
                if self.q is not None:
                    NOTIFY(APPLIST_UPDATE_FAIL)

            NOTIFY.send(self.q)
Exemple #2
0
def _start_tracking():

    _background_process = None
    no_detection_wait = 2

    try:

        q_feedback = Queue()
        #Setup message server
        if CONFIG['API']['RunServer']:
            q_msg = Queue()
            message = PrintFormat(MessageWithQueue(q_msg).send)
            server_port = get_free_port()
            local_message_server(port=server_port,
                                 q_main=q_msg,
                                 q_feedback=q_feedback)
        else:
            message = PrintFormat(MessageWithQueue().send)
            server_port = None
        #message(NOTIFY.get_output())

        #Setup web server
        if CONFIG['API']['RunWeb']:
            app.config.update(create_pipe('REQUEST', duplex=False))
            app.config.update(create_pipe('CONTROL', duplex=False))
            app.config.update(create_pipe('STATUS', duplex=False))
            app.config.update(create_pipe('PORT', duplex=False))
            app.config.update(create_pipe('CONFIG', duplex=False))
            app.config.update(create_pipe('CONFIG_UPDATE', duplex=False))
            web_port = get_free_port()
            web_port = 65043
            local_web_server(app=app, port=web_port, q_feedback=q_feedback)
        else:
            web_port = None
        message(NOTIFY.get_output())

        #Start main script
        NOTIFY(MT_PATH)
        message(NOTIFY.get_output())
        CONFIG.save()

        #Adjust timings to account for tick rate
        timer = {
            'UpdateScreen': CONFIG['Advanced']['CheckResolution'],
            'UpdatePrograms': CONFIG['Advanced']['CheckRunningApplications'],
            'Save': CONFIG['Save']['Frequency'] * UPDATES_PER_SECOND,
            'ReloadProgramList': CONFIG['Advanced']['ReloadApplicationList'],
            'UpdateQueuedCommands': CONFIG['Advanced']['ShowQueuedCommands'],
            'RefreshGamepads': CONFIG['Advanced']['RefreshGamepads'],
            'HistoryCheck': CONFIG['Advanced']['HistoryCheck']
        }

        store = {
            'Resolution': {
                'Current': monitor_info(),
                'Previous': None,
                'Boundaries': None
            },
            'Mouse': {
                'Position': {
                    'Current': None,
                    'Previous': None
                },
                'NotMoved':
                0,
                'Inactive':
                False,
                'Clicked': {},
                'LastClick':
                None,
                'LastClickTime':
                0,
                'OffScreen':
                False,
                'DoubleClickTime':
                get_double_click_time() / 1000 * UPDATES_PER_SECOND
            },
            'Keyboard': {
                'KeysPressed': {k: False
                                for k in KEYS.keys()},
                'KeysInvalid': set()
            },
            'LastActivity': 0,
            'LastSent': 0,
            'Save': {
                'Finished': True,
                'Next': timer['Save']
            },
            'Gamepad': {
                'ButtonsPressed': {}
            },
            'Flask': {
                'App': app if web_port is not None else None,
                'Port': {
                    'Web': web_port,
                    'Server': server_port
                }
            }
        }
        mouse_pos = store['Mouse']['Position']

        #Start background processes
        q_bg_recv = Queue()
        q_bg_send = Queue()
        _background_process = Process(target=background_process,
                                      args=(q_bg_send, q_bg_recv))
        _background_process.daemon = True
        _background_process.start()

        q_rp_recv = Queue()
        q_rp_send = Queue()
        _running_programs = Thread(target=running_processes,
                                   args=(q_rp_send, q_rp_recv, q_bg_send))
        _running_programs.daemon = True
        _running_programs.start()

        ticks = 0
        NOTIFY(START_MAIN)
        message(NOTIFY.get_output())
        script_status = STATUS_RUNNING
        while script_status != STATUS_TERMINATED:
            with RefreshRateLimiter(UPDATES_PER_SECOND) as limiter:

                #Handle web server API requests
                if store['Flask']['App'] is not None:

                    #Control state of script
                    if store['Flask']['App'].config['PIPE_CONTROL_RECV'].poll(
                    ):
                        api_control = store['Flask']['App'].config[
                            'PIPE_CONTROL_RECV'].recv()

                        #Change if running or paused, or exit script
                        if api_control in (STATUS_RUNNING, STATUS_PAUSED,
                                           STATUS_TERMINATED):
                            script_status = api_control

                        #Set config values
                        if api_control == CONFIG_SET:
                            config_header, config_var, config_val = store[
                                'Flask']['App'].config[
                                    'PIPE_CONFIG_UPDATE_RECV'].recv()
                            CONFIG[config_header][config_var] = config_val
                            print('Set {}.{} to {}'.format(
                                config_header, config_var,
                                CONFIG[config_header][config_var]))

                    #Requests that require response
                    if store['Flask']['App'].config['PIPE_REQUEST_RECV'].poll(
                    ):
                        request_id = store['Flask']['App'].config[
                            'PIPE_REQUEST_RECV'].recv()
                        if request_id == FEEDBACK_STATUS:
                            store['Flask']['App'].config[
                                'PIPE_STATUS_SEND'].send(script_status)
                        elif request_id == FEEDBACK_PORT:
                            store['Flask']['App'].config[
                                'PIPE_PORT_SEND'].send({
                                    'server':
                                    store['Flask']['Port']['Server'],
                                    'web':
                                    store['Flask']['Port']['Web']
                                })
                        elif request_id == FEEDBACK_CONFIG:
                            store['Flask']['App'].config[
                                'PIPE_CONFIG_SEND'].send(CONFIG)

                if script_status != STATUS_RUNNING:
                    continue

                #Send data to thread
                try:
                    if frame_data or frame_data_rp:
                        last_sent = ticks - store['LastSent']
                        if frame_data:
                            if last_sent:
                                frame_data['Ticks'] = last_sent
                            q_bg_send.put(frame_data)
                        if frame_data_rp:
                            q_rp_send.put(frame_data_rp)
                        store['LastSent'] = ticks
                except NameError:
                    pass

                #Get messages from running program thread
                while not q_rp_recv.empty():
                    received = q_rp_recv.get()
                    if isinstance(received, str):
                        message(received, limiter.time)

                    #Do not continue tracking held down keys
                    #This behaviour is sometimes abused for games
                    #but it will continue well after the game is quit
                    elif isinstance(received, dict):
                        if 'Program' in received:
                            store['Keyboard']['KeysInvalid'] |= set([
                                k for k, v in get_items(store['Keyboard']
                                                        ['KeysPressed']) if v
                            ])

                #Print any messages from previous loop
                notify_extra = ''
                received_data = []
                while not q_bg_recv.empty():

                    received_message = q_bg_recv.get()

                    #Receive text messages
                    try:
                        if received_message.startswith(
                                'Traceback (most recent call last)'):
                            q_bg_send.put({'Quit': True})
                            handle_error(received_message)
                    except AttributeError:
                        pass
                    else:
                        received_data.append(received_message)

                    #Get notification when saving is finished
                    try:
                        received_message.pop('SaveFinished')
                    except (KeyError, AttributeError):
                        pass
                    else:
                        store['Save']['Finished'] = True
                        store['Save']['Next'] = ticks + timer['Save']

                output_list = [received_data]

                #Add on output from Notify class
                output_list.append(NOTIFY.get_output())

                #Add output from server
                if CONFIG['API']['RunServer']:
                    received_data = []
                    while not q_feedback.empty():
                        received_data.append(q_feedback.get())
                    output_list.append(received_data)

                #Join all valid outputs together
                output = u' | '.join(u' | '.join(msg_group) if isinstance(
                    msg_group, (list, tuple)) else msg_group
                                     for msg_group in output_list if msg_group)
                if output:
                    message(output, limiter.time)

                frame_data = {}
                frame_data_rp = {}

                #Mouse Movement
                mouse_pos['Current'] = get_cursor_pos()

                #Check if mouse is inactive (such as in a screensaver)
                if mouse_pos['Current'] is None:
                    if not store['Mouse']['Inactive']:
                        NOTIFY(MOUSE_UNDETECTED)
                        store['Mouse']['Inactive'] = True
                    time.sleep(no_detection_wait)
                    continue

                #Check if mouse left the monitor
                elif (not MULTI_MONITOR
                      and (not 0 <= mouse_pos['Current'][0] <
                           store['Resolution']['Current'][0]
                           or not 0 <= mouse_pos['Current'][1] <
                           store['Resolution']['Current'][1])):
                    if not store['Mouse']['OffScreen']:
                        NOTIFY(MOUSE_OFFSCREEN)
                        store['Mouse']['OffScreen'] = True
                elif store['Mouse']['OffScreen']:
                    NOTIFY(MOUSE_ONSCREEN)
                    store['Mouse']['OffScreen'] = False

                #Notify once if mouse is no longer inactive
                if store['Mouse']['Inactive']:
                    store['Mouse']['Inactive'] = False
                    NOTIFY(MOUSE_DETECTED)

                #Check if mouse is in a duplicate position
                if mouse_pos['Current'] is None or mouse_pos[
                        'Current'] == mouse_pos['Previous']:
                    store['Mouse']['NotMoved'] += 1
                elif store['Mouse']['NotMoved']:
                    store['Mouse']['NotMoved'] = 0
                if not store['Mouse']['NotMoved']:
                    if not store['Mouse']['OffScreen']:
                        frame_data['MouseMove'] = (mouse_pos['Previous'],
                                                   mouse_pos['Current'])
                        NOTIFY(MOUSE_POSITION, mouse_pos['Current'])
                        store['LastActivity'] = ticks

                #Mouse clicks
                click_repeat = CONFIG['Advanced']['RepeatClicks']
                for mouse_button, clicked in enumerate(get_mouse_click()):

                    mb_clicked = store['Mouse']['Clicked'].get(
                        mouse_button, False)
                    mb_data = (mouse_button, mouse_pos['Current'])

                    if clicked:
                        store['LastActivity'] = ticks

                        #First click
                        if not mb_clicked:

                            #Double click
                            double_click = False
                            if (store['Mouse']['LastClickTime'] >
                                    ticks - store['Mouse']['DoubleClickTime']
                                    and store['Mouse']['LastClick']
                                    == mb_data):
                                store['Mouse']['LastClickTime'] = 0
                                store['Mouse']['LastClick'] = None
                                double_click = True
                                try:
                                    frame_data['DoubleClick'].append(mb_data)
                                except KeyError:
                                    frame_data['DoubleClick'] = [mb_data]
                            else:
                                store['Mouse']['LastClickTime'] = ticks

                            #Single click
                            store['Mouse']['Clicked'][mouse_button] = ticks

                            if not store['Mouse']['OffScreen']:
                                if double_click:
                                    NOTIFY(MOUSE_CLICKED_DOUBLE, mouse_button,
                                           mouse_pos['Current'])
                                else:
                                    NOTIFY(MOUSE_CLICKED, mouse_button,
                                           mouse_pos['Current'])
                                try:
                                    frame_data['MouseClick'].append(mb_data)
                                except KeyError:
                                    frame_data['MouseClick'] = [mb_data]
                                frame_data['MouseHeld'] = False
                            else:
                                if double_click:
                                    NOTIFY(MOUSE_CLICKED_DOUBLE, mouse_button)
                                else:
                                    NOTIFY(MOUSE_CLICKED, mouse_button)

                        #Held clicks
                        elif click_repeat and mb_clicked < ticks - click_repeat:
                            store['Mouse']['Clicked'][mouse_button] = ticks
                            if not store['Mouse']['OffScreen']:
                                NOTIFY(MOUSE_CLICKED_HELD, mouse_button,
                                       mouse_pos['Current'])
                                try:
                                    frame_data['MouseClick'].append(mb_data)
                                except KeyError:
                                    frame_data['MouseClick'] = [mb_data]
                                frame_data['MouseHeld'] = True
                            else:
                                NOTIFY(MOUSE_CLICKED_HELD, mouse_button)

                        store['Mouse']['LastClick'] = mb_data

                    elif mb_clicked:
                        NOTIFY(MOUSE_UNCLICKED)
                        del store['Mouse']['Clicked'][mouse_button]
                        store['LastActivity'] = ticks

                #Key presses
                keys_pressed = []
                keys_held = []
                key_status = store['Keyboard']['KeysPressed']
                key_press_repeat = CONFIG['Advanced']['RepeatKeyPress']
                key_invalid = store['Keyboard']['KeysInvalid']
                _keys_held = []
                _keys_pressed = []
                _keys_released = []
                for k in KEYS:
                    if get_key_press(KEYS[k]):

                        #Ignore if held down from last profile
                        if k in key_invalid:
                            continue

                        keys_held.append(k)

                        #If key is currently being held down
                        if key_status[k]:
                            if key_press_repeat and key_status[
                                    k] < ticks - key_press_repeat:
                                keys_pressed.append(k)
                                _keys_held.append(k)
                                key_status[k] = ticks

                        #If key has been pressed
                        else:
                            keys_pressed.append(k)
                            _keys_pressed.append(k)
                            key_status[k] = ticks
                            notify_key_press = list(keys_pressed)

                    #If key has been released
                    elif key_status[k]:
                        key_status[k] = False
                        _keys_released.append(k)

                        #Mark key as valid again
                        try:
                            key_invalid.remove(k)
                        except KeyError:
                            pass

                if keys_pressed:
                    frame_data['KeyPress'] = keys_pressed
                    store['LastActivity'] = ticks

                if keys_held:
                    frame_data['KeyHeld'] = keys_held
                    store['LastActivity'] = ticks

                if _keys_pressed:
                    NOTIFY(KEYBOARD_PRESSES, *_keys_pressed)

                if _keys_held:
                    NOTIFY(KEYBOARD_PRESSES_HELD, *_keys_held)

                if _keys_released:
                    NOTIFY(KEYBOARD_RELEASED, *_keys_released)

                if CONFIG['Main']['_TrackGamepads']:
                    #Reload list of gamepads (in case one was plugged in)
                    if timer['RefreshGamepads'] and not ticks % timer[
                            'RefreshGamepads']:
                        try:
                            old_gamepads = set(gamepads)
                        except UnboundLocalError:
                            old_gamepads = set()
                        gamepads = {
                            gamepad.device_number: gamepad
                            for gamepad in Gamepad.list_gamepads()
                        }
                        difference = set(gamepads) - old_gamepads
                        for i, id in enumerate(difference):
                            NOTIFY(GAMEPAD_FOUND, id)
                            store['Gamepad']['ButtonsPressed'][id] = {}

                    #Gamepad tracking (multiple controllers not tested yet)
                    button_repeat = CONFIG['Advanced']['RepeatButtonPress']
                    invalid_ids = []
                    buttons_held = {}
                    _buttons_pressed = {}
                    _buttons_released = {}

                    for id, gamepad in get_items(gamepads):

                        #Repeat presses
                        if button_repeat:
                            for button_id, last_update in get_items(
                                    store['Gamepad']['ButtonsPressed'][id]):
                                if last_update < ticks - button_repeat:
                                    try:
                                        buttons_held[id].append(button_id)
                                    except KeyError:
                                        buttons_held[id] = [button_id]
                                    store['Gamepad']['ButtonsPressed'][id][
                                        button_id] = ticks

                        with gamepad as gamepad_input:

                            #Break the connection if controller can't be found
                            if not gamepad.connected:
                                NOTIFY(GAMEPAD_LOST, id)
                                invalid_ids.append(id)
                                continue

                            #Axis events (thumbsticks, triggers, etc)
                            #Send an update every tick, but only print the changes
                            #The dead zone can be tracked now and ignored later
                            printable = {}
                            axis_updates = gamepad_input.get_axis(
                                printable=printable)
                            if axis_updates:
                                store['LastActivity'] = ticks
                                try:
                                    frame_data['GamepadAxis'].append(
                                        axis_updates)
                                except KeyError:
                                    frame_data['GamepadAxis'] = [axis_updates]
                                for axis, value in get_items(printable):
                                    NOTIFY(GAMEPAD_AXIS, id, axis, value)

                            #Button events
                            button_presses = gamepad_input.get_button()
                            if button_presses:
                                for button_id, state in get_items(
                                        button_presses):

                                    #Button pressed
                                    if state:
                                        try:
                                            frame_data[
                                                'GamepadButtonPress'].append(
                                                    button_id)
                                        except KeyError:
                                            frame_data[
                                                'GamepadButtonPress'] = [
                                                    button_id
                                                ]
                                        store['Gamepad']['ButtonsPressed'][id][
                                            button_id] = ticks
                                        try:
                                            _buttons_pressed[id].append(
                                                button_id)
                                        except KeyError:
                                            _buttons_pressed[id] = [button_id]

                                    #Button has been released
                                    elif button_id in store['Gamepad'][
                                            'ButtonsPressed'][id]:
                                        held_length = ticks - store['Gamepad'][
                                            'ButtonsPressed'][id][button_id]
                                        del store['Gamepad']['ButtonsPressed'][
                                            id][button_id]
                                        try:
                                            _buttons_released[id].append(
                                                button_id)
                                        except KeyError:
                                            _buttons_released[id] = [button_id]

                    #Send held buttons each frame
                    for id, held_buttons in get_items(
                            store['Gamepad']['ButtonsPressed']):
                        if held_buttons:
                            try:
                                frame_data['GamepadButtonHeld'].add(
                                    held_buttons)
                            except KeyError:
                                frame_data['GamepadButtonHeld'] = set(
                                    held_buttons)

                    #Cleanup disconnected controllers
                    for id in invalid_ids:
                        del gamepads[id]
                        del store['Gamepad']['ButtonsPressed'][id]

                    if buttons_held:
                        try:
                            frame_data['GamepadButtonPress'] += buttons_held
                        except KeyError:
                            frame_data['GamepadButtonPress'] = buttons_held
                        store['LastActivity'] = ticks
                        for id, buttons in get_items(buttons_held):
                            NOTIFY(GAMEPAD_BUTTON_HELD, id, buttons)

                    if _buttons_pressed:
                        store['LastActivity'] = ticks
                        for id, buttons in get_items(_buttons_pressed):
                            NOTIFY(GAMEPAD_BUTTON_PRESS, id, buttons)

                    if _buttons_released:
                        store['LastActivity'] = ticks
                        for id, buttons in get_items(_buttons_released):
                            NOTIFY(GAMEPAD_BUTTON_RELEASED, id, buttons)

                #Resolution
                recalculate_mouse = False
                check_resolution = timer[
                    'UpdateScreen'] and not ticks % timer['UpdateScreen']

                #Check if resolution has changed
                if check_resolution:

                    if MULTI_MONITOR:
                        old_resolution = store['Resolution']['Boundaries']
                        store['Resolution']['Boundaries'] = monitor_info()
                        if old_resolution != store['Resolution']['Boundaries']:
                            frame_data['MonitorLimits'] = store['Resolution'][
                                'Boundaries']
                            recalculate_mouse = True
                    else:
                        store['Resolution']['Current'] = monitor_info()
                        if store['Resolution']['Previous'] != store[
                                'Resolution']['Current']:
                            if store['Resolution']['Previous'] is not None:
                                NOTIFY(RESOLUTION_CHANGED,
                                       store['Resolution']['Previous'],
                                       store['Resolution']['Current'])
                            frame_data['Resolution'] = store['Resolution'][
                                'Current']
                            store['Resolution']['Previous'] = store[
                                'Resolution']['Current']

                #Display message that mouse has switched monitors
                if MULTI_MONITOR:
                    try:
                        current_mouse_pos = frame_data['MouseMove'][1]
                    except KeyError:
                        current_mouse_pos = mouse_pos['Current']
                    else:
                        recalculate_mouse = True

                    if recalculate_mouse:
                        try:
                            #Calculate which monitor the mouse is on
                            try:
                                current_screen_resolution = monitor_offset(
                                    current_mouse_pos,
                                    store['Resolution']['Boundaries'])[0]

                            except TypeError:

                                if check_resolution:
                                    raise TypeError

                                #Send to background process if the monitor list changes
                                old_resolution = store['Resolution'][
                                    'Boundaries']
                                store['Resolution'][
                                    'Boundaries'] = monitor_info()
                                if old_resolution != store['Resolution'][
                                        'Boundaries']:
                                    frame_data['MonitorLimits'] = store[
                                        'Resolution']['Boundaries']
                                current_screen_resolution = monitor_offset(
                                    current_mouse_pos,
                                    store['Resolution']['Boundaries'])[0]

                        except TypeError:
                            pass

                        else:
                            if current_screen_resolution != store[
                                    'Resolution']['Previous']:
                                if store['Resolution']['Previous'] is not None:
                                    NOTIFY(MONITOR_CHANGED,
                                           store['Resolution']['Previous'],
                                           current_screen_resolution)
                                store['Resolution'][
                                    'Previous'] = current_screen_resolution

                #Send request to check history list
                if timer['HistoryCheck'] and not ticks % timer['HistoryCheck']:
                    frame_data['HistoryCheck'] = True

                #Send request to update programs
                if timer['UpdatePrograms'] and not ticks % timer[
                        'UpdatePrograms']:
                    frame_data_rp['Update'] = True

                #Send request to reload program list
                if timer['ReloadProgramList'] and not ticks % timer[
                        'ReloadProgramList']:
                    frame_data_rp['Reload'] = True

                #Update user about the queue size
                if (timer['UpdateQueuedCommands']
                        and not ticks % timer['UpdateQueuedCommands']
                        and timer['Save']
                        and store['LastActivity'] > ticks - timer['Save']):
                    try:
                        NOTIFY(QUEUE_SIZE, q_bg_send.qsize())
                    except NotImplementedError:
                        pass

                #Send save request
                if store['Save']['Finished'] and ticks and not ticks % store[
                        'Save']['Next']:
                    frame_data['Save'] = True
                    store['Save']['Finished'] = False

                if store['Mouse']['OffScreen']:
                    mouse_pos['Previous'] = None
                else:
                    mouse_pos['Previous'] = mouse_pos['Current']
                ticks += 1

    except Exception as e:
        if _background_process is not None:
            try:
                q_bg_send.put({'Quit': True})
            except IOError:
                pass
        handle_error(traceback.format_exc())

    except KeyboardInterrupt:
        if _background_process is not None:
            try:
                q_bg_send.put({'Quit': True})
            except IOError:
                pass
        NOTIFY(THREAD_EXIT)
        NOTIFY(PROCESS_EXIT)
        message(NOTIFY.get_output())
        handle_error()
Exemple #3
0
def start_tracking():

    _background_process = None
    no_detection_wait = 2

    try:
        NOTIFY(MT_PATH)
        _print(u'{} {}'.format(time_format(time.time()), NOTIFY.get_output()))
        CONFIG.save()

        timer = {
            'UpdateScreen': CONFIG['Advanced']['CheckResolution'],
            'UpdatePrograms': CONFIG['Advanced']['CheckRunningApplications'],
            'Save': CONFIG['Save']['Frequency'] * UPDATES_PER_SECOND,
            'ReloadProgramList': CONFIG['Advanced']['ReloadApplicationList'],
            'UpdateQueuedCommands': CONFIG['Advanced']['ShowQueuedCommands']
        }

        store = {
            'Resolution': {
                'Current': monitor_info(),
                'Previous': None,
                'Boundaries': None
            },
            'Mouse': {
                'Position': {
                    'Current': None,
                    'Previous': None
                },
                'NotMoved': 0,
                'Inactive': False,
                'Clicked': {},
                'LastClick': None,
                'LastClickTime': 0,
                'OffScreen': False,
                'DoubleClickTime': get_double_click_time() / 1000
            },
            'Keyboard': {
                'KeysPressed': {k: False
                                for k in KEYS.keys()}
            },
            'LastActivity': 0,
            'LastSent': 0,
            'Save': {
                'Finished': True,
                'Next': timer['Save']
            }
        }
        mouse_pos = store['Mouse']['Position']

        #Start background processes
        q_bg_send = Queue()
        q_bg_recv = Queue()
        _background_process = Process(target=background_process,
                                      args=(q_bg_send, q_bg_recv))
        _background_process.daemon = True
        _background_process.start()

        q_rp_send = Queue()
        q_rp_recv = Queue()
        _running_programs = ThreadHelper(running_processes, q_rp_send,
                                         q_rp_recv, q_bg_send)
        _running_programs.daemon = True
        _running_programs.start()

        i = 0
        NOTIFY(START_MAIN)
        _print(u'{} {}'.format(time_format(time.time()), NOTIFY.get_output()))
        while True:
            with RefreshRateLimiter(UPDATES_PER_SECOND) as limiter:

                #Send data to thread
                try:
                    if frame_data or frame_data_rp:
                        last_sent = i - store['LastSent']
                        if frame_data:
                            if last_sent:
                                frame_data['Ticks'] = last_sent
                            q_bg_send.put(frame_data)
                        if frame_data_rp:
                            q_rp_send.put(frame_data_rp)
                        store['LastSent'] = i
                except NameError:
                    pass

                while not q_rp_recv.empty():
                    _print(u'{} {}'.format(time_format(limiter.time),
                                           q_rp_recv.get()))

                #Print any messages from previous loop
                notify_extra = ''
                received_data = []
                while not q_bg_recv.empty():

                    received_message = q_bg_recv.get()

                    #Receive text messages
                    try:
                        if received_message.startswith(
                                'Traceback (most recent call last)'):
                            q_bg_send.put({'Quit': True})
                            handle_error(received_message)
                    except AttributeError:
                        pass
                    else:
                        received_data.append(received_message)

                    #Get notification when saving is finished
                    try:
                        received_message.pop('SaveFinished')
                    except (KeyError, AttributeError):
                        pass
                    else:
                        store['Save']['Finished'] = True
                        store['Save']['Next'] = i + timer['Save']

                if received_data:
                    notify_extra = u' | '.join(received_data)
                notify_output = NOTIFY.get_output()

                if notify_extra:
                    if notify_output:
                        notify_output = notify_extra + ' | ' + notify_output
                    else:
                        notify_output = notify_extra
                if notify_output:
                    _print(u'{} {}'.format(time_format(limiter.time),
                                           notify_output))

                frame_data = {}
                frame_data_rp = {}
                mouse_pos['Current'] = get_cursor_pos()

                #Check if mouse is inactive (such as in a screensaver)
                if mouse_pos['Current'] is None:
                    if not store['Mouse']['Inactive']:
                        NOTIFY(MOUSE_UNDETECTED)
                        store['Mouse']['Inactive'] = True
                    time.sleep(no_detection_wait)
                    continue

                #Check if mouse left the monitor
                elif (not MULTI_MONITOR
                      and (not 0 <= mouse_pos['Current'][0] <
                           store['Resolution']['Current'][0]
                           or not 0 <= mouse_pos['Current'][1] <
                           store['Resolution']['Current'][1])):
                    if not store['Mouse']['OffScreen']:
                        NOTIFY(MOUSE_OFFSCREEN)
                        store['Mouse']['OffScreen'] = True
                elif store['Mouse']['OffScreen']:
                    NOTIFY(MOUSE_ONSCREEN)
                    store['Mouse']['OffScreen'] = False

                #Notify once if mouse is no longer inactive
                if store['Mouse']['Inactive']:
                    store['Mouse']['Inactive'] = False
                    NOTIFY(MOUSE_DETECTED)

                #Check if mouse is in a duplicate position
                if mouse_pos['Current'] is None or mouse_pos[
                        'Current'] == mouse_pos['Previous']:
                    store['Mouse']['NotMoved'] += 1
                elif store['Mouse']['NotMoved']:
                    store['Mouse']['NotMoved'] = 0
                if not store['Mouse']['NotMoved']:
                    if not store['Mouse']['OffScreen']:
                        frame_data['MouseMove'] = (mouse_pos['Previous'],
                                                   mouse_pos['Current'])
                        NOTIFY(MOUSE_POSITION, mouse_pos['Current'])
                        store['LastActivity'] = i

                #Mouse clicks
                click_repeat = CONFIG['Advanced']['RepeatClicks']
                for mouse_button, clicked in enumerate(get_mouse_click()):

                    mb_clicked = store['Mouse']['Clicked'].get(
                        mouse_button, False)
                    mb_data = (mouse_button, mouse_pos['Current'])

                    if clicked:
                        store['LastActivity'] = i

                        #First click
                        if not mb_clicked:

                            #Double click
                            double_click = False
                            if (store['Mouse']['LastClickTime'] > limiter.time
                                    - store['Mouse']['DoubleClickTime'] and
                                    store['Mouse']['LastClick'] == mb_data):
                                store['Mouse']['LastClickTime'] = 0
                                store['Mouse']['LastClick'] = None
                                double_click = True
                                try:
                                    frame_data['DoubleClick'].append(mb_data)
                                except KeyError:
                                    frame_data['DoubleClick'] = [mb_data]
                            else:
                                store['Mouse']['LastClickTime'] = limiter.time

                            #Single click
                            store['Mouse']['Clicked'][
                                mouse_button] = limiter.time

                            if not store['Mouse']['OffScreen']:
                                if double_click:
                                    NOTIFY(MOUSE_CLICKED_DOUBLE, mouse_button,
                                           mouse_pos['Current'])
                                else:
                                    NOTIFY(MOUSE_CLICKED, mouse_button,
                                           mouse_pos['Current'])
                                try:
                                    frame_data['MouseClick'].append(mb_data)
                                except KeyError:
                                    frame_data['MouseClick'] = [mb_data]
                                frame_data['MouseHeld'] = False
                            else:
                                if double_click:
                                    NOTIFY(MOUSE_CLICKED_DOUBLE, mouse_button)
                                else:
                                    NOTIFY(MOUSE_CLICKED, mouse_button)

                        #Held clicks
                        elif click_repeat and mb_clicked < limiter.time - click_repeat:
                            store['Mouse']['Clicked'][
                                mouse_button] = limiter.time
                            if not store['Mouse']['OffScreen']:
                                NOTIFY(MOUSE_CLICKED_HELD, mouse_button,
                                       mouse_pos['Current'])
                                try:
                                    frame_data['MouseClick'].append(mb_data)
                                except KeyError:
                                    frame_data['MouseClick'] = [mb_data]
                                frame_data['MouseHeld'] = True
                            else:
                                NOTIFY(MOUSE_CLICKED_HELD, mouse_button)

                        store['Mouse']['LastClick'] = mb_data

                    elif mb_clicked:
                        NOTIFY(MOUSE_UNCLICKED)
                        del store['Mouse']['Clicked'][mouse_button]
                        store['LastActivity'] = i

                #Key presses
                keys_pressed = []
                keys_held = []
                key_status = store['Keyboard']['KeysPressed']
                key_press_repeat = CONFIG['Advanced']['RepeatKeyPress']
                _keys_held = []
                _keys_pressed = []
                for k in KEYS:
                    if get_key_press(KEYS[k]):
                        keys_held.append(k)

                        #If key is currently being held down
                        if key_status[k]:
                            if key_press_repeat and key_status[
                                    k] < limiter.time - key_press_repeat:
                                keys_pressed.append(k)
                                _keys_held.append(k)
                                key_status[k] = limiter.time

                        #If key has been pressed
                        else:
                            keys_pressed.append(k)
                            _keys_pressed.append(k)
                            key_status[k] = limiter.time
                            notify_key_press = list(keys_pressed)

                    #If key has been released
                    elif key_status[k]:
                        key_status[k] = False

                if keys_pressed:
                    frame_data['KeyPress'] = keys_pressed
                if keys_held:
                    frame_data['KeyHeld'] = keys_held
                    store['LastActivity'] = i
                if _keys_held:
                    NOTIFY(KEYBOARD_PRESSES_HELD, _keys_held)
                if _keys_pressed:
                    NOTIFY(KEYBOARD_PRESSES, _keys_pressed)

                recalculate_mouse = False

                #Check if resolution has changed
                if timer['UpdateScreen'] and not i % timer['UpdateScreen']:

                    if MULTI_MONITOR:
                        try:
                            old_resolution = list(
                                store['Resolution']['Boundaries'])
                        except TypeError:
                            old_resolution = None
                        store['Resolution']['Boundaries'] = monitor_info()
                        frame_data['MonitorLimits'] = store['Resolution'][
                            'Boundaries']
                        if old_resolution != store['Resolution']['Boundaries']:
                            recalculate_mouse = True
                    else:
                        store['Resolution']['Current'] = monitor_info()
                        if store['Resolution']['Previous'] != store[
                                'Resolution']['Current']:
                            if store['Resolution']['Previous'] is not None:
                                NOTIFY(RESOLUTION_CHANGED,
                                       store['Resolution']['Previous'],
                                       store['Resolution']['Current'])
                            frame_data['Resolution'] = ['Resolution'
                                                        ]['Current']
                            store['Resolution']['Previous'] = store[
                                'Resolution']['Current']

                #Display message that mouse has switched monitors
                if MULTI_MONITOR:
                    try:
                        current_mouse_pos = frame_data['MouseMove'][1]
                    except KeyError:
                        current_mouse_pos = mouse_pos['Current']
                    else:
                        recalculate_mouse = True

                    if recalculate_mouse:
                        try:
                            try:
                                res = monitor_offset(
                                    current_mouse_pos,
                                    store['Resolution']['Boundaries'])[0]
                            except TypeError:
                                frame_data['MonitorLimits'] = monitor_info()
                                store['Resolution']['Boundaries'] = frame_data[
                                    'MonitorLimits']
                                res = monitor_offset(
                                    current_mouse_pos,
                                    store['Resolution']['Boundaries'])[0]
                        except TypeError:
                            pass
                        else:
                            store['Resolution']['Current'] = res
                            if store['Resolution']['Previous'] is not None:
                                if store['Resolution']['Current'] != store[
                                        'Resolution']['Previous']:
                                    NOTIFY(MONITOR_CHANGED,
                                           store['Resolution']['Previous'],
                                           store['Resolution']['Current'])
                            store['Resolution']['Previous'] = store[
                                'Resolution']['Current']

                #Send request to update programs
                if timer['UpdatePrograms'] and not i % timer['UpdatePrograms']:
                    frame_data_rp['Update'] = True

                #Send request to reload program list
                if timer['ReloadProgramList'] and not i % timer[
                        'ReloadProgramList']:
                    frame_data_rp['Reload'] = True

                #Update user about the queue size
                if (timer['UpdateQueuedCommands']
                        and not i % timer['UpdateQueuedCommands']
                        and timer['Save']
                        and store['LastActivity'] > i - timer['Save']):
                    try:
                        NOTIFY(QUEUE_SIZE, q_bg_send.qsize())
                    except NotImplementedError:
                        pass

                #Send save request
                if store['Save'][
                        'Finished'] and i and not i % store['Save']['Next']:
                    frame_data['Save'] = True
                    store['Save']['Finished'] = False

                if store['Mouse']['OffScreen']:
                    mouse_pos['Previous'] = None
                else:
                    mouse_pos['Previous'] = mouse_pos['Current']
                i += 1

    except Exception as e:
        if _background_process is not None:
            try:
                q_bg_send.put({'Quit': True})
            except IOError:
                pass
        handle_error(traceback.format_exc())

    except KeyboardInterrupt:
        if _background_process is not None:
            try:
                q_bg_send.put({'Quit': True})
            except IOError:
                pass
        NOTIFY(THREAD_EXIT)
        NOTIFY(PROCESS_EXIT)
        _print(u'{} {}'.format(time_format(time.time()), NOTIFY.get_output()))
        handle_error()
Exemple #4
0
def user_generate():
    CONFIG.save()
    print('Type profile to load, or type "list" to see them all:')
    profile = raw_input()

    if profile == 'list':

        #Read the data folder and format names
        all_files = sorted(list_data_files())
        if not all_files:
            print('Sorry, nothing was found in the data folder.')
            print('Press enter to exit.')
            raw_input()
            sys.exit()
        programs = {format_name(DEFAULT_NAME): DEFAULT_NAME}
        for program_name in read_app_list().values():
            programs[format_name(program_name)] = program_name

        page = 1
        limit = 15
        maximum = len(all_files)
        total_pages = round_up(maximum / limit)

        #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
                print('{}: {}'.format(i + offset + 1, program_name))
            print('Page {} of {}. Type "page <number>" to switch.'.format(
                page, total_pages))
            print('You can type the number or name of a profile to load it.')

            profile = raw_input()
            last_page = page
            if profile.startswith('page '):
                try:
                    page = int(profile.split()[1])
                    if not 0 < page <= total_pages:
                        raise ValueError
                except IndexError:
                    print('Invalid page number')
                except ValueError:
                    if page > total_pages:
                        page = total_pages
                    else:
                        page = 1
            elif profile == '>':
                if page < total_pages:
                    page += 1
            elif profile == '<':
                if page > 1:
                    page -= 1
            else:
                try:
                    num = int(profile) - 1
                    if not 0 <= num <= maximum:
                        raise IndexError
                    try:
                        profile = programs[all_files[num]]
                    except KeyError:
                        profile = all_files[num]
                    break
                except ValueError:
                    break
                except IndexError:
                    print('Number doesn\'t match any profiles')

    try:
        current_profile = format_name(RunningApplications().check()[0])
    except TypeError:
        pass
    else:
        selected_profile = format_name(profile)

        if current_profile == selected_profile:
            print('Warning: The profile you selected is currently running.')

            save_time = ticks_to_seconds(CONFIG['Save']['Frequency'], 1)
            metadata = load_program(profile, _metadata_only=True)
            if metadata['Modified'] is None:
                print(
                    'It has not had a chance to save yet, please wait a short while before trying again.'
                )
                print('The saving frequency is currently set to {}.'.format(
                    save_time))
                print('Press enter to exit.')
                raw_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)
                print(
                    'It was last saved {} ago, so any tracks more recent than this will not be shown.'
                    .format(last_save))
                print('The next save is due in roughly {}.'.format(next_save))

    generate_tracks = False
    generate_heatmap = False

    print('What do you want to generate?')
    print('Separate options with a space, or hit enter for all.')
    print('1: Tracks')
    print('2: Click Heatmap')

    result = simple_bit_mask(raw_input().split(), 2)

    if result[0]:
        generate_tracks = True

    if result[1]:

        generate_heatmap = True
        print('Which mouse buttons should be included in the heatmap?.')
        print('Separate options with a space, or hit enter for all.')
        print('1: Left Mouse Button')
        print('2: Middle Mouse Button')
        print('3: Right Mouse Button')
        heatmap_buttons = map(bool, simple_bit_mask(raw_input().split(), 3))
        CONFIG['GenerateHeatmap']['_MouseButtonLeft'] = heatmap_buttons[0]
        CONFIG['GenerateHeatmap']['_MouseButtonMiddle'] = heatmap_buttons[1]
        CONFIG['GenerateHeatmap']['_MouseButtonRight'] = heatmap_buttons[2]
        if not heatmap_buttons:
            generate_heatmap = False

    if generate_tracks or generate_heatmap:
        print('Importing modules...')
        from core.image import RenderImage

        print('Loading profile {}...'.format(profile))
        r = RenderImage(profile)

        last_session_start = r.data['Ticks']['Session']['Total']
        last_session_end = r.data['Ticks']['Total']
        ups = CONFIG['Main']['UpdatesPerSecond']
        all_time = ticks_to_seconds(last_session_end, ups)
        last_session_time = ticks_to_seconds(
            last_session_end - last_session_start, ups)

        if not last_session_time or last_session_time == all_time:
            last_session = False

        else:
            while True:
                print(
                    'Would you like to generate everything or just the last session?'
                )
                print('1: Everything ({}) [Default]'.format(all_time))
                print('2: Last Session ({})'.format(last_session_time))

                result = simple_bit_mask(raw_input().split(),
                                         2,
                                         default_all=False)
                if result[0] and result[1]:
                    print('Please only select one option.')
                elif result[1]:
                    last_session = True
                    break
                else:
                    last_session = False
                    break

        #Generate
        if generate_tracks:
            r.generate('Tracks', last_session)
        if generate_heatmap:
            r.generate('Clicks', last_session)
    else:
        print('Nothing was set to generate.')
Exemple #5
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
    """
    CONFIG.save()

    all_strings = Language().get_strings()
    _string = all_strings['string']
    string = all_strings['string']['image']
    word = all_strings['word']

    _print(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:
            _print(string['profile']['empty'])
            _print(all_strings['exit'])
            input()
            sys.exit()
        programs = {format_name(DEFAULT_NAME): DEFAULT_NAME}

        app_list = read_app_list()
        for program_name in app_list.values():
            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
                _print('{}: {}'.format(i + offset + 1, program_name))
            _print(string['page']['current'].format(C=page,
                                                    T=total_pages,
                                                    P=word['page']))

            _print(change_sort[0].format(
                S='{} {}'.format(word['sort'], change_sort[1])))
            _print(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:
                    _print(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:
                    _print(string['profile']['number']['nomatch'])

        try:
            profile = programs[profile]
        except KeyError:
            pass

    #Load functions
    _print(_string['import'])
    from core.image import RenderImage

    _print(_string['profile']['load'].format(P=profile))
    try:
        r = RenderImage(profile)
    except ValueError:
        _print('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:
            _print(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:
                _print(string['save']['wait'])
                _print(string['save']['frequency'].format(T=save_time))
                _print(_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)
                _print(string['save']['next'].format(T1=last_save,
                                                     T2=next_save))

    generate_tracks = False
    generate_heatmap = False
    generate_keyboard = False
    generate_csv = False

    default_options = [True, 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'],
            string['name']['low']['steam']).format(C=round(kph, 2))

    _print(string['option']['generate'])
    default_option_text = ' '.join(
        str(i + 1) for i, v in enumerate(default_options) if v)
    _print(string['option']['select'].format(V=default_option_text))
    _print('1: {}'.format(string['name']['track']))
    _print('2: {}'.format(string['name']['click']))
    _print('3: {}'.format(kb_string))
    _print('4: {}'.format(string['name']['csv']))

    selection = map(int, input().split())
    result = value_select(selection, default_options, start=1)

    if result[0]:
        generate_tracks = True

    if result[1]:

        generate_heatmap = True
        _print('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)
        _print(string['option']['select'].format(V=default_option_text))

        _print('1: {}'.format(word['mousebutton']['left']))
        _print('2: {}'.format(word['mousebutton']['middle']))
        _print('3: {}'.format(word['mousebutton']['right']))
        selection = 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[2]:
        generate_keyboard = True

    if result[3]:
        generate_csv = True

    if any(
        (generate_tracks, 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:
                _print(string['option']['session']['select'])

                _print('1: {} [{}]'.format(
                    string['option']['session']['all'].format(T=all_time),
                    word['default']))
                _print('2: {}'.format(
                    string['option']['session']['last'].format(
                        T=last_session_time)))

                selection = map(int, input().split())
                result = value_select(selection, [True, False], start=1)
                if result[0] and result[1]:
                    _print(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_heatmap:
            r.clicks(last_session)
        if generate_keyboard:
            r.keyboard(last_session)
        if generate_csv:
            r.csv()

    else:
        _print(string['option']['error']['nothing'])
import time
import traceback
from multiprocessing import freeze_support

from core.config import CONFIG
from core.misc import error_output
from core.main import start_tracking


if __name__ == '__main__':

    freeze_support()

    #Rewrite the config with validated values
    CONFIG.save()

    #Run the script and exit safely if an error happens
    try:
        error = start_tracking()
        if error.startswith('Traceback (most recent call last)'):
            error_output(error)
    except Exception as e:
        error_output(traceback.format_exc())