| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.accessorydisplay.sink; |
| |
| import java.nio.ByteBuffer; |
| |
| /** |
| * Helper for creating USB HID descriptors and reports. |
| */ |
| final class UsbHid { |
| private UsbHid() { |
| } |
| |
| /** |
| * Generates basic Windows 7 compatible HID multitouch descriptors and reports |
| * that should be supported by recent versions of the Linux hid-multitouch driver. |
| */ |
| public static final class Multitouch { |
| private final int mReportId; |
| private final int mMaxContacts; |
| private final int mWidth; |
| private final int mHeight; |
| |
| public Multitouch(int reportId, int maxContacts, int width, int height) { |
| mReportId = reportId; |
| mMaxContacts = maxContacts; |
| mWidth = width; |
| mHeight = height; |
| } |
| |
| public void generateDescriptor(ByteBuffer buffer) { |
| buffer.put(new byte[] { |
| 0x05, 0x0d, // USAGE_PAGE (Digitizers) |
| 0x09, 0x04, // USAGE (Touch Screen) |
| (byte)0xa1, 0x01, // COLLECTION (Application) |
| (byte)0x85, (byte)mReportId, // REPORT_ID (Touch) |
| 0x09, 0x22, // USAGE (Finger) |
| (byte)0xa1, 0x00, // COLLECTION (Physical) |
| 0x09, 0x55, // USAGE (Contact Count Maximum) |
| 0x15, 0x00, // LOGICAL_MINIMUM (0) |
| 0x25, (byte)mMaxContacts, // LOGICAL_MAXIMUM (...) |
| 0x75, 0x08, // REPORT_SIZE (8) |
| (byte)0x95, 0x01, // REPORT_COUNT (1) |
| (byte)0xb1, (byte)mMaxContacts, // FEATURE (Data,Var,Abs) |
| 0x09, 0x54, // USAGE (Contact Count) |
| (byte)0x81, 0x02, // INPUT (Data,Var,Abs) |
| }); |
| byte maxXLsb = (byte)(mWidth - 1); |
| byte maxXMsb = (byte)((mWidth - 1) >> 8); |
| byte maxYLsb = (byte)(mHeight - 1); |
| byte maxYMsb = (byte)((mHeight - 1) >> 8); |
| byte[] collection = new byte[] { |
| 0x05, 0x0d, // USAGE_PAGE (Digitizers) |
| 0x09, 0x22, // USAGE (Finger) |
| (byte)0xa1, 0x02, // COLLECTION (Logical) |
| 0x09, 0x42, // USAGE (Tip Switch) |
| 0x15, 0x00, // LOGICAL_MINIMUM (0) |
| 0x25, 0x01, // LOGICAL_MAXIMUM (1) |
| 0x75, 0x01, // REPORT_SIZE (1) |
| (byte)0x81, 0x02, // INPUT (Data,Var,Abs) |
| 0x09, 0x32, // USAGE (In Range) |
| (byte)0x81, 0x02, // INPUT (Data,Var,Abs) |
| 0x09, 0x51, // USAGE (Contact Identifier) |
| 0x25, 0x3f, // LOGICAL_MAXIMUM (63) |
| 0x75, 0x06, // REPORT_SIZE (6) |
| (byte)0x81, 0x02, // INPUT (Data,Var,Abs) |
| 0x05, 0x01, // USAGE_PAGE (Generic Desktop) |
| 0x09, 0x30, // USAGE (X) |
| 0x26, maxXLsb, maxXMsb, // LOGICAL_MAXIMUM (...) |
| 0x75, 0x10, // REPORT_SIZE (16) |
| (byte)0x81, 0x02, // INPUT (Data,Var,Abs) |
| 0x09, 0x31, // USAGE (Y) |
| 0x26, maxYLsb, maxYMsb, // LOGICAL_MAXIMUM (...) |
| (byte)0x81, 0x02, // INPUT (Data,Var,Abs) |
| (byte)0xc0, // END_COLLECTION |
| }; |
| for (int i = 0; i < mMaxContacts; i++) { |
| buffer.put(collection); |
| } |
| buffer.put(new byte[] { |
| (byte)0xc0, // END_COLLECTION |
| (byte)0xc0, // END_COLLECTION |
| }); |
| } |
| |
| public void generateReport(ByteBuffer buffer, Contact[] contacts, int contactCount) { |
| // Report Id |
| buffer.put((byte)mReportId); |
| // Contact Count |
| buffer.put((byte)contactCount); |
| |
| for (int i = 0; i < contactCount; i++) { |
| final Contact contact = contacts[i]; |
| // Tip Switch, In Range, Contact Identifier |
| buffer.put((byte)((contact.id << 2) | 0x03)); |
| // X |
| buffer.put((byte)contact.x).put((byte)(contact.x >> 8)); |
| // Y |
| buffer.put((byte)contact.y).put((byte)(contact.y >> 8)); |
| } |
| for (int i = contactCount; i < mMaxContacts; i++) { |
| buffer.put((byte)0).put((byte)0).put((byte)0).put((byte)0).put((byte)0); |
| } |
| } |
| |
| public int getReportSize() { |
| return 2 + mMaxContacts * 5; |
| } |
| |
| public static final class Contact { |
| public int id; // range 0..63 |
| public int x; |
| public int y; |
| } |
| } |
| } |