You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Windows系统中使用Ruby获取当前屏幕方向?Ruby 3.0单屏幕场景下检测屏幕是否翻转纵向(倒置)

Hey there! Let's figure out how to get your screen orientation and detect inverted portrait mode on Windows using Ruby 3.0. Since Ruby doesn't have built-in utilities for this, we'll need to hook into Windows' native APIs—don't worry, it's straightforward with a couple of gems.

Option 1: Using the win32-api Gem

This gem lets you call Windows API functions directly from Ruby. First, install it:

gem install win32-api

Then use this code to fetch orientation and check for inverted states:

require 'win32/api'

# Windows API constants we'll need
DM_DISPLAYORIENTATION = 0x00000080
DMDO_DEFAULT = 0       # Normal landscape
DMDO_90 = 1            # 90° clockwise (portrait)
DMDO_180 = 2           # 180° rotation (inverted landscape)
DMDO_270 = 3           # 270° clockwise (inverted portrait)

# Define the EnumDisplaySettingsA function from user32.dll
EnumDisplaySettings = Win32API.new('user32', 'EnumDisplaySettingsA', ['P', 'L', 'P'], 'L')

# Initialize the DEVMODE structure (holds display settings)
DEVMODE_SIZE = 156
devmode = "\x00" * DEVMODE_SIZE
devmode[0, 2] = [DEVMODE_SIZE].pack('S')  # Set the dmSize field

# Fetch current display settings
if EnumDisplaySettings.call(nil, -1, devmode) != 0
  dm_fields = devmode[40, 4].unpack('L')[0]
  
  # Check if orientation data is available
  if dm_fields & DM_DISPLAYORIENTATION != 0
    orientation = devmode[44, 4].unpack('L')[0]
    
    # Translate orientation code to human-readable text
    orientation_label = case orientation
                        when DMDO_DEFAULT then "Default (normal landscape)"
                        when DMDO_90 then "90° clockwise (portrait)"
                        when DMDO_180 then "180° rotation (inverted landscape)"
                        when DMDO_270 then "270° clockwise (inverted portrait)"
                        else "Unknown orientation"
                        end
    
    puts "Current screen orientation: #{orientation_label}"
    
    # Check for inverted states
    is_inverted_landscape = orientation == DMDO_180
    is_inverted_portrait = orientation == DMDO_270
    
    puts "\nDetection results:"
    puts "Is screen in inverted landscape? #{is_inverted_landscape}"
    puts "Is screen in inverted portrait? #{is_inverted_portrait}"
  else
    puts "Could not retrieve orientation information from display settings."
  end
else
  puts "Failed to fetch current display settings."
end

Option 2: Using the ffi Gem (Modern Alternative)

ffi is a more flexible, cross-platform way to call native APIs. Install it first:

gem install ffi

Here's the equivalent code using ffi:

require 'ffi'

module User32
  extend FFI::Library
  ffi_lib 'user32'
  ffi_convention :stdcall

  # Define the DEVMODE structure that holds display settings
  class DEVMODE < FFI::Struct
    layout(
      :dmDeviceName, [:char, 32],
      :dmSpecVersion, :word,
      :dmDriverVersion, :word,
      :dmSize, :word,
      :dmDriverExtra, :word,
      :dmFields, :dword,
      :union, [:union, {
        :dmOrientation, :short,
        :dmPosition, :pointl,
        :dmDisplayOrientation, :dword,
        :dmDisplayFixedOutput, :dword
      }]
    )
  end

  # Constants for display settings and orientation
  ENUM_CURRENT_SETTINGS = -1
  DM_DISPLAYORIENTATION = 0x00000080
  DMDO_DEFAULT = 0
  DMDO_90 = 1
  DMDO_180 = 2
  DMDO_270 = 3

  # Attach the EnumDisplaySettingsA function
  attach_function :EnumDisplaySettingsA, [:pointer, :long, :pointer], :bool
end

# Initialize and populate the DEVMODE structure
devmode = User32::DEVMODE.new
devmode[:dmSize] = User32::DEVMODE.size

if User32.EnumDisplaySettingsA(nil, User32::ENUM_CURRENT_SETTINGS, devmode)
  if (devmode[:dmFields] & User32::DM_DISPLAYORIENTATION) != 0
    orientation = devmode[:union][:dmDisplayOrientation]
    
    # Map orientation code to readable label
    orientation_label = case orientation
                        when User32::DMDO_DEFAULT then "Default (normal landscape)"
                        when User32::DMDO_90 then "90° clockwise (portrait)"
                        when User32::DMDO_180 then "180° rotation (inverted landscape)"
                        when User32::DMDO_270 then "270° clockwise (inverted portrait)"
                        else "Unknown orientation"
                        end
    
    puts "Current screen orientation: #{orientation_label}"
    
    # Check for inverted states
    is_inverted_landscape = orientation == User32::DMDO_180
    is_inverted_portrait = orientation == User32::DMDO_270
    
    puts "\nDetection results:"
    puts "Is screen in inverted landscape? #{is_inverted_landscape}"
    puts "Is screen in inverted portrait? #{is_inverted_portrait}"
  else
    puts "Display orientation data not available."
  end
else
  puts "Failed to query display settings."
end

Key Notes for Single-Screen Scenarios

Both examples above target your primary display, which works perfectly for single-screen setups. If you ever need to handle multi-screen setups later, you'd use EnumDisplayDevices to iterate over connected monitors, but that's unnecessary here.

What Do the Orientation Values Mean?

  • DMDO_DEFAULT: Normal landscape (your screen's default position)
  • DMDO_90: Clockwise 90° rotation (standard portrait mode)
  • DMDO_180: 180° rotation (inverted landscape, upside-down)
  • DMDO_270: Clockwise 270° (equivalent to counter-clockwise 90°, which is inverted portrait)

Based on your question, DMDO_270 is the "flipped portrait (inverted)" state you're looking to detect.

内容的提问来源于stack exchange,提问作者GT Baka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 13:32:40