如何获取操作系统的内部/键盘字符集,与alt键字符输入相关

问题描述 投票:0回答:1

前言

我目前正在开发一个小应用程序

  • 字面意思是类型输入
  • 来自系统剪贴板(使用
    Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
    ),
  • 通过模拟键盘的击键(使用
    java.awt.Robot.keyPress(keyCode)
    )。

这适用于 UI 元素不支持复制粘贴(既不支持 ctrl+v 也不支持 shift+ins),或者死键控制在应用程序或整个系统中被阻止的情况。

我花了很长时间才找到一个简单的解决方案:使用Alt键输入法。 (基本上按 Alt,输入代码,例如

0128
代表
,然后松开 Alt,badaa:你会得到

要获取该代码,我可以简单地将字符转换为字节(

String.getBytes
和新的
String(bytes)
),但是对于这两种方法,我需要指定正确的字符集,因为Java将尝试使用UTF-8,这那里错了。

对于我迄今为止遇到的所有场合,这一切都非常有效。

问题

但是:这种方法有一个缺点:我需要知道操作系统的键盘字符集/代码页。

通常,在 Windows 下,它们是单字节 CP1252,但这会因国家和操作系统而异。

问题:

如何找出当前操作系统用于键盘输入的字符集/代码页?

(如果可能的话,首选与Java相关的答案。)

提示

以下检索字符集的方法可行,因为它们仅与文件 I/O 相关:

  • java.lang.System.getProperty("file.encoding")
  • java.nio.charset.Charset.defaultCharset()
  • java.io.FileReader.getEncoding()
    (这只是
    java.io.InputStreamReader.getEncoding()
    ,而且通常最终都会打电话给
    java.nio.charset.Charset.defaultCharset()
    ...)
  • JVM 的命令行参数如
    java -Dfile.encoding=XXX app
    client.encoding.override
    ,但这需要手动调整,这是一项更好的任务留给用户

到目前为止我发现:

  • Windows PowerShell:
    [System.Text.Encoding]::Default
    ,但这需要 Windows PowerShell...
  • 我是否必须使用 JNI 和
    BOOL GetKeyboardLayoutName(LPTSTR pwszKLID);
    并希望我能将其与 Java 的字符集相匹配?
java character-encoding keyboard user-input charset
1个回答
0
投票

哇。这比预想的要容易。

非常感谢@Elliott Frisch:他给了我一个非常好的主意。

第一步:想法

所以我用这段代码测试了一些System.properties

import java.nio.charset.Charset;

public class CharsetInfo {



    static public final String[]    TESTS_JAVA      = { "java.version\t\t", "java.runtime.version\t", "sun.arch.data.model\t" };
    static public final String[]    TESTS_ENCODING  = { "file.encoding\t\t", "native.encoding\t\t", "sun.jnu.encoding\t", "sun.stdout.encoding\t", "sun.stderr.encoding\t" };



    public static void main(final String[] args) {
        System.out.println("----------------------------------------------------------");

        for (final String t : TESTS_JAVA) {
            System.out.println("\t" + t + "\t" + System.getProperty(t.trim()));
        }

        System.out.println("    ------------------------------------------");

        for (final String t : TESTS_ENCODING) {
            System.out.println("\t" + t + "\t" + System.getProperty(t.trim()));
        }
        System.out.println("\t" + "Charset.defaultCharset()\t" + Charset.defaultCharset());
        //      System.out.println("System.console().charset()                = " + System.console().charset()); // java 22/23/24/+

        System.out.println("----------------------------------------------------------");
    }

}

(摘自这里并稍微修改过)

最后一行的

Info(关于

System.console().charset()
):这只用22+编译,然后它总是返回
null

第 2 步:收集数据

我写了一个小应用程序

  • 检测所有已安装的完整 JDK,
  • 然后编译给定的文件
    CharsetInfo
  • 然后运行它,输出如下所示的负载

(在同一个 Windows Server 2016 上运行所有这些 JDK)

D:\apps\java\jdk-10.0.2\bin
        Compiling:  D:\apps\java\jdk-10.0.2\bin\javac.exe D:\workspace\Test\src\CharsetInfo.java
        Success.

        Executing:  D:\apps\java\jdk-10.0.2\bin\java.exe -classpath D:\workspace\Test\src CharsetInfo
        Out:
----------------------------------------------------------
    java.version            10.0.2
    java.runtime.version        10.0.2+13
    sun.arch.data.model     64
    ------------------------------------------
    file.encoding           Cp1252
    native.encoding         null
    sun.jnu.encoding        Cp1252
    sun.stdout.encoding     null
    sun.stderr.encoding     null
    Charset.defaultCharset()    windows-1252
----------------------------------------------------------
        Success.

第3步:统计

现在我将所有输出放入表格中:

Java Native Encoding

第四步:经验教训

正如所见,sun.jnu.encoding 似乎存在于所有 Java 版本中。我使用过 Oracle JDK、OpenJDK、Zulu。 (看起来我在过去的某个时间摆脱了我的 GraalVM。)

但我们也看到,从 Java 17 开始,native.encoding 也将出现。

第五步:将其写入代码

当然,这现在会进入我的图书馆:

static public Charset getSystemCharset() {
    {
        final String csName = System.getProperty("native.encoding");
        if (csName != null && csName.trim().length() > 0) return Charset.forName(csName);
    }
    {
        final String csName = System.getProperty("sun.jnu.encoding");
        if (csName != null && csName.trim().length() > 0) return Charset.forName(csName);
    }
    return Charset.defaultCharset();
}
© www.soinside.com 2019 - 2024. All rights reserved.