Convert USB keyboard data from byte array to String USB4Java - java

I am reading a USB Keyboard (QR Code scanner) input using usb4java.
My code snippet looks like this:
byte[] data = new byte[16];
UsbPipe usbPipe = usbEndpoint.getUsbPipe();
if (usbPipe != null) {
if (!usbPipe.isOpen()) {
usbPipe.open();
}
if (usbPipe.isOpen()) {
UsbIrp usbIrp = usbPipe.createUsbIrp();
usbIrp.setData(data);
I have two questions:
1] On pressing A, byte array data is 2,0,0,0,0,0,0,0,2,0,4,0,0,0,0,0
On pressing AB, byte aray data is 2,0,0,0,0,0,0,0,2,0,4,0,0,0,0,0,2,0,5,0,0,0,0,0
How to convert it into character in java? i.e. get A or AB after conversion.
2] Currently, I am passing fixed size of byte array in above code snippet. For example, if I am expecting 1 char, I am passing 16 as size of byte array, for 2 characters 24 as size and so on. Is there any other elegant solution for making it dynamic?
PS: My byte array converter snippet:
StringBuffer sb = new StringBuffer();
for (byte b : data) {
sb.append(b);
sb.append(",");
}
String byteString = sb.toString();
return byteString;
Thanks for any help
EDIT 1: Full source code here: http://tpcg.io/zt3WfM

Based on the documentation the format should be:
22 00 04 00 00 00 00 00
Offset Size Description
0 Byte Modifier keys status.
1 Byte Reserved field.
2 Byte Keypress #1.
3 Byte Keypress #2.
4 Byte Keypress #3.
5 Byte Keypress #4.
6 Byte Keypress #5.
7 Byte Keypress #6.
Based on the ASCII codes
// 'A' is 0x65
byte codeA = 0x04; // The code for A key
cahr a = 0x61 + codeA ;
byte codeX = 0x1B; // The code for X key
char x = 0x61 + code; // x == 'X'
System.out.println(a);
System.out.println(x);
Or you can use a Map(0x04, 'A')

Related

Why reading a character that has no ASCII representation with System.in doesn't give the character in two bytes?

import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
char ch = '诶';
System.out.println((int)ch);
int c;
while ((c = System.in.read()) != -1)
{
System.out.println(c);
}
}
}
Output:
35830
Here, The value that represents the char 诶 in unicode is 35830. In binary, It'll be 10001011 11110110.
When I enter that character in the terminal, I expected to get two bytes, 10001011 and 11110110. and when combining them again, I can be able to obtain the original char.
But what I actually get is:
232
175
182
10
I can see that 10 represent the newline character. But what does the first 3 numbers mean?
UTF-8 is a multi-byte variable-length encoding.
In order for something reading a stream of bytes to know that there are more bytes to be read in order to finish the current codepoint, there are some values that just cannot occur in a valid UTF-8 byte stream. Basically, certain patterns indicate "hang on, I'm not done".
There's a table which explains it here. For a codepoint in the range U+0800 to U+FFFF, it needs 16 bits to represent it; its byte representation consists of 3 bytes:
1st byte 2nd byte 3rd byte
1110xxxx 10xxxxxx 10xxxxxx
You are seeing 232 175 182 because those are the bytes of the UTF-8 encoding.
byte[] bytes = "诶".getBytes(StandardCharsets.UTF_8);
for (byte b : bytes) {
System.out.println((0xFF & b) + " " + Integer.toString(0xFF & b, 2));
}
Ideone demo
Output:
232 11101000
175 10101111
182 10110110
So the 3 bytes follow the pattern described above.

How do I convert from ASCII to String

I am trying to parse an ascii list to a string. The problem is that with some special chars, I have torubles. If I try to parse this:
115 097 116 195 168 108 194 183 108 105 116
, the result sould be "satèl·lit". The code I am using to parse it is :
ASCIIList.add(Character.toString((char) Integer.parseInt(asciiValue)));
But the result is satèl·lit. I saw that for example "è" -> "195 168". I do not know how to parse it correctly.
Assuming you already have split the input into an array of string, the code could look like so:
String convertToString(String[] numberArray) {
byte[] utf8Bytes = new byte[numberArray.length];
for (int i = 0; i < numberArray.length; i++) {
utf8Bytes[i] = (byte) Integer.parseInt(numberArray[i]);
}
return new String(utf8Bytes, StandardCharsets.UTF_8);
}
So each number becomes a bytes. The entire array of bytes is then converted into a string using UTF-8 charset.
UTF-8 uses multiple bytes to represent characters outside the ASCII range. In your example it affects "è" and "·".

How to easily change String formatted like "20 0F 01" into hex values in Java?

I've found method toHexString() but it converts string into hex, while the value is already converted (like "20 0F 01 etc."). What's the best way to get hex values from this String for later purposes (ex. adding, sending some of them to output device)?
Try
Integer.parseInt(String val, int radix)
Example
Integer.parseInt("-FF", 16) returns -255
https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt(java.lang.String,%20int)
Use String.split() to break the string up into individual bytes, and Integer.parseInt(s, 16) to convert the string representation into an integer.
Something like this should work:
List<Integer> parseHex(String hex) {
ArrayList<Integer> a = new ArrayList<Integer>();
for (String s : hex.split("\\s+")) {
a.add(Integer.parseInt(s, 16));
}
return a;
}
Since you mention preferring a byte array, you can use a ByteBuffer to accumulate byte values:
String text = "20 0F 01";
ByteBuffer buffer = ByteBuffer.allocate((text.length() + 1) / 3);
Scanner scanner = new Scanner(text);
while (scanner.hasNextInt(16)) {
buffer.put((byte) scanner.nextInt(16));
}
byte[] bytes = buffer.array();
We use hasNextInt and nextInt, rather than hasNextByte and nextByte, because Java’s numeric types are signed, and values above 7f are not representable as signed bytes.

Why am i getting 3 bytes instead 1 byte after hexadecimal/string/byte conversion in java?

I have this program:
String hexadecimal = "AF";
byte decimal[] = new byte[hexadecimal.length()/2];
int j = 0;
for ( int i = 0; i < decimal.length; i++)
{
decimal[i] = (byte) Integer.parseInt(hexadecimal.substring(j,j+2),16); //Maybe the problem is this statement
j = j + 2;
}
String s = new String(decimal);
System.out.println("TOTAL LEN: " + s.length());
byte aux[] = s.getBytes();
System.out.println("TOTAL LEN: " + aux.length);
The first total is "1" and the second one is "3", i thought i would will get "1" in the second total. Why is happen this? My intention is generate another hexadecimal string with the same value as the original string (AF), but i am having this issue.
Regards!
P.D. Sorry for my english, let me know if i explained myself well.
Don't know what exactly you try to achieve. But find below what you are doing.
Integer.parseInt(hexadecimal.substring(j, j + 2), 16) returns 175
(byte) 175 is -81
new String(decimal) tries to create an String from this byte array related to your current character set (probably it's UTF-8)
As the byte array does not contain a valid representation of UTF-8 bytes the created String contains the "REPLACEMENT CHARACTER" for the Unicode codepoint U+FFFD. The UTF-8 byte representation for this codepoint is EF BF BD (or -17 -65 -67). That's why the second length is three.
Have a look here Wikipedia UTF-8. Any character with a codepoint <= 7F can be represented by a single byte. For all other characters the first byte must have the bits 7 and 6 set 11....... Which is not the case for the value -81 which is 10101111. There for this is not a valid codepoint and it's replaced with the "REPLACEMENT CHARACTER".

Printing the address of hex string instead of hex string value

I converted a byte array into string by doing
String s = encryptedBytes1.toString();
String gh = convertStringToHex(s);
Then I printed on screen gh which is the hex form it returned this:
gh:[B#5985910
this is the function convert
public static String convertStringToHex(String str){
char[] chars = str.toCharArray();
StringBuffer hex = new StringBuffer();
for(int i = 0; i < chars.length; i++){
hex.append(Integer.toHexString((int)chars[i]));
}
return hex.toString();
}
Can any one help me printing the hex form string?
In general you can convert string and hex values (numbers) with the following functions:
String hexString1 = "0x20";
Integer integer = Integer.decode(hexString); // is 32
String hexString1 = String.toHexString(integer); // is "20"
Now you need to iterate over your byteArray/String.
EDIT: As you specified your question, please see this answer on SO. I guess it is the same problem: Converting A String To Hexadecimal In Java
encryptedBytes1.toString() is giving you a string representation of the object because all arrays are objects in Java it is not converting a byte array into a String.
I think that you are not converting your byte array to String properly. This works for me.
byte encryptedBytes1[] = "ABCDEFGHIK".getBytes();
String aux = new String(encryptedBytes1);
System.out.println(convertStringToHex(aux));
41 42 43 44 45 46 47 48 49 4b
Keep in mind that you may need to specify a charset and that the primitive data byte takes 1 byte and char(which is meant to contain a Unicode Character) takes 2.

Categories