def on_suggest(self, user_input, items_chain): if (not items_chain or items_chain[0].category() != kp.ItemCategory.KEYWORD or items_chain[0].target() != "jumpfile"): return with self.wa_mutex: playlist = self.wa.get_tracks_titles() if not playlist: return suggestions = [] desc_fmt = "Requests Winamp to jump to track #{:0" + str( len(str(len(playlist)))) + "}" for idx in range(len(playlist)): title = playlist[idx] if title is None: continue # if user_input is empty, just match everything we get include_track = 1 if len(user_input) > 0: #include_track = True if user_input.lower() in title.lower() else False include_track = kpu.fuzzy_score(user_input, title) > 0 if include_track: clone = items_chain[0].clone() clone.set_args(str(idx), title) clone.set_short_desc(desc_fmt.format(idx + 1)) suggestions.append(clone) if len(suggestions) > 0: self.set_suggestions(suggestions)
def on_suggest(self, user_input, items_chain): if not items_chain or items_chain[0].category( ) != kp.ItemCategory.KEYWORD: return suggestions = [] data_bag = kpu.kwargs_decode(items_chain[0].data_bag()) sessions = self._distros[data_bag['distro_name']]['sessions'] for session in sessions: session_name = str(session).replace('\\', '/') if not user_input or kpu.fuzzy_score(user_input, session_name) > 0: suggestions.append( self.create_item( category=kp.ItemCategory.REFERENCE, label=session_name, short_desc='Open "{}" with HeidiSQL'.format( session_name), target=kpu.kwargs_encode( distro_name=data_bag['distro_name'], session=session), args_hint=kp.ItemArgsHint.FORBIDDEN, hit_hint=kp.ItemHitHint.IGNORE)) self.set_suggestions(suggestions, kp.Match.ANY, kp.Sort.NONE)
def _home_suggestions(self, search_terms): # suggest only existing home dirs existing_home_dirs = [] for home_dir in self.home: if os.path.isdir(home_dir): existing_home_dirs.append(home_dir) # If only one home dir remains, directly browse its content and filter # the results using search_terms, if any. if len(existing_home_dirs) == 1: suggestions, match_method, sort_method = self._browse_dir( existing_home_dirs[0], check_base_dir=False, search_terms=search_terms, store_score=True) if len(search_terms) > 0: # Because of the self.home_trigger prefix, the user_input cannot # be matched against files names. So we have to sort the # suggestions by ourselves. self._sort_matched_suggestions(suggestions) return suggestions, kp.Match.ANY, kp.Sort.NONE else: return suggestions, match_method, sort_method # Otherwise, we must first offer the list of available "home" # directories. Here again, we filter them by using search_terms if # needed. else: suggestions = [] for home_dir in existing_home_dirs: match_score = None if len(search_terms) > 0: match_score = kpu.fuzzy_score(search_terms, os.path.basename(home_dir)) if not match_score: continue match_score = str(match_score) suggestions.append( self.create_item(category=kp.ItemCategory.FILE, label=os.path.basename(home_dir), short_desc="", target=home_dir, args_hint=kp.ItemArgsHint.ACCEPTED, hit_hint=kp.ItemHitHint.KEEPALL, loop_on_suggest=True, data_bag=match_score)) if len(search_terms) > 0: # Because of the self.home_trigger prefix, the user_input cannot be # matched against files names. So we have to sort the suggestions by # ourselves. self._sort_matched_suggestions(suggestions) return suggestions, kp.Match.ANY, kp.Sort.NONE
def on_suggest(self, user_input, items_chain): if not items_chain or items_chain[0].category( ) != kp.ItemCategory.FILE: return suggestions = [] data_bag = kpu.kwargs_decode(items_chain[0].data_bag()) current_distro = self._distros[data_bag['distro_name']] current_distro_path = os.path.dirname( os.path.abspath(current_distro['exe_file'])) sessions = current_distro['sessions'] for session_name in sessions: displayed_session_name = session_name.replace( os.path.join(current_distro_path, 'Sessions') + os.sep, '') if not user_input or kpu.fuzzy_score(user_input, displayed_session_name) > 0: suggestions.append( self.create_item(category=kp.ItemCategory.REFERENCE, label="{}".format(displayed_session_name), short_desc='Launch "{}" session'.format( displayed_session_name), target=kpu.kwargs_encode( dist=data_bag['distro_name'], session=session_name), args_hint=kp.ItemArgsHint.FORBIDDEN, hit_hint=kp.ItemHitHint.IGNORE)) if user_input: suggestions.append( self.create_item( category=kp.ItemCategory.REFERENCE, label="{}".format(user_input), short_desc='Launch "{}" directly'.format(user_input), target=kpu.kwargs_encode(dist=data_bag['distro_name'], host_name=user_input), args_hint=kp.ItemArgsHint.FORBIDDEN, hit_hint=kp.ItemHitHint.IGNORE)) self.set_suggestions(suggestions, kp.Match.ANY, kp.Sort.NONE)
def on_suggest(self, user_input, items_chain): if not items_chain and (not self.always_suggest or len(user_input) == 0): return if items_chain and ( items_chain[0].category() != kp.ItemCategory.KEYWORD or items_chain[0].target() != self.KEYWORD): return try: handles = AltTab.list_alttab_windows() except OSError as exc: self.err("Failed to list Alt+Tab windows.", str(exc)) return suggestions = [] procs = {} for hwnd in handles: # get window's title and the id of its parent process try: wnd_title = AltTab.get_window_text(hwnd) (_, proc_id) = AltTab.get_window_thread_process_id(hwnd) if proc_id == kp.pid(): continue # skip any window from main keypirinha's process except OSError: continue # Get the name of its parent process. # We have to OpenProcess to do that. Unfortunately, Vista and beyond # won't allow us to do so if the remote process has higher # privileges than us. if proc_id in procs: proc_image = procs[proc_id] else: try: proc_image = AltTab.get_process_image_path(proc_id) except OSError: proc_image = None procs[proc_id] = proc_image # build the final label of the suggestion item item_label = wnd_title item_short_desc = "{}: {}".format(self.item_label, wnd_title) if proc_image is not None: proc_name = os.path.splitext(os.path.basename(proc_image))[0] if self.proc_name_first: item_label = proc_name + ": " + item_label #item_short_desc = proc_name + ": " + item_short_desc else: item_label += " (" + proc_name + ")" item_short_desc += " (" + proc_name + ")" # if user_input is empty, just match everything we get match_score = 1 if len(user_input) > 0: if items_chain and items_chain[0]: against = item_label else: against = self.item_label + " " + item_label match_score = kpu.fuzzy_score(user_input, against) if match_score: suggestion = self._create_keyword_item(self.item_label, item_short_desc, target=proc_image) suggestion.set_args(str(hwnd), item_label) suggestions.append(suggestion) if len(suggestions) > 0: self.set_suggestions(suggestions)
def _enum_key(self, keypath, user_input="", show_error=True, loop_on_current=True): def _sort_names(sequence, do_natsort): if do_natsort: yield from natsort.natsorted(sequence, alg=natsort.ns.GROUPLETTERS | natsort.ns.LOCALE | natsort.ns.IGNORECASE) else: yield from sequence def _sort_items(sequence): # sort items using the score that is stored in the data_bag member, # then clear it to avoid polluting the Catalog and the History def _sortkey(item): score = item.data_bag() item.set_data_bag("") return score sequence.sort(key=_sortkey, reverse=True) user_input = user_input.strip() if not len(user_input): user_input = None items = [] # open registry key try: hkey = winreg.OpenKey(keypath.root_hkey, keypath.subkey) except OSError as exc: if show_error: items.append( self.create_error_item( label=keypath.path, short_desc="Registry key not found: " + keypath.path)) return items # enumerate keys and values subkeys = {} values = {} try: idx = 0 while True: try: name = winreg.EnumKey(hkey, idx) idx += 1 if len(name): if user_input is None: score = None else: score = kpu.fuzzy_score(user_input, name) if score is None or score > 0: subkeys[name] = score except OSError: break # enum values idx = 0 while True: try: val = _KeyValue(*winreg.EnumValue(hkey, idx)) idx += 1 if user_input is None: score = None elif not len(val.name): score = 1 # name may be empty for the "(Default)" value else: score = kpu.fuzzy_score(user_input, val.name) if score is None or score > 0: values[val.name] = (val, score) except OSError: break finally: hkey.Close() for subkey_name in _sort_names(subkeys.keys(), user_input is None): full_path = keypath.path + "\\" + subkey_name data_bag = None if subkeys[subkey_name] is None else str( subkeys[subkey_name]) items.append( self.create_item(category=self.ITEMCAT_REGKEY, label=subkey_name, short_desc=full_path, target=full_path, args_hint=kp.ItemArgsHint.ACCEPTED, hit_hint=kp.ItemHitHint.IGNORE, loop_on_suggest=True, data_bag=data_bag)) for value_name in _sort_names(values.keys(), user_input is None): full_path = keypath.path + "\\" + value_name data_bag = None if values[value_name][1] is None else str( values[value_name][1]) if values[value_name][0].data_type in ( winreg.REG_SZ, winreg.REG_MULTI_SZ, winreg.REG_EXPAND_SZ, winreg.REG_LINK, winreg.REG_RESOURCE_LIST, winreg.REG_FULL_RESOURCE_DESCRIPTOR, winreg.REG_RESOURCE_REQUIREMENTS_LIST): icon = self.icon_strvalue else: icon = self.icon_binvalue items.append( self.create_item( category=self.ITEMCAT_REGVALUE, label="(Default)" if not len(value_name) else value_name, short_desc=full_path, target=full_path, args_hint=kp.ItemArgsHint.FORBIDDEN, hit_hint=kp.ItemHitHint.IGNORE, loop_on_suggest=False, icon_handle=icon, data_bag=data_bag)) if user_input is None: items.insert( 0, self.create_item(category=self.ITEMCAT_REGKEY, label="\\", short_desc=keypath.path, target=keypath.path, args_hint=kp.ItemArgsHint.ACCEPTED, hit_hint=kp.ItemHitHint.IGNORE, loop_on_suggest=loop_on_current)) else: _sort_items(items) return items
def _insert_recents(self, suggestions, match_method=kp.Match.ANY, sort_method=kp.Sort.NONE, search_terms=""): recents = [] if search_terms: search_terms = os.path.normcase(os.path.normpath(search_terms)) try: with winreg.OpenKey( winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\TypedPaths" ) as hkey: url_idx = 0 while True: (name, value, typ) = winreg.EnumValue(hkey, url_idx) url_idx += 1 if typ == winreg.REG_SZ and name.lower().startswith("url"): # we must check that value is a path since value can # also be the name of a known folder like "Computer" value = os.path.normpath(value) if not (os.path.isabs(value) or os.path.ismount(value)): continue if search_terms and not os.path.normcase( value).startswith(search_terms): continue if match_method == kp.Match.FUZZY: score = str(kpu.fuzzy_score(search_terms, value)) else: score = None recents.append( self.create_item( category=kp.ItemCategory.FILE, label=value, short_desc="", target=value, args_hint=kp.ItemArgsHint.ACCEPTED, hit_hint=kp.ItemHitHint.KEEPALL, loop_on_suggest=True, data_bag=score)) except OSError as exc: pass if sort_method == kp.Sort.NONE: def _find_same_item(target, lst): target = os.path.normpath(target) for idx in range(len(lst)): if target == os.path.normpath(lst[idx].target()): return idx return None # remove duplicates by ourselves so Keypirinha does not try to merge # them, which may alter the desired positioning of items for recent_item in recents: match_idx = _find_same_item(recent_item.target(), suggestions) if match_idx is not None: suggestions.pop(match_idx) recents = natsort.natsorted(recents, key=lambda x: x.label(), alg=natsort.ns.PATH | natsort.ns.LOCALE | natsort.ns.IGNORECASE) # prepend the recents list to the suggestions # but always keep the "." item at the top if len(suggestions) > 0 and suggestions[0].label() == ".": suggestions[1:0] = recents else: suggestions[:0] = recents else: # note: Keypirinha will take care of removing duplicates suggestions += recents