/*
* Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* 18 June 1998 Start IOKit version.
* 18 Nov 1998 suurballe port to C++
* 4 Oct 1999 decesare Revised for Type 4 support and sub-classed drivers.
* 1 Feb 2000 tsherman Added extended mouse functionality (implemented in setParamProperties)
* 28 June 2005 ffscroll Added the ability to read absolute packets based off ScrollPad
* Added a callback loop to allow tap click and tap drag to work the same as the apple driver
* Added the ability to detect two fingers
* Pass two finger relative movement to the iScroll2 2 finger scrolling code
* Added relative and absolute hotspots for buttons and scrolling
* Move most trackpad data and preferences into structs to make them easier to manage
*/
// Note to tawsi -- working on double tap tolerance
// TODO
// Preference Validation -- make sure we cant block the whole pad (maybe this should be done in prefpane)
// Scrolling continues if edge of scroll area reached and finger left down - DONE?
// If tap dragging physical button can be told to do something else - DONE?
// Flick gestures (eg forwards/backwards)
// Full relative coordinates for hotspots
#include "FFScroll.h"
#include <IOKit/hidsystem/IOHIDTypes.h>
#include <IOKit/hidsystem/IOHIDParameter.h>
#include <IOKit/IOLib.h>
#include <IOKit/IOPlatformExpert.h>
#define OS_WE_BUILD_FOR 3
// ^---- 10.3
#if OS_WE_BUILD_FOR == 4
// taken from the 10.3 kernel headers, they're no longer available in the 10.4 kernel stuff for some reason
#ifndef AbsoluteTime_to_scalar(x)
#define AbsoluteTime_to_scalar(x) (*(uint64_t *)(x))
#endif
/* t1 < = > t2 */
#ifndef CMP_ABSOLUTETIME(t1, t2)
#define CMP_ABSOLUTETIME(t1, t2) \
(AbsoluteTime_to_scalar(t1) > \
AbsoluteTime_to_scalar(t2)? (int)+1 : \
(AbsoluteTime_to_scalar(t1) < \
AbsoluteTime_to_scalar(t2)? (int)-1 : 0))
#endif
/* t1 += t2 */
#ifndef ADD_ABSOLUTETIME(t1, t2)
#define ADD_ABSOLUTETIME(t1, t2) \
(AbsoluteTime_to_scalar(t1) += \
AbsoluteTime_to_scalar(t2))
#endif
/* t1 -= t2 */
#ifdef ADD_ABSOLUTETIME(t1, t2)
#define SUB_ABSOLUTETIME(t1, t2) \
(AbsoluteTime_to_scalar(t1) -= \
AbsoluteTime_to_scalar(t2))
#endif
// End stuff from 10.3 kernel headers
#elif OS_WE_BUILD_FOR == 3
// don't need anything
#else
#error OS_WE_BUILD_FOR has bad value
#endif
//Need the following to compile with GCC3
static inline int
my_abs(int x)
{
return x < 0 ? -x : x;
}
// came from iscroll 2 but useful for other stuff
static inline int
my_sgn(int x)
{
return x < 0 ? -1 : (x > 0 ? +1 : 0);
}
static bool add_usb_mouse(OSObject *, void *, IOService * );
static bool remove_usb_mouse(OSObject *, void *, IOService * );
enum {
kIgnoreTrackpadState_USBMouse = 0x1,
kIgnoreTrackpadState_MouseKeys = 0x2,
kIgnoreTrackpadState_MouseKeys_State_On = 0x4
};
// ****************************************************************************
// NewMouseData
//
// ****************************************************************************
static void NewMouseData(IOService * target, UInt8 adbCommand, IOByteCount length, UInt8 * data)
{
((AppleADBMouse *)target)->packet(adbCommand, length, data);
}
// ****************************************************************************
#undef super
#define super IOHIPointing
OSDefineMetaClassAndStructors(AppleADBMouse, IOHIPointing);
// ****************************************************************************
// probe
//
// ****************************************************************************
IOService * AppleADBMouse::probe(IOService * provider, SInt32 * score)
{
//kprintf("ADB generic probe called\n");
adbDevice = (IOADBDevice *)provider;
return this;
}
// ****************************************************************************
// start
//
// ****************************************************************************
bool AppleADBMouse::start(IOService * provider)
{
if(!super::start(provider)) return false;
if(!adbDevice->seizeForClient(this, NewMouseData)) {
IOLog("%s: Seize failed\n", getName());
return false;
}
return true;
}
// ****************************************************************************
// interfaceID
//
// ****************************************************************************
UInt32 AppleADBMouse::interfaceID(void)
{
return NX_EVS_DEVICE_INTERFACE_ADB;
}
// ****************************************************************************
// deviceType
//
// ****************************************************************************
UInt32 AppleADBMouse::deviceType ( void )
{
return adbDevice->handlerID();
}
// ****************************************************************************
// resolution
//
// ****************************************************************************
IOFixed AppleADBMouse::resolution(void)
{
return _resolution;
}
// ****************************************************************************
// buttonCount
//
// ****************************************************************************
IOItemCount AppleADBMouse::buttonCount(void)
{
return _buttonCount;
}
// ****************************************************************************
// packet
//
// ****************************************************************************
void AppleADBMouse::packet(UInt8 /*adbCommand*/,
IOByteCount /*length*/, UInt8 * data)
{
int dx, dy;
UInt32 buttonState = 0;
AbsoluteTime now;
dy = data[0] & 0x7f;
dx = data[1] & 0x7f;
if (dy & 0x40) dy |= 0xffffffc0;
if (dx & 0x40) dx |= 0xffffffc0;
if ((data[0] & 0x80) == 0) buttonState |= 1;
//clock_get_uptime(&now);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
dispatchRelativePointerEvent(dx, dy, buttonState, now);
}
// ****************************************************************************
#undef super
#define super AppleADBMouse
OSDefineMetaClassAndStructors(AppleADBMouseType1, AppleADBMouse);
IOService * AppleADBMouseType1::probe(IOService * provider, SInt32 * score)
{
if (!super::probe(provider, score)) return 0;
return this;
}
bool AppleADBMouseType1::start(IOService * provider)
{
OSNumber *dpi;
if (adbDevice->setHandlerID(1) != kIOReturnSuccess) return false;
dpi = OSDynamicCast( OSNumber, getProperty("dpi"));
if (dpi)
{
_resolution = dpi->unsigned16BitValue() << 16;
}
else
{
_resolution = 100 << 16;
}
_buttonCount = 1;
return super::start(provider);
}
// ****************************************************************************
#undef super
#define super AppleADBMouse
OSDefineMetaClassAndStructors(AppleADBMouseType2, AppleADBMouse);
IOService * AppleADBMouseType2::probe(IOService * provider, SInt32 * score)
{
if (!super::probe(provider, score)) return 0;
if (adbDevice->setHandlerID(2) != kIOReturnSuccess) return 0;
return this;
}
bool AppleADBMouseType2::start(IOService * provider)
{
OSNumber *dpi;
if (adbDevice->setHandlerID(2) != kIOReturnSuccess) return false;
dpi = OSDynamicCast( OSNumber, getProperty("dpi"));
if (dpi)
{
_resolution = dpi->unsigned16BitValue() << 16;
}
else
{
_resolution = 200 << 16;
}
_buttonCount = 1;
return super::start(provider);
}
// ****************************************************************************
#undef super
#define super AppleADBMouse
OSDefineMetaClassAndStructors(FFScroll, AppleADBMouse);
IOService * FFScroll::probe(IOService * provider, SInt32 * score)
{
UInt8 data[8];
IOByteCount length = 8;
if (!super::probe(provider, score)) return 0;
if (adbDevice->setHandlerID(4) != kIOReturnSuccess) {
adbDevice->setHandlerID(adbDevice->defaultHandlerID());
return 0;
}
// To be a Type 4 Extended Mouse, register 1 must return 8 bytes.
if (adbDevice->readRegister(1, data, &length) != kIOReturnSuccess) return 0;
if (length != 8) return 0;
// Save the device's Extended Mouse Info.
deviceSignature = ((UInt32 *)data)[0];
deviceResolution = ((UInt16 *)data)[2];
deviceClass = data[6];
deviceNumButtons = data[7];
return this;
}
//FFScroll Added
//Procedure produced by taking parts of iScroll2
void FFScroll::doScrolling(SInt16 dx,SInt16 dy, AbsoluteTime now){
bool _enableScrollRot=_trackpadprefs.twoFingerScrollingPrefs.circularScrollingEnabled;
bool _enableScrollX=_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingEnabled;
bool _enableScrollY=_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingEnabled;
bool _scrollDominantAxisOnly=_trackpadprefs.twoFingerScrollingPrefs.scrollDominantOnly;
UInt16 _scrollScaleX=_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingRate;
UInt16 _scrollScaleY=_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingRate;
UInt16 _scrollScaleRot=_trackpadprefs.twoFingerScrollingPrefs.circularScrollingRate;
bool _scrollInvertRot=_trackpadprefs.twoFingerScrollingPrefs.invertCircularScrolling;
bool _scrollInvertX=_trackpadprefs.twoFingerScrollingPrefs.invertVerticalScrolling;
bool _scrollInvertY=_trackpadprefs.twoFingerScrollingPrefs.invertHorizontalScrolling;
UInt16 _scrollThreshRot=_trackpadprefs.twoFingerScrollingPrefs.circularScrollingThreshold;
UInt16 _scrollThreshX=_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingThreshold;
UInt16 _scrollThreshY=_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingThreshold;
bool _scrollOnlyRot=!(_enableScrollX || _enableScrollY);
static AbsoluteTime _scrollMinDelayAB;
static AbsoluteTime _lastScrollTimeAB;
static bool _stickyRotating;
// static UInt8 _oldButtonState;
static short _scrollX;
static short _scrollY;
static short _scrollRot;
static short _oldScrollX;
static short _oldScrollY;
#ifdef FFSDEBUG
IOLog("FFScroll: Wheel data: %d, %d\n", dx, dy) ;
#endif
//if((_enableScrollX || _enableScrollY || _enableScrollRot) && has2fingers)
{
bool skipLinear = _enableScrollRot && _scrollOnlyRot;
AbsoluteTime sub_now = now;
bool withhold;
SUB_ABSOLUTETIME(&sub_now, &_scrollMinDelayAB);
withhold = CMP_ABSOLUTETIME(&sub_now, &_lastScrollTimeAB) == -1;
if(_enableScrollRot)
{
short angleSquared = _oldScrollY * dx - _oldScrollX * dy;
angleSquared = 100 * my_abs(angleSquared) * angleSquared /
((_oldScrollX * _oldScrollX + _oldScrollY * _oldScrollY) * (dx * dx + dy * dy));
if(_stickyRotating || (my_abs(angleSquared) >= _scrollThreshRot))
{
_scrollRot += my_sgn(_scrollInvertRot ? -angleSquared : angleSquared) * (my_abs(dx) + my_abs(dy));
if((_scrollRot / _scrollScaleRot) && !withhold)
{
dispatchScrollWheelEvent(_scrollRot / _scrollScaleRot, 0, 0, now);
_scrollRot = 0;
_lastScrollTimeAB = now;
}
skipLinear = true;
}
}
if(!skipLinear)
{
if(_enableScrollX && ((my_abs(dx) >= _scrollThreshX)
&& (!_scrollDominantAxisOnly || (my_abs(dx) >= my_abs(dy)))))
_scrollX += (_scrollInvertX ? dx : -dx);
if(_enableScrollY && ((my_abs(dy) >= _scrollThreshY)
&& (!_scrollDominantAxisOnly || (my_abs(dy) >= my_abs(dx)))))
_scrollY += (_scrollInvertY ? dy : -dy);
if(((_scrollX / _scrollScaleX) || (_scrollY / _scrollScaleY)) && !withhold)
{
dispatchScrollWheelEvent(_scrollY / _scrollScaleY, _scrollX / _scrollScaleX, 0, now);
_scrollX = _scrollY = 0;
_lastScrollTimeAB = now;
}
}
_oldScrollX = dx;
_oldScrollY = dy;
}
}
//End iScroll2 Procedure
inline bool inRange(int x,int y,int lowx,int highx,int lowy,int highy) // inline to work out if x & y are contain in range
{
return (x<=highx && y<=highy && x>=lowx && y>=lowy);
}
inline bool inRange(int a,int lowa,int higha)
{
return (a<=higha && a>=lowa);
}
inline bool inRange(int x, int y, COORD hotspot)
{
return inRange(x, y, hotspot.x0, hotspot.x1, hotspot.y0, hotspot.y1);
}
void FFScroll::updateHotspot(COORD *coordRead, COORD *coordAbs, int coordType, char* kind)
{
char* coordString;
switch(coordType)
{
case 0:
coordString = "absolute";
coordAbs->x0 = coordRead->x0;
coordAbs->x1 = coordRead->x1;
coordAbs->y0 = coordRead->y0;
coordAbs->y1 = coordRead->y1;
break;
case 1:
coordString = "relative";
coordAbs->x0 = _trackpadprefs.minX + coordRead->x0*(_trackpadprefs.maxX-_trackpadprefs.minX);
coordAbs->y0 = _trackpadprefs.minY + coordRead->y0*(_trackpadprefs.maxY-_trackpadprefs.minY);
coordAbs->x1 = coordAbs->x0 + ((1 - 2*coordRead->x0)*(coordRead->x1)*(_trackpadprefs.maxX-_trackpadprefs.minX))/100;
coordAbs->y1 = coordAbs->y0 + ((1 - 2*coordRead->y0)*(coordRead->y1)*(_trackpadprefs.maxY-_trackpadprefs.minY))/100;
if(coordRead->x0 == 1)
{
UInt16 tmp = coordAbs->x0;
coordAbs->x0 = coordAbs->x1;
coordAbs->x1 = tmp;
}
if(coordRead->y0 == 1)
{
UInt16 tmp = coordAbs->y0;
coordAbs->y0 = coordAbs->y1;
coordAbs->y1 = tmp;
}
break;
case 2:
// IOLog("FFScroll:: Full relative coordinates not implemented yet");
coordString = "full relative";
coordAbs->x0 = _trackpadprefs.minX + (coordRead->x0*(_trackpadprefs.maxX-_trackpadprefs.minX))/100;
coordAbs->x1 = _trackpadprefs.minX + (coordRead->x1*(_trackpadprefs.maxX-_trackpadprefs.minX))/100;
coordAbs->y0 = _trackpadprefs.minY + (coordRead->y0*(_trackpadprefs.maxY-_trackpadprefs.minY))/100;
coordAbs->y1 = _trackpadprefs.minY + (coordRead->y1*(_trackpadprefs.maxY-_trackpadprefs.minY))/100;
break;
default:
IOLog("FFScroll:: Unknown coordinate type: %d", coordType);
}
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Updated %s with from %s coords:\n Read coords = (%d, %d, %d, %d)\n Abs coords = (%d, %d, %d, %d)\n",
kind,
coordString,
coordRead->x0,
coordRead->x1,
coordRead->y0,
coordRead->y1,
coordAbs->x0,
coordAbs->x1,
coordAbs->y0,
coordAbs->y1);
#endif
}
void FFScroll::generateAbsoluteHotspots()
{
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Generating Relative hotspots...\n") ;
#endif
for(int i=0; i<_trackpadprefs.numberOfHotspots; i++)
updateHotspot(&(_trackpadprefs.Hotspots[i].coordRel), &(_trackpadprefs.Hotspots[i].coordAbs), _trackpadprefs.Hotspots[i].type, "action hotspot");
for(int i=0; i<_trackpadprefs.numberOfScrollAreas; i++)
updateHotspot(&(_trackpadprefs.ScrollAreas[i].coordRel), &(_trackpadprefs.ScrollAreas[i].coordAbs), _trackpadprefs.ScrollAreas[i].type, "scroll hotspot");
}
void FFScroll::sendClickUpIfNotDragging(){ // this function is a callback from a tap, if we are not dragging then send the click // safe
AbsoluteTime now;
UInt64 nowNs;
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowNs);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowNs);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
_trackpaddata.mouseupCallbacksAwaited--;
//IOLog("Timeout, awaiting callbacks %d",_trackpaddata.mouseupCallbacksAwaited);
if(!_trackpaddata.stickTapDrag)
dispatchRelativePointerEvent(0, 0, _trackpaddata.lastButtonState, now);
else if(_trackpaddata.stickTapDrag && !_trackpadprefs.tapDragLock && (nowNs-_trackpaddata.lastFingerContactTime>_trackpadprefs.maxTapDragRevTime)) // if we are dragging and exceeded our limit
dispatchRelativePointerEvent(0, 0, _trackpaddata.lastButtonState, now);
}
void FFScroll::sendClickNow() //safe
{
AbsoluteTime now;
UInt64 nowNs;
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowNs);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowNs);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
#ifdef FFSDEBUG
IOLog("FFScroll: Sending Click");
#endif
_trackpaddata.clickCallbacksAwaited--;
dispatchRelativePointerEvent(0,0,_trackpaddata.lastButtonState | _trackpaddata.buttonStateToSend,now);
}
void FFScroll::hotspotScrolling(int dx,int dy, AbsoluteTime now, UInt64 nowNs)
{
int scrollX = 0; // switch to int from SInt16 for simplicity
int scrollY = 0;
SCROLLHOTSPOT* currenthotspot = &(_trackpadprefs.ScrollAreas[_trackpaddata.scrollHotspotActive]);
int direction = (currenthotspot->direction) + 1;
if(currenthotspot->autoScrollMode==3 && _trackpaddata.distanceScrolled>_trackpadprefs.tapTolerance)
{
proportionalAutoScrolling(now,nowNs);
return;
}
else
{
if(direction & 1) // if the scroll area has Y scrolling
{
scrollY = -dy;
if(
my_abs(dy)<5 && _trackpaddata.distanceScrolled>_trackpadprefs.tapTolerance && currenthotspot->autoScrollMode
&& ((_trackpaddata.y<((100-currenthotspot->autoScrollCap)*currenthotspot->coordAbs.y0+(currenthotspot->autoScrollCap)*currenthotspot->coordAbs.y1)/100)
||
(_trackpaddata.y>((currenthotspot->autoScrollCap)*currenthotspot->coordAbs.y0+(100-currenthotspot->autoScrollCap)*currenthotspot->coordAbs.y1)/100)
) // if autoscrolling is enabled, the distrance moved is less
)
{
if(!_trackpaddata.autoScrollYActivated) // if we havent activate autoscrolly Y yet then do it now
{
_trackpaddata.autoScrollYActivated = true;
_trackpaddata.lastScrollYTime = nowNs;
}
//proportionalAutoScrolling(now,nowNs);
switch(currenthotspot->autoScrollMode)
{
case 1:
scrollY = autoScrolling(now, nowNs, 1);
break;
case 2:
scrollY = velocityAutoScrolling(now, nowNs, 1);
break;
default:
IOLog("FFScroll:: Somehow reached end of autoscrolling modes with mode value %d", currenthotspot->autoScrollMode);
}
}
//_trackpaddata.distanceScrolled+=my_abs(dy);
else
{
if(my_abs(dy) > 2)
{ // if its moved significantly
if(nowNs-_trackpaddata.scrollStrokeYLastUpdateTime < 100000000)
{
#ifdef FFSDEBUGSCROLLING
IOLog("FFScroll:: Velocity Scrolling continuing\n");
#endif
_trackpaddata.scrollStrokeYLastUpdateTime = nowNs;
}
else
{
#ifdef FFSDEBUGSCROLLING
IOLog("FFScroll :: Velocity Scrolling starting\n");
#endif
_trackpaddata.scrollStrokeYStartPos = _trackpaddata.y;
_trackpaddata.scrollStrokeYLastUpdateTime = nowNs;
_trackpaddata.scrollStrokeYStartTime = nowNs;
}
}
_trackpaddata.autoScrollYActivated = false;
scrollY = 100 * scrollY + _trackpaddata.verticalScrollingRem;
_trackpaddata.verticalScrollingRem = scrollY % currenthotspot->speedScale;
scrollY /= currenthotspot->speedScale;
}
}
if(direction & 2) // if the scroll area has X scrolling
{
scrollX = -dx;
if(my_abs(dx)<5 && _trackpaddata.distanceScrolled>_trackpadprefs.tapTolerance && currenthotspot->autoScrollMode
&& ((_trackpaddata.x<((100-currenthotspot->autoScrollCap)*currenthotspot->coordAbs.x0+(currenthotspot->autoScrollCap)*currenthotspot->coordAbs.x1)/100) || (_trackpaddata.x>((currenthotspot->autoScrollCap)*currenthotspot->coordAbs.x0+(100-currenthotspot->autoScrollCap)*currenthotspot->coordAbs.x1)/100))
)
{
if(!_trackpaddata.autoScrollXActivated)
{
_trackpaddata.autoScrollXActivated=true;
_trackpaddata.lastScrollXTime=nowNs;
}
switch(currenthotspot->autoScrollMode)
{
case 1:
scrollX=autoScrolling(now,nowNs,2);
break;
case 2:
scrollX=velocityAutoScrolling(now,nowNs,2);
break;
default:
IOLog("FFScroll:: Somehow reached end of autoscrolling modes with mode value %d",currenthotspot->autoScrollMode);
}
}
//_trackpaddata.distanceScrolled+=my_abs(dx);
else
{
_trackpaddata.autoScrollXActivated=false;
scrollX = 100 * scrollX + _trackpaddata.horizontalScrollingRem;
_trackpaddata.horizontalScrollingRem = scrollX % currenthotspot->speedScale;
scrollX /= currenthotspot->speedScale;
}
}
}
scrollX = currenthotspot->invert? -scrollX:scrollX;
scrollY = currenthotspot->invert? -scrollY:scrollY;
dispatchScrollWheelEvent(scrollY, scrollX, 0, now);
}
int FFScroll::autoScrolling(AbsoluteTime now, UInt64 nowNs, int dir)
{
int scrollX=0,scrollY=0;
int returnvalue=0;
SCROLLHOTSPOT* currenthotspot = &(_trackpadprefs.ScrollAreas[_trackpaddata.scrollHotspotActive]);
if(dir==1){ // dir 1 means y scrolling
UInt64 dyt=nowNs-_trackpaddata.lastScrollYTime;
SInt16 dy=my_sgn(_trackpaddata.y-((currenthotspot->coordAbs.y0+currenthotspot->coordAbs.y1)/2));
scrollY = (currenthotspot->autoScrollRate)*dyt/(1000000000); //possible rounding problems not sure if we should use rate per ms s or something else;
scrollY = -scrollY*dy; // now to scale for distance (currently linear but may work better with something quadratic etc)
// if we have scrolled then update the last update times (can probably make this more accurate by storing fractions but not sure its worth it
if(scrollY){
_trackpaddata.lastScrollYTime=nowNs;
}
returnvalue=scrollY;
}
if(dir==2){ // dir 2 is X scrolling
UInt64 dxt=nowNs-_trackpaddata.lastScrollXTime;
//using variables to mean something slightly different :)
SInt16 dx=my_sgn(_trackpaddata.x-((currenthotspot->coordAbs.x0+currenthotspot->coordAbs.x1)/2)); // cant remember which way round scroll goes
scrollX = (currenthotspot->autoScrollRate)*dxt/(1000000000); //possible rounding problems not sure if we should use rate per ms s or something else; // now to scale for distance (currently linear but may work better with something quadratic etc)
scrollX = -scrollX*dx;
// if we have scrolled then update the last update times (can probably make this more accurate by storing fractions but not sure its worth it
if(scrollX){
_trackpaddata.lastScrollXTime=nowNs;
}
returnvalue=scrollX;
}
// return the scroll value;
return returnvalue;
}
int FFScroll::velocityAutoScrolling(AbsoluteTime now, UInt64 nowNs, int direction) // direction 1=x,2=y,3=both
{
SCROLLHOTSPOT* currenthotspot = &(_trackpadprefs.ScrollAreas[_trackpaddata.scrollHotspotActive]);
int scrollX=0;
int scrollY=0;
int returnvalue=0;
if(direction==1) // Y scrolling
{
long dyt=(nowNs-_trackpaddata.lastScrollYTime)/1000; // time in microseconds due to overflow problems
int scrollYdistance=_trackpaddata.y-_trackpaddata.scrollStrokeYStartPos;
//int scrollYrate=scrollYdistance*(1000000000/(_trackpaddata.scrollStrokeYLastUpdateTime-_trackpaddata.scrollStrokeYStartTime));
scrollY=-((scrollYdistance*dyt)/((long)(_trackpaddata.scrollStrokeYLastUpdateTime/1000-_trackpaddata.scrollStrokeYStartTime/1000)));
if(scrollY){ // this probably needs looking at
_trackpaddata.lastScrollYTime=nowNs;
}
scrollY = 100 * scrollY + _trackpaddata.verticalScrollingRem;
_trackpaddata.verticalScrollingRem = scrollY % currenthotspot->speedScale;
scrollY /= currenthotspot->speedScale;
#ifdef FFSDEBUGSCROLLING
IOLog("FFScroll:: Velocity Y Scrolling dyt %ld\n",dyt);
IOLog("FFScroll:: Velocity Y Scrolling distance %d\n",scrollYdistance);
IOLog("FFScroll:: Velocity Y Scrolling distance * dy %ld\n", (scrollYdistance*dyt));
IOLog("FFScroll:: Divisor %ld\n", ((long)(_trackpaddata.scrollStrokeYLastUpdateTime/1000-_trackpaddata.scrollStrokeYStartTime/1000)));
#endif
returnvalue=scrollY;
}
// still needs some work to avoid rounding errors
else if(direction == 2)
{
long dxt=(nowNs-_trackpaddata.lastScrollXTime)/1000;
// SInt16 scrollXdistance=_trackpaddata.x-_trackpaddata.scrollStrokeXStartPos;
// SInt16 scrollXrate=scrollXdistance*(1000000000/(_trackpaddata.scrollStrokeXLastUpdateTime-_trackpaddata.scrollStrokeXStartTime));
int scrollXdistance=_trackpaddata.x-_trackpaddata.scrollStrokeXStartPos;
scrollX=-((scrollXdistance*dxt)/((long)(_trackpaddata.scrollStrokeXLastUpdateTime/1000-_trackpaddata.scrollStrokeXStartTime/1000)));
if(scrollX){
_trackpaddata.lastScrollXTime=nowNs;
}
scrollX = 100 * scrollX + _trackpaddata.verticalScrollingRem;
_trackpaddata.horizontalScrollingRem = scrollX % currenthotspot->speedScale;
scrollX /= currenthotspot->speedScale;
#ifdef FFSDEBUGSCROLLING
IOLog("FFScroll:: Velocity X Scrolling dyt %ld\n",dxt);
IOLog("FFScroll:: Velocity X Scrolling distance %d\n",scrollXdistance);
IOLog("FFScroll:: Velocity X Scrolling distance * dy %ld\n", (scrollXdistance*dxt));
IOLog("FFScroll:: Divisor %ld\n", ((long)(_trackpaddata.scrollStrokeXLastUpdateTime/1000-_trackpaddata.scrollStrokeXStartTime/1000)));
#endif
returnvalue=scrollX;
}
// if we have scrolled then update the last update times (can probably make this more accurate by storing fractions but not sure its worth it
//dispatch the event
//dispatchScrollWheelEvent(scrollY, scrollX, 0, now);
return returnvalue;
}
void FFScroll::proportionalAutoScrolling(AbsoluteTime now, UInt64 nowNs)
{
UInt64 dxt=nowNs-_trackpaddata.lastScrollXTime;
UInt64 dyt=nowNs-_trackpaddata.lastScrollYTime;
SCROLLHOTSPOT* currenthotspot = &(_trackpadprefs.ScrollAreas[_trackpaddata.scrollHotspotActive]);
SInt16 width=(currenthotspot->coordAbs.x1-currenthotspot->coordAbs.x0);
SInt16 height=(currenthotspot->coordAbs.y1-currenthotspot->coordAbs.y0);
//using variables to mean something slightly different :)
SInt16 dx=_trackpaddata.x-((currenthotspot->coordAbs.x0+currenthotspot->coordAbs.x1)/2); // cant remember which way round scroll goes
SInt16 dy=_trackpaddata.y-((currenthotspot->coordAbs.y0+currenthotspot->coordAbs.y1)/2);
SInt16 scrollX=0,scrollY=0;
switch(currenthotspot->direction)
{
case 0:
// how far to scroll assuming normal speed
scrollY = (currenthotspot->autoScrollRate)*dyt/(1000000000); //possible rounding problems not sure if we should use rate per ms s or something else;
// now to scale for distance (currently linear but may work better with something quadratic etc)
scrollY = -scrollY*dy*my_abs(dy)/((height*height/4));
break;
case 1:
// how far to scroll assuming normal speed
scrollX = (currenthotspot->autoScrollRate)*dxt/(1000000000); //possible rounding problems not sure if we should use rate per ms s or something else;
// now to scale for distance (currently linear but may work better with something quadratic etc)
scrollX = -scrollX*dx*my_abs(dx)/(width*width/4);
break;
case 2:
// how far to scroll assuming normal speed
scrollX = (currenthotspot->autoScrollRate)*dxt/(1000000000); //possible rounding problems not sure if we should use rate per ms s or something else;
// now to scale for distance (currently linear but may work better with something quadratic etc)
scrollX = -scrollX*dx*my_abs(dx)/(width*width/4);
// how far to scroll assuming normal speed
scrollY = (currenthotspot->autoScrollRate)*dyt/(1000000000); //possible rounding problems not sure if we should use rate per ms s or something else;
// now to scale for distance (currently linear but may work better with something quadratic etc)
scrollY = -scrollY*dy*my_abs(dy)/((height*height/4));
break;
default:
// ?? some kinda error ??
IOLog("FFScroll: Unknown direction");
break;
}
scrollX = currenthotspot->invert? -scrollX:scrollX;
scrollY = currenthotspot->invert? -scrollY:scrollY;
// if we have scrolled then update the last update times (can probably make this more accurate by storing fractions but not sure its worth it
if(scrollX){
_trackpaddata.lastScrollXTime=nowNs;
}
if(scrollY){
_trackpaddata.lastScrollYTime=nowNs;
}
//dispatch the event
dispatchScrollWheelEvent(scrollY, scrollX, 0, now);
}
void FFScroll::trackpadClick(int x,int y,AbsoluteTime now) // procedure used to handle taps on the trackpad // unsafe
{
#ifdef FFSDEBUG
IOLog("FFScroll: Doing a tap at %d %d\n", x,y) ;
IOLog("FFScroll: Absolute Extremes: %d, %d, %d, %d\n", _trackpadprefs.minX, _trackpadprefs.minY, _trackpadprefs.maxX,_trackpadprefs.maxY) ;
#endif
// BEGIN HOTSPOT ACTIONS
if(_trackpaddata.mouseupCallbacksAwaited) dispatchRelativePointerEvent(0, 0, _trackpaddata.lastButtonState, now); // if we are not awaiting a callback we don't need this
// should probably only send this if we are awaiting a callback
if(!_trackpadprefs.calibrateMode && _trackpadprefs.hasHotspots) // if we are in calibrate mode ignore hotspots
{
int buttonState=0;
for(int i=0; i<_trackpadprefs.numberOfHotspots; i++) // Cycle through hotspots
if(inRange(x, y, _trackpadprefs.Hotspots[i].coordAbs)) // if the tap was inside the hotspot
buttonState |= _trackpadprefs.Hotspots[i].button; // bitwise or with buttonState (turn on the button corresponding to the hotspot)
if(buttonState == 0 && _trackpadprefs.tapClickEnable){ // if no buttons are pressed
buttonState = 1;
}// set the output to the default button (currently 1)
//if(!_trackpadprefs.tapDragEnable){
if(!_trackpaddata.mouseupCallbacksAwaited) // if we were waiting for a callback then we need to delay the click
{
dispatchRelativePointerEvent(0, 0, buttonState|_trackpaddata.lastButtonState, now); // send the click event we may want to always send these in the future
}
else
{
_trackpaddata.buttonStateToSend = buttonState;
//if(clickTimer->setTimeoutUS(_trackpadprefs.minTapDuration/2000)==kIOReturnSuccess){
if(clickTimer->setTimeoutUS(10000) == kIOReturnSuccess) // send the click in 10ms time
{
//_trackpaddata.mouseupCallbacksAwaited++;
#ifdef FFSDRAGDEBUG
IOLog("Click Timer Set");
#endif
}
}
}
// END HOTSPOT ACTIONS
else if(_trackpadprefs.tapClickEnable)
{
//dispatchRelativePointerEvent(0, 0, 1|_trackpaddata.lastButtonState, now); // anywhere else == left click
//if(!_trackpadprefs.tapDragEnable){
if(!_trackpaddata.mouseupCallbacksAwaited) // if we were waiting for a callback then we need to delay the click
dispatchRelativePointerEvent(0, 0, 1|_trackpaddata.lastButtonState, now); // send the click event we may want to always send these in the future
else
{
_trackpaddata.buttonStateToSend = 1;
if(clickTimer->setTimeoutUS(_trackpadprefs.minTapDuration/2000)==kIOReturnSuccess) // dispatch this button state in half the time it would take to send a click to avoid issues with the finder triple tap bug
{
_trackpaddata.clickCallbacksAwaited++;
#ifdef FFSDRAGDEBUG
IOLog("Click Timer Set");
#endif
}
}
}
//TODO add code to allow dragging by any button
if(_trackpadprefs.tapDragEnable) // if tap dragging is enabled we need to delay the click til we know it is just a click and not a drag
{
if(timeout->setTimeoutUS(_trackpadprefs.maxTapDragTime/1000)==kIOReturnSuccess){ // code to send a mouse up event if we dont get a drag in the specified time
_trackpaddata.mouseupCallbacksAwaited++;
#ifdef FFSDRAGDEBUG
IOLog("Set Timeout Success\n");
}
else
{
IOLog("Set Timeout Failed\n");
#endif
}
}
//else dispatchRelativePointerEvent(0, 0, _trackpaddata.lastButtonState, now); // send the mouse up click
else // modified to account for the issues we found with finder and sending 2 events in one go
{
if(timeout->setTimeoutUS(10000) == kIOReturnSuccess) // code to send a delayed mouse up event
{
_trackpaddata.mouseupCallbacksAwaited++;
#ifdef FFSDRAGDEBUG
IOLog("Set Timeout Success\n");
}
else
{
IOLog("Set Timeout Failed\n");
#endif
}
}
}
//TODO
//Finish Jitter code and make it handle hotspots
//Jitter -> Reset data so pointer is up
void FFScroll::packetABS(UInt8 adbCommand, IOByteCount length, UInt8* data)
{
AbsoluteTime now;
UInt64 nowNs ;
// Packed decoding code taken from Scrollpad as reinventing the wheel seems pointless
// read the absolute position out of the data
// this bit will act funny on intel hardware (which shouldnt have ADB anyway)
UInt16 x1 = data[1] & 0x7F ;
UInt16 x2 = data[2] & 7 ;
UInt16 x3 = data[3] & 7 ;
UInt16 y1 = data[0] & 0x7F ;
UInt16 y2 = (data[2] >> 4) & 7 ;
UInt16 y3 = (data[3] >> 4) & 7 ;
SInt16 absX = x1 | (x2<<7) | (x3<<10) ;
SInt16 absY = y1 | (y2<<7) | (y3<<10) ;
SInt16 absZ = ((data[4] >> 4) & 7) | ((data[4] & 7) << 3) ;
int buttonState = (data[0] & 0x80) ? 0 : 1 ;
#ifdef FFSDEBUGCOORDS
IOLog("FFScroll: -------------------------------------------------\n") ;
IOLog("FFScroll: Absolute data: %d, %d, %d\n", absX, absY, absZ) ;
IOLog("FFScroll: Button State: %d\n", buttonState) ;
#endif
// done reading the data from the pad
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowNs);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowNs);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
//Cases to deal with
//Finger just put on touch pad
//Finger removed from touch pad
//Finger on touch pad and button clicked
//Finger not on touch pad and button clicked
//TODO
//Hotspots
//Better Detect for back to single finger
//if(_trackpaddata.stickTapDrag && _trackpadprefs.physicalButtonDragAction == 0 && buttonState)
_trackpaddata.buttonPressedWhileFingerOnPadDragging=(_trackpaddata.buttonPressedWhileFingerOnPadDragging && buttonState); // unset bpwfop if button comes up
if(_trackpaddata.stickTapDrag
&& (_trackpadprefs.physicalButtonDragAction == 0
|| (!_trackpaddata.buttonPressedWhileFingerOnPadDragging && absZ==0)
|| (_trackpadprefs.buttonStopsDrag && _trackpadprefs.physicalButtonDragAction == 1)
)
&& buttonState)
_trackpaddata.stickTapDrag = false;
_trackpaddata.lastButtonState = buttonState? _trackpadprefs.physicalButtonAction:0;
if(absZ == 0) // finger is not on the touch pad
{
#ifdef FFSDEBUGCOORDS
IOLog("FFScroll absZ=0\n");
#endif
if(_trackpaddata.z != 0) // finger has been lifted off the touch pad
{
//TODO add tap tolerance
#ifdef FFSDEBUG
IOLog("FFScroll: Finger Up\n") ;
#endif
bool jitter=false; //code to detect for jitter
if ((_jitterclick) && (_pADBKeyboard)) // if we are blocking taps on jitter
{
AbsoluteTime keyboardtime;
UInt64 nowtime64, keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false,
(void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowtime64);
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
#ifdef FFSDEBUG
IOLog("FFScroll: Testing for jitter Time:%lld KeyTime:%lld Jitterclicktime: %lld\n",nowtime64,keytime64,_jitterclicktime64) ;
#endif
if (!(nowtime64 - keytime64 > _jitterclicktime64))
jitter = true;
}
if(!jitter) // if jitter detected do nothing
{
if(_trackpadprefs.tapClickEnable || _trackpadprefs.hasHotspots)
{
if(
(_trackpaddata.x-_trackpaddata.downX<=_trackpadprefs.tapTolerance && _trackpaddata.downX-_trackpaddata.x<=_trackpadprefs.tapTolerance &&
_trackpaddata.y-_trackpaddata.downY<=_trackpadprefs.tapTolerance && _trackpaddata.downY-_trackpaddata.y<=_trackpadprefs.tapTolerance)
// &&
// (nowNS-_trackpaddata.lastTapTime>
)
{
#ifdef FFSDEBUG
IOLog("FFScroll: Tap started at %d,%d ended at %d,%d\n", _trackpaddata.downX,_trackpaddata.downY,_trackpaddata.x,_trackpaddata.y) ;
#endif
if(!_trackpadprefs.tapDragEnable || !_trackpaddata.stickTapDrag) // if we are not dragging
{
if((nowNs-_trackpaddata.fingerDownTime<_trackpadprefs.maxTapDuration) &&
(_trackpadprefs.minTapDuration<nowNs-_trackpaddata.fingerDownTime)
)
{ // finger was only down long enough to click
#ifdef FFSDEBUG
IOLog("FFScroll: Time to do a tap %lld\n", nowNs-_trackpaddata.fingerDownTime) ;
#endif
#ifdef FFSDRAGDEBUG
IOLog("FFScroll: Time to do a tap %lld done at %lld\n", nowNs-_trackpaddata.fingerDownTime,nowNs) ;
#endif
_trackpaddata.lastTapTime = nowNs;
_trackpaddata.lastTapX=_trackpaddata.x;
_trackpaddata.lastTapY=_trackpaddata.y;
trackpadClick(_trackpaddata.x, _trackpaddata.y, now); // Dispatch the click event corresponding to the point
}
}
else // We are dragging
{
if(
(nowNs-_trackpaddata.fingerDownTime<_trackpadprefs.maxTapDuration) &&
(_trackpadprefs.minTapDuration<nowNs-_trackpaddata.fingerDownTime)
)
{ // finger was only down long enough to click
#ifdef FFSDRAGDEBUG
IOLog("FFScroll: Time to do a tap %lld\n", nowNs-_trackpaddata.fingerDownTime) ;
#endif
_trackpaddata.stickTapDrag=false; // end the drag event
if(nowNs-_trackpaddata.tapDragStartTime<_trackpadprefs.minDragAssumedTime) //if the click occured at the start of the drag event
{
_trackpaddata.lastTapTime=nowNs;
_trackpaddata.lastTapX=_trackpaddata.x;
_trackpaddata.lastTapY=_trackpaddata.y;
trackpadClick(_trackpaddata.x,_trackpaddata.y,now); // assume it wansn't a drag and send a click
//dispatchRelativePointerEvent(0, 0, 0, now); // send the mouse up click
}
else
{
dispatchRelativePointerEvent(0,0,0,now); // otherwise send a mouse up event
}
}
}
}
}
}
#ifdef FFSDEBUG
else
{
IOLog("FFScroll: Jitter stopped mouse click\n") ;
}
#endif
if(_trackpadprefs.tapDragEnable && _trackpaddata.stickTapDrag && !_trackpadprefs.tapDragLock) // if we are dragging and there is no lock then set a callback for mouse up once the rev timeout has passed
{
if(timeout->setTimeoutUS((_trackpadprefs.maxTapDragRevTime/1000))==kIOReturnSuccess){
#ifdef FFSDRAGDEBUG
_trackpaddata.mouseupCallbacksAwaited++;
IOLog("Set Timeout Success\n");
}
else{
IOLog("Set Timeout Failed\n");
#endif
}
}
_trackpaddata.x = absX; // finger was on touch pad previously so reset all the data about it
_trackpaddata.y = absY;
_trackpaddata.z = absZ;
_trackpaddata.xrem=0; // reset xrem and yrem as tracking remainders after finger up doesnt really make sense
_trackpaddata.yrem=0;
_trackpaddata.zArrayFilled = false;
_trackpaddata.zArrayCurrent = 0;
_trackpaddata.stickTwoFinger = false;
_trackpaddata.scrollHotspotActive = -1;
}
else // Physical button has been pressed or released
{
#ifdef FFSDEBUG
IOLog("FFScroll: Non finger event\n") ;
#endif
if(_trackpadprefs.tapDragEnable && _trackpaddata.stickTapDrag)
{
if(_trackpadprefs.tapDragLock || (nowNs-_trackpaddata.lastFingerContactTime<_trackpadprefs.maxTapDragRevTime)) // if tap drag has not yet timed out
{
if(_trackpadprefs.physicalButtonDragAction > 0)
{
dispatchRelativePointerEvent(0,0,(_trackpaddata.stickTapDrag?1:0)|(buttonState?_trackpadprefs.physicalButtonDragAction:0),now);
}
else
{
_trackpaddata.stickTapDrag = false;
dispatchRelativePointerEvent(0,0,(_trackpaddata.stickTapDrag?1:0),now); //|(buttonState?_trackpadprefs.physicalButtonAction:0)
}
}
//TIMEOUT!
else if(_trackpadprefs.physicalButtonDragAction == 0) // if button doesnt maintain drag unset it
{
if(!_trackpadprefs.tapDragLock)
{
_trackpaddata.stickTapDrag = false;
#ifdef FFSDEBUG
IOLog("FFScroll: Unsetting tap drag due to timeout\n") ;
#endif
}
}
else
{
_trackpaddata.stickTapDrag = (buttonState != 0 && _trackpadprefs.physicalButtonDragAction == 1); // maintain drag if button is down
dispatchRelativePointerEvent(0,0,(_trackpaddata.stickTapDrag?1:0), now); //|(buttonState?_trackpadprefs.physicalButtonAction:0)
}
}
else // if no tap dragging then just dispatch the button state
{
dispatchRelativePointerEvent(0, 0, buttonState?_trackpadprefs.physicalButtonAction:0, now);
}
}
// work out how the pointer has moved
}
else
{
#ifdef FFSDEBUG
IOLog("FFScroll: Finger Down button state %d\n",buttonState) ;
#endif
// calibrate trackpad
if(absX > _trackpadprefs.maxX)
{
_trackpaddata.calibrationHasChanged=true;
_trackpadprefs.maxX = absX;
}
if(absY > _trackpadprefs.maxY)
{
_trackpaddata.calibrationHasChanged=true;
_trackpadprefs.maxY = absY;
}
if(absX < _trackpadprefs.minX)
{
_trackpaddata.calibrationHasChanged=true;
_trackpadprefs.minX = absX;
}
if(absY < _trackpadprefs.minY)
{
_trackpaddata.calibrationHasChanged=true;
_trackpadprefs.minY = absY;
}
if(_trackpaddata.calibrationHasChanged && (nowNs>_trackpaddata.lastCalibrationUpdate+(UInt64)5*(UInt64)1000*(UInt64)1000000 || _trackpadprefs.calibrateMode))
{
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Writing new calibration data %d %d %d %d\n",_trackpadprefs.minX,_trackpadprefs.minY,_trackpadprefs.maxX,_trackpadprefs.maxY);
#endif
setProperty(minXKey, _trackpadprefs.minX, 16);
setProperty(maxXKey, _trackpadprefs.maxX, 16);
setProperty(minYKey, _trackpadprefs.minY, 16);
setProperty(maxYKey, _trackpadprefs.maxY, 16);
_trackpaddata.calibrationHasChanged = false;
_trackpaddata.lastCalibrationUpdate = nowNs;
generateAbsoluteHotspots();
}
// end calibration
if(_trackpaddata.z != 0) // finger was on touch pad in previous occurence
{
SInt16 dx = absX - _trackpaddata.x;
SInt16 dy = absY - _trackpaddata.y;
#ifdef FFSDEBUGCOORDS
IOLog("FFScroll: Absolute Extremes: %d, %d, %d, %d\n", _trackpadprefs.minX, _trackpadprefs.minY, _trackpadprefs.maxX,_trackpadprefs.maxY) ;
#endif
// update the coordinates of the last position on the trackpad
_trackpaddata.x = absX;
_trackpaddata.y = absY;
_trackpaddata.z = absZ;
_trackpaddata.zArray[_trackpaddata.zArrayCurrent] = absZ;
_trackpaddata.zArrayCurrent++;
_trackpaddata.zArrayCurrent %= _trackpadprefs.twoFingerScrollingPrefs.zArraySize;
if(_trackpaddata.zArrayCurrent == 0) // if we are back to 0 we have filled the array
_trackpaddata.zArrayFilled = true;
if(_trackpaddata.zArrayFilled) // if the array containing z data is filled
{
SInt16 zAverage = 0;
for(int i=0; i<_trackpadprefs.twoFingerScrollingPrefs.zArraySize; i++)
if(_trackpaddata.zArray[i] >= _trackpadprefs.twoFingerScrollingPrefs.zAcceptThreshold)
zAverage++;
#ifdef FFSDEBUGCOORDS
IOLog("FFScroll: zAcceptAverage : %d\n", zAverage);
#endif
if(zAverage >= _trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStart)
_trackpaddata.stickTwoFinger = true;
zAverage = 0;
for(int i=0; i<_trackpadprefs.twoFingerScrollingPrefs.zArraySize; i++)
if(_trackpaddata.zArray[i] <= _trackpadprefs.twoFingerScrollingPrefs.zDeclineThreshold)
zAverage++;
#ifdef FFSDEBUGCOORDS
IOLog("FFScroll: zDeclineAverage : %d\n", zAverage);
#endif
if(zAverage>=_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStop)
_trackpaddata.stickTwoFinger = false;
}
//IOLog("FFScroll:: Outside\n");
if(_trackpadprefs.tapDragEnable && _trackpaddata.stickTapDrag) // if dragging enable and we are dragging
{ // override button 1
//fix me
//IOLog("FFScroll:: Dragging");
if(buttonState){
_trackpaddata.buttonPressedWhileFingerOnPadDragging=true;
IOLog("FFScroll:: Button Pressed While Dragging\n");
}
if(!_trackpadprefs.scaleTrackpadSpeed) // if scaling is off send the unscaled dx and dy
{
dispatchRelativePointerEvent(dx,dy,1,now);
}
else //if scaling is on
{
//IOLog("FFScroll:: Dragging with Scaling");
SInt16 tmpx=100*dx+_trackpaddata.xrem; // multiply by 100 (to allow more finely grained scaling) and add the remainder
SInt16 tmpy=100*dy+_trackpaddata.yrem;
_trackpaddata.xrem=tmpx % _trackpadprefs.speedScale; // calculate the new remainders
_trackpaddata.yrem=tmpy % _trackpadprefs.speedScale;
dispatchRelativePointerEvent(tmpx/_trackpadprefs.speedScale,tmpy/_trackpadprefs.speedScale,1|(buttonState?_trackpadprefs.physicalButtonDragAction:0),now); // dispatch the scaled event
//IOLog("FFSCroll:: Sending button state %d",1|(buttonState?_trackpadprefs.physicalButtonDragAction:0));
}
}
// BEGIN HOTSPOT SCROLLING
else if
(
!_trackpadprefs.calibrateMode &&
_trackpadprefs.hasScrollAreas &&
_trackpadprefs.numberOfScrollAreas != 0 &&
_trackpaddata.scrollHotspotActive != -1 &&
(
_trackpadprefs.ScrollAreas[_trackpaddata.scrollHotspotActive].scrollOutsideArea ||
inRange(absX, absY, _trackpadprefs.ScrollAreas[_trackpaddata.scrollHotspotActive].coordAbs)
)
)
{
_trackpaddata.distanceScrolled+=my_abs(dy)+my_abs(dx); // may want to make it so it only adds the one corresponding to the direction of the hotspot
hotspotScrolling(dx,dy,now,nowNs);
}
// END HOTSPOT SCROLLLING
else if((_trackpaddata.scrollHotspotActive = -1) && !_trackpaddata.stickTwoFinger) // I don't like not having this as the else so feel free to swap them round
{
if(!_trackpadprefs.scaleTrackpadSpeed) // if scaling is off send the unscaled dx and dy
dispatchRelativePointerEvent(dx, dy, buttonState?_trackpadprefs.physicalButtonAction:0, now);
else
{
SInt16 tmpx=100*dx+_trackpaddata.xrem; // multiply by 100 (to allow more finely grained scaling) and add the remainder
SInt16 tmpy=100*dy+_trackpaddata.yrem;
_trackpaddata.xrem=tmpx % _trackpadprefs.speedScale; // calculate the new remainders
_trackpaddata.yrem=tmpy % _trackpadprefs.speedScale;
dispatchRelativePointerEvent(tmpx/_trackpadprefs.speedScale,tmpy/_trackpadprefs.speedScale,buttonState?_trackpadprefs.physicalButtonAction:0,now); // dispatch the scaled event
}
}
else
doScrolling(dx, dy, now);
}
else // finger was just put down
{
_trackpaddata.x = absX;
_trackpaddata.y = absY;
_trackpaddata.z = absZ;
// BEGIN HOTSPOT SCROLLING
if(!_trackpadprefs.calibrateMode && _trackpadprefs.hasScrollAreas)
{
for(int i=0; i<_trackpadprefs.numberOfScrollAreas && _trackpaddata.scrollHotspotActive == -1; i++)
{
#ifdef FFSDEBUG
IOLog("FFScroll: Testing Scroll Area %d with parameters %d %d %d %d\n", i,_trackpadprefs.ScrollAreas[i].coordAbs.x0,_trackpadprefs.ScrollAreas[i].coordAbs.x1,_trackpadprefs.ScrollAreas[i].coordAbs.y0,_trackpadprefs.ScrollAreas[i].coordAbs.y1);
#endif
if(inRange(absX, absY, _trackpadprefs.ScrollAreas[i].coordAbs))
{
#ifdef FFSDEBUG
IOLog("FFScroll: Detected fingerdown in Scroll hotspot %d\n", i);
#endif
_trackpaddata.scrollHotspotActive = i;
_trackpaddata.distanceScrolled=0;
_trackpaddata.lastScrollXTime=nowNs;
_trackpaddata.lastScrollYTime=nowNs;
_trackpaddata.scrollStrokeXStartTime=0;
_trackpaddata.scrollStrokeXLastUpdateTime=0;
_trackpaddata.scrollStrokeYStartTime=0;
_trackpaddata.scrollStrokeYLastUpdateTime=0;
}
}
}
// END HOTSPOT SCROLLING
if(_trackpadprefs.tapDragEnable)
{
if((nowNs-_trackpaddata.lastTapTime<_trackpadprefs.maxTapDragTime)&&
(_trackpadprefs.minTapDragTime<nowNs-_trackpaddata.lastTapTime)
&&
(_trackpaddata.x-_trackpaddata.downX<=_trackpadprefs.doubleTapTolerance && _trackpaddata.downX-_trackpaddata.x<=_trackpadprefs.doubleTapTolerance &&
_trackpaddata.y-_trackpaddata.downY<=_trackpadprefs.doubleTapTolerance && _trackpaddata.downY-_trackpaddata.y<=_trackpadprefs.doubleTapTolerance)
)
{ // Finger was only taken off pad to signal tap drag
#ifdef FFSDEBUG
IOLog("FFScroll: Drag started at (%d,%d) tap was at (%d,%d) time gap was %lld \n",_trackpaddata.x,_trackpaddata.y,_trackpaddata.downX,_trackpaddata.downY,(nowNs-_trackpaddata.lastTapTime));
#endif
#ifdef FFSDRAGDEBUG
IOLog("FFScroll: Drag started at (%d,%d) tap was at (%d,%d) time gap was %lld \n",_trackpaddata.x,_trackpaddata.y,_trackpaddata.downX,_trackpaddata.downY,(nowNs-_trackpaddata.lastTapTime));
#endif
_trackpaddata.stickTapDrag = true;
_trackpaddata.tapDragStartTime = nowNs;
}
else if(_trackpaddata.stickTapDrag) // if we are already dragging
{
if(_trackpadprefs.tapDragLock || (nowNs-_trackpaddata.lastFingerContactTime<_trackpadprefs.maxTapDragRevTime)) // if it is locked or within the rev time do nothing
{}
else
_trackpaddata.stickTapDrag = false; // release the tap drag
}
#ifdef FFSDRAGDEBUG
else
IOLog("FFScroll: No Drag found tap at %lld time now %lld time gap was %lld max gap is %lld\n",_trackpaddata.lastTapTime,nowNs,(nowNs-_trackpaddata.lastTapTime),_trackpadprefs.maxTapDragTime);
#endif
}
_trackpaddata.downX = absX;
_trackpaddata.downY = absY;
_trackpaddata.downZ = absZ;
_trackpaddata.fingerDownTime = nowNs;
}
_trackpaddata.lastFingerContactTime = nowNs;
}
}
// function to enable Absolute mode and report back success, derived from scrollpad::activate()
bool FFScroll::enableABS()
{
UInt8 adbdata[8];
IOByteCount adblength = 8;
IOLog("FFScroll: Enabling Absolute Mode.\n");
adbDevice->readRegister(1, adbdata, &adblength);
if((adbdata[6] != 0))
{
adbdata[6] = 0;
if (adbDevice->writeRegister(1, adbdata, &adblength) != 0)
{
// modes = 0 ;
IOLog("FFScroll: Can not activate absolute mode\n") ;
return false;
}
if (adbDevice->readRegister(1, adbdata, &adblength) != 0)
{
// modes = 0 ;
IOLog("FFScroll: Can not activate absolute mode (read failed)\n") ;
return false;
}
if (adbdata[6] != 0)
{
// modes = 0 ;
IOLog("FFScroll: Can not activate absolute mode (read != 0: 0x%x)\n", adbdata[6]);
return false;
}
}
return true;
}
void FFScroll::sendClickUp(OSObject* trackpad,IOTimerEventSource *sender) // little static procedure for callbacks for events
{
((FFScroll*)trackpad)->sendClickUpIfNotDragging();
}
void FFScroll::sendClick(OSObject* trackpad,IOTimerEventSource *sender) // used by the timer to send a delayed click event
{
((FFScroll*)trackpad)->sendClickNow();
}
bool FFScroll::addTimers()
{
bool result = true;
IOLog("Set Timeout Starting\n");
timeout = IOTimerEventSource::timerEventSource(this,(IOTimerEventSource::Action) &(this->sendClickUp));
if( this->getWorkLoop()->addEventSource(timeout))
{
IOLog("Set Timeout to loop Success\n");
}
else
{
result = false;
IOLog("Set Timeout to loop Failed\n");
}
IOLog("Set Timeout to loop Ending\n");
IOLog("Click Timer Starting\n");
clickTimer = IOTimerEventSource::timerEventSource(this,(IOTimerEventSource::Action) &(this->sendClick));
if( this->getWorkLoop()->addEventSource(clickTimer))
{
IOLog("Add Click Timer to Work Loop Success\n");
}
else
{
result = false;
IOLog("Add Click Timer to Work loop Failed\n");
}
IOLog("Set Timeout to loop Ending\n");
return result;
}
void FFScroll::setupDataAndPrefs() // Procedure to set up the data and preferences structs
{
#ifdef FFSDEBUGSETTINGS
#warning Using Debug Settings
_trackpadprefs.minX=10000;
_trackpadprefs.minY=10000;
_trackpadprefs.maxX=1;
_trackpadprefs.maxY=1;
_trackpadprefs.minTapDuration= 25000000; //0.025s
_trackpadprefs.maxTapDuration= 100000000; //0.1s
_trackpadprefs.minTapDragTime= 25000000; //0.025s
_trackpadprefs.maxTapDragTime= 200000000; //0.2s
_trackpadprefs.maxTapDragRevTime=500000000; //0.5s
_trackpadprefs.tapDragLock=false;
_trackpadprefs.buttonMaintainsDrag=false;
#warning button stops drag only makes sense if button set to 1
_trackpadprefs.buttonStopsDrag=true;
_trackpadprefs.tapDragEnable=false;
_trackpadprefs.tapClickEnable=true;
_trackpadprefs.zArraySize=8;
//TODO fix memory leak here
delete _trackpaddata.zArray;
_trackpaddata.zArray=new SInt16[_trackpadprefs.zArraySize];
_trackpaddata.zArrayCurrent=0;
_trackpaddata.zArrayFilled=false;
_trackpadprefs.stickTwoFingerStart=7;
_trackpadprefs.stickTwoFingerStop=8;
_trackpadprefs.zAcceptThreshold=61;
_trackpadprefs.zDeclineThreshold=10;
_trackpadprefs.hasScrollAreas=false;
_trackpadprefs.numberOfScrollAreas=0;
_trackpadprefs.hasHotspots=false;
_trackpadprefs.numberOfHotspots=0;
_trackpadprefs.scaleTrackpadSpeed=true;
_trackpadprefs.speedScale=150;
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingEnabled=true;
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingEnabled=false;
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingEnabled=true;
_trackpadprefs.twoFingerScrollingPrefs.scrollDominantOnly=false;
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingRate=2;
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingRate=1;
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingRate=1;
_trackpadprefs.twoFingerScrollingPrefs.invertCircularScrolling=false;
_trackpadprefs.twoFingerScrollingPrefs.invertVerticalScrolling=false;
_trackpadprefs.twoFingerScrollingPrefs.invertHorizontalScrolling=false;
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingThreshold=2;
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingThreshold=0;
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingThreshold=0;
_trackpadprefs.doubleTapTolerance=50;
_trackpadprefs.tapTolerance=10;
_trackpadprefs.physicalButtonAction=1;
#else
#warning Using Default Settings
_trackpadprefs.minX=10000;
_trackpadprefs.minY=10000;
_trackpadprefs.maxX=1;
_trackpadprefs.maxY=1;
_trackpadprefs.minTapDuration= 25000000; //0.025s
_trackpadprefs.maxTapDuration= 100000000; //0.1s
_trackpadprefs.minTapDragTime= 25000000; //0.025s
_trackpadprefs.maxTapDragTime= 200000000; //0.2s
_trackpadprefs.maxTapDragRevTime=500000000; //0.5s
_trackpadprefs.tapDragLock=false;
_trackpadprefs.physicalButtonDragAction=1;
// _trackpadprefs.buttonStopsDrag=true;
_trackpadprefs.tapDragEnable=false;
_trackpadprefs.tapClickEnable=false;
_trackpadprefs.twoFingerScrollingPrefs.zArraySize=8;
_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStart=7;
_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStop=8;
_trackpadprefs.twoFingerScrollingPrefs.zAcceptThreshold=61;
_trackpadprefs.twoFingerScrollingPrefs.zDeclineThreshold=10;
// TODO fix memory leak here!
delete _trackpaddata.zArray;
_trackpaddata.zArray=new SInt16[_trackpadprefs.twoFingerScrollingPrefs.zArraySize];
_trackpaddata.zArrayCurrent=0;
_trackpaddata.zArrayFilled=false;
_trackpadprefs.hasScrollAreas=false;
_trackpadprefs.numberOfScrollAreas=0;
_trackpadprefs.hasHotspots=false;
_trackpadprefs.numberOfHotspots=0;
_trackpadprefs.scaleTrackpadSpeed=true;
_trackpadprefs.speedScale=150;
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingEnabled=false;
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingEnabled=false;
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingEnabled=false;
_trackpadprefs.twoFingerScrollingPrefs.scrollDominantOnly=false;
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingRate=2;
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingRate=1;
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingRate=1;
_trackpadprefs.twoFingerScrollingPrefs.invertCircularScrolling=false;
_trackpadprefs.twoFingerScrollingPrefs.invertVerticalScrolling=false;
_trackpadprefs.twoFingerScrollingPrefs.invertHorizontalScrolling=false;
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingThreshold=2;
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingThreshold=0;
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingThreshold=0;
_trackpadprefs.doubleTapTolerance=50;
_trackpadprefs.tapTolerance=10;
_trackpadprefs.physicalButtonAction=1;
_trackpadprefs.minDragAssumedTime=500000000;
#endif
_trackpadprefs.calibrateMode=false;
_trackpaddata.x=0;
_trackpaddata.y=0;
_trackpaddata.z=0;
_trackpaddata.downX=0;
_trackpaddata.downY=0;
_trackpaddata.downZ=0;
_trackpaddata.fingerDownTime=0;
_trackpaddata.lastTapTime=0;
_trackpaddata.lastFingerContactTime=0;
_trackpaddata.tapDragStartTime=0;
_trackpaddata.stickTapDrag=false;
_trackpaddata.buttonPressedWhileFingerOnPadDragging=false;
_trackpaddata.stickTwoFinger=false;
_trackpaddata.xrem=0;
_trackpaddata.yrem=0;
_trackpaddata.horizontalScrollingRem=0;
_trackpaddata.verticalScrollingRem=0;
_trackpaddata.scrollHotspotActive=-1;
_trackpaddata.lastCalibrationUpdate=0;
_trackpaddata.calibrationHasChanged=false;
_trackpaddata.lastButtonState=0;
_trackpaddata.mouseupCallbacksAwaited=0;
_trackpaddata.clickCallbacksAwaited=0;
}
//End FFScroll
bool FFScroll::start(IOService * provider)
{
UInt8 adbdata[8];
IOByteCount adblength = 8;
OSNumber *dpi;
addTimers(); // adds timers -- returns a bool indicating success that will be used in the future
setupDataAndPrefs();
typeTrackpad = false;
if(adbDevice->setHandlerID(4) != kIOReturnSuccess)
return false;
dpi = OSDynamicCast( OSNumber, getProperty("dpi"));
if (dpi)
_resolution = dpi->unsigned16BitValue() << 16;
else
_resolution = deviceResolution << 16;
_notifierA = _notifierT = NULL; //Only used by trackpad, but inspected by all type 4 mice
_gettime = OSSymbol::withCString("get_last_keydown");
_mouseLock = IOLockAlloc();
adbDevice->readRegister(1, adbdata, &adblength);
if( (adbdata[0] == 't') && (adbdata[1] = 'p') && (adbdata[2] == 'a') && (adbdata[3] == 'd') )
{
mach_timespec_t t;
OSNumber *jitter_num;
t.tv_sec = 1; //Wait for keyboard driver for up to 1 second
t.tv_nsec = 0;
typeTrackpad = TRUE;
#ifdef FFSDEBUG
IOLog("FFScroll: Setting Type to trackpad.\n") ;
#endif
IOLog("FFScroll: Activate...\n") ;
_isAbsolute = enableABS();
//enableEnhancedMode();
IOLog("FFScroll: Absolute mode is %s.\n", _isAbsolute?"on":"off");
_pADBKeyboard = waitForService(serviceMatching("AppleADBKeyboard"), &t);
jitter_num = OSDynamicCast( OSNumber, getProperty("Trackpad Jitter Milliseconds"));
if (jitter_num)
{
_jitterclicktime64 = jitter_num->unsigned16BitValue() * 1000 * 1000; // in nanoseconds;
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime( _jitterclicktime64, (UInt64*)&_jitterclicktimeAB);
#elif OS_WE_BUILD_FOR == 3
nanoseconds_to_absolutetime( _jitterclicktime64, &_jitterclicktimeAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
}
else
{
_jitterclicktime64 = 750 * 1000 * 1000; // in nanoseconds;
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime( _jitterclicktime64, (UInt64*)&_jitterclicktimeAB);
#elif OS_WE_BUILD_FOR == 3
nanoseconds_to_absolutetime( _jitterclicktime64, &_jitterclicktimeAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
}
jitter_num = OSDynamicCast( OSNumber, getProperty("Trackpad Jitter Max delta"));
if (jitter_num)
{
_jitterdelta = jitter_num->unsigned16BitValue();
if (_jitterdelta == 0)
_jittermove = false;
}
else
{
_jitterdelta = 16; // pixels;
}
setProperty(kIOHIDPointerAccelerationTypeKey, kIOHIDTrackpadAccelerationType);
//This is the only way to find out if we have new trackpad with W info passed in relative mode
if ( deviceNumButtons == 4 )
{
setProperty("W Enhanced Trackpad", (unsigned long long)true, sizeof(Clicking)*8);
_isWEnhanced = true;
_usePantherSettings = false;
_jitterclick = _jittermove; //Necessary since Mouse Pref fix isn't available
// FFScroll Modified
_buttonCount = 6;
// End FFScroll Modified
}
else
{
// FFScroll Modified
_buttonCount = 6;
// End FFScroll Modified
_isWEnhanced = false;
// Don't even bother to set the property. Its ABSENCE will be just as informative.
}
} //end of trackpad processing
if (!_notifierA)
_notifierA = addNotification( gIOFirstMatchNotification, serviceMatching( "IOHIPointing" ),
(IOServiceNotificationHandler)add_usb_mouse, this, 0 );
if (!_notifierT)
_notifierT = addNotification( gIOTerminatedNotification, serviceMatching( "IOHIPointing" ),
(IOServiceNotificationHandler)remove_usb_mouse, this, 0 );
// The same C function can handle both firstmatch and termination notifications
// FFScroll Modified
// _buttonCount = 1; //All Apple trackpads have 1 button - [3770193] - oh really?
// End FFScroll
#ifdef FFSDEBUG
IOLog("FFScroll: Finished FFScroll::start\n") ;
#endif
return super::start(provider);
}
//FFScroll Added
void FFScroll::stop(IOService *provider) // added to allow the driver to get rid of the timers
{
if(timeout)
{
timeout->cancelTimeout();
timeout->disable();
this->getWorkLoop()->removeEventSource(timeout);
}
if(clickTimer)
{
clickTimer->cancelTimeout();
clickTimer->disable();
this->getWorkLoop()->removeEventSource(clickTimer);
}
super::stop(provider);
}
//End FFScroll
void FFScroll::free( void )
{
if (_notifierA)
{
_notifierA->remove();
_notifierA = NULL;
}
if (_notifierT)
{
_notifierT->remove();
_notifierT = NULL;
}
_ignoreTrackpadState = 0;
_sticky2finger = false;
_zonepeckingtimeAB = _keyboardTimeAB; //unsticks trackpad when sleeping
if (_gettime)
_gettime->release();
if (_mouseLock)
{
IOLock * lock;
IOLockLock(_mouseLock);
lock = _mouseLock;
_mouseLock = NULL;
IOLockUnlock(lock);
IOLockFree(lock);
}
if (_externalMice)
{
_externalMice->release();
_externalMice = 0;
}
super::free();
}
bool add_usb_mouse(OSObject * us, void *, IOService * yourDevice)
{
if (us)
{
((FFScroll *)us)->_check_usb_mouse(yourDevice, true);
}
return true;
}
bool remove_usb_mouse(OSObject * us, void *, IOService * yourDevice)
{
if (us)
{
((FFScroll *)us)->_check_usb_mouse(yourDevice, false);
}
return true;
}
/*
* If any extra mouse is found, then disable the trackpad.
*/
void FFScroll::_check_usb_mouse( IOService * service, bool added )
{
// Check to see if we are interested in this service
if ( (service == this) ||
!OSDynamicCast(IOHIPointing, service) ||
(service->getProperty(kIOHIDVirtualHIDevice) == kOSBooleanTrue))
return;
IOLockLock(_mouseLock);
if ( !_externalMice &&
!(_externalMice = OSSet::withCapacity(4)))
{
IOLockUnlock(_mouseLock);
return;
}
if (added)
{
_externalMice->setObject(service);
}
else
{
_externalMice->removeObject(service);
}
IOLockUnlock(_mouseLock);
}
/*
* The following ::packet() has not been changed at all. Enhanced trackpad processing
* will automatically go to ::packetW().
*/
void FFScroll::packet(UInt8 /*adbCommand*/, IOByteCount length, UInt8 * data)
{
int dx, dy, cnt, numExtraBytes;
UInt32 buttonState = 0;
AbsoluteTime now;
IOLockLock(_mouseLock);
bool shouldIgnore = (((_ignoreTrackpadState & kIgnoreTrackpadState_USBMouse) && (_externalMice && (_externalMice->getCount() > 0 )))
|| ((_ignoreTrackpadState & kIgnoreTrackpadState_MouseKeys) && (_ignoreTrackpadState & kIgnoreTrackpadState_MouseKeys_State_On)));
IOLockUnlock(_mouseLock);
//FFScroll Modified
// FFScroll Changed this, hopefully should be the only change other than fixing time
if (typeTrackpad && shouldIgnore)
return;
// End FFScroll
if (_isAbsolute) // want to call this variable degree absolute but actually this just says if in absolute mode interpret the packet as absolute
{
packetABS(0,length,data);
return;
}
if(_isWEnhanced) //This also implies typeTrackpad == true
{
packetW(0, length, data);
return;
}
numExtraBytes = length - 2;
dy = data[0] & 0x7f;
dx = data[1] & 0x7f;
if ((data[0] & 0x80) == 0)
{
buttonState |= 1;
}
if ((deviceNumButtons > 1) && ((data[1] & 0x80) == 0))
{
if(typeTrackpad)
{
if ((_jitterclick) && (_pADBKeyboard))
{
AbsoluteTime keyboardtime;
UInt64 nowtime64, keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false,
(void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowtime64);
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
if (nowtime64 - keytime64 > _jitterclicktime64)
{
buttonState |= 1;
}
}
else
buttonState |= 1;
}
else
{
buttonState |= 2;
}
}
for (cnt = 0; cnt < numExtraBytes; cnt++) {
dy |= ((data[2 + cnt] >> 4) & 7) << (7 + (cnt * 3));
dx |= ((data[2 + cnt]) & 7) << (7 + (cnt * 3));
if ((deviceNumButtons > (cnt + 2)) && ((data[2 + cnt] & 0x80) == 0))
buttonState |= 4 << (cnt * 2);
if ((deviceNumButtons > (cnt + 2 + 1)) && ((data[2 + cnt] & 0x08) == 0))
buttonState |= 4 << (cnt * 2 + 1);
}
if (dy & (0x40 << (numExtraBytes * 3)))
dy |= (0xffffffc0 << (numExtraBytes * 3));
if (dx & (0x40 << (numExtraBytes * 3)))
dx |= (0xffffffc0 << (numExtraBytes * 3));
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
if( typeTrackpad && _jittermove && _pADBKeyboard )
{
AbsoluteTime keyboardtime;
UInt64 nowtime64, keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false, (void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
absolutetime_to_nanoseconds(now, &nowtime64);
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// absolutetime_to_nanoseconds(now, &nowtime64);
// absolutetime_to_nanoseconds(keyboardtime, &keytime64);
if (nowtime64 - keytime64 < _jitterclicktime64)
{
if ((my_abs(dx) < _jitterdelta) && (my_abs(dy) < _jitterdelta))
{
if (!buttonState && !_oldButtonState)
{
//simulate no mouse move. Keeps cursor invisible.
return;
}
else
{
dx = 0;
dy = 0;
}
}
}
}
_oldButtonState = buttonState;
dispatchRelativePointerEvent(dx, dy, buttonState, now);
}
/*
* The following ::packetW() assumes two flags:
* _isWEnhanced is true and typeTrackpad is true.
*/
void FFScroll::packetW(UInt8 /*adbCommand*/, IOByteCount length, UInt8 * data)
{
int dx, dy, cnt, numExtraBytes;
bool palm = false, outzone = false, has2fingers = false;
UInt32 buttonState = 0;
AbsoluteTime now;
if (_usePantherSettings)
{
packetWP(0, length, data);
return;
}
numExtraBytes = length - 2;
dy = data[0] & 0x7f;
dx = data[1] & 0x7f;
if ((data[0] & 0x80) == 0)
{
buttonState |= 1;
}
//Here we check for inadvertent palm presses and outside-zone clicks. In theory I
// should check for gesture clicks when outzone below is true, but the
// trackpad never picks up on that. Can't make gesture clicks using edge of
// my palm either.
//if(_isWEnhanced) //This also implies typeTrackpad == true
{
if ((data[2] & 0x80) == 0)
{
if (_zonenomove)
outzone = true;
}
if ((data[2] & 0x08) == 0)
{
if (_palmnomove)
palm = true;
}
if ((data[3] & 0x80) == 0)
{
if (_2fingernoaction)
{
has2fingers = true;
_sticky2finger = true;
//I need to log when it became sticky for timeout purposes
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&_sticky2fingerTimeAB);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&_sticky2fingerTimeAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// clock_get_uptime(&_sticky2fingerTimeAB);
}
}
if ((data[3] & 0x08) != 0)
{
//All fingers are off the trackpad now, so clear sticky bit
_sticky2finger = false;
}
//Fake a 2 finger contact if sticky bit is still on. But calculate time delta first.
if (_sticky2finger)
{
AbsoluteTime nowtimeAB;
// clock_get_uptime(&nowtimeAB);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&nowtimeAB);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&nowtimeAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
//if (nowtime64 - _sticky2fingerTime64 < _timeoutSticky64)
SUB_ABSOLUTETIME(&nowtimeAB, &_sticky2fingerTimeAB);
if ( CMP_ABSOLUTETIME(&nowtimeAB, &_timeoutStickyAB) == -1)
{
has2fingers = true;
}
else
{
_sticky2finger = false; //Make it more efficient
}
}
//Apple trackpads should not have more than two buttons. Non-Apple trackpads
// should never match the "tpad" signature anyways.
data[2] |= 0x88; //clear two button bits, both negative logic
data[3] |= 0x88; //Assume Apple trackpads will never have multiple buttons for ADB
}
if ((deviceNumButtons > 1) && ((data[1] & 0x80) == 0))
{
//if(typeTrackpad)
{
if ((_jitterclick) && (_pADBKeyboard))
{
_pADBKeyboard->callPlatformFunction(_gettime, false,
(void *)&_keyboardTimeAB, 0, 0, 0);
// clock_get_uptime(&now);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
SUB_ABSOLUTETIME(&now, &_keyboardTimeAB);
if ( CMP_ABSOLUTETIME(&now, &_jitterclicktimeAB) == 1)
//if (nowtime64 - keytime64 > _jitterclicktime64)
{
buttonState |= 1;
//This part automatically takes care of narrow objects along outside zones.
//It is accepted if no recent typing, it is filtered if recent typing
//The rejection is taken care of by code below, not here
}
//This is new for WEnhanced trackpads: ANYTHING in center of pad is ALWAYS accepted.
// That means even when typing.... this differs from old behavior
if ( !outzone)
{
buttonState |= 1; // EB .. this could come first
}
if (CMP_ABSOLUTETIME( &_zonepeckingtimeAB, &_keyboardTimeAB) != 0)
{
buttonState = 0;
}
}
else
buttonState |= 1;
}
}
for (cnt = 0; cnt < numExtraBytes; cnt++) {
dy |= ((data[2 + cnt] >> 4) & 7) << (7 + (cnt * 3));
dx |= ((data[2 + cnt]) & 7) << (7 + (cnt * 3));
if ((deviceNumButtons > (cnt + 2)) && ((data[2 + cnt] & 0x80) == 0))
buttonState |= 4 << (cnt * 2);
if ((deviceNumButtons > (cnt + 2 + 1)) && ((data[2 + cnt] & 0x08) == 0))
buttonState |= 4 << (cnt * 2 + 1);
}
if (dy & (0x40 << (numExtraBytes * 3)))
dy |= (0xffffffc0 << (numExtraBytes * 3));
if (dx & (0x40 << (numExtraBytes * 3)))
dx |= (0xffffffc0 << (numExtraBytes * 3));
// clock_get_uptime(&now);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
//If UI sets _jittermove, then we need special filtering for W Enhanced trackpads.
// That checkbox implies that ALL multi-finger presses are filtered.
// Also, if both outzone and palm are true, meaning palm on outside edges,
// then that is always filtered.
if (_jittermove)
{
if ((has2fingers) || (outzone && palm))
{
//If current button state is empty and the prior button state was empty too, then
//simulate no mouse move to keep cursor invisible. However, if the previous button
//state had a click, then a single button UP state should be sent to Window Server so that
//it does not keep buffering up typed text even though the user is not holding down
//the trackpad button in any way.
if ( !buttonState && !_oldButtonState)
{
return;
}
else if ((data[1] & 0x80) == 0) //filter out gesture clicks
{
return;
}
else //If a button is logicaly down, it needs to go to the Window Server but not dx, dy
{
dx = 0;
dy = 0;
}
}
//This is new for WEnhanced trackpads: ANYTHING in center of pad is ALWAYS accepted
// unless 2 finger (or sticky 2 finger) is active above. Note also that palm
// input is rejected above ONLY if the palm is along the edge. Palm contact in
// center of pad will always be allowed.
if (( !outzone) && (_pADBKeyboard))
{
_pADBKeyboard->callPlatformFunction(_gettime, false, (void *)&_zonepeckingtimeAB, 0, 0, 0);
}
else if (_pADBKeyboard)
{
AbsoluteTime sub_now;
_pADBKeyboard->callPlatformFunction(_gettime, false, (void *)&_keyboardTimeAB, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime ((unsigned long long)( (unsigned long long)(5 * 60 * 1000) * (unsigned long long)(1000 * 1000) ), (UInt64 *)&_fake5minAB);
#elif OS_WE_BUILD_FOR ==3
nanoseconds_to_absolutetime( (unsigned long long)( (unsigned long long)(5 * 60 * 1000) * (unsigned long long)(1000 * 1000) ), &_fake5minAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// nanoseconds_to_absolutetime( (unsigned long long)( (unsigned long long)(5 * 60 * 1000) * (unsigned long long)(1000 * 1000) ), &_fake5minAB);
sub_now = now;
SUB_ABSOLUTETIME(&sub_now, &_keyboardTimeAB);
if (CMP_ABSOLUTETIME (&sub_now, &_fake5minAB) == -1)
//if (nowtime64 - keytime64 < _fake5min)
{
//This part rejects all movements along the edge when typing. By
// logic that means narrow contact along edge. Wide contact along
// edge (regardless of recent keyboarding) was already filtered out above.
//if (_zonepeckingtime64 != keytime64)
if ( CMP_ABSOLUTETIME ( &_zonepeckingtimeAB, &_keyboardTimeAB) != 0)
{
if (!buttonState && !_oldButtonState)
{
//simulate no mouse move. Keeps cursor invisible.
return;
}
else if ((data[1] & 0x80) == 0)
{
return;
}
else
{
dx = 0;
dy = 0;
}
}
}
}
} //jittermove
_oldButtonState = buttonState;
dispatchRelativePointerEvent(dx, dy, buttonState, now);
}
/*
* Next method is mostly for exploring future Panther filtering for trackpads.
* Since it is called by ::packetW(), it also assumes a W enhanced trackpad.
*/
void FFScroll::packetWP(UInt8 /*adbCommand*/, IOByteCount length, UInt8 * data)
{
int dx, dy, cnt, numExtraBytes;
bool palm = false, outzone = false, has2fingers = false;
UInt32 buttonState = 0;
AbsoluteTime now;
numExtraBytes = length - 2;
dy = data[0] & 0x7f;
dx = data[1] & 0x7f;
if ((data[0] & 0x80) == 0)
{
buttonState |= 1;
}
//Here we check for inadvertent palm presses and outside-zone clicks. In theory I
// should check for gesture clicks when outzone below is true, but the
// trackpad never picks up on that. Can't make gesture clicks using edge of
// my palm either.
//if(typeTrackpad)
{
if ((data[2] & 0x80) == 0)
{
outzone = true;
}
if ((data[2] & 0x08) == 0)
{
palm = true;
}
if ((data[3] & 0x80) == 0)
{
if (_2fingernoaction)
{
has2fingers = true;
_sticky2finger = true;
//I need to log when it became sticky for timeout purposes
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &_sticky2fingerTime64);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &_sticky2fingerTime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// clock_get_uptime(&now);
// absolutetime_to_nanoseconds(now, &_sticky2fingerTime64);
}
}
if ((data[3] & 0x08) != 0)
{
//All fingers are off the trackpad now, so clear sticky bit
_sticky2finger = false;
}
//Fake a 2 finger contact via palm bit if _sticky2finger is still on
if (_sticky2finger)
{
UInt64 nowtime64;
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowtime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// clock_get_uptime(&now);
// absolutetime_to_nanoseconds(now, &nowtime64);
if (nowtime64 - _sticky2fingerTime64 < _timeoutSticky64)
{
palm = true;
}
else
{
_sticky2finger = false; //Make it more efficient
}
}
//Apple trackpads should not have more than two buttons. Non-Apple trackpads
// should never match the "tpad" signature anyways.
data[2] |= 0x88; //clear two button bits, both negative logic
data[3] |= 0x88; //Assume Apple trackpads will never have multiple buttons for ADB
}
if ((deviceNumButtons > 1) && ((data[1] & 0x80) == 0))
{
//if(typeTrackpad)
{
if ((_jitterclick) && (_pADBKeyboard))
{
AbsoluteTime keyboardtime;
UInt64 nowtime64, keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false,
(void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
absolutetime_to_nanoseconds(now, &nowtime64);
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
//clock_get_uptime(&now);
//absolutetime_to_nanoseconds(now, &nowtime64);
//absolutetime_to_nanoseconds(keyboardtime, &keytime64);
if (nowtime64 - keytime64 > _jitterclicktime64)
{
buttonState |= 1;
}
}
else
buttonState |= 1;
}
}
for (cnt = 0; cnt < numExtraBytes; cnt++) {
dy |= ((data[2 + cnt] >> 4) & 7) << (7 + (cnt * 3));
dx |= ((data[2 + cnt]) & 7) << (7 + (cnt * 3));
if ((deviceNumButtons > (cnt + 2)) && ((data[2 + cnt] & 0x80) == 0))
buttonState |= 4 << (cnt * 2);
if ((deviceNumButtons > (cnt + 2 + 1)) && ((data[2 + cnt] & 0x08) == 0))
buttonState |= 4 << (cnt * 2 + 1);
}
if (dy & (0x40 << (numExtraBytes * 3)))
dy |= (0xffffffc0 << (numExtraBytes * 3));
if (dx & (0x40 << (numExtraBytes * 3)))
dx |= (0xffffffc0 << (numExtraBytes * 3));
#if OS_WE_BUILD_FOR == 4
clock_get_uptime((UInt64*)&now);
#elif OS_WE_BUILD_FOR == 3
clock_get_uptime(&now);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// clock_get_uptime(&now);
if(typeTrackpad )
{
//The UI is expected to affect _palmnoaction but not _zonenoaction. However,
// I am leaving _zonenoaction to a default of false. Someone may find
// it useful some day and set it to true.
if ((_2fingernoaction && has2fingers) || (_palmnoaction && palm) ||
(_zonenoaction && outzone))
{
if (!buttonState && !_oldButtonState)
{
//simulate no mouse move. Keeps cursor invisible.
return;
}
else
{
dx = 0;
dy = 0;
}
}
if ( _jittermove && _pADBKeyboard )
{
AbsoluteTime keyboardtime;
UInt64 nowtime64, keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false, (void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
absolutetime_to_nanoseconds(now, &nowtime64);
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// absolutetime_to_nanoseconds(now, &nowtime64);
// absolutetime_to_nanoseconds(keyboardtime, &keytime64);
if (nowtime64 - keytime64 < _jitterclicktime64)
{
if ((my_abs(dx) < _jitterdelta) && (my_abs(dy) < _jitterdelta))
{
//If current button state is empty and the prior button state was empty too, then
//simulate no mouse move to keep cursor invisible. However, if the previous button
//state had a click, then a single button UP state should be sent to Window Server so that
//it does not keep buffering up typed text even though the user is not holding down
//the trackpad button in any way.
if ( !buttonState && !_oldButtonState )
{
return;
}
else
{
dx = 0;
dy = 0;
}
}
}
} //jittermove
//I am assuming the UI eventually will make _zonenomove and _jittermove mutually
// exclusive, but for now I'll allow possibility of both being active. Actions
// in _jitternomove code above take precedence, of course, and they affect the
// entire trackpad, not just certain zones. The UI should not make _zonenomove
// available for older PowerBooks
if (_zonenomove)
{
if (_pADBKeyboard)
{
AbsoluteTime keyboardtime;
UInt64 nowtime64, keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false, (void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
absolutetime_to_nanoseconds(*(UInt64*)&now, &nowtime64);
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
absolutetime_to_nanoseconds(now, &nowtime64);
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
//absolutetime_to_nanoseconds(now, &nowtime64);
//absolutetime_to_nanoseconds(keyboardtime, &keytime64);
if (nowtime64 - keytime64 < _jitterclicktime64)
{
//_palmnomove will not be in UI and it should default to off, but I
// am leaving this property here for now in case someone finds it useful.
// _palmnoaction is intended for the main palm check feature and
// supercedes _palmnomove. Note also that I am rejecting even valid
// clicks from the physical button (not just gestures) because the
// entire palm may be on the trackpad
if (_palmnomove && palm)
{
return;
}
//If it has been a while since the user last touched the ADB keyboard,
// then movements should be allowed anywhere on trackpad, but
// then we would not be in this part of the driver anyways.
if (outzone)
{
// _ignorezone is set below if user touches middle (major) zone of trackpad.
// _ignorezone is set to false initially in ::enableEnhancedMode()
if (!_ignorezone)
{
if (!buttonState && !_oldButtonState)
{
return;
}
else if ((data[1] & 0x80) == 0) //filter out gesture clicks
{
return;
}
else
{
dx = 0;
dy = 0;
}
}
}
else
{
//If user touches within center of trackpad and not outside edges,
// assume the touch is intentional so then set a flag so that even
// if the user strays to edges again within our time period, those
// moves will not be filtered out
_ignorezone = true;
}
}
else //if long time has passed, reset zone checking for subsequent keyboard clicks
{
_ignorezone = false;
}
}
} //_zonenomove
//Again I am assuming the UI will make following _zonepecknomove mutually exclusive from
// _zonenomove and _jittermove above, meaning only ONE of the three would be active.
// However, to keep our options flexible for now I will allow all three to be active
// simultaneously.
if (_zonepecknomove)
{
if (_pADBKeyboard)
{
AbsoluteTime keyboardtime;
UInt64 keytime64;
_pADBKeyboard->callPlatformFunction(_gettime, false, (void *)&keyboardtime, 0, 0, 0);
#if OS_WE_BUILD_FOR == 4
absolutetime_to_nanoseconds(*(UInt64*)&keyboardtime, &keytime64);
#elif OS_WE_BUILD_FOR == 3
absolutetime_to_nanoseconds(keyboardtime, &keytime64);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// absolutetime_to_nanoseconds(keyboardtime, &keytime64);
if (outzone)
{
//if user had pressed a new keyboard key since the last time the trackpad
// was touched in the center zone, we need to cut that trackpad movement out.
// This is intended as a PERMANENT filtering for as long as the user does
// not touch the center zone of the trackpad
if (_zonepeckingtime64 != keytime64)
{
if (!buttonState && !_oldButtonState)
{
return;
}
else if ((data[1] & 0x80) == 0) //filter out gesture clicks
{
return;
}
else
{
dx = 0;
dy = 0;
}
}
}
else
{
//Save time of last keypress since user is moving withing center zone now
_zonepeckingtime64 = keytime64;
}
}
} // _zonepecknomove
}
_oldButtonState = buttonState;
dispatchRelativePointerEvent(dx, dy, buttonState, now);
}
OSData * FFScroll::copyAccelerationTable()
{
char keyName[10];
strcpy( keyName, "accl" );
keyName[4] = (deviceSignature >> 24);
keyName[5] = (deviceSignature >> 16);
keyName[6] = (deviceSignature >> 8);
keyName[7] = (deviceSignature >> 0);
keyName[8] = 0;
IOLockLock( _mouseLock);
OSData * data = OSDynamicCast( OSData,
getProperty( keyName ));
IOLockUnlock( _mouseLock);
if( data)
{
data->retain();
}
else
{
data = super::copyAccelerationTable();
}
return( data );
}
// ****************************************************************************
// enableEnhancedMode
//
// ****************************************************************************
bool FFScroll::enableEnhancedMode()
{
UInt8 adbdata[8];
IOByteCount adblength = 8;
OSNumber *plistnum;
//IOLog("enableEnhancedMode called.\n");
adbDevice->readRegister(1, adbdata, &adblength);
if((adbdata[6] != 0x0D))
{
adbdata[6] = 0xD;
if (adbDevice->writeRegister(1, adbdata, &adblength) != 0)
return FALSE;
if (adbDevice->readRegister(1, adbdata, &adblength) != 0)
return FALSE;
if (adbdata[6] != 0x0D)
{
IOLog("FFScroll deviceClass = %d (non-Extended Mode)\n", adbdata[6]);
return FALSE;
}
//IOLog("FFScroll deviceClass = %d (Extended Mode)\n", adbdata[6]);
// Set ADB Extended Features to default values.
adbdata[0] = 0x19; //MSB=Use Soft click (gesture). 7 bits for DownTime.
adbdata[1] = 0x14;
adbdata[2] = 0x19;
adbdata[3] = 0xB2; //MSB=Use sticky drag. 7 bits for StickyDragTime.
adbdata[4] = 0xB2;
adbdata[5] = 0x8A;
adbdata[6] = 0x1B;
//WARNING... next one may have a conflict
//adbdata[7] = 0x50;
adbdata[7] = 0x57; //bits 3:0 for W mode
adblength = 8;
adbDevice->writeRegister(2, adbdata, &adblength);
/* Add IORegistry entries for Enhanced mode */
Clicking = FALSE;
Dragging = FALSE;
DragLock = FALSE;
setProperty("Clicking", (unsigned long long)Clicking, sizeof(Clicking)*8);
setProperty("Dragging", (unsigned long long)Dragging, sizeof(Dragging)*8);
setProperty("DragLock", (unsigned long long)DragLock, sizeof(DragLock)*8);
/* check for jitter correction initially before Mouse Preferences
calls setParamProperties*/
plistnum = OSDynamicCast( OSNumber, getProperty("JitterNoClick"));
if (plistnum)
{
_jitterclick = (bool) plistnum->unsigned16BitValue();
}
else
{
_jitterclick = false;
}
plistnum = OSDynamicCast( OSNumber, getProperty("JitterNoMove"));
if (plistnum)
{
_jittermove = (bool) plistnum->unsigned16BitValue();
}
else
{
_jittermove = false;
}
if (_isWEnhanced) //W enhanced trackpads should get filtering on by default
{
setProperty("JitterNoClick", true, sizeof(UInt32));
setProperty("JitterNoMove", true, sizeof(UInt32));
_jitterclick = _jittermove = true;
}
plistnum = OSDynamicCast( OSNumber, getProperty("W sticky input timeout"));
if (plistnum)
{
_timeoutSticky64 = plistnum->unsigned32BitValue() * 1000 * 1000; // in nanoseconds;
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime (_timeoutSticky64, (UInt64 *)&_timeoutStickyAB);
#elif OS_WE_BUILD_FOR ==3
nanoseconds_to_absolutetime (_timeoutSticky64, &_timeoutStickyAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// nanoseconds_to_absolutetime(_timeoutSticky64, &_timeoutStickyAB);
}
else
{
_timeoutSticky64 = 500 * 1000 * 1000; // 500 millisecond sticky timeout
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime (_timeoutSticky64, (UInt64 *)&_timeoutStickyAB);
#elif OS_WE_BUILD_FOR ==3
nanoseconds_to_absolutetime (_timeoutSticky64, &_timeoutStickyAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// nanoseconds_to_absolutetime(_timeoutSticky64, &_timeoutStickyAB);
}
plistnum = OSDynamicCast( OSNumber, getProperty("W threshold"));
if (plistnum)
{
_WThreshold = (UInt8) plistnum->unsigned16BitValue();
}
else
{
_WThreshold = 7; //Arbitrary value for medium size thumbs
}
plistnum = OSDynamicCast( OSNumber, getProperty("TwofingerNoAction"));
if (plistnum)
{
_2fingernoaction = (bool) plistnum->unsigned16BitValue();
}
else
{
_2fingernoaction = false;
}
plistnum = OSDynamicCast( OSNumber, getProperty("PalmNoAction Permanent"));
if (plistnum)
{
_palmnoaction = (bool) plistnum->unsigned16BitValue();
}
else
{
_palmnoaction = false;
}
plistnum = OSDynamicCast( OSNumber, getProperty("PalmNoAction When Typing"));
if (plistnum)
{
_palmnomove = (bool) plistnum->unsigned16BitValue();
}
else
{
_palmnomove = false;
}
plistnum = OSDynamicCast( OSNumber, getProperty("OutsidezoneNoAction Permanent"));
if (plistnum)
{
_zonenoaction = (bool) plistnum->unsigned16BitValue();
}
else
{
_zonenoaction = false;
}
plistnum = OSDynamicCast( OSNumber, getProperty("OutsidezoneNoAction When Typing"));
if (plistnum)
{
_zonenomove = (bool) plistnum->unsigned16BitValue();
}
else
{
_zonenomove = false;
}
plistnum = OSDynamicCast( OSNumber, getProperty("OutsidezoneNoAction When Pecking"));
if (plistnum)
{
_zonepecknomove = (bool) plistnum->unsigned16BitValue();
}
else
{
_zonepecknomove = false;
}
_ignorezone = false;
_zonepeckingtime64 = 0;
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime (0, (UInt64 *)&_zonepeckingtimeAB);
#elif OS_WE_BUILD_FOR ==3
nanoseconds_to_absolutetime (0, &_zonepeckingtimeAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
// nanoseconds_to_absolutetime(0, &_zonepeckingtimeAB);
return TRUE;
}
return FALSE;
}
// ****************************************************************************
// setParamProperties
//
// ****************************************************************************
IOReturn FFScroll::setParamProperties( OSDictionary * dict )
{
OSNumber *datan;
OSBoolean *datab; // Place to store OSBoolean data
OSArray *dataa; // Place to store OSArraydata
OSDictionary *datad; // Place to store OSDictionary data
OSDictionary *dictionary; // Place to store FFScroll's OSDictionary data
IOReturn err = kIOReturnSuccess;
UInt8 adbdata[8];
IOByteCount adblength;
// UInt16 settrue = 0;
if (typeTrackpad == TRUE)
{
// =========================
// BEGIN READING APPLE PREFS
// =========================
IOLockLock( _mouseLock);
if (datan = OSDynamicCast(OSNumber, dict->getObject(AppleClickingKey)))
{
if (datan->unsigned32BitValue())
{
_trackpadprefs.tapClickEnable=true;
//settrue = 1; //Guard against values that are neither 0 nor 1
}
else{
_trackpadprefs.tapClickEnable=false;
_trackpadprefs.tapDragEnable=false;
_trackpadprefs.tapDragLock=false;
_trackpaddata.stickTapDrag=false;
}
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Clicking set to: %d\n", (char)_trackpadprefs.tapClickEnable) ;
#endif
//setProperty("Clicking", (unsigned long long)(_trackpadprefs.tapClickEnable?1:0), sizeof(adbdata[0])*8);
setProperty("Clicking", (unsigned long long)(_trackpadprefs.tapClickEnable?1:0), 8);
}
if (datan = OSDynamicCast(OSNumber, dict->getObject(AppleDraggingKey)))
{
if (datan->unsigned32BitValue())
{
_trackpadprefs.tapDragEnable=true;
}
else{
_trackpadprefs.tapDragEnable=false;
_trackpadprefs.tapDragLock=false;
_trackpaddata.stickTapDrag=false;
}
//setProperty("Dragging", (unsigned long long)(property), sizeof(property)*8);
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Drag State set to: %d\n", (char)_trackpadprefs.tapDragEnable) ;
#endif
setProperty("Dragging", (unsigned long long)(_trackpadprefs.tapDragEnable?1:0), 8);
}
if (datan = OSDynamicCast(OSNumber, dict->getObject(AppleDragLockKey)))
{
_trackpadprefs.tapDragLock=false;
if(datan->unsigned32BitValue())
{
_trackpadprefs.tapDragLock=true;
}
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Drag Lock set to: %d\n", (char)_trackpadprefs.tapDragLock);
#endif
setProperty("DragLock", (unsigned long long)(_trackpadprefs.tapDragLock?1:0), 8);
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("JitterNoClick")))
{
_jitterclick = (bool) datan->unsigned32BitValue();
setProperty("JitterNoClick", _jitterclick, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Jitter Click set to: %d\n", (char)_jitterclick) ;
#endif
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("JitterNoMove")))
{
_jittermove = (bool) datan->unsigned32BitValue();
setProperty("JitterNoMove", _jittermove, sizeof(UInt32));
_jitterclick = _jittermove;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Jitter No Move set to: %d\n", (char)_jittermove) ;
#endif
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("Trackpad Jitter Milliseconds")))
{
_jitterclicktime64 = datan->unsigned32BitValue() * 1000 * 1000; // in nanoseconds;
setProperty("Trackpad Jitter Milliseconds", datan->unsigned32BitValue(),
8 * sizeof(adbdata[1]));
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime (_jitterclicktime64, (UInt64 *)&_jitterclicktimeAB);
#elif OS_WE_BUILD_FOR ==3
nanoseconds_to_absolutetime (_jitterclicktime64, &_jitterclicktimeAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Jitter Milliseconds set to: %d\n", datan->unsigned32BitValue()) ;
#endif
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("W sticky input timeout")))
{
_timeoutSticky64 = datan->unsigned32BitValue() * 1000 * 1000; // in nanoseconds;
setProperty("W sticky input timeout", datan->unsigned32BitValue(),
8 * sizeof(adbdata[1]));
#if OS_WE_BUILD_FOR == 4
nanoseconds_to_absolutetime (_timeoutSticky64, (UInt64 *)&_timeoutStickyAB);
#elif OS_WE_BUILD_FOR ==3
nanoseconds_to_absolutetime(_timeoutSticky64, &_timeoutStickyAB);
#else
#error OS_WE_BUILD_FOR has bad value
#endif
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("W threshold")))
{
_WThreshold = (UInt8) datan->unsigned32BitValue();
_WThreshold &= 0xf; //f is max threshold
setProperty("W threshold", _WThreshold, sizeof((adbdata[2]) * 8));
adblength = sizeof(adbdata);
adbDevice->readRegister(2, adbdata, &adblength);
adbdata[7] = adbdata[7] & 0xf0; //only set bits 3..0
adbdata[7] = adbdata[7] | _WThreshold;
adblength = sizeof(adbdata);
adbDevice->writeRegister(2, adbdata, &adblength);
#if 0
//Now test it, and log problems
adblength = sizeof(adbdata);
adbDevice->readRegister(1, adbdata, &adblength);
if((adbdata[6] != 0x0D))
{
IOLog("Gestures are not in mode 0x0D\n");
}
adblength = sizeof(adbdata);
adbdata[7] = 0; //sanity check
adbDevice->readRegister(2, adbdata, &adblength);
#endif
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("Use Panther Settings for W")))
{
_usePantherSettings = (bool) datan->unsigned32BitValue();
setProperty("Use Panther Settings for W", _usePantherSettings, sizeof(UInt32));
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("PalmNoAction Permanent")))
{
_palmnoaction = (bool) datan->unsigned32BitValue();
setProperty("PalmNoAction Permanent", _palmnoaction, sizeof(UInt32));
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("PalmNoAction When Typing")))
{
_palmnomove = (bool) datan->unsigned32BitValue();
setProperty("PalmNoAction When Typing", _palmnomove, sizeof(UInt32));
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("TwofingerNoAction")))
{
_2fingernoaction = (bool) datan->unsigned32BitValue();
setProperty("TwofingerNoAction", _2fingernoaction, sizeof(UInt32));
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("OutsidezoneNoAction Permanent")))
{
_zonenoaction = (bool) datan->unsigned32BitValue();
setProperty("OutsidezoneNoAction Permanent", _zonenoaction, sizeof(UInt32));
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("OutsidezoneNoAction When Typing")))
{
_zonenomove = (bool) datan->unsigned32BitValue();
setProperty("OutsidezoneNoAction When Typing", _zonenomove, sizeof(UInt32));
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("OutsidezoneNoAction When Pecking")))
{
_zonepecknomove = (bool) datan->unsigned32BitValue();
setProperty("OutsidezoneNoAction When Pecking", _zonepecknomove, sizeof(UInt32));
}
//FFScroll Modified
// Based on code found in iScroll2
if (datan = OSDynamicCast(OSNumber, dict->getObject(AppleUseTwoFingersToScrollKey))) // get the two finger scrolling key
{
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingEnabled=(bool) datan->unsigned8BitValue();
setProperty(AppleUseTwoFingersToScrollKey, datan->unsigned8BitValue(), sizeof(UInt8)*8); // this setting tells OSX that we have a trackpad capable of scrolling
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting Circular Scrolling to %d\n",(char)_trackpadprefs.twoFingerScrollingPrefs.circularScrollingEnabled) ;
#endif
}
if (datan = OSDynamicCast(OSNumber, dict->getObject(AppleAllowHorizontalScrollingKey))) // get the two finger scrolling key
{
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingEnabled=(bool) datan->unsigned8BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting Horizontal Scrolling to %d\n",(char)_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingEnabled) ;
#endif
setProperty(AppleAllowHorizontalScrollingKey, datan->unsigned8BitValue(), sizeof(UInt8)*8);
}
//End FFScroll
if (datan = OSDynamicCast(OSNumber, dict->getObject("USBMouseStopsTrackpad")))
{
UInt8 mode;
mode = datan->unsigned32BitValue();
setProperty("USBMouseStopsTrackpad", (unsigned long long)(mode), sizeof(mode)*8);
if (mode)
{
_ignoreTrackpadState |= kIgnoreTrackpadState_USBMouse;
}
else
{
_ignoreTrackpadState &= ~kIgnoreTrackpadState_USBMouse;
}
}
if (datan = OSDynamicCast(OSNumber, dict->getObject("MouseKeysStopsTrackpad")))
{
UInt8 mode;
mode = datan->unsigned32BitValue();
setProperty("MouseKeysStopsTrackpad", (unsigned long long)(mode), sizeof(mode)*8);
if (mode)
{
_ignoreTrackpadState |= kIgnoreTrackpadState_MouseKeys;
}
else
{
_ignoreTrackpadState &= ~kIgnoreTrackpadState_MouseKeys;
}
}
if (datan = OSDynamicCast(OSNumber, dict->getObject(kIOHIDMouseKeysOnKey)))
{
UInt8 mode;
mode = datan->unsigned32BitValue();
if (mode)
{
_ignoreTrackpadState |= kIgnoreTrackpadState_MouseKeys_State_On;
}
else
{
_ignoreTrackpadState &= ~kIgnoreTrackpadState_MouseKeys_State_On;
}
}
// =========================
// END READING APPLE PREFS
// =========================
// ============================
// BEGIN READING FFSCROLL PREFS
// ============================
// FFScroll Modified
if (dictionary = OSDynamicCast(OSDictionary, dict->getObject(FFScrollDictionaryKey))) // if we can find the FFScroll Dictionary
{
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Opened the FFScroll Dictionary\n") ;
#endif
// ---------------------------
// BEGIN READING GENERAL PREFS
// ---------------------------
// Min time finger can stay on trackpad for it to be considered a tap
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(minTapDurationKey)))
{
_trackpadprefs.minTapDuration = datan->unsigned64BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting minTapDuration to %lld\n", _trackpadprefs.minTapDuration) ;
#endif
}
// Max time finger can stay on trackpad for it to be considered a tap
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(maxTapDurationKey)))
{
_trackpadprefs.maxTapDuration = datan->unsigned64BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting maxTapDuration to %lld\n",_trackpadprefs.maxTapDuration) ;
#endif
}
// max time between a tap and a finger down for it to start a drag event
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(minTapDragTimeKey)))
{
_trackpadprefs.minTapDragTime = datan->unsigned64BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting minTapDragTime to %lld\n",_trackpadprefs.minTapDragTime) ;
#endif
}
// max time between a tap and a finger down for it to start a drag event
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(maxTapDragTimeKey)))
{
_trackpadprefs.maxTapDragTime = datan->unsigned64BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting maxTapDragTime to %lld\n",_trackpadprefs.maxTapDragTime) ;
#endif
}
// max time finger can leave trackpad before drag event ends
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(maxTapDragRevTimeKey)))
{
_trackpadprefs.maxTapDragRevTime = datan->unsigned64BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting maxTapDragRev to %lld\n",_trackpadprefs.maxTapDragRevTime) ;
#endif
}
// time finger must spend on pad after starting a drag for it to be considered one
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(minDragAssumedTimeKey)))
{
_trackpadprefs.minDragAssumedTime = datan->unsigned64BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting minDragAssumedTime to %lld\n", _trackpadprefs.minDragAssumedTime) ;
#endif
}
// Physical Button Drag Action
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(physicalButtonDragActionKey)))
{
//TODO ADD SOME RANGE CHECKING
_trackpadprefs.physicalButtonDragAction = 1<<(datan->unsigned32BitValue()-1);
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting physicalButtonDragAction to %d\n",_trackpadprefs.physicalButtonDragAction) ;
#endif
}
// //Button maintains tap drag being set
// if (datab = OSDynamicCast(OSBoolean, dictionary->getObject(buttonMaintainsDragKey)))
// {
// _trackpadprefs.buttonMaintainsDrag = datab->isTrue();
// setProperty(buttonMaintainsDragKey, _trackpadprefs.buttonMaintainsDrag, sizeof(UInt32));
//#ifdef FFSPREFSDEBUG
// IOLog("FFScroll: Setting buttonMaintainsDrag to %d\n",(char)_trackpadprefs.buttonMaintainsDrag) ;
//#endif
// }
// Double Tap Tolerance
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(doubleTapToleranceKey)))
{
_trackpadprefs.doubleTapTolerance = datan->unsigned32BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting doubleTapTolerance to %d\n", _trackpadprefs.doubleTapTolerance);
#endif
}
// Tap Tolerance
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(tapToleranceKey)))
{
_trackpadprefs.tapTolerance = datan->unsigned32BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting tapTolerance to %d\n", _trackpadprefs.tapTolerance);
#endif
}
// Physical Button Action
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(physicalButtonActionKey)))
{
//TODO ADD SOME RANGE CHECKING
_trackpadprefs.physicalButtonAction = 1<<(datan->unsigned32BitValue()-1);
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting physicalButtonAction to %d\n",_trackpadprefs.physicalButtonAction) ;
#endif
}
//Minimum possible X value with finger on pad
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(minXKey))) //
{
_trackpadprefs.minX = datan->unsigned16BitValue();
setProperty(minXKey,_trackpadprefs.minX,16);
//setProperty(minXKey, _trackpadprefs.buttonMaintainsDrag, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting minX to %d\n",_trackpadprefs.minX) ;
#endif
}
//Minimum possible Y value with finger on pad
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(minYKey))) //
{
_trackpadprefs.minY = datan->unsigned16BitValue();
setProperty(minYKey,_trackpadprefs.minY,16);
//setProperty(minYKey, _trackpadprefs.buttonMaintainsDrag, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting minY to %d\n",_trackpadprefs.minY) ;
#endif
}
//Maximum possible X value with finger on pad
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(maxXKey))) //
{
_trackpadprefs.maxX = datan->unsigned16BitValue();
setProperty(maxXKey,_trackpadprefs.maxX,16);
//setProperty(maxXKey, _trackpadprefs.buttonMaintainsDrag, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting maxX to %d\n",_trackpadprefs.maxX) ;
#endif
}
//Maximum possible Y value with finger on pad
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(maxYKey))) //
{
_trackpadprefs.maxY = datan->unsigned16BitValue();
setProperty(maxYKey,_trackpadprefs.maxY,16);
//setProperty(maxXKey, _trackpadprefs.buttonMaintainsDrag, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting maxY to %d\n",_trackpadprefs.maxY) ;
#endif
}
//Test if we scale the speed of trackpad movement
if (datab = OSDynamicCast(OSBoolean, dictionary->getObject(scaleTrackpadSpeedKey)))
{
_trackpadprefs.scaleTrackpadSpeed = datab->isTrue();
//setProperty(scaleTrackpadSpeed, _trackpadprefs.scaleTrackpadSpeed, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scaleTrackpadSpeed to %d\n",(char)_trackpadprefs.scaleTrackpadSpeed) ;
#endif
}
//Get scaling of trackpad speed
if (datan = OSDynamicCast(OSNumber, dictionary->getObject(speedScaleKey))) //
{
_trackpadprefs.speedScale = datan->unsigned16BitValue();
//setProperty(minXKey, _trackpadprefs.buttonMaintainsDrag, sizeof(UInt32));
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting speedScale to %d\n",_trackpadprefs.speedScale) ;
#endif
}
// -------------------------
// END READING GENERAL PREFS
// -------------------------
// ----------------------
// BEGIN READING 2F PREFS
// ----------------------
if(datad = OSDynamicCast(OSDictionary, dictionary->getObject(twoFingerScrollingPrefsKey)))
{
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Opened the dictionary\n");
#endif
// sets the size of the zArray
if (datan = OSDynamicCast(OSNumber, datad->getObject(zArraySizeKey)))
{
int tmp = datan->unsigned32BitValue();
if(tmp != _trackpadprefs.twoFingerScrollingPrefs.zArraySize) // Dont waste time reallocating the zArray if the size is the same
{
//Not only do we need to set the zArraySize but we also need to replace the zArray
_trackpadprefs.twoFingerScrollingPrefs.zArraySize = tmp;
delete _trackpaddata.zArray;
_trackpaddata.zArray =new SInt16[_trackpadprefs.twoFingerScrollingPrefs.zArraySize];
_trackpaddata.zArrayCurrent = 0;
_trackpaddata.zArrayFilled = false;
}
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Setting zArraySize to %d\n",_trackpadprefs.twoFingerScrollingPrefs.zArraySize) ;
#endif
}
//sets the value at which we count z axis data as indicating a two finger event
if (datan = OSDynamicCast(OSNumber, datad->getObject(zAcceptThresholdKey))) //
{
_trackpadprefs.twoFingerScrollingPrefs.zAcceptThreshold = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Setting zAcceptThreshold to %d\n",_trackpadprefs.twoFingerScrollingPrefs.zAcceptThreshold) ;
#endif
}
//sets the value at which we count z axis data as indicating a single finger event
if (datan = OSDynamicCast(OSNumber, datad->getObject(zDeclineThresholdKey)))
{
_trackpadprefs.twoFingerScrollingPrefs.zDeclineThreshold = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Setting zDeclineThreshold to %d\n",_trackpadprefs.twoFingerScrollingPrefs.zDeclineThreshold) ;
#endif
}
//sets the number of samples considered two finger events before we engage two finger mode
if (datan = OSDynamicCast(OSNumber, datad->getObject(stickTwoFingerStartKey)))
{
_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStart = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Setting stickTwoFingerStart to %d\n",_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStart) ;
#endif
}
//sets the number of samples considered single finger events before we stop two finger mode
if (datan = OSDynamicCast(OSNumber, datad->getObject(stickTwoFingerStopKey)))
{
_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStop = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Setting stickTwoFingerStop to %d\n",_trackpadprefs.twoFingerScrollingPrefs.stickTwoFingerStop) ;
#endif
}
// dominant axis only
if (datab = OSDynamicCast(OSBoolean,datad->getObject(scrollDominantOnlyKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.scrollDominantOnly = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Circular Scrolling: scrollDominantOnly = %s\n", result?"true":"false");
#endif
}
// read prefs for 2f circular scrolling
if (datab = OSDynamicCast(OSBoolean,datad->getObject(circularScrollingEnabledKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingEnabled = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Circular Scrolling: Enabled = %s\n", result?"true":"false");
#endif
}
if (datab = OSDynamicCast(OSBoolean,datad->getObject(circularScrollingInvertKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.invertCircularScrolling = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Circular Scrolling: Inverted is %s\n", result?"true":"false");
#endif
}
if (datan = OSDynamicCast(OSNumber, datad->getObject(circularScrollingRateKey)))
{
int result = datan->unsigned32BitValue();
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingRate = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Circular Scrolling: Rate is %d\n", result);
#endif
}
if (datan = OSDynamicCast(OSNumber, datad->getObject(circularScrollingThresholdKey)))
{
int result = datan->unsigned32BitValue();
_trackpadprefs.twoFingerScrollingPrefs.circularScrollingThreshold = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Circular Scrolling: circularScrollingThreshold is %d\n", result);
#endif
}
// read prefs for 2f vertical scrolling
if (datab = OSDynamicCast(OSBoolean,datad->getObject(verticalScrollingEnabledKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingEnabled = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Vertical Scrolling: Enabled = %s\n", result?"true":"false");
#endif
}
if (datab = OSDynamicCast(OSBoolean,datad->getObject(verticalScrollingInvertKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.invertVerticalScrolling = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Vertical Scrolling: Inverted is %s\n", result?"true":"false");
#endif
}
if (datan = OSDynamicCast(OSNumber, datad->getObject(verticalScrollingRateKey)))
{
int result = datan->unsigned32BitValue();
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingRate = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Vertical Scrolling: Rate is %d\n", result);
#endif
}
if (datan = OSDynamicCast(OSNumber, datad->getObject(verticalScrollingThresholdKey)))
{
int result = datan->unsigned32BitValue();
_trackpadprefs.twoFingerScrollingPrefs.verticalScrollingThreshold = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Vertical Scrolling: verticalScrollingThreshold is %d\n", result);
#endif
}
// read prefs for 2f horizontal scrolling
if (datab = OSDynamicCast(OSBoolean,datad->getObject(horizontalScrollingEnabledKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingEnabled = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Horizontal Scrolling: Enabled = %s\n", result?"true":"false");
#endif
}
if (datab = OSDynamicCast(OSBoolean,datad->getObject(horizontalScrollingInvertKey)))
{
bool result = datab->isTrue();
_trackpadprefs.twoFingerScrollingPrefs.invertHorizontalScrolling = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Horizontal Scrolling: Inverted is %s\n", result?"true":"false");
#endif
}
if (datan = OSDynamicCast(OSNumber, datad->getObject(horizontalScrollingRateKey)))
{
int result = datan->unsigned32BitValue();
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingRate = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Horizontal Scrolling: Rate is %d\n", result);
#endif
}
if (datan = OSDynamicCast(OSNumber, datad->getObject(horizontalScrollingThresholdKey)))
{
int result = datan->unsigned32BitValue();
_trackpadprefs.twoFingerScrollingPrefs.horizontalScrollingThreshold = result;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: 2F: Horizontal Scrolling: horizontalScrollingThreshold is %d\n", result);
#endif
}
}
// --------------------
// END READING 2F PREFS
// --------------------
// --------------
// BEGIN HOTSPOTS
// --------------
// Test if we have hotspots enabled
if (datab = OSDynamicCast(OSBoolean, dictionary->getObject(hasHotspotsKey)))
{
_trackpadprefs.hasHotspots = datab->isTrue();
_trackpadprefs.numberOfHotspots = 0;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting hasHotspots to %d\n", (char)_trackpadprefs.hasHotspots) ;
#endif
}
// Code to read scrollAreas Array in
if (dataa = OSDynamicCast(OSArray, dictionary->getObject(hotspotsArrayKey)))
{
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Opened Hotspots Array\n") ;
#endif
_trackpadprefs.numberOfHotspots = dataa->getCount(); // determine number of hotspots by the size of the array
delete _trackpadprefs.Hotspots; // remove old hotspots array
_trackpadprefs.Hotspots = new ACTIONHOTSPOT[_trackpadprefs.numberOfHotspots]; // assign new hotspots array
bool success = true; // variable to track for problems reading hotspots
for(int i=0; i<_trackpadprefs.numberOfHotspots; i++)
{
if(datad = OSDynamicCast(OSDictionary, dataa->getObject(i)))
{
// read in the type of the hotspot
if(datan = OSDynamicCast(OSNumber, datad->getObject(typeKey)))
{
_trackpadprefs.Hotspots[i].type = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting Hotspot %d type to %s\n", i,
(_trackpadprefs.Hotspots[i].type == 0)? "absolute":"relative");
#endif
}
else
success = false;
COORD tmpcoord;
// read in coordinates of the area
if(datan = OSDynamicCast(OSNumber, datad->getObject(x0Key)))
tmpcoord.x0 = datan->unsigned16BitValue();
else
success = false;
if(datan = OSDynamicCast(OSNumber, datad->getObject(x1Key)))
tmpcoord.x1 = datan->unsigned16BitValue();
else
success = false;
if(datan = OSDynamicCast(OSNumber, datad->getObject(y0Key)))
tmpcoord.y0 = datan->unsigned16BitValue();
else
success = false;
if(datan = OSDynamicCast(OSNumber, datad->getObject(y1Key)))
tmpcoord.y1 = datan->unsigned16BitValue();
else
success = false;
switch(_trackpadprefs.Hotspots[i].type)
{
case 0:
_trackpadprefs.Hotspots[i].coordAbs = tmpcoord;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Assigning Hotspot %d absolute coords as (%d, %d, %d, %d)\n",
i, tmpcoord.x0, tmpcoord.x1, tmpcoord.y0, tmpcoord.y1);
#endif
break;
case 1:
_trackpadprefs.Hotspots[i].coordRel = tmpcoord;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Assigning Hotspot %d relative coords as (%d, %d, %d, %d)\n",
i, tmpcoord.x0, tmpcoord.x1, tmpcoord.y0, tmpcoord.y1);
#endif
break;
case 2:
_trackpadprefs.Hotspots[i].coordRel = tmpcoord;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Assigning Hotspot %d fully relative coords as (%d, %d, %d, %d)\n",
i, tmpcoord.x0, tmpcoord.x1, tmpcoord.y0, tmpcoord.y1);
#endif
break;
default:
success = false;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Unknown type was read for Hotspot %d\n", i);
#endif
break;
}
// read in the direction of the scroll area
if(datan = OSDynamicCast(OSNumber, datad->getObject(buttonKey)))
{
_trackpadprefs.Hotspots[i].button = 1 << (datan->unsigned16BitValue() - 1);
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting Hotspot %d button to %d\n", i, _trackpadprefs.Hotspots[i].button);
#endif
}
else
success = false;
}
else
success = false;
}
if(!success) // if an error has occured set it so we don't use the hotspots (add a log entry later possibly with an error message)
{
_trackpadprefs.hasScrollAreas = false;
_trackpadprefs.numberOfScrollAreas = 0;
}
}
// ------------
// END HOTSPOTS
// ------------
// ------------------
// BEGIN SCROLL AREAS
// ------------------
// Test if we have scroll areas enabled
if (datab = OSDynamicCast(OSBoolean, dictionary->getObject(hasScrollAreasKey)))
{
_trackpadprefs.hasScrollAreas = datab->isTrue();
_trackpadprefs.numberOfScrollAreas = 0;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting hasScrollAreas to %d\n",(char)_trackpadprefs.hasScrollAreas) ;
#endif
}
// Code to read scrollAreas Array in
if (dataa = OSDynamicCast(OSArray, dictionary->getObject(scrollAreasArrayKey)))
{
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Opened ScrollAreas Array\n") ;
#endif
_trackpadprefs.numberOfScrollAreas = dataa->getCount(); // determine number of hotspots by the size of the array
delete _trackpadprefs.ScrollAreas; // remove old hotspots array
_trackpadprefs.ScrollAreas = new SCROLLHOTSPOT[_trackpadprefs.numberOfScrollAreas]; // assign new hotspots array
bool success = true; // variable to track for problems reading hotspots
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: There will be %d scroll areas\n", _trackpadprefs.numberOfScrollAreas);
#endif
for(int i=0; i<_trackpadprefs.numberOfScrollAreas; i++)
{
if(datad = OSDynamicCast(OSDictionary, dataa->getObject(i)))
{
// read in the type of the scroll area
if(datan = OSDynamicCast(OSNumber, datad->getObject(typeKey)))
{
_trackpadprefs.ScrollAreas[i].type = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d type to %s\n", i,
(_trackpadprefs.ScrollAreas[i].type == 0)? "absolute":"relative");
#endif
}
else
success = false;
COORD tmpcoord;
// read in coordinates of the area
if(datan = OSDynamicCast(OSNumber, datad->getObject(x0Key)))
tmpcoord.x0 = datan->unsigned16BitValue();
else
success = false;
if(datan = OSDynamicCast(OSNumber, datad->getObject(x1Key)))
tmpcoord.x1 = datan->unsigned16BitValue();
else
success = false;
if(datan = OSDynamicCast(OSNumber, datad->getObject(y0Key)))
tmpcoord.y0 = datan->unsigned16BitValue();
else
success = false;
if(datan = OSDynamicCast(OSNumber, datad->getObject(y1Key)))
tmpcoord.y1 = datan->unsigned16BitValue();
else
success = false;
switch(_trackpadprefs.ScrollAreas[i].type)
{
case 0:
_trackpadprefs.ScrollAreas[i].coordAbs = tmpcoord;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Assigning scrollArea %d absolute coords as (%d, %d, %d, %d)\n",
i, tmpcoord.x0, tmpcoord.x1, tmpcoord.y0, tmpcoord.y1);
#endif
break;
case 1:
_trackpadprefs.ScrollAreas[i].coordRel = tmpcoord;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Assigning scrollArea %d relative coords as (%d, %d, %d, %d)\n",
i, tmpcoord.x0, tmpcoord.x1, tmpcoord.y0, tmpcoord.y1);
#endif
break;
case 2:
_trackpadprefs.ScrollAreas[i].coordRel = tmpcoord;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Assigning scrollArea %d fully relative coords as (%d, %d, %d, %d)\n",
i, tmpcoord.x0, tmpcoord.x1, tmpcoord.y0, tmpcoord.y1);
#endif
break;
default:
success = false;
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Unknown type was read for scrollArea %d\n", i);
#endif
break;
}
// read in the if the scroll area is inverted
if(datab = OSDynamicCast(OSBoolean, datad->getObject(invertKey)))
{
_trackpadprefs.ScrollAreas[i].invert = datab->isTrue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d invert to %s\n", i,
_trackpadprefs.ScrollAreas[i].invert? "true":"false");
#endif
}
else
success = false;
// read in the direction of the scroll area
if(datan = OSDynamicCast(OSNumber, datad->getObject(directionKey)))
{
_trackpadprefs.ScrollAreas[i].direction = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d direction to %s\n", i,
(_trackpadprefs.ScrollAreas[i].direction == 0)? "vertical":
(_trackpadprefs.ScrollAreas[i].direction == 1)? "horizontal":
"both");
#endif
}
else
success = false;
// read in the if we should scroll outside the area
if(datab = OSDynamicCast(OSBoolean, datad->getObject(scrollOutsideAreaKey)))
{
_trackpadprefs.ScrollAreas[i].scrollOutsideArea = datab->isTrue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d scrollOutsideArea to %s\n", i,
_trackpadprefs.ScrollAreas[i].scrollOutsideArea? "true":"false");
#endif
}
else
success = false;
// read in the if we should scroll outside the area
if(datab = OSDynamicCast(OSBoolean, datad->getObject(scaleSpeedKey)))
{
_trackpadprefs.ScrollAreas[i].scaleSpeed = datab->isTrue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d scaleSpeed to %s\n", i,
_trackpadprefs.ScrollAreas[i].scaleSpeed? "true":"false");
#endif
}
else
success = false;
// read in the amount we should scale the speed by
if(datan = OSDynamicCast(OSNumber, datad->getObject(speedScaleKey)))
{
_trackpadprefs.ScrollAreas[i].speedScale = datan->unsigned16BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d speedScale to %d\n", i,
_trackpadprefs.ScrollAreas[i].speedScale);
#endif
}
else
success = false;
// read in the autoscroll mode
if(datan = OSDynamicCast(OSNumber, datad->getObject(autoScrollModeKey)))
{
_trackpadprefs.ScrollAreas[i].autoScrollMode = datan->unsigned32BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting %d Auto Scrolling Mode to %d\n", i,
_trackpadprefs.ScrollAreas[i].autoScrollMode);
#endif
}
else
success = false;
// read in the autoscrolling rate
if(datan = OSDynamicCast(OSNumber, datad->getObject(autoScrollRateKey)))
{
_trackpadprefs.ScrollAreas[i].autoScrollRate = datan->unsigned32BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting %d Auto Scrolling Rate to %d\n", i,
_trackpadprefs.ScrollAreas[i].autoScrollRate);
#endif
}
else
success = false;
// read in the size of the autoscrolling caps
if(datan = OSDynamicCast(OSNumber, datad->getObject(autoScrollCapKey)))
{
_trackpadprefs.ScrollAreas[i].autoScrollCap = datan->unsigned32BitValue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting scrollArea %d continue Scrolling Cap to %d\n", i,
_trackpadprefs.ScrollAreas[i].autoScrollCap);
#endif
}
else
success = false;
}
else
success = false;
}
if(!success) // if an error has occured set it so we don't use the hotspots (add a log entry later possibly with an error message)
{
_trackpadprefs.hasScrollAreas = false;
_trackpadprefs.numberOfScrollAreas = 0;
}
}
if(_trackpadprefs.hasScrollAreas || _trackpadprefs.hasHotspots)
{
generateAbsoluteHotspots();
}
// ----------------
// END SCROLL AREAS
// ----------------
// ------------------
// BEGIN CALIBRATION
// ------------------
if (datab = OSDynamicCast(OSBoolean, dictionary->getObject(calibrateModeKey)))
{
_trackpadprefs.calibrateMode = datab->isTrue();
#ifdef FFSPREFSDEBUG
IOLog("FFScroll: Setting calibrationMode %s\n", _trackpadprefs.calibrateMode?"on":"off");
#endif
}
// ----------------
// END CALIBRATION
// ----------------
}
// ==========================
// END READING FFSCROLL PREFS
// ==========================
IOLockUnlock( _mouseLock);
} // end of typeTrackpad
#ifdef FFSDEBUG
// For debugging purposes
adblength = 8;
adbDevice->readRegister(2, adbdata, &adblength);
IOLog("adbdata[0] = 0x%x\n", adbdata[0]);
IOLog("adbdata[1] = 0x%x\n", adbdata[1]);
IOLog("adbdata[2] = 0x%x\n", adbdata[2]);
IOLog("adbdata[3] = 0x%x\n", adbdata[3]);
IOLog("adbdata[4] = 0x%x\n", adbdata[4]);
IOLog("adbdata[5] = 0x%x\n", adbdata[5]);
IOLog("adbdata[6] = 0x%x\n", adbdata[6]);
IOLog("adbdata[7] = 0x%x\n", adbdata[7]);
#endif
if (err == kIOReturnSuccess)
{
return super::setParamProperties(dict);
}
IOLog("FFScroll::setParamProperties failing here\n");
return( err );
}