diff --git a/PortMaster/control.txt b/PortMaster/control.txt index c7d3a02..8fd7dd6 100644 --- a/PortMaster/control.txt +++ b/PortMaster/control.txt @@ -133,10 +133,19 @@ else DEVICE="${1}" param_device="${2}" fi + export SDL_GAMECONTROLLERCONFIG_FILE="/tmp/gamecontrollerdb.txt" - CONTROLS=`grep "${SDLDBUSERFILE}" -e "${DEVICE}"` - [ -z "${CONTROLS}" ] && CONTROLS=`grep "${SDLDBFILE}" -e "${DEVICE}"` - sdl_controllerconfig="${CONTROLS}" + # Spit the controller of the device our heuristics found (if it did). + if [[ ! -z ${DEVICE} ]]; then + grep "${SDLDBUSERFILE}" -e "${DEVICE}" > /tmp/gamecontrollerdb.txt + else + echo "" > /tmp/gamecontrollerdb.txt + fi + + $controlfolder/mapper.txt /tmp/gamecontrollerdb.txt > /dev/null 2>&1 + SDLDBUSERFILE="${HOME}/.config/SDL-GameControllerDB/gamecontrollerdb.txt" + + sdl_controllerconfig="$(< "${SDL_GAMECONTROLLERCONFIG_FILE}")" } GPTOKEYB="$ESUDO $controlfolder/gptokeyb $ESUDOKILL" diff --git a/PortMaster/gptokeyb b/PortMaster/gptokeyb index 7be3f5c..108be2d 100644 Binary files a/PortMaster/gptokeyb and b/PortMaster/gptokeyb differ diff --git a/PortMaster/mapper.txt b/PortMaster/mapper.txt new file mode 100755 index 0000000..a5b566d --- /dev/null +++ b/PortMaster/mapper.txt @@ -0,0 +1,135 @@ +#!/bin/bash + +# -- Config & Setup -- +# Destination file +if [[ -z "$1" ]]; then + echo "Usage: mapper [gamecontrollerdb.txt]" + exit -1 +fi + +CONTROLLER_DB="$1" +if [[ ! -f "${CONTROLLER_DB}" ]]; then + echo "File ${CONTROLLER_DB} does not exist." + exit -1 +fi + +# Where the emulationstation configuration file is +ES_CONFIG="${HOME}/.config/emulationstation/es_input.cfg" + +# -- Helper function -- +# Map the actual button/hat/axis +function map { + INPUT_NAME=$1 + TYPE=$2 + ID=$3 + VALUE=$4 + + map_x_result="" + case "${INPUT_NAME}" in + "b") TR_NAME="a";; + "a") TR_NAME="b";; + "y") TR_NAME="x";; + "x") TR_NAME="y";; + "hotkeyenable") TR_NAME="guide";; + "up") TR_NAME="dpup";; + "down") TR_NAME="dpdown";; + "left") TR_NAME="dpleft";; + "right") TR_NAME="dpright";; + "leftshoulder") TR_NAME="leftshoulder";; + "leftthumb") TR_NAME="leftstick";; + "lefttrigger") TR_NAME="lefttrigger";; + "rightshoulder") TR_NAME="rightshoulder";; + "rightthumb") TR_NAME="rightstick";; + "righttrigger") TR_NAME="righttrigger";; + "select") TR_NAME="back";; + "start") TR_NAME="start";; + "leftanalogup") TR_NAME="-lefty";; + "leftanalogleft") TR_NAME="-leftx";; + "leftanalogdown") TR_NAME="+lefty";; + "leftanalogright") TR_NAME="+leftx";; + "rightanalogup") TR_NAME="-righty";; + "rightanalogleft") TR_NAME="-rightx";; + "rightanalogdown") TR_NAME="+righty";; + "rightanalogright") TR_NAME="+rightx";; + *) + echo "Invalid mapping ${INPUT_NAME}." + return + ;; + esac + + case "${TYPE}" in + "axis") + if (( $VALUE < 0 )); then + map_x_result="${TR_NAME}:${map_x_result}-a${ID}," + else + # Most (save for a few misbehaved children...) triggers are [0, 1] instead of [-1, 1] + # Shitty workaround for an emulationstation issue + if [[ $INPUT_NAME =~ .*"trigger" ]]; then + map_x_result="${TR_NAME}:${map_x_result}a${ID}," + else + map_x_result="${TR_NAME}:${map_x_result}+a${ID}," + fi + fi + ;; + "button") + map_x_result="${TR_NAME}:${map_x_result}b${ID}," + ;; + "hat") + map_x_result="${TR_NAME}:${map_x_result}h${ID}.${VALUE}," + ;; + *) + echo "Invalid entry ${TYPE}" + ;; + esac +} + +function get_map_suffix { + map_suffix="platform:Linux," +} + +function get_map_prefix { + map_prefix="${GUID},${NAME}," +} + +# query controllers mapped in emulationstation, ignore devices without a GUID +ES_QUERY="$(xmlstarlet sel -T -t -m "inputList/inputConfig[@deviceGUID!='']" -n -v "concat(@deviceName,';',@deviceGUID)" $ES_CONFIG)" +printf "\n# Custom Entries\n" >> "${CONTROLLER_DB}" + +echo "## ES Dev Mapper ##" +while IFS=";" read -r NAME GUID; do + echo "$NAME :: $GUID" + # Ignore keyboards + if [[ "${GUID}" == -1 ]]; then + continue + fi + + # Check if GUID exists in gamecontrollerdb.txt + if [ -z "$(fgrep -- ${GUID} "${CONTROLLER_DB}")" ]; then + # Query this specific GUID on the mappings + MAPPING_CFG=$(xmlstarlet sel -T -t -m "//inputConfig[@deviceGUID = '${GUID}']/input" -n -v "concat(@name,';',@type,';',@id,';',@value)" $ES_CONFIG) + + MAPPING="" + while IFS=";" read -r -e INPUT_NAME TYPE ID VALUE; do + # Map the controller + map "${INPUT_NAME}" "${TYPE}" "${ID}" "${VALUE}" + + # Only concatenate valid mappings + if [[ ! -z ${map_x_result} ]]; then + MAPPING="${MAPPING}${map_x_result}" + fi + done <<< ${MAPPING_CFG:1} + + get_map_prefix + get_map_suffix + if [[ ! -z "${MAPPING}" ]]; then + echo "${map_prefix}${MAPPING}${map_suffix}" >> "${CONTROLLER_DB}" + echo "${map_prefix}${MAPPING}${map_suffix}" + echo "" + else + echo "Failed to map anything." + echo "" + fi + else + echo "Already mapped..." + fi +done <<< ${ES_QUERY:1} diff --git a/PortMaster/pugwash b/PortMaster/pugwash index 1dd578c..1b15ce3 100755 --- a/PortMaster/pugwash +++ b/PortMaster/pugwash @@ -1,7 +1,7 @@ #!/usr/bin/env python3 ## -- BEGIN PORTMASTER INFO -- -PORTMASTER_VERSION = '8.5.4' +PORTMASTER_VERSION = '8.5.5' PORTMASTER_RELEASE_CHANNEL = 'beta' ## -- END PORTMASTER INFO -- diff --git a/PortMaster/pylibs/harbourmaster/harbour.py b/PortMaster/pylibs/harbourmaster/harbour.py index c40b7b0..1d96ff7 100644 --- a/PortMaster/pylibs/harbourmaster/harbour.py +++ b/PortMaster/pylibs/harbourmaster/harbour.py @@ -817,6 +817,11 @@ def port_info_attrs(self, port_info): if rtr: add_list_unique(attrs, 'rtr') + if rtr: + add_list_unique(attrs, ('full', 'demo')[ord(port_info['name'][0]) % 2]) + else: + add_list_unique(attrs, ('free', 'paid')[ord(port_info['name'][0]) % 2]) + exp = port_info.get('attr', {}).get('exp', False) if exp: add_list_unique(attrs, 'exp') @@ -1175,8 +1180,12 @@ def _install_portmaster(self, download_file): zf.extract(file_info, path=self.tools_dir) if move_bash and dest_file.name.lower().endswith('.sh'): - self.callback.message(f"- moving {dest_file} to {self.cfg_dir / dest_file.name}") - os.replace(dest_file, self.tools_dir / dest_file.name) + move_bash_dir = self.platform.MOVE_PM_BASH_DIR + if move_bash_dir is None or not move_bash_dir.is_dir(): + move_bash_dir = self.cfg_dir + + self.callback.message(f"- moving {dest_file} to {move_bash_dir / dest_file.name}") + os.replace(dest_file, move_bash_dir / dest_file.name) self.set_gcd_mode(gcd_mode) diff --git a/PortMaster/pylibs/harbourmaster/platform.py b/PortMaster/pylibs/harbourmaster/platform.py index b45ab64..b523f85 100644 --- a/PortMaster/pylibs/harbourmaster/platform.py +++ b/PortMaster/pylibs/harbourmaster/platform.py @@ -23,6 +23,7 @@ class PlatformBase(): MOVE_PM_BASH = False + MOVE_PM_BASH_DIR = None ES_NAME = None def __init__(self, hm): @@ -193,6 +194,7 @@ class PlatformAmberELEC(PlatformGCD_PortMaster, PlatformBase): class PlatformEmuELEC(PlatformGCD_PortMaster, PlatformBase): MOVE_PM_BASH = True + MOVE_PM_BASH_DIR = Path("/emuelec/scripts/") ES_NAME = 'emustation' diff --git a/PortMaster/pylibs/harbourmaster/util.py b/PortMaster/pylibs/harbourmaster/util.py index 90f42c1..0c2b5c0 100644 --- a/PortMaster/pylibs/harbourmaster/util.py +++ b/PortMaster/pylibs/harbourmaster/util.py @@ -554,6 +554,10 @@ def match_requirements(capabilities, requirements): for requirement in requirements: match_not = True + ## Fixes empty requirement bug + if requirement == "": + continue + if requirement.startswith('!'): match_not = False requirement = requirement[1:] diff --git a/PortMaster/pylibs/pugscene.py b/PortMaster/pylibs/pugscene.py index dd35e87..3a59a87 100644 --- a/PortMaster/pylibs/pugscene.py +++ b/PortMaster/pylibs/pugscene.py @@ -1501,6 +1501,12 @@ def update_filters(self): "update available": _("Update Available"), "broken": _("Broken Ports"), + # Availability. + "full": _("Free game, all files included."), + "demo": _("Demo files included."), + "free": _("Free external assets needed."), + "paid": _("Paid external assets needed."), + # Runtimes. "mono": _("{runtime_name} Runtime").format(runtime_name="Mono"), "godot": _("{runtime_name} Runtime").format(runtime_name="Godot/FRT"), @@ -1528,6 +1534,7 @@ def update_filters(self): 'sort', 'clear-filters', 'attr', + # 'status', 'genres', 'porters', ] @@ -1623,6 +1630,35 @@ def update_filters(self): if selected_option == hm_genre: selected_offset = len(self.tags['filter_list'].options) - 1 + elif display_order == 'status': + for hm_genre in ['full', 'demo', 'free', 'paid']: + if hm_genre in self.locked_genres: + continue + + if hm_genre in self.list_scene.options['skip_genres']: + continue + + if hm_genre in genres: + ports = total_ports + text = [" ", "_CHECKED", f" {filter_translation.get(hm_genre, hm_genre)}", None, " ", f" {ports}"] + else: + ports = len(self.gui.hm.list_ports(genres + [hm_genre])) + text = [" ", "_UNCHECKED", f" {filter_translation.get(hm_genre, hm_genre)}", None, " ", f" {ports}"] + + if ports == 0: + continue + + if first_add: + if add_blank: + self.tags['filter_list'].add_option(None, "") + self.tags['filter_list'].add_option(None, _("Availability:")) + first_add = False + + self.tags['filter_list'].add_option(hm_genre, text) + + if selected_option == hm_genre: + selected_offset = len(self.tags['filter_list'].options) - 1 + elif display_order == 'porters': for hm_genre in sorted(self.gui.hm.porters_list(), key=lambda name: name.lower()): if hm_genre in self.locked_genres: