Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

Proof-of-concept code to add pinch gestures to Magic Mouse Other Hardware
I wrote some proof-of-concept code that allows you to use the Apple Magic Mouse to zoom in/out in the frontmost application with pinch gestures. I've detailed the process of how I got this working in this entry on my blog, including some compilable source code that implements pinch for zoom in/out (in Preview, for instance).

[robg adds: The referenced blog post walks is quite technical, and the end result is some source code that can be compiled to add pinch gesture functionality to the Magic Mouse (you'll need Xcode installed to compile it). As this is a very technical hint, I've chosen to simply link to the blog post instead of recreating it here in full. However, in case the blog ever vanishes, I have recreated the source code in the body of this hint -- but check the blog post first for updated versions.]

#include <unistd.h>
#import <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
#include <ApplicationServices/ApplicationServices.h>

/*
Costantino Pistagna <valvoline -at- gmail -dot- com>

This code will read raw input from all multi-touch devices attached to chain deviceList.
Either if you're dealing with a trackpad or magic mouse, you'll get the raw multi-touch taps.

touchCallback function uses the nFinger parameter to detect a multitouch event. We don't want to
detect the one finger gestures.

If you don't want to handle a gesture, just return null from the callback function.

Compile with:

gcc -o main main.m -F/System/Library/PrivateFrameworks -framework MultitouchSupport -lIOKit \
-framework CoreFoundation -framework ApplicationServices -lobjc

If you make something usefull with this proof of concept, notify me, and i'll wrote some lines
on my page at: http://aladino.dmi.unict.it

*/



/*
These structs are required, in order to handle some parameters returned from the
MultiTouchSupport.framework
*/
typedef struct {
float x;
float y;
}mtPoint;

typedef struct {
mtPoint position;
mtPoint velocity;
}mtReadout;

/*
Some reversed engineered informations from MultiTouchSupport.framework
*/
typedef struct
{
int frame; //the current frame
double timestamp; //event timestamp
int identifier; //identifier guaranteed unique for life of touch per device
int state; //the current state (not sure what the values mean)
int unknown1; //no idea what this does
int unknown2; //no idea what this does either
mtReadout normalized; //the normalized position and vector of the touch (0,0 to 1,1)
float size; //the size of the touch (the area of your finger being tracked)
int unknown3; //no idea what this does
float angle; //the angle of the touch -|
float majorAxis; //the major axis of the touch -|-- an ellipsoid. you can track the angle of each finger!
float minorAxis; //the minor axis of the touch -|
mtReadout unknown4; //not sure what this is for
int unknown5[2]; //no clue
float unknown6; //no clue
}Touch;

//a reference pointer for the multitouch device
typedef void *MTDeviceRef;

//the prototype for the callback function
typedef int (*MTContactCallbackFunction)(int,Touch*,int,double,int);

//returns a pointer to the default device (the trackpad?)
MTDeviceRef MTDeviceCreateDefault();

//returns a CFMutableArrayRef array of all multitouch devices
CFMutableArrayRef MTDeviceCreateList(void);

//registers a device's frame callback to your callback function
void MTRegisterContactFrameCallback(MTDeviceRef, MTContactCallbackFunction);

//start sending events
void MTDeviceStart(MTDeviceRef, int);

//just output debug info. use it to see all the raw infos dumped to screen
void printDebugInfos(int nFingers, Touch *data) {
int i;
for (i=0; i<nFingers; i++) {
Touch *f = &data[i];
printf("Finger: %d, frame: %d, timestamp: %f, ID: %d, state: %d, PosX: %f, PosY: %f, VelX: %f, VelY: %f, Angle: %f, MajorAxis: %f, MinorAxis: %f\n", i,
f->frame,
f->timestamp,
f->identifier,
f->state,
f->normalized.position.x,
f->normalized.position.y,
f->normalized.velocity.x,
f->normalized.velocity.y,
f->angle,
f->majorAxis,
f->minorAxis);
}
}

//this's a simple touchCallBack routine. handle your events here
int touchCallback(int device, Touch *data, int nFingers, double timestamp, int frame) {
int i;
if(nFingers>=2) { //only report if two or more fingers are touching
//printf("Device: %d ",device);
//printDebugInfos(nFingers, data);

//use two different Touch pointers for the two fingers gestures
Touch *f1 = &data[0]; //first finger
Touch *f2 = &data[1]; //second finger

//compute the euclide distance between the two touches
float distAB = sqrt(((f1->normalized.position.x - f2->normalized.position.x) * \
(f1->normalized.position.x - f2->normalized.position.x) + \
(f1->normalized.position.y - f2->normalized.position.y) * \
(f1->normalized.position.y - f2->normalized.position.y)));

//if we pinch-in (zoom-in)
if(distAB > 0.40 && distAB < 0.41) {
printf("pinch-in detected\n");
/*
CGEventPost(kCGHIDEventTap, CGEventCreateKeyboardEvent (NULL, (CGKeyCode)55, true));
CGEventPost(kCGHIDEventTap, CGEventCreateKeyboardEvent (NULL, (CGKeyCode)69, true));
CGEventPost(kCGHIDEventTap, CGEventCreateKeyboardEvent (NULL, (CGKeyCode)69, false));
CGEventPost(kCGHIDEventTap, CGEventCreateKeyboardEvent (NULL, (CGKeyCode)55, false));
*/
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, true); // command (hit)
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)69, true); // + (hit)
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)69, false); // + (out)
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, false); // command (out)
} else if(distAB < 0.80 && distAB > 0.79) { //if we pinch-out (zoom-out)
printf("pinch-out detected\n");
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, true); // command (hit)
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)78, true); // command (hit)
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)78, false); // command (hit)
CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, false); // command (hit)
}
}
return 0;
}

int main(void) {
int i;
NSMutableArray* deviceList = (NSMutableArray*)MTDeviceCreateList(); //grab our device list
for(i = 0; i<[deviceList count]; i++) { //iterate available devices
MTRegisterContactFrameCallback([deviceList objectAtIndex:i], touchCallback); //assign callback for device
MTDeviceStart([deviceList objectAtIndex:i], 0); //start sending events
}
printf("Ctrl-C to abort\n");
sleep(-1);
return 0;
} 
    •    
  • Currently 3.05 / 5
  You rated: 3 / 5 (19 votes cast)
 
[8,809 views]  

Proof-of-concept code to add pinch gestures to Magic Mouse | 3 comments | Create New Account
Click here to return to the 'Proof-of-concept code to add pinch gestures to Magic Mouse' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
Proof-of-concept code to add pinch gestures to Magic Mouse
Authored by: smilec on Nov 24, '09 01:12:57AM
Nice hack and very promising for the next OS update. I can't get it to compile, though, on 10.6.2: /System/Library/Frameworks/CoreFoundation.framework/Headers/CFBundle.h:147:1: error: format string argument not a string type /System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:131:83: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:87:42: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSArray.h:91:41: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSCache.h:43:1: error: stray '@' in program /System/Library/Frameworks/Foundation.framework/Headers/NSCache.h:44:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '-' token /System/Library/Frameworks/Foundation.framework/Headers/NSCoder.h:83:35: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSCoder.h:91:22: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSConnection.h:114:1: error: stray '@' in program /System/Library/Frameworks/Foundation.framework/Headers/NSConnection.h:118:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before '-' token /System/Library/Frameworks/Foundation.framework/Headers/NSConnection.h:50:37: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSDate.h:27:47: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSDictionary.h:56:57: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSDictionary.h:61:51: error: expected ';' before '__attribute__' /System/Library/Frameworks/Foundation.framework/Headers/NSException.h:61:63: error: expected ';' before '__attribute__'

[ Reply to This | # ]
Proof-of-concept code to add pinch gestures to Magic Mouse
Authored by: bpabbott on Nov 29, '09 04:36:38PM
@smilec The error you've encountered ...
/System/Library/Frameworks/CoreFoundation.framework/Headers/CFBundle.h:147:1: error: format string argument not a string type
is one I've encountered when building the gcc-4.4. Switching to gcc-4.2 resolves it.

[ Reply to This | # ]
Proof-of-concept code to add pinch gestures to Magic Mouse
Authored by: bsb@mac.com on Dec 19, '09 06:36:10AM

Rob - there is a NICE solution out there for this, called BetterTouchTool ... http://blog.boastr.net/ this guy has done an absolutely fantastic job of exposing multi-touch capabilities on the Magic Mouse. Frankly, I was sorely disappointed in the Magic Mouse until I found this app.
My favorites:
- tap to click (very intuitive!)
- three & four finger swipes (for duplicating my MBP mutlti-touch trackpad expose gestures)

---
--
bsb



[ Reply to This | # ]