Skip to content

Instantly share code, notes, and snippets.

@royshil
Created December 12, 2013 23:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save royshil/7937573 to your computer and use it in GitHub Desktop.
Save royshil/7937573 to your computer and use it in GitHub Desktop.
Simple HID "driver" for the AIPTEK HyperPen model T-6000U using libHID
/*
* Simple HID "driver" for the AIPTEK HyperPen model T-6000U using libHID
* http://bfoz.github.io/libhid/
*
* The MIT License (MIT)
*
* Copyright (c) 2013 Roy Shilkrot
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include <iostream>
#include <iomanip>
using namespace std;
#include <unistd.h>
#include <ApplicationServices/ApplicationServices.h>
#include <hid.h>
HID::device_type* device;
void printElement(HID::element_type& el) {
cout << "element " << el.name() <<
" report: " << el.reportID() <<
" typeName: " << el.typeName() <<
" usage: " << el.usage() <<
" \n";
if(el.children().size() > 0) {
HID::elements_type& els = el.children();
for (int i = 0; i < els.size(); ++i) {
printElement(*(els[i]));
}
}
}
/**
* Connect to the AIPTEK tablet, using product and vendor IDs from Apple's USB Prober
*/
bool connectLIBHID() {
HID::filter::And filters;
filters.push_back(new HID::filter::vendorID(0x08CA));
filters.push_back(new HID::filter::productID(0x0021));
HID::device_list devices = HID::find(&filters);
if (devices.size()) {
device = devices.front();
cout <<"found device: "<<device->manufacturer()<<"\n";
for (int i = 0; i < device->elements().size(); ++i) {
printElement(*(device->elements()[i]));
}
cout <<"open\n";
if(!device->open(HID::ReadMode)) {
cerr << "cannot open\n"; return false;
} else {
cout << "opened.\n";
return true;
}
}
return false;
}
void disconnectLIBHID() {
cout << "disconnect\n";
// We're finished with the device, so close it
device->close();
}
/**
* Emulate mouse movement and button clicks
* https://developer.apple.com/library/mac/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html#//apple_ref/doc/uid/TP40003550-CH202-BBCFCJGH
*
*/
void mouse(int x, int y, uint32_t mouseButton, bool down) {
CGPoint newloc;
newloc.x = x;
newloc.y = y;
uint32_t mouseType_down = -1, mouseType_up = -1;
if(mouseButton == kCGMouseButtonLeft) {
mouseType_down = kCGEventLeftMouseDown;
mouseType_up = kCGEventLeftMouseUp;
} else {
mouseType_down = kCGEventOtherMouseDown;
mouseType_up = kCGEventOtherMouseUp;
}
CGEventType eventType = down ? mouseType_down : mouseType_up;
CGEventRef eventRef = CGEventCreateMouseEvent(NULL, eventType, newloc, mouseButton);
CGEventSetType(eventRef, eventType);
CGEventPost(kCGSessionEventTap, eventRef);
CFRelease(eventRef);
}
/*
* Change mouse on-screen location
*/
int to(int x, int y, CGEventType eventType)
{
CGPoint newloc;
CGEventRef eventRef;
newloc.x = x;
newloc.y = y;
eventRef = CGEventCreateMouseEvent(NULL, eventType, newloc, kCGMouseButtonLeft);
CGEventSetType(eventRef, eventType);
CGEventPost(kCGSessionEventTap, eventRef);
CFRelease(eventRef);
return 0;
}
int last_buf2 = -1;
/**
* Poll the device for information, which should be flowing steadily
* Parse the buffer for location and button commands
*
* unremark the cout-ings to see some debug info on the console.
*/
void pollLIBHID(void*) {
// cout << "poll: ";tm
HID::buffer_type buffer;
device->read(buffer);
// for (int i = 0; i < buffer.size(); ++i) cout << std::setw(5) << (int)buffer[i];
// cout << "\n";
//buffer[3] and buffer[4] (both uint_8) make a uint16_t with X axis location information,
//same goes for 5 and 6 for the Y axis
int x = ((int)buffer[3] + (int)buffer[4] * 255);
int y = ((int)buffer[5] + (int)buffer[6] * 255);
// cout << "to " << x << " x " << y << "\n";
//buffer[2] states: (learned that simply from looking at the data)
// 0 - pen up (goes away from tablet)
// 192 - pen hovering near tablet
// 193 - pen touching tablet (dragging)
// 194 - pen hovering + low pen button pressed
// 196 - either: pen hover + high button pressed, or pen dragging + low button pressed
if(buffer[2] == 193 && (last_buf2 == 192 || last_buf2 == 0)) //was hovering (or off the tablet) now touching
mouse(x,y,kCGMouseButtonLeft,true); //left button down
else if((buffer[2] == 192 || buffer[2] == 0) && last_buf2 == 193) //now touching, was hovering
mouse(x,y,kCGMouseButtonLeft,false); //left button up
else //else: mouse drag or just move
to(x,y,(buffer[2] == 193)?kCGEventLeftMouseDragged:kCGEventMouseMoved);
last_buf2 = buffer[2];
//TODO: where is the pressure level information? I donno. it must be in another HID report or usage... or - it doesn't exist
//TODO: there's a memory leak, I think. It gets slussigh after working a while
}
/**
* Simple.
*/
int main(int argc, char** argv) {
if(!connectLIBHID()) return 0;
while(true) {
pollLIBHID(NULL);
usleep(1 * 1000);
}
disconnectLIBHID();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment