C#在二合一平板电脑关于旋转模式相关设置

二合一平板电脑会根据方向调整而旋转,下面是介绍关于旋转方向的一些设置。

  1. 设置应用进程不跟随旋转

  2. 设置系统旋转开关,实时生效

  3. 监听旋转变化

1.设置单个应用旋转固定方向SetDisplayAutoRotationPreferences

设置当前进程的屏幕自动旋转首选项。setDisplayAutoRotationPreferences 函数 (winuser.h) - Win32 apps

问题:当设置uiAccess="true"的时候,有小部分设备会必现无法固定旋转方向。但是其他大部分设备都没问题,具体造成差异原因还是需要查一查。

解决办法,如果是全局应用可以通过SetDisplayAutoRotation设置系统的旋转状态来禁用旋转。

       // 定义方向偏好枚举,用于控制屏幕显示方向
       [Flags]
       public enum ORIENTATION_PREFERENCE : int
       {
           /// <summary>
           /// 无方向偏好,允许所有方向
           /// </summary>
           ORIENTATION_PREFERENCE_NONE = 0x0,

           /// <summary>
           /// 横屏方向(正常横向)
           /// 屏幕宽度大于高度,标准的横向显示
           /// </summary>
           ORIENTATION_PREFERENCE_LANDSCAPE = 0x1,

           /// <summary>
           /// 竖屏方向(正常纵向)
           /// 屏幕高度大于宽度,标准的纵向显示
           /// </summary>
           ORIENTATION_PREFERENCE_PORTRAIT = 0x2,

           /// <summary>
           /// 翻转横屏方向
           /// 屏幕宽度大于高度,但上下翻转的横向显示
           /// </summary>
           ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,

           /// <summary>
           /// 翻转竖屏方向
           /// 屏幕高度大于宽度,但左右翻转的纵向显示
           /// </summary>
           ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8
       }

  /// <summary>
  /// 设置当前进程的屏幕自动旋转首选项。
  /// </summary>
  /// <param name="orientation"></param>
  /// <returns></returns>
  [DllImport("user32.dll", SetLastError = true)]
  private static extern bool SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE orientation);

  /// <summary>
  /// 检索当前进程的屏幕自动旋转首选项。
  /// </summary>
  /// <param name="orientation"></param>
  /// <returns></returns>
  [DllImport("user32.dll")]
  private static extern bool GetDisplayAutoRotationPreferences(out ORIENTATION_PREFERENCE orientation);

       // 供应用程序调用的方法
       public static bool LockLandscape()
       {
           // 同时锁定正常
           var preference = ORIENTATION_PREFERENCE.ORIENTATION_PREFERENCE_LANDSCAPE;
           return SetDisplayAutoRotationPreferences(preference);
       }

2. 设置系统旋转开关SetDisplayAutoRotation

SetDisplayAutoRotation这个方法没找到官方API,此方法是非公开的接口,这个方式设置立即生效的,如果是注册表设置需要重启才生效。

要获取 DllImport 中 EntryPoint = "#2507" 这类函数导出序号,需通过工具分析 DLL 的导出表.

Windows DLL 中的函数可通过名称序号导出。当函数无公开文档(如未官方发布的 API)时,只能通过序号调用(即 EntryPoint = "#序号")。具体方法可以使用 Visual Studio 自带工具 dumpbin

系统屏幕自动旋转状态:GetAutoRotationState 函数 (winuser.h) - Win32 apps

// 禁用启用自动旋转
[DllImport("user32.dll", EntryPoint = "#2507")]
public static extern bool SetDisplayAutoRotation(bool enable);

// 导入获取系统自动旋转状态的 API
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetAutoRotationState(out AR_STATE pState);

通过注册设置和获取当前系统是否禁用旋转

注意通过注册表设置系统旋转需要重启系统之后才生效的无法实时生效。获取旋转状态的方法是实时生效。

  /// <summary>
  /// 获取自动旋转是否启用
  /// </summary>
  /// <returns>true表示启用,false表示禁用,null表示无法确定</returns>
  public bool? IsAutoRotationEnabled()
  {
      try
      {
          using var key = Registry.LocalMachine.OpenSubKey(AutoRotationRegistryPath);
          if (key != null)
          {
              var value = key.GetValue(EnableValueName);
              if (value != null)
              {
                  // 注册表值通常是 1(启用) 或 0(禁用)
                  if (int.TryParse(value.ToString(), out int enableValue))
                  {
                      AnnotatorService.Log.Info($"获取自动旋转状态成功: {enableValue == 1}");
                      return enableValue == 1;
                  }
              }
          }
          AnnotatorService.Log.Info("未找到自动旋转注册表项");
          return null;
      }
      catch (Exception ex)
      {
          AnnotatorService.Log.Error($"获取自动旋转状态失败: {ex.Message}");
          return null;
      }
  }
  /// <summary>
  /// 设置自动旋转启用状态
  /// </summary>
  /// <param name="enable">true表示启用,false表示禁用</param>
  /// <returns>设置是否成功</returns>
  private bool SetAutoRotationEnabled(bool enable)
  {
      try
      {
          using var key = Registry.LocalMachine.CreateSubKey(AutoRotationRegistryPath);
          if (key != null)
          {
              int value = enable ? 1 : 0;
              key.SetValue(EnableValueName, value, RegistryValueKind.DWord);
              AnnotatorService.Log.Info($"设置自动旋转状态成功: {enable}");
              return true;
          }

          AnnotatorService.Log.Error("无法创建或访问自动旋转注册表项");
          return false;
      }
      catch (Exception ex)
      {
          AnnotatorService.Log.Error($"设置自动旋转状态失败: {ex.Message}");
          return false;
      }
  }
      private const string AutoRotationRegistryPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\AutoRotation";
    /// <summary>
    /// 控制系统级自动旋转的总开关(0 禁用,1 启用)
    /// </summary>
    private const string EnableValueName = "Enable";

3. 监听设备旋转变化

使用Win10 Api的SimpleOrientationSensor SimpleOrientationSensor 类 (Windows.Devices.Sensors) - Windows UWP applications

注意:当触发SimpleSensor_OrientationChanged变化的时候立即去获取旋转方向是获取到旋转好之前的方向的,需要等待300ms才能获取到旋转完成之后的方向。

internal class OrientationManager
{

    #region 监听方向变化
    private SimpleOrientationSensor simpleSensor;

    private SimpleOrientation currentOrientation;
    /// <summary>
    /// 监听方向变化重启应用
    /// </summary>
    public void RegisterOrientationChanged()
    {
        try
        {
            if (simpleSensor != null)
            {
                simpleSensor.OrientationChanged -= SimpleSensor_OrientationChanged;
            }
            simpleSensor = SimpleOrientationSensor.GetDefault();
            AnnotatorService.Log.Info($"初始化方向传感器:{simpleSensor != null}");
            if (simpleSensor != null)
            {
                currentOrientation = simpleSensor.GetCurrentOrientation();
                // 订阅方向变化事件
                simpleSensor.OrientationChanged += SimpleSensor_OrientationChanged;
            }

        }
        catch (Exception e)
        {
            AnnotatorService.Log.Error(e);
        }
    }
    public void UnregisterOrientationChanged()
    {
        if (simpleSensor != null)
        {
            simpleSensor.OrientationChanged -= SimpleSensor_OrientationChanged;
            simpleSensor = null;
        }
    }
    public Action<SimpleOrientation> OnDelayOrientationChanged;
  
    private async void SimpleSensor_OrientationChanged(SimpleOrientationSensor sender, SimpleOrientationSensorOrientationChangedEventArgs args)
    {
        AnnotatorService.Log.Info($"方向变化:{args.Orientation}");
        if (currentOrientation == args.Orientation) return;
        currentOrientation = args.Orientation;
        if (IsSignificantOrientationChange(currentOrientation))
        {
            await Task.Delay(300);
            OnDelayOrientationChanged?.Invoke(args.Orientation);
        }
    }
    private bool IsSignificantOrientationChange(SimpleOrientation newOrientation)
    {
        // 过滤掉不重要的方向变化
        // 例如:Faceup/Facedown 可能不需要处理
        switch (newOrientation)
        {
            case SimpleOrientation.Faceup:
            case SimpleOrientation.Facedown:
                return false;
            default:
                return true;
        }
    }

    #endregion

}
posted @ 2025-10-19 12:08  拚忘  阅读(7)  评论(0)    收藏  举报