/* * 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; } } }