diff --git a/.github/update.log b/.github/update.log index cab299f361..ffe0fb5159 100644 --- a/.github/update.log +++ b/.github/update.log @@ -620,3 +620,4 @@ Update On Mon Apr 15 01:03:26 CEST 2024 Update On Mon Apr 15 20:26:48 CEST 2024 Update On Tue Apr 16 20:28:30 CEST 2024 Update On Wed Apr 17 20:28:12 CEST 2024 +Update On Thu Apr 18 20:29:16 CEST 2024 diff --git a/clash-meta/.github/workflows/build.yml b/clash-meta/.github/workflows/build.yml index 570d2e96c5..df320d29b0 100644 --- a/clash-meta/.github/workflows/build.yml +++ b/clash-meta/.github/workflows/build.yml @@ -177,6 +177,11 @@ jobs: else ARCH=${{matrix.jobs.goarch}} fi + PackageVersion=$(curl -s "https://api.github.com/repos/MetaCubeX/mihomo/releases/latest" | grep -o '"tag_name": "[^"]*' | grep -o '[^"]*$' | sed 's/v//g' ) + if [ $(git branch | awk -F ' ' '{print $2}') = "Alpha" ]; then + PackageVersion="$(echo "${PackageVersion}" | awk -F '.' '{$NF = $NF + 1; print}' OFS='.')-${VERSION}" + fi + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo @@ -194,7 +199,7 @@ jobs: cat > mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/control < { - const { setConfigs, setProxies, deleteConnections, ...api } = clash(); + const { deleteConnections, ...api } = clash(); const getConfigs = useSWR("getClashConfig", api.getConfigs); + const setConfigs = async (payload: Partial) => { + try { + await api.setConfigs(payload); + + await getConfigs.mutate(); + } finally { + return getConfigs.data; + } + }; + const getVersion = useSWR("getClashVersion", api.getVersion); const getRules = useSWR("getClashRules", api.getRules); @@ -18,6 +28,16 @@ export const useClash = () => { const getProxies = useSWR("getClashProxies", api.getProxies); + const setProxies = async (payload: { group: string; proxy: string }) => { + try { + await api.setProxies(payload); + + await getProxies.mutate(); + } finally { + return getProxies.data; + } + }; + return { getConfigs, setConfigs, diff --git a/clash-nyanpasu/frontend/interface/service/clash.ts b/clash-nyanpasu/frontend/interface/service/clash.ts index 6290b3fff1..417246c4b8 100644 --- a/clash-nyanpasu/frontend/interface/service/clash.ts +++ b/clash-nyanpasu/frontend/interface/service/clash.ts @@ -81,11 +81,9 @@ export const clash = () => { }; const getRules = async () => { - interface PrivateRule { + return (await buildRequest())<{ rules: Clash.Rule[]; - } - - return (await buildRequest())("/rules"); + }>("/rules"); }; const getProxiesDelay = async ( @@ -107,11 +105,9 @@ export const clash = () => { }; const getProxies = async () => { - interface PrivateProxy { + return (await buildRequest())<{ proxies: Clash.Proxy[]; - } - - return (await buildRequest())("/proxies"); + }>("/proxies"); }; const setProxies = async ({ diff --git a/clash-nyanpasu/frontend/nyanpasu/package.json b/clash-nyanpasu/frontend/nyanpasu/package.json index 9615018371..f390c92548 100644 --- a/clash-nyanpasu/frontend/nyanpasu/package.json +++ b/clash-nyanpasu/frontend/nyanpasu/package.json @@ -4,8 +4,8 @@ "license": "GPL-3.0", "type": "module", "scripts": { - "dev": "vite", "build": "vite build", + "dev": "vite", "serve": "vite preview" }, "dependencies": { diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts index 373823f7af..be9a500067 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.ts @@ -41,15 +41,15 @@ export const useCustomTheme = () => { const [mode, setMode] = useRecoilState(atomThemeMode); - appWindow.onThemeChanged((e) => { - setMode(e.payload); - }); - useEffect(() => { if (nyanpasuConfig?.theme_mode === "system") { appWindow.theme().then((m) => m && setMode(m)); - return; + const unlisten = appWindow.onThemeChanged((e) => setMode(e.payload)); + + return () => { + unlisten.then((fn) => fn()); + }; } if (nyanpasuConfig?.theme_mode) { diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts new file mode 100644 index 0000000000..e1f427d6dd --- /dev/null +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/create-props.ts @@ -0,0 +1,67 @@ +import { SwitchProps } from "@mui/material/Switch/Switch"; +import { Clash, useClash } from "@nyanpasu/interface"; +import { MenuItemProps } from "@nyanpasu/ui"; + +/** + * @example + * createBooleanProps("ipv6") + * + * @returns {SwitchProps} + * SwitchProps + * + * `Only supports boolean-type value keys.` + * + * @author keiko233 + * @copyright LibNyanpasu org. 2024 + */ +export const createBooleanProps = ( + propName: { + [K in keyof Clash.Config]: Clash.Config[K] extends boolean ? K : never; + }[keyof Clash.Config], +): SwitchProps => { + const { getConfigs, setConfigs } = useClash(); + + return { + checked: getConfigs.data?.[propName] || false, + onChange: () => { + setConfigs({ [propName]: !getConfigs.data?.[propName] }); + }, + }; +}; + +type OptionValue = string | number | boolean; + +interface CreateMenuPropsOptions { + options: Record; + fallbackSelect: OptionValue; +} + +/** + * @example + * createMenuProps("log-level", { + options, + fallbackSelect: "debug", + }) + * + * @returns {Omit} + * Omit + * + * `Recommend use MemuItem component.` + * + * @author keiko233 + * @copyright LibNyanpasu org. 2024 + */ +export const createMenuProps = ( + propName: keyof Clash.Config, + { options, fallbackSelect }: CreateMenuPropsOptions, +): Omit => { + const { getConfigs, setConfigs } = useClash(); + + return { + options, + selected: getConfigs.data?.[propName] || fallbackSelect, + onSelected: (value: OptionValue) => { + setConfigs({ [propName]: value }); + }, + }; +}; diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts new file mode 100644 index 0000000000..93021902c5 --- /dev/null +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/index.ts @@ -0,0 +1 @@ +export * from "./create-props"; diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/baseCard/index.tsx b/clash-nyanpasu/frontend/ui/materialYou/components/baseCard/index.tsx new file mode 100644 index 0000000000..c4f7b02262 --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/components/baseCard/index.tsx @@ -0,0 +1,34 @@ +import { Box, Card, CardContent, Typography } from "@mui/material"; +import { ReactNode } from "react"; + +export const BaseCard = ({ + label, + labelChildren, + children, +}: { + label?: string; + labelChildren?: ReactNode; + children?: ReactNode; +}) => { + return ( + + + {label && ( + + + {label} + + + {labelChildren} + + )} + + {children} + + + ); +}; diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/index.ts b/clash-nyanpasu/frontend/ui/materialYou/components/index.ts index ca2b903d43..29ffe92ee8 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/components/index.ts +++ b/clash-nyanpasu/frontend/ui/materialYou/components/index.ts @@ -1 +1,3 @@ export * from "./basePage"; +export * from "./baseCard"; +export * from "./item"; diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/item/index.ts b/clash-nyanpasu/frontend/ui/materialYou/components/item/index.ts new file mode 100644 index 0000000000..f376231f61 --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/components/item/index.ts @@ -0,0 +1,2 @@ +export * from "./switchItem"; +export * from "./menuItem"; diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/item/menuItem.tsx b/clash-nyanpasu/frontend/ui/materialYou/components/item/menuItem.tsx new file mode 100644 index 0000000000..fcd541f339 --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/components/item/menuItem.tsx @@ -0,0 +1,50 @@ +import { + ListItem, + ListItemText, + MenuItem as MuiMenuItem, + Select, +} from "@mui/material"; + +type OptionValue = string | number | boolean; + +export interface MenuItemProps { + label: string; + options: Record; + selected: OptionValue; + onSelected: (value: OptionValue) => void; +} + +export const MenuItem = ({ + label, + options, + selected, + onSelected, +}: MenuItemProps) => { + return ( + + + + + + ); +}; + +export default MenuItem; diff --git a/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx b/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx new file mode 100644 index 0000000000..5f6d6ce6e9 --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/components/item/switchItem.tsx @@ -0,0 +1,15 @@ +import { ListItem, ListItemText, Switch, SwitchProps } from "@mui/material"; + +interface Props extends SwitchProps { + label: string; +} + +export const SwitchItem = ({ label, ...switchProps }: Props) => { + return ( + + + + + + ); +}; diff --git a/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts b/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts index 6c97362dc4..1aca3fd1e9 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts +++ b/clash-nyanpasu/frontend/ui/materialYou/createTheme.ts @@ -5,7 +5,14 @@ import { hexFromArgb, themeFromSourceColor, } from "@material/material-color-utilities"; -import { MuiButton, MuiButtonGroup, MuiPaper } from "./themeComponents"; +import { + MuiButton, + MuiButtonGroup, + MuiCard, + MuiCardContent, + MuiPaper, + MuiSwitch, +} from "./themeComponents"; interface ThemeSchema { primary_color: string; @@ -52,7 +59,19 @@ export const createMDYTheme = ( components: { MuiButton, MuiButtonGroup, - MuiPaper, + MuiCard, + MuiCardContent, + // MuiPaper, + MuiSwitch: MuiSwitch(palette), + }, + breakpoints: { + values: { + xs: 0, + sm: 720, + md: 960, + lg: 1200, + xl: 1536, + }, }, }); }; diff --git a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiCard.ts b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiCard.ts new file mode 100644 index 0000000000..be2a5f8ffd --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiCard.ts @@ -0,0 +1,11 @@ +import { Theme } from "@mui/material"; +import { Components } from "@mui/material/styles/components"; + +export const MuiCard: Components["MuiCard"] = { + defaultProps: { + sx: { + borderRadius: 6, + elevation: 0, + }, + }, +}; diff --git a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiCardContent.ts b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiCardContent.ts new file mode 100644 index 0000000000..8c01c240b6 --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiCardContent.ts @@ -0,0 +1,10 @@ +import { Theme } from "@mui/material"; +import { Components } from "@mui/material/styles/components"; + +export const MuiCardContent: Components["MuiCardContent"] = { + defaultProps: { + sx: { + padding: 3, + }, + }, +}; diff --git a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts new file mode 100644 index 0000000000..6ae0db9d33 --- /dev/null +++ b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/MuiSwitch.ts @@ -0,0 +1,111 @@ +import { Theme } from "@mui/material"; +import { Components } from "@mui/material/styles/components"; +import { Palette } from "@mui/material/styles/createPalette"; + +export const MuiSwitch = (palette: Palette): Components["MuiSwitch"] => { + const isDark = palette.mode === "dark"; + + return { + styleOverrides: { + root: { + padding: 0, + margin: 0, + + "& .Mui-checked": { + "& .MuiSwitch-thumb": { + color: palette.grey.A100, + }, + }, + + "&:has(.Mui-checked) .MuiSwitch-track::before": { + opacity: 0, + }, + }, + track: { + borderRadius: "48px", + backgroundColor: isDark ? palette.grey.A700 : palette.grey.A200, + opacity: `${isDark ? 0.7 : 1} !important`, + + "&::before": { + content: '""', + border: `solid 2px ${palette.grey.A700}`, + width: "100%", + height: "100%", + opacity: 1, + position: "absolute", + borderRadius: "inherit", + boxSizing: "border-box", + transitionProperty: "opacity, background-color", + transitionTimingFunction: "linear", + transitionDuration: "100ms", + }, + }, + thumb: { + boxShadow: "none", + color: isDark ? palette.grey.A200 : palette.grey.A700, + }, + }, + variants: [ + { + props: { + size: "medium", + }, + style: { + height: 32, + + "& .MuiSwitch-switchBase": { + padding: "6px", + }, + + "& .MuiSwitch-thumb": { + width: 14, + height: 14, + margin: 3, + }, + + "& .Mui-checked": { + "&.MuiSwitch-switchBase": { + marginLeft: "6px", + }, + + "& .MuiSwitch-thumb": { + width: 24, + height: 24, + margin: -2, + }, + }, + }, + }, + { + props: { + size: "small", + }, + style: { + height: 24, + + "& .MuiSwitch-switchBase": { + padding: "3px", + }, + + "& .MuiSwitch-thumb": { + width: 12, + height: 12, + margin: 3, + }, + + "& .Mui-checked": { + "&.MuiSwitch-switchBase": { + marginLeft: "1px", + }, + + "& .MuiSwitch-thumb": { + width: 17, + height: 17, + margin: 0, + }, + }, + }, + }, + ], + }; +}; diff --git a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/index.ts b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/index.ts index c0d851004e..7a8d1cdebe 100644 --- a/clash-nyanpasu/frontend/ui/materialYou/themeComponents/index.ts +++ b/clash-nyanpasu/frontend/ui/materialYou/themeComponents/index.ts @@ -1,3 +1,6 @@ export * from "./MuiButton"; export * from "./MuiButtonGroup"; export * from "./MuiPaper"; +export * from "./MuiCard"; +export * from "./MuiCardContent"; +export * from "./MuiSwitch"; diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index d7b4fcda3d..6301d3eb83 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.18.3", - "mihomo_alpha": "alpha-d84f88b", + "mihomo_alpha": "alpha-ff2071c", "clash_rs": "v0.1.16", "clash_premium": "2023-09-05-gdcc8d87" }, @@ -36,5 +36,5 @@ "darwin-x64": "clash-darwin-amd64-n{}.gz" } }, - "updated_at": "2024-04-13T22:18:27.726Z" + "updated_at": "2024-04-17T22:19:33.317Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 52219d6638..78db8373ac 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -1,12 +1,9 @@ { "name": "@nyanpasu/monorepo", "version": "1.5.1", + "repository": "https://github.com/LibNyanpasu/clash-nyanpasu.git", "license": "GPL-3.0", "type": "module", - "repository": "https://github.com/LibNyanpasu/clash-nyanpasu.git", - "engines": { - "node": "21.7.3" - }, "scripts": { "dev": "tauri dev -c ./backend/tauri/tauri.conf.json", "dev:diff": "tauri dev -f verge-dev deadlock-detection -c ./backend/tauri/tauri.conf.json", @@ -42,10 +39,10 @@ "prepare:release": "tsx scripts/prepare-release.ts" }, "prettier": { + "endOfLine": "lf", "plugins": [ "prettier-plugin-toml" ], - "endOfLine": "lf", "semi": true, "singleQuote": false, "tabWidth": 2, @@ -61,11 +58,6 @@ } ] }, - "pnpm": { - "overrides": { - "vite-plugin-monaco-editor": "npm:vite-plugin-monaco-editor-new@1.1.3" - } - }, "dependencies": { "husky": "9.0.11", "lodash-es": "4.17.21" @@ -108,5 +100,14 @@ "stylelint-scss": "6.2.1", "tsx": "4.7.2", "typescript": "5.4.5" + }, + "packageManager": "pnpm@9.0.2", + "engines": { + "node": "^20 || ^21" + }, + "pnpm": { + "overrides": { + "vite-plugin-monaco-editor": "npm:vite-plugin-monaco-editor-new@1.1.3" + } } } diff --git a/clash-verge-rev/src-tauri/src/config/clash.rs b/clash-verge-rev/src-tauri/src/config/clash.rs index 8e4f75cc3b..d9ff5ce9d4 100644 --- a/clash-verge-rev/src-tauri/src/config/clash.rs +++ b/clash-verge-rev/src-tauri/src/config/clash.rs @@ -38,7 +38,7 @@ impl IClashTemp { tun.insert("strict-route".into(), false.into()); tun.insert("auto-detect-interface".into(), true.into()); tun.insert("dns-hijack".into(), vec!["any:53"].into()); - tun.insert("mtu".into(), 9000.into()); + tun.insert("mtu".into(), 1500.into()); #[cfg(not(target_os = "windows"))] map.insert("redir-port".into(), 7895.into()); #[cfg(target_os = "linux")] diff --git a/clash-verge-rev/src/components/setting/mods/tun-viewer.tsx b/clash-verge-rev/src/components/setting/mods/tun-viewer.tsx index a5b9861ed0..9720f32f49 100644 --- a/clash-verge-rev/src/components/setting/mods/tun-viewer.tsx +++ b/clash-verge-rev/src/components/setting/mods/tun-viewer.tsx @@ -27,7 +27,7 @@ export const TunViewer = forwardRef((props, ref) => { autoDetectInterface: true, dnsHijack: ["any:53"], strictRoute: false, - mtu: 9000, + mtu: 1500, }); useImperativeHandle(ref, () => ({ @@ -40,7 +40,7 @@ export const TunViewer = forwardRef((props, ref) => { autoDetectInterface: clash?.tun["auto-detect-interface"] ?? true, dnsHijack: clash?.tun["dns-hijack"] ?? ["any:53"], strictRoute: clash?.tun["strict-route"] ?? false, - mtu: clash?.tun.mtu ?? 9000, + mtu: clash?.tun.mtu ?? 1500, }); }, close: () => setOpen(false), @@ -88,7 +88,7 @@ export const TunViewer = forwardRef((props, ref) => { "auto-detect-interface": true, "dns-hijack": ["any:53"], "strict-route": false, - mtu: 9000, + mtu: 1500, }; setValues({ stack: "gvisor", @@ -97,7 +97,7 @@ export const TunViewer = forwardRef((props, ref) => { autoDetectInterface: true, dnsHijack: ["any:53"], strictRoute: false, - mtu: 9000, + mtu: 1500, }); await patchClash({ tun }); await mutateClash( @@ -208,7 +208,7 @@ export const TunViewer = forwardRef((props, ref) => { spellCheck="false" sx={{ width: 250 }} value={values.mtu} - placeholder="9000" + placeholder="1500" onChange={(e) => setValues((v) => ({ ...v, diff --git a/echo/hack/get-ehco.sh b/echo/hack/get-ehco.sh index 96429888d0..c87e2ad58d 100755 --- a/echo/hack/get-ehco.sh +++ b/echo/hack/get-ehco.sh @@ -50,7 +50,7 @@ Type=simple LimitNOFILE=65535 ExecStart=$EXECUTABLE_INSTALL_PATH -c "$API_OR_CONFIG_PATH" WorkingDirectory=~ -NoNewPrivileges=trues +NoNewPrivileges=true Restart=always [Install] diff --git a/lede/package/firmware/linux-firmware/Makefile b/lede/package/firmware/linux-firmware/Makefile index 79341c30cb..d056140f45 100644 --- a/lede/package/firmware/linux-firmware/Makefile +++ b/lede/package/firmware/linux-firmware/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=linux-firmware -PKG_VERSION:=20231211 +PKG_VERSION:=20240220 PKG_RELEASE:=1 PKG_SOURCE_URL:=@KERNEL/linux/kernel/firmware PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz -PKG_HASH:=96af7e4b5eabd37869cdb3dcbb7ab36911106d39b76e799fa1caab16a9dbe8bb +PKG_HASH:=bf0f239dc0801e9d6bf5d5fb3e2f549575632cf4688f4348184199cb02c2bcd7 PKG_MAINTAINER:=Felix Fietkau diff --git a/lede/package/kernel/rtw88-usb/Makefile b/lede/package/kernel/rtw88-usb/Makefile index cf05b4cc02..7afa41c7f7 100644 --- a/lede/package/kernel/rtw88-usb/Makefile +++ b/lede/package/kernel/rtw88-usb/Makefile @@ -11,10 +11,10 @@ PKG_NAME:=rtw88-usb PKG_RELEASE:=1 PKG_SOURCE_PROTO:=git -PKG_SOURCE_DATE:=2023-06-28 +PKG_SOURCE_DATE:=2024-04-10 PKG_SOURCE_URL:=https://github.com/lwfinger/rtw88.git -PKG_SOURCE_VERSION:=7ca1ec0e768f083e4a2116d6978021814b83bb74 -PKG_MIRROR_HASH:=101e4769c8c25a0b1c186c2b65a1f03b4c600b36fdb20948ef3c82e75e2f6582 +PKG_SOURCE_VERSION:=2e9f468009df592a51990d024928034e0af1c2b4 +PKG_MIRROR_HASH:=684b30e58d8b990bbe141baae00c48439f45c9f39faa6f552ffb18afb6594c74 PKG_BUILD_PARALLEL:=1 diff --git a/lede/package/kernel/rtw88-usb/patches/001-fix-merge-error.patch b/lede/package/kernel/rtw88-usb/patches/001-fix-merge-error.patch new file mode 100644 index 0000000000..4439c4f18b --- /dev/null +++ b/lede/package/kernel/rtw88-usb/patches/001-fix-merge-error.patch @@ -0,0 +1,96 @@ +--- a/fw.c ++++ b/fw.c +@@ -1009,7 +1009,7 @@ static u8 rtw_get_rsvd_page_probe_req_location(struct rtw_dev *rtwdev, + if (rsvd_pkt->type != RSVD_PROBE_REQ) + continue; + if ((!ssid && !rsvd_pkt->ssid) || +- cfg80211_ssid_eq(rsvd_pkt->ssid, ssid)) ++ cfg80211_ssid_eq(rsvd_pkt->ssid, ssid)) + location = rsvd_pkt->page; + } + +--- a/mac.c ++++ b/mac.c +@@ -316,13 +316,6 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) + rtw_write8_clr(rtwdev, REG_SYS_STATUS1 + 1, BIT(0)); + } + +- if (pwr_on && rtw_hci_type(rtwdev) == RTW_HCI_TYPE_USB) { +- if (chip->id == RTW_CHIP_TYPE_8822C || +- chip->id == RTW_CHIP_TYPE_8822B || +- chip->id == RTW_CHIP_TYPE_8821C) +- rtw_write8_clr(rtwdev, REG_SYS_STATUS1 + 1, BIT(0)); +- } +- + if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) + rtw_write32(rtwdev, REG_SDIO_HIMR, imr); + +@@ -956,18 +949,6 @@ static int __rtw_download_firmware_legacy(struct rtw_dev *rtwdev, + rtw_write8(rtwdev, REG_MCUFW_CTRL, 0x00); + } + +- /* reset firmware if still present */ +- if (rtwdev->chip->id == RTW_CHIP_TYPE_8703B && +- rtw_read8_mask(rtwdev, REG_MCUFW_CTRL, BIT_RAM_DL_SEL)) { +- rtw_write8(rtwdev, REG_MCUFW_CTRL, 0x00); +- } +- +- /* reset firmware if still present */ +- if (rtwdev->chip->id == RTW_CHIP_TYPE_8703B && +- rtw_read8_mask(rtwdev, REG_MCUFW_CTRL, BIT_RAM_DL_SEL)) { +- rtw_write8(rtwdev, REG_MCUFW_CTRL, 0x00); +- } +- + en_download_firmware_legacy(rtwdev, true); + ret = download_firmware_legacy(rtwdev, fw->firmware->data, fw->firmware->size); + en_download_firmware_legacy(rtwdev, false); +--- a/main.c ++++ b/main.c +@@ -110,9 +110,7 @@ static const struct ieee80211_iface_limit rtw_iface_limits[] = { + }, + { + .max = 1, +- .types = BIT(NL80211_IFTYPE_AP) | +- BIT(NL80211_IFTYPE_P2P_CLIENT) | +- BIT(NL80211_IFTYPE_P2P_GO) ++ .types = BIT(NL80211_IFTYPE_AP), + } + }; + +@@ -2124,11 +2122,6 @@ static int rtw_chip_efuse_info_setup(struct rtw_dev *rtwdev) + dev_warn(rtwdev->dev, "efuse MAC invalid, using random\n"); + } + +- if (!is_valid_ether_addr(efuse->addr)) { +- eth_random_addr(efuse->addr); +- dev_warn(rtwdev->dev, "efuse MAC invalid, using random\n"); +- } +- + out_disable: + rtw_chip_efuse_disable(rtwdev); + +@@ -2361,9 +2354,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_ADHOC) | +- BIT(NL80211_IFTYPE_MESH_POINT) | +- BIT(NL80211_IFTYPE_P2P_CLIENT) | +- BIT(NL80211_IFTYPE_P2P_GO); ++ BIT(NL80211_IFTYPE_MESH_POINT); + hw->wiphy->available_antennas_tx = hal->antenna_tx; + hw->wiphy->available_antennas_rx = hal->antenna_rx; + +--- a/usb.c ++++ b/usb.c +@@ -93,11 +93,6 @@ static u32 rtw_usb_read(struct rtw_dev *rtwdev, u32 addr, u16 len) + rtwdev->chip->id == RTW_CHIP_TYPE_8821C) + rtw_usb_reg_sec(rtwdev, addr, data); + +- if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C || +- rtwdev->chip->id == RTW_CHIP_TYPE_8822B || +- rtwdev->chip->id == RTW_CHIP_TYPE_8821C) +- rtw_usb_reg_sec(rtwdev, addr, data); +- + return le32_to_cpu(*data); + } + diff --git a/lede/package/kernel/rtw88-usb/patches/101-wireless-6.1.patch b/lede/package/kernel/rtw88-usb/patches/101-wireless-6.1.patch index 89111d2f90..37a9bca9fd 100644 --- a/lede/package/kernel/rtw88-usb/patches/101-wireless-6.1.patch +++ b/lede/package/kernel/rtw88-usb/patches/101-wireless-6.1.patch @@ -20,7 +20,7 @@ bfee->aid = bss_conf->aid; --- a/fw.c +++ b/fw.c -@@ -118,7 +118,7 @@ legacy: +@@ -191,7 +191,7 @@ legacy: si->ra_report.desc_rate = rate; si->ra_report.bit_rate = bit_rate; @@ -29,7 +29,7 @@ sta->deflink.agg.max_rc_amsdu_len = get_max_amsdu_len(bit_rate); #else sta->max_rc_amsdu_len = get_max_amsdu_len(bit_rate); -@@ -652,7 +652,7 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) +@@ -726,7 +726,7 @@ void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) rtw_fw_send_h2c_command(rtwdev, h2c_pkt); } @@ -38,7 +38,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, bool reset_ra_mask) #else -@@ -661,7 +661,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) +@@ -735,7 +735,7 @@ void rtw_fw_send_ra_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si) { u8 h2c_pkt[H2C_PKT_SIZE] = {0}; bool disable_pt = true; @@ -47,7 +47,7 @@ bool reset_ra_mask = true; #endif -@@ -1154,7 +1154,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, +@@ -1228,7 +1228,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, switch (rsvd_pkt->type) { case RSVD_BEACON: @@ -56,7 +56,7 @@ skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL, 0); #else skb_new = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL); -@@ -1169,7 +1169,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, +@@ -1243,7 +1243,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, break; case RSVD_NULL: #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 17) @@ -65,7 +65,7 @@ skb_new = ieee80211_nullfunc_get(hw, vif, -1, false); #else skb_new = ieee80211_nullfunc_get(hw, vif, false); -@@ -1180,7 +1180,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, +@@ -1254,7 +1254,7 @@ static struct sk_buff *rtw_get_rsvd_page_skb(struct ieee80211_hw *hw, break; case RSVD_QOS_NULL: #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 17) @@ -76,7 +76,7 @@ skb_new = ieee80211_nullfunc_get(hw, vif, true); --- a/fw.h +++ b/fw.h -@@ -831,7 +831,7 @@ void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data); +@@ -834,7 +834,7 @@ void rtw_fw_coex_query_hid_info(struct rtw_dev *rtwdev, u8 sub_id, u8 data); void rtw_fw_bt_wifi_control(struct rtw_dev *rtwdev, u8 op_code, u8 *data); void rtw_fw_send_rssi_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si); @@ -152,7 +152,7 @@ u16 duration) --- a/main.c +++ b/main.c -@@ -192,7 +192,7 @@ static void rtw_vif_watch_dog_iter(void *data, u8 *mac, +@@ -191,7 +191,7 @@ static void rtw_vif_watch_dog_iter(void *data, struct ieee80211_vif *vif) struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; if (vif->type == NL80211_IFTYPE_STATION) @@ -161,7 +161,7 @@ if (vif->cfg.assoc) #else if (vif->bss_conf.assoc) -@@ -345,7 +345,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, +@@ -343,7 +343,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, if (si->mac_id >= RTW_MAX_MAC_ID_NUM) return -ENOSPC; @@ -170,7 +170,7 @@ if (vif->type == NL80211_IFTYPE_STATION && vif->cfg.assoc == 0) #else if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc == 0) -@@ -574,7 +574,7 @@ EXPORT_SYMBOL(rtw_dump_reg); +@@ -572,7 +572,7 @@ EXPORT_SYMBOL(rtw_dump_reg); void rtw_vif_assoc_changed(struct rtw_vif *rtwvif, struct ieee80211_bss_conf *conf) { @@ -179,7 +179,7 @@ struct ieee80211_vif *vif = NULL; if (conf) -@@ -1002,7 +1002,7 @@ static void rtw_hw_config_rf_ant_num(struct rtw_dev *rtwdev, u8 hw_ant_num) +@@ -1000,7 +1000,7 @@ static void rtw_hw_config_rf_ant_num(struct rtw_dev *rtwdev, u8 hw_ant_num) static u64 get_vht_ra_mask(struct ieee80211_sta *sta) { u64 ra_mask = 0; @@ -188,7 +188,7 @@ u16 mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map); #else u16 mcs_map = le16_to_cpu(sta->vht_cap.vht_mcs.rx_mcs_map); -@@ -1226,26 +1226,26 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1224,26 +1224,26 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, bool is_vht_enable = false; bool is_support_sgi = false; @@ -219,7 +219,7 @@ } else if (sta->deflink.ht_cap.ht_supported) { ra_mask |= (sta->deflink.ht_cap.mcs.rx_mask[1] << 20) | (sta->deflink.ht_cap.mcs.rx_mask[0] << 12); -@@ -1268,20 +1268,20 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1266,20 +1266,20 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, ra_mask &= RA_MASK_VHT_RATES_1SS | RA_MASK_HT_RATES_1SS; if (hal->current_band_type == RTW_BAND_5G) { @@ -243,7 +243,7 @@ } else if (sta->deflink.ht_cap.ht_supported) { #else } else if (sta->ht_cap.ht_supported) { -@@ -1293,13 +1293,13 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1291,13 +1291,13 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, } dm_info->rrsr_val_init = RRSR_INIT_5G; } else if (hal->current_band_type == RTW_BAND_2G) { @@ -259,7 +259,7 @@ if (sta->deflink.vht_cap.vht_supported) { #else if (sta->vht_cap.vht_supported) { -@@ -1308,7 +1308,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1306,7 +1306,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, RA_MASK_OFDM_IN_VHT; wireless_set = WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_HT | WIRELESS_VHT; @@ -268,7 +268,7 @@ } else if (sta->deflink.ht_cap.ht_supported) { #else } else if (sta->ht_cap.ht_supported) { -@@ -1317,7 +1317,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1315,7 +1315,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, RA_MASK_OFDM_IN_HT_2G; wireless_set = WIRELESS_CCK | WIRELESS_OFDM | WIRELESS_HT; @@ -277,7 +277,7 @@ } else if (sta->deflink.supp_rates[0] <= 0xf) { #else } else if (sta->supp_rates[0] <= 0xf) { -@@ -1334,14 +1334,14 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1332,14 +1332,14 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, wireless_set = 0; } @@ -294,7 +294,7 @@ is_support_sgi = sta->deflink.vht_cap.vht_supported && (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80); #else -@@ -1351,7 +1351,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1349,7 +1349,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, break; case IEEE80211_STA_RX_BW_40: bw_mode = RTW_CHANNEL_WIDTH_40; @@ -303,7 +303,7 @@ is_support_sgi = sta->deflink.ht_cap.ht_supported && (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40); #else -@@ -1361,7 +1361,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1359,7 +1359,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, break; default: bw_mode = RTW_CHANNEL_WIDTH_20; @@ -312,7 +312,7 @@ is_support_sgi = sta->deflink.ht_cap.ht_supported && (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20); #else -@@ -1371,14 +1371,14 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1369,14 +1369,14 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, break; } @@ -329,7 +329,7 @@ } else if (sta->deflink.ht_cap.ht_supported && ra_mask & 0xfff00000) { #else } else if (sta->ht_cap.ht_supported && ra_mask & 0xfff00000) { -@@ -1403,7 +1403,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, +@@ -1400,7 +1400,7 @@ void rtw_update_sta_info(struct rtw_dev *rtwdev, struct rtw_sta_info *si, si->ra_mask = ra_mask; si->rate_id = rate_id; @@ -338,7 +338,7 @@ rtw_fw_send_ra_info(rtwdev, si, reset_ra_mask); #else rtw_fw_send_ra_info(rtwdev, si); -@@ -1783,7 +1783,7 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, +@@ -1780,7 +1780,7 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, { struct rtw_dev *rtwdev = (struct rtw_dev *)data; @@ -347,7 +347,7 @@ if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) #else if (vif->type != NL80211_IFTYPE_STATION || !vif->bss_conf.assoc) -@@ -1791,13 +1791,13 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, +@@ -1788,13 +1788,13 @@ static void rtw_vif_smps_iter(void *data, u8 *mac, return; if (rtwdev->hal.txrx_1ss) @@ -363,7 +363,7 @@ ieee80211_request_smps(vif, 0, IEEE80211_SMPS_OFF); #else ieee80211_request_smps(vif, IEEE80211_SMPS_OFF); -@@ -2511,7 +2511,7 @@ static void rtw_check_sta_active_iter(void *data, u8 *mac, +@@ -2516,7 +2516,7 @@ static void rtw_check_sta_active_iter(void *data, struct ieee80211_vif *vif) if (vif->type != NL80211_IFTYPE_STATION) return; diff --git a/lede/package/kernel/rtw88-usb/patches/102-disable-pcie.patch b/lede/package/kernel/rtw88-usb/patches/102-disable-pcie.patch index d80af386ad..f57ad4c88c 100644 --- a/lede/package/kernel/rtw88-usb/patches/102-disable-pcie.patch +++ b/lede/package/kernel/rtw88-usb/patches/102-disable-pcie.patch @@ -1,6 +1,6 @@ --- a/Makefile +++ b/Makefile -@@ -24,10 +24,6 @@ NO_SKIP_SIGN := y +@@ -30,10 +30,6 @@ NO_SKIP_SIGN := y endif EXTRA_CFLAGS += -O2 @@ -11,7 +11,7 @@ EXTRA_CFLAGS += -DCONFIG_RTW88_DEBUG=1 EXTRA_CFLAGS += -DCONFIG_RTW88_DEBUGFS=1 #EXTRA_CFLAGS += -DCONFIG_RTW88_REGD_USER_REG_HINTS -@@ -54,9 +50,6 @@ rtw_core-objs += main.o \ +@@ -60,9 +56,6 @@ rtw_core-objs += main.o \ obj-m += rtw_8822b.o rtw_8822b-objs := rtw8822b.o rtw8822b_table.o @@ -21,7 +21,7 @@ obj-m += rtw_8822bu.o rtw_8822bu-objs := rtw8822bu.o -@@ -66,9 +59,6 @@ rtw_8822bs-objs := rtw8822bs.o +@@ -72,9 +65,6 @@ rtw_8822bs-objs := rtw8822bs.o obj-m += rtw_8822c.o rtw_8822c-objs := rtw8822c.o rtw8822c_table.o @@ -31,7 +31,7 @@ obj-m += rtw_8822cu.o rtw_8822cu-objs := rtw8822cu.o -@@ -78,9 +68,6 @@ rtw_8822cs-objs := rtw8822cs.o +@@ -102,9 +92,6 @@ rtw_8723cs-objs := rtw8723cs.o obj-m += rtw_8723d.o rtw_8723d-objs := rtw8723d.o rtw8723d_table.o @@ -41,16 +41,23 @@ obj-m += rtw_8723du.o rtw_8723du-objs := rtw8723du.o -@@ -90,18 +77,12 @@ rtw_8723ds-objs := rtw8723ds.o +@@ -114,15 +101,9 @@ rtw_8723ds-objs := rtw8723ds.o obj-m += rtw_8821c.o rtw_8821c-objs := rtw8821c.o rtw8821c_table.o -obj-m += rtw_8821ce.o -rtw_8821ce-objs := rtw8821ce.o - - obj-m += rtw_8821cs.o - rtw_8821cs-objs := rtw8821cs.o + obj-m += rtw_8821a.o + rtw_8821a-objs := rtw8821a.o rtw8821a_table.o +-obj-m += rtw_8821ae.o +-rtw_8821ae-objs := rtw8821ae.o +- + obj-m += rtw_8821au.o + rtw_8821au-objs := rtw8821au.o + +@@ -132,9 +113,6 @@ rtw_8821cs-objs := rtw8821cs.o obj-m += rtw_8821cu.o rtw_8821cu-objs := rtw8821cu.o diff --git a/mihomo/.github/workflows/build.yml b/mihomo/.github/workflows/build.yml index 570d2e96c5..df320d29b0 100644 --- a/mihomo/.github/workflows/build.yml +++ b/mihomo/.github/workflows/build.yml @@ -177,6 +177,11 @@ jobs: else ARCH=${{matrix.jobs.goarch}} fi + PackageVersion=$(curl -s "https://api.github.com/repos/MetaCubeX/mihomo/releases/latest" | grep -o '"tag_name": "[^"]*' | grep -o '[^"]*$' | sed 's/v//g' ) + if [ $(git branch | awk -F ' ' '{print $2}') = "Alpha" ]; then + PackageVersion="$(echo "${PackageVersion}" | awk -F '.' '{$NF = $NF + 1; print}' OFS='.')-${VERSION}" + fi + mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/usr/bin mkdir -p mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/etc/mihomo @@ -194,7 +199,7 @@ jobs: cat > mihomo-${{matrix.jobs.goos}}-${{matrix.jobs.output}}-${VERSION}/DEBIAN/control < - + diff --git a/ryujinx/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/ryujinx/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index e9c163cf20..0cb49ca8ce 100644 --- a/ryujinx/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/ryujinx/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -1,7 +1,5 @@ namespace Ryujinx.Common.Configuration.Hid { - // NOTE: Please don't change this to struct. - // This breaks Avalonia's TwoWay binding, which makes us unable to save new KeyboardHotkeys. public class KeyboardHotkeys { public Key ToggleVsync { get; set; } diff --git a/ryujinx/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs b/ryujinx/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs new file mode 100644 index 0000000000..5a8ca96a19 --- /dev/null +++ b/ryujinx/src/Ryujinx.Gtk3/UI/Helper/ButtonHelper.cs @@ -0,0 +1,158 @@ +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Input; +using System; +using System.Collections.Generic; +using Key = Ryujinx.Common.Configuration.Hid.Key; +using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; + +namespace Ryujinx.UI.Helper +{ + public static class ButtonHelper + { + private static readonly Dictionary _keysMap = new() + { + { Key.Unknown, "Unknown" }, + { Key.ShiftLeft, "ShiftLeft" }, + { Key.ShiftRight, "ShiftRight" }, + { Key.ControlLeft, "CtrlLeft" }, + { Key.ControlRight, "CtrlRight" }, + { Key.AltLeft, OperatingSystem.IsMacOS() ? "OptLeft" : "AltLeft" }, + { Key.AltRight, OperatingSystem.IsMacOS() ? "OptRight" : "AltRight" }, + { Key.WinLeft, OperatingSystem.IsMacOS() ? "CmdLeft" : "WinLeft" }, + { Key.WinRight, OperatingSystem.IsMacOS() ? "CmdRight" : "WinRight" }, + { Key.Up, "Up" }, + { Key.Down, "Down" }, + { Key.Left, "Left" }, + { Key.Right, "Right" }, + { Key.Enter, "Enter" }, + { Key.Escape, "Escape" }, + { Key.Space, "Space" }, + { Key.Tab, "Tab" }, + { Key.BackSpace, "Backspace" }, + { Key.Insert, "Insert" }, + { Key.Delete, "Delete" }, + { Key.PageUp, "PageUp" }, + { Key.PageDown, "PageDown" }, + { Key.Home, "Home" }, + { Key.End, "End" }, + { Key.CapsLock, "CapsLock" }, + { Key.ScrollLock, "ScrollLock" }, + { Key.PrintScreen, "PrintScreen" }, + { Key.Pause, "Pause" }, + { Key.NumLock, "NumLock" }, + { Key.Clear, "Clear" }, + { Key.Keypad0, "Keypad0" }, + { Key.Keypad1, "Keypad1" }, + { Key.Keypad2, "Keypad2" }, + { Key.Keypad3, "Keypad3" }, + { Key.Keypad4, "Keypad4" }, + { Key.Keypad5, "Keypad5" }, + { Key.Keypad6, "Keypad6" }, + { Key.Keypad7, "Keypad7" }, + { Key.Keypad8, "Keypad8" }, + { Key.Keypad9, "Keypad9" }, + { Key.KeypadDivide, "KeypadDivide" }, + { Key.KeypadMultiply, "KeypadMultiply" }, + { Key.KeypadSubtract, "KeypadSubtract" }, + { Key.KeypadAdd, "KeypadAdd" }, + { Key.KeypadDecimal, "KeypadDecimal" }, + { Key.KeypadEnter, "KeypadEnter" }, + { Key.Number0, "0" }, + { Key.Number1, "1" }, + { Key.Number2, "2" }, + { Key.Number3, "3" }, + { Key.Number4, "4" }, + { Key.Number5, "5" }, + { Key.Number6, "6" }, + { Key.Number7, "7" }, + { Key.Number8, "8" }, + { Key.Number9, "9" }, + { Key.Tilde, "~" }, + { Key.Grave, "`" }, + { Key.Minus, "-" }, + { Key.Plus, "+" }, + { Key.BracketLeft, "[" }, + { Key.BracketRight, "]" }, + { Key.Semicolon, ";" }, + { Key.Quote, "'" }, + { Key.Comma, "," }, + { Key.Period, "." }, + { Key.Slash, "/" }, + { Key.BackSlash, "\\" }, + { Key.Unbound, "Unbound" }, + }; + + private static readonly Dictionary _gamepadInputIdMap = new() + { + { GamepadInputId.LeftStick, "LeftStick" }, + { GamepadInputId.RightStick, "RightStick" }, + { GamepadInputId.LeftShoulder, "LeftShoulder" }, + { GamepadInputId.RightShoulder, "RightShoulder" }, + { GamepadInputId.LeftTrigger, "LeftTrigger" }, + { GamepadInputId.RightTrigger, "RightTrigger" }, + { GamepadInputId.DpadUp, "DpadUp" }, + { GamepadInputId.DpadDown, "DpadDown" }, + { GamepadInputId.DpadLeft, "DpadLeft" }, + { GamepadInputId.DpadRight, "DpadRight" }, + { GamepadInputId.Minus, "Minus" }, + { GamepadInputId.Plus, "Plus" }, + { GamepadInputId.Guide, "Guide" }, + { GamepadInputId.Misc1, "Misc1" }, + { GamepadInputId.Paddle1, "Paddle1" }, + { GamepadInputId.Paddle2, "Paddle2" }, + { GamepadInputId.Paddle3, "Paddle3" }, + { GamepadInputId.Paddle4, "Paddle4" }, + { GamepadInputId.Touchpad, "Touchpad" }, + { GamepadInputId.SingleLeftTrigger0, "SingleLeftTrigger0" }, + { GamepadInputId.SingleRightTrigger0, "SingleRightTrigger0" }, + { GamepadInputId.SingleLeftTrigger1, "SingleLeftTrigger1" }, + { GamepadInputId.SingleRightTrigger1, "SingleRightTrigger1" }, + { GamepadInputId.Unbound, "Unbound" }, + }; + + private static readonly Dictionary _stickInputIdMap = new() + { + { StickInputId.Left, "StickLeft" }, + { StickInputId.Right, "StickRight" }, + { StickInputId.Unbound, "Unbound" }, + }; + + public static string ToString(Button button) + { + string keyString = ""; + + switch (button.Type) + { + case ButtonType.Key: + var key = button.AsHidType(); + + if (!_keysMap.TryGetValue(button.AsHidType(), out keyString)) + { + keyString = key.ToString(); + } + + break; + case ButtonType.GamepadButtonInputId: + var gamepadButton = button.AsHidType(); + + if (!_gamepadInputIdMap.TryGetValue(button.AsHidType(), out keyString)) + { + keyString = gamepadButton.ToString(); + } + + break; + case ButtonType.StickId: + var stickInput = button.AsHidType(); + + if (!_stickInputIdMap.TryGetValue(button.AsHidType(), out keyString)) + { + keyString = stickInput.ToString(); + } + + break; + } + + return keyString; + } + } +} diff --git a/ryujinx/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs b/ryujinx/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs index 6712657f8d..d0b8266f42 100644 --- a/ryujinx/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs +++ b/ryujinx/src/Ryujinx.Gtk3/UI/Windows/ControllerWindow.cs @@ -10,6 +10,7 @@ using Ryujinx.Input; using Ryujinx.Input.Assigner; using Ryujinx.Input.GTK3; using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Helper; using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; @@ -17,6 +18,7 @@ using System.IO; using System.Reflection; using System.Text.Json; using System.Threading; +using Button = Ryujinx.Input.Button; using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using GUI = Gtk.Builder.ObjectAttribute; @@ -887,13 +889,13 @@ namespace Ryujinx.UI.Windows Thread.Sleep(10); assigner.ReadInput(); - if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.HasAnyButtonPressed() || assigner.ShouldCancel()) + if (_mousePressed || keyboard.IsPressed(Ryujinx.Input.Key.Escape) || assigner.IsAnyButtonPressed() || assigner.ShouldCancel()) { break; } } - string pressedButton = assigner.GetPressedButton(); + string pressedButton = ButtonHelper.ToString(assigner.GetPressedButton() ?? new Button(Input.Key.Unknown)); Application.Invoke(delegate { diff --git a/ryujinx/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs b/ryujinx/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs index 388ebcc07a..80fed2b82e 100644 --- a/ryujinx/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs +++ b/ryujinx/src/Ryujinx.Input/Assigner/GamepadButtonAssigner.cs @@ -49,9 +49,9 @@ namespace Ryujinx.Input.Assigner CollectButtonStats(); } - public bool HasAnyButtonPressed() + public bool IsAnyButtonPressed() { - return _detector.HasAnyButtonPressed(); + return _detector.IsAnyButtonPressed(); } public bool ShouldCancel() @@ -59,16 +59,11 @@ namespace Ryujinx.Input.Assigner return _gamepad == null || !_gamepad.IsConnected; } - public string GetPressedButton() + public Button? GetPressedButton() { IEnumerable pressedButtons = _detector.GetPressedButtons(); - if (pressedButtons.Any()) - { - return !_forStick ? pressedButtons.First().ToString() : ((StickInputId)pressedButtons.First()).ToString(); - } - - return ""; + return !_forStick ? new(pressedButtons.FirstOrDefault()) : new((StickInputId)pressedButtons.FirstOrDefault()); } private void CollectButtonStats() @@ -123,7 +118,7 @@ namespace Ryujinx.Input.Assigner _stats = new Dictionary(); } - public bool HasAnyButtonPressed() + public bool IsAnyButtonPressed() { return _stats.Values.Any(CheckButtonPressed); } diff --git a/ryujinx/src/Ryujinx.Input/Assigner/IButtonAssigner.cs b/ryujinx/src/Ryujinx.Input/Assigner/IButtonAssigner.cs index 76a9fece49..688fbddb44 100644 --- a/ryujinx/src/Ryujinx.Input/Assigner/IButtonAssigner.cs +++ b/ryujinx/src/Ryujinx.Input/Assigner/IButtonAssigner.cs @@ -19,7 +19,7 @@ namespace Ryujinx.Input.Assigner /// Check if a button was pressed. /// /// True if a button was pressed - bool HasAnyButtonPressed(); + bool IsAnyButtonPressed(); /// /// Indicate if the user of this API should cancel operations. This is triggered for example when a gamepad get disconnected or when a user cancel assignation operations. @@ -31,6 +31,6 @@ namespace Ryujinx.Input.Assigner /// Get the pressed button that was read in by the button assigner. /// /// The pressed button that was read - string GetPressedButton(); + Button? GetPressedButton(); } } diff --git a/ryujinx/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs b/ryujinx/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs index e52ef4a2ce..3c011a63b8 100644 --- a/ryujinx/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs +++ b/ryujinx/src/Ryujinx.Input/Assigner/KeyboardKeyAssigner.cs @@ -21,9 +21,9 @@ namespace Ryujinx.Input.Assigner _keyboardState = _keyboard.GetKeyboardStateSnapshot(); } - public bool HasAnyButtonPressed() + public bool IsAnyButtonPressed() { - return GetPressedButton().Length != 0; + return GetPressedButton() is not null; } public bool ShouldCancel() @@ -31,20 +31,20 @@ namespace Ryujinx.Input.Assigner return _keyboardState.IsPressed(Key.Escape); } - public string GetPressedButton() + public Button? GetPressedButton() { - string keyPressed = ""; + Button? keyPressed = null; for (Key key = Key.Unknown; key < Key.Count; key++) { if (_keyboardState.IsPressed(key)) { - keyPressed = key.ToString(); + keyPressed = new(key); break; } } - return !ShouldCancel() ? keyPressed : ""; + return !ShouldCancel() ? keyPressed : null; } } } diff --git a/ryujinx/src/Ryujinx.Input/Button.cs b/ryujinx/src/Ryujinx.Input/Button.cs new file mode 100644 index 0000000000..4289901ce9 --- /dev/null +++ b/ryujinx/src/Ryujinx.Input/Button.cs @@ -0,0 +1,33 @@ +using System; + +namespace Ryujinx.Input +{ + public readonly struct Button + { + public readonly ButtonType Type; + private readonly uint _rawValue; + + public Button(Key key) + { + Type = ButtonType.Key; + _rawValue = (uint)key; + } + + public Button(GamepadButtonInputId gamepad) + { + Type = ButtonType.GamepadButtonInputId; + _rawValue = (uint)gamepad; + } + + public Button(StickInputId stick) + { + Type = ButtonType.StickId; + _rawValue = (uint)stick; + } + + public T AsHidType() where T : Enum + { + return (T)Enum.ToObject(typeof(T), _rawValue); + } + } +} diff --git a/ryujinx/src/Ryujinx.Input/ButtonType.cs b/ryujinx/src/Ryujinx.Input/ButtonType.cs new file mode 100644 index 0000000000..25ef5eea81 --- /dev/null +++ b/ryujinx/src/Ryujinx.Input/ButtonType.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Input +{ + public enum ButtonType + { + Key, + GamepadButtonInputId, + StickId, + } +} diff --git a/ryujinx/src/Ryujinx.Input/HLE/NpadController.cs b/ryujinx/src/Ryujinx.Input/HLE/NpadController.cs index 8411c10a79..cde20f5d07 100644 --- a/ryujinx/src/Ryujinx.Input/HLE/NpadController.cs +++ b/ryujinx/src/Ryujinx.Input/HLE/NpadController.cs @@ -203,8 +203,6 @@ namespace Ryujinx.Input.HLE new(Key.NumLock, 10), }; - private bool _isValid; - private MotionInput _leftMotionInput; private MotionInput _rightMotionInput; @@ -222,7 +220,6 @@ namespace Ryujinx.Input.HLE { State = default; Id = null; - _isValid = false; _cemuHookClient = cemuHookClient; } @@ -234,11 +231,10 @@ namespace Ryujinx.Input.HLE Id = config.Id; _gamepad = GamepadDriver.GetGamepad(Id); - _isValid = _gamepad != null; UpdateUserConfiguration(config); - return _isValid; + return _gamepad != null; } public void UpdateUserConfiguration(InputConfig config) @@ -262,10 +258,7 @@ namespace Ryujinx.Input.HLE _config = config; - if (_isValid) - { - _gamepad.SetConfiguration(config); - } + _gamepad?.SetConfiguration(config); } private void UpdateMotionInput(MotionConfigController motionConfig) @@ -282,18 +275,21 @@ namespace Ryujinx.Input.HLE public void Update() { - if (_isValid && GamepadDriver != null) + // _gamepad may be altered by other threads + var gamepad = _gamepad; + + if (gamepad != null && GamepadDriver != null) { - State = _gamepad.GetMappedStateSnapshot(); + State = gamepad.GetMappedStateSnapshot(); if (_config is StandardControllerInputConfig controllerConfig && controllerConfig.Motion.EnableMotion) { if (controllerConfig.Motion.MotionBackend == MotionInputBackendType.GamepadDriver) { - if (_gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion)) + if (gamepad.Features.HasFlag(GamepadFeaturesFlag.Motion)) { - Vector3 accelerometer = _gamepad.GetMotionData(MotionInputId.Accelerometer); - Vector3 gyroscope = _gamepad.GetMotionData(MotionInputId.Gyroscope); + Vector3 accelerometer = gamepad.GetMotionData(MotionInputId.Accelerometer); + Vector3 gyroscope = gamepad.GetMotionData(MotionInputId.Gyroscope); accelerometer = new Vector3(accelerometer.X, -accelerometer.Z, accelerometer.Y); gyroscope = new Vector3(gyroscope.X, -gyroscope.Z, gyroscope.Y); diff --git a/ryujinx/src/Ryujinx/Assets/Locales/en_US.json b/ryujinx/src/Ryujinx/Assets/Locales/en_US.json index ef40fd5b2e..77ad7d1f8c 100644 --- a/ryujinx/src/Ryujinx/Assets/Locales/en_US.json +++ b/ryujinx/src/Ryujinx/Assets/Locales/en_US.json @@ -266,6 +266,107 @@ "ControllerSettingsMotionGyroDeadzone": "Gyro Deadzone:", "ControllerSettingsSave": "Save", "ControllerSettingsClose": "Close", + "KeyUnknown": "Unknown", + "KeyShiftLeft": "Shift Left", + "KeyShiftRight": "Shift Right", + "KeyControlLeft": "Ctrl Left", + "KeyMacControlLeft": "⌃ Left", + "KeyControlRight": "Ctrl Right", + "KeyMacControlRight": "⌃ Right", + "KeyAltLeft": "Alt Left", + "KeyMacAltLeft": "⌥ Left", + "KeyAltRight": "Alt Right", + "KeyMacAltRight": "⌥ Right", + "KeyWinLeft": "⊞ Left", + "KeyMacWinLeft": "⌘ Left", + "KeyWinRight": "⊞ Right", + "KeyMacWinRight": "⌘ Right", + "KeyMenu": "Menu", + "KeyUp": "Up", + "KeyDown": "Down", + "KeyLeft": "Left", + "KeyRight": "Right", + "KeyEnter": "Enter", + "KeyEscape": "Escape", + "KeySpace": "Space", + "KeyTab": "Tab", + "KeyBackSpace": "Backspace", + "KeyInsert": "Insert", + "KeyDelete": "Delete", + "KeyPageUp": "Page Up", + "KeyPageDown": "Page Down", + "KeyHome": "Home", + "KeyEnd": "End", + "KeyCapsLock": "Caps Lock", + "KeyScrollLock": "Scroll Lock", + "KeyPrintScreen": "Print Screen", + "KeyPause": "Pause", + "KeyNumLock": "Num Lock", + "KeyClear": "Clear", + "KeyKeypad0": "Keypad 0", + "KeyKeypad1": "Keypad 1", + "KeyKeypad2": "Keypad 2", + "KeyKeypad3": "Keypad 3", + "KeyKeypad4": "Keypad 4", + "KeyKeypad5": "Keypad 5", + "KeyKeypad6": "Keypad 6", + "KeyKeypad7": "Keypad 7", + "KeyKeypad8": "Keypad 8", + "KeyKeypad9": "Keypad 9", + "KeyKeypadDivide": "Keypad Divide", + "KeyKeypadMultiply": "Keypad Multiply", + "KeyKeypadSubtract": "Keypad Subtract", + "KeyKeypadAdd": "Keypad Add", + "KeyKeypadDecimal": "Keypad Decimal", + "KeyKeypadEnter": "Keypad Enter", + "KeyNumber0": "0", + "KeyNumber1": "1", + "KeyNumber2": "2", + "KeyNumber3": "3", + "KeyNumber4": "4", + "KeyNumber5": "5", + "KeyNumber6": "6", + "KeyNumber7": "7", + "KeyNumber8": "8", + "KeyNumber9": "9", + "KeyTilde": "~", + "KeyGrave": "`", + "KeyMinus": "-", + "KeyPlus": "+", + "KeyBracketLeft": "[", + "KeyBracketRight": "]", + "KeySemicolon": ";", + "KeyQuote": "\"", + "KeyComma": ",", + "KeyPeriod": ".", + "KeySlash": "/", + "KeyBackSlash": "\\", + "KeyUnbound": "Unbound", + "GamepadLeftStick": "L Stick Button", + "GamepadRightStick": "R Stick Button", + "GamepadLeftShoulder": "Left Shoulder", + "GamepadRightShoulder": "Right Shoulder", + "GamepadLeftTrigger": "Left Trigger", + "GamepadRightTrigger": "Right Trigger", + "GamepadDpadUp": "Up", + "GamepadDpadDown": "Down", + "GamepadDpadLeft": "Left", + "GamepadDpadRight": "Right", + "GamepadMinus": "-", + "GamepadPlus": "+", + "GamepadGuide": "Guide", + "GamepadMisc1": "Misc", + "GamepadPaddle1": "Paddle 1", + "GamepadPaddle2": "Paddle 2", + "GamepadPaddle3": "Paddle 3", + "GamepadPaddle4": "Paddle 4", + "GamepadTouchpad": "Touchpad", + "GamepadSingleLeftTrigger0": "Left Trigger 0", + "GamepadSingleRightTrigger0": "Right Trigger 0", + "GamepadSingleLeftTrigger1": "Left Trigger 1", + "GamepadSingleRightTrigger1": "Right Trigger 1", + "StickLeft": "Left Stick", + "StickRight": "Right Stick", "UserProfilesSelectedUserProfile": "Selected User Profile:", "UserProfilesSaveProfileName": "Save Profile Name", "UserProfilesChangeProfileImage": "Change Profile Image", diff --git a/ryujinx/src/Ryujinx/Assets/Styles/Styles.xaml b/ryujinx/src/Ryujinx/Assets/Styles/Styles.xaml index f7f64be22f..b3a6f59c8d 100644 --- a/ryujinx/src/Ryujinx/Assets/Styles/Styles.xaml +++ b/ryujinx/src/Ryujinx/Assets/Styles/Styles.xaml @@ -15,8 +15,7 @@ - + @@ -393,4 +392,4 @@ 600 756 - \ No newline at end of file + diff --git a/ryujinx/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs b/ryujinx/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs index 7e8ba73421..4f2b8daaea 100644 --- a/ryujinx/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs +++ b/ryujinx/src/Ryujinx/UI/Helpers/ButtonKeyAssigner.cs @@ -1,11 +1,8 @@ -using Avalonia.Controls; using Avalonia.Controls.Primitives; -using Avalonia.LogicalTree; using Avalonia.Threading; using Ryujinx.Input; using Ryujinx.Input.Assigner; using System; -using System.Linq; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Helpers @@ -15,12 +12,12 @@ namespace Ryujinx.Ava.UI.Helpers internal class ButtonAssignedEventArgs : EventArgs { public ToggleButton Button { get; } - public bool IsAssigned { get; } + public Button? ButtonValue { get; } - public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned) + public ButtonAssignedEventArgs(ToggleButton button, Button? buttonValue) { Button = button; - IsAssigned = isAssigned; + ButtonValue = buttonValue; } } @@ -69,7 +66,7 @@ namespace Ryujinx.Ava.UI.Helpers assigner.ReadInput(); - if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape))) + if (assigner.IsAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape))) { break; } @@ -78,15 +75,11 @@ namespace Ryujinx.Ava.UI.Helpers await Dispatcher.UIThread.InvokeAsync(() => { - string pressedButton = assigner.GetPressedButton(); + Button? pressedButton = assigner.GetPressedButton(); if (_shouldUnbind) { - SetButtonText(ToggledButton, "Unbound"); - } - else if (pressedButton != "") - { - SetButtonText(ToggledButton, pressedButton); + pressedButton = null; } _shouldUnbind = false; @@ -94,17 +87,8 @@ namespace Ryujinx.Ava.UI.Helpers ToggledButton.IsChecked = false; - ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null)); + ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton)); - static void SetButtonText(ToggleButton button, string text) - { - ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock); - - if (textBlock != null && textBlock is TextBlock block) - { - block.Text = text; - } - } }); } diff --git a/ryujinx/src/Ryujinx/UI/Helpers/KeyValueConverter.cs b/ryujinx/src/Ryujinx/UI/Helpers/KeyValueConverter.cs index 028ed6bf46..cbcf16ab32 100644 --- a/ryujinx/src/Ryujinx/UI/Helpers/KeyValueConverter.cs +++ b/ryujinx/src/Ryujinx/UI/Helpers/KeyValueConverter.cs @@ -1,7 +1,9 @@ using Avalonia.Data.Converters; +using Ryujinx.Ava.Common.Locale; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using System; +using System.Collections.Generic; using System.Globalization; namespace Ryujinx.Ava.UI.Helpers @@ -10,37 +12,173 @@ namespace Ryujinx.Ava.UI.Helpers { public static KeyValueConverter Instance = new(); + private static readonly Dictionary _keysMap = new() + { + { Key.Unknown, LocaleKeys.KeyUnknown }, + { Key.ShiftLeft, LocaleKeys.KeyShiftLeft }, + { Key.ShiftRight, LocaleKeys.KeyShiftRight }, + { Key.ControlLeft, LocaleKeys.KeyControlLeft }, + { Key.ControlRight, LocaleKeys.KeyControlRight }, + { Key.AltLeft, LocaleKeys.KeyControlLeft }, + { Key.AltRight, LocaleKeys.KeyControlRight }, + { Key.WinLeft, LocaleKeys.KeyWinLeft }, + { Key.WinRight, LocaleKeys.KeyWinRight }, + { Key.Up, LocaleKeys.KeyUp }, + { Key.Down, LocaleKeys.KeyDown }, + { Key.Left, LocaleKeys.KeyLeft }, + { Key.Right, LocaleKeys.KeyRight }, + { Key.Enter, LocaleKeys.KeyEnter }, + { Key.Escape, LocaleKeys.KeyEscape }, + { Key.Space, LocaleKeys.KeySpace }, + { Key.Tab, LocaleKeys.KeyTab }, + { Key.BackSpace, LocaleKeys.KeyBackSpace }, + { Key.Insert, LocaleKeys.KeyInsert }, + { Key.Delete, LocaleKeys.KeyDelete }, + { Key.PageUp, LocaleKeys.KeyPageUp }, + { Key.PageDown, LocaleKeys.KeyPageDown }, + { Key.Home, LocaleKeys.KeyHome }, + { Key.End, LocaleKeys.KeyEnd }, + { Key.CapsLock, LocaleKeys.KeyCapsLock }, + { Key.ScrollLock, LocaleKeys.KeyScrollLock }, + { Key.PrintScreen, LocaleKeys.KeyPrintScreen }, + { Key.Pause, LocaleKeys.KeyPause }, + { Key.NumLock, LocaleKeys.KeyNumLock }, + { Key.Clear, LocaleKeys.KeyClear }, + { Key.Keypad0, LocaleKeys.KeyKeypad0 }, + { Key.Keypad1, LocaleKeys.KeyKeypad1 }, + { Key.Keypad2, LocaleKeys.KeyKeypad2 }, + { Key.Keypad3, LocaleKeys.KeyKeypad3 }, + { Key.Keypad4, LocaleKeys.KeyKeypad4 }, + { Key.Keypad5, LocaleKeys.KeyKeypad5 }, + { Key.Keypad6, LocaleKeys.KeyKeypad6 }, + { Key.Keypad7, LocaleKeys.KeyKeypad7 }, + { Key.Keypad8, LocaleKeys.KeyKeypad8 }, + { Key.Keypad9, LocaleKeys.KeyKeypad9 }, + { Key.KeypadDivide, LocaleKeys.KeyKeypadDivide }, + { Key.KeypadMultiply, LocaleKeys.KeyKeypadMultiply }, + { Key.KeypadSubtract, LocaleKeys.KeyKeypadSubtract }, + { Key.KeypadAdd, LocaleKeys.KeyKeypadAdd }, + { Key.KeypadDecimal, LocaleKeys.KeyKeypadDecimal }, + { Key.KeypadEnter, LocaleKeys.KeyKeypadEnter }, + { Key.Number0, LocaleKeys.KeyNumber0 }, + { Key.Number1, LocaleKeys.KeyNumber1 }, + { Key.Number2, LocaleKeys.KeyNumber2 }, + { Key.Number3, LocaleKeys.KeyNumber3 }, + { Key.Number4, LocaleKeys.KeyNumber4 }, + { Key.Number5, LocaleKeys.KeyNumber5 }, + { Key.Number6, LocaleKeys.KeyNumber6 }, + { Key.Number7, LocaleKeys.KeyNumber7 }, + { Key.Number8, LocaleKeys.KeyNumber8 }, + { Key.Number9, LocaleKeys.KeyNumber9 }, + { Key.Tilde, LocaleKeys.KeyTilde }, + { Key.Grave, LocaleKeys.KeyGrave }, + { Key.Minus, LocaleKeys.KeyMinus }, + { Key.Plus, LocaleKeys.KeyPlus }, + { Key.BracketLeft, LocaleKeys.KeyBracketLeft }, + { Key.BracketRight, LocaleKeys.KeyBracketRight }, + { Key.Semicolon, LocaleKeys.KeySemicolon }, + { Key.Quote, LocaleKeys.KeyQuote }, + { Key.Comma, LocaleKeys.KeyComma }, + { Key.Period, LocaleKeys.KeyPeriod }, + { Key.Slash, LocaleKeys.KeySlash }, + { Key.BackSlash, LocaleKeys.KeyBackSlash }, + { Key.Unbound, LocaleKeys.KeyUnbound }, + }; + + private static readonly Dictionary _gamepadInputIdMap = new() + { + { GamepadInputId.LeftStick, LocaleKeys.GamepadLeftStick }, + { GamepadInputId.RightStick, LocaleKeys.GamepadRightStick }, + { GamepadInputId.LeftShoulder, LocaleKeys.GamepadLeftShoulder }, + { GamepadInputId.RightShoulder, LocaleKeys.GamepadRightShoulder }, + { GamepadInputId.LeftTrigger, LocaleKeys.GamepadLeftTrigger }, + { GamepadInputId.RightTrigger, LocaleKeys.GamepadRightTrigger }, + { GamepadInputId.DpadUp, LocaleKeys.GamepadDpadUp}, + { GamepadInputId.DpadDown, LocaleKeys.GamepadDpadDown}, + { GamepadInputId.DpadLeft, LocaleKeys.GamepadDpadLeft}, + { GamepadInputId.DpadRight, LocaleKeys.GamepadDpadRight}, + { GamepadInputId.Minus, LocaleKeys.GamepadMinus}, + { GamepadInputId.Plus, LocaleKeys.GamepadPlus}, + { GamepadInputId.Guide, LocaleKeys.GamepadGuide}, + { GamepadInputId.Misc1, LocaleKeys.GamepadMisc1}, + { GamepadInputId.Paddle1, LocaleKeys.GamepadPaddle1}, + { GamepadInputId.Paddle2, LocaleKeys.GamepadPaddle2}, + { GamepadInputId.Paddle3, LocaleKeys.GamepadPaddle3}, + { GamepadInputId.Paddle4, LocaleKeys.GamepadPaddle4}, + { GamepadInputId.Touchpad, LocaleKeys.GamepadTouchpad}, + { GamepadInputId.SingleLeftTrigger0, LocaleKeys.GamepadSingleLeftTrigger0}, + { GamepadInputId.SingleRightTrigger0, LocaleKeys.GamepadSingleRightTrigger0}, + { GamepadInputId.SingleLeftTrigger1, LocaleKeys.GamepadSingleLeftTrigger1}, + { GamepadInputId.SingleRightTrigger1, LocaleKeys.GamepadSingleRightTrigger1}, + { GamepadInputId.Unbound, LocaleKeys.KeyUnbound}, + }; + + private static readonly Dictionary _stickInputIdMap = new() + { + { StickInputId.Left, LocaleKeys.StickLeft}, + { StickInputId.Right, LocaleKeys.StickRight}, + { StickInputId.Unbound, LocaleKeys.KeyUnbound}, + }; + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - if (value == null) + string keyString = ""; + LocaleKeys localeKey; + + switch (value) { - return null; + case Key key: + if (_keysMap.TryGetValue(key, out localeKey)) + { + if (OperatingSystem.IsMacOS()) + { + localeKey = localeKey switch + { + LocaleKeys.KeyControlLeft => LocaleKeys.KeyMacControlLeft, + LocaleKeys.KeyControlRight => LocaleKeys.KeyMacControlRight, + LocaleKeys.KeyAltLeft => LocaleKeys.KeyMacAltLeft, + LocaleKeys.KeyAltRight => LocaleKeys.KeyMacAltRight, + LocaleKeys.KeyWinLeft => LocaleKeys.KeyMacWinLeft, + LocaleKeys.KeyWinRight => LocaleKeys.KeyMacWinRight, + _ => localeKey + }; + } + + keyString = LocaleManager.Instance[localeKey]; + } + else + { + keyString = key.ToString(); + } + break; + case GamepadInputId gamepadInputId: + if (_gamepadInputIdMap.TryGetValue(gamepadInputId, out localeKey)) + { + keyString = LocaleManager.Instance[localeKey]; + } + else + { + keyString = gamepadInputId.ToString(); + } + break; + case StickInputId stickInputId: + if (_stickInputIdMap.TryGetValue(stickInputId, out localeKey)) + { + keyString = LocaleManager.Instance[localeKey]; + } + else + { + keyString = stickInputId.ToString(); + } + break; } - return value.ToString(); + return keyString; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - object key = null; - - if (value != null) - { - if (targetType == typeof(Key)) - { - key = Enum.Parse(value.ToString()); - } - else if (targetType == typeof(GamepadInputId)) - { - key = Enum.Parse(value.ToString()); - } - else if (targetType == typeof(StickInputId)) - { - key = Enum.Parse(value.ToString()); - } - } - - return key; + throw new NotSupportedException(); } } } diff --git a/ryujinx/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/ryujinx/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs new file mode 100644 index 0000000000..833670bdc4 --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -0,0 +1,580 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Common.Configuration.Hid.Controller.Motion; +using System; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class GamepadInputConfig : BaseModel + { + public bool EnableCemuHookMotion { get; set; } + public string DsuServerHost { get; set; } + public int DsuServerPort { get; set; } + public int Slot { get; set; } + public int AltSlot { get; set; } + public bool MirrorInput { get; set; } + public int Sensitivity { get; set; } + public double GyroDeadzone { get; set; } + + public float WeakRumble { get; set; } + public float StrongRumble { get; set; } + + public string Id { get; set; } + public ControllerType ControllerType { get; set; } + public PlayerIndex PlayerIndex { get; set; } + + private StickInputId _leftJoystick; + public StickInputId LeftJoystick + { + get => _leftJoystick; + set + { + _leftJoystick = value; + OnPropertyChanged(); + } + } + + private bool _leftInvertStickX; + public bool LeftInvertStickX + { + get => _leftInvertStickX; + set + { + _leftInvertStickX = value; + OnPropertyChanged(); + } + } + + private bool _leftInvertStickY; + public bool LeftInvertStickY + { + get => _leftInvertStickY; + set + { + _leftInvertStickY = value; + OnPropertyChanged(); + } + } + + private bool _leftRotate90; + public bool LeftRotate90 + { + get => _leftRotate90; + set + { + _leftRotate90 = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _leftStickButton; + public GamepadInputId LeftStickButton + { + get => _leftStickButton; + set + { + _leftStickButton = value; + OnPropertyChanged(); + } + } + + private StickInputId _rightJoystick; + public StickInputId RightJoystick + { + get => _rightJoystick; + set + { + _rightJoystick = value; + OnPropertyChanged(); + } + } + + private bool _rightInvertStickX; + public bool RightInvertStickX + { + get => _rightInvertStickX; + set + { + _rightInvertStickX = value; + OnPropertyChanged(); + } + } + + private bool _rightInvertStickY; + public bool RightInvertStickY + { + get => _rightInvertStickY; + set + { + _rightInvertStickY = value; + OnPropertyChanged(); + } + } + + private bool _rightRotate90; + public bool RightRotate90 + { + get => _rightRotate90; + set + { + _rightRotate90 = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _rightStickButton; + public GamepadInputId RightStickButton + { + get => _rightStickButton; + set + { + _rightStickButton = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadUp; + public GamepadInputId DpadUp + { + get => _dpadUp; + set + { + _dpadUp = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadDown; + public GamepadInputId DpadDown + { + get => _dpadDown; + set + { + _dpadDown = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadLeft; + public GamepadInputId DpadLeft + { + get => _dpadLeft; + set + { + _dpadLeft = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _dpadRight; + public GamepadInputId DpadRight + { + get => _dpadRight; + set + { + _dpadRight = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonL; + public GamepadInputId ButtonL + { + get => _buttonL; + set + { + _buttonL = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonMinus; + public GamepadInputId ButtonMinus + { + get => _buttonMinus; + set + { + _buttonMinus = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _leftButtonSl; + public GamepadInputId LeftButtonSl + { + get => _leftButtonSl; + set + { + _leftButtonSl = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _leftButtonSr; + public GamepadInputId LeftButtonSr + { + get => _leftButtonSr; + set + { + _leftButtonSr = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonZl; + public GamepadInputId ButtonZl + { + get => _buttonZl; + set + { + _buttonZl = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonA; + public GamepadInputId ButtonA + { + get => _buttonA; + set + { + _buttonA = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonB; + public GamepadInputId ButtonB + { + get => _buttonB; + set + { + _buttonB = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonX; + public GamepadInputId ButtonX + { + get => _buttonX; + set + { + _buttonX = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonY; + public GamepadInputId ButtonY + { + get => _buttonY; + set + { + _buttonY = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonR; + public GamepadInputId ButtonR + { + get => _buttonR; + set + { + _buttonR = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonPlus; + public GamepadInputId ButtonPlus + { + get => _buttonPlus; + set + { + _buttonPlus = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _rightButtonSl; + public GamepadInputId RightButtonSl + { + get => _rightButtonSl; + set + { + _rightButtonSl = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _rightButtonSr; + public GamepadInputId RightButtonSr + { + get => _rightButtonSr; + set + { + _rightButtonSr = value; + OnPropertyChanged(); + } + } + + private GamepadInputId _buttonZr; + public GamepadInputId ButtonZr + { + get => _buttonZr; + set + { + _buttonZr = value; + OnPropertyChanged(); + } + } + + private float _deadzoneLeft; + public float DeadzoneLeft + { + get => _deadzoneLeft; + set + { + _deadzoneLeft = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _deadzoneRight; + public float DeadzoneRight + { + get => _deadzoneRight; + set + { + _deadzoneRight = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _rangeLeft; + public float RangeLeft + { + get => _rangeLeft; + set + { + _rangeLeft = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _rangeRight; + public float RangeRight + { + get => _rangeRight; + set + { + _rangeRight = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private float _triggerThreshold; + public float TriggerThreshold + { + get => _triggerThreshold; + set + { + _triggerThreshold = MathF.Round(value, 3); + OnPropertyChanged(); + } + } + + private bool _enableMotion; + public bool EnableMotion + { + get => _enableMotion; + set + { + _enableMotion = value; + OnPropertyChanged(); + } + } + + private bool _enableRumble; + public bool EnableRumble + { + get => _enableRumble; + set + { + _enableRumble = value; + OnPropertyChanged(); + } + } + + public GamepadInputConfig(InputConfig config) + { + if (config != null) + { + Id = config.Id; + ControllerType = config.ControllerType; + PlayerIndex = config.PlayerIndex; + + if (config is not StandardControllerInputConfig controllerInput) + { + return; + } + + LeftJoystick = controllerInput.LeftJoyconStick.Joystick; + LeftInvertStickX = controllerInput.LeftJoyconStick.InvertStickX; + LeftInvertStickY = controllerInput.LeftJoyconStick.InvertStickY; + LeftRotate90 = controllerInput.LeftJoyconStick.Rotate90CW; + LeftStickButton = controllerInput.LeftJoyconStick.StickButton; + + RightJoystick = controllerInput.RightJoyconStick.Joystick; + RightInvertStickX = controllerInput.RightJoyconStick.InvertStickX; + RightInvertStickY = controllerInput.RightJoyconStick.InvertStickY; + RightRotate90 = controllerInput.RightJoyconStick.Rotate90CW; + RightStickButton = controllerInput.RightJoyconStick.StickButton; + + DpadUp = controllerInput.LeftJoycon.DpadUp; + DpadDown = controllerInput.LeftJoycon.DpadDown; + DpadLeft = controllerInput.LeftJoycon.DpadLeft; + DpadRight = controllerInput.LeftJoycon.DpadRight; + ButtonL = controllerInput.LeftJoycon.ButtonL; + ButtonMinus = controllerInput.LeftJoycon.ButtonMinus; + LeftButtonSl = controllerInput.LeftJoycon.ButtonSl; + LeftButtonSr = controllerInput.LeftJoycon.ButtonSr; + ButtonZl = controllerInput.LeftJoycon.ButtonZl; + + ButtonA = controllerInput.RightJoycon.ButtonA; + ButtonB = controllerInput.RightJoycon.ButtonB; + ButtonX = controllerInput.RightJoycon.ButtonX; + ButtonY = controllerInput.RightJoycon.ButtonY; + ButtonR = controllerInput.RightJoycon.ButtonR; + ButtonPlus = controllerInput.RightJoycon.ButtonPlus; + RightButtonSl = controllerInput.RightJoycon.ButtonSl; + RightButtonSr = controllerInput.RightJoycon.ButtonSr; + ButtonZr = controllerInput.RightJoycon.ButtonZr; + + DeadzoneLeft = controllerInput.DeadzoneLeft; + DeadzoneRight = controllerInput.DeadzoneRight; + RangeLeft = controllerInput.RangeLeft; + RangeRight = controllerInput.RangeRight; + TriggerThreshold = controllerInput.TriggerThreshold; + + if (controllerInput.Motion != null) + { + EnableMotion = controllerInput.Motion.EnableMotion; + GyroDeadzone = controllerInput.Motion.GyroDeadzone; + Sensitivity = controllerInput.Motion.Sensitivity; + + if (controllerInput.Motion is CemuHookMotionConfigController cemuHook) + { + EnableCemuHookMotion = true; + DsuServerHost = cemuHook.DsuServerHost; + DsuServerPort = cemuHook.DsuServerPort; + Slot = cemuHook.Slot; + AltSlot = cemuHook.AltSlot; + MirrorInput = cemuHook.MirrorInput; + } + } + + if (controllerInput.Rumble != null) + { + EnableRumble = controllerInput.Rumble.EnableRumble; + WeakRumble = controllerInput.Rumble.WeakRumble; + StrongRumble = controllerInput.Rumble.StrongRumble; + } + } + } + + public InputConfig GetConfig() + { + var config = new StandardControllerInputConfig + { + Id = Id, + Backend = InputBackendType.GamepadSDL2, + PlayerIndex = PlayerIndex, + ControllerType = ControllerType, + LeftJoycon = new LeftJoyconCommonConfig + { + DpadUp = DpadUp, + DpadDown = DpadDown, + DpadLeft = DpadLeft, + DpadRight = DpadRight, + ButtonL = ButtonL, + ButtonMinus = ButtonMinus, + ButtonSl = LeftButtonSl, + ButtonSr = LeftButtonSr, + ButtonZl = ButtonZl, + }, + RightJoycon = new RightJoyconCommonConfig + { + ButtonA = ButtonA, + ButtonB = ButtonB, + ButtonX = ButtonX, + ButtonY = ButtonY, + ButtonPlus = ButtonPlus, + ButtonSl = RightButtonSl, + ButtonSr = RightButtonSr, + ButtonR = ButtonR, + ButtonZr = ButtonZr, + }, + LeftJoyconStick = new JoyconConfigControllerStick + { + Joystick = LeftJoystick, + InvertStickX = LeftInvertStickX, + InvertStickY = LeftInvertStickY, + Rotate90CW = LeftRotate90, + StickButton = LeftStickButton, + }, + RightJoyconStick = new JoyconConfigControllerStick + { + Joystick = RightJoystick, + InvertStickX = RightInvertStickX, + InvertStickY = RightInvertStickY, + Rotate90CW = RightRotate90, + StickButton = RightStickButton, + }, + Rumble = new RumbleConfigController + { + EnableRumble = EnableRumble, + WeakRumble = WeakRumble, + StrongRumble = StrongRumble, + }, + Version = InputConfig.CurrentVersion, + DeadzoneLeft = DeadzoneLeft, + DeadzoneRight = DeadzoneRight, + RangeLeft = RangeLeft, + RangeRight = RangeRight, + TriggerThreshold = TriggerThreshold, + }; + + if (EnableCemuHookMotion) + { + config.Motion = new CemuHookMotionConfigController + { + EnableMotion = EnableMotion, + MotionBackend = MotionInputBackendType.CemuHook, + GyroDeadzone = GyroDeadzone, + Sensitivity = Sensitivity, + DsuServerHost = DsuServerHost, + DsuServerPort = DsuServerPort, + Slot = Slot, + AltSlot = AltSlot, + MirrorInput = MirrorInput, + }; + } + else + { + config.Motion = new StandardMotionConfigController + { + EnableMotion = EnableMotion, + MotionBackend = MotionInputBackendType.GamepadDriver, + GyroDeadzone = GyroDeadzone, + Sensitivity = Sensitivity, + }; + } + + return config; + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/ryujinx/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs new file mode 100644 index 0000000000..b5f53508bd --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -0,0 +1,141 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class HotkeyConfig : BaseModel + { + private Key _toggleVsync; + public Key ToggleVsync + { + get => _toggleVsync; + set + { + _toggleVsync = value; + OnPropertyChanged(); + } + } + + private Key _screenshot; + public Key Screenshot + { + get => _screenshot; + set + { + _screenshot = value; + OnPropertyChanged(); + } + } + + private Key _showUI; + public Key ShowUI + { + get => _showUI; + set + { + _showUI = value; + OnPropertyChanged(); + } + } + + private Key _pause; + public Key Pause + { + get => _pause; + set + { + _pause = value; + OnPropertyChanged(); + } + } + + private Key _toggleMute; + public Key ToggleMute + { + get => _toggleMute; + set + { + _toggleMute = value; + OnPropertyChanged(); + } + } + + private Key _resScaleUp; + public Key ResScaleUp + { + get => _resScaleUp; + set + { + _resScaleUp = value; + OnPropertyChanged(); + } + } + + private Key _resScaleDown; + public Key ResScaleDown + { + get => _resScaleDown; + set + { + _resScaleDown = value; + OnPropertyChanged(); + } + } + + private Key _volumeUp; + public Key VolumeUp + { + get => _volumeUp; + set + { + _volumeUp = value; + OnPropertyChanged(); + } + } + + private Key _volumeDown; + public Key VolumeDown + { + get => _volumeDown; + set + { + _volumeDown = value; + OnPropertyChanged(); + } + } + + public HotkeyConfig(KeyboardHotkeys config) + { + if (config != null) + { + ToggleVsync = config.ToggleVsync; + Screenshot = config.Screenshot; + ShowUI = config.ShowUI; + Pause = config.Pause; + ToggleMute = config.ToggleMute; + ResScaleUp = config.ResScaleUp; + ResScaleDown = config.ResScaleDown; + VolumeUp = config.VolumeUp; + VolumeDown = config.VolumeDown; + } + } + + public KeyboardHotkeys GetConfig() + { + var config = new KeyboardHotkeys + { + ToggleVsync = ToggleVsync, + Screenshot = Screenshot, + ShowUI = ShowUI, + Pause = Pause, + ToggleMute = ToggleMute, + ResScaleUp = ResScaleUp, + ResScaleDown = ResScaleDown, + VolumeUp = VolumeUp, + VolumeDown = VolumeDown, + }; + + return config; + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs b/ryujinx/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs new file mode 100644 index 0000000000..66f1f62a22 --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs @@ -0,0 +1,422 @@ +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Common.Configuration.Hid; +using Ryujinx.Common.Configuration.Hid.Keyboard; + +namespace Ryujinx.Ava.UI.Models.Input +{ + public class KeyboardInputConfig : BaseModel + { + public string Id { get; set; } + public ControllerType ControllerType { get; set; } + public PlayerIndex PlayerIndex { get; set; } + + private Key _leftStickUp; + public Key LeftStickUp + { + get => _leftStickUp; + set + { + _leftStickUp = value; + OnPropertyChanged(); + } + } + + private Key _leftStickDown; + public Key LeftStickDown + { + get => _leftStickDown; + set + { + _leftStickDown = value; + OnPropertyChanged(); + } + } + + private Key _leftStickLeft; + public Key LeftStickLeft + { + get => _leftStickLeft; + set + { + _leftStickLeft = value; + OnPropertyChanged(); + } + } + + private Key _leftStickRight; + public Key LeftStickRight + { + get => _leftStickRight; + set + { + _leftStickRight = value; + OnPropertyChanged(); + } + } + + private Key _leftStickButton; + public Key LeftStickButton + { + get => _leftStickButton; + set + { + _leftStickButton = value; + OnPropertyChanged(); + } + } + + private Key _rightStickUp; + public Key RightStickUp + { + get => _rightStickUp; + set + { + _rightStickUp = value; + OnPropertyChanged(); + } + } + + private Key _rightStickDown; + public Key RightStickDown + { + get => _rightStickDown; + set + { + _rightStickDown = value; + OnPropertyChanged(); + } + } + + private Key _rightStickLeft; + public Key RightStickLeft + { + get => _rightStickLeft; + set + { + _rightStickLeft = value; + OnPropertyChanged(); + } + } + + private Key _rightStickRight; + public Key RightStickRight + { + get => _rightStickRight; + set + { + _rightStickRight = value; + OnPropertyChanged(); + } + } + + private Key _rightStickButton; + public Key RightStickButton + { + get => _rightStickButton; + set + { + _rightStickButton = value; + OnPropertyChanged(); + } + } + + private Key _dpadUp; + public Key DpadUp + { + get => _dpadUp; + set + { + _dpadUp = value; + OnPropertyChanged(); + } + } + + private Key _dpadDown; + public Key DpadDown + { + get => _dpadDown; + set + { + _dpadDown = value; + OnPropertyChanged(); + } + } + + private Key _dpadLeft; + public Key DpadLeft + { + get => _dpadLeft; + set + { + _dpadLeft = value; + OnPropertyChanged(); + } + } + + private Key _dpadRight; + public Key DpadRight + { + get => _dpadRight; + set + { + _dpadRight = value; + OnPropertyChanged(); + } + } + + private Key _buttonL; + public Key ButtonL + { + get => _buttonL; + set + { + _buttonL = value; + OnPropertyChanged(); + } + } + + private Key _buttonMinus; + public Key ButtonMinus + { + get => _buttonMinus; + set + { + _buttonMinus = value; + OnPropertyChanged(); + } + } + + private Key _leftButtonSl; + public Key LeftButtonSl + { + get => _leftButtonSl; + set + { + _leftButtonSl = value; + OnPropertyChanged(); + } + } + + private Key _leftButtonSr; + public Key LeftButtonSr + { + get => _leftButtonSr; + set + { + _leftButtonSr = value; + OnPropertyChanged(); + } + } + + private Key _buttonZl; + public Key ButtonZl + { + get => _buttonZl; + set + { + _buttonZl = value; + OnPropertyChanged(); + } + } + + private Key _buttonA; + public Key ButtonA + { + get => _buttonA; + set + { + _buttonA = value; + OnPropertyChanged(); + } + } + + private Key _buttonB; + public Key ButtonB + { + get => _buttonB; + set + { + _buttonB = value; + OnPropertyChanged(); + } + } + + private Key _buttonX; + public Key ButtonX + { + get => _buttonX; + set + { + _buttonX = value; + OnPropertyChanged(); + } + } + + private Key _buttonY; + public Key ButtonY + { + get => _buttonY; + set + { + _buttonY = value; + OnPropertyChanged(); + } + } + + private Key _buttonR; + public Key ButtonR + { + get => _buttonR; + set + { + _buttonR = value; + OnPropertyChanged(); + } + } + + private Key _buttonPlus; + public Key ButtonPlus + { + get => _buttonPlus; + set + { + _buttonPlus = value; + OnPropertyChanged(); + } + } + + private Key _rightButtonSl; + public Key RightButtonSl + { + get => _rightButtonSl; + set + { + _rightButtonSl = value; + OnPropertyChanged(); + } + } + + private Key _rightButtonSr; + public Key RightButtonSr + { + get => _rightButtonSr; + set + { + _rightButtonSr = value; + OnPropertyChanged(); + } + } + + private Key _buttonZr; + public Key ButtonZr + { + get => _buttonZr; + set + { + _buttonZr = value; + OnPropertyChanged(); + } + } + + public KeyboardInputConfig(InputConfig config) + { + if (config != null) + { + Id = config.Id; + ControllerType = config.ControllerType; + PlayerIndex = config.PlayerIndex; + + if (config is not StandardKeyboardInputConfig keyboardConfig) + { + return; + } + + LeftStickUp = keyboardConfig.LeftJoyconStick.StickUp; + LeftStickDown = keyboardConfig.LeftJoyconStick.StickDown; + LeftStickLeft = keyboardConfig.LeftJoyconStick.StickLeft; + LeftStickRight = keyboardConfig.LeftJoyconStick.StickRight; + LeftStickButton = keyboardConfig.LeftJoyconStick.StickButton; + + RightStickUp = keyboardConfig.RightJoyconStick.StickUp; + RightStickDown = keyboardConfig.RightJoyconStick.StickDown; + RightStickLeft = keyboardConfig.RightJoyconStick.StickLeft; + RightStickRight = keyboardConfig.RightJoyconStick.StickRight; + RightStickButton = keyboardConfig.RightJoyconStick.StickButton; + + DpadUp = keyboardConfig.LeftJoycon.DpadUp; + DpadDown = keyboardConfig.LeftJoycon.DpadDown; + DpadLeft = keyboardConfig.LeftJoycon.DpadLeft; + DpadRight = keyboardConfig.LeftJoycon.DpadRight; + ButtonL = keyboardConfig.LeftJoycon.ButtonL; + ButtonMinus = keyboardConfig.LeftJoycon.ButtonMinus; + LeftButtonSl = keyboardConfig.LeftJoycon.ButtonSl; + LeftButtonSr = keyboardConfig.LeftJoycon.ButtonSr; + ButtonZl = keyboardConfig.LeftJoycon.ButtonZl; + + ButtonA = keyboardConfig.RightJoycon.ButtonA; + ButtonB = keyboardConfig.RightJoycon.ButtonB; + ButtonX = keyboardConfig.RightJoycon.ButtonX; + ButtonY = keyboardConfig.RightJoycon.ButtonY; + ButtonR = keyboardConfig.RightJoycon.ButtonR; + ButtonPlus = keyboardConfig.RightJoycon.ButtonPlus; + RightButtonSl = keyboardConfig.RightJoycon.ButtonSl; + RightButtonSr = keyboardConfig.RightJoycon.ButtonSr; + ButtonZr = keyboardConfig.RightJoycon.ButtonZr; + } + } + + public InputConfig GetConfig() + { + var config = new StandardKeyboardInputConfig + { + Id = Id, + Backend = InputBackendType.WindowKeyboard, + PlayerIndex = PlayerIndex, + ControllerType = ControllerType, + LeftJoycon = new LeftJoyconCommonConfig + { + DpadUp = DpadUp, + DpadDown = DpadDown, + DpadLeft = DpadLeft, + DpadRight = DpadRight, + ButtonL = ButtonL, + ButtonMinus = ButtonMinus, + ButtonZl = ButtonZl, + ButtonSl = LeftButtonSl, + ButtonSr = LeftButtonSr, + }, + RightJoycon = new RightJoyconCommonConfig + { + ButtonA = ButtonA, + ButtonB = ButtonB, + ButtonX = ButtonX, + ButtonY = ButtonY, + ButtonPlus = ButtonPlus, + ButtonSl = RightButtonSl, + ButtonSr = RightButtonSr, + ButtonR = ButtonR, + ButtonZr = ButtonZr, + }, + LeftJoyconStick = new JoyconConfigKeyboardStick + { + StickUp = LeftStickUp, + StickDown = LeftStickDown, + StickRight = LeftStickRight, + StickLeft = LeftStickLeft, + StickButton = LeftStickButton, + }, + RightJoyconStick = new JoyconConfigKeyboardStick + { + StickUp = RightStickUp, + StickDown = RightStickDown, + StickLeft = RightStickLeft, + StickRight = RightStickRight, + StickButton = RightStickButton, + }, + Version = InputConfig.CurrentVersion, + }; + + return config; + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/Models/InputConfiguration.cs b/ryujinx/src/Ryujinx/UI/Models/InputConfiguration.cs deleted file mode 100644 index f1352c6d8b..0000000000 --- a/ryujinx/src/Ryujinx/UI/Models/InputConfiguration.cs +++ /dev/null @@ -1,456 +0,0 @@ -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Common.Configuration.Hid.Controller.Motion; -using Ryujinx.Common.Configuration.Hid.Keyboard; -using System; - -namespace Ryujinx.Ava.UI.Models -{ - internal class InputConfiguration : BaseModel - { - private float _deadzoneRight; - private float _triggerThreshold; - private float _deadzoneLeft; - private double _gyroDeadzone; - private int _sensitivity; - private bool _enableMotion; - private float _weakRumble; - private float _strongRumble; - private float _rangeLeft; - private float _rangeRight; - - public InputBackendType Backend { get; set; } - - /// - /// Controller id - /// - public string Id { get; set; } - - /// - /// Controller's Type - /// - public ControllerType ControllerType { get; set; } - - /// - /// Player's Index for the controller - /// - public PlayerIndex PlayerIndex { get; set; } - - public TStick LeftJoystick { get; set; } - public bool LeftInvertStickX { get; set; } - public bool LeftInvertStickY { get; set; } - public bool RightRotate90 { get; set; } - public TKey LeftControllerStickButton { get; set; } - - public TStick RightJoystick { get; set; } - public bool RightInvertStickX { get; set; } - public bool RightInvertStickY { get; set; } - public bool LeftRotate90 { get; set; } - public TKey RightControllerStickButton { get; set; } - - public float DeadzoneLeft - { - get => _deadzoneLeft; - set - { - _deadzoneLeft = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float RangeLeft - { - get => _rangeLeft; - set - { - _rangeLeft = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float DeadzoneRight - { - get => _deadzoneRight; - set - { - _deadzoneRight = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float RangeRight - { - get => _rangeRight; - set - { - _rangeRight = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float TriggerThreshold - { - get => _triggerThreshold; - set - { - _triggerThreshold = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public MotionInputBackendType MotionBackend { get; set; } - - public TKey ButtonMinus { get; set; } - public TKey ButtonL { get; set; } - public TKey ButtonZl { get; set; } - public TKey LeftButtonSl { get; set; } - public TKey LeftButtonSr { get; set; } - public TKey DpadUp { get; set; } - public TKey DpadDown { get; set; } - public TKey DpadLeft { get; set; } - public TKey DpadRight { get; set; } - - public TKey ButtonPlus { get; set; } - public TKey ButtonR { get; set; } - public TKey ButtonZr { get; set; } - public TKey RightButtonSl { get; set; } - public TKey RightButtonSr { get; set; } - public TKey ButtonX { get; set; } - public TKey ButtonB { get; set; } - public TKey ButtonY { get; set; } - public TKey ButtonA { get; set; } - - public TKey LeftStickUp { get; set; } - public TKey LeftStickDown { get; set; } - public TKey LeftStickLeft { get; set; } - public TKey LeftStickRight { get; set; } - public TKey LeftKeyboardStickButton { get; set; } - - public TKey RightStickUp { get; set; } - public TKey RightStickDown { get; set; } - public TKey RightStickLeft { get; set; } - public TKey RightStickRight { get; set; } - public TKey RightKeyboardStickButton { get; set; } - - public int Sensitivity - { - get => _sensitivity; - set - { - _sensitivity = value; - - OnPropertyChanged(); - } - } - - public double GyroDeadzone - { - get => _gyroDeadzone; - set - { - _gyroDeadzone = Math.Round(value, 3); - - OnPropertyChanged(); - } - } - - public bool EnableMotion - { - get => _enableMotion; set - { - _enableMotion = value; - - OnPropertyChanged(); - } - } - - public bool EnableCemuHookMotion { get; set; } - public int Slot { get; set; } - public int AltSlot { get; set; } - public bool MirrorInput { get; set; } - public string DsuServerHost { get; set; } - public int DsuServerPort { get; set; } - - public bool EnableRumble { get; set; } - public float WeakRumble - { - get => _weakRumble; set - { - _weakRumble = value; - - OnPropertyChanged(); - } - } - public float StrongRumble - { - get => _strongRumble; set - { - _strongRumble = value; - - OnPropertyChanged(); - } - } - - public InputConfiguration(InputConfig config) - { - if (config != null) - { - Backend = config.Backend; - Id = config.Id; - ControllerType = config.ControllerType; - PlayerIndex = config.PlayerIndex; - - if (config is StandardKeyboardInputConfig keyboardConfig) - { - LeftStickUp = (TKey)(object)keyboardConfig.LeftJoyconStick.StickUp; - LeftStickDown = (TKey)(object)keyboardConfig.LeftJoyconStick.StickDown; - LeftStickLeft = (TKey)(object)keyboardConfig.LeftJoyconStick.StickLeft; - LeftStickRight = (TKey)(object)keyboardConfig.LeftJoyconStick.StickRight; - LeftKeyboardStickButton = (TKey)(object)keyboardConfig.LeftJoyconStick.StickButton; - - RightStickUp = (TKey)(object)keyboardConfig.RightJoyconStick.StickUp; - RightStickDown = (TKey)(object)keyboardConfig.RightJoyconStick.StickDown; - RightStickLeft = (TKey)(object)keyboardConfig.RightJoyconStick.StickLeft; - RightStickRight = (TKey)(object)keyboardConfig.RightJoyconStick.StickRight; - RightKeyboardStickButton = (TKey)(object)keyboardConfig.RightJoyconStick.StickButton; - - ButtonA = (TKey)(object)keyboardConfig.RightJoycon.ButtonA; - ButtonB = (TKey)(object)keyboardConfig.RightJoycon.ButtonB; - ButtonX = (TKey)(object)keyboardConfig.RightJoycon.ButtonX; - ButtonY = (TKey)(object)keyboardConfig.RightJoycon.ButtonY; - ButtonR = (TKey)(object)keyboardConfig.RightJoycon.ButtonR; - RightButtonSl = (TKey)(object)keyboardConfig.RightJoycon.ButtonSl; - RightButtonSr = (TKey)(object)keyboardConfig.RightJoycon.ButtonSr; - ButtonZr = (TKey)(object)keyboardConfig.RightJoycon.ButtonZr; - ButtonPlus = (TKey)(object)keyboardConfig.RightJoycon.ButtonPlus; - - DpadUp = (TKey)(object)keyboardConfig.LeftJoycon.DpadUp; - DpadDown = (TKey)(object)keyboardConfig.LeftJoycon.DpadDown; - DpadLeft = (TKey)(object)keyboardConfig.LeftJoycon.DpadLeft; - DpadRight = (TKey)(object)keyboardConfig.LeftJoycon.DpadRight; - ButtonMinus = (TKey)(object)keyboardConfig.LeftJoycon.ButtonMinus; - LeftButtonSl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSl; - LeftButtonSr = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSr; - ButtonZl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonZl; - ButtonL = (TKey)(object)keyboardConfig.LeftJoycon.ButtonL; - } - else if (config is StandardControllerInputConfig controllerConfig) - { - LeftJoystick = (TStick)(object)controllerConfig.LeftJoyconStick.Joystick; - LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX; - LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY; - LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW; - LeftControllerStickButton = (TKey)(object)controllerConfig.LeftJoyconStick.StickButton; - - RightJoystick = (TStick)(object)controllerConfig.RightJoyconStick.Joystick; - RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX; - RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY; - RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW; - RightControllerStickButton = (TKey)(object)controllerConfig.RightJoyconStick.StickButton; - - ButtonA = (TKey)(object)controllerConfig.RightJoycon.ButtonA; - ButtonB = (TKey)(object)controllerConfig.RightJoycon.ButtonB; - ButtonX = (TKey)(object)controllerConfig.RightJoycon.ButtonX; - ButtonY = (TKey)(object)controllerConfig.RightJoycon.ButtonY; - ButtonR = (TKey)(object)controllerConfig.RightJoycon.ButtonR; - RightButtonSl = (TKey)(object)controllerConfig.RightJoycon.ButtonSl; - RightButtonSr = (TKey)(object)controllerConfig.RightJoycon.ButtonSr; - ButtonZr = (TKey)(object)controllerConfig.RightJoycon.ButtonZr; - ButtonPlus = (TKey)(object)controllerConfig.RightJoycon.ButtonPlus; - - DpadUp = (TKey)(object)controllerConfig.LeftJoycon.DpadUp; - DpadDown = (TKey)(object)controllerConfig.LeftJoycon.DpadDown; - DpadLeft = (TKey)(object)controllerConfig.LeftJoycon.DpadLeft; - DpadRight = (TKey)(object)controllerConfig.LeftJoycon.DpadRight; - ButtonMinus = (TKey)(object)controllerConfig.LeftJoycon.ButtonMinus; - LeftButtonSl = (TKey)(object)controllerConfig.LeftJoycon.ButtonSl; - LeftButtonSr = (TKey)(object)controllerConfig.LeftJoycon.ButtonSr; - ButtonZl = (TKey)(object)controllerConfig.LeftJoycon.ButtonZl; - ButtonL = (TKey)(object)controllerConfig.LeftJoycon.ButtonL; - - DeadzoneLeft = controllerConfig.DeadzoneLeft; - DeadzoneRight = controllerConfig.DeadzoneRight; - RangeLeft = controllerConfig.RangeLeft; - RangeRight = controllerConfig.RangeRight; - TriggerThreshold = controllerConfig.TriggerThreshold; - - if (controllerConfig.Motion != null) - { - EnableMotion = controllerConfig.Motion.EnableMotion; - MotionBackend = controllerConfig.Motion.MotionBackend; - GyroDeadzone = controllerConfig.Motion.GyroDeadzone; - Sensitivity = controllerConfig.Motion.Sensitivity; - - if (controllerConfig.Motion is CemuHookMotionConfigController cemuHook) - { - EnableCemuHookMotion = true; - DsuServerHost = cemuHook.DsuServerHost; - DsuServerPort = cemuHook.DsuServerPort; - Slot = cemuHook.Slot; - AltSlot = cemuHook.AltSlot; - MirrorInput = cemuHook.MirrorInput; - } - - if (controllerConfig.Rumble != null) - { - EnableRumble = controllerConfig.Rumble.EnableRumble; - WeakRumble = controllerConfig.Rumble.WeakRumble; - StrongRumble = controllerConfig.Rumble.StrongRumble; - } - } - } - } - } - - public InputConfiguration() - { - } - - public InputConfig GetConfig() - { - if (Backend == InputBackendType.WindowKeyboard) - { - return new StandardKeyboardInputConfig - { - Id = Id, - Backend = Backend, - PlayerIndex = PlayerIndex, - ControllerType = ControllerType, - LeftJoycon = new LeftJoyconCommonConfig - { - DpadUp = (Key)(object)DpadUp, - DpadDown = (Key)(object)DpadDown, - DpadLeft = (Key)(object)DpadLeft, - DpadRight = (Key)(object)DpadRight, - ButtonL = (Key)(object)ButtonL, - ButtonZl = (Key)(object)ButtonZl, - ButtonSl = (Key)(object)LeftButtonSl, - ButtonSr = (Key)(object)LeftButtonSr, - ButtonMinus = (Key)(object)ButtonMinus, - }, - RightJoycon = new RightJoyconCommonConfig - { - ButtonA = (Key)(object)ButtonA, - ButtonB = (Key)(object)ButtonB, - ButtonX = (Key)(object)ButtonX, - ButtonY = (Key)(object)ButtonY, - ButtonPlus = (Key)(object)ButtonPlus, - ButtonSl = (Key)(object)RightButtonSl, - ButtonSr = (Key)(object)RightButtonSr, - ButtonR = (Key)(object)ButtonR, - ButtonZr = (Key)(object)ButtonZr, - }, - LeftJoyconStick = new JoyconConfigKeyboardStick - { - StickUp = (Key)(object)LeftStickUp, - StickDown = (Key)(object)LeftStickDown, - StickRight = (Key)(object)LeftStickRight, - StickLeft = (Key)(object)LeftStickLeft, - StickButton = (Key)(object)LeftKeyboardStickButton, - }, - RightJoyconStick = new JoyconConfigKeyboardStick - { - StickUp = (Key)(object)RightStickUp, - StickDown = (Key)(object)RightStickDown, - StickLeft = (Key)(object)RightStickLeft, - StickRight = (Key)(object)RightStickRight, - StickButton = (Key)(object)RightKeyboardStickButton, - }, - Version = InputConfig.CurrentVersion, - }; - - } - - if (Backend == InputBackendType.GamepadSDL2) - { - var config = new StandardControllerInputConfig - { - Id = Id, - Backend = Backend, - PlayerIndex = PlayerIndex, - ControllerType = ControllerType, - LeftJoycon = new LeftJoyconCommonConfig - { - DpadUp = (GamepadInputId)(object)DpadUp, - DpadDown = (GamepadInputId)(object)DpadDown, - DpadLeft = (GamepadInputId)(object)DpadLeft, - DpadRight = (GamepadInputId)(object)DpadRight, - ButtonL = (GamepadInputId)(object)ButtonL, - ButtonZl = (GamepadInputId)(object)ButtonZl, - ButtonSl = (GamepadInputId)(object)LeftButtonSl, - ButtonSr = (GamepadInputId)(object)LeftButtonSr, - ButtonMinus = (GamepadInputId)(object)ButtonMinus, - }, - RightJoycon = new RightJoyconCommonConfig - { - ButtonA = (GamepadInputId)(object)ButtonA, - ButtonB = (GamepadInputId)(object)ButtonB, - ButtonX = (GamepadInputId)(object)ButtonX, - ButtonY = (GamepadInputId)(object)ButtonY, - ButtonPlus = (GamepadInputId)(object)ButtonPlus, - ButtonSl = (GamepadInputId)(object)RightButtonSl, - ButtonSr = (GamepadInputId)(object)RightButtonSr, - ButtonR = (GamepadInputId)(object)ButtonR, - ButtonZr = (GamepadInputId)(object)ButtonZr, - }, - LeftJoyconStick = new JoyconConfigControllerStick - { - Joystick = (StickInputId)(object)LeftJoystick, - InvertStickX = LeftInvertStickX, - InvertStickY = LeftInvertStickY, - Rotate90CW = LeftRotate90, - StickButton = (GamepadInputId)(object)LeftControllerStickButton, - }, - RightJoyconStick = new JoyconConfigControllerStick - { - Joystick = (StickInputId)(object)RightJoystick, - InvertStickX = RightInvertStickX, - InvertStickY = RightInvertStickY, - Rotate90CW = RightRotate90, - StickButton = (GamepadInputId)(object)RightControllerStickButton, - }, - Rumble = new RumbleConfigController - { - EnableRumble = EnableRumble, - WeakRumble = WeakRumble, - StrongRumble = StrongRumble, - }, - Version = InputConfig.CurrentVersion, - DeadzoneLeft = DeadzoneLeft, - DeadzoneRight = DeadzoneRight, - RangeLeft = RangeLeft, - RangeRight = RangeRight, - TriggerThreshold = TriggerThreshold, - Motion = EnableCemuHookMotion - ? new CemuHookMotionConfigController - { - DsuServerHost = DsuServerHost, - DsuServerPort = DsuServerPort, - Slot = Slot, - AltSlot = AltSlot, - MirrorInput = MirrorInput, - MotionBackend = MotionInputBackendType.CemuHook, - } - : new StandardMotionConfigController - { - MotionBackend = MotionInputBackendType.GamepadDriver, - }, - }; - - config.Motion.Sensitivity = Sensitivity; - config.Motion.EnableMotion = EnableMotion; - config.Motion.GyroDeadzone = GyroDeadzone; - - return config; - } - - return null; - } - } -} diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs new file mode 100644 index 0000000000..6ee79a371c --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -0,0 +1,84 @@ +using Avalonia.Svg.Skia; +using Ryujinx.Ava.UI.Models.Input; +using Ryujinx.Ava.UI.Views.Input; + +namespace Ryujinx.Ava.UI.ViewModels.Input +{ + public class ControllerInputViewModel : BaseModel + { + private GamepadInputConfig _config; + public GamepadInputConfig Config + { + get => _config; + set + { + _config = value; + OnPropertyChanged(); + } + } + + private bool _isLeft; + public bool IsLeft + { + get => _isLeft; + set + { + _isLeft = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + private bool _isRight; + public bool IsRight + { + get => _isRight; + set + { + _isRight = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + public bool HasSides => IsLeft ^ IsRight; + + private SvgImage _image; + public SvgImage Image + { + get => _image; + set + { + _image = value; + OnPropertyChanged(); + } + } + + public readonly InputViewModel ParentModel; + + public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) + { + ParentModel = model; + model.NotifyChangesEvent += OnParentModelChanged; + OnParentModelChanged(); + Config = config; + } + + public async void ShowMotionConfig() + { + await MotionInputView.Show(this); + } + + public async void ShowRumbleConfig() + { + await RumbleInputView.Show(this); + } + + public void OnParentModelChanged() + { + IsLeft = ParentModel.IsLeft; + IsRight = ParentModel.IsRight; + Image = ParentModel.Image; + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs similarity index 92% rename from ryujinx/src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs rename to ryujinx/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 71ad2c1278..74da459793 100644 --- a/ryujinx/src/Ryujinx/UI/ViewModels/ControllerInputViewModel.cs +++ b/ryujinx/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -8,7 +8,7 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.Views.Input; +using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.Common.Configuration; @@ -30,9 +30,9 @@ using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.Gamepad using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using Key = Ryujinx.Common.Configuration.Hid.Key; -namespace Ryujinx.Ava.UI.ViewModels +namespace Ryujinx.Ava.UI.ViewModels.Input { - public class ControllerInputViewModel : BaseModel, IDisposable + public class InputViewModel : BaseModel, IDisposable { private const string Disabled = "disabled"; private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg"; @@ -48,7 +48,7 @@ namespace Ryujinx.Ava.UI.ViewModels private int _controllerNumber; private string _controllerImage; private int _device; - private object _configuration; + private object _configViewModel; private string _profileName; private bool _isLoaded; @@ -71,13 +71,14 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsLeft { get; set; } public bool IsModified { get; set; } + public event Action NotifyChangesEvent; - public object Configuration + public object ConfigViewModel { - get => _configuration; + get => _configViewModel; set { - _configuration = value; + _configViewModel = value; OnPropertyChanged(); } @@ -232,7 +233,7 @@ namespace Ryujinx.Ava.UI.ViewModels public InputConfig Config { get; set; } - public ControllerInputViewModel(UserControl owner) : this() + public InputViewModel(UserControl owner) : this() { if (Program.PreviewerDetached) { @@ -255,7 +256,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public ControllerInputViewModel() + public InputViewModel() { PlayerIndexes = new ObservableCollection(); Controllers = new ObservableCollection(); @@ -282,12 +283,12 @@ namespace Ryujinx.Ava.UI.ViewModels if (Config is StandardKeyboardInputConfig keyboardInputConfig) { - Configuration = new InputConfiguration(keyboardInputConfig); + ConfigViewModel = new KeyboardInputViewModel(this, new KeyboardInputConfig(keyboardInputConfig)); } if (Config is StandardControllerInputConfig controllerInputConfig) { - Configuration = new InputConfiguration(controllerInputConfig); + ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig)); } } @@ -323,16 +324,6 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public async void ShowMotionConfig() - { - await MotionInputView.Show(this); - } - - public async void ShowRumbleConfig() - { - await RumbleInputView.Show(this); - } - private void LoadInputDriver() { if (_device < 0) @@ -740,7 +731,7 @@ namespace Ryujinx.Ava.UI.ViewModels return; } - if (Configuration == null) + if (ConfigViewModel == null) { return; } @@ -751,35 +742,37 @@ namespace Ryujinx.Ava.UI.ViewModels return; } - - bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - - if (validFileName) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - InputConfig config = null; - - if (IsKeyboard) - { - config = (Configuration as InputConfiguration).GetConfig(); - } - else if (IsController) - { - config = (Configuration as InputConfiguration).GetConfig(); - } - - config.ControllerType = Controllers[_controller].Type; - - string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); - - await File.WriteAllTextAsync(path, jsonString); - - LoadProfiles(); - } else { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); + bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; + + if (validFileName) + { + string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); + + InputConfig config = null; + + if (IsKeyboard) + { + config = (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig(); + } + else if (IsController) + { + config = (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); + } + + config.ControllerType = Controllers[_controller].Type; + + string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); + + await File.WriteAllTextAsync(path, jsonString); + + LoadProfiles(); + } + else + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); + } } } @@ -830,18 +823,18 @@ namespace Ryujinx.Ava.UI.ViewModels if (device.Type == DeviceType.Keyboard) { - var inputConfig = Configuration as InputConfiguration; + var inputConfig = (ConfigViewModel as KeyboardInputViewModel).Config; inputConfig.Id = device.Id; } else { - var inputConfig = Configuration as InputConfiguration; + var inputConfig = (ConfigViewModel as ControllerInputViewModel).Config; inputConfig.Id = device.Id.Split(" ")[0]; } var config = !IsController - ? (Configuration as InputConfiguration).GetConfig() - : (Configuration as InputConfiguration).GetConfig(); + ? (ConfigViewModel as KeyboardInputViewModel).Config.GetConfig() + : (ConfigViewModel as ControllerInputViewModel).Config.GetConfig(); config.ControllerType = Controllers[_controller].Type; config.PlayerIndex = _playerId; @@ -872,12 +865,13 @@ namespace Ryujinx.Ava.UI.ViewModels public void NotifyChanges() { - OnPropertyChanged(nameof(Configuration)); + OnPropertyChanged(nameof(ConfigViewModel)); OnPropertyChanged(nameof(IsController)); OnPropertyChanged(nameof(ShowSettings)); OnPropertyChanged(nameof(IsKeyboard)); OnPropertyChanged(nameof(IsRight)); OnPropertyChanged(nameof(IsLeft)); + NotifyChangesEvent?.Invoke(); } public void Dispose() diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs new file mode 100644 index 0000000000..0b530eb094 --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs @@ -0,0 +1,73 @@ +using Avalonia.Svg.Skia; +using Ryujinx.Ava.UI.Models.Input; + +namespace Ryujinx.Ava.UI.ViewModels.Input +{ + public class KeyboardInputViewModel : BaseModel + { + private KeyboardInputConfig _config; + public KeyboardInputConfig Config + { + get => _config; + set + { + _config = value; + OnPropertyChanged(); + } + } + + private bool _isLeft; + public bool IsLeft + { + get => _isLeft; + set + { + _isLeft = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + private bool _isRight; + public bool IsRight + { + get => _isRight; + set + { + _isRight = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(HasSides)); + } + } + + public bool HasSides => IsLeft ^ IsRight; + + private SvgImage _image; + public SvgImage Image + { + get => _image; + set + { + _image = value; + OnPropertyChanged(); + } + } + + public readonly InputViewModel ParentModel; + + public KeyboardInputViewModel(InputViewModel model, KeyboardInputConfig config) + { + ParentModel = model; + model.NotifyChangesEvent += OnParentModelChanged; + OnParentModelChanged(); + Config = config; + } + + public void OnParentModelChanged() + { + IsLeft = ParentModel.IsLeft; + IsRight = ParentModel.IsRight; + Image = ParentModel.Image; + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs similarity index 97% rename from ryujinx/src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs rename to ryujinx/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs index 0b12a51f6c..c9ed8f2d46 100644 --- a/ryujinx/src/Ryujinx/UI/ViewModels/MotionInputViewModel.cs +++ b/ryujinx/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ava.UI.ViewModels +namespace Ryujinx.Ava.UI.ViewModels.Input { public class MotionInputViewModel : BaseModel { diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs similarity index 92% rename from ryujinx/src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs rename to ryujinx/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs index 49de19937d..8ad33cf4ce 100644 --- a/ryujinx/src/Ryujinx/UI/ViewModels/RumbleInputViewModel.cs +++ b/ryujinx/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ava.UI.ViewModels +namespace Ryujinx.Ava.UI.ViewModels.Input { public class RumbleInputViewModel : BaseModel { diff --git a/ryujinx/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/ryujinx/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index fde8f74ae4..6074a5fdb3 100644 --- a/ryujinx/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/ryujinx/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -7,9 +7,9 @@ using Ryujinx.Audio.Backends.SDL2; using Ryujinx.Audio.Backends.SoundIo; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.Logging; @@ -46,7 +46,6 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _isVulkanAvailable = true; private bool _directoryChanged; private readonly List _gpuIds = new(); - private KeyboardHotkeys _keyboardHotkeys; private int _graphicsBackendIndex; private int _scalingFilter; private int _scalingFilterLevel; @@ -237,16 +236,7 @@ namespace Ryujinx.Ava.UI.ViewModels get => new(_networkInterfaces.Keys); } - public KeyboardHotkeys KeyboardHotkeys - { - get => _keyboardHotkeys; - set - { - _keyboardHotkeys = value; - - OnPropertyChanged(); - } - } + public HotkeyConfig KeyboardHotkey { get; set; } public int NetworkInterfaceIndex { @@ -413,7 +403,7 @@ namespace Ryujinx.Ava.UI.ViewModels EnableMouse = config.Hid.EnableMouse; // Keyboard Hotkeys - KeyboardHotkeys = config.Hid.Hotkeys.Value; + KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value); // System Region = (int)config.System.Region.Value; @@ -500,7 +490,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.Hid.EnableMouse.Value = EnableMouse; // Keyboard Hotkeys - config.Hid.Hotkeys.Value = KeyboardHotkeys; + config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig(); // System config.System.Region.Value = (Region)Region; diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/ryujinx/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 99f2b6b694..08bdf90f4c 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/ryujinx/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -1,13 +1,11 @@ @@ -34,192 +33,10 @@ HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Vertical"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + MinHeight="450"> @@ -258,9 +75,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsTriggerZL}" TextAlignment="Center" /> - + @@ -274,9 +91,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsTriggerL}" TextAlignment="Center" /> - + @@ -290,9 +107,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsButtonMinus}" TextAlignment="Center" /> - + @@ -312,100 +129,8 @@ Margin="0,0,0,10" HorizontalAlignment="Center" Text="{locale:Locale ControllerSettingsLStick}" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -416,9 +141,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsStickButton}" TextAlignment="Center" /> - + @@ -433,22 +158,22 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsStickStick}" TextAlignment="Center" /> - + - + - + - + + Value="{Binding Config.DeadzoneLeft, Mode=TwoWay}" /> + Text="{Binding Config.DeadzoneLeft, StringFormat=\{0:0.00\}}" /> + Value="{Binding Config.RangeLeft, Mode=TwoWay}" /> + Text="{Binding Config.RangeLeft, StringFormat=\{0:0.00\}}" /> @@ -526,9 +251,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadUp}" TextAlignment="Center" /> - + @@ -543,9 +268,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadDown}" TextAlignment="Center" /> - + @@ -560,9 +285,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadLeft}" TextAlignment="Center" /> - + @@ -577,9 +302,9 @@ VerticalAlignment="Center" Text="{locale:Locale ControllerSettingsDPadRight}" TextAlignment="Center" /> - + @@ -592,6 +317,13 @@ Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> + + + Value="{Binding Config.TriggerThreshold, Mode=TwoWay}" /> + Text="{Binding Config.TriggerThreshold, StringFormat=\{0:0.00\}}" /> - + - + IsVisible="{Binding IsLeft}" + Orientation="Horizontal"> - - - - + + + + - + IsVisible="{Binding IsLeft}" + Orientation="Horizontal"> - - - - + + + + - + IsVisible="{Binding IsRight}" + Orientation="Horizontal"> - - - - + + + + - + IsVisible="{Binding IsRight}" + Orientation="Horizontal"> - + + + + - - + HorizontalAlignment="Stretch"> @@ -721,7 +449,7 @@ Margin="10" MinWidth="0" Grid.Column="0" - IsChecked="{ReflectionBinding Configuration.EnableMotion, Mode=TwoWay}"> + IsChecked="{Binding Config.EnableMotion, Mode=TwoWay}"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/InputView.axaml.cs b/ryujinx/src/Ryujinx/UI/Views/Input/InputView.axaml.cs new file mode 100644 index 0000000000..356381a8aa --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/Views/Input/InputView.axaml.cs @@ -0,0 +1,61 @@ +using Avalonia.Controls; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models; +using Ryujinx.Ava.UI.ViewModels.Input; + +namespace Ryujinx.Ava.UI.Views.Input +{ + public partial class InputView : UserControl + { + private bool _dialogOpen; + private InputViewModel ViewModel { get; set; } + + public InputView() + { + DataContext = ViewModel = new InputViewModel(this); + + InitializeComponent(); + } + + public void SaveCurrentProfile() + { + ViewModel.Save(); + } + + private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (ViewModel.IsModified && !_dialogOpen) + { + _dialogOpen = true; + + var result = await ContentDialogHelper.CreateConfirmationDialog( + LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage], + LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage], + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + if (result == UserResult.Yes) + { + ViewModel.Save(); + } + + _dialogOpen = false; + + ViewModel.IsModified = false; + + if (e.AddedItems.Count > 0) + { + var player = (PlayerModel)e.AddedItems[0]; + ViewModel.PlayerId = player.Id; + } + } + } + + public void Dispose() + { + ViewModel.Dispose(); + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml b/ryujinx/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml new file mode 100644 index 0000000000..e4566f463d --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml @@ -0,0 +1,675 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs b/ryujinx/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs new file mode 100644 index 0000000000..f17c7496ca --- /dev/null +++ b/ryujinx/src/Ryujinx/UI/Views/Input/KeyboardInputView.axaml.cs @@ -0,0 +1,208 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.Primitives; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.LogicalTree; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels.Input; +using Ryujinx.Input; +using Ryujinx.Input.Assigner; +using Key = Ryujinx.Common.Configuration.Hid.Key; + +namespace Ryujinx.Ava.UI.Views.Input +{ + public partial class KeyboardInputView : UserControl + { + private ButtonKeyAssigner _currentAssigner; + + public KeyboardInputView() + { + InitializeComponent(); + + foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) + { + if (visual is ToggleButton button and not CheckBox) + { + button.IsCheckedChanged += Button_IsCheckedChanged; + } + } + } + + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver) + { + _currentAssigner.Cancel(); + } + } + + private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) + { + if (sender is ToggleButton button) + { + if ((bool)button.IsChecked) + { + if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + { + return; + } + + if (_currentAssigner == null) + { + _currentAssigner = new ButtonKeyAssigner(button); + + Focus(NavigationMethod.Pointer); + + PointerPressed += MouseClick; + + var viewModel = (DataContext as KeyboardInputViewModel); + + IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations. + IButtonAssigner assigner = CreateButtonAssigner(); + + _currentAssigner.ButtonAssigned += (sender, e) => + { + if (e.ButtonValue.HasValue) + { + var buttonValue = e.ButtonValue.Value; + viewModel.ParentModel.IsModified = true; + + switch (button.Name) + { + case "ButtonZl": + viewModel.Config.ButtonZl = buttonValue.AsHidType(); + break; + case "ButtonL": + viewModel.Config.ButtonL = buttonValue.AsHidType(); + break; + case "ButtonMinus": + viewModel.Config.ButtonMinus = buttonValue.AsHidType(); + break; + case "LeftStickButton": + viewModel.Config.LeftStickButton = buttonValue.AsHidType(); + break; + case "LeftStickUp": + viewModel.Config.LeftStickUp = buttonValue.AsHidType(); + break; + case "LeftStickDown": + viewModel.Config.LeftStickDown = buttonValue.AsHidType(); + break; + case "LeftStickRight": + viewModel.Config.LeftStickRight = buttonValue.AsHidType(); + break; + case "LeftStickLeft": + viewModel.Config.LeftStickLeft = buttonValue.AsHidType(); + break; + case "DpadUp": + viewModel.Config.DpadUp = buttonValue.AsHidType(); + break; + case "DpadDown": + viewModel.Config.DpadDown = buttonValue.AsHidType(); + break; + case "DpadLeft": + viewModel.Config.DpadLeft = buttonValue.AsHidType(); + break; + case "DpadRight": + viewModel.Config.DpadRight = buttonValue.AsHidType(); + break; + case "LeftButtonSr": + viewModel.Config.LeftButtonSr = buttonValue.AsHidType(); + break; + case "LeftButtonSl": + viewModel.Config.LeftButtonSl = buttonValue.AsHidType(); + break; + case "RightButtonSr": + viewModel.Config.RightButtonSr = buttonValue.AsHidType(); + break; + case "RightButtonSl": + viewModel.Config.RightButtonSl = buttonValue.AsHidType(); + break; + case "ButtonZr": + viewModel.Config.ButtonZr = buttonValue.AsHidType(); + break; + case "ButtonR": + viewModel.Config.ButtonR = buttonValue.AsHidType(); + break; + case "ButtonPlus": + viewModel.Config.ButtonPlus = buttonValue.AsHidType(); + break; + case "ButtonA": + viewModel.Config.ButtonA = buttonValue.AsHidType(); + break; + case "ButtonB": + viewModel.Config.ButtonB = buttonValue.AsHidType(); + break; + case "ButtonX": + viewModel.Config.ButtonX = buttonValue.AsHidType(); + break; + case "ButtonY": + viewModel.Config.ButtonY = buttonValue.AsHidType(); + break; + case "RightStickButton": + viewModel.Config.RightStickButton = buttonValue.AsHidType(); + break; + case "RightStickUp": + viewModel.Config.RightStickUp = buttonValue.AsHidType(); + break; + case "RightStickDown": + viewModel.Config.RightStickDown = buttonValue.AsHidType(); + break; + case "RightStickRight": + viewModel.Config.RightStickRight = buttonValue.AsHidType(); + break; + case "RightStickLeft": + viewModel.Config.RightStickLeft = buttonValue.AsHidType(); + break; + } + } + }; + + _currentAssigner.GetInputAndAssign(assigner, keyboard); + } + else + { + if (_currentAssigner != null) + { + _currentAssigner.Cancel(); + _currentAssigner = null; + button.IsChecked = false; + } + } + } + else + { + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } + } + + private void MouseClick(object sender, PointerPressedEventArgs e) + { + bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; + + _currentAssigner?.Cancel(shouldUnbind); + + PointerPressed -= MouseClick; + } + + private IButtonAssigner CreateButtonAssigner() + { + IButtonAssigner assigner; + + assigner = new KeyboardKeyAssigner((IKeyboard)(DataContext as KeyboardInputViewModel).ParentModel.SelectedGamepad); + + return assigner; + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + base.OnDetachedFromVisualTree(e); + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } +} diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml b/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml index a6b587f671..0d018e297a 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml +++ b/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml @@ -6,7 +6,7 @@ xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" + xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" mc:Ignorable="d" x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView" x:DataType="viewModels:MotionInputViewModel" diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs b/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs index 1b340752b1..2304364b67 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs +++ b/ryujinx/src/Ryujinx/UI/Views/Input/MotionInputView.axaml.cs @@ -1,9 +1,7 @@ using Avalonia.Controls; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Ava.UI.ViewModels.Input; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Views.Input @@ -19,7 +17,7 @@ namespace Ryujinx.Ava.UI.Views.Input public MotionInputView(ControllerInputViewModel viewModel) { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; _viewModel = new MotionInputViewModel { @@ -51,7 +49,7 @@ namespace Ryujinx.Ava.UI.Views.Input }; contentDialog.PrimaryButtonClick += (sender, args) => { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; config.Slot = content._viewModel.Slot; config.Sensitivity = content._viewModel.Sensitivity; config.GyroDeadzone = content._viewModel.GyroDeadzone; diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml b/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml index 5b7087a470..1beb1f06e8 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml +++ b/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml @@ -5,7 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" + xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" mc:Ignorable="d" x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView" x:DataType="viewModels:RumbleInputViewModel" diff --git a/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs b/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs index 9307f872c3..58a4b416b6 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs +++ b/ryujinx/src/Ryujinx/UI/Views/Input/RumbleInputView.axaml.cs @@ -1,9 +1,7 @@ using Avalonia.Controls; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Ava.UI.ViewModels.Input; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Views.Input @@ -19,7 +17,7 @@ namespace Ryujinx.Ava.UI.Views.Input public RumbleInputView(ControllerInputViewModel viewModel) { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; _viewModel = new RumbleInputViewModel { @@ -47,7 +45,7 @@ namespace Ryujinx.Ava.UI.Views.Input contentDialog.PrimaryButtonClick += (sender, args) => { - var config = viewModel.Configuration as InputConfiguration; + var config = viewModel.Config; config.StrongRumble = content._viewModel.StrongRumble; config.WeakRumble = content._viewModel.WeakRumble; }; diff --git a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml index b4eae01ef9..bffcada055 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml @@ -9,6 +9,7 @@ xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" mc:Ignorable="d" x:DataType="viewModels:SettingsViewModel" + x:CompileBindings="True" Focusable="True"> @@ -16,6 +17,23 @@ + + + + + + - - - - - - + + + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - - - - + + + + - \ No newline at end of file + diff --git a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs index b006d703f4..fb0fe2bb12 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsHotkeysView.axaml.cs @@ -2,10 +2,13 @@ using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; +using Avalonia.LogicalTree; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Input; using Ryujinx.Input.Assigner; +using Key = Ryujinx.Common.Configuration.Hid.Key; namespace Ryujinx.Ava.UI.Views.Settings { @@ -17,9 +20,28 @@ namespace Ryujinx.Ava.UI.Views.Settings public SettingsHotkeysView() { InitializeComponent(); + + foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) + { + if (visual is ToggleButton button and not CheckBox) + { + button.IsCheckedChanged += Button_IsCheckedChanged; + } + } + _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this); } + protected override void OnPointerReleased(PointerReleasedEventArgs e) + { + base.OnPointerReleased(e); + + if (!_currentAssigner?.ToggledButton?.IsPointerOver ?? false) + { + _currentAssigner.Cancel(); + } + } + private void MouseClick(object sender, PointerPressedEventArgs e) { bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; @@ -29,53 +51,94 @@ namespace Ryujinx.Ava.UI.Views.Settings PointerPressed -= MouseClick; } - private void Button_Checked(object sender, RoutedEventArgs e) + private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) { if (sender is ToggleButton button) { - if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + if ((bool)button.IsChecked) { - return; - } + if (_currentAssigner != null && button == _currentAssigner.ToggledButton) + { + return; + } - if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked) - { - _currentAssigner = new ButtonKeyAssigner(button); + if (_currentAssigner == null) + { + _currentAssigner = new ButtonKeyAssigner(button); - this.Focus(NavigationMethod.Pointer); + this.Focus(NavigationMethod.Pointer); - PointerPressed += MouseClick; + PointerPressed += MouseClick; - var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]); - IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); + var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad("0"); + IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); - _currentAssigner.GetInputAndAssign(assigner); + _currentAssigner.ButtonAssigned += (sender, e) => + { + if (e.ButtonValue.HasValue) + { + var viewModel = (DataContext) as SettingsViewModel; + var buttonValue = e.ButtonValue.Value; + + switch (button.Name) + { + case "ToggleVsync": + viewModel.KeyboardHotkey.ToggleVsync = buttonValue.AsHidType(); + break; + case "Screenshot": + viewModel.KeyboardHotkey.Screenshot = buttonValue.AsHidType(); + break; + case "ShowUI": + viewModel.KeyboardHotkey.ShowUI = buttonValue.AsHidType(); + break; + case "Pause": + viewModel.KeyboardHotkey.Pause = buttonValue.AsHidType(); + break; + case "ToggleMute": + viewModel.KeyboardHotkey.ToggleMute = buttonValue.AsHidType(); + break; + case "ResScaleUp": + viewModel.KeyboardHotkey.ResScaleUp = buttonValue.AsHidType(); + break; + case "ResScaleDown": + viewModel.KeyboardHotkey.ResScaleDown = buttonValue.AsHidType(); + break; + case "VolumeUp": + viewModel.KeyboardHotkey.VolumeUp = buttonValue.AsHidType(); + break; + case "VolumeDown": + viewModel.KeyboardHotkey.VolumeDown = buttonValue.AsHidType(); + break; + } + } + }; + + _currentAssigner.GetInputAndAssign(assigner, keyboard); + } + else + { + if (_currentAssigner != null) + { + _currentAssigner.Cancel(); + _currentAssigner = null; + button.IsChecked = false; + } + } } else { - if (_currentAssigner != null) - { - ToggleButton oldButton = _currentAssigner.ToggledButton; - - _currentAssigner.Cancel(); - _currentAssigner = null; - - button.IsChecked = false; - } + _currentAssigner?.Cancel(); + _currentAssigner = null; } } } - private void Button_Unchecked(object sender, RoutedEventArgs e) - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - public void Dispose() { _currentAssigner?.Cancel(); _currentAssigner = null; + + _avaloniaKeyboardDriver.Dispose(); } } } diff --git a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml index 81f4b68b74..55c2ed6e3c 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml +++ b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml @@ -27,9 +27,9 @@ - + Name="InputView" /> diff --git a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs index e75c9f0cc4..55b69af068 100644 --- a/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs +++ b/ryujinx/src/Ryujinx/UI/Views/Settings/SettingsInputView.axaml.cs @@ -11,7 +11,7 @@ namespace Ryujinx.Ava.UI.Views.Settings public void Dispose() { - ControllerSettings.Dispose(); + InputView.Dispose(); } } } diff --git a/ryujinx/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs b/ryujinx/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs index d7bb0b8837..314501c525 100644 --- a/ryujinx/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs +++ b/ryujinx/src/Ryujinx/UI/Windows/SettingsWindow.axaml.cs @@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.Windows public void SaveSettings() { - InputPage.ControllerSettings?.SaveCurrentProfile(); + InputPage.InputView?.SaveCurrentProfile(); if (Owner is MainWindow window && ViewModel.DirectoryChanged) { diff --git a/shadowsocks-rust/Cargo.lock b/shadowsocks-rust/Cargo.lock index 63b7e12750..84ef41a17f 100644 --- a/shadowsocks-rust/Cargo.lock +++ b/shadowsocks-rust/Cargo.lock @@ -180,32 +180,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" -[[package]] -name = "aws-lc-rs" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f379c4e505c0692333bd90a334baa234990faa06bdabefd3261f765946aa920" -dependencies = [ - "aws-lc-sys", - "mirai-annotations", - "paste", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68aa3d613f42dbf301dbbcaf3dc260805fd33ffd95f6d290ad7231a9e5d877a7" -dependencies = [ - "bindgen", - "cmake", - "dunce", - "fs_extra", - "libc", - "paste", -] - [[package]] name = "backtrace" version = "0.3.71" @@ -245,29 +219,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bindgen" -version = "0.69.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" -dependencies = [ - "bitflags 2.5.0", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.57", - "which", -] - [[package]] name = "bit-vec" version = "0.6.3" @@ -408,15 +359,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.0" @@ -476,17 +418,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.4.18" @@ -747,12 +678,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - [[package]] name = "ecdsa" version = "0.16.9" @@ -950,12 +875,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1103,12 +1022,6 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "group" version = "0.13.0" @@ -1306,15 +1219,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "hostname" version = "0.3.1" @@ -1677,12 +1581,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.153" @@ -1852,12 +1750,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.7.2" @@ -1879,12 +1771,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "mirai-annotations" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" - [[package]] name = "multimap" version = "0.8.3" @@ -1921,16 +1807,6 @@ dependencies = [ "libc", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "notify" version = "6.1.1" @@ -2159,12 +2035,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -2791,9 +2661,9 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c4d6d8ad9f2492485e13453acbb291dd08f64441b6609c491f1c2cd2c6b4fe1" dependencies = [ - "aws-lc-rs", "log", "once_cell", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki 0.102.2", "subtle", @@ -2866,7 +2736,6 @@ version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ - "aws-lc-rs", "ring 0.17.8", "rustls-pki-types", "untrusted 0.9.0", @@ -3209,12 +3078,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -3995,18 +3858,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "widestring" version = "1.0.2" diff --git a/shadowsocks-rust/Cross.toml b/shadowsocks-rust/Cross.toml index a64c818271..1a4557b517 100644 --- a/shadowsocks-rust/Cross.toml +++ b/shadowsocks-rust/Cross.toml @@ -1,18 +1,2 @@ [build.env] passthrough = ["RUSTFLAGS"] - -[target.mips-unknown-linux-musl] -# image = "rustembedded/cross:mips-unknown-linux-musl-0.2.1" -# pre-build = [ -# "dpkg --add-architecture $CROSS_DEB_ARCH", -# "apt-get update", -# "apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH", -# ] - -[target.mipsel-unknown-linux-musl] -# image = "rustembedded/cross:mipsel-unknown-linux-musl-0.2.1" -# pre-build = [ -# "dpkg --add-architecture $CROSS_DEB_ARCH", -# "apt-get update", -# "apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH", -# ] diff --git a/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml b/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml index 8565c31481..9272800a20 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml +++ b/shadowsocks-rust/crates/shadowsocks-service/Cargo.toml @@ -145,7 +145,6 @@ tokio = { version = "1.5", features = [ ] } tokio-native-tls = { version = "0.3", optional = true } native-tls = { version = "0.2.8", optional = true, features = ["alpn"] } -tokio-rustls = { version = "0.26", optional = true } webpki-roots = { version = "0.26", optional = true } rustls-native-certs = { version = "0.7", optional = true } async-trait = "0.1" @@ -190,6 +189,19 @@ nix = { version = "0.28", features = ["ioctl"] } [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.52", features = ["Win32_Networking_WinSock"] } +[target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] +tokio-rustls = { version = "0.26", optional = true, default-features = false, features = [ + "logging", + "tls12", + "ring", +] } +[target.'cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))'.dependencies] +tokio-rustls = { version = "0.26", optional = true, default-features = false, features = [ + "logging", + "tls12", +] } + + [build-dependencies] prost-build = { version = "0.12.4", optional = true } diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/config.rs b/shadowsocks-rust/crates/shadowsocks-service/src/config.rs index 46820e9453..d71241efd1 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/config.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/config.rs @@ -393,6 +393,12 @@ struct SSServerExtConfig { #[serde(skip_serializing_if = "Option::is_none")] #[cfg(any(target_os = "linux", target_os = "android"))] outbound_fwmark: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + outbound_bind_addr: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + outbound_bind_interface: Option, } /// Server config type @@ -1178,9 +1184,11 @@ pub struct ServerInstanceConfig { pub config: ServerConfig, /// Server's private ACL, set to `None` will use the global `AccessControl` pub acl: Option, - /// Server's outbound fwmark to support split tunnel + /// Server's outbound fwmark / address / interface to support split tunnel #[cfg(any(target_os = "linux", target_os = "android"))] pub outbound_fwmark: Option, + pub outbound_bind_addr: Option, + pub outbound_bind_interface: Option, } impl ServerInstanceConfig { @@ -1191,6 +1199,8 @@ impl ServerInstanceConfig { acl: None, #[cfg(any(target_os = "linux", target_os = "android"))] outbound_fwmark: None, + outbound_bind_addr: None, + outbound_bind_interface: None, } } } @@ -1861,11 +1871,25 @@ impl Config { nsvr.set_timeout(timeout); } + let mut outbound_bind_addr: Option = None; + + if let Some(ref bind_addr) = config.outbound_bind_addr { + match bind_addr.parse::() { + Ok(b) => outbound_bind_addr = Some(b), + Err(..) => { + let err = Error::new(ErrorKind::Invalid, "invalid outbound_bind_addr", None); + return Err(err); + } + } + } + let server_instance = ServerInstanceConfig { config: nsvr, acl: None, #[cfg(any(target_os = "linux", target_os = "android"))] outbound_fwmark: config.outbound_fwmark, + outbound_bind_addr, + outbound_bind_interface: config.outbound_bind_interface.clone(), }; nconfig.server.push(server_instance); @@ -2029,11 +2053,25 @@ impl Config { nsvr.set_weight(weight); } + let mut outbound_bind_addr: Option = None; + + if let Some(ref bind_addr) = config.outbound_bind_addr { + match bind_addr.parse::() { + Ok(b) => outbound_bind_addr = Some(b), + Err(..) => { + let err = Error::new(ErrorKind::Invalid, "invalid outbound_bind_addr", None); + return Err(err); + } + } + } + let mut server_instance = ServerInstanceConfig { config: nsvr, acl: None, #[cfg(any(target_os = "linux", target_os = "android"))] outbound_fwmark: config.outbound_fwmark, + outbound_bind_addr, + outbound_bind_interface: config.outbound_bind_interface.clone(), }; if let Some(acl_path) = svr.acl { @@ -2056,6 +2094,14 @@ impl Config { server_instance.outbound_fwmark = Some(outbound_fwmark); } + if let Some(outbound_bind_addr) = svr.outbound_bind_addr { + server_instance.outbound_bind_addr = Some(outbound_bind_addr); + } + + if let Some(ref outbound_bind_interface) = svr.outbound_bind_interface { + server_instance.outbound_bind_interface = Some(outbound_bind_interface.clone()); + } + nconfig.server.push(server_instance); } } @@ -2829,7 +2875,9 @@ impl fmt::Display for Config { .as_ref() .and_then(|a| a.file_path().to_str().map(ToOwned::to_owned)), #[cfg(any(target_os = "linux", target_os = "android"))] - outbound_fwmark: inst.outbound_fwmark.clone(), + outbound_fwmark: inst.outbound_fwmark, + outbound_bind_addr: inst.outbound_bind_addr, + outbound_bind_interface: inst.outbound_bind_interface.clone(), }); } diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/http/utils.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/http/utils.rs index 32ae7b908c..41bd4a6c89 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/http/utils.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/http/utils.rs @@ -131,7 +131,12 @@ pub async fn connect_host( } else { let server = balancer.best_tcp_server(); - match AutoProxyClientStream::connect(context, server.as_ref(), host).await { + match AutoProxyClientStream::connect_with_opts( + context, + server.as_ref(), + host, + server.connect_opts_ref() + ).await { Ok(s) => Ok((s, Some(server))), Err(err) => { error!( diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/loadbalancing/server_data.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/loadbalancing/server_data.rs index f42fce1edd..413b8dd8f4 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/loadbalancing/server_data.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/loadbalancing/server_data.rs @@ -86,6 +86,14 @@ impl ServerIdent { connect_opts.fwmark = Some(fwmark); } + if let Some(bind_local_addr) = svr_cfg.outbound_bind_addr { + connect_opts.bind_local_addr = Some(bind_local_addr); + } + + if let Some(ref bind_interface) = svr_cfg.outbound_bind_interface { + connect_opts.bind_interface = Some(bind_interface.clone()); + } + ServerIdent { tcp_score: ServerScore::new(svr_cfg.config.weight().tcp_weight(), max_server_rtt, check_window), udp_score: ServerScore::new(svr_cfg.config.weight().udp_weight(), max_server_rtt, check_window), diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs index fd225cab56..ed19aa6ba5 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/net/tcp/auto_proxy_stream.rs @@ -10,7 +10,7 @@ use std::{ use pin_project::pin_project; use shadowsocks::{ - net::TcpStream, + net::{ConnectOpts, TcpStream}, relay::{socks5::Address, tcprelay::proxy_stream::ProxyClientStream}, }; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; @@ -37,19 +37,44 @@ impl AutoProxyClientStream { server: &ServerIdent, addr: A, ) -> io::Result + where + A: Into
, + { + AutoProxyClientStream::connect_with_opts(context.clone(), server, addr, context.connect_opts_ref()).await + } + + /// Connect to target `addr` via shadowsocks' server configured by `svr_cfg` + pub async fn connect_with_opts( + context: Arc, + server: &ServerIdent, + addr: A, + opts: &ConnectOpts, + ) -> io::Result where A: Into
, { let addr = addr.into(); if context.check_target_bypassed(&addr).await { - AutoProxyClientStream::connect_bypassed(context, addr).await + AutoProxyClientStream::connect_bypassed_with_opts(context, addr, opts).await } else { - AutoProxyClientStream::connect_proxied(context, server, addr).await + AutoProxyClientStream::connect_proxied_with_opts(context, server, addr, opts).await } } /// Connect directly to target `addr` pub async fn connect_bypassed(context: Arc, addr: A) -> io::Result + where + A: Into
, + { + AutoProxyClientStream::connect_bypassed_with_opts(context.clone(), addr, context.connect_opts_ref()).await + } + + /// Connect directly to target `addr` + pub async fn connect_bypassed_with_opts( + context: Arc, + addr: A, + connect_opts: &ConnectOpts, + ) -> io::Result where A: Into
, { @@ -61,7 +86,7 @@ impl AutoProxyClientStream { addr = mapped_addr; } let stream = - TcpStream::connect_remote_with_opts(context.context_ref(), &addr, context.connect_opts_ref()).await?; + TcpStream::connect_remote_with_opts(context.context_ref(), &addr, connect_opts).await?; Ok(AutoProxyClientStream::Bypassed(stream)) } @@ -71,6 +96,25 @@ impl AutoProxyClientStream { server: &ServerIdent, addr: A, ) -> io::Result + where + A: Into
, + { + AutoProxyClientStream::connect_proxied_with_opts( + context.clone(), + server, + addr, + context.connect_opts_ref() + ) + .await + } + + /// Connect to target `addr` via shadowsocks' server configured by `svr_cfg` + pub async fn connect_proxied_with_opts( + context: Arc, + server: &ServerIdent, + addr: A, + connect_opts: &ConnectOpts, + ) -> io::Result where A: Into
, { @@ -85,7 +129,7 @@ impl AutoProxyClientStream { context.context(), server.server_config(), addr, - context.connect_opts_ref(), + connect_opts, |stream| MonProxyStream::from_stream(stream, flow_stat), ) .await diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/net/udp/association.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/net/udp/association.rs index 49b99671fd..13e066097e 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/net/udp/association.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/net/udp/association.rs @@ -572,7 +572,7 @@ where let svr_cfg = server.server_config(); let socket = - ProxySocket::connect_with_opts(self.context.context(), svr_cfg, self.context.connect_opts_ref()) + ProxySocket::connect_with_opts(self.context.context(), svr_cfg, server.connect_opts_ref()) .await?; let socket = MonProxySocket::from_socket(socket, self.context.flow_stat()); diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs index f4b928c50a..b416319c8c 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/redir/tcprelay/mod.rs @@ -47,7 +47,7 @@ async fn establish_client_tcp_redir<'a>( let server = balancer.best_tcp_server(); let svr_cfg = server.server_config(); - let mut remote = AutoProxyClientStream::connect(context, &server, addr).await?; + let mut remote = AutoProxyClientStream::connect_with_opts(context, &server, addr, server.connect_opts_ref()).await?; establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, addr).await } diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks4/tcprelay.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks4/tcprelay.rs index 7a8c973fcf..fa502d5466 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks4/tcprelay.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks4/tcprelay.rs @@ -102,7 +102,13 @@ impl Socks4TcpHandler { } else { let server = self.balancer.best_tcp_server(); - let r = AutoProxyClientStream::connect(self.context, &server, &target_addr).await; + let r = AutoProxyClientStream::connect_with_opts( + self.context, + &server, + &target_addr, + server.connect_opts_ref() + ) + .await; server_opt = Some(server); r diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks5/tcprelay.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks5/tcprelay.rs index cd24b1bb6b..eff5af3c46 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks5/tcprelay.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/socks/server/socks5/tcprelay.rs @@ -254,7 +254,13 @@ impl Socks5TcpHandler { } else { let server = self.balancer.best_tcp_server(); - let r = AutoProxyClientStream::connect(self.context.clone(), &server, &target_addr).await; + let r = AutoProxyClientStream::connect_with_opts( + self.context, + &server, + &target_addr, + server.connect_opts_ref() + ) + .await; server_opt = Some(server); r diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/tun/tcp.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/tun/tcp.rs index fa376b185a..857271476e 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/tun/tcp.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/tun/tcp.rs @@ -576,7 +576,7 @@ async fn establish_client_tcp_redir<'a>( let server = balancer.best_tcp_server(); let svr_cfg = server.server_config(); - let mut remote = AutoProxyClientStream::connect(context, &server, addr).await?; + let mut remote = AutoProxyClientStream::connect_with_opts(context, &server, addr, server.connect_opts_ref()).await?; establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, addr).await } diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs b/shadowsocks-rust/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs index d4f2f91b30..1ccf55a3cc 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/local/tunnel/tcprelay.rs @@ -138,6 +138,12 @@ async fn handle_tcp_client( svr_cfg.addr(), ); - let mut remote = AutoProxyClientStream::connect_proxied(context, &server, forward_addr).await?; + let mut remote = AutoProxyClientStream::connect_proxied_with_opts( + context, + &server, + forward_addr, + server.connect_opts_ref() + ) + .await?; establish_tcp_tunnel(svr_cfg, &mut stream, &mut remote, peer_addr, forward_addr).await } diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/manager/server.rs b/shadowsocks-rust/crates/shadowsocks-service/src/manager/server.rs index acce92e9df..f5db629dad 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/manager/server.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/manager/server.rs @@ -410,6 +410,8 @@ impl Manager { acl: None, // Set with --acl command line argument #[cfg(any(target_os = "linux", target_os = "android"))] outbound_fwmark: None, + outbound_bind_addr: None, + outbound_bind_interface: None, }; let mut config = Config::new(ConfigType::Server); diff --git a/shadowsocks-rust/crates/shadowsocks-service/src/server/mod.rs b/shadowsocks-rust/crates/shadowsocks-service/src/server/mod.rs index 34f26c718e..bb4c6b47b4 100644 --- a/shadowsocks-rust/crates/shadowsocks-service/src/server/mod.rs +++ b/shadowsocks-rust/crates/shadowsocks-service/src/server/mod.rs @@ -116,6 +116,14 @@ pub async fn run(config: Config) -> io::Result<()> { connect_opts.fwmark = Some(fwmark); } + if let Some(bind_local_addr) = inst.outbound_bind_addr { + connect_opts.bind_local_addr = Some(bind_local_addr); + } + + if let Some(bind_interface) = inst.outbound_bind_interface { + connect_opts.bind_interface = Some(bind_interface); + } + server_builder.set_connect_opts(connect_opts.clone()); server_builder.set_accept_opts(accept_opts.clone()); diff --git a/small/v2ray-geodata/Makefile b/small/v2ray-geodata/Makefile index f84d46eacd..8d4dd63bc3 100644 --- a/small/v2ray-geodata/Makefile +++ b/small/v2ray-geodata/Makefile @@ -12,13 +12,13 @@ PKG_MAINTAINER:=Tianling Shen include $(INCLUDE_DIR)/package.mk -GEOIP_VER:=202404110039 +GEOIP_VER:=202404180039 GEOIP_FILE:=geoip.dat.$(GEOIP_VER) define Download/geoip URL:=https://github.com/v2fly/geoip/releases/download/$(GEOIP_VER)/ URL_FILE:=geoip.dat FILE:=$(GEOIP_FILE) - HASH:=d4a2e3666139dc98b76f1b0bc7db6b9dd9b35a5d2b0aecb5943e4211c1ebd026 + HASH:=a0ba7f1aa6fc85c20d6e17c4696cee28bc45784cf2b04c2891f8b6f2eb653d9a endef GEOSITE_VER:=20240416175239 diff --git a/suyu/.forgejo/workflows/codespell.yml b/suyu/.forgejo/workflows/codespell.yml index d711137d3a..951e1583ef 100644 --- a/suyu/.forgejo/workflows/codespell.yml +++ b/suyu/.forgejo/workflows/codespell.yml @@ -20,7 +20,7 @@ permissions: {} jobs: codespell: name: Check for spelling errors - runs-on: verify + runs-on: docker steps: - uses: https://code.forgejo.org/actions/checkout@v3 with: diff --git a/suyu/.forgejo/workflows/reuse.yml b/suyu/.forgejo/workflows/reuse.yml index 39bbbdf2c6..ba2fe448b5 100644 --- a/suyu/.forgejo/workflows/reuse.yml +++ b/suyu/.forgejo/workflows/reuse.yml @@ -30,7 +30,7 @@ jobs: reuse: name: Check REUSE Specification - runs-on: verify + runs-on: docker if: ${{ github.repository == 'suyu/suyu' }} steps: - uses: https://code.forgejo.org/actions/checkout@v3 diff --git a/suyu/.forgejo/workflows/verify.yml b/suyu/.forgejo/workflows/verify.yml index 1292ddcfa9..c858448468 100644 --- a/suyu/.forgejo/workflows/verify.yml +++ b/suyu/.forgejo/workflows/verify.yml @@ -38,7 +38,7 @@ env: jobs: format: name: 'Verify Format' - runs-on: ubuntu-latest + runs-on: docker container: fijxu/build-environments:linux-clang-format steps: - uses: https://code.forgejo.org/actions/checkout@v3 @@ -54,7 +54,7 @@ jobs: build-linux: name: 'test build' needs: format - runs-on: ubuntu-latest + runs-on: docker strategy: fail-fast: false matrix: @@ -175,7 +175,7 @@ jobs: # name: ${{ env.INDIVIDUAL_EXE }} # path: ${{ env.INDIVIDUAL_EXE }} android: - runs-on: ubuntu-latest + runs-on: docker container: fijxu/build-environments:android needs: format steps: diff --git a/suyu/README.md b/suyu/README.md index 8b9c5880c9..54274fa083 100644 --- a/suyu/README.md +++ b/suyu/README.md @@ -21,9 +21,10 @@ Support the original suyu developer team [here](https://discord.gg/ajz5hdrZ)
-

suyu was the continuation of the world's most popular, open-source, Nintendo Switch emulator, yuzu. +

suyu was the continuation of the world's most popular, open-source Nintendo Switch emulator, yuzu, but is now something more.
-It is written in C++ (C# possibly required soon) with portability in mind, and we're actively working on builds for Windows, Linux and Android along with a custom OS called [suyuos](https://git.suyu.dev/suyu/suyu-os). +It is written in C++ (C# possibly required soon) with portability in mind, we actively work on builds for Windows, Linux, Android and hopefully IOS, along with a WIP custom OS called suyuOS (https://git.suyu.dev/suyu/suyu-os) . +

@@ -61,6 +62,7 @@ You can also contact any of the developers on Discord to learn more about the cu * __Linux__: [Releases](https://git.suyu.dev/suyu/suyu/releases) * __macOS__: [Releases](https://git.suyu.dev/suyu/suyu/releases) * __Android__: [Releases](https://git.suyu.dev/suyu/suyu/releases) +* __For IOS users, we recommend Sudachi__: [Releases](https://github.com/emuPlace/Sudachi/releases) If you want daily builds then [Click here](https://git.suyu.dev/suyu/suyu/actions) If you don't know how to download the daily builds then [Click here](https://git.suyu.dev/suyu/suyu/raw/branch/dev/img/daily-builds.png) diff --git a/suyu/src/core/hle/kernel/k_page_table_base.cpp b/suyu/src/core/hle/kernel/k_page_table_base.cpp index 7714717f74..e67105dea4 100644 --- a/suyu/src/core/hle/kernel/k_page_table_base.cpp +++ b/suyu/src/core/hle/kernel/k_page_table_base.cpp @@ -172,6 +172,7 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start m_mapped_unsafe_physical_memory = 0; m_mapped_insecure_memory = 0; m_mapped_ipc_server_memory = 0; + m_alias_region_extra_size = 0; m_memory_block_slab_manager = m_kernel.GetSystemSystemResource().GetMemoryBlockSlabManagerPointer(); @@ -269,6 +270,12 @@ Result KPageTableBase::InitializeForProcess(Svc::CreateProcessFlag as_type, bool process_code_end = m_code_region_end; } + m_alias_region_extra_size = 0; + if (as_type == Svc::CreateProcessFlag::EnableReservedRegionExtraSize) { + m_alias_region_extra_size = GetAddressSpaceSize() / 8; + alias_region_size += m_alias_region_extra_size; + } + // Set other basic fields. m_enable_aslr = enable_aslr; m_enable_device_address_space_merge = enable_das_merge; diff --git a/suyu/src/core/hle/kernel/k_page_table_base.h b/suyu/src/core/hle/kernel/k_page_table_base.h index 37c745d14a..d944306b70 100644 --- a/suyu/src/core/hle/kernel/k_page_table_base.h +++ b/suyu/src/core/hle/kernel/k_page_table_base.h @@ -208,6 +208,7 @@ private: size_t m_mapped_unsafe_physical_memory{}; size_t m_mapped_insecure_memory{}; size_t m_mapped_ipc_server_memory{}; + size_t m_alias_region_extra_size{}; mutable KLightLock m_general_lock; mutable KLightLock m_map_physical_memory_lock; KLightLock m_device_map_lock; @@ -682,6 +683,9 @@ public: size_t GetAliasRegionSize() const { return m_alias_region_end - m_alias_region_start; } + size_t GetReservedRegionExtraSize() const { + return m_alias_region_extra_size; + } size_t GetStackRegionSize() const { return m_stack_region_end - m_stack_region_start; } diff --git a/suyu/src/core/hle/kernel/k_process_page_table.h b/suyu/src/core/hle/kernel/k_process_page_table.h index 346d7ca083..38c5fb8162 100644 --- a/suyu/src/core/hle/kernel/k_process_page_table.h +++ b/suyu/src/core/hle/kernel/k_process_page_table.h @@ -410,6 +410,9 @@ public: size_t GetAliasRegionSize() const { return m_page_table.GetAliasRegionSize(); } + size_t GetReservedRegionExtraSize() const { + return m_page_table.GetReservedRegionExtraSize(); + } size_t GetStackRegionSize() const { return m_page_table.GetStackRegionSize(); } diff --git a/suyu/src/core/hle/kernel/svc/svc_info.cpp b/suyu/src/core/hle/kernel/svc/svc_info.cpp index 231e4d0e1b..007bb9f705 100644 --- a/suyu/src/core/hle/kernel/svc/svc_info.cpp +++ b/suyu/src/core/hle/kernel/svc/svc_info.cpp @@ -37,7 +37,8 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle case InfoType::TotalNonSystemMemorySize: case InfoType::UsedNonSystemMemorySize: case InfoType::IsApplication: - case InfoType::FreeThreadCount: { + case InfoType::FreeThreadCount: + case InfoType::ReservedRegionExtraSize: { R_UNLESS(info_sub_id == 0, ResultInvalidEnumValue); const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable(); @@ -134,6 +135,10 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle } R_SUCCEED(); + case InfoType::ReservedRegionExtraSize: + *result = process->GetPageTable().GetReservedRegionExtraSize(); + R_SUCCEED(); + default: break; } diff --git a/suyu/src/core/hle/kernel/svc_types.h b/suyu/src/core/hle/kernel/svc_types.h index ab432ea78b..df92fa0089 100644 --- a/suyu/src/core/hle/kernel/svc_types.h +++ b/suyu/src/core/hle/kernel/svc_types.h @@ -153,6 +153,7 @@ enum class InfoType : u32 { ThreadTickCount = 25, IsSvcPermitted = 26, IoRegionHint = 27, + ReservedRegionExtraSize = 28, MesosphereMeta = 65000, MesosphereCurrentProcess = 65001, @@ -642,9 +643,12 @@ enum class CreateProcessFlag : u32 { // 11.x+ DisableDeviceAddressSpaceMerge. DisableDeviceAddressSpaceMerge = (1 << 12), + EnableReservedRegionExtraSize = (1 << 13), + // Mask of all flags. All = Is64Bit | AddressSpaceMask | EnableDebug | EnableAslr | IsApplication | - PoolPartitionMask | OptimizeMemoryAllocation | DisableDeviceAddressSpaceMerge, + PoolPartitionMask | OptimizeMemoryAllocation | DisableDeviceAddressSpaceMerge | + EnableReservedRegionExtraSize, }; DECLARE_ENUM_FLAG_OPERATORS(CreateProcessFlag); diff --git a/suyu/src/core/hle/service/acc/acc.cpp b/suyu/src/core/hle/service/acc/acc.cpp index d0771996b7..fd7104dfee 100644 --- a/suyu/src/core/hle/service/acc/acc.cpp +++ b/suyu/src/core/hle/service/acc/acc.cpp @@ -323,7 +323,7 @@ public: {11, &IProfileCommon::LoadImage, "LoadImage"}, {20, &IProfileCommon::GetImageSize, "GetLargeImageSize"}, // 18.0.0+ {21, &IProfileCommon::LoadImage, "LoadLargeImage"}, // 18.0.0+ - {30, nullptr, "GetImageId"}, // 18.0.0+ + {30, &IProfileCommon::Unknown, "GetImageId"}, // 18.0.0+ }; RegisterHandlers(functions); @@ -494,6 +494,13 @@ protected: rb.Push(ResultSuccess); } + void Unknown(HLERequestContext& ctx) { + LOG_WARNING(Service_ACC, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(0); + } + ProfileManager& profile_manager; Common::UUID user_id{}; ///< The user id this profile refers to. }; @@ -509,7 +516,15 @@ class IProfileEditor final : public IProfileCommon { public: explicit IProfileEditor(Core::System& system_, Common::UUID user_id_, ProfileManager& profile_manager_) - : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} {} + : IProfileCommon{system_, "IProfileEditor", true, user_id_, profile_manager_} { + // clang-format off + static const FunctionInfo functions[] = { + {30, &IProfileEditor::Unknown, "Unknown"}, + }; + // clang-format on + + RegisterHandlers(functions); + } }; class ISessionObject final : public ServiceFramework { diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt index 715d319379..e20eb12e56 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainActivity.kt @@ -329,6 +329,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList MmkvManager.removeAllServer() mainViewModel.reloadServerList() } + .setNegativeButton(android.R.string.no) {_, _ -> + //do noting + } .show() true } @@ -337,6 +340,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList .setPositiveButton(android.R.string.ok) { _, _ -> mainViewModel.removeDuplicateServer() } + .setNegativeButton(android.R.string.no) {_, _ -> + //do noting + } .show() true } @@ -346,6 +352,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList MmkvManager.removeInvalidServer() mainViewModel.reloadServerList() } + .setNegativeButton(android.R.string.no) {_, _ -> + //do noting + } .show() true } diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt index 12278e3935..8ad9fe860c 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt @@ -11,6 +11,7 @@ import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import com.google.gson.Gson import com.tencent.mmkv.MMKV +import com.v2ray.ang.AngApplication.Companion.application import com.v2ray.ang.AppConfig import com.v2ray.ang.R import com.v2ray.ang.databinding.ItemQrcodeBinding @@ -144,10 +145,15 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter removeServer(guid, position) } + .setNegativeButton(android.R.string.no) {_, _ -> + //do noting + } .show() } else { removeServer(guid, position) } + } else { + application.toast(R.string.toast_action_not_allowed) } } diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt index 3622332b16..6fffabd0f0 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerActivity.kt @@ -8,6 +8,7 @@ import android.view.View import android.widget.* import androidx.appcompat.app.AlertDialog import com.tencent.mmkv.MMKV +import com.v2ray.ang.AngApplication import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig.PREF_ALLOW_INSECURE import com.v2ray.ang.AppConfig.WIREGUARD_LOCAL_ADDRESS_V4 @@ -209,7 +210,7 @@ class ServerActivity : BaseActivity() { } /** - * bingding seleced server config + * binding selected server config */ private fun bindingServer(config: ServerConfig): Boolean { val outbound = config.getProxyOutbound() ?: return false @@ -560,11 +561,16 @@ class ServerActivity : BaseActivity() { MmkvManager.removeServer(editGuid) finish() } + .setNegativeButton(android.R.string.no) { _, _ -> + // do nothing + } .show() } else { MmkvManager.removeServer(editGuid) finish() } + } else { + application.toast(R.string.toast_action_not_allowed) } } return true diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt index f76fa4ca23..5fdb57f1ff 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt @@ -111,6 +111,9 @@ class ServerCustomConfigActivity : BaseActivity() { MmkvManager.removeServer(editGuid) finish() } + .setNegativeButton(android.R.string.no) {_, _ -> + // do nothing + } .show() } return true diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt index 180b120047..210375575b 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SubEditActivity.kt @@ -111,6 +111,9 @@ class SubEditActivity : BaseActivity() { MmkvManager.removeSubscription(editSubId) finish() } + .setNegativeButton(android.R.string.no) {_, _ -> + // do nothing + } .show() } return true diff --git a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetUrlActivity.kt b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetUrlActivity.kt index c032bef3ff..48404d3104 100644 --- a/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetUrlActivity.kt +++ b/v2rayng/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/UserAssetUrlActivity.kt @@ -114,6 +114,9 @@ class UserAssetUrlActivity : BaseActivity() { MmkvManager.removeAssetUrl(editAssetId) finish() } + .setNegativeButton(android.R.string.no) {_, _ -> + // do nothing + } .show() } return true diff --git a/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml index fbdcd75d89..5a1ef352c8 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-ar/strings.xml @@ -78,6 +78,7 @@ فشل نسخ الملف، يرجى استخدام مدير الملفات إضافة ملفات تحميل الملفات + هذا الإجراء محظور أضف عنوان URL للأصل لم يتم العثور على الملف diff --git a/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml index f87d54953a..cb9edb67b7 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-fa/strings.xml @@ -80,6 +80,7 @@ کپی فایل انجام نشد، لطفا از برنامه مدیریت فایل استفاده کنید افزودن فایل‌ها دانلود فایل‌ها + این عمل ممنوع است URL را اضافه کنید diff --git a/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml index 71d146d08e..21458bd2cc 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -85,6 +85,7 @@ Добавить URL ресурса Файл не найден Описание уже существует + Это действие запрещено Загрузка… diff --git a/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml index 1d8743c8d6..047aef2b12 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-vi/strings.xml @@ -80,6 +80,7 @@ Không thể sao chép tệp tin, hãy dùng trình quản lý tệp! Thêm tệp Tải xuống tệp tin + Hành động này bị cấm Thêm URL nội dung diff --git a/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index 46e6f71ce3..a40135eaca 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -80,6 +80,7 @@ 失败, 请使用文件管理器 添加文件 下载文件 + 禁止此项操作 diff --git a/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index 2e32c5ed1f..5ac04f3eab 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -80,6 +80,7 @@ 失敗,請使用檔案總管 新增檔案 下載檔案 + 禁止此項操作 新增資產網址 diff --git a/v2rayng/V2rayNG/app/src/main/res/values/strings.xml b/v2rayng/V2rayNG/app/src/main/res/values/strings.xml index d20fedd4b0..a15db1c2ee 100644 --- a/v2rayng/V2rayNG/app/src/main/res/values/strings.xml +++ b/v2rayng/V2rayNG/app/src/main/res/values/strings.xml @@ -93,6 +93,7 @@ Add asset URL File not found The remarks already exists + Action not allowed diff --git a/xray-core/app/router/config.pb.go b/xray-core/app/router/config.pb.go index 23aba91138..d0da6d1414 100644 --- a/xray-core/app/router/config.pb.go +++ b/xray-core/app/router/config.pb.go @@ -864,7 +864,7 @@ type StrategyLeastLoadConfig struct { Baselines []int64 `protobuf:"varint,3,rep,packed,name=baselines,proto3" json:"baselines,omitempty"` // expected nodes count to select Expected int32 `protobuf:"varint,4,opt,name=expected,proto3" json:"expected,omitempty"` - // max acceptable rtt, filter away high delay nodes. defalut 0 + // max acceptable rtt, filter away high delay nodes. default 0 MaxRTT int64 `protobuf:"varint,5,opt,name=maxRTT,proto3" json:"maxRTT,omitempty"` // acceptable failure rate Tolerance float32 `protobuf:"fixed32,6,opt,name=tolerance,proto3" json:"tolerance,omitempty"` diff --git a/xray-core/app/router/config.proto b/xray-core/app/router/config.proto index cff00fade4..fdd2e61d7f 100644 --- a/xray-core/app/router/config.proto +++ b/xray-core/app/router/config.proto @@ -147,7 +147,7 @@ message StrategyLeastLoadConfig { repeated int64 baselines = 3; // expected nodes count to select int32 expected = 4; - // max acceptable rtt, filter away high delay nodes. defalut 0 + // max acceptable rtt, filter away high delay nodes. default 0 int64 maxRTT = 5; // acceptable failure rate float tolerance = 6; diff --git a/xray-core/go.mod b/xray-core/go.mod index 7f6b58fb7e..e400e8f362 100644 --- a/xray-core/go.mod +++ b/xray-core/go.mod @@ -3,11 +3,13 @@ module github.com/xtls/xray-core go 1.22 require ( + github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 + github.com/cloudflare/circl v1.3.7 github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 github.com/golang/mock v1.7.0-rc.1 github.com/google/go-cmp v0.6.0 github.com/gorilla/websocket v1.5.1 - github.com/miekg/dns v1.1.58 + github.com/miekg/dns v1.1.59 github.com/pelletier/go-toml v1.9.5 github.com/pires/go-proxyproto v0.7.0 github.com/quic-go/quic-go v0.42.0 @@ -30,12 +32,10 @@ require ( gvisor.dev/gvisor v0.0.0-20231104011432-48a6d7d5bd0b h12.io/socks v1.0.3 lukechampine.com/blake3 v1.2.2 - github.com/OmarTariq612/goech v0.0.0-20240405204721-8e2e1dafd3a0 ) require ( github.com/andybalholm/brotli v1.1.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-metro v0.0.0-20211217172704-adc40b04c140 // indirect github.com/francoispqt/gojay v1.2.13 // indirect diff --git a/xray-core/go.sum b/xray-core/go.sum index e3560abdb5..dc99982a5e 100644 --- a/xray-core/go.sum +++ b/xray-core/go.sum @@ -90,8 +90,8 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= +github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= +github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= diff --git a/xray-core/infra/conf/router_strategy.go b/xray-core/infra/conf/router_strategy.go index 58367b4a06..4d0f647adb 100644 --- a/xray-core/infra/conf/router_strategy.go +++ b/xray-core/infra/conf/router_strategy.go @@ -38,7 +38,7 @@ type strategyLeastLoadConfig struct { Baselines []duration.Duration `json:"baselines,omitempty"` // expected nodes count to select Expected int32 `json:"expected,omitempty"` - // max acceptable rtt, filter away high delay nodes. defalut 0 + // max acceptable rtt, filter away high delay nodes. default 0 MaxRTT duration.Duration `json:"maxRTT,omitempty"` // acceptable failure rate Tolerance float64 `json:"tolerance,omitempty"` diff --git a/xray-core/transport/internet/websocket/hub.go b/xray-core/transport/internet/websocket/hub.go index 8a860c30bf..60f0739001 100644 --- a/xray-core/transport/internet/websocket/hub.go +++ b/xray-core/transport/internet/websocket/hub.go @@ -39,10 +39,12 @@ var upgrader = &websocket.Upgrader{ func (h *requestHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { if len(h.host) > 0 && request.Host != h.host { + newError("failed to validate host, request:", request.Host, ", config:", h.host).WriteToLog() writer.WriteHeader(http.StatusNotFound) return } if request.URL.Path != h.path { + newError("failed to validate path, request:", request.URL.Path, ", config:", h.path).WriteToLog() writer.WriteHeader(http.StatusNotFound) return } diff --git a/yass/src/android/jni.cpp b/yass/src/android/jni.cpp index 2874e24980..3763407518 100644 --- a/yass/src/android/jni.cpp +++ b/yass/src/android/jni.cpp @@ -11,6 +11,8 @@ #include +using namespace std::string_literals; + JavaVM* g_jvm = nullptr; jobject g_activity_obj = nullptr; @@ -124,8 +126,8 @@ JNIEXPORT jobject JNICALL Java_it_gui_yass_MainActivity_saveConfig(JNIEnv* env, DCHECK_LT((uint32_t)_method_idx, methods_idxes.size()); auto method = methods_idxes[_method_idx]; - std::string local_host = "0.0.0.0"; - std::string local_port = "0"; + std::string local_host = "0.0.0.0"s; + std::string local_port = "0"s; const char* doh_url_str = env->GetStringUTFChars((jstring)_doh_url, nullptr); std::string doh_url = doh_url_str != nullptr ? doh_url_str : std::string(); diff --git a/yass/src/cli/cli_worker.cpp b/yass/src/cli/cli_worker.cpp index 776d8c5f05..f1eece0121 100644 --- a/yass/src/cli/cli_worker.cpp +++ b/yass/src/cli/cli_worker.cpp @@ -144,11 +144,11 @@ std::vector Worker::GetRemoteIpsV6() const { } std::string Worker::GetDomain() const { - return absl::StrCat(cached_local_host_, ":", std::to_string(cached_local_port_)); + return absl::StrCat(cached_local_host_, ":", cached_local_port_); } std::string Worker::GetRemoteDomain() const { - return absl::StrCat(cached_server_host_, ":", std::to_string(cached_server_port_)); + return absl::StrCat(cached_server_host_, ":", cached_server_port_); } int Worker::GetLocalPort() const { diff --git a/yass/src/config/config.cpp b/yass/src/config/config.cpp index df861a26c9..5c230636fc 100644 --- a/yass/src/config/config.cpp +++ b/yass/src/config/config.cpp @@ -37,7 +37,7 @@ std::string AbslUnparseFlag(const RateFlag&); bool AbslParseFlag(absl::string_view text, PortFlag* flag, std::string* err) { std::optional p = StringToIntegerU64(std::string(text)); if (!p.has_value() || p.value() > UINT16_MAX) { - *err = "bad port number: " + std::string(text); + *err = absl::StrCat("bad port number: ", text); return false; } flag->port = static_cast(p.value()); @@ -53,7 +53,7 @@ std::string AbslUnparseFlag(const PortFlag& flag) { bool AbslParseFlag(absl::string_view text, CipherMethodFlag* flag, std::string* err) { flag->method = to_cipher_method(std::string(text)); if (flag->method == CRYPTO_INVALID) { - *err = "bad cipher_method: " + std::string(text); + *err = absl::StrCat("bad cipher_method: ", text); return false; } return true; @@ -138,7 +138,7 @@ static int64_t ngx_parse_size(const char* line, size_t len) { bool AbslParseFlag(absl::string_view text, RateFlag* flag, std::string* err) { int64_t size = ngx_parse_size(text.data(), text.size()); if (size < 0) { - *err = "bad size: " + std::string(text); + *err = absl::StrCat("bad size: ", text); return false; } flag->rate = size; diff --git a/yass/src/config/config_test.cpp b/yass/src/config/config_test.cpp index 480a0796b9..d14634c504 100644 --- a/yass/src/config/config_test.cpp +++ b/yass/src/config/config_test.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include "config/config_impl.hpp" @@ -16,6 +17,8 @@ ABSL_FLAG(int64_t, test_signed_64val, 0, "Test int64_t value"); ABSL_FLAG(uint64_t, test_unsigned_64val, 0, "Test uint64_t value"); ABSL_FLAG(std::string, test_string, "", "Test string value"); +using namespace std::string_literals; + class ConfigTest : public ::testing::Test { public: void SetUp() override { @@ -24,7 +27,7 @@ class ConfigTest : public ::testing::Test { const char* tmpdir = getenv("TMPDIR"); if (!tmpdir || *tmpdir == '\0') tmpdir = "/tmp"; - std::string tmpdir_configfile = std::string(tmpdir) + "/" + "yass.json"; + std::string tmpdir_configfile = absl::StrCat(tmpdir, "/", "yass.json"); config::g_configfile = tmpdir_configfile; #endif } @@ -167,7 +170,7 @@ TEST_F(ConfigTest, RWUint64) { TEST_F(ConfigTest, RWString) { auto config_impl = config::ConfigImpl::Create(); - std::string test_string = "test-str"; + std::string test_string = "test-str"s; absl::SetFlag(&FLAGS_test_string, test_string); diff --git a/yass/src/core/logging.cpp b/yass/src/core/logging.cpp index df9c8f0cbb..8d1a62cb21 100644 --- a/yass/src/core/logging.cpp +++ b/yass/src/core/logging.cpp @@ -7,6 +7,7 @@ #endif #include #include +#include #include #include #include @@ -990,7 +991,7 @@ inline void LogDestination::MaybeLogToStderr(LogSeverity severity, // CF-1153.18/CFUtilities.c __CFLogCString(). CFBundleRef main_bundle = CFBundleGetMainBundle(); CFStringRef main_bundle_id_cf = main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr; - std::string main_bundle_id = main_bundle_id_cf ? SysCFStringRefToUTF8(main_bundle_id_cf) : std::string(""); + std::string main_bundle_id = main_bundle_id_cf ? SysCFStringRefToUTF8(main_bundle_id_cf) : std::string(); #if defined(USE_ASL) // The facility is set to the main bundle ID if available. Otherwise, // "com.apple.console" is used. @@ -1371,7 +1372,7 @@ bool LogFileObject::CreateLogfile(const std::string& time_pid_string) { if (!symlink_basename_.empty()) { // take directory from filename const char* slash = strrchr(filename, PATH_SEPARATOR); - const std::string linkname = symlink_basename_ + '.' + log_severity_name(severity_); + const std::string linkname = absl::StrCat(symlink_basename_, ".", log_severity_name(severity_)); std::string linkpath; // get dirname if (slash) diff --git a/yass/src/core/process_utils.cpp b/yass/src/core/process_utils.cpp index 519a117d1a..e064725996 100644 --- a/yass/src/core/process_utils.cpp +++ b/yass/src/core/process_utils.cpp @@ -3,6 +3,8 @@ #include "core/process_utils.hpp" +#include +#include #include #include "core/logging.hpp" @@ -27,6 +29,8 @@ #define ASIO_NO_SSL #include "net/asio.hpp" +using namespace std::string_literals; + static int Pipe2(int pipe_fds[2]) { int ret; #ifdef HAVE_PIPE2 @@ -154,12 +158,7 @@ int ExecuteProcess(const std::vector& params, std::string* output, DCHECK(!params.empty()) << "ExecuteProcess empty parameters"; output->clear(); error->clear(); - std::string command_line = "'"; - for (const auto& param : params) { - command_line += param; - command_line += " "; - } - command_line[command_line.size() - 1] = '\''; + std::string command_line = absl::StrCat("'", absl::StrJoin(params, " "), "'"); int ret; pid_t pid; diff --git a/yass/src/core/process_utils_test.cpp b/yass/src/core/process_utils_test.cpp index 4d95aef000..b44f2d8e05 100644 --- a/yass/src/core/process_utils_test.cpp +++ b/yass/src/core/process_utils_test.cpp @@ -21,6 +21,8 @@ ABSL_FLAG(bool, no_exec_proc_tests, true, "skip execute_process tests"); ABSL_FLAG(bool, no_exec_proc_tests, false, "skip execute_process tests"); #endif +using namespace std::string_literals; + TEST(PROCESS_TEST, ExecuteProcessBasic) { if (absl::GetFlag(FLAGS_no_exec_proc_tests)) { GTEST_SKIP() << "skipped as required"; @@ -28,7 +30,7 @@ TEST(PROCESS_TEST, ExecuteProcessBasic) { } std::string main_exe; GetExecutablePath(&main_exe); - std::vector params = {main_exe.c_str(), "--version"}; + std::vector params = {main_exe, "--version"s}; std::string output, error; int ret = ExecuteProcess(params, &output, &error); EXPECT_EQ(ret, 0); diff --git a/yass/src/core/utils.cpp b/yass/src/core/utils.cpp index 4f541bbfe0..7f4bd57288 100644 --- a/yass/src/core/utils.cpp +++ b/yass/src/core/utils.cpp @@ -44,6 +44,8 @@ std::string h_cache_dir; std::string h_data_dir; #endif +using namespace std::string_literals; + std::optional StringToInteger(const std::string& value) { int result; @@ -233,7 +235,7 @@ std::string ExpandUser(const std::string& file_path) { #if !defined(__APPLE__) && !defined(_WIN32) -static std::string main_exe_path = "UNKNOWN"; +static std::string main_exe_path = "UNKNOWN"s; bool GetExecutablePath(std::string* path) { char exe_path[PATH_MAX]; diff --git a/yass/src/core/utils_mac.mm b/yass/src/core/utils_mac.mm index 741672240e..19b365e18c 100644 --- a/yass/src/core/utils_mac.mm +++ b/yass/src/core/utils_mac.mm @@ -21,6 +21,8 @@ #include #include "core/logging.hpp" +using namespace std::string_literals; + bool SetCurrentThreadPriority(ThreadPriority priority) { // Changing the priority of the main thread causes performance regressions. // https://crbug.com/601270 @@ -78,7 +80,7 @@ bool SetUTF8Locale() { return true; } -static std::string main_exe_path = "UNKNOWN"; +static std::string main_exe_path = "UNKNOWN"s; bool GetExecutablePath(std::string* path) { char exe_path[PATH_MAX]; diff --git a/yass/src/core/utils_win.cpp b/yass/src/core/utils_win.cpp index a8ae7655da..6647b2c0a2 100644 --- a/yass/src/core/utils_win.cpp +++ b/yass/src/core/utils_win.cpp @@ -19,6 +19,8 @@ struct IUnknown; #include #include +using namespace std::string_literals; + #define MAKE_WIN_VER(major, minor, build_number) (((major) << 24) | ((minor) << 16) | (build_number)) #include "core/logging.hpp" @@ -468,7 +470,7 @@ bool IsWindowsVersionBNOrGreater(int wMajorVersion, int wMinorVersion, int wBuil MAKE_WIN_VER(wMajorVersion, wMinorVersion, wBuildNumber); } -static std::string main_exe_path = "UNKNOWN"; +static std::string main_exe_path = "UNKNOWN"s; bool GetExecutablePath(std::string* exe_path) { std::wstring wexe_path; diff --git a/yass/src/crashpad_helper.cpp b/yass/src/crashpad_helper.cpp index 518c4e9c8d..0f1a42c29b 100644 --- a/yass/src/crashpad_helper.cpp +++ b/yass/src/crashpad_helper.cpp @@ -13,6 +13,8 @@ #include "version.h" +using namespace std::string_literals; + #ifdef __ANDROID__ extern struct android_app* a_app; extern std::string a_data_dir; @@ -26,7 +28,7 @@ bool InitializeCrashpad(const std::string& exe_path) { base::FilePath reportsDir(tempDir / "crashpad"); // Configure url with BugSplat’s public fred database. Replace 'fred' with the name of your BugSplat database. - std::string url = "https://yass.bugsplat.com/post/bp/crash/crashpad.php"; + std::string url = "https://yass.bugsplat.com/post/bp/crash/crashpad.php"s; // Metadata that will be posted to the server with the crash report map std::map annotations; @@ -73,7 +75,7 @@ bool InitializeCrashpad(const std::string& exe_path) { base::FilePath metricsDir(tempDir / "crashpad"); // Configure url with BugSplat’s public fred database. Replace 'fred' with the name of your BugSplat database. - std::string url = "https://yass.bugsplat.com/post/bp/crash/crashpad.php"; + std::string url = "https://yass.bugsplat.com/post/bp/crash/crashpad.php"s; // Metadata that will be posted to the server with the crash report map std::map annotations; diff --git a/yass/src/crypto/decrypter.cpp b/yass/src/crypto/decrypter.cpp index a1555848c7..43b683abea 100644 --- a/yass/src/crypto/decrypter.cpp +++ b/yass/src/crypto/decrypter.cpp @@ -72,22 +72,4 @@ std::unique_ptr Decrypter::CreateFromCipherSuite(uint32_t cipher_suit } } -#if 0 -// static -void QuicDecrypter::DiversifyPreliminaryKey(QuicStringPiece preliminary_key, - QuicStringPiece nonce_prefix, - const DiversificationNonce& nonce, - size_t key_size, - size_t nonce_prefix_size, - std::string* out_key, - std::string* out_nonce_prefix) { - QuicHKDF hkdf((std::string(preliminary_key)) + (std::string(nonce_prefix)), - QuicStringPiece(nonce.data(), nonce.size()), - "QUIC key diversification", 0, key_size, 0, nonce_prefix_size, - 0); - *out_key = std::string(hkdf.server_write_key()); - *out_nonce_prefix = std::string(hkdf.server_write_iv()); -} -#endif - } // namespace crypto diff --git a/yass/src/gtk/utils_gtk.cpp b/yass/src/gtk/utils_gtk.cpp index 2fd7be9dd9..f84eedd8dd 100644 --- a/yass/src/gtk/utils_gtk.cpp +++ b/yass/src/gtk/utils_gtk.cpp @@ -27,6 +27,8 @@ #define G_SOURCE_FUNC(f) ((GSourceFunc)(void (*)(void))(f)) #endif +using namespace std::string_literals; + using namespace yass; static constexpr const char kDefaultAutoStartName[] = "it.gui.yass"; @@ -93,7 +95,7 @@ void Utils::EnableAutoStart(bool on) { } // write to target - std::string executable_path = "yass"; + std::string executable_path = "yass"s; GetExecutablePath(&executable_path); std::string desktop_entry = absl::StrFormat(kAutoStartFileContent, executable_path); if (!WriteFileWithBuffer(autostart_desktop_path, desktop_entry)) { @@ -105,7 +107,7 @@ void Utils::EnableAutoStart(bool on) { // Update Desktop Database std::string _; - std::vector params = {"update-desktop-database", ExpandUser("~/.local/share/applications")}; + std::vector params = {"update-desktop-database"s, ExpandUser("~/.local/share/applications"s)}; if (ExecuteProcess(params, &_, &_) != 0) { PLOG(WARNING) << "update-desktop-database failed"; } else { @@ -146,7 +148,7 @@ bool Utils::SetSystemProxy(bool on) { ret = ::SetSystemProxy_KDE(on, server_addr, bypass_addr); } bool enabled; - std::string server_host, server_port, bypass_addr = "['localhost', '127.0.0.0/8', '::1']"; + std::string server_host, server_port, bypass_addr = "['localhost', '127.0.0.0/8', '::1']"s; ::QuerySystemProxy(&enabled, &server_host, &server_port, &bypass_addr); if (on) { server_host = "'" + absl::GetFlag(FLAGS_local_host) + "'"; @@ -179,7 +181,7 @@ std::string Utils::GetLocalAddr() { bool QuerySystemProxy(bool* enabled, std::string* server_host, std::string* server_port, std::string* bypass_addr) { std::string output, _; - std::vector params = {"gsettings", "get", "org.gnome.system.proxy", "mode"}; + std::vector params = {"gsettings"s, "get"s, "org.gnome.system.proxy"s, "mode"s}; if (ExecuteProcess(params, &output, &_) != 0) { return false; } @@ -226,8 +228,8 @@ bool SetSystemProxy(bool enable, const std::string& server_port, const std::string& bypass_addr) { std::string _; - std::vector params = {"gsettings", "set", "org.gnome.system.proxy", "mode", - enable ? "'manual'" : "'none'"}; + std::vector params = {"gsettings"s, "set"s, "org.gnome.system.proxy"s, "mode"s, + enable ? "'manual'"s : "'none'"s}; if (ExecuteProcess(params, &_, &_) != 0) { return false; } @@ -309,9 +311,9 @@ bool QuerySystemProxy_KDE(bool* enabled, std::string* server_addr, std::string* bool SetSystemProxy_KDE(bool enable, const std::string& server_addr, const std::string& bypass_addr) { std::string config_dir = GetConfigDir(); std::string _; - std::vector params = {"kwriteconfig5", "--file", config_dir + "/kioslaverc", - "--group", "Proxy Settings", "--key", - "ProxyType", enable ? "1" : "0"}; + std::vector params = {"kwriteconfig5"s, "--file"s, config_dir + "/kioslaverc"s, + "--group"s, "Proxy Settings"s, "--key"s, + "ProxyType"s, enable ? "1"s : "0"s}; if (ExecuteProcess(params, &_, &_) != 0) { return false; } diff --git a/yass/src/gtk/yass.cpp b/yass/src/gtk/yass.cpp index f30c30dc87..693a1c1f0e 100644 --- a/yass/src/gtk/yass.cpp +++ b/yass/src/gtk/yass.cpp @@ -27,6 +27,8 @@ ABSL_FLAG(bool, background, false, "start up backgroundd"); +using namespace std::string_literals; + YASSApp* mApp = nullptr; static const char* kAppId = "it.gui.yass"; @@ -42,7 +44,7 @@ int main(int argc, const char** argv) { if (!SetUTF8Locale()) { LOG(WARNING) << "Failed to set up utf-8 locale"; } - std::string locale_path = "../share/locale"; + std::string locale_path = "../share/locale"s; size_t rpos = exec_path.rfind('/'); if (rpos != std::string::npos) locale_path = exec_path.substr(0, rpos + 1) + locale_path; diff --git a/yass/src/gtk4/yass.cpp b/yass/src/gtk4/yass.cpp index 22eeeaa659..3b1b33a91c 100644 --- a/yass/src/gtk4/yass.cpp +++ b/yass/src/gtk4/yass.cpp @@ -28,6 +28,8 @@ ABSL_FLAG(bool, background, false, "start up backgroundd"); +using namespace std::string_literals; + YASSApp* mApp = nullptr; static const char* kAppId = "it.gui.yass"; @@ -93,7 +95,7 @@ int main(int argc, const char** argv) { if (!SetUTF8Locale()) { LOG(WARNING) << "Failed to set up utf-8 locale"; } - std::string locale_path = "../share/locale"; + std::string locale_path = "../share/locale"s; size_t rpos = exec_path.rfind('/'); if (rpos != std::string::npos) locale_path = exec_path.substr(0, rpos + 1) + locale_path; diff --git a/yass/src/harmony/yass.cpp b/yass/src/harmony/yass.cpp index 1e794fd999..30bf63374e 100644 --- a/yass/src/harmony/yass.cpp +++ b/yass/src/harmony/yass.cpp @@ -30,6 +30,8 @@ typedef enum { extern "C" bool OH_LOG_IsLoggable(unsigned int domain, const char* tag, HILOG_LogLevel level); +using namespace std::string_literals; + static constexpr const char kLogTag[] = YASS_APP_NAME; static constexpr const unsigned int kLogDomain = 0x0; @@ -883,8 +885,8 @@ static napi_value saveConfig(napi_env env, napi_callback_info info) { std::string dot_host = argList[7]; std::string timeout = argList[8]; - std::string local_host = "0.0.0.0"; - std::string local_port = "0"; + std::string local_host = "0.0.0.0"s; + std::string local_port = "0"s; std::string err_msg = config::ReadConfigFromArgument(server_host, server_sni, server_port, username, password, method, local_host, local_port, doh_url, dot_host, timeout); diff --git a/yass/src/ios/extensions/YassPacketTunnelProvider.mm b/yass/src/ios/extensions/YassPacketTunnelProvider.mm index 760d5ba0b5..64bdf1830e 100644 --- a/yass/src/ios/extensions/YassPacketTunnelProvider.mm +++ b/yass/src/ios/extensions/YassPacketTunnelProvider.mm @@ -15,6 +15,8 @@ #include "ios/utils.h" #include "tun2proxy.h" +using namespace std::string_literals; + static constexpr const int DEFAULT_MTU = 1500; static const char PRIVATE_VLAN4_CLIENT[] = "172.19.0.1"; static const char PRIVATE_VLAN4_GATEWAY[] = "172.19.0.2"; @@ -44,8 +46,8 @@ static constexpr const uint32_t kYieldConcurrencyOfConnections = 12u; auto server_port = SysNSStringToUTF8(dict[@(kServerPortFieldName)]); auto username = SysNSStringToUTF8(dict[@(kUsernameFieldName)]); auto password = SysNSStringToUTF8(dict[@(kPasswordFieldName)]); - auto local_host = std::string("127.0.0.1"); - auto local_port = std::string("0"); + auto local_host = "127.0.0.1"s; + auto local_port = "0"s; auto method_string = SysNSStringToUTF8(dict[@(kMethodStringFieldName)]); auto doh_url = SysNSStringToUTF8(dict[@(kDoHURLFieldName)]); auto dot_host = SysNSStringToUTF8(dict[@(kDoTHostFieldName)]); diff --git a/yass/src/mac/utils_mac.mm b/yass/src/mac/utils_mac.mm index 4b7ff15013..473bc2acd5 100644 --- a/yass/src/mac/utils_mac.mm +++ b/yass/src/mac/utils_mac.mm @@ -29,6 +29,8 @@ #include #include +using namespace std::string_literals; + using namespace gurl_base::apple; namespace { @@ -525,7 +527,7 @@ bool QuerySystemProxy(bool* enabled, std::string* server_addr, int32_t* server_p bool SetSystemProxy(bool enable, const std::string& server_addr, int32_t server_port, const std::string& bypass_addr) { std::string output, _; - std::vector params = {"/usr/sbin/networksetup", "-listallnetworkservices"}; + std::vector params = {"/usr/sbin/networksetup"s, "-listallnetworkservices"s}; if (ExecuteProcess(params, &output, &_) != 0) { return false; } diff --git a/yass/src/net/asio_ssl.cpp b/yass/src/net/asio_ssl.cpp index 55ef37472d..4bdcedadab 100644 --- a/yass/src/net/asio_ssl.cpp +++ b/yass/src/net/asio_ssl.cpp @@ -9,6 +9,7 @@ #include #endif +#include #include #include #include @@ -398,7 +399,7 @@ static int load_ca_to_ssl_ctx_path(SSL_CTX* ssl_ctx, const std::string& dir_path if (dent->d_type != DT_REG && dent->d_type != DT_LNK) { continue; } - std::string ca_bundle = dir_path + "/" + dent->d_name; + std::string ca_bundle = absl::StrCat(dir_path, "/", dent->d_name); int result = load_ca_to_ssl_ctx_bundle(ssl_ctx, ca_bundle); if (result > 0) { VLOG(1) << "Loaded ca cert from: " << ca_bundle << " with " << result << " certificates"; diff --git a/yass/src/net/content_server.hpp b/yass/src/net/content_server.hpp index f300f6578a..0b70d6f699 100644 --- a/yass/src/net/content_server.hpp +++ b/yass/src/net/content_server.hpp @@ -28,6 +28,8 @@ namespace net { +using std::string_literals::operator""s; + /// An interface used to provide service template class ContentServer { @@ -374,7 +376,7 @@ class ContentServer { // Use BoringSSL defaults, but disable 3DES and HMAC-SHA1 ciphers in ECDSA. // These are the remaining CBC-mode ECDSA ciphers. - std::string command("ALL:!aPSK:!ECDSA+SHA1:!3DES"); + std::string command("ALL:!aPSK:!ECDSA+SHA1:!3DES"s); #if 0 // SSLPrivateKey only supports ECDHE-based ciphers because it lacks decrypt. diff --git a/yass/src/net/ssl_socket.cpp b/yass/src/net/ssl_socket.cpp index 7a9abb339b..219a457f9b 100644 --- a/yass/src/net/ssl_socket.cpp +++ b/yass/src/net/ssl_socket.cpp @@ -6,6 +6,8 @@ #include +using namespace std::string_literals; + namespace net { namespace { @@ -76,7 +78,7 @@ SSLSocket::SSLSocket(int ssl_socket_data_index, SSL_set_mode(ssl_.get(), mode.set_mask); SSL_clear_mode(ssl_.get(), mode.clear_mask); - std::string command("ALL:!aPSK:!ECDSA+SHA1:!3DES"); + std::string command("ALL:!aPSK:!ECDSA+SHA1:!3DES"s); #if 0 if (ssl_config_.require_ecdhe) { diff --git a/yass/src/net/stream.hpp b/yass/src/net/stream.hpp index 0622fefbfa..041fe046ce 100644 --- a/yass/src/net/stream.hpp +++ b/yass/src/net/stream.hpp @@ -148,7 +148,7 @@ class stream : public RefCountedThreadSafe { }); } - std::string domain() { return absl::StrCat(host_sni_, ":", std::to_string(port_)); } + std::string domain() { return absl::StrCat(host_sni_, ":", port_); } bool connected() const { return connected_; } diff --git a/yass/src/ss_test.cpp b/yass/src/ss_test.cpp index ae01d62b24..e7b362ff11 100644 --- a/yass/src/ss_test.cpp +++ b/yass/src/ss_test.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "third_party/boringssl/src/include/openssl/crypto.h" @@ -394,7 +395,7 @@ class EndToEndTest : public ::testing::TestWithParam { curl = curl_easy_init(); ASSERT_TRUE(curl) << "curl initial failure"; - std::string url = "http://localhost:" + std::to_string(content_provider_endpoint_.port()); + std::string url = absl::StrCat("http://localhost:", content_provider_endpoint_.port()); // TODO A bug inside curl that it doesn't respect IPRESOLVE_V6 // https://github.com/curl/curl/issues/11465 if (absl::GetFlag(FLAGS_proxy_type) == "socks5") { @@ -411,7 +412,7 @@ class EndToEndTest : public ::testing::TestWithParam { const long ip_version = absl::GetFlag(FLAGS_ipv6_mode) ? CURL_IPRESOLVE_V6 : CURL_IPRESOLVE_V4; curl_easy_setopt(curl, CURLOPT_IPRESOLVE, ip_version); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - std::string proxy_url = "localhost:" + std::to_string(local_endpoint_.port()); + std::string proxy_url = absl::StrCat("localhost:", local_endpoint_.port()); curl_easy_setopt(curl, CURLOPT_PROXY, proxy_url.c_str()); if (absl::GetFlag(FLAGS_proxy_type) == "socks4") { curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); diff --git a/yass/src/win32/utils_win.cpp b/yass/src/win32/utils_win.cpp index 1c496ce704..201785a090 100644 --- a/yass/src/win32/utils_win.cpp +++ b/yass/src/win32/utils_win.cpp @@ -202,6 +202,8 @@ typedef int(__stdcall* PFNGETUSERDEFAULTLOCALENAME)(LPWSTR lpLocaleName, int cch #undef EnableNonClientDpiScaling #undef SystemParametersInfoForDpi +using namespace std::string_literals; + namespace { HANDLE EnsureUser32Loaded() { @@ -897,7 +899,7 @@ std::string Utils::GetLocalAddr() { bool Utils::SetSystemProxy(bool on) { bool enabled; - std::string server_addr, bypass_addr = ""; + std::string server_addr, bypass_addr = ""s; ::QuerySystemProxy(&enabled, &server_addr, &bypass_addr); if (on) { server_addr = GetLocalAddr();