/*****************************************************
* Decode usages using HidGen's initialization files *
*****************************************************
*110830 created
*/
#include "hidparse.h"
// Parsed DT.INI and *.UPG files.
// This structure tree is not intended to be freed recursively, it is allocated in one heap.
struct UE { // Usage Entry
USAGE u[2]; // range from-to, equal when one value only
char *name; // usage string (template), ASCII (7-bit english only)
};
struct UPE { // Usage Page Entry
USAGE up[2]; // range from-to, equal when one value only
char* name; // usage page string (template), ASCII (7-bit english only)
UE* ulist; // array of Usage Entries
int ulen; // length of array
bool Build(const TCHAR *fname);
};
struct UP {
UPE* uplist; // array of Usage Page Entries
int uplen; // length of array
HANDLE heap; // using Windows Heap functions
bool Build(const TCHAR *directory);
}uplist;
static void HeapGrow(void*&p, int&len, int elemsize) {
if (!(len&15)) { // action every 16 elements
if (p) p=HeapReAlloc(uplist.heap,HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,p,(len+16)*elemsize);
else p=HeapAlloc(uplist.heap,HEAP_GENERATE_EXCEPTIONS|HEAP_ZERO_MEMORY,16*elemsize);
}
len++;
}
static char* mystrdup(char* s) {
int l=lstrlenA(s)+1;
char*p=(char*)HeapAlloc(uplist.heap,HEAP_GENERATE_EXCEPTIONS,l);
CopyMemory(p,s,l);
return p;
}
bool UPE::Build(const TCHAR *fname) {
FILE *f=_tfopen(fname,T("r"));
if (!f) return false;
char line[128];
fgets(line,sizeof(line),f); // Name of usage page (unused)
fgets(line,sizeof(line),f); // Type of usage (either "NORMAL" or "REPEATING")
while (fgets(line,sizeof(line),f)) {
HeapGrow((void*&)ulist,ulen,sizeof(UE));
UE&ue=ulist[ulen-1]; // Address the newly available element
if (sscanf(line,"%hx-%hx",&ue.u[0],&ue.u[1])==1) ue.u[1]=ue.u[0];
char *p=StrPBrkA(line,"\t ");
if (p) {
char *e=StrPBrkA(++p,"\r\n");
if (e) *e=0;
ue.name=mystrdup(p);
}
}
fclose(f);
return true;
}
bool UP::Build(const TCHAR *directory) {
TCHAR fname[MAX_PATH];
PathCombine(fname,directory,T("dt.ini"));
int n=GetPrivateProfileInt(T("UsagePages"),T("Count"),0,fname);
if (!n) return false;
for (int i=0; i<n; i++) {
TCHAR key[16];
wnsprintf(key,elemof(key),T("UP%d"),i);
TCHAR buf[128];
GetPrivateProfileString(T("UsagePages"),key,NULL,buf,elemof(buf),fname);
TCHAR *k1=StrChr(buf,',');
if (k1) {
*k1++=0;
TCHAR *k2=StrChr(k1,',');
if (k2) {
*k2++=0;
HeapGrow((void*&)uplist,uplen,sizeof(UPE));
UPE&upe=uplist[uplen-1];
upe.up[0]=upe.up[1]=StrToInt(buf);
#ifdef UNICODE
int l=lstrlen(k1)+1;
upe.name=(char*)HeapAlloc(heap,HEAP_GENERATE_EXCEPTIONS,l);
WideCharToMultiByte(CP_ACP,0,k1,l,upe.name,l,NULL,NULL);
#else
upe.name=mystrdup(k1);
#endif
TCHAR fname[MAX_PATH];
PathCombine(fname,directory,k2);
upe.Build(fname);
}
}
}
return true;
}
bool UsageDecode::Init(const TCHAR*directory) {
uplist.heap=HeapCreate(HEAP_GENERATE_EXCEPTIONS,0x10000,0x100000);
return uplist.Build(directory);
}
void UsageDecode::Done() {
HeapDestroy(uplist.heap);
uplist.heap=0;
uplist.uplen=0;
}
int UsageDecode::Decode(USAGE_AND_PAGE u, BYTE flags, TCHAR*buf, int buflen) {
char sp[64]; // name of usage page
char su[64]; // name of usage
int i;
UPE *upe;
// Scan for usage page (always)
for (upe=uplist.uplist,i=0; i<uplist.uplen; i++,upe++)
if (upe->up[0]<=u.UsagePage && u.UsagePage<=upe->up[1]) {
wnsprintfA(sp,elemof(sp),upe->name,u.UsagePage-upe->up[0]);
break;
}
// When not found, make hexadecimal number
if (i==uplist.uplen) {
upe=NULL; // no Usage Page entry
wnsprintfA(sp,elemof(sp),"0x%02X",u.UsagePage);
}
// Scan for usage (when needed)
if (flags&1) {
UE *ue;
if (upe) {
for (ue=upe->ulist,i=0; i<upe->ulen; i++,ue++)
if (ue->u[0]<=u.Usage && u.Usage<=ue->u[1]) {
wnsprintfA(su,elemof(su),ue->name,u.Usage-ue->u[0]);
goto found_usage;
}
ue=NULL; // no Usage entry
found_usage:;
}else ue=NULL;
// When not found, make hexadecimal number
if (!ue) wnsprintfA(su,elemof(su),"0x%02X",u.Usage);
}
// Generate final strings
switch (flags&3) {
case 3: // long usage
return wnsprintf(buf,buflen,T("Usage (") ASTR T(":") ASTR T(")"),sp,su);
case 1: // short usage
return wnsprintf(buf,buflen,T("Usage (") ASTR T(")"),su);
case 2: // usage page
return wnsprintf(buf,buflen,T("UsagePage (") ASTR T(")"),sp);
}
return 0;
}
Vorgefundene Kodierung: ASCII (7 bit) | 2
|