如何在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

