improve webviewer & hotkey

This commit is contained in:
DismissedLight
2023-11-07 21:02:25 +08:00
parent ec007d5d81
commit acdf2baa9a
11 changed files with 152 additions and 88 deletions

View File

@@ -4,7 +4,6 @@
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
<Setter Property="BorderBrush" Value="{ThemeResource CardStrokeColorDefaultBrush}"/>
</Style>
<Style

View File

@@ -36,7 +36,7 @@ internal static partial class IocHttpClientConfiguration
}
/// <summary>
/// 对于需要添加动态密钥的客户端使用此配置
/// 对于需要添加动态密钥1的客户端使用此配置
/// </summary>
/// <param name="client">配置后的客户端</param>
private static void XRpcConfiguration(HttpClient client)
@@ -50,7 +50,7 @@ internal static partial class IocHttpClientConfiguration
}
/// <summary>
/// 对于需要添加动态密钥的客户端使用此配置
/// 对于需要添加动态密钥2的客户端使用此配置
/// </summary>
/// <param name="client">配置后的客户端</param>
private static void XRpc2Configuration(HttpClient client)
@@ -64,11 +64,11 @@ internal static partial class IocHttpClientConfiguration
client.DefaultRequestHeaders.Add("x-rpc-client_type", "2");
client.DefaultRequestHeaders.Add("x-rpc-device_id", HoyolabOptions.DeviceId);
client.DefaultRequestHeaders.Add("x-rpc-game_biz", "bbs_cn");
client.DefaultRequestHeaders.Add("x-rpc-sdk_version", "1.3.1.2");
client.DefaultRequestHeaders.Add("x-rpc-sdk_version", "2.16.0");
}
/// <summary>
/// 对于需要添加动态密钥的客户端使用此配置
/// 对于需要添加动态密钥1的客户端使用此配置
/// HoYoLAB app
/// </summary>
/// <param name="client">配置后的客户端</param>
@@ -84,7 +84,7 @@ internal static partial class IocHttpClientConfiguration
}
/// <summary>
/// 对于需要添加动态密钥的客户端使用此配置
/// 对于需要添加动态密钥2的客户端使用此配置
/// HoYoLAB web
/// </summary>
/// <param name="client">配置后的客户端</param>

View File

@@ -184,8 +184,9 @@ internal sealed class HotKeyCombination : ObservableObject
}
HWND hwnd = currentWindowReference.GetWindowHandle();
registered = RegisterHotKey(hwnd, hotKeyId, Modifiers, (uint)Key);
return registered;
BOOL result = RegisterHotKey(hwnd, hotKeyId, Modifiers, (uint)Key);
registered = result;
return result;
}
public bool UnregisterForCurrentWindow()
@@ -201,8 +202,9 @@ internal sealed class HotKeyCombination : ObservableObject
}
HWND hwnd = currentWindowReference.GetWindowHandle();
registered = UnregisterHotKey(hwnd, hotKeyId);
return registered;
BOOL result = UnregisterHotKey(hwnd, hotKeyId);
registered = !result;
return result;
}
public override string ToString()

View File

@@ -2535,7 +2535,7 @@
<value>当前用户</value>
</data>
<data name="ViewUserCookieOperationGameRecordIndexAction" xml:space="preserve">
<value>我的角色</value>
<value>旅行工具</value>
</data>
<data name="ViewUserCookieOperationLoginMihoyoUserAction" xml:space="preserve">
<value>网页登录</value>

View File

@@ -6,5 +6,43 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Transitions="{ThemeResource EntranceThemeTransitions}"
mc:Ignorable="d">
<WebView2 x:Name="WebView" DefaultBackgroundColor="Transparent"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button
MinWidth="42"
Command="{x:Bind GoBackCommand}"
FontSize="12"
IsEnabled="{x:Bind WebView.CanGoBack, Mode=OneWay}"
Style="{StaticResource NavigationBackButtonSmallStyle}"/>
<Button
MinWidth="42"
Command="{x:Bind RefreshCommand}"
Content="&#xE72C;"
FontSize="12"
Style="{StaticResource NavigationBackButtonSmallStyle}"/>
<TextBlock
MaxWidth="240"
Margin="6"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Bind DocumentTitle, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap"/>
</StackPanel>
<WebView2
x:Name="WebView"
Grid.Row="1"
DefaultBackgroundColor="Transparent"/>
<Rectangle
Grid.Row="2"
Height="8"
Fill="{ThemeResource SystemControlAccentAcrylicElementAccentMediumHighBrush}"/>
</Grid>
</UserControl>

View File

@@ -10,17 +10,20 @@ using Snap.Hutao.Service.Notification;
using Snap.Hutao.Service.User;
using Snap.Hutao.ViewModel.User;
using Snap.Hutao.Web.Bridge;
using Windows.Foundation;
using WinRT;
using WinRT.Interop;
namespace Snap.Hutao.View.Control;
[DependencyProperty("SourceProvider", typeof(IWebViewerSource))]
[DependencyProperty("DocumentTitle", typeof(string))]
internal partial class WebViewer : UserControl, IRecipient<UserChangedMessage>
{
private readonly IServiceProvider serviceProvider;
private readonly IInfoBarService infoBarService;
private readonly RoutedEventHandler loadEventHandler;
private readonly TypedEventHandler<CoreWebView2, object> documentTitleChangedEventHander;
private MiHoYoJSInterface? jsInterface;
private bool isInitializingOrInitialized;
@@ -34,6 +37,7 @@ internal partial class WebViewer : UserControl, IRecipient<UserChangedMessage>
serviceProvider.GetRequiredService<IMessenger>().Register(this);
loadEventHandler = OnLoaded;
documentTitleChangedEventHander = OnDocumentTitleChanged;
Loaded += loadEventHandler;
}
@@ -44,6 +48,21 @@ internal partial class WebViewer : UserControl, IRecipient<UserChangedMessage>
taskContext.InvokeOnMainThread(RefreshWebview2Content);
}
[Command("GoBackCommand")]
private void GoBack()
{
if (WebView.CanGoBack)
{
WebView.GoBack();
}
}
[Command("RefreshCommand")]
private void Refresh()
{
WebView.Reload();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
InitializeAsync().SafeForget();
@@ -60,9 +79,15 @@ internal partial class WebViewer : UserControl, IRecipient<UserChangedMessage>
await WebView.EnsureCoreWebView2Async();
WebView.CoreWebView2.DisableDevToolsForReleaseBuild();
WebView.CoreWebView2.DocumentTitleChanged += documentTitleChangedEventHander;
RefreshWebview2Content();
}
private void OnDocumentTitleChanged(CoreWebView2 sender, object args)
{
DocumentTitle = sender.DocumentTitle;
}
private async void RefreshWebview2Content()
{
User? user = serviceProvider.GetRequiredService<IUserService>().Current;

View File

@@ -22,22 +22,28 @@
Text="{x:Bind Title}"
TextWrapping="NoWrap"/>
<ToggleButton
<StackPanel
Grid.Column="1"
Margin="0,0,6,0"
VerticalAlignment="Center"
IsChecked="{x:Bind HotKeyOptions.IsMouseClickRepeatForeverOn, Mode=OneWay}"
IsHitTestVisible="False"
Visibility="{x:Bind RuntimeOptions.IsElevated}">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
Orientation="Horizontal"
Spacing="6"
Visibility="{x:Bind RuntimeOptions.IsElevated, Converter={StaticResource BoolToVisibilityConverter}}">
<ToggleButton
Margin="0,0,6,0"
VerticalAlignment="Center"
IsChecked="{x:Bind HotKeyOptions.IsMouseClickRepeatForeverOn, Mode=OneWay}"
IsHitTestVisible="False"
Visibility="{x:Bind HotKeyOptions.MouseClickRepeatForeverKeyCombination.IsEnabled, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{x:Bind HotKeyOptions.MouseClickRepeatForeverKeyCombination.DisplayName, Mode=OneWay}"/>
<TextBlock Grid.Column="1" Text="{shcm:ResourceString Name=ViewTitleAutoClicking}"/>
</Grid>
</ToggleButton>
</StackPanel>
<TextBlock Grid.Column="0" Text="{x:Bind HotKeyOptions.MouseClickRepeatForeverKeyCombination.DisplayName, Mode=OneWay}"/>
<TextBlock Grid.Column="1" Text="{shcm:ResourceString Name=ViewTitleAutoClicking}"/>
</Grid>
</ToggleButton>
</Grid>
</UserControl>

View File

@@ -216,15 +216,10 @@
Style="{StaticResource DefaultAppBarButtonStyle}">
<FlyoutBase.AttachedFlyout>
<Flyout
FlyoutPresenterStyle="{StaticResource WebViewerFlyoutPresenterStyle}"
LightDismissOverlayMode="On"
Placement="Full"
ShouldConstrainToRootBounds="False">
<Flyout.FlyoutPresenterStyle>
<Style BasedOn="{StaticResource DefaultFlyoutPresenterStyle}" TargetType="FlyoutPresenter">
<Setter Property="Padding" Value="0"/>
<Setter Property="CornerRadius" Value="0"/>
</Style>
</Flyout.FlyoutPresenterStyle>
<Grid>
<shvc:WebViewer>
<shvc:WebViewer.SourceProvider>

View File

@@ -74,12 +74,20 @@ internal class MiHoYoJSInterface
public event Action? ClosePageRequested;
public void Detach()
{
coreWebView2.WebMessageReceived -= webMessageReceivedEventHandler;
coreWebView2.DOMContentLoaded -= domContentLoadedEventHandler;
coreWebView2.NavigationStarting -= navigationStartingEventHandler;
coreWebView2 = default!;
}
/// <summary>
/// 关闭
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual async ValueTask<IJsResult?> ClosePageAsync(JsParam param)
protected virtual async ValueTask<IJsResult?> ClosePageAsync(JsParam param)
{
await taskContext.SwitchToMainThreadAsync();
if (coreWebView2.CanGoBack)
@@ -99,7 +107,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual IJsResult? ConfigureShare(JsParam param)
protected virtual IJsResult? ConfigureShare(JsParam param)
{
return null;
}
@@ -109,7 +117,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="jsParam">参数</param>
/// <returns>响应</returns>
public virtual async ValueTask<IJsResult?> GetActionTicketAsync(JsParam<ActionTypePayload> jsParam)
protected virtual async ValueTask<IJsResult?> GetActionTicketAsync(JsParam<ActionTypePayload> jsParam)
{
return await serviceProvider
.GetRequiredService<AuthClient>()
@@ -122,7 +130,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual JsResult<Dictionary<string, string>> GetCookieInfo(JsParam param)
protected virtual JsResult<Dictionary<string, string>> GetCookieInfo(JsParam param)
{
ArgumentNullException.ThrowIfNull(userAndUid.User.LToken);
@@ -142,7 +150,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual async ValueTask<JsResult<Dictionary<string, string>>> GetCookieTokenAsync(JsParam<CookieTokenPayload> param)
protected virtual async ValueTask<JsResult<Dictionary<string, string>>> GetCookieTokenAsync(JsParam<CookieTokenPayload> param)
{
IUserService userService = serviceProvider.GetRequiredService<IUserService>();
if (param.Payload.ForceRefresh)
@@ -162,7 +170,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">param</param>
/// <returns>语言与时区</returns>
public virtual JsResult<Dictionary<string, string>> GetCurrentLocale(JsParam<PushPagePayload> param)
protected virtual JsResult<Dictionary<string, string>> GetCurrentLocale(JsParam<PushPagePayload> param)
{
MetadataOptions metadataOptions = serviceProvider.GetRequiredService<MetadataOptions>();
@@ -181,7 +189,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV1(JsParam param)
protected virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV1(JsParam param)
{
string salt = HoyolabOptions.Salts[SaltType.LK2];
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
@@ -212,7 +220,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV2(JsParam<DynamicSecrect2Playload> param)
protected virtual JsResult<Dictionary<string, string>> GetDynamicSecrectV2(JsParam<DynamicSecrect2Playload> param)
{
string salt = HoyolabOptions.Salts[SaltType.X4];
long t = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
@@ -235,13 +243,20 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>Http请求头</returns>
public virtual JsResult<Dictionary<string, string>> GetHttpRequestHeader(JsParam param)
protected virtual JsResult<Dictionary<string, string>> GetHttpRequestHeader(JsParam param)
{
Dictionary<string, string> headers = new()
{
// Skip x-rpc-device_name
// Skip x-rpc-device_model
// Skip x-rpc-sys_version
// Skip x-rpc-game_biz
// Skip x-rpc-lifecycle_id
{ "x-rpc-app_id", "bll8iq97cem8" },
{ "x-rpc-client_type", "5" },
{ "x-rpc-device_id", HoyolabOptions.DeviceId },
{ "x-rpc-app_version", SaltConstants.CNVersion },
{ "x-rpc-device_id", HoyolabOptions.DeviceId },
{ "x-rpc-app_version", userAndUid.IsOversea ? SaltConstants.OSVersion : SaltConstants.CNVersion },
{ "x-rpc-sdk_version", "2.16.0" },
};
if (!userAndUid.IsOversea)
@@ -249,18 +264,24 @@ internal class MiHoYoJSInterface
headers.Add("x-rpc-device_fp", userAndUid.User.Fingerprint ?? string.Empty);
}
GetHttpRequestHeaderCore(headers);
return new()
{
Data = headers,
};
}
protected virtual void GetHttpRequestHeaderCore(Dictionary<string, string> headers)
{
}
/// <summary>
/// 获取状态栏高度
/// </summary>
/// <param name="param">参数</param>
/// <returns>结果</returns>
public virtual JsResult<Dictionary<string, object>> GetStatusBarHeight(JsParam param)
protected virtual JsResult<Dictionary<string, object>> GetStatusBarHeight(JsParam param)
{
return new() { Data = new() { ["statusBarHeight"] = 0 } };
}
@@ -270,7 +291,7 @@ internal class MiHoYoJSInterface
/// </summary>
/// <param name="param">参数</param>
/// <returns>响应</returns>
public virtual async ValueTask<JsResult<Dictionary<string, object>>> GetUserInfoAsync(JsParam param)
protected virtual async ValueTask<JsResult<Dictionary<string, object>>> GetUserInfoAsync(JsParam param)
{
Response<UserFullInfoWrapper> response = await serviceProvider
.GetRequiredService<IOverseaSupportFactory<IUserClient>>()
@@ -299,7 +320,7 @@ internal class MiHoYoJSInterface
}
}
public virtual async ValueTask<IJsResult?> PushPageAsync(JsParam<PushPagePayload> param)
protected virtual async ValueTask<IJsResult?> PushPageAsync(JsParam<PushPagePayload> param)
{
const string bbsSchema = "mihoyobbs://";
string pageUrl = param.Payload.Page;
@@ -323,7 +344,7 @@ internal class MiHoYoJSInterface
return null;
}
public virtual IJsResult? Share(JsParam<SharePayload> param)
protected virtual IJsResult? Share(JsParam<SharePayload> param)
{
return new JsResult<Dictionary<string, string>>()
{
@@ -334,57 +355,53 @@ internal class MiHoYoJSInterface
};
}
public virtual ValueTask<IJsResult?> ShowAlertDialogAsync(JsParam param)
protected virtual ValueTask<IJsResult?> ShowAlertDialogAsync(JsParam param)
{
return ValueTask.FromException<IJsResult?>(new NotSupportedException());
}
public virtual IJsResult? StartRealPersonValidation(JsParam param)
protected virtual IJsResult? StartRealPersonValidation(JsParam param)
{
throw new NotImplementedException();
}
public virtual IJsResult? StartRealnameAuth(JsParam param)
protected virtual IJsResult? StartRealnameAuth(JsParam param)
{
throw new NotImplementedException();
}
public virtual IJsResult? GenAuthKey(JsParam param)
protected virtual IJsResult? GenAuthKey(JsParam param)
{
throw new NotImplementedException();
}
public virtual IJsResult? GenAppAuthKey(JsParam param)
protected virtual IJsResult? GenAppAuthKey(JsParam param)
{
throw new NotImplementedException();
}
public virtual IJsResult? OpenSystemBrowser(JsParam param)
protected virtual IJsResult? OpenSystemBrowser(JsParam param)
{
throw new NotImplementedException();
}
public virtual IJsResult? SaveLoginTicket(JsParam param)
protected virtual IJsResult? SaveLoginTicket(JsParam param)
{
throw new NotImplementedException();
}
public virtual ValueTask<IJsResult?> GetNotificationSettingsAsync(JsParam param)
protected virtual ValueTask<IJsResult?> GetNotificationSettingsAsync(JsParam param)
{
throw new NotImplementedException();
}
public virtual IJsResult? ShowToast(JsParam param)
protected virtual IJsResult? ShowToast(JsParam param)
{
throw new NotImplementedException();
}
public void Detach()
protected virtual void DOMContentLoaded(CoreWebView2 coreWebView2)
{
coreWebView2.WebMessageReceived -= webMessageReceivedEventHandler;
coreWebView2.DOMContentLoaded -= domContentLoadedEventHandler;
coreWebView2.NavigationStarting -= navigationStartingEventHandler;
coreWebView2 = default!;
}
private async ValueTask<string> ExecuteCallbackScriptAsync(string callback, string? payload = null)
@@ -485,6 +502,7 @@ internal class MiHoYoJSInterface
private void OnDOMContentLoaded(CoreWebView2 coreWebView2, CoreWebView2DOMContentLoadedEventArgs args)
{
DOMContentLoaded(coreWebView2);
coreWebView2.ExecuteScriptAsync(HideScrollBarScript).AsTask().SafeForget(logger);
}

View File

@@ -20,17 +20,8 @@ internal sealed class SignInJSInterface : MiHoYoJSInterface
{
}
/// <inheritdoc/>
public override JsResult<Dictionary<string, string>> GetHttpRequestHeader(JsParam param)
protected override void GetHttpRequestHeaderCore(Dictionary<string, string> headers)
{
return new()
{
Data = new Dictionary<string, string>()
{
{ "x-rpc-client_type", "2" },
{ "x-rpc-device_id", HoyolabOptions.DeviceId },
{ "x-rpc-app_version", SaltConstants.CNVersion },
},
};
headers["x-rpc-client_type"] = "2";
}
}

View File

@@ -14,6 +14,7 @@ namespace Snap.Hutao.Web.Bridge;
[HighQuality]
internal sealed class SignInJSInterfaceOversea : MiHoYoJSInterface
{
// 移除 请旋转手机 提示所在的HTML元素
private const string RemoveRotationWarningScript = """
let landscape = document.getElementById('mihoyo_landscape');
landscape.remove();
@@ -26,26 +27,15 @@ internal sealed class SignInJSInterfaceOversea : MiHoYoJSInterface
: base(webView, userAndUid)
{
logger = serviceProvider.GetRequiredService<ILogger<MiHoYoJSInterface>>();
webView.DOMContentLoaded += OnDOMContentLoaded;
}
/// <inheritdoc/>
public override JsResult<Dictionary<string, string>> GetHttpRequestHeader(JsParam param)
protected override void GetHttpRequestHeaderCore(Dictionary<string, string> headers)
{
return new()
{
Data = new Dictionary<string, string>()
{
{ "x-rpc-client_type", "2" },
{ "x-rpc-device_id", HoyolabOptions.DeviceId },
{ "x-rpc-app_version", SaltConstants.OSVersion },
},
};
headers["x-rpc-client_type"] = "2";
}
private void OnDOMContentLoaded(CoreWebView2 coreWebView2, CoreWebView2DOMContentLoadedEventArgs args)
protected override void DOMContentLoaded(CoreWebView2 coreWebView2)
{
// 移除“请旋转手机”提示所在的HTML元素
coreWebView2.ExecuteScriptAsync(RemoveRotationWarningScript).AsTask().SafeForget(logger);
}
}
}