Home | History | Annotate | Download | only in sink
      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 {
     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 
     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 
     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 
    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 
    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