我目前正在开发一个小应用程序
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()
...)java -Dfile.encoding=XXX app
或 client.encoding.override
,但这需要手动调整,这是一项更好的任务不留给用户到目前为止我发现:
[System.Text.Encoding]::Default
,但这需要 Windows 和 PowerShell...BOOL GetKeyboardLayoutName(LPTSTR pwszKLID);
并希望我能将其与 Java 的字符集相匹配?哇。这比预想的要容易。
非常感谢@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
。
我写了一个小应用程序
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.
现在我将所有输出放入表格中:
正如所见,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();
}