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)
from core.config import CONFIG from core.redisquery import RedisQuery from core.httpd import init_httpd_thread from core.cli import Cli from core.ui import UI from core.mysqlquery import MySQLQuery if __name__ == "__main__": UI.banner() if len(sys.argv) < 3: UI.error( "Missing configuration file path or username\n\nUsage: %s config username (optional -nohttpd)" % sys.argv[0], True) config = CONFIG(sys.argv[1]) if config.reload_config(): config = CONFIG(sys.argv[1]) profile = config.get("http-profile") if not profile == "": Utils.file_exists(profile, True) profile = CONFIG(profile) config.set("profile", profile) uid = Utils.guid() config.set("uid", uid) config.set("username", "(CLI)%s" % sys.argv[2]) db = RedisQuery(config) sql = MySQLQuery(config) sql.install_db().init_uid()
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()
Utils.start_redis() from core.config import CONFIG from core.redisquery import RedisQuery from core.httpd import init_httpd_thread from core.gui import init_gui_thread from core.cli import Cli if __name__ == '__main__': if len(sys.argv) < 3: UI.error( '''Missing configuration file path or username\n\n Usage: %s config username (optional -nohttpd, -nogui)''' % sys.argv[0], True) config = CONFIG(sys.argv[1]) if config.reload_config(): config = CONFIG(sys.argv[1]) profile = config.get('http-profile') if not profile == '': Utils.file_exists(profile, True) profile = CONFIG(profile) config.set('profile', profile) uid = Utils.guid() config.set('uid', uid) config.set('username', '%s' % sys.argv[2]) db = RedisQuery(config) config.set('redis', db)
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()
import sys from core.config import CONFIG from core.redisquery import RedisQuery from core.httpd import init_httpd_thread from core.cli import Cli from core.ui import UI if __name__ == "__main__": UI.banner() if len(sys.argv) < 2: UI.error( "Missing configuration file path\n\nUsage: %s config (optional -nohttpd)" % sys.argv[0], True) config = CONFIG(sys.argv[1]) db = RedisQuery(config) config.set("redis", db) # Launch the HTTPD daemon if not "-nohttpd" in sys.argv: httpd_thread = init_httpd_thread(config) cli = Cli(config) while True: try: cmd = cli.prompt() cli.parse_cmd(cmd) except KeyboardInterrupt as e:
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.')
""" import os import sys from core.config import CONFIG from core.redisquery import RedisQuery from core.httpd import init_httpd_thread from core.cli import Cli from core.ui import UI if __name__ == "__main__": UI.banner() if len(sys.argv) < 2: UI.error("Missing configuration file path\n\nUsage: %s config (optional -nohttpd)" % sys.argv[0], True) config = CONFIG(sys.argv[1]) db = RedisQuery(config) config.set("redis", db) # Launch the HTTPD daemon if not "-nohttpd" in sys.argv: httpd_thread = init_httpd_thread(config) cli = Cli(config) while True: try: cmd = cli.prompt() cli.parse_cmd(cmd)
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'])
from core.config import CONFIG from core.redisquery import RedisQuery from core.httpd import init_httpd_thread from core.gui import init_gui_thread from core.cli import Cli from core.mysqlquery import MySQLQuery if __name__ == '__main__': if len(sys.argv) < 3: UI.error( '''Missing configuration file path or username\n\n Usage: %s config username (optional -nohttpd, -gui)''' % sys.argv[0], True) config = CONFIG(sys.argv[1]) if config.reload_config(): config = CONFIG(sys.argv[1]) profile = config.get('http-profile') if not profile == '': Utils.file_exists(profile, True) profile = CONFIG(profile) config.set('profile', profile) uid = Utils.guid() config.set('uid', uid) config.set('username', '(CLI)%s' % sys.argv[2]) db = RedisQuery(config) sql = MySQLQuery(config) sql.install_db().init_uid()
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())
def start(self): self.channel = CONFIG.get('output_hpfeed', 'channel', fallback='elasticpot') if CONFIG.has_option('output_hpfeed', 'endpoint'): endpoint = CONFIG.get('output_hpfeed', 'endpoint') else: server = CONFIG.get('output_hpfeed', 'server') port = CONFIG.getint('output_hpfeed', 'port') if CONFIG.has_option('output_hpfeed', 'tlscert'): with open(CONFIG.get('output_hpfeed', 'tlscert')) as fp: authority = ssl.Certificate.loadPEM(fp.read()) options = ssl.optionsForClientTLS(server, authority) endpoint = endpoints.SSL4ClientEndpoint( reactor, server, port, options) else: endpoint = endpoints.HostnameEndpoint(reactor, server, port) try: self.tags = [ tag.strip() for tag in CONFIG.get('output_hpfeed', 'tags').split(',') ] except Exception as e: self.tags = [] ident = CONFIG.get('output_hpfeed', 'identifier') secret = CONFIG.get('output_hpfeed', 'secret') reported_ip = CONFIG.get('output_hpfeed', 'reported_ip') if reported_ip and reported_ip != '': self.reported_ip = reported_ip else: self.reported_ip = None self.client = ClientSessionService(endpoint, ident, secret) self.client.startService()