10

我正在使用终端仿真器库来创建终端,然后使用它将通过串行输入的数据发送到串行设备。图书馆可以在这里看到。

当我将数据输入终端时,正在发送/接收一系列奇怪的字符。我认为 unicode 替换字符是通过串行发送的,串行设备不知道它是什么并返回 ~0。

当我写“测试”时,终端中出现的屏幕截图:在此处输入图像描述

以及显示发送的字符串和接收的数据的日志。http://i.imgur.com/x79aPzv.png

我创建了一个 EmulatorView,它是终端视图。它在这里提到了钻石。

private void sendText(CharSequence text) {
                int n = text.length();
                char c;
                try {
                    for(int i = 0; i < n; i++) {
                        c = text.charAt(i);
                        if (Character.isHighSurrogate(c)) {
                            int codePoint;
                            if (++i < n) {
                                codePoint = Character.toCodePoint(c, text.charAt(i));
                            } else {
                                // Unicode Replacement Glyph, aka white question mark in black diamond.
                                codePoint = '\ufffd';
                            }
                            mapAndSend(codePoint);
                        } else {
                            mapAndSend(c);
                        }
                    }
                } catch (IOException e) {
                    Log.e(TAG, "error writing ", e);
                }
            }

有没有什么办法解决这一问题?任何人都可以在库类中看到为什么会这样吗?,如果我愿意,我如何在 java 中引用 � 来解析它?我不能说如果 (!str.contains("�") 我接受它。

当我在终端中输入时,它会运行:

public void write(byte[] bytes, int offset, int count) {


 String str;
try {
    str = new String(bytes, "UTF-8");
      Log.d(TAG, "data received in write: " +str );

      GraphicsTerminalActivity.sendOverSerial(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
    Log.d(TAG, "exception" );
    e.printStackTrace();
}

        // appendToEmulator(bytes, 0, bytes.length);

 return;
}

这就是我所说的发送数据。sendData(Byte[] data) 是一个库方法。

public static void sendOverSerial(byte[] data) {
        String str;
        try {
            str = new String(data,"UTF-8");
             if(mSelectedAdapter !=null && data !=null){
                 Log.d(TAG, "send over serial string==== " + str);

                mSelectedAdapter.sendData(str.getBytes("UTF-8"));
                 }
        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, "exception");
            e.printStackTrace();
        }

    }

发送数据后,将在此处收到回复:

public void onDataReceived(int id, byte[] data) {

        try {
            dataReceived = new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, "exception");
            e.printStackTrace();
        }

        try {
            dataReceivedByte = dataReceived.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            Log.d(TAG, "exception");
            e.printStackTrace();
        }
        statusBool = true;
        Log.d(TAG, "in data received " + dataReceived);
        ((MyBAIsWrapper) bis).renew(data);


        runOnUiThread(new Runnable(){

            @Override
            public void run() {

                mSession.appendToEmulator(dataReceivedByte, 0, dataReceivedByte.length);

            }});

    viewHandler.post(updateView);

}

写入字符的库类的相关部分:

类的相关部分:

private void sendText(CharSequence text) {
                int n = text.length();
                char c;
                try {
                    for(int i = 0; i < n; i++) {
                        c = text.charAt(i);
                        if (Character.isHighSurrogate(c)) {
                            int codePoint;
                            if (++i < n) {
                                codePoint = Character.toCodePoint(c, text.charAt(i));
                            } else {
                                // Unicode Replacement Glyph, aka white question mark in black diamond.
                                codePoint = '\ufffd';
                            }
                            mapAndSend(codePoint);
                        } else {
                            mapAndSend(c);
                        }
                    }
                } catch (IOException e) {
                    Log.e(TAG, "error writing ", e);
                }
            }

            private void mapAndSend(int c) throws IOException {
                int result = mKeyListener.mapControlChar(c);
                if (result < TermKeyListener.KEYCODE_OFFSET) {
                    mTermSession.write(result);
                } else {
                    mKeyListener.handleKeyCode(result - TermKeyListener.KEYCODE_OFFSET, getKeypadApplicationMode());
                }
                clearSpecialKeyStatus();
            }
4

3 回答 3

1

Java 在内部将文本存储为未编码的 Unicode。曾经是 16 位,现在我猜测它是 32 位,因为您在终端上为您尝试输出的每个 unicode 字符获得了四个输出字符。

您可能想要做的是使用类似 string.getBytes("ASCII") 的东西将您的 unicode 字符串转换为直接的单字节 ascii。如果您的终端模拟器处理其他字符集(如 Latin-1),请使用它而不是“ASCII”。

然后,将字节传输到终端仿真器而不是字符串。

注意:我不肯定“ASCII”是字符集的确切名称;你会想自己研究。另外,我不知道 getBytes() 会对无法转换为 ascii 的 unicode 字符做什么,所以你也想研究一下。

ETA:我无法从您发布的废料中遵循您的代码逻辑。谁调用了 write(),数据从哪里来,又去了哪里?同样的问题也适用于 sendOverSerial() 和 onDataReceived()。

无论如何,我几乎可以肯定,在某个地方,原始的 32 位 Unicode 数据在没有被编码的​​情况下被转换为字节。从那时起,无论是按原样发送还是将其重新编码为 UTF-8 都会产生您所看到的效果。我看不出这在您发布的任何代码中是如何发生的,所以我猜它发生在您向我们展示的任何函数被调用之前的其他地方。

于 2013-01-25T16:26:56.100 回答
0

您正在使用的库似乎将代码点作为 int(32 位)发送,并且您的代码假设其编码为 utf-8,它不能正确处理 4 字节。这与 java 如何在内部存储文本无关。顺便说一句,Java 在内部将文本存储为编码的 UTF-16,而不是未编码的 unicode。同样,这不是导致此问题的原因。这是您与正在使用的库进行交互的方式。

于 2013-02-01T19:28:07.917 回答
0

我通过编辑我正在使用的库解决了这个问题。他们正在使用一种将字节转换为 int 的方法,它接受一个 codePoint 并对其进行转换。因此,每次按键都会使用 4 个字节。我改变了这一点,以便使用一个字节而不是一个 int。没有更多的额外字节。与编码格式无关。

于 2013-01-30T11:53:05.277 回答