在Rust中转换*const __CFData为String并获取键盘语言的问题
解决Rust中获取当前键盘语言并判断的问题
错误原因
你遇到的问题核心是对kTISPropertyLocalizedName的返回值类型判断错误:这个属性返回的是CFStringRef(和NSString是toll-free桥接的),而非你声明的*const __CFData。强行用CFDataGetBytePtr处理CFString/NSString对象,必然触发unrecognized selector错误——因为NSString根本没有bytes方法(该方法属于CFData)。
正确实现代码
以下是修正后的Rust代码,包含正确的类型处理和Core Foundation内存管理:
use core_foundation::{ string::CFString, base::{CFRelease, CFTypeRef}, }; use std::ffi::CStr; // 假设你的ffi模块已正确声明以下函数/常量 // ffi::TISCopyCurrentKeyboardLayoutInputSource() -> CFTypeRef; // ffi::TISGetInputSourceProperty(source: CFTypeRef, property: CFTypeRef) -> CFTypeRef; // ffi::kTISPropertyLocalizedName: CFTypeRef; fn is_current_keyboard_english() -> bool { // 获取当前键盘布局输入源,返回对象需手动释放 let current_source = unsafe { ffi::TISCopyCurrentKeyboardLayoutInputSource() }; if current_source.is_null() { return false; } // 获取本地化名称(CFString类型) let localized_name = unsafe { ffi::TISGetInputSourceProperty(current_source, ffi::kTISPropertyLocalizedName) }; if localized_name.is_null() { unsafe { CFRelease(current_source) }; return false; } // 将CFString转换为Rust String let lang_str = unsafe { // 优先尝试快速获取C字符串指针(适用于UTF-8兼容的字符串) match CFString::new(localized_name).c_string_ptr() { Some(ptr) => CStr::from_ptr(ptr).to_str().unwrap_or_default().to_string(), None => { // 快速获取失败时,用缓冲区复制处理特殊字符 let mut buf = [0u8; 256]; let success = CFString::new(localized_name).get_cstring( &mut buf, core_foundation::string::CFStringEncoding::UTF8 ); if success { CStr::from_bytes_until_nul(&buf).unwrap_or_default().to_str().unwrap_or_default().to_string() } else { String::new() } } } }; // 释放Core Foundation对象,避免内存泄漏 unsafe { CFRelease(localized_name); CFRelease(current_source); } lang_str.contains("English") }
关键注意事项
- 类型匹配:务必对照官方文档确认
TISGetInputSourceProperty返回的属性类型,kTISPropertyLocalizedName明确为CFString类型。 - 内存管理:所有以
Copy/Create开头的Core Foundation函数返回的对象,必须用CFRelease手动释放。 - 字符串转换:优先用
CFString::c_string_ptr提升效率,失败时再用缓冲区复制的方式兼容特殊字符场景。
内容的提问来源于stack exchange,提问作者hyoyin_Kyuoma
相关产品推荐
相关产品推荐

