djpnewton / vmulti

Virtual Multiple HID Driver (multitouch, mouse, digitizer, keyboard, joystick)
MIT License
401 stars 171 forks source link

More than two touch points at a time #3

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi,

currently, vmulti_update_multitouch supports only two touch points to generate 
at a time. Can you add support for multiple points (for example an array as 
input parameter)?

Thank you! 

Original issue reported on code.google.com by matgr...@gmail.com on 2 Dec 2010 at 1:25

GoogleCodeExporter commented 9 years ago
The maximum touch points supported needs to be set by the multitouch hid 
descriptor, so what do you think is a reasonable maximum number of touches? 5?

Original comment by djpnew...@gmail.com on 3 Dec 2010 at 8:26

GoogleCodeExporter commented 9 years ago
How about 20? You see, when you have big touch screen, more than 1 user can 
touch and operate. 20 is maximum for 2 simultaneous users. If I were you, I 
will consider setting it to a value that is not very high, but nearly possible 
to achieve by multiple users. For example 50, or 100 (ok, 100 is maybe too 
many). What do you think about it?

Original comment by matgr...@gmail.com on 3 Dec 2010 at 9:52

GoogleCodeExporter commented 9 years ago
So, what is your opinion?

Original comment by matgr...@gmail.com on 9 Dec 2010 at 3:52

GoogleCodeExporter commented 9 years ago
Ok I think this will be simple enough:

1) change MULTI_MAX_COUNT to 20 in vmulticommon.h, rebuild and reinstall driver
2) use vmulti_update_multitouch client api in hybrid mode (see 
http://www.microsoft.com/whdc/device/input/DigitizerDrvs_touch.mspx):

  "In hybrid mode, the numbers of contacts that can be reported in one packet is less
than the maximum that the device supports. For example, a device that supports a
maximum of 48 contacts can set up its top-level collection to report a maximum 
of
12 contacts in one packet. If it must report 48 contacts, it can break these 
down into
4 serial packets that report 12 contacts each.

When a device chooses to report data in this manner, the actual contact usage 
value
in the first packet should reflect the total number of contacts that are being 
reported
in the hybrid packets. The other serial packets should have an actual count of 
0. Using
the preceding example, the actual count usage in the first packet has a value 
of 48,
whereas the subsequent three packets have an actual usage count of 0."

Original comment by djpnew...@gmail.com on 11 Dec 2010 at 12:59

GoogleCodeExporter commented 9 years ago
Hi, I'm back after a while :-)
So I did the step 1, but after reinstall testvmulti.exe /multitouch ended with 
success, but nothing happened. No visual feedback of a test touch. What could 
go wrong? Thanks!

Original comment by matgr...@gmail.com on 7 Mar 2011 at 5:28

GoogleCodeExporter commented 9 years ago
If you look at "My Computer" properties it should tell you how many touches the 
system supports. What does that say?

Original comment by djpnew...@gmail.com on 14 Mar 2011 at 2:17

GoogleCodeExporter commented 9 years ago
It says 40, that's what I set in MULTI_MAX_COUNT.

Original comment by matgr...@gmail.com on 14 Mar 2011 at 10:11

GoogleCodeExporter commented 9 years ago
Now the vmulti_update_multitouch function probably needs updating

Original comment by djpnew...@gmail.com on 20 Mar 2011 at 9:57

GoogleCodeExporter commented 9 years ago
Ok, but could you please tell me how? Or paste code here or to my email? It's 
your code and I don't understand it fully. It would take me some time to get 
into it and figure out what to change, but I'm in a hurry right now and need to 
work on other parts of my project. Thank you, I really appreciate your help.

Original comment by matgr...@gmail.com on 22 Mar 2011 at 9:33

GoogleCodeExporter commented 9 years ago
I dont have the time to make the change to the vmulti_update_multitouch client 
api at the moment.

I will be away on holiday for the next few weeks sorry. If you bug me at the 
end of April I might be able to look at it then

Original comment by djpnew...@gmail.com on 25 Mar 2011 at 3:12

GoogleCodeExporter commented 9 years ago
End of April is my deadline for the whole project. If it's not working I'm 
screwed :-(
Please, could you at least explain to me what to change? I REALLY need it. 
Thanks!

PS: Sorry for bothering you like this, but I'm desperate...

Original comment by matgr...@gmail.com on 25 Mar 2011 at 8:13

GoogleCodeExporter commented 9 years ago
Have you read the white paper at 
http://www.microsoft.com/whdc/device/input/DigitizerDrvs_touch.mspx ? 
Specifically the part covering hybrid reporting mode?

I haven't tried it but I think the vmulti_update_multitouch function needs to 
be changed to something like this:

BOOL vmulti_update_multitouch(PTOUCH pTouch, BYTE actualCount)
{
    VMultiReportHeader* pReport = NULL;
    VMultiMultiTouchReport* pMultiReport = NULL;
    int numberOfTouchesSent = 0;

    if (VENDOR_REPORT_SIZE <= sizeof(VMultiReportHeader) + sizeof(VMultiMultiTouchReport))
    {
        return FALSE;
    }

    //
    // Set the report header
    //

    pReport = (VMultiReportHeader*)vmulti->vendorReport;
    pReport->ReportID = REPORTID_VENDOR_01;
    pReport->ReportLength = sizeof(VMultiMultiTouchReport);

    while (numberOfTouchesSent < actualCount)
    {

        //
        // Set the input report
        //

        pMultiReport = (VMultiMultiTouchReport*)(vmulti->vendorReport + sizeof(VMultiReportHeader));
        pMultiReport->ReportID = REPORTID_MTOUCH;
        memcpy(pMultiReport->Touch, pTouch + numberOfTouchesSent, sizeof(TOUCH));
        if (actualCount % 2 == 0)
            memcpy(pMultiReport->Touch + 1, pTouch + numberOfTouchesSent + 1, sizeof(TOUCH));
        if (numberOfTouchesSent == 0)
            pMultiReport->ActualCount = actualCount;
        else
            pMultiReport->ActualCount = 0;

        // Send the report
        if (!HidOutput(TRUE, vmulti->hVMulti, (PCHAR)vmulti->vendorReport, VENDOR_REPORT_SIZE))
            return FALSE;

        numberOfTouchesSent += 2;
    }

    return TRUE;
}

Original comment by djpnew...@gmail.com on 25 Mar 2011 at 8:42

GoogleCodeExporter commented 9 years ago
A brief explanation of the above function:
 BOOL vmulti_update_multitouch(PTOUCH pTouch, BYTE actualCount)

pTouch is an array of TOUCH structures (defined in vmulticommon.h) and 
actualCount is the number of touch points in the array.

Once again I havent compiled or tried this (I am about to fly overseas for a 
few weeks and am running short on time).

Original comment by djpnew...@gmail.com on 25 Mar 2011 at 8:45

GoogleCodeExporter commented 9 years ago
Ok, I think I quite understand it now. THANK YOU VERY MUCH!
I should be able to make it work now... hopefully.

Enjoy your holiday, you deserve it :-)

Original comment by matgr...@gmail.com on 25 Mar 2011 at 9:00

GoogleCodeExporter commented 9 years ago
Hi,

I know that you are probably still on holiday, but hope you will respond as 
soon as possible. I have tried your code and have found out several things:

1. You forgot 'pvmulti_client vmulti' in input parameters

2. VENDOR_REPORT_SIZE has to be adjusted according to the new MULTI_MAX_COUNT, 
otherwise the code returns FALSE at the first if condition. 
sizeof(VMultiMultiTouchReport) is 402, but I have read somewhere that report 
size should be equal to 2^x, so I set VENDOR_REPORT_SIZE to 512, ie 0x200. Is 
it ok?

3. I think that 'if (actualCount % 2 == 0)' condition is wrong. If you want to 
send two points at a time IN CASE OF even actualCount, then you should not 
increase numberOfTouchesSent + 2 in all cases. I suggest to change this 
condition to 'if (numberOfTouchesSent <= actualCount - 2)'. In this case, two 
points are sent in all cases, except the one last odd point, which will be sent 
alone.

However, you are still rewriting first two elements in pMultiReport->Touch, I 
don't know if it is intended. Moreover, if actualCount is odd, then the second 
point is not overwritten, beacause the last one is written to the frist elment, 
so the same point is sent as before (I mean the second one).

Anyway, it is still not working. Not even the old function. 
HidD_SetOutputReport is returning error 87 and WriteFile error 1784. I have 
searched, but have not found anything meaningful. Only that it has somtehing to 
do with the report size.

That is about it for now. Back to the struggle :-/

Original comment by matgr...@gmail.com on 19 Apr 2011 at 6:24

GoogleCodeExporter commented 9 years ago
Oh, well according to msdn's system error codes, 87 is ERROR_INVALID_PARAMETER 
and 1784 is ERROR_INVALID_USER_BUFFER. But that is not very helpful, at least 
for me...

Original comment by matgr...@gmail.com on 19 Apr 2011 at 6:35

GoogleCodeExporter commented 9 years ago
Hi,

I am back with great news! IT IS WORKING! I have been drawing in Windows Paint 
with 8 finger simultaneously, using gestures and controling everything in the 
system a while ago :-) 

In order to help the others, who might need this as well, here is how I have 
done it.
My assumtion about VENDOR_REPORT_SIZE was wrong. What had to be changed is 
_VMULTI_MULTITOUCH_REPORT struct. Since the final system report contains only 
two points (I think from the code I have seen, correct me if I am wrong), the 
Touch array has to be Touch[2], instead of Touch[MULTI_MAX_COUNT]. I have set 
VENDOR_REPORT_SIZE back to 65 (0x41) and here is my current code for 
vmulti_update_multitouch:

BOOL vmulti_update_multitouch(pvmulti_client vmulti, PTOUCH pTouch, BYTE 
actualCount)
{
  VMultiReportHeader* pReport = NULL;
  VMultiMultiTouchReport* pMultiReport = NULL;
  int numberOfTouchesSent = 0;
  unsigned char success = 0;

  if (VENDOR_REPORT_SIZE <= sizeof(VMultiReportHeader) + sizeof(VMultiMultiTouchReport))
    return FALSE;

  //
  // Set the report header
  //
  pReport = (VMultiReportHeader*)vmulti->vendorReport;
  pReport->ReportID = REPORTID_VENDOR_01;
  pReport->ReportLength = (BYTE)sizeof(VMultiMultiTouchReport);

  while (numberOfTouchesSent < actualCount)
  {
    // Set the input report
    pMultiReport = (VMultiMultiTouchReport*)(vmulti->vendorReport + sizeof(VMultiReportHeader));
    pMultiReport->ReportID = REPORTID_MTOUCH;
    memcpy(pMultiReport->Touch, pTouch + numberOfTouchesSent, sizeof(TOUCH));

    if (numberOfTouchesSent > actualCount - 2)
    {
      pMultiReport->Touch[1].ContactID = NULL;
      pMultiReport->Touch[1].Status = NULL;
      pMultiReport->Touch[1].XValue = NULL;
      pMultiReport->Touch[1].YValue = NULL;
      pMultiReport->Touch[1].Width = NULL;
      pMultiReport->Touch[1].Height = NULL;
    }
    else 
      memcpy(pMultiReport->Touch + 1, pTouch + numberOfTouchesSent + 1, sizeof(TOUCH));

    if (numberOfTouchesSent == 0)
      pMultiReport->ActualCount = actualCount;
    else
      pMultiReport->ActualCount = 0;

    // Send the report
    if (!HidOutput(FALSE, vmulti->hVMulti, (PCHAR)vmulti->vendorReport, VENDOR_REPORT_SIZE))
      success += 1;

    numberOfTouchesSent += 2;
  }

  return (success == 0);
}

So, once again, this code for vmulti_update_multitouch and change 
Touch[MULTI_MAX_COUNT] to Touch[2] in _VMULTI_MULTITOUCH_REPORT struct in 
vmulticommon.h

As for PTOUCH data, that has to be sent as an input parameter in 
vmulti_update_multitouch, here is an example of generating such structure for 
any number of testing touch points. 

actualCount = 4; // set whatever number you want, lower than MULTI_MAX_COUNT
pTouch = (TOUCH*) malloc(actualCount*sizeof(TOUCH));
for (i=0; i<actualCount; i++)
{
  pTouch[i].ContactID = i+1;
  pTouch[i].Status = MULTI_CONFIDENCE_BIT | MULTI_IN_RANGE_BIT | MULTI_TIPSWITCH_BIT;
  // max x or y coordinate is 32767 so actualCount should be less than 32 for this example  
  pTouch[i].XValue = (i+1)*1000;
  pTouch[i].YValue = (i+1)*1000;
  pTouch[i].Width = 20;
  pTouch[i].Height = 30;
}

if (!vmulti_update_multitouch(vmulti, pTouch, actualCount))
  printf("vmulti_update_multitouch TOUCH_DOWN FAILED\n");

for (i=0; i<actualCount; i++)
  pTouch[i].Status = 0;

if (!vmulti_update_multitouch(vmulti, pTouch, actualCount))
  printf("vmulti_update_multitouch TOUCH_UP FAILED\n");

free(pTouch);

THANK YOU VERY MUCH! For this driver and for your help. I hope, that this 
little contribution from me will help you and others in return. :-) Bye!

Original comment by matgr...@gmail.com on 21 Apr 2011 at 8:48

GoogleCodeExporter commented 9 years ago
Hi Mat,

Good work, I committed the changed along with the problems you spotted.

Cheers

Original comment by djpnew...@gmail.com on 30 Apr 2011 at 1:12

GoogleCodeExporter commented 9 years ago
I cannot get two input get working on Paint,
I can see one input on paint.

Please find the code snippet below,
pMultiReport = (VMultiMultiTouchReport*)(vmulti->vendorReport + 
sizeof(VMultiReportHeader));
        pMultiReport->ReportID = REPORTID_MTOUCH;
        pMultiReport->Touch[0].Status = MULTI_CONFIDENCE_BIT | MULTI_IN_RANGE_BIT | MULTI_TIPSWITCH_BIT;
        pMultiReport->Touch[0].XValue = (int) (tempX * 1000000);
        pMultiReport->Touch[0].YValue = (int) (tempY * 1000000);//4000;//(int) (tempY * 100000);
        pMultiReport->Touch[0].Width = 20;
        pMultiReport->Touch[0].Height = 30;
        pMultiReport->Touch[0].ContactID = 0;//contactId1;
        pMultiReport->Touch[1].Status = MULTI_CONFIDENCE_BIT | MULTI_IN_RANGE_BIT | MULTI_TIPSWITCH_BIT;
        pMultiReport->Touch[1].XValue = (int) (tempX * 1000000) + 1000;//status2;//x2;
        pMultiReport->Touch[1].YValue = (int) (tempY * 1000000) + 2000;//y2;
        pMultiReport->Touch[1].Width = 20;
        pMultiReport->Touch[1].Height = 30;
        pMultiReport->Touch[1].ContactID = 1;//contactId2;
        pMultiReport->ActualCount = 2;//actualCount;

Can you please provide any pointer, Am I going in right direction?

Any help would be highly appreciated,
Thanks

Original comment by goodcaus...@googlemail.com on 4 May 2011 at 1:36

GoogleCodeExporter commented 9 years ago
hmmmm.. are your x and y values in the range 
MULTI_MIN_COORDINATE<->MULTI_MAX_COORDINATE?

Are you dragging the touch points? If you simply move the touch points to one 
location you will only see the cursor move.

Failing that have you tried starting with testvmulti.exe as a base and 
modifying it?

Original comment by djpnew...@gmail.com on 4 May 2011 at 10:21

GoogleCodeExporter commented 9 years ago
HI Daniel,

THanks you so much for your reply,

I got it working!

pMultiReport = (VMultiMultiTouchReport*)(vmulti->vendorReport + 
sizeof(VMultiReportHeader));
        pMultiReport->ReportID = REPORTID_MTOUCH;
        pMultiReport->Touch[0].Status = MULTI_CONFIDENCE_BIT | MULTI_IN_RANGE_BIT | MULTI_TIPSWITCH_BIT;
        pMultiReport->Touch[0].XValue = (int) (tempX * 1000000);
        pMultiReport->Touch[0].YValue = (int) (tempY * 1000000);
        pMultiReport->Touch[0].Width = 0;
        pMultiReport->Touch[0].Height = 0;
        pMultiReport->Touch[0].ContactID = 0;//contactId1;
        pMultiReport->Touch[1].Status = 0;//status2;
        pMultiReport->Touch[1].XValue = 0;//x2;
        pMultiReport->Touch[1].YValue = 0;//y2;
        pMultiReport->Touch[1].Width = 0;
        pMultiReport->Touch[1].Height = 0;
        pMultiReport->Touch[1].ContactID = 0;//contactId2;
        pMultiReport->ActualCount = 1;//actualCount;

        {
        if (!HidD_SetOutputReport(vmulti, (PCHAR)vmulti->vendorReport, 65))
        {
            printf("failed HidD_SetOutputReport %d\n", GetLastError());
            //return FALSE;
        }

        pMultiReport->Touch[0].XValue = (int) (tempX * 1000000) + 4000;
        pMultiReport->Touch[0].YValue = (int) (tempY * 1000000) + 3000; 
        pMultiReport->Touch[0].ContactID = 1;//contactId1;
        if (!HidD_SetOutputReport(vmulti, (PCHAR)vmulti->vendorReport, 65))
        {
            printf("failed HidD_SetOutputReport %d\n", GetLastError());

        }

I above code works ,  I think I need to see it twice for two independent moves,

I have a question on KMDF driver

As we manually some of the request to the read queue for the HID_READ_REPORT, 
it will be failed all the time,
Do we need to queue the request every time even we know it fails every time?

Thanks for your support, I know you are very busy with your schedule, Thanks 
for taking some time.

Original comment by goodcaus...@googlemail.com on 5 May 2011 at 9:01