aboutsummaryrefslogtreecommitdiff
path: root/redist
diff options
context:
space:
mode:
Diffstat (limited to 'redist')
-rw-r--r--redist/CNFGFunctions.c (renamed from redist/DrawFunctions.c)11
-rw-r--r--redist/CNFGFunctions.h (renamed from redist/DrawFunctions.h)6
-rw-r--r--redist/CNFGNullDriver.c74
-rw-r--r--redist/CNFGRasterizer.h247
-rw-r--r--redist/CNFGWinDriver.c (renamed from redist/WinDriver.c)234
-rw-r--r--redist/CNFGXDriver.c (renamed from redist/XDriver.c)16
-rw-r--r--redist/hid-osx.c1111
-rw-r--r--redist/hid-windows.c996
-rw-r--r--redist/hidapi.h405
-rw-r--r--redist/json_helpers.c15
-rw-r--r--redist/json_helpers.h2
-rw-r--r--redist/linmath.c16
-rw-r--r--redist/os_generic.c1
-rw-r--r--redist/symbol_enumerator.c10
14 files changed, 3027 insertions, 117 deletions
diff --git a/redist/DrawFunctions.c b/redist/CNFGFunctions.c
index f4f27d2..947456f 100644
--- a/redist/DrawFunctions.c
+++ b/redist/CNFGFunctions.c
@@ -21,14 +21,13 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
-#include "DrawFunctions.h"
+#include "CNFGFunctions.h"
#include <stdio.h>
int CNFGPenX, CNFGPenY;
uint32_t CNFGBGColor;
uint32_t CNFGLastColor;
uint32_t CNFGDialogColor; //background for boxes
-
const unsigned short FontCharMap[256] = {
65535, 0, 10, 20, 32, 44, 56, 68, 70, 65535, 65535, 80, 92, 65535, 104, 114,
126, 132, 138, 148, 156, 166, 180, 188, 200, 206, 212, 218, 224, 228, 238, 244,
@@ -68,7 +67,7 @@ const unsigned char FontCharData[1902] = {
0x23, 0x14, 0x14, 0x03, 0x10, 0x94, 0x00, 0x01, 0x23, 0x24, 0x04, 0x03, 0x03, 0x21, 0x21, 0xa0,
0x21, 0x10, 0x10, 0x01, 0x01, 0x12, 0x12, 0x03, 0x03, 0x14, 0x14, 0x23, 0x02, 0xa4, 0x10, 0x91,
0x10, 0x01, 0x01, 0x03, 0x03, 0x94, 0x10, 0x21, 0x21, 0x23, 0x23, 0x94, 0x01, 0x23, 0x11, 0x13,
- 0x21, 0x03, 0x02, 0xa2, 0x02, 0x22, 0x11, 0x93, 0x31, 0xc0, 0x03, 0xa1, 0x00, 0x20, 0x20, 0x24,
+ 0x21, 0x03, 0x02, 0xa2, 0x02, 0x22, 0x11, 0x93, 0x04, 0x93, 0x03, 0xa1, 0x00, 0x20, 0x20, 0x24,
0x24, 0x04, 0x04, 0x00, 0x12, 0x92, 0x01, 0x10, 0x10, 0x14, 0x04, 0xa4, 0x01, 0x10, 0x10, 0x21,
0x21, 0x22, 0x22, 0x04, 0x04, 0xa4, 0x00, 0x20, 0x20, 0x24, 0x24, 0x04, 0x12, 0xa2, 0x00, 0x02,
0x02, 0x22, 0x20, 0xa4, 0x20, 0x00, 0x00, 0x02, 0x02, 0x22, 0x22, 0x24, 0x24, 0x84, 0x20, 0x02,
@@ -208,11 +207,7 @@ void CNFGDrawText( const char * text, int scale )
int x2 = (int)((((*(lmap+1)) & 0x70)>>4)*scale + iox);
int y2 = (int)(((*(lmap+1)) & 0x0f)*scale + ioy);
lmap++;
- if(x1 == x2 && y1 == y2){
- CNFGTackPixel( x1, y1 );
- } else {
- CNFGTackSegment( x1, y1, x2, y2 );
- }
+ CNFGTackSegment( x1, y1, x2, y2 );
bQuit = *lmap & 0x80;
lmap++;
} while( !bQuit );
diff --git a/redist/DrawFunctions.h b/redist/CNFGFunctions.h
index 542fcf9..9ecb1bd 100644
--- a/redist/DrawFunctions.h
+++ b/redist/CNFGFunctions.h
@@ -34,7 +34,6 @@ void CNFGClearFrame();
void CNFGSwapBuffers();
void CNFGGetDimensions( short * x, short * y );
-void CNFGTearDown();
void CNFGSetup( const char * WindowName, int w, int h );
void CNFGSetupFullscreen( const char * WindowName, int screen_number );
void CNFGHandleInput();
@@ -44,6 +43,11 @@ void CNFGHandleInput();
void HandleKey( int keycode, int bDown );
void HandleButton( int x, int y, int button, int bDown );
void HandleMotion( int x, int y, int mask );
+void HandleDestroy();
+
+
+//Internal function for resizing rasterizer for rasterizer-mode.
+void CNFGInternalResize( short x, short y ); //don't call this.
#ifdef __cplusplus
diff --git a/redist/CNFGNullDriver.c b/redist/CNFGNullDriver.c
new file mode 100644
index 0000000..34346cc
--- /dev/null
+++ b/redist/CNFGNullDriver.c
@@ -0,0 +1,74 @@
+//Copyright (c) 2017 <>< Charles Lohr - Under the MIT/x11 or NewBSD License you choose.
+
+#include "DrawFunctions.h"
+
+static int w, h;
+void CNFGGetDimensions( short * x, short * y )
+{
+ *x = w;
+ *y = h;
+}
+
+static void InternalLinkScreenAndGo( const char * WindowName )
+{
+}
+
+void CNFGSetupFullscreen( const char * WindowName, int screen_no )
+{
+ CNFGSetup( WindowName, 640, 480 );
+}
+
+
+void CNFGTearDown()
+{
+}
+
+void CNFGSetup( const char * WindowName, int sw, int sh )
+{
+ w = sw;
+ h = sh;
+}
+
+void CNFGHandleInput()
+{
+}
+
+
+void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h )
+{
+}
+
+
+#ifndef RASTERIZER
+
+
+uint32_t CNFGColor( uint32_t RGB )
+{
+}
+
+void CNFGClearFrame()
+{
+}
+
+void CNFGSwapBuffers()
+{
+}
+
+void CNFGTackSegment( short x1, short y1, short x2, short y2 )
+{
+}
+
+void CNFGTackPixel( short x1, short y1 )
+{
+}
+
+void CNFGTackRectangle( short x1, short y1, short x2, short y2 )
+{
+}
+
+void CNFGTackPoly( RDPoint * points, int verts )
+{
+}
+
+#endif
+
diff --git a/redist/CNFGRasterizer.h b/redist/CNFGRasterizer.h
new file mode 100644
index 0000000..1b8e2dd
--- /dev/null
+++ b/redist/CNFGRasterizer.h
@@ -0,0 +1,247 @@
+//Don't call this file yourself. It is intended to be included in any drivers which want to support the rasterizer plugin.
+
+#ifdef RASTERIZER
+#include "CNFGFunctions.h"
+#include <stdlib.h>
+#include <stdint.h>
+
+static uint32_t * buffer = 0;
+static short bufferx;
+static short buffery;
+
+
+void CNFGInternalResize( short x, short y )
+{
+ bufferx = x;
+ buffery = y;
+ if( buffer ) free( buffer );
+ buffer = malloc( bufferx * buffery * 4 );
+}
+
+static uint32_t SWAPS( uint32_t r )
+{
+ uint32_t ret = (r&0xFF)<<16;
+ r>>=8;
+ ret |= (r&0xff)<<8;
+ r>>=8;
+ ret |= r;
+ return ret;
+}
+
+uint32_t CNFGColor( uint32_t RGB )
+{
+ CNFGLastColor = SWAPS(RGB);
+ return CNFGLastColor;
+}
+
+void CNFGTackSegment( short x1, short y1, short x2, short y2 )
+{
+ short tx, ty;
+ float slope, lp;
+
+ short dx = x2 - x1;
+ short dy = y2 - y1;
+
+ if( !buffer ) return;
+
+ if( dx < 0 ) dx = -dx;
+ if( dy < 0 ) dy = -dy;
+
+ if( dx > dy )
+ {
+ short minx = (x1 < x2)?x1:x2;
+ short maxx = (x1 < x2)?x2:x1;
+ short miny = (x1 < x2)?y1:y2;
+ short maxy = (x1 < x2)?y2:y1;
+ float thisy = miny;
+ slope = (float)(maxy-miny) / (float)(maxx-minx);
+
+ for( tx = minx; tx <= maxx; tx++ )
+ {
+ ty = thisy;
+ if( tx < 0 || ty < 0 || ty >= buffery ) continue;
+ if( tx >= bufferx ) break;
+ buffer[ty * bufferx + tx] = CNFGLastColor;
+ thisy += slope;
+ }
+ }
+ else
+ {
+ short minx = (y1 < y2)?x1:x2;
+ short maxx = (y1 < y2)?x2:x1;
+ short miny = (y1 < y2)?y1:y2;
+ short maxy = (y1 < y2)?y2:y1;
+ float thisx = minx;
+ slope = (float)(maxx-minx) / (float)(maxy-miny);
+
+ for( ty = miny; ty <= maxy; ty++ )
+ {
+ tx = thisx;
+ if( ty < 0 || tx < 0 || tx >= bufferx ) continue;
+ if( ty >= buffery ) break;
+ buffer[ty * bufferx + tx] = CNFGLastColor;
+ thisx += slope;
+ }
+ }
+}
+void CNFGTackRectangle( short x1, short y1, short x2, short y2 )
+{
+ short minx = (x1<x2)?x1:x2;
+ short miny = (y1<y2)?y1:y2;
+ short maxx = (x1>=x2)?x1:x2;
+ short maxy = (y1>=y2)?y1:y2;
+
+ short x, y;
+
+ if( minx < 0 ) minx = 0;
+ if( miny < 0 ) miny = 0;
+ if( maxx >= bufferx ) maxx = bufferx-1;
+ if( maxy >= buffery ) maxy = buffery-1;
+
+ for( y = miny; y <= maxy; y++ )
+ {
+ uint32_t * bufferstart = &buffer[y * bufferx + minx];
+ for( x = minx; x <= maxx; x++ )
+ {
+ (*bufferstart++) = CNFGLastColor;
+ }
+ }
+}
+
+void CNFGTackPoly( RDPoint * points, int verts )
+{
+ short minx = 10000, miny = 10000;
+ short maxx =-10000, maxy =-10000;
+ short i, x, y;
+
+ //Just in case...
+ if( verts > 32767 ) return;
+
+ for( i = 0; i < verts; i++ )
+ {
+ RDPoint * p = &points[i];
+ if( p->x < minx ) minx = p->x;
+ if( p->y < miny ) miny = p->y;
+ if( p->x > maxx ) maxx = p->x;
+ if( p->y > maxy ) maxy = p->y;
+ }
+
+ if( miny < 0 ) miny = 0;
+ if( maxy >= buffery ) maxy = buffery-1;
+
+ for( y = miny; y <= maxy; y++ )
+ {
+ short startfillx = maxx;
+ short endfillx = minx;
+
+ //Figure out what line segments intersect this line.
+ for( i = 0; i < verts; i++ )
+ {
+ short pl = i + 1;
+ if( pl == verts ) pl = 0;
+
+ RDPoint ptop;
+ RDPoint pbot;
+
+ ptop.x = points[i].x;
+ ptop.y = points[i].y;
+ pbot.x = points[pl].x;
+ pbot.y = points[pl].y;
+//printf( "Poly: %d %d\n", pbot.y, ptop.y );
+
+ if( pbot.y < ptop.y )
+ {
+ RDPoint ptmp;
+ ptmp.x = pbot.x;
+ ptmp.y = pbot.y;
+ pbot.x = ptop.x;
+ pbot.y = ptop.y;
+ ptop.x = ptmp.x;
+ ptop.y = ptmp.y;
+ }
+
+ //Make sure this line segment is within our range.
+//printf( "PT: %d %d %d\n", y, ptop.y, pbot.y );
+ if( ptop.y <= y && pbot.y >= y )
+ {
+ short diffy = pbot.y - ptop.y;
+ uint32_t placey = (uint32_t)(y - ptop.y)<<16; //Scale by 16 so we can do integer math.
+ short diffx = pbot.x - ptop.x;
+ short isectx;
+
+ if( diffy == 0 )
+ {
+ if( pbot.x < ptop.x )
+ {
+ if( startfillx > pbot.x ) startfillx = pbot.x;
+ if( endfillx < ptop.x ) endfillx = ptop.x;
+ }
+ else
+ {
+ if( startfillx > ptop.x ) startfillx = ptop.x;
+ if( endfillx < pbot.x ) endfillx = pbot.x;
+ }
+ }
+ else
+ {
+ //Inner part is scaled by 65536, outer part must be scaled back.
+ isectx = (( (placey / diffy) * diffx + 32768 )>>16) + ptop.x;
+ if( isectx < startfillx ) startfillx = isectx;
+ if( isectx > endfillx ) endfillx = isectx;
+ }
+//printf( "R: %d %d %d\n", pbot.x, ptop.x, isectx );
+ }
+ }
+
+//printf( "%d %d %d\n", y, startfillx, endfillx );
+
+ if( endfillx >= bufferx ) endfillx = bufferx - 1;
+ if( endfillx >= bufferx ) endfillx = buffery - 1;
+ if( startfillx < 0 ) startfillx = 0;
+ if( startfillx < 0 ) startfillx = 0;
+
+ unsigned int * bufferstart = &buffer[y * bufferx + startfillx];
+ for( x = startfillx; x <= endfillx; x++ )
+ {
+ (*bufferstart++) = CNFGLastColor;
+ }
+ }
+//exit(1);
+}
+
+
+void CNFGClearFrame()
+{
+ int i, m;
+ uint32_t col = 0;
+ short x, y;
+ CNFGGetDimensions( &x, &y );
+ if( x != bufferx || y != buffery || !buffer )
+ {
+ bufferx = x;
+ buffery = y;
+ buffer = malloc( x * y * 8 );
+ }
+
+ m = x * y;
+ col = CNFGColor( CNFGBGColor );
+ for( i = 0; i < m; i++ )
+ {
+//printf( "Got: %d %p %d\n", m, buffer, i );
+ buffer[i] = col;
+ }
+}
+
+void CNFGTackPixel( short x, short y )
+{
+ if( x < 0 || y < 0 || x >= bufferx || y >= buffery ) return;
+ buffer[x+bufferx*y] = CNFGLastColor;
+}
+
+void CNFGSwapBuffers()
+{
+ CNFGUpdateScreenWithBitmap( (long unsigned int*)buffer, bufferx, buffery );
+}
+
+
+#endif
diff --git a/redist/WinDriver.c b/redist/CNFGWinDriver.c
index a6dd1e6..a029419 100644
--- a/redist/WinDriver.c
+++ b/redist/CNFGWinDriver.c
@@ -2,80 +2,54 @@
//Portion from: http://en.wikibooks.org/wiki/Windows_Programming/Window_Creation
-#include "DrawFunctions.h"
+#include "CNFGFunctions.h"
#include <windows.h>
#include <stdlib.h>
#include <malloc.h> //for alloca
+static HBITMAP lsBitmap;
static HINSTANCE lhInstance;
static HWND lsHWND;
-static HDC lsHDC;
-static HBITMAP lsBackBitmap;
static HDC lsWindowHDC;
-static HBRUSH lsHBR;
-static HPEN lsHPEN;
-static HBRUSH lsClearBrush;
-static unsigned int lsLastWidth;
-static unsigned int lsLastHeight;
+static HDC lsHDC;
-static void InternalHandleResize()
-{
- DeleteObject( lsBackBitmap );
- lsBackBitmap = CreateCompatibleBitmap( lsHDC, lsLastWidth, lsLastHeight );
- SelectObject( lsHDC, lsBackBitmap );
-}
+#ifdef RASTERIZER
+#include "CNFGRasterizer.h"
-uint32_t CNFGColor( uint32_t RGB )
+void InternalHandleResize()
{
- CNFGLastColor = RGB;
-
- DeleteObject( lsHBR );
- lsHBR = CreateSolidBrush( RGB );
- SelectObject( lsHDC, lsHBR );
+ if( lsBitmap ) DeleteObject( lsBitmap );
- DeleteObject( lsHPEN );
- lsHPEN = CreatePen( PS_SOLID, 0, RGB );
- SelectObject( lsHDC, lsHPEN );
-
- return RGB;
+ CNFGInternalResize( bufferx, buffery );
+ lsBitmap = CreateBitmap( bufferx, buffery, 1, 32, buffer );
+ SelectObject( lsHDC, lsBitmap );
}
+#else
+static int bufferx, buffery;
+static int bufferx, buffery;
+static void InternalHandleResize();
+#endif
-void CNFGTackSegment( short x1, short y1, short x2, short y2 )
-{
- POINT pt[2] = { {x1, y1}, {x2, y2} };
- Polyline( lsHDC, pt, 2 );
- SetPixel( lsHDC, x1, y1, CNFGLastColor );
- SetPixel( lsHDC, x2, y2, CNFGLastColor );
-}
-void CNFGTackRectangle( short x1, short y1, short x2, short y2 )
+void CNFGGetDimensions( short * x, short * y )
{
- RECT r;
- if( x1 < x2 ) { r.left = x1; r.right = x2; }
- else { r.left = x2; r.right = x1; }
- if( y1 < y2 ) { r.top = y1; r.bottom = y2; }
- else { r.top = y2; r.bottom = y1; }
- FillRect( lsHDC, &r, lsHBR );
+ *x = bufferx;
+ *y = buffery;
}
-void CNFGClearFrame()
-{
- RECT r = { 0, 0, lsLastWidth, lsLastHeight };
- DeleteObject( lsClearBrush );
- lsClearBrush = CreateSolidBrush( CNFGBGColor );
- SelectObject( lsHDC, lsClearBrush );
- FillRect( lsHDC, &r, lsClearBrush );
-}
-void CNFGSwapBuffers()
+void CNFGUpdateScreenWithBitmap( unsigned long * data, int w, int h )
{
- int thisw, thish;
RECT r;
- BitBlt( lsWindowHDC, 0, 0, lsLastWidth, lsLastHeight, lsHDC, 0, 0, SRCCOPY );
+
+ int a = SetBitmapBits(lsBitmap,w*h*4,data);
+ a = BitBlt(lsWindowHDC, 0, 0, w, h, lsHDC, 0, 0, SRCCOPY);
UpdateWindow( lsHWND );
+ int thisw, thish;
+
//Check to see if the window is closed.
if( !IsWindow( lsHWND ) )
{
@@ -85,36 +59,18 @@ void CNFGSwapBuffers()
GetClientRect( lsHWND, &r );
thisw = r.right - r.left;
thish = r.bottom - r.top;
- if( thisw != lsLastWidth || thish != lsLastHeight )
+ if( thisw != bufferx || thish != buffery )
{
- lsLastWidth = thisw;
- lsLastHeight = thish;
+ bufferx = thisw;
+ buffery = thish;
InternalHandleResize();
}
}
-void CNFGTackPoly( RDPoint * points, int verts )
-{
- int i;
- POINT * t = (POINT*)alloca( sizeof( POINT ) * verts );
- for( i = 0; i < verts; i++ )
- {
- t[i].x = points[i].x;
- t[i].y = points[i].y;
- }
- Polygon( lsHDC, t, verts );
-}
-
-
-void CNFGTackPixel( short x1, short y1 )
-{
- SetPixel( lsHDC, x1, y1, CNFGLastColor );
-}
-void CNFGGetDimensions( short * x, short * y )
+void CNFGTearDown()
{
- *x = lsLastWidth;
- *y = lsLastHeight;
+ PostQuitMessage(0);
}
//This was from the article
@@ -123,17 +79,13 @@ LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
switch(msg)
{
case WM_DESTROY:
+ HandleDestroy();
CNFGTearDown();
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
-void CNFGTearDown()
-{
- PostQuitMessage(0);
-}
-
//This was from the article, too... well, mostly.
void CNFGSetup( const char * name_of_window, int width, int height )
{
@@ -143,8 +95,8 @@ void CNFGSetup( const char * name_of_window, int width, int height )
int w, h, wd, hd;
HINSTANCE hInstance = GetModuleHandle(NULL);
- lsLastWidth = width;
- lsLastHeight = height;
+ bufferx = width;
+ buffery = height;
wnd.style = CS_HREDRAW | CS_VREDRAW; //we will explain this later
wnd.lpfnWndProc = MyWndProc;
@@ -167,8 +119,8 @@ void CNFGSetup( const char * name_of_window, int width, int height )
WS_OVERLAPPEDWINDOW, //basic window style
CW_USEDEFAULT,
CW_USEDEFAULT, //set starting point to default value
- lsLastWidth,
- lsLastHeight, //set all the dimensions to default value
+ bufferx,
+ buffery, //set all the dimensions to default value
NULL, //no parent window
NULL, //no menu
hInstance,
@@ -176,13 +128,14 @@ void CNFGSetup( const char * name_of_window, int width, int height )
lsWindowHDC = GetDC( lsHWND );
+
lsHDC = CreateCompatibleDC( lsWindowHDC );
- lsBackBitmap = CreateCompatibleBitmap( lsWindowHDC, lsLastWidth, lsLastHeight );
- SelectObject( lsHDC, lsBackBitmap );
+ lsBitmap = CreateCompatibleBitmap( lsWindowHDC, bufferx, buffery );
+ SelectObject( lsHDC, lsBitmap );
- lsClearBrush = CreateSolidBrush( CNFGBGColor );
- lsHBR = CreateSolidBrush( 0xFFFFFF );
- lsHPEN = CreatePen( PS_SOLID, 0, 0xFFFFFF );
+ //lsClearBrush = CreateSolidBrush( CNFGBGColor );
+ //lsHBR = CreateSolidBrush( 0xFFFFFF );
+ //lsHPEN = CreatePen( PS_SOLID, 0, 0xFFFFFF );
ShowWindow(lsHWND, 1); //display the window on the screen
@@ -193,7 +146,7 @@ void CNFGSetup( const char * name_of_window, int width, int height )
h = ( window.bottom - window.top);
wd = w - client.right;
hd = h - client.bottom;
- MoveWindow( lsHWND, window.left, window.top, lsLastWidth + wd, lsLastHeight + hd, 1 );
+ MoveWindow( lsHWND, window.left, window.top, bufferx + wd, buffery + hd, 1 );
InternalHandleResize();
}
@@ -229,3 +182,108 @@ void CNFGHandleInput()
}
}
+
+#ifndef RASTERIZER
+
+static HBITMAP lsBackBitmap;
+static HDC lsWindowHDC;
+static HBRUSH lsHBR;
+static HPEN lsHPEN;
+static HBRUSH lsClearBrush;
+
+static void InternalHandleResize()
+{
+ DeleteObject( lsBackBitmap );
+ lsBackBitmap = CreateCompatibleBitmap( lsHDC, bufferx, buffery );
+ SelectObject( lsHDC, lsBackBitmap );
+}
+
+uint32_t CNFGColor( uint32_t RGB )
+{
+ CNFGLastColor = RGB;
+
+ DeleteObject( lsHBR );
+ lsHBR = CreateSolidBrush( RGB );
+ SelectObject( lsHDC, lsHBR );
+
+ DeleteObject( lsHPEN );
+ lsHPEN = CreatePen( PS_SOLID, 0, RGB );
+ SelectObject( lsHDC, lsHPEN );
+
+ return RGB;
+}
+
+void CNFGTackSegment( short x1, short y1, short x2, short y2 )
+{
+ POINT pt[2] = { {x1, y1}, {x2, y2} };
+ Polyline( lsHDC, pt, 2 );
+ SetPixel( lsHDC, x1, y1, CNFGLastColor );
+ SetPixel( lsHDC, x2, y2, CNFGLastColor );
+}
+
+void CNFGTackRectangle( short x1, short y1, short x2, short y2 )
+{
+ RECT r;
+ if( x1 < x2 ) { r.left = x1; r.right = x2; }
+ else { r.left = x2; r.right = x1; }
+ if( y1 < y2 ) { r.top = y1; r.bottom = y2; }
+ else { r.top = y2; r.bottom = y1; }
+ FillRect( lsHDC, &r, lsHBR );
+}
+
+void CNFGClearFrame()
+{
+ RECT r = { 0, 0, bufferx, buffery };
+ DeleteObject( lsClearBrush );
+ lsClearBrush = CreateSolidBrush( CNFGBGColor );
+ SelectObject( lsHDC, lsClearBrush );
+
+ FillRect( lsHDC, &r, lsClearBrush );
+}
+
+void CNFGTackPoly( RDPoint * points, int verts )
+{
+ int i;
+ POINT * t = (POINT*)alloca( sizeof( POINT ) * verts );
+ for( i = 0; i < verts; i++ )
+ {
+ t[i].x = points[i].x;
+ t[i].y = points[i].y;
+ }
+ Polygon( lsHDC, t, verts );
+}
+
+
+void CNFGTackPixel( short x1, short y1 )
+{
+ SetPixel( lsHDC, x1, y1, CNFGLastColor );
+}
+
+void CNFGSwapBuffers()
+{
+ int thisw, thish;
+
+ RECT r;
+ BitBlt( lsWindowHDC, 0, 0, bufferx, buffery, lsHDC, 0, 0, SRCCOPY );
+ UpdateWindow( lsHWND );
+ //Check to see if the window is closed.
+ if( !IsWindow( lsHWND ) )
+ {
+ exit( 0 );
+ }
+
+ GetClientRect( lsHWND, &r );
+ thisw = r.right - r.left;
+ thish = r.bottom - r.top;
+
+ if( thisw != bufferx || thish != buffery )
+ {
+ bufferx = thisw;
+ buffery = thish;
+ InternalHandleResize();
+ }
+}
+
+void CNFGInternalResize( short bufferx, short buffery ) { }
+#endif
+
diff --git a/redist/XDriver.c b/redist/CNFGXDriver.c
index 507ca95..8a8904a 100644
--- a/redist/XDriver.c
+++ b/redist/CNFGXDriver.c
@@ -4,7 +4,7 @@
//#define HAS_XINERAMA
-#include "DrawFunctions.h"
+#include "CNFGFunctions.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -29,8 +29,18 @@ int FullScreen = 0;
void CNFGGetDimensions( short * x, short * y )
{
+ static int lastx;
+ static int lasty;
+
*x = CNFGWinAtt.width;
*y = CNFGWinAtt.height;
+
+ if( lastx != *x || lasty != *y )
+ {
+ lastx = *x;
+ lasty = *y;
+ CNFGInternalResize( lastx, lasty );
+ }
}
static void InternalLinkScreenAndGo( const char * WindowName )
@@ -286,5 +296,9 @@ void CNFGTackPoly( RDPoint * points, int verts )
XFillPolygon(CNFGDisplay, CNFGPixmap, CNFGGC, (XPoint *)points, 3, Convex, CoordModeOrigin );
}
+void CNFGInternalResize( short x, short y ) { }
+
+#else
+#include "CNFGRasterizer.h"
#endif
diff --git a/redist/hid-osx.c b/redist/hid-osx.c
new file mode 100644
index 0000000..57a337c
--- /dev/null
+++ b/redist/hid-osx.c
@@ -0,0 +1,1111 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 2010-07-03
+
+ Copyright 2010, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/* See Apple Technical Note TN2187 for details on IOHidManager. */
+
+#include <IOKit/hid/IOHIDManager.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/IOKitLib.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <wchar.h>
+#include <locale.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <dlfcn.h>
+
+#include "hidapi.h"
+
+/* Barrier implementation because Mac OSX doesn't have pthread_barrier.
+ It also doesn't have clock_gettime(). So much for POSIX and SUSv2.
+ This implementation came from Brent Priddy and was posted on
+ StackOverflow. It is used with his permission. */
+typedef int pthread_barrierattr_t;
+typedef struct pthread_barrier {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int count;
+ int trip_count;
+} pthread_barrier_t;
+
+static int pthread_barrier_init(pthread_barrier_t *barrier, const pthread_barrierattr_t *attr, unsigned int count)
+{
+ if(count == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if(pthread_mutex_init(&barrier->mutex, 0) < 0) {
+ return -1;
+ }
+ if(pthread_cond_init(&barrier->cond, 0) < 0) {
+ pthread_mutex_destroy(&barrier->mutex);
+ return -1;
+ }
+ barrier->trip_count = count;
+ barrier->count = 0;
+
+ return 0;
+}
+
+static int pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_cond_destroy(&barrier->cond);
+ pthread_mutex_destroy(&barrier->mutex);
+ return 0;
+}
+
+static int pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ pthread_mutex_lock(&barrier->mutex);
+ ++(barrier->count);
+ if(barrier->count >= barrier->trip_count)
+ {
+ barrier->count = 0;
+ pthread_cond_broadcast(&barrier->cond);
+ pthread_mutex_unlock(&barrier->mutex);
+ return 1;
+ }
+ else
+ {
+ pthread_cond_wait(&barrier->cond, &(barrier->mutex));
+ pthread_mutex_unlock(&barrier->mutex);
+ return 0;
+ }
+}
+
+static int return_data(hid_device *dev, unsigned char *data, size_t length);
+
+/* Linked List of input reports received from the device. */
+struct input_report {
+ uint8_t *data;
+ size_t len;
+ struct input_report *next;
+};
+
+struct hid_device_ {
+ IOHIDDeviceRef device_handle;
+ int blocking;
+ int uses_numbered_reports;
+ int disconnected;
+ CFStringRef run_loop_mode;
+ CFRunLoopRef run_loop;
+ CFRunLoopSourceRef source;
+ uint8_t *input_report_buf;
+ CFIndex max_input_report_len;
+ struct input_report *input_reports;
+
+ pthread_t thread;
+ pthread_mutex_t mutex; /* Protects input_reports */
+ pthread_cond_t condition;
+ pthread_barrier_t barrier; /* Ensures correct startup sequence */
+ pthread_barrier_t shutdown_barrier; /* Ensures correct shutdown sequence */
+ int shutdown_thread;
+};
+
+static hid_device *new_hid_device(void)
+{
+ hid_device *dev = calloc(1, sizeof(hid_device));
+ dev->device_handle = NULL;
+ dev->blocking = 1;
+ dev->uses_numbered_reports = 0;
+ dev->disconnected = 0;
+ dev->run_loop_mode = NULL;
+ dev->run_loop = NULL;
+ dev->source = NULL;
+ dev->input_report_buf = NULL;
+ dev->input_reports = NULL;
+ dev->shutdown_thread = 0;
+
+ /* Thread objects */
+ pthread_mutex_init(&dev->mutex, NULL);
+ pthread_cond_init(&dev->condition, NULL);
+ pthread_barrier_init(&dev->barrier, NULL, 2);
+ pthread_barrier_init(&dev->shutdown_barrier, NULL, 2);
+
+ return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+ if (!dev)
+ return;
+
+ /* Delete any input reports still left over. */
+ struct input_report *rpt = dev->input_reports;
+ while (rpt) {
+ struct input_report *next = rpt->next;
+ free(rpt->data);
+ free(rpt);
+ rpt = next;
+ }
+
+ /* Free the string and the report buffer. The check for NULL
+ is necessary here as CFRelease() doesn't handle NULL like
+ free() and others do. */
+ if (dev->run_loop_mode)
+ CFRelease(dev->run_loop_mode);
+ if (dev->source)
+ CFRelease(dev->source);
+ free(dev->input_report_buf);
+
+ /* Clean up the thread objects */
+ pthread_barrier_destroy(&dev->shutdown_barrier);
+ pthread_barrier_destroy(&dev->barrier);
+ pthread_cond_destroy(&dev->condition);
+ pthread_mutex_destroy(&dev->mutex);
+
+ /* Free the structure itself. */
+ free(dev);
+}
+
+static IOHIDManagerRef hid_mgr = 0x0;
+
+
+#if 0
+static void register_error(hid_device *device, const char *op)
+{
+
+}
+#endif
+
+
+static int32_t get_int_property(IOHIDDeviceRef device, CFStringRef key)
+{
+ CFTypeRef ref;
+ int32_t value;
+
+ ref = IOHIDDeviceGetProperty(device, key);
+ if (ref) {
+ if (CFGetTypeID(ref) == CFNumberGetTypeID()) {
+ CFNumberGetValue((CFNumberRef) ref, kCFNumberSInt32Type, &value);
+ return value;
+ }
+ }
+ return 0;
+}
+
+static unsigned short get_vendor_id(IOHIDDeviceRef device)
+{
+ return get_int_property(device, CFSTR(kIOHIDVendorIDKey));
+}
+
+static unsigned short get_product_id(IOHIDDeviceRef device)
+{
+ return get_int_property(device, CFSTR(kIOHIDProductIDKey));
+}
+
+static int32_t get_max_report_length(IOHIDDeviceRef device)
+{
+ return get_int_property(device, CFSTR(kIOHIDMaxInputReportSizeKey));
+}
+
+static int get_string_property(IOHIDDeviceRef device, CFStringRef prop, wchar_t *buf, size_t len)
+{
+ CFStringRef str;
+
+ if (!len)
+ return 0;
+
+ str = IOHIDDeviceGetProperty(device, prop);
+
+ buf[0] = 0;
+
+ if (str) {
+ CFIndex str_len = CFStringGetLength(str);
+ CFRange range;
+ CFIndex used_buf_len;
+ CFIndex chars_copied;
+
+ len --;
+
+ range.location = 0;
+ range.length = ((size_t)str_len > len)? len: (size_t)str_len;
+ chars_copied = CFStringGetBytes(str,
+ range,
+ kCFStringEncodingUTF32LE,
+ (char)'?',
+ FALSE,
+ (UInt8*)buf,
+ len * sizeof(wchar_t),
+ &used_buf_len);
+
+ if (chars_copied == len)
+ buf[len] = 0; /* len is decremented above */
+ else
+ buf[chars_copied] = 0;
+
+ return 0;
+ }
+ else
+ return -1;
+
+}
+
+static int get_serial_number(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+ return get_string_property(device, CFSTR(kIOHIDSerialNumberKey), buf, len);
+}
+
+static int get_manufacturer_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+ return get_string_property(device, CFSTR(kIOHIDManufacturerKey), buf, len);
+}
+
+static int get_product_string(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+ return get_string_property(device, CFSTR(kIOHIDProductKey), buf, len);
+}
+
+
+/* Implementation of wcsdup() for Mac. */
+static wchar_t *dup_wcs(const wchar_t *s)
+{
+ size_t len = wcslen(s);
+ wchar_t *ret = malloc((len+1)*sizeof(wchar_t));
+ wcscpy(ret, s);
+
+ return ret;
+}
+
+/* hidapi_IOHIDDeviceGetService()
+ *
+ * Return the io_service_t corresponding to a given IOHIDDeviceRef, either by:
+ * - on OS X 10.6 and above, calling IOHIDDeviceGetService()
+ * - on OS X 10.5, extract it from the IOHIDDevice struct
+ */
+static io_service_t hidapi_IOHIDDeviceGetService(IOHIDDeviceRef device)
+{
+ static void *iokit_framework = NULL;
+ static io_service_t (*dynamic_IOHIDDeviceGetService)(IOHIDDeviceRef device) = NULL;
+
+ /* Use dlopen()/dlsym() to get a pointer to IOHIDDeviceGetService() if it exists.
+ * If any of these steps fail, dynamic_IOHIDDeviceGetService will be left NULL
+ * and the fallback method will be used.
+ */
+ if (iokit_framework == NULL) {
+ iokit_framework = dlopen("/System/Library/IOKit.framework/IOKit", RTLD_LAZY);
+
+ if (iokit_framework != NULL)
+ dynamic_IOHIDDeviceGetService = dlsym(iokit_framework, "IOHIDDeviceGetService");
+ }
+
+ if (dynamic_IOHIDDeviceGetService != NULL) {
+ /* Running on OS X 10.6 and above: IOHIDDeviceGetService() exists */
+ return dynamic_IOHIDDeviceGetService(device);
+ }
+ else
+ {
+ /* Running on OS X 10.5: IOHIDDeviceGetService() doesn't exist.
+ *
+ * Be naughty and pull the service out of the IOHIDDevice.
+ * IOHIDDevice is an opaque struct not exposed to applications, but its
+ * layout is stable through all available versions of OS X.
+ * Tested and working on OS X 10.5.8 i386, x86_64, and ppc.
+ */
+ struct IOHIDDevice_internal {
+ /* The first field of the IOHIDDevice struct is a
+ * CFRuntimeBase (which is a private CF struct).
+ *
+ * a, b, and c are the 3 fields that make up a CFRuntimeBase.
+ * See http://opensource.apple.com/source/CF/CF-476.18/CFRuntime.h
+ *
+ * The second field of the IOHIDDevice is the io_service_t we're looking for.
+ */
+ uintptr_t a;
+ uint8_t b[4];
+#if __LP64__
+ uint32_t c;
+#endif
+ io_service_t service;
+ };
+ struct IOHIDDevice_internal *tmp = (struct IOHIDDevice_internal *)device;
+
+ return tmp->service;
+ }
+}
+
+/* Initialize the IOHIDManager. Return 0 for success and -1 for failure. */
+static int init_hid_manager(void)
+{
+ /* Initialize all the HID Manager Objects */
+ hid_mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+ if (hid_mgr) {
+ IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
+ IOHIDManagerScheduleWithRunLoop(hid_mgr, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ return 0;
+ }
+
+ return -1;
+}
+
+/* Initialize the IOHIDManager if necessary. This is the public function, and
+ it is safe to call this function repeatedly. Return 0 for success and -1
+ for failure. */
+int HID_API_EXPORT hid_init(void)
+{
+ if (!hid_mgr) {
+ return init_hid_manager();
+ }
+
+ /* Already initialized. */
+ return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+ if (hid_mgr) {
+ /* Close the HID manager. */
+ IOHIDManagerClose(hid_mgr, kIOHIDOptionsTypeNone);
+ CFRelease(hid_mgr);
+ hid_mgr = NULL;
+ }
+
+ return 0;
+}
+
+static void process_pending_events(void) {
+ SInt32 res;
+ do {
+ res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.001, FALSE);
+ } while(res != kCFRunLoopRunFinished && res != kCFRunLoopRunTimedOut);
+}
+
+struct hid_device_info HID_API_EXPORT *hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+ struct hid_device_info *root = NULL; /* return object */
+ struct hid_device_info *cur_dev = NULL;
+ CFIndex num_devices;
+ int i;
+
+ /* Set up the HID Manager if it hasn't been done */
+ if (hid_init() < 0)
+ return NULL;
+
+ /* give the IOHIDManager a chance to update itself */
+ process_pending_events();
+
+ /* Get a list of the Devices */
+ IOHIDManagerSetDeviceMatching(hid_mgr, NULL);
+ CFSetRef device_set = IOHIDManagerCopyDevices(hid_mgr);
+
+ /* Convert the list into a C array so we can iterate easily. */
+ num_devices = CFSetGetCount(device_set);
+ IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
+ CFSetGetValues(device_set, (const void **) device_array);
+
+ /* Iterate over each device, making an entry for it. */
+ for (i = 0; i < num_devices; i++) {
+ unsigned short dev_vid;
+ unsigned short dev_pid;
+ #define BUF_LEN 256
+ wchar_t buf[BUF_LEN];
+
+ IOHIDDeviceRef dev = device_array[i];
+
+ if (!dev) {
+ continue;
+ }
+ dev_vid = get_vendor_id(dev);
+ dev_pid = get_product_id(dev);
+
+ /* Check the VID/PID against the arguments */
+ if ((vendor_id == 0x0 || vendor_id == dev_vid) &&
+ (product_id == 0x0 || product_id == dev_pid)) {
+ struct hid_device_info *tmp;
+ io_object_t iokit_dev;
+ kern_return_t res;
+ io_string_t path;
+
+ /* VID/PID match. Create the record. */
+ tmp = malloc(sizeof(struct hid_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ }
+ else {
+ root = tmp;
+ }
+ cur_dev = tmp;
+
+ /* Get the Usage Page and Usage for this device. */
+ cur_dev->usage_page = get_int_property(dev, CFSTR(kIOHIDPrimaryUsagePageKey));
+ cur_dev->usage = get_int_property(dev, CFSTR(kIOHIDPrimaryUsageKey));
+
+ /* Fill out the record */
+ cur_dev->next = NULL;
+
+ /* Fill in the path (IOService plane) */
+ iokit_dev = hidapi_IOHIDDeviceGetService(dev);
+ res = IORegistryEntryGetPath(iokit_dev, kIOServicePlane, path);
+ if (res == KERN_SUCCESS)
+ cur_dev->path = strdup(path);
+ else
+ cur_dev->path = strdup("");
+
+ /* Serial Number */
+ get_serial_number(dev, buf, BUF_LEN);
+ cur_dev->serial_number = dup_wcs(buf);
+
+ /* Manufacturer and Product strings */
+ get_manufacturer_string(dev, buf, BUF_LEN);
+ cur_dev->manufacturer_string = dup_wcs(buf);
+ get_product_string(dev, buf, BUF_LEN);
+ cur_dev->product_string = dup_wcs(buf);
+
+ /* VID/PID */
+ cur_dev->vendor_id = dev_vid;
+ cur_dev->product_id = dev_pid;
+
+ /* Release Number */
+ cur_dev->release_number = get_int_property(dev, CFSTR(kIOHIDVersionNumberKey));
+
+ /* Interface Number (Unsupported on Mac)*/
+ cur_dev->interface_number = -1;
+ }
+ }
+
+ free(device_array);
+ CFRelease(device_set);
+
+ return root;
+}
+
+void HID_API_EXPORT hid_free_enumeration(struct hid_device_info *devs)
+{
+ /* This function is identical to the Linux version. Platform independent. */
+ struct hid_device_info *d = devs;
+ while (d) {
+ struct hid_device_info *next = d->next;
+ free(d->path);
+ free(d->serial_number);
+ free(d->manufacturer_string);
+ free(d->product_string);
+ free(d);
+ d = next;
+ }
+}
+
+hid_device * HID_API_EXPORT hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+ /* This function is identical to the Linux version. Platform independent. */
+ struct hid_device_info *devs, *cur_dev;
+ const char *path_to_open = NULL;
+ hid_device * handle = NULL;
+
+ devs = hid_enumerate(vendor_id, product_id);
+ cur_dev = devs;
+ while (cur_dev) {
+ if (cur_dev->vendor_id == vendor_id &&
+ cur_dev->product_id == product_id) {
+ if (serial_number) {
+ if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ else {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open) {
+ /* Open the device */
+ handle = hid_open_path(path_to_open);
+ }
+
+ hid_free_enumeration(devs);
+
+ return handle;
+}
+
+static void hid_device_removal_callback(void *context, IOReturn result,
+ void *sender)
+{
+ /* Stop the Run Loop for this device. */
+ hid_device *d = context;
+
+ d->disconnected = 1;
+ CFRunLoopStop(d->run_loop);
+}
+
+/* The Run Loop calls this function for each input report received.
+ This function puts the data into a linked list to be picked up by
+ hid_read(). */
+static void hid_report_callback(void *context, IOReturn result, void *sender,
+ IOHIDReportType report_type, uint32_t report_id,
+ uint8_t *report, CFIndex report_length)
+{
+ struct input_report *rpt;
+ hid_device *dev = context;
+
+ /* Make a new Input Report object */
+ rpt = calloc(1, sizeof(struct input_report));
+ rpt->data = calloc(1, report_length);
+ memcpy(rpt->data, report, report_length);
+ rpt->len = report_length;
+ rpt->next = NULL;
+
+ /* Lock this section */
+ pthread_mutex_lock(&dev->mutex);
+
+ /* Attach the new report object to the end of the list. */
+ if (dev->input_reports == NULL) {
+ /* The list is empty. Put it at the root. */
+ dev->input_reports = rpt;
+ }
+ else {
+ /* Find the end of the list and attach. */
+ struct input_report *cur = dev->input_reports;
+ int num_queued = 0;
+ while (cur->next != NULL) {
+ cur = cur->next;
+ num_queued++;
+ }
+ cur->next = rpt;
+
+ /* Pop one off if we've reached 30 in the queue. This
+ way we don't grow forever if the user never reads
+ anything from the device. */
+ if (num_queued > 30) {
+ return_data(dev, NULL, 0);
+ }
+ }
+
+ /* Signal a waiting thread that there is data. */
+ pthread_cond_signal(&dev->condition);
+
+ /* Unlock */
+ pthread_mutex_unlock(&dev->mutex);
+
+}
+
+/* This gets called when the read_thread's run loop gets signaled by
+ hid_close(), and serves to stop the read_thread's run loop. */
+static void perform_signal_callback(void *context)
+{
+ hid_device *dev = context;
+ CFRunLoopStop(dev->run_loop); /*TODO: CFRunLoopGetCurrent()*/
+}
+
+static void *read_thread(void *param)
+{
+ hid_device *dev = param;
+ SInt32 code;
+
+ /* Move the device's run loop to this thread. */
+ IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetCurrent(), dev->run_loop_mode);
+
+ /* Create the RunLoopSource which is used to signal the
+ event loop to stop when hid_close() is called. */
+ CFRunLoopSourceContext ctx;
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.version = 0;
+ ctx.info = dev;
+ ctx.perform = &perform_signal_callback;
+ dev->source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0/*order*/, &ctx);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), dev->source, dev->run_loop_mode);
+
+ /* Store off the Run Loop so it can be stopped from hid_close()
+ and on device disconnection. */
+ dev->run_loop = CFRunLoopGetCurrent();
+
+ /* Notify the main thread that the read thread is up and running. */
+ pthread_barrier_wait(&dev->barrier);
+
+ /* Run the Event Loop. CFRunLoopRunInMode() will dispatch HID input
+ reports into the hid_report_callback(). */
+ while (!dev->shutdown_thread && !dev->disconnected) {
+ code = CFRunLoopRunInMode(dev->run_loop_mode, 1000/*sec*/, FALSE);
+ /* Return if the device has been disconnected */
+ if (code == kCFRunLoopRunFinished) {
+ dev->disconnected = 1;
+ break;
+ }
+
+
+ /* Break if The Run Loop returns Finished or Stopped. */
+ if (code != kCFRunLoopRunTimedOut &&
+ code != kCFRunLoopRunHandledSource) {
+ /* There was some kind of error. Setting
+ shutdown seems to make sense, but
+ there may be something else more appropriate */
+ dev->shutdown_thread = 1;
+ break;
+ }
+ }
+
+ /* Now that the read thread is stopping, Wake any threads which are
+ waiting on data (in hid_read_timeout()). Do this under a mutex to
+ make sure that a thread which is about to go to sleep waiting on
+ the condition actually will go to sleep before the condition is
+ signaled. */
+ pthread_mutex_lock(&dev->mutex);
+ pthread_cond_broadcast(&dev->condition);
+ pthread_mutex_unlock(&dev->mutex);
+
+ /* Wait here until hid_close() is called and makes it past
+ the call to CFRunLoopWakeUp(). This thread still needs to
+ be valid when that function is called on the other thread. */
+ pthread_barrier_wait(&dev->shutdown_barrier);
+
+ return NULL;
+}
+
+/* hid_open_path()
+ *
+ * path must be a valid path to an IOHIDDevice in the IOService plane
+ * Example: "IOService:/AppleACPIPlatformExpert/PCI0@0/AppleACPIPCI/EHC1@1D,7/AppleUSBEHCI/PLAYSTATION(R)3 Controller@fd120000/IOUSBInterface@0/IOUSBHIDDriver"
+ */
+hid_device * HID_API_EXPORT hid_open_path(const char *path)
+{
+ hid_device *dev = NULL;
+ io_registry_entry_t entry = MACH_PORT_NULL;
+
+ dev = new_hid_device();
+
+ /* Set up the HID Manager if it hasn't been done */
+ if (hid_init() < 0)
+ return NULL;
+
+ /* Get the IORegistry entry for the given path */
+ entry = IORegistryEntryFromPath(kIOMasterPortDefault, path);
+ if (entry == MACH_PORT_NULL) {
+ /* Path wasn't valid (maybe device was removed?) */
+ goto return_error;
+ }
+
+ /* Create an IOHIDDevice for the entry */
+ dev->device_handle = IOHIDDeviceCreate(kCFAllocatorDefault, entry);
+ if (dev->device_handle == NULL) {
+ /* Error creating the HID device */
+ goto return_error;
+ }
+
+ /* Open the IOHIDDevice */
+ IOReturn ret = IOHIDDeviceOpen(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
+ if (ret == kIOReturnSuccess) {
+ char str[32];
+
+ /* Create the buffers for receiving data */
+ dev->max_input_report_len = (CFIndex) get_max_report_length(dev->device_handle);
+ dev->input_report_buf = calloc(dev->max_input_report_len, sizeof(uint8_t));
+
+ /* Create the Run Loop Mode for this device.
+ printing the reference seems to work. */
+ sprintf(str, "HIDAPI_%p", dev->device_handle);
+ dev->run_loop_mode =
+ CFStringCreateWithCString(NULL, str, kCFStringEncodingASCII);
+
+ /* Attach the device to a Run Loop */
+ IOHIDDeviceRegisterInputReportCallback(
+ dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+ &hid_report_callback, dev);
+ IOHIDDeviceRegisterRemovalCallback(dev->device_handle, hid_device_removal_callback, dev);
+
+ /* Start the read thread */
+ pthread_create(&dev->thread, NULL, read_thread, dev);
+
+ /* Wait here for the read thread to be initialized. */
+ pthread_barrier_wait(&dev->barrier);
+
+ IOObjectRelease(entry);
+ return dev;
+ }
+ else {
+ goto return_error;
+ }
+
+return_error:
+ if (dev->device_handle != NULL)
+ CFRelease(dev->device_handle);
+
+ if (entry != MACH_PORT_NULL)
+ IOObjectRelease(entry);
+
+ free_hid_device(dev);
+ return NULL;
+}
+
+static int set_report(hid_device *dev, IOHIDReportType type, const unsigned char *data, size_t length)
+{
+ const unsigned char *data_to_send;
+ size_t length_to_send;
+ IOReturn res;
+
+ /* Return if the device has been disconnected. */
+ if (dev->disconnected)
+ return -1;
+
+ if (data[0] == 0x0) {
+ /* Not using numbered Reports.
+ Don't send the report number. */
+ data_to_send = data+1;
+ length_to_send = length-1;
+ }
+ else {
+ /* Using numbered Reports.
+ Send the Report Number */
+ data_to_send = data;
+ length_to_send = length;
+ }
+
+ if (!dev->disconnected) {
+ res = IOHIDDeviceSetReport(dev->device_handle,
+ type,
+ data[0], /* Report ID*/
+ data_to_send, length_to_send);
+
+ if (res == kIOReturnSuccess) {
+ return length;
+ }
+ else
+ return -1;
+ }
+
+ return -1;
+}
+
+int HID_API_EXPORT hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+ return set_report(dev, kIOHIDReportTypeOutput, data, length);
+}
+
+/* Helper function, so that this isn't duplicated in hid_read(). */
+static int return_data(hid_device *dev, unsigned char *data, size_t length)
+{
+ /* Copy the data out of the linked list item (rpt) into the
+ return buffer (data), and delete the liked list item. */
+ struct input_report *rpt = dev->input_reports;
+ size_t len = (length < rpt->len)? length: rpt->len;
+ memcpy(data, rpt->data, len);
+ dev->input_reports = rpt->next;
+ free(rpt->data);
+ free(rpt);
+ return len;
+}
+
+static int cond_wait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ while (!dev->input_reports) {
+ int res = pthread_cond_wait(cond, mutex);
+ if (res != 0)
+ return res;
+
+ /* A res of 0 means we may have been signaled or it may
+ be a spurious wakeup. Check to see that there's acutally
+ data in the queue before returning, and if not, go back
+ to sleep. See the pthread_cond_timedwait() man page for
+ details. */
+
+ if (dev->shutdown_thread || dev->disconnected)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int cond_timedwait(const hid_device *dev, pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+ while (!dev->input_reports) {
+ int res = pthread_cond_timedwait(cond, mutex, abstime);
+ if (res != 0)
+ return res;
+
+ /* A res of 0 means we may have been signaled or it may
+ be a spurious wakeup. Check to see that there's acutally
+ data in the queue before returning, and if not, go back
+ to sleep. See the pthread_cond_timedwait() man page for
+ details. */
+
+ if (dev->shutdown_thread || dev->disconnected)
+ return -1;
+ }
+
+ return 0;
+
+}
+
+int HID_API_EXPORT hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+ int bytes_read = -1;
+
+ /* Lock the access to the report list. */
+ pthread_mutex_lock(&dev->mutex);
+
+ /* There's an input report queued up. Return it. */
+ if (dev->input_reports) {
+ /* Return the first one */
+ bytes_read = return_data(dev, data, length);
+ goto ret;
+ }
+
+ /* Return if the device has been disconnected. */
+ if (dev->disconnected) {
+ bytes_read = -1;
+ goto ret;
+ }
+
+ if (dev->shutdown_thread) {
+ /* This means the device has been closed (or there
+ has been an error. An error code of -1 should
+ be returned. */
+ bytes_read = -1;
+ goto ret;
+ }
+
+ /* There is no data. Go to sleep and wait for data. */
+
+ if (milliseconds == -1) {
+ /* Blocking */
+ int res;
+ res = cond_wait(dev, &dev->condition, &dev->mutex);
+ if (res == 0)
+ bytes_read = return_data(dev, data, length);
+ else {
+ /* There was an error, or a device disconnection. */
+ bytes_read = -1;
+ }
+ }
+ else if (milliseconds > 0) {
+ /* Non-blocking, but called with timeout. */
+ int res;
+ struct timespec ts;
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+ ts.tv_sec += milliseconds / 1000;
+ ts.tv_nsec += (milliseconds % 1000) * 1000000;
+ if (ts.tv_nsec >= 1000000000L) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000L;
+ }
+
+ res = cond_timedwait(dev, &dev->condition, &dev->mutex, &ts);
+ if (res == 0)
+ bytes_read = return_data(dev, data, length);
+ else if (res == ETIMEDOUT)
+ bytes_read = 0;
+ else
+ bytes_read = -1;
+ }
+ else {
+ /* Purely non-blocking */
+ bytes_read = 0;
+ }
+
+ret:
+ /* Unlock */
+ pthread_mutex_unlock(&dev->mutex);
+ return bytes_read;
+}
+
+int HID_API_EXPORT hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+ return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+ /* All Nonblocking operation is handled by the library. */
+ dev->blocking = !nonblock;
+
+ return 0;
+}
+
+int HID_API_EXPORT hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+ return set_report(dev, kIOHIDReportTypeFeature, data, length);
+}
+
+int HID_API_EXPORT hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ CFIndex len = length;
+ IOReturn res;
+
+ /* Return if the device has been unplugged. */
+ if (dev->disconnected)
+ return -1;
+
+ res = IOHIDDeviceGetReport(dev->device_handle,
+ kIOHIDReportTypeFeature,
+ data[0], /* Report ID */
+ data, &len);
+ if (res == kIOReturnSuccess)
+ return len;
+ else
+ return -1;
+}
+
+
+void HID_API_EXPORT hid_close(hid_device *dev)
+{
+ if (!dev)
+ return;
+
+ /* Disconnect the report callback before close. */
+ if (!dev->disconnected) {
+ IOHIDDeviceRegisterInputReportCallback(
+ dev->device_handle, dev->input_report_buf, dev->max_input_report_len,
+ NULL, dev);
+ IOHIDDeviceRegisterRemovalCallback(dev->device_handle, NULL, dev);
+ IOHIDDeviceUnscheduleFromRunLoop(dev->device_handle, dev->run_loop, dev->run_loop_mode);
+ IOHIDDeviceScheduleWithRunLoop(dev->device_handle, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
+ }
+
+ /* Cause read_thread() to stop. */
+ dev->shutdown_thread = 1;
+
+ /* Wake up the run thread's event loop so that the thread can exit. */
+ CFRunLoopSourceSignal(dev->source);
+ CFRunLoopWakeUp(dev->run_loop);
+
+ /* Notify the read thread that it can shut down now. */
+ pthread_barrier_wait(&dev->shutdown_barrier);
+
+ /* Wait for read_thread() to end. */
+ pthread_join(dev->thread, NULL);
+
+ /* Close the OS handle to the device, but only if it's not
+ been unplugged. If it's been unplugged, then calling
+ IOHIDDeviceClose() will crash. */
+ if (!dev->disconnected) {
+ IOHIDDeviceClose(dev->device_handle, kIOHIDOptionsTypeSeizeDevice);
+ }
+
+ /* Clear out the queue of received reports. */
+ pthread_mutex_lock(&dev->mutex);
+ while (dev->input_reports) {
+ return_data(dev, NULL, 0);
+ }
+ pthread_mutex_unlock(&dev->mutex);
+ CFRelease(dev->device_handle);
+
+ free_hid_device(dev);
+}
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ return get_manufacturer_string(dev->device_handle, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ return get_product_string(dev->device_handle, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ return get_serial_number(dev->device_handle, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+ /* TODO: */
+
+ return 0;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
+{
+ /* TODO: */
+
+ return NULL;
+}
+
+
+
+
+
+
+
+#if 0
+static int32_t get_location_id(IOHIDDeviceRef device)
+{
+ return get_int_property(device, CFSTR(kIOHIDLocationIDKey));
+}
+
+static int32_t get_usage(IOHIDDeviceRef device)
+{
+ int32_t res;
+ res = get_int_property(device, CFSTR(kIOHIDDeviceUsageKey));
+ if (!res)
+ res = get_int_property(device, CFSTR(kIOHIDPrimaryUsageKey));
+ return res;
+}
+
+static int32_t get_usage_page(IOHIDDeviceRef device)
+{
+ int32_t res;
+ res = get_int_property(device, CFSTR(kIOHIDDeviceUsagePageKey));
+ if (!res)
+ res = get_int_property(device, CFSTR(kIOHIDPrimaryUsagePageKey));
+ return res;
+}
+
+static int get_transport(IOHIDDeviceRef device, wchar_t *buf, size_t len)
+{
+ return get_string_property(device, CFSTR(kIOHIDTransportKey), buf, len);
+}
+
+
+int main(void)
+{
+ IOHIDManagerRef mgr;
+ int i;
+
+ mgr = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+ IOHIDManagerSetDeviceMatching(mgr, NULL);
+ IOHIDManagerOpen(mgr, kIOHIDOptionsTypeNone);
+
+ CFSetRef device_set = IOHIDManagerCopyDevices(mgr);
+
+ CFIndex num_devices = CFSetGetCount(device_set);
+ IOHIDDeviceRef *device_array = calloc(num_devices, sizeof(IOHIDDeviceRef));
+ CFSetGetValues(device_set, (const void **) device_array);
+
+ for (i = 0; i < num_devices; i++) {
+ IOHIDDeviceRef dev = device_array[i];
+ printf("Device: %p\n", dev);
+ printf(" %04hx %04hx\n", get_vendor_id(dev), get_product_id(dev));
+
+ wchar_t serial[256], buf[256];
+ char cbuf[256];
+ get_serial_number(dev, serial, 256);
+
+
+ printf(" Serial: %ls\n", serial);
+ printf(" Loc: %ld\n", get_location_id(dev));
+ get_transport(dev, buf, 256);
+ printf(" Trans: %ls\n", buf);
+ make_path(dev, cbuf, 256);
+ printf(" Path: %s\n", cbuf);
+
+ }
+
+ return 0;
+}
+#endif
+
diff --git a/redist/hid-windows.c b/redist/hid-windows.c
new file mode 100644
index 0000000..6c379b5
--- /dev/null
+++ b/redist/hid-windows.c
@@ -0,0 +1,996 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+
+/* Copy of LICENSE-orig.txt (compatible with MIT/x11 license)
+
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
+*/
+
+#include <windows.h>
+
+#ifndef _NTDEF_
+typedef LONG NTSTATUS;
+#endif
+
+#ifdef __MINGW32__
+#include <ntdef.h>
+#include <winbase.h>
+#endif
+
+#ifdef __CYGWIN__
+#include <ntdef.h>
+#define _wcsdup wcsdup
+#endif
+
+/* The maximum number of characters that can be passed into the
+ HidD_Get*String() functions without it failing.*/
+#define MAX_STRING_WCHARS 0xFFF
+
+/*#define HIDAPI_USE_DDK*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef TCC
+ typedef struct _SP_DEVINFO_DATA {
+ DWORD cbSize;
+ GUID ClassGuid;
+ DWORD DevInst;
+ ULONG_PTR Reserved;
+ } SP_DEVINFO_DATA, *PSP_DEVINFO_DATA;
+ typedef struct _SP_DEVICE_INTERFACE_DATA {
+ DWORD cbSize;
+ GUID InterfaceClassGuid;
+ DWORD Flags;
+ ULONG_PTR Reserved;
+ } SP_DEVICE_INTERFACE_DATA, *PSP_DEVICE_INTERFACE_DATA;
+ typedef struct _SP_DEVICE_INTERFACE_DETAIL_DATA {
+ DWORD cbSize;
+ CHAR DevicePath[ANYSIZE_ARRAY];
+ } SP_DEVICE_INTERFACE_DETAIL_DATA_A, *PSP_DEVICE_INTERFACE_DETAIL_DATA_A;
+ typedef PVOID HDEVINFO;
+
+ HDEVINFO WINAPI SetupDiGetClassDevsA(CONST GUID*,PCSTR,HWND,DWORD);
+
+ #define DIGCF_PRESENT 0x00000002
+ #define DIGCF_DEVICEINTERFACE 0x00000010
+ #define SPDRP_CLASS 7
+ #define SPDRP_DRIVER 9
+ #define FILE_DEVICE_KEYBOARD 0x0000000b
+ #define METHOD_OUT_DIRECT 2
+ enum
+ { FILE_ANY_ACCESS = 0x00000000UL,
+ FILE_SPECIAL_ACCESS = FILE_ANY_ACCESS,
+ FILE_READ_ACCESS = 0x00000001UL,
+ FILE_WRITE_ACCESS = 0x00000002UL
+ };
+ #define CTL_CODE(t,f,m,a) (((t)<<16)|((a)<<14)|((f)<<2)|(m))
+
+#else
+ #include <setupapi.h>
+ #include <winioctl.h>
+#endif
+ #ifdef HIDAPI_USE_DDK
+ #include <hidsdi.h>
+ #endif
+
+ /* Copied from inc/ddk/hidclass.h, part of the Windows DDK. */
+ #define HID_OUT_CTL_CODE(id) \
+ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+ #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#include "hidapi.h"
+
+#undef MIN
+#define MIN(x,y) ((x) < (y)? (x): (y))
+
+#ifdef _MSC_VER
+ /* Thanks Microsoft, but I know how to use strncpy(). */
+ #pragma warning(disable:4996)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HIDAPI_USE_DDK
+ /* Since we're not building with the DDK, and the HID header
+ files aren't part of the SDK, we have to define all this
+ stuff here. In lookup_functions(), the function pointers
+ defined below are set. */
+ typedef struct _HIDD_ATTRIBUTES{
+ ULONG Size;
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+ } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+
+ typedef USHORT USAGE;
+ typedef struct _HIDP_CAPS {
+ USAGE Usage;
+ USAGE UsagePage;
+ USHORT InputReportByteLength;
+ USHORT OutputReportByteLength;
+ USHORT FeatureReportByteLength;
+ USHORT Reserved[17];
+ USHORT fields_not_used_by_hidapi[10];
+ } HIDP_CAPS, *PHIDP_CAPS;
+ typedef void* PHIDP_PREPARSED_DATA;
+ #define HIDP_STATUS_SUCCESS 0x110000
+
+ typedef BOOLEAN (__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib);
+ typedef BOOLEAN (__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length);
+ typedef BOOLEAN (__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len);
+ typedef BOOLEAN (__stdcall *HidD_GetPreparsedData_)(HANDLE handle, PHIDP_PREPARSED_DATA *preparsed_data);
+ typedef BOOLEAN (__stdcall *HidD_FreePreparsedData_)(PHIDP_PREPARSED_DATA preparsed_data);
+ typedef NTSTATUS (__stdcall *HidP_GetCaps_)(PHIDP_PREPARSED_DATA preparsed_data, HIDP_CAPS *caps);
+ typedef BOOLEAN (__stdcall *HidD_SetNumInputBuffers_)(HANDLE handle, ULONG number_buffers);
+
+ static HidD_GetAttributes_ HidD_GetAttributes;
+ static HidD_GetSerialNumberString_ HidD_GetSerialNumberString;
+ static HidD_GetManufacturerString_ HidD_GetManufacturerString;
+ static HidD_GetProductString_ HidD_GetProductString;
+ static HidD_SetFeature_ HidD_SetFeature;
+ static HidD_GetFeature_ HidD_GetFeature;
+ static HidD_GetIndexedString_ HidD_GetIndexedString;
+ static HidD_GetPreparsedData_ HidD_GetPreparsedData;
+ static HidD_FreePreparsedData_ HidD_FreePreparsedData;
+ static HidP_GetCaps_ HidP_GetCaps;
+ static HidD_SetNumInputBuffers_ HidD_SetNumInputBuffers;
+
+ static HMODULE lib_handle = NULL;
+ static BOOLEAN initialized = FALSE;
+#endif /* HIDAPI_USE_DDK */
+
+struct hid_device_ {
+ HANDLE device_handle;
+ BOOL blocking;
+ USHORT output_report_length;
+ size_t input_report_length;
+ void *last_error_str;
+ DWORD last_error_num;
+ BOOL read_pending;
+ char *read_buf;
+ OVERLAPPED ol;
+};
+
+static hid_device *new_hid_device()
+{
+ hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device));
+ dev->device_handle = INVALID_HANDLE_VALUE;
+ dev->blocking = TRUE;
+ dev->output_report_length = 0;
+ dev->input_report_length = 0;
+ dev->last_error_str = NULL;
+ dev->last_error_num = 0;
+ dev->read_pending = FALSE;
+ dev->read_buf = NULL;
+ memset(&dev->ol, 0, sizeof(dev->ol));
+ dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*initial state f=nonsignaled*/, NULL);
+
+ return dev;
+}
+
+static void free_hid_device(hid_device *dev)
+{
+ CloseHandle(dev->ol.hEvent);
+ CloseHandle(dev->device_handle);
+ LocalFree(dev->last_error_str);
+ free(dev->read_buf);
+ free(dev);
+}
+
+static void register_error(hid_device *device, const char *op)
+{
+ WCHAR *ptr, *msg;
+
+ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPVOID)&msg, 0/*sz*/,
+ NULL);
+
+ /* Get rid of the CR and LF that FormatMessage() sticks at the
+ end of the message. Thanks Microsoft! */
+ ptr = msg;
+ while (*ptr) {
+ if (*ptr == '\r') {
+ *ptr = 0x0000;
+ break;
+ }
+ ptr++;
+ }
+
+ /* Store the message off in the Device entry so that
+ the hid_error() function can pick it up. */
+ LocalFree(device->last_error_str);
+ device->last_error_str = msg;
+}
+
+#ifndef HIDAPI_USE_DDK
+static int lookup_functions()
+{
+ lib_handle = LoadLibraryA("hid.dll");
+ if (lib_handle) {
+#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1;
+ RESOLVE(HidD_GetAttributes);
+ RESOLVE(HidD_GetSerialNumberString);
+ RESOLVE(HidD_GetManufacturerString);
+ RESOLVE(HidD_GetProductString);
+ RESOLVE(HidD_SetFeature);
+ RESOLVE(HidD_GetFeature);
+ RESOLVE(HidD_GetIndexedString);
+ RESOLVE(HidD_GetPreparsedData);
+ RESOLVE(HidD_FreePreparsedData);
+ RESOLVE(HidP_GetCaps);
+ RESOLVE(HidD_SetNumInputBuffers);
+#undef RESOLVE
+ }
+ else
+ return -1;
+
+ return 0;
+}
+#endif
+
+static HANDLE open_device(const char *path, BOOL enumerate)
+{
+ HANDLE handle;
+ DWORD desired_access = (enumerate)? 0: (GENERIC_WRITE | GENERIC_READ);
+ DWORD share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
+
+ handle = CreateFileA(path,
+ desired_access,
+ share_mode,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,/*FILE_ATTRIBUTE_NORMAL,*/
+ 0);
+
+ return handle;
+}
+
+int HID_API_EXPORT hid_init(void)
+{
+#ifndef HIDAPI_USE_DDK
+ if (!initialized) {
+ if (lookup_functions() < 0) {
+ hid_exit();
+ return -1;
+ }
+ initialized = TRUE;
+ }
+#endif
+ return 0;
+}
+
+int HID_API_EXPORT hid_exit(void)
+{
+#ifndef HIDAPI_USE_DDK
+ if (lib_handle)
+ FreeLibrary(lib_handle);
+ lib_handle = NULL;
+ initialized = FALSE;
+#endif
+ return 0;
+}
+
+struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+ BOOL res;
+ struct hid_device_info *root = NULL; /* return object */
+ struct hid_device_info *cur_dev = NULL;
+
+ /* Windows objects for interacting with the driver. */
+ GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} };
+ SP_DEVINFO_DATA devinfo_data;
+ SP_DEVICE_INTERFACE_DATA device_interface_data;
+ SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL;
+ HDEVINFO device_info_set = INVALID_HANDLE_VALUE;
+ int device_index = 0;
+ int i;
+
+ if (hid_init() < 0)
+ return NULL;
+
+ /* Initialize the Windows objects. */
+ memset(&devinfo_data, 0x0, sizeof(devinfo_data));
+ devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA);
+ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+
+ /* Get information for all the devices belonging to the HID class. */
+ device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
+
+ /* Iterate over each device in the HID class, looking for the right one. */
+
+ for (;;) {
+ HANDLE write_handle = INVALID_HANDLE_VALUE;
+ DWORD required_size = 0;
+ HIDD_ATTRIBUTES attrib;
+
+ res = SetupDiEnumDeviceInterfaces(device_info_set,
+ NULL,
+ &InterfaceClassGuid,
+ device_index,
+ &device_interface_data);
+
+ if (!res) {
+ /* A return of FALSE from this function means that
+ there are no more devices. */
+ break;
+ }
+
+ /* Call with 0-sized detail size, and let the function
+ tell us how long the detail struct needs to be. The
+ size is put in &required_size. */
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ NULL,
+ 0,
+ &required_size,
+ NULL);
+
+ /* Allocate a long enough structure for device_interface_detail_data. */
+ device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size);
+ device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+
+ /* Get the detailed data for this device. The detail data gives us
+ the device path for this device, which is then passed into
+ CreateFile() to get a handle to the device. */
+ res = SetupDiGetDeviceInterfaceDetailA(device_info_set,
+ &device_interface_data,
+ device_interface_detail_data,
+ required_size,
+ NULL,
+ NULL);
+
+ if (!res) {
+ /* register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail");
+ Continue to the next device. */
+ goto cont;
+ }
+
+ /* Make sure this device is of Setup Class "HIDClass" and has a
+ driver bound to it. */
+ for (i = 0; ; i++) {
+ char driver_name[256];
+
+ /* Populate devinfo_data. This function will return failure
+ when there are no more interfaces left. */
+ res = SetupDiEnumDeviceInfo(device_info_set, i, &devinfo_data);
+ if (!res)
+ goto cont;
+
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_CLASS, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (!res)
+ goto cont;
+
+ if (strcmp(driver_name, "HIDClass") == 0) {
+ /* See if there's a driver bound. */
+ res = SetupDiGetDeviceRegistryPropertyA(device_info_set, &devinfo_data,
+ SPDRP_DRIVER, NULL, (PBYTE)driver_name, sizeof(driver_name), NULL);
+ if (res)
+ break;
+ }
+ }
+
+ //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath);
+
+ /* Open a handle to the device */
+ write_handle = open_device(device_interface_detail_data->DevicePath, TRUE);
+
+ /* Check validity of write_handle. */
+ if (write_handle == INVALID_HANDLE_VALUE) {
+ /* Unable to open the device. */
+ //register_error(dev, "CreateFile");
+ goto cont_close;
+ }
+
+
+ /* Get the Vendor ID and Product ID for this device. */
+ attrib.Size = sizeof(HIDD_ATTRIBUTES);
+ HidD_GetAttributes(write_handle, &attrib);
+ //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID);
+
+ /* Check the VID/PID to see if we should add this
+ device to the enumeration list. */
+ if ((vendor_id == 0x0 || attrib.VendorID == vendor_id) &&
+ (product_id == 0x0 || attrib.ProductID == product_id)) {
+
+ #define WSTR_LEN 512
+ const char *str;
+ struct hid_device_info *tmp;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ HIDP_CAPS caps;
+ BOOLEAN res;
+ NTSTATUS nt_res;
+ wchar_t wstr[WSTR_LEN]; /* TODO: Determine Size */
+ size_t len;
+
+ /* VID/PID match. Create the record. */
+ tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info));
+ if (cur_dev) {
+ cur_dev->next = tmp;
+ }
+ else {
+ root = tmp;
+ }
+ cur_dev = tmp;
+
+ /* Get the Usage Page and Usage for this device. */
+ res = HidD_GetPreparsedData(write_handle, &pp_data);
+ if (res) {
+ nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res == HIDP_STATUS_SUCCESS) {
+ cur_dev->usage_page = caps.UsagePage;
+ cur_dev->usage = caps.Usage;
+ }
+
+ HidD_FreePreparsedData(pp_data);
+ }
+
+ /* Fill out the record */
+ cur_dev->next = NULL;
+ str = device_interface_detail_data->DevicePath;
+ if (str) {
+ len = strlen(str);
+ cur_dev->path = (char*) calloc(len+1, sizeof(char));
+ strncpy(cur_dev->path, str, len+1);
+ cur_dev->path[len] = '\0';
+ }
+ else
+ cur_dev->path = NULL;
+
+ /* Serial Number */
+ res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->serial_number = _wcsdup(wstr);
+ }
+
+ /* Manufacturer String */
+ res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->manufacturer_string = _wcsdup(wstr);
+ }
+
+ /* Product String */
+ res = HidD_GetProductString(write_handle, wstr, sizeof(wstr));
+ wstr[WSTR_LEN-1] = 0x0000;
+ if (res) {
+ cur_dev->product_string = _wcsdup(wstr);
+ }
+
+ /* VID/PID */
+ cur_dev->vendor_id = attrib.VendorID;
+ cur_dev->product_id = attrib.ProductID;
+
+ /* Release Number */
+ cur_dev->release_number = attrib.VersionNumber;
+
+ /* Interface Number. It can sometimes be parsed out of the path
+ on Windows if a device has multiple interfaces. See
+ http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or
+ search for "Hardware IDs for HID Devices" at MSDN. If it's not
+ in the path, it's set to -1. */
+ cur_dev->interface_number = -1;
+ if (cur_dev->path) {
+ char *interface_component = strstr(cur_dev->path, "&mi_");
+ if (interface_component) {
+ char *hex_str = interface_component + 4;
+ char *endptr = NULL;
+ cur_dev->interface_number = strtol(hex_str, &endptr, 16);
+ if (endptr == hex_str) {
+ /* The parsing failed. Set interface_number to -1. */
+ cur_dev->interface_number = -1;
+ }
+ }
+ }
+ }
+
+cont_close:
+ CloseHandle(write_handle);
+cont:
+ /* We no longer need the detail data. It can be freed */
+ free(device_interface_detail_data);
+
+ device_index++;
+
+ }
+
+ /* Close the device information handle. */
+ SetupDiDestroyDeviceInfoList(device_info_set);
+
+ return root;
+
+}
+
+void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
+{
+ /* TODO: Merge this with the Linux version. This function is platform-independent. */
+ struct hid_device_info *d = devs;
+ while (d) {
+ struct hid_device_info *next = d->next;
+ free(d->path);
+ free(d->serial_number);
+ free(d->manufacturer_string);
+ free(d->product_string);
+ free(d);
+ d = next;
+ }
+}
+
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+ /* TODO: Merge this functions with the Linux version. This function should be platform independent. */
+ struct hid_device_info *devs, *cur_dev;
+ const char *path_to_open = NULL;
+ hid_device *handle = NULL;
+
+ devs = hid_enumerate(vendor_id, product_id);
+ cur_dev = devs;
+ while (cur_dev) {
+ if (cur_dev->vendor_id == vendor_id &&
+ cur_dev->product_id == product_id) {
+ if (serial_number) {
+ if (wcscmp(serial_number, cur_dev->serial_number) == 0) {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ else {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open) {
+ /* Open the device */
+ handle = hid_open_path(path_to_open);
+ }
+
+ hid_free_enumeration(devs);
+
+ return handle;
+}
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path)
+{
+ hid_device *dev;
+ HIDP_CAPS caps;
+ PHIDP_PREPARSED_DATA pp_data = NULL;
+ BOOLEAN res;
+ NTSTATUS nt_res;
+
+ if (hid_init() < 0) {
+ return NULL;
+ }
+
+ dev = new_hid_device();
+
+ /* Open a handle to the device */
+ dev->device_handle = open_device(path, FALSE);
+
+ /* Check validity of write_handle. */
+ if (dev->device_handle == INVALID_HANDLE_VALUE) {
+ /* Unable to open the device. */
+ register_error(dev, "CreateFile");
+ goto err;
+ }
+
+ /* Set the Input Report buffer size to 64 reports. */
+ res = HidD_SetNumInputBuffers(dev->device_handle, 64);
+ if (!res) {
+ register_error(dev, "HidD_SetNumInputBuffers");
+ goto err;
+ }
+
+ /* Get the Input Report length for the device. */
+ res = HidD_GetPreparsedData(dev->device_handle, &pp_data);
+ if (!res) {
+ register_error(dev, "HidD_GetPreparsedData");
+ goto err;
+ }
+ nt_res = HidP_GetCaps(pp_data, &caps);
+ if (nt_res != HIDP_STATUS_SUCCESS) {
+ register_error(dev, "HidP_GetCaps");
+ goto err_pp_data;
+ }
+ dev->output_report_length = caps.OutputReportByteLength;
+ dev->input_report_length = caps.InputReportByteLength;
+ HidD_FreePreparsedData(pp_data);
+
+ dev->read_buf = (char*) malloc(dev->input_report_length);
+
+ return dev;
+
+err_pp_data:
+ HidD_FreePreparsedData(pp_data);
+err:
+ free_hid_device(dev);
+ return NULL;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length)
+{
+ DWORD bytes_written;
+ BOOL res;
+
+ OVERLAPPED ol;
+ unsigned char *buf;
+ memset(&ol, 0, sizeof(ol));
+
+ /* Make sure the right number of bytes are passed to WriteFile. Windows
+ expects the number of bytes which are in the _longest_ report (plus
+ one for the report number) bytes even if the data is a report
+ which is shorter than that. Windows gives us this value in
+ caps.OutputReportByteLength. If a user passes in fewer bytes than this,
+ create a temporary buffer which is the proper size. */
+ if (length >= dev->output_report_length) {
+ /* The user passed the right number of bytes. Use the buffer as-is. */
+ buf = (unsigned char *) data;
+ } else {
+ /* Create a temporary buffer and copy the user's data
+ into it, padding the rest with zeros. */
+ buf = (unsigned char *) malloc(dev->output_report_length);
+ memcpy(buf, data, length);
+ memset(buf + length, 0, dev->output_report_length - length);
+ length = dev->output_report_length;
+ }
+
+ res = WriteFile(dev->device_handle, buf, (DWORD)length, NULL, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* WriteFile() failed. Return error. */
+ register_error(dev, "WriteFile");
+ bytes_written = -1;
+ goto end_of_function;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_write() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/);
+ if (!res) {
+ /* The Write operation failed. */
+ register_error(dev, "WriteFile");
+ bytes_written = -1;
+ goto end_of_function;
+ }
+
+end_of_function:
+ if (buf != data)
+ free(buf);
+
+ return bytes_written;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds)
+{
+ DWORD bytes_read = 0;
+ size_t copy_len = 0;
+ BOOL res;
+
+ /* Copy the handle for convenience. */
+ HANDLE ev = dev->ol.hEvent;
+
+ if (!dev->read_pending) {
+ /* Start an Overlapped I/O read. */
+ dev->read_pending = TRUE;
+ memset(dev->read_buf, 0, dev->input_report_length);
+ ResetEvent(ev);
+ res = ReadFile(dev->device_handle, dev->read_buf, (DWORD)dev->input_report_length, &bytes_read, &dev->ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* ReadFile() has failed.
+ Clean up and return error. */
+ CancelIo(dev->device_handle);
+ dev->read_pending = FALSE;
+ goto end_of_function;
+ }
+ }
+ }
+
+ if (milliseconds >= 0) {
+ /* See if there is any data yet. */
+ res = WaitForSingleObject(ev, milliseconds);
+ if (res != WAIT_OBJECT_0) {
+ /* There was no data this time. Return zero bytes available,
+ but leave the Overlapped I/O running. */
+ return 0;
+ }
+ }
+
+ /* Either WaitForSingleObject() told us that ReadFile has completed, or
+ we are in non-blocking mode. Get the number of bytes read. The actual
+ data has been copied to the data[] array which was passed to ReadFile(). */
+ res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/);
+
+ /* Set pending back to false, even if GetOverlappedResult() returned error. */
+ dev->read_pending = FALSE;
+
+ if (res && bytes_read > 0) {
+ if (dev->read_buf[0] == 0x0) {
+ /* If report numbers aren't being used, but Windows sticks a report
+ number (0x0) on the beginning of the report anyway. To make this
+ work like the other platforms, and to make it work more like the
+ HID spec, we'll skip over this byte. */
+ bytes_read--;
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf+1, copy_len);
+ }
+ else {
+ /* Copy the whole buffer, report number and all. */
+ copy_len = length > bytes_read ? bytes_read : length;
+ memcpy(data, dev->read_buf, copy_len);
+ }
+ }
+
+end_of_function:
+ if (!res) {
+ register_error(dev, "GetOverlappedResult");
+ return -1;
+ }
+
+ return (int)copy_len;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length)
+{
+ return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock)
+{
+ dev->blocking = !nonblock;
+ return 0; /* Success */
+}
+
+int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length)
+{
+ BOOL res = HidD_SetFeature(dev->device_handle, (PVOID)data, (ULONG)length);
+ if (!res) {
+ register_error(dev, "HidD_SetFeature");
+ return -1;
+ }
+
+ return (int)length;
+}
+
+
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length)
+{
+ BOOL res;
+#if 0
+ res = HidD_GetFeature(dev->device_handle, data, length);
+ if (!res) {
+ register_error(dev, "HidD_GetFeature");
+ return -1;
+ }
+ return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */
+#else
+ DWORD bytes_returned;
+
+ OVERLAPPED ol;
+ memset(&ol, 0, sizeof(ol));
+
+ res = DeviceIoControl(dev->device_handle,
+ IOCTL_HID_GET_FEATURE,
+ data, (DWORD)length,
+ data, (DWORD)length,
+ &bytes_returned, &ol);
+
+ if (!res) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ /* DeviceIoControl() failed. Return error. */
+ register_error(dev, "Send Feature Report DeviceIoControl");
+ return -1;
+ }
+ }
+
+ /* Wait here until the write is done. This makes
+ hid_get_feature_report() synchronous. */
+ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/);
+ if (!res) {
+ /* The operation failed. */
+ register_error(dev, "Send Feature Report GetOverLappedResult");
+ return -1;
+ }
+
+ /* bytes_returned does not include the first byte which contains the
+ report ID. The data buffer actually contains one more byte than
+ bytes_returned. */
+ bytes_returned++;
+
+ return bytes_returned;
+#endif
+}
+
+void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev)
+{
+ if (!dev)
+ return;
+ CancelIo(dev->device_handle);
+ free_hid_device(dev);
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetManufacturerString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+ if (!res) {
+ register_error(dev, "HidD_GetManufacturerString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetProductString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+ if (!res) {
+ register_error(dev, "HidD_GetProductString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetSerialNumberString(dev->device_handle, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+ if (!res) {
+ register_error(dev, "HidD_GetSerialNumberString");
+ return -1;
+ }
+
+ return 0;
+}
+
+int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen)
+{
+ BOOL res;
+
+ res = HidD_GetIndexedString(dev->device_handle, string_index, string, (ULONG)(sizeof(wchar_t) * MIN(maxlen, MAX_STRING_WCHARS)));
+ if (!res) {
+ register_error(dev, "HidD_GetIndexedString");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev)
+{
+ return (wchar_t*)dev->last_error_str;
+}
+
+
+/*#define PICPGM*/
+/*#define S11*/
+#define P32
+#ifdef S11
+ unsigned short VendorID = 0xa0a0;
+ unsigned short ProductID = 0x0001;
+#endif
+
+#ifdef P32
+ unsigned short VendorID = 0x04d8;
+ unsigned short ProductID = 0x3f;
+#endif
+
+
+#ifdef PICPGM
+ unsigned short VendorID = 0x04d8;
+ unsigned short ProductID = 0x0033;
+#endif
+
+
+#if 0
+int __cdecl main(int argc, char* argv[])
+{
+ int res;
+ unsigned char buf[65];
+
+ UNREFERENCED_PARAMETER(argc);
+ UNREFERENCED_PARAMETER(argv);
+
+ /* Set up the command buffer. */
+ memset(buf,0x00,sizeof(buf));
+ buf[0] = 0;
+ buf[1] = 0x81;
+
+
+ /* Open the device. */
+ int handle = open(VendorID, ProductID, L"12345");
+ if (handle < 0)
+ printf("unable to open device\n");
+
+
+ /* Toggle LED (cmd 0x80) */
+ buf[1] = 0x80;
+ res = write(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to write()\n");
+
+ /* Request state (cmd 0x81) */
+ buf[1] = 0x81;
+ write(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to write() (2)\n");
+
+ /* Read requested state */
+ read(handle, buf, 65);
+ if (res < 0)
+ printf("Unable to read()\n");
+
+ /* Print out the returned buffer. */
+ for (int i = 0; i < 4; i++)
+ printf("buf[%d]: %d\n", i, buf[i]);
+
+ return 0;
+}
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
diff --git a/redist/hidapi.h b/redist/hidapi.h
new file mode 100644
index 0000000..43b8e7a
--- /dev/null
+++ b/redist/hidapi.h
@@ -0,0 +1,405 @@
+/*******************************************************
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Alan Ott
+ Signal 11 Software
+
+ 8/22/2009
+
+ Copyright 2009, All Rights Reserved.
+
+ At the discretion of the user of this library,
+ this software may be licensed under the terms of the
+ GNU General Public License v3, a BSD-Style license, or the
+ original HIDAPI license as outlined in the LICENSE.txt,
+ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt
+ files located at the root of the source distribution.
+ These files may also be found in the public source
+ code repository located at:
+ http://github.com/signal11/hidapi .
+********************************************************/
+
+/* Copy of LICENSE-orig.txt (compatible with MIT/x11 license)
+
+ HIDAPI - Multi-Platform library for
+ communication with HID devices.
+
+ Copyright 2009, Alan Ott, Signal 11 Software.
+ All Rights Reserved.
+
+ This software may be used by anyone for any reason so
+ long as the copyright notice in the source files
+ remains intact.
+*/
+
+
+/** @file
+ * @defgroup API hidapi API
+ */
+
+#ifndef HIDAPI_H__
+#define HIDAPI_H__
+
+#include <wchar.h>
+
+#ifdef _WIN32
+ #define HID_API_EXPORT __declspec(dllexport)
+ #define HID_API_CALL
+#else
+ #define HID_API_EXPORT /**< API export macro */
+ #define HID_API_CALL /**< API call macro */
+#endif
+
+#define HID_API_EXPORT_CALL HID_API_EXPORT HID_API_CALL /**< API export and call macro*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ struct hid_device_;
+ typedef struct hid_device_ hid_device; /**< opaque hidapi structure */
+
+ /** hidapi info structure */
+ struct hid_device_info {
+ /** Platform-specific device path */
+ char *path;
+ /** Device Vendor ID */
+ unsigned short vendor_id;
+ /** Device Product ID */
+ unsigned short product_id;
+ /** Serial Number */
+ wchar_t *serial_number;
+ /** Device Release Number in binary-coded decimal,
+ also known as Device Version Number */
+ unsigned short release_number;
+ /** Manufacturer String */
+ wchar_t *manufacturer_string;
+ /** Product string */
+ wchar_t *product_string;
+ /** Usage Page for this Device/Interface
+ (Windows/Mac only). */
+ unsigned short usage_page;
+ /** Usage for this Device/Interface
+ (Windows/Mac only).*/
+ unsigned short usage;
+ /** The USB interface which this logical device
+ represents. Valid on both Linux implementations
+ in all cases, and valid on the Windows implementation
+ only if the device contains more than one interface. */
+ int interface_number;
+
+ /** Pointer to the next device */
+ struct hid_device_info *next;
+ };
+
+
+ /** @brief Initialize the HIDAPI library.
+
+ This function initializes the HIDAPI library. Calling it is not
+ strictly necessary, as it will be called automatically by
+ hid_enumerate() and any of the hid_open_*() functions if it is
+ needed. This function should be called at the beginning of
+ execution however, if there is a chance of HIDAPI handles
+ being opened by different threads simultaneously.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_init(void);
+
+ /** @brief Finalize the HIDAPI library.
+
+ This function frees all of the static data associated with
+ HIDAPI. It should be called at the end of execution to avoid
+ memory leaks.
+
+ @ingroup API
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_exit(void);
+
+ /** @brief Enumerate the HID Devices.
+
+ This function returns a linked list of all the HID devices
+ attached to the system which match vendor_id and product_id.
+ If @p vendor_id is set to 0 then any vendor matches.
+ If @p product_id is set to 0 then any product matches.
+ If @p vendor_id and @p product_id are both set to 0, then
+ all HID devices will be returned.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the types of device
+ to open.
+ @param product_id The Product ID (PID) of the types of
+ device to open.
+
+ @returns
+ This function returns a pointer to a linked list of type
+ struct #hid_device, containing information about the HID devices
+ attached to the system, or NULL in the case of failure. Free
+ this linked list by calling hid_free_enumeration().
+ */
+ struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id);
+
+ /** @brief Free an enumeration Linked List
+
+ This function frees a linked list created by hid_enumerate().
+
+ @ingroup API
+ @param devs Pointer to a list of struct_device returned from
+ hid_enumerate().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs);
+
+ /** @brief Open a HID device using a Vendor ID (VID), Product ID
+ (PID) and optionally a serial number.
+
+ If @p serial_number is NULL, the first device with the
+ specified VID and PID is opened.
+
+ @ingroup API
+ @param vendor_id The Vendor ID (VID) of the device to open.
+ @param product_id The Product ID (PID) of the device to open.
+ @param serial_number The Serial Number of the device to open
+ (Optionally NULL).
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number);
+
+ /** @brief Open a HID device by its path name.
+
+ The path name be determined by calling hid_enumerate(), or a
+ platform-specific path name can be used (eg: /dev/hidraw0 on
+ Linux).
+
+ @ingroup API
+ @param path The path name of the device to open
+
+ @returns
+ This function returns a pointer to a #hid_device object on
+ success or NULL on failure.
+ */
+ HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path);
+
+ /** @brief Write an Output report to a HID device.
+
+ The first byte of @p data[] must contain the Report ID. For
+ devices which only support a single report, this must be set
+ to 0x0. The remaining bytes contain the report data. Since
+ the Report ID is mandatory, calls to hid_write() will always
+ contain one more byte than the report contains. For example,
+ if a hid report is 16 bytes long, 17 bytes must be passed to
+ hid_write(), the Report ID (or 0x0, for devices with a
+ single report), followed by the report data (16 bytes). In
+ this example, the length passed in would be 17.
+
+ hid_write() will send the data on the first OUT endpoint, if
+ one exists. If it does not, it will send the data through
+ the Control Endpoint (Endpoint 0).
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Read an Input report from a HID device with timeout.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+ @param milliseconds timeout in milliseconds or -1 for blocking wait.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read within
+ the timeout period, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds);
+
+ /** @brief Read an Input report from a HID device.
+
+ Input reports are returned
+ to the host through the INTERRUPT IN endpoint. The first byte will
+ contain the Report number if the device uses numbered reports.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into.
+ @param length The number of bytes to read. For devices with
+ multiple reports, make sure to read an extra byte for
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes read and
+ -1 on error. If no packet was available to be read and
+ the handle is in non-blocking mode, this function returns 0.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Set the device handle to be non-blocking.
+
+ In non-blocking mode calls to hid_read() will return
+ immediately with a value of 0 if there is no data to be
+ read. In blocking mode, hid_read() will wait (block) until
+ there is data to read before returning.
+
+ Nonblocking can be turned on and off at any time.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param nonblock enable or not the nonblocking reads
+ - 1 to enable nonblocking
+ - 0 to disable nonblocking.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock);
+
+ /** @brief Send a Feature report to the device.
+
+ Feature reports are sent over the Control endpoint as a
+ Set_Report transfer. The first byte of @p data[] must
+ contain the Report ID. For devices which only support a
+ single report, this must be set to 0x0. The remaining bytes
+ contain the report data. Since the Report ID is mandatory,
+ calls to hid_send_feature_report() will always contain one
+ more byte than the report contains. For example, if a hid
+ report is 16 bytes long, 17 bytes must be passed to
+ hid_send_feature_report(): the Report ID (or 0x0, for
+ devices which do not use numbered reports), followed by the
+ report data (16 bytes). In this example, the length passed
+ in would be 17.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data The data to send, including the report number as
+ the first byte.
+ @param length The length in bytes of the data to send, including
+ the report number.
+
+ @returns
+ This function returns the actual number of bytes written and
+ -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length);
+
+ /** @brief Get a feature report from a HID device.
+
+ Set the first byte of @p data[] to the Report ID of the
+ report to be read. Make sure to allow space for this
+ extra byte in @p data[]. Upon return, the first byte will
+ still contain the Report ID, and the report data will
+ start in data[1].
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param data A buffer to put the read data into, including
+ the Report ID. Set the first byte of @p data[] to the
+ Report ID of the report to be read, or set it to zero
+ if your device does not use numbered reports.
+ @param length The number of bytes to read, including an
+ extra byte for the report ID. The buffer can be longer
+ than the actual report.
+
+ @returns
+ This function returns the number of bytes read plus
+ one for the report ID (which is still in the first
+ byte), or -1 on error.
+ */
+ int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length);
+
+ /** @brief Close a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ */
+ void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device);
+
+ /** @brief Get The Manufacturer String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Product String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get The Serial Number String from a HID device.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string from a HID device, based on its string index.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+ @param string_index The index of the string to get.
+ @param string A wide string buffer to put the data into.
+ @param maxlen The length of the buffer in multiples of wchar_t.
+
+ @returns
+ This function returns 0 on success and -1 on error.
+ */
+ int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen);
+
+ /** @brief Get a string describing the last error which occurred.
+
+ @ingroup API
+ @param device A device handle returned from hid_open().
+
+ @returns
+ This function returns a string containing the last error
+ which occurred or NULL if none has occurred.
+ */
+ HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/redist/json_helpers.c b/redist/json_helpers.c
index 7690318..0267932 100644
--- a/redist/json_helpers.c
+++ b/redist/json_helpers.c
@@ -7,11 +7,11 @@
#include <string.h>
#include "json_helpers.h"
#include <jsmn.h>
-#ifndef __FreeBSD__
+#if !defined(__FreeBSD__) && !defined(__APPLE__)
#include <malloc.h>
#endif
-#ifdef _WIN32
+#ifdef _MSC_VER
#include <stdarg.h>
// Windows doesn't provide asprintf, so we need to make it.
@@ -107,7 +107,7 @@ void json_write_str(FILE* f, const char* tag, const char* v) {
void (*json_begin_object)(char* tag) = NULL;
void (*json_end_object)() = NULL;
-void (*json_tag_value)(char* tag, char** values, uint16_t count) = NULL;
+void (*json_tag_value)(char* tag, char** values, uint8_t count) = NULL;
uint32_t JSON_STRING_LEN;
@@ -146,7 +146,7 @@ static uint16_t json_load_array(const char* JSON_STRING, jsmntok_t* tokens, uint
values[i] = substr(JSON_STRING, t->start, t->end, JSON_STRING_LEN);
}
- if (json_tag_value != NULL) json_tag_value(tag, values, i);
+ if (json_tag_value != NULL) json_tag_value(tag, values, (uint8_t)i);
for (i=0;i<size;++i) free(values[i]);
@@ -159,12 +159,13 @@ void json_load_file(const char* path) {
char* JSON_STRING = load_file_to_mem(path);
if (JSON_STRING==NULL) return;
- JSON_STRING_LEN = strlen(JSON_STRING);
+ JSON_STRING_LEN = (uint32_t)strlen(JSON_STRING);
jsmn_parser parser;
jsmn_init(&parser);
- uint32_t items = jsmn_parse(&parser, JSON_STRING, JSON_STRING_LEN, NULL, 0);
+ int32_t items = jsmn_parse(&parser, JSON_STRING, JSON_STRING_LEN, NULL, 0);
+ if (items < 0) return;
jsmntok_t* tokens = malloc(items * sizeof(jsmntok_t));
jsmn_init(&parser);
@@ -172,7 +173,7 @@ void json_load_file(const char* path) {
int16_t children = -1;
- for (i=0; i<items; i+=2)
+ for (i=0; i<(int)items; i+=2)
{
//increment i on each successful tag + values combination, not individual tokens
jsmntok_t* tag_t = tokens+i;
diff --git a/redist/json_helpers.h b/redist/json_helpers.h
index 1670058..1cccfe3 100644
--- a/redist/json_helpers.h
+++ b/redist/json_helpers.h
@@ -14,7 +14,7 @@ void json_write_str(FILE* f, const char* tag, const char* v);
void json_load_file(const char* path);
extern void (*json_begin_object)(char* tag);
extern void (*json_end_object)();
-extern void (*json_tag_value)(char* tag, char** values, uint16_t count);
+extern void (*json_tag_value)(char* tag, char** values, uint8_t count);
#endif \ No newline at end of file
diff --git a/redist/linmath.c b/redist/linmath.c
index dd6bd15..eefcd5f 100644
--- a/redist/linmath.c
+++ b/redist/linmath.c
@@ -207,28 +207,28 @@ void quattomatrix(FLT * matrix44, const FLT * qin)
void quatfrommatrix( FLT * q, const FLT * matrix44 )
{
//Algorithm from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/
- float tr = matrix44[0] + matrix44[5] + matrix44[10];
+ FLT tr = matrix44[0] + matrix44[5] + matrix44[10];
if (tr > 0) {
- float S = sqrt(tr+1.0) * 2; // S=4*qw
- q[0] = 0.25 * S;
+ FLT S = FLT_SQRT(tr+1.0) * 2.; // S=4*qw
+ q[0] = 0.25f * S;
q[1] = (matrix44[9] - matrix44[6]) / S;
q[2] = (matrix44[2] - matrix44[8]) / S;
q[3] = (matrix44[4] - matrix44[1]) / S;
} else if ((matrix44[0] > matrix44[5])&(matrix44[0] > matrix44[10])) {
- float S = sqrt(1.0 + matrix44[0] - matrix44[5] - matrix44[10]) * 2; // S=4*qx
+ FLT S = FLT_SQRT(1.0 + matrix44[0] - matrix44[5] - matrix44[10]) * 2.; // S=4*qx
q[0] = (matrix44[9] - matrix44[6]) / S;
- q[1] = 0.25 * S;
+ q[1] = 0.25f * S;
q[2] = (matrix44[1] + matrix44[4]) / S;
q[3] = (matrix44[2] + matrix44[8]) / S;
} else if (matrix44[5] > matrix44[10]) {
- float S = sqrt(1.0 + matrix44[5] - matrix44[0] - matrix44[10]) * 2; // S=4*qy
+ FLT S = FLT_SQRT(1.0 + matrix44[5] - matrix44[0] - matrix44[10]) * 2.; // S=4*qy
q[0] = (matrix44[2] - matrix44[8]) / S;
q[1] = (matrix44[1] + matrix44[4]) / S;
- q[2] = 0.25 * S;
+ q[2] = 0.25f * S;
q[3] = (matrix44[6] + matrix44[9]) / S;
} else {
- float S = sqrt(1.0 + matrix44[10] - matrix44[0] - matrix44[5]) * 2; // S=4*qz
+ FLT S = FLT_SQRT(1.0 + matrix44[10] - matrix44[0] - matrix44[5]) * 2.; // S=4*qz
q[0] = (matrix44[4] - matrix44[1]) / S;
q[1] = (matrix44[2] + matrix44[8]) / S;
q[2] = (matrix44[6] + matrix44[9]) / S;
diff --git a/redist/os_generic.c b/redist/os_generic.c
index 0993d7a..1ab4863 100644
--- a/redist/os_generic.c
+++ b/redist/os_generic.c
@@ -55,6 +55,7 @@ void * OGJoinThread( og_thread_t ot )
{
WaitForSingleObject( ot, INFINITE );
CloseHandle( ot );
+ return 0;
}
void OGCancelThread( og_thread_t ot )
diff --git a/redist/symbol_enumerator.c b/redist/symbol_enumerator.c
index 7d33900..fcb3727 100644
--- a/redist/symbol_enumerator.c
+++ b/redist/symbol_enumerator.c
@@ -51,9 +51,13 @@ BOOL WINAPI SymEnumSymbols(
);
BOOL WINAPI SymInitialize(
- HANDLE hProcess,
- PCTSTR UserSearchPath,
- BOOL fInvadeProcess
+ HANDLE hProcess,
+ PCTSTR UserSearchPath,
+ BOOL fInvadeProcess
+);
+
+BOOL WINAPI SymCleanup(
+ HANDLE hProcess
);
BOOL CALLBACK __cdecl mycb(