1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.accessorydisplay.sink; 18 19 import java.nio.ByteBuffer; 20 21 /** 22 * Helper for creating USB HID descriptors and reports. 23 */ 24 final class UsbHid { UsbHid()25 private UsbHid() { 26 } 27 28 /** 29 * Generates basic Windows 7 compatible HID multitouch descriptors and reports 30 * that should be supported by recent versions of the Linux hid-multitouch driver. 31 */ 32 public static final class Multitouch { 33 private final int mReportId; 34 private final int mMaxContacts; 35 private final int mWidth; 36 private final int mHeight; 37 Multitouch(int reportId, int maxContacts, int width, int height)38 public Multitouch(int reportId, int maxContacts, int width, int height) { 39 mReportId = reportId; 40 mMaxContacts = maxContacts; 41 mWidth = width; 42 mHeight = height; 43 } 44 generateDescriptor(ByteBuffer buffer)45 public void generateDescriptor(ByteBuffer buffer) { 46 buffer.put(new byte[] { 47 0x05, 0x0d, // USAGE_PAGE (Digitizers) 48 0x09, 0x04, // USAGE (Touch Screen) 49 (byte)0xa1, 0x01, // COLLECTION (Application) 50 (byte)0x85, (byte)mReportId, // REPORT_ID (Touch) 51 0x09, 0x22, // USAGE (Finger) 52 (byte)0xa1, 0x00, // COLLECTION (Physical) 53 0x09, 0x55, // USAGE (Contact Count Maximum) 54 0x15, 0x00, // LOGICAL_MINIMUM (0) 55 0x25, (byte)mMaxContacts, // LOGICAL_MAXIMUM (...) 56 0x75, 0x08, // REPORT_SIZE (8) 57 (byte)0x95, 0x01, // REPORT_COUNT (1) 58 (byte)0xb1, (byte)mMaxContacts, // FEATURE (Data,Var,Abs) 59 0x09, 0x54, // USAGE (Contact Count) 60 (byte)0x81, 0x02, // INPUT (Data,Var,Abs) 61 }); 62 byte maxXLsb = (byte)(mWidth - 1); 63 byte maxXMsb = (byte)((mWidth - 1) >> 8); 64 byte maxYLsb = (byte)(mHeight - 1); 65 byte maxYMsb = (byte)((mHeight - 1) >> 8); 66 byte[] collection = new byte[] { 67 0x05, 0x0d, // USAGE_PAGE (Digitizers) 68 0x09, 0x22, // USAGE (Finger) 69 (byte)0xa1, 0x02, // COLLECTION (Logical) 70 0x09, 0x42, // USAGE (Tip Switch) 71 0x15, 0x00, // LOGICAL_MINIMUM (0) 72 0x25, 0x01, // LOGICAL_MAXIMUM (1) 73 0x75, 0x01, // REPORT_SIZE (1) 74 (byte)0x81, 0x02, // INPUT (Data,Var,Abs) 75 0x09, 0x32, // USAGE (In Range) 76 (byte)0x81, 0x02, // INPUT (Data,Var,Abs) 77 0x09, 0x51, // USAGE (Contact Identifier) 78 0x25, 0x3f, // LOGICAL_MAXIMUM (63) 79 0x75, 0x06, // REPORT_SIZE (6) 80 (byte)0x81, 0x02, // INPUT (Data,Var,Abs) 81 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 82 0x09, 0x30, // USAGE (X) 83 0x26, maxXLsb, maxXMsb, // LOGICAL_MAXIMUM (...) 84 0x75, 0x10, // REPORT_SIZE (16) 85 (byte)0x81, 0x02, // INPUT (Data,Var,Abs) 86 0x09, 0x31, // USAGE (Y) 87 0x26, maxYLsb, maxYMsb, // LOGICAL_MAXIMUM (...) 88 (byte)0x81, 0x02, // INPUT (Data,Var,Abs) 89 (byte)0xc0, // END_COLLECTION 90 }; 91 for (int i = 0; i < mMaxContacts; i++) { 92 buffer.put(collection); 93 } 94 buffer.put(new byte[] { 95 (byte)0xc0, // END_COLLECTION 96 (byte)0xc0, // END_COLLECTION 97 }); 98 } 99 generateReport(ByteBuffer buffer, Contact[] contacts, int contactCount)100 public void generateReport(ByteBuffer buffer, Contact[] contacts, int contactCount) { 101 // Report Id 102 buffer.put((byte)mReportId); 103 // Contact Count 104 buffer.put((byte)contactCount); 105 106 for (int i = 0; i < contactCount; i++) { 107 final Contact contact = contacts[i]; 108 // Tip Switch, In Range, Contact Identifier 109 buffer.put((byte)((contact.id << 2) | 0x03)); 110 // X 111 buffer.put((byte)contact.x).put((byte)(contact.x >> 8)); 112 // Y 113 buffer.put((byte)contact.y).put((byte)(contact.y >> 8)); 114 } 115 for (int i = contactCount; i < mMaxContacts; i++) { 116 buffer.put((byte)0).put((byte)0).put((byte)0).put((byte)0).put((byte)0); 117 } 118 } 119 getReportSize()120 public int getReportSize() { 121 return 2 + mMaxContacts * 5; 122 } 123 124 public static final class Contact { 125 public int id; // range 0..63 126 public int x; 127 public int y; 128 } 129 } 130 } 131