*** HIDReport.h.dist	2024-04-18 08:04:24.950272000 +0100
--- HIDReport.h	2024-04-25 23:33:06.950009856 +0100
***************
*** 29,34 ****
--- 29,35 ----
  
  		uint8					Type() { return fType; };
  		uint8					ID() { return fReportID; };
+ 		status_t				Status() { return fReportStatus; };
  		size_t					ReportSize() { return (fReportSize + 7) / 8; };
  
  		HIDParser *				Parser() { return fParser; };
***************
*** 56,61 ****
--- 57,63 ----
  
  #ifndef USERLAND_HID
  		status_t				WaitForReport(bigtime_t timeout);
+ 		status_t				WaitMoreReport(bigtime_t timeout);
  		void					DoneProcessing();
  #endif
  
*** HIDReport.cpp.dist	2024-04-25 23:27:01.043253760 +0100
--- HIDReport.cpp	2024-04-25 23:32:27.376963072 +0100
***************
*** 251,256 ****
--- 251,269 ----
  	return B_OK;
  }
  
+ status_t
+ HIDReport::WaitMoreReport(bigtime_t timeout)
+ {
+ 	while (atomic_get(&fBusyCount) != 0)
+ 		snooze(1000);
+ 
+ 	if (fReportStatus != B_OK)
+ 		return fReportStatus;
+ 
+ 	atomic_add(&fBusyCount, 1);
+ 	return B_OK;
+ }
+ 
  
  void
  HIDReport::DoneProcessing()
*** ProtocolHandler.h.dist	2024-04-22 00:21:07.873725952 +0100
--- ProtocolHandler.h	2024-04-26 15:34:58.022806528 +0100
***************
*** 11,16 ****
--- 11,20 ----
  
  #define PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED		0x80000000
  
+ #define PROTOCOL_NEED_MOUSE_XY     0x0001
+ #define PROTOCOL_NEED_MOUSE_BUTTON  0x0002
+ #define PROTOCOL_NEED_MOUSE_WHEEL   0x0004
+ #define PROTOCOL_NEED_MOUSE_ALL     0x0007
  
  class HIDDevice;
  class HIDReport;
***************
*** 22,27 ****
--- 26,34 ----
  									const char *basePath,
  									size_t ringBufferSize);
  	virtual						~ProtocolHandler();
+ 	bool NeedFlag(int32 flag) { return (flag & fNeedCapability) != 0; }
+ 	void ClearFlag(int32 flag) { fNeedCapability &= ~flag; }
+ 	void SetFlags(int32 flag) { fNeedCapability = flag; }
  
  			status_t			InitCheck() { return fStatus; }
  
***************
*** 64,69 ****
--- 71,77 ----
  			HIDDevice *			fDevice;
  			const char *		fBasePath;
  			char *				fPublishPath;
+ 			uint32				fNeedCapability;
  			struct ring_buffer *fRingBuffer;
  
  			ProtocolHandler *	fNextHandler;
*** ProtocolHandler.cpp.dist	2024-04-18 08:04:25.077332480 +0100
--- ProtocolHandler.cpp	2024-04-26 14:40:35.703594496 +0100
***************
*** 27,32 ****
--- 27,33 ----
  		fDevice(device),
  		fBasePath(basePath),
  		fPublishPath(NULL),
+ 		fNeedCapability(0),
  		fRingBuffer(NULL),
  		fNextHandler(NULL)
  {
*** MouseProtocolHandler.h.dist	2024-04-23 10:47:52.149159936 +0100
--- MouseProtocolHandler.h	2024-04-26 14:06:34.458489856 +0100
***************
*** 22,30 ****
  
  class MouseProtocolHandler : public ProtocolHandler {
  public:
! 								MouseProtocolHandler(HIDReport &report,
! 									HIDReportItem &xAxis,
! 									HIDReportItem &yAxis);
  
  	static	void				AddHandlers(HIDDevice &device,
  									HIDCollection &collection,
--- 22,34 ----
  
  class MouseProtocolHandler : public ProtocolHandler {
  public:
! 								MouseProtocolHandler(HIDReport *report);
! 						uint32		GetButtonInfo(HIDReport *report);
! 						void		InitAxes(HIDReport *report,
! 									HIDReportItem *xAxis,
! 									HIDReportItem *yAxis);
! 						void		InitWheel(HIDReport *report,
! 									HIDReportItem *wheel);
  
  	static	void				AddHandlers(HIDDevice &device,
  									HIDCollection &collection,
***************
*** 36,46 ****
  private:
  			status_t			_ReadReport(void *buffer, uint32 *cookie);
  
! 			HIDReport &			fReportWheel;
! 			HIDReport &			fReportAxes;
  
! 			HIDReportItem &		fXAxis;
! 			HIDReportItem &		fYAxis;
  			HIDReportItem *		fWheel;
  			HIDReportItem *		fHorizontalPan;
  			HIDReportItem *		fButtons[B_MAX_MOUSE_BUTTONS];
--- 40,50 ----
  private:
  			status_t			_ReadReport(void *buffer, uint32 *cookie);
  
! 			HIDReport *			fReportAxes;
! 			HIDReport *			fReportWheel;
  
! 			HIDReportItem *		fXAxis;
! 			HIDReportItem *		fYAxis;
  			HIDReportItem *		fWheel;
  			HIDReportItem *		fHorizontalPan;
  			HIDReportItem *		fButtons[B_MAX_MOUSE_BUTTONS];
*** MouseProtocolHandler.cpp.dist	2024-04-18 08:04:25.054525952 +0100
--- MouseProtocolHandler.cpp	2024-04-26 15:41:31.460849152 +0100
***************
*** 22,69 ****
  #include <kernel.h>
  #include <keyboard_mouse_driver.h>
  
  
! MouseProtocolHandler::MouseProtocolHandler(HIDReport &report,
! 	HIDReportItem &xAxis, HIDReportItem &yAxis)
  	:
! 	ProtocolHandler(report.Device(), "input/mouse/" DEVICE_PATH_SUFFIX "/", 0),
! 	fReport(report),
! 
! 	fXAxis(xAxis),
! 	fYAxis(yAxis),
  	fWheel(NULL),
  	fHorizontalPan(NULL),
- 
  	fLastButtons(0),
  	fClickCount(0),
  	fLastClickTime(0),
  	fClickSpeed(250000)
  {
  	uint32 buttonCount = 0;
! 	for (uint32 i = 0; i < report.CountItems(); i++) {
! 		HIDReportItem *item = report.ItemAt(i);
  		if (!item->HasData())
  			continue;
  
  		if (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON
! 			&& item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS) {
  			fButtons[buttonCount++] = item;
  		}
  	}
  
! 	fButtons[buttonCount] = NULL;
  
! 	fWheel = report.FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP,
! 		B_HID_UID_GD_WHEEL);
! 	fHorizontalPan = report.FindItem(B_HID_USAGE_PAGE_CONSUMER,
! 		B_HID_UID_CON_AC_PAN);
  
! 	TRACE("mouse device with %" B_PRIu32 " buttons %sand %swheel\n",
  		buttonCount, fHorizontalPan == NULL ? "" : ", horizontal pan ",
  		fWheel == NULL ? "no " : "");
! 	TRACE("report id: %u\n", report.ID());
  }
  
  
  void
  MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
--- 22,142 ----
  #include <kernel.h>
  #include <keyboard_mouse_driver.h>
  
+ //  Supported configurations:
+ //  - one report with axis and button codes
+ //  or
+ //  - two reports:
+ //    -- axis
+ //    -- wheel and buttons, must have wheel
  
! MouseProtocolHandler::MouseProtocolHandler(HIDReport *report)
  	:
! 	ProtocolHandler(report->Device(), "input/mouse/" DEVICE_PATH_SUFFIX "/", 0),
! 	fReportAxes(report),
! 	fReportWheel(report),
! 	fXAxis(NULL),
! 	fYAxis(NULL),
  	fWheel(NULL),
  	fHorizontalPan(NULL),
  	fLastButtons(0),
  	fClickCount(0),
  	fLastClickTime(0),
  	fClickSpeed(250000)
  {
+ 	fButtons[0] = NULL;
+ 	//  Report items yet identifying axes, buttons etc. will be found
+ 	//  and added in later.
+ 	SetFlags(PROTOCOL_NEED_MOUSE_ALL);
+ 	TRACE("mouse device initialized on report id: %u\n", report->ID());
+ }
+ 
+ uint32
+ MouseProtocolHandler::GetButtonInfo(HIDReport *report)
+ {
+ 	// why isn't this just "int"?
  	uint32 buttonCount = 0;
! 	for (buttonCount = 0; buttonCount < B_MAX_MOUSE_BUTTONS; ++buttonCount) {
! 		if (!fButtons[buttonCount])
! 			break;
! 	}
! 	for (uint32 i = 0; i < report->CountItems(); i++) {
! 		HIDReportItem *item = report->ItemAt(i);
  		if (!item->HasData())
  			continue;
+ 		TRACE(" report item : %x %x @%d\n", item->UsagePage(), item->UsageID(), buttonCount);
  
  		if (item->UsagePage() == B_HID_USAGE_PAGE_BUTTON
! 			&& item->UsageID() - 1 < B_MAX_MOUSE_BUTTONS
! 			&& buttonCount < B_MAX_MOUSE_BUTTONS) {
  			fButtons[buttonCount++] = item;
+ 			ClearFlag(PROTOCOL_NEED_MOUSE_BUTTON);
  		}
  	}
  
! 	if (buttonCount < B_MAX_MOUSE_BUTTONS)
! 		fButtons[buttonCount] = NULL;
! 	else
! 		TRACE_ALWAYS("button count maxed out.\n");
! 
! 	if (!fWheel) {
! 	 	fWheel = report->FindItem(B_HID_USAGE_PAGE_GENERIC_DESKTOP,
! 	 		B_HID_UID_GD_WHEEL);
! 		ClearFlag(PROTOCOL_NEED_MOUSE_WHEEL);
! 	}
! 
! 	if (!fHorizontalPan)
! 		fHorizontalPan = report->FindItem(B_HID_USAGE_PAGE_CONSUMER,
! 			B_HID_UID_CON_AC_PAN);
  
! 	return buttonCount;
! }
  
! void
! MouseProtocolHandler::InitAxes(HIDReport *report,
! 	HIDReportItem *xAxis, HIDReportItem *yAxis)
! {
! 	fReportAxes = report;
! 	fXAxis = xAxis;
! 	fYAxis = yAxis;
! 	ClearFlag(PROTOCOL_NEED_MOUSE_XY);
! 
! 	TRACE("InitAxes(Report ID %d\n)\n", report->ID());
! 	uint32 buttonCount = GetButtonInfo(report);
! 
! 	// TRACE_ALWAYS, because build will abort when TRACE is off, due to
! 	// unused button count.
! 	TRACE_ALWAYS("mouse device with %" B_PRIu32 " buttons %sand %swheel\n",
  		buttonCount, fHorizontalPan == NULL ? "" : ", horizontal pan ",
  		fWheel == NULL ? "no " : "");
! 	TRACE("report id: %u\n", fReportAxes->ID());
  }
  
+ void
+ MouseProtocolHandler::InitWheel(HIDReport *report, HIDReportItem *wheel)
+ {
+ 	fReportWheel = report;
+ 	fWheel = wheel;
+ 	ClearFlag(PROTOCOL_NEED_MOUSE_WHEEL);
+ 
+ 	TRACE("InitWheel(Report ID %d\n)\n", report->ID());
+ 	uint32 buttonCount = GetButtonInfo(report);
+ 
+ 	TRACE_ALWAYS("mouse device with %" B_PRIu32 " buttons %sand %swheel\n",
+ 		buttonCount, fHorizontalPan == NULL ? "" : ", horizontal pan ",
+ 		fWheel == NULL ? "no " : "");
+ 	TRACE("report id: %u\n", fReportWheel->ID());
+ }
+ 
+ static MouseProtocolHandler *
+ findNeededHandler(ProtocolHandler *t, int32 need)
+ {
+ 	while (t) {
+ 		if (t->NeedFlag(need))
+ 			return (MouseProtocolHandler *) t;
+ 		t = t->NextHandler();
+ 	}
+ 	return NULL;
+ }
  
  void
  MouseProtocolHandler::AddHandlers(HIDDevice &device, HIDCollection &collection,
***************
*** 105,127 ****
  		// try to find at least an absolute x and y axis
  		HIDReportItem *xAxis = inputReport->FindItem(
  			B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
! 		if (xAxis == NULL || !xAxis->Relative())
! 			continue;
  
! 		HIDReportItem *yAxis = inputReport->FindItem(
! 			B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
! 		if (yAxis == NULL || !yAxis->Relative())
! 			continue;
  
! 		ProtocolHandler *newHandler = new(std::nothrow) MouseProtocolHandler(
! 			*inputReport, *xAxis, *yAxis);
! 		if (newHandler == NULL) {
! 			TRACE("failed to allocated mouse protocol handler\n");
! 			continue;
  		}
  
! 		newHandler->SetNextHandler(handlerList);
! 		handlerList = newHandler;
  	}
  }
  
--- 178,244 ----
  		// try to find at least an absolute x and y axis
  		HIDReportItem *xAxis = inputReport->FindItem(
  			B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_X);
! 		if (xAxis && xAxis->Relative()) {
! 			HIDReportItem *yAxis = inputReport->FindItem(
! 				B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_Y);
! 			if (yAxis && yAxis->Relative()) {
! 
! 				MouseProtocolHandler *oldHandler = findNeededHandler(handlerList, PROTOCOL_NEED_MOUSE_XY);
! 				MouseProtocolHandler *newHandler;
! 				if (oldHandler) {
! 					newHandler = NULL;
! 				} else {
! 					newHandler = new(std::nothrow) MouseProtocolHandler(inputReport);
! 					if (newHandler == NULL) {
! 						TRACE("failed to allocated mouse protocol handler\n");
! 						continue;
! 					} else {
! 						oldHandler = newHandler;
! 					}
! 				}
  
! 				oldHandler->InitAxes(inputReport, xAxis, yAxis);
  
! 				if (newHandler) {
! 					newHandler->SetNextHandler(handlerList);
! 					handlerList = (ProtocolHandler *) newHandler;
! 				}
! //  Here ends the apparently normal mouse button report, with X Y axes
! //  and apparently everything else reported.
! 				continue;
! 			}
! 			// X, no Y
  		}
+ 		TRACE("mouse?  no x/y\n");
+ //  Failed to find x-y, but maybe there's wheel ...
+ //  Honestly I'd rather look for buttons here, but from the listing it seemed
+ //  unclear what the first parameter would be - USAGE_PAGE_GENERIC_DESKTOP ?
+ 		HIDReportItem *wheel = inputReport->FindItem(
+ 			B_HID_USAGE_PAGE_GENERIC_DESKTOP, B_HID_UID_GD_WHEEL);
+ 		if (wheel) {
+ 			MouseProtocolHandler *oldHandler = findNeededHandler(handlerList, PROTOCOL_NEED_MOUSE_WHEEL);
+ 			MouseProtocolHandler *newHandler;
+ 			if (oldHandler) {
+ 				newHandler = NULL;
+ 			} else {
+ 				//  It's the first mouse protocol report.
+ 				newHandler = new(std::nothrow) MouseProtocolHandler(inputReport);
+ 				if (newHandler == NULL) {
+ 					TRACE("failed to allocated mouse protocol handler\n");
+ 					continue;
+ 				} else {
+ 					oldHandler = newHandler;
+ 				}
+ 			}
+ 
+ 			oldHandler->InitWheel(inputReport, wheel);
  
! 			if (newHandler) {
! 				newHandler->SetNextHandler(handlerList);
! 				handlerList = (MouseProtocolHandler *) newHandler;
! 			}
! 		} else
! 			TRACE("mouse?  no wheel\n");
  	}
  }
  
***************
*** 161,167 ****
  
  		case MS_NUM_EVENTS:
  		{
! 			if (fReport.Device()->IsRemoved())
  				return B_DEV_NOT_READY;
  
  			// we are always on demand, so 0 queued events
--- 278,285 ----
  
  		case MS_NUM_EVENTS:
  		{
! 			// ?
! 			if (fReportAxes->Device()->IsRemoved())
  				return B_DEV_NOT_READY;
  
  			// we are always on demand, so 0 queued events
***************
*** 185,193 ****
  status_t
  MouseProtocolHandler::_ReadReport(void *buffer, uint32 *cookie)
  {
! 	status_t result = fReport.WaitForReport(B_INFINITE_TIMEOUT);
! 	if (result != B_OK) {
! 		if (fReport.Device()->IsRemoved()) {
  			TRACE("device has been removed\n");
  			return B_DEV_NOT_READY;
  		}
--- 303,325 ----
  status_t
  MouseProtocolHandler::_ReadReport(void *buffer, uint32 *cookie)
  {
! 
! 	bool got_axes = false;
! 	bool got_buttons = false;
! 	status_t resultWheel;
! 
! 	//  Look for input on the axis report, first.
! 	status_t resultAxes = fReportAxes->WaitForReport(B_INFINITE_TIMEOUT);
! 	TRACE("WaitForReport -> %d, axis %d report status %d %p, button %d status %d %p\n", resultAxes, fReportAxes->ID(), fReportAxes->Status(), fReportAxes->CurrentReport(), fReportWheel->ID(), fReportWheel->Status(), fReportWheel->CurrentReport());
! 
! 	if (resultAxes == B_OK) {
! 		got_axes = true;
! 	} else {
! 		got_axes = false;
! 
! 		//  Doesn't matter which report, for the following?
! 
! 		if (fReportAxes->Device()->IsRemoved()) {
  			TRACE("device has been removed\n");
  			return B_DEV_NOT_READY;
  		}
***************
*** 195,255 ****
  		if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0)
  			return B_CANCELED;
  
! 		if (result != B_INTERRUPTED) {
  			// interrupts happen when other reports come in on the same
  			// input as ours
! 			TRACE_ALWAYS("error waiting for report: %s\n", strerror(result));
  		}
- 
- 		// signal that we simply want to try again
- 		return B_INTERRUPTED;
  	}
  
  	uint32 axisRelativeData[2];
  	axisRelativeData[0] = 0;
  	axisRelativeData[1] = 0;
  
! 	if (fXAxis.Extract() == B_OK && fXAxis.Valid())
! 		axisRelativeData[0] = fXAxis.Data();
  
! 	if (fYAxis.Extract() == B_OK && fYAxis.Valid())
! 		axisRelativeData[1] = fYAxis.Data();
  
! 	uint32 wheelData[2] = {0};
! 	if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid())
! 		wheelData[0] = fWheel->Data();
! 	if (fHorizontalPan != NULL && fHorizontalPan->Extract() == B_OK
! 			&& fHorizontalPan->Valid())
! 		wheelData[1] = fHorizontalPan->Data();
  
! 	uint32 buttons = 0;
! 	for (uint32 i = 0; i < B_MAX_MOUSE_BUTTONS; i++) {
! 		HIDReportItem *button = fButtons[i];
! 		if (button == NULL)
! 			break;
  
! 		if (button->Extract() == B_OK && button->Valid())
! 			buttons |= (button->Data() & 1) << (button->UsageID() - 1);
  	}
  
! 	fReport.DoneProcessing();
  	TRACE("got mouse report\n");
  
- 	int32 clicks = 0;
  	bigtime_t timestamp = system_time();
! 	if (buttons != 0) {
! 		if (fLastButtons == 0) {
! 			if (fLastClickTime + fClickSpeed > timestamp)
! 				fClickCount++;
! 			else
! 				fClickCount = 1;
! 		}
  
! 		fLastClickTime = timestamp;
! 		clicks = fClickCount;
! 	}
  
! 	fLastButtons = buttons;
  
  	mouse_movement *info = (mouse_movement *)buffer;
  	memset(info, 0, sizeof(mouse_movement));
--- 327,439 ----
  		if ((*cookie & PROTOCOL_HANDLER_COOKIE_FLAG_CLOSED) != 0)
  			return B_CANCELED;
  
! 		if (resultAxes != B_INTERRUPTED) {
  			// interrupts happen when other reports come in on the same
  			// input as ours
! 			TRACE_ALWAYS("error waiting for report: %s\n", strerror(resultAxes));
  		}
  	}
  
+ 	//  If no axis report, these will be the outcome values.
  	uint32 axisRelativeData[2];
  	axisRelativeData[0] = 0;
  	axisRelativeData[1] = 0;
  
! 	if (got_axes && fXAxis != NULL && fYAxis != NULL) {
! 		if (fXAxis->Extract() == B_OK && fXAxis->Valid())
! 			axisRelativeData[0] = fXAxis->Data();
! 		else if (!fXAxis->Valid())
! 			TRACE("X axis invalid\n");
! 		else
! 			TRACE("X Extract not OK?\n");
! 
! 		if (fYAxis->Extract() == B_OK && fYAxis->Valid())
! 			axisRelativeData[1] = fYAxis->Data();
! 		else if (!fYAxis->Valid())
! 			TRACE("Y axis invalid\n");
! 		else
! 			TRACE("Y Extract not OK?\n");
! 	}
  
! 	//  Unblock the axis report, if it was blocked.
! 	if (resultAxes == B_OK)
! 		fReportAxes->DoneProcessing();
! 
! 	resultWheel = fReportWheel->Status();
! 	bool separateWheel = fReportWheel->ID() != fReportAxes->ID();
! 
! 	if (separateWheel && fReportWheel->Status() == B_OK) {
! 		//  There are two reports, and peeking at their status values
! 		//  it appears that the wheel/button report is the one that
! 		//  actually has data.  So block it, while we get the data.
  
! 		resultWheel = fReportWheel->WaitMoreReport(B_INFINITE_TIMEOUT);
! 		TRACE("WaitMoreReport -> %d, axis %d report status %d %p, button %d status %d %p\n", resultWheel, fReportAxes->ID(), fReportAxes->Status(), fReportAxes->CurrentReport(), fReportWheel->ID(), fReportWheel->Status(), fReportWheel->CurrentReport());
! 	}
  
! 	if (resultWheel == B_OK) {
! 		got_buttons = true;
! 	} else {
! 		if (resultAxes == B_OK) {
! 			//  if only one report, resultWheel = resultAxes,
! 			//  se evidently this is axis only.
! 			got_buttons = false;
! 		} else {
! 			// signal that we simply want to try again
! 			return B_INTERRUPTED;
! 		}
! 	}
  
! 	uint32 wheelData[2] = {0, 0};
! 	uint32 buttons = 0;
! 	if (got_buttons) {
! 		if (fWheel != NULL && fWheel->Extract() == B_OK && fWheel->Valid())
! 			wheelData[0] = fWheel->Data();
! 		if (fHorizontalPan != NULL && fHorizontalPan->Extract() == B_OK
! 				&& fHorizontalPan->Valid())
! 			wheelData[1] = fHorizontalPan->Data();
! 		TRACE("wheel %d / %d\n", wheelData[0], wheelData[1]);
! 
! 		for (uint32 i = 0; i < B_MAX_MOUSE_BUTTONS; i++) {
! 			HIDReportItem *button = fButtons[i];
! 			if (button == NULL)
! 				break;
! 
! 			if (button->Extract() == B_OK && button->Valid()) {
! 				buttons |= (button->Data() & 1) << (button->UsageID() - 1);
! 				TRACE("perceived button %d / %x\n", i, buttons);
! 			}
! 		}
  	}
  
! 	//  If there was a button/wheel report with data on it, unblock it now.
! 	if (separateWheel && resultWheel == B_OK)
! 		fReportWheel->DoneProcessing();
! 
  	TRACE("got mouse report\n");
+ 	TRACE("last buttons %x\n", fLastButtons);
  
  	bigtime_t timestamp = system_time();
! 	int32 clicks = 0;
  
! 	//  If it wasn't just axis info, work out happenings with the buttons.
! 	//  Otherwise, just use stored button mask.
! 	if (got_buttons) {
! 		if (buttons != 0) {
! 			if (fLastButtons == 0) {
! 				if (fLastClickTime + fClickSpeed > timestamp)
! 					fClickCount++;
! 				else
! 					fClickCount = 1;
! 			}
  
! 			fLastClickTime = timestamp;
! 			clicks = fClickCount;
! 		}
! 		fLastButtons = buttons;
! 	} else
! 		buttons = fLastButtons;
! 	TRACE("mouse buttons %x\n", buttons);
  
  	mouse_movement *info = (mouse_movement *)buffer;
  	memset(info, 0, sizeof(mouse_movement));
