From 3b905ff65c2d8f42903a61dac42b7fbfcc2fc11e Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 2 Jan 2013 15:41:29 -0500 Subject: [PATCH] Added Matlab/Octave bindings, thanks to Thomas Weibel. --- README.txt | 11 +++ contrib/matlab/ManyMouse.m | 33 +++++++ contrib/matlab/compile_manymouse_mex.m | 40 ++++++++ contrib/matlab/demo_class.m | 25 +++++ contrib/matlab/demo_mex.m | 24 +++++ contrib/matlab/manymouse_mex.cpp | 125 +++++++++++++++++++++++++ 6 files changed, 258 insertions(+) create mode 100755 contrib/matlab/ManyMouse.m create mode 100755 contrib/matlab/compile_manymouse_mex.m create mode 100755 contrib/matlab/demo_class.m create mode 100755 contrib/matlab/demo_mex.m create mode 100755 contrib/matlab/manymouse_mex.cpp diff --git a/README.txt b/README.txt index d7025ec..0aeb198 100644 --- a/README.txt +++ b/README.txt @@ -102,6 +102,17 @@ Java bindings: gave me the rundown on getting this to work with Cygwin. +Matlab/Octave bindings: + There's a little Matlab/Octave wrapper in contrib/matlab. It can be compiled + using the function "compile_manymouse_mex.m". Tested under Windows 7 + (Matlab 2010b) and Ubuntu 12.04 (Octave 3.2.4 and Matlab 2011a). + + Demo scripts for Octave compatible function call ('demo_mex.m') as well as + Matlab's class Interface ('ManyMouse.m', 'demo_class.m') are also included. + + Thanks to Thomas Weibel for the Matlab work. + + Some general ManyMouse usage notes: - If a mouse is disconnected, it will not return future events, even if you plug it right back in. You will be alerted of disconnects programmatically diff --git a/contrib/matlab/ManyMouse.m b/contrib/matlab/ManyMouse.m new file mode 100755 index 0000000..385cf0c --- /dev/null +++ b/contrib/matlab/ManyMouse.m @@ -0,0 +1,33 @@ +classdef ManyMouse + + properties + end + + methods (Static) + + + function availableMice = init( ) + availableMice = manymouse_mex( 'ManyMouse_Init' ); + end + + function quit( ) + manymouse_mex( 'ManyMouse_Quit' ); + end + + function sDriverName = driverName( ) + sDriverName = manymouse_mex( 'ManyMouse_DriverName' ); + end + + function sDeviceNames = deviceName( ) + sDeviceNames = manymouse_mex( 'ManyMouse_DeviceName' ); + end + + function event = pollEvent( ) + event = manymouse_mex( 'ManyMouse_PollEvent' ); + end + + + end + +end + diff --git a/contrib/matlab/compile_manymouse_mex.m b/contrib/matlab/compile_manymouse_mex.m new file mode 100755 index 0000000..6622b81 --- /dev/null +++ b/contrib/matlab/compile_manymouse_mex.m @@ -0,0 +1,40 @@ +function compile_manymouse_mex + + if isOctave() + + % The file 'mkoctfile' (/usr/bin/mkoctfile on Ubuntu 12.04) should have these flags added to CXXFLAGS: + % -std=c++0x -fpermissive -fPIC -DNDEBUG + % While Matlab allows to add these flags when calling mex() (see below) , Octave doesn't ... + mex( '-I../..', '-lX11', '-ldl', ... + 'manymouse_mex.cpp', ... + '../../manymouse.c', ... + '../../linux_evdev.c', ... + '../../macosx_hidmanager.c', ... + '../../macosx_hidutilities.c', ... + '../../windows_wminput.c', ... + '../../x11_xinput2.c' ); + + else + mex( '-I../..', '-lX11', '-ldl', 'CXXFLAGS=$CXXFLAGS -std=c++0x -fpermissive -fPIC -DNDEBUG', ... + 'manymouse_mex.cpp', ... + '../../manymouse.c', ... + '../../linux_evdev.c', ... + '../../macosx_hidmanager.c', ... + '../../macosx_hidutilities.c', ... + '../../windows_wminput.c', ... + '../../x11_xinput2.c' ); + end + +end + + +function isOct = isOctave() + v = ver; + ret = strcmpi(v(1).Name,'Octave'); + if ret + isOct = true; + else + isOct = false; + end +end + diff --git a/contrib/matlab/demo_class.m b/contrib/matlab/demo_class.m new file mode 100755 index 0000000..5ec4d7e --- /dev/null +++ b/contrib/matlab/demo_class.m @@ -0,0 +1,25 @@ +%% Example for Matlab's class interface + +% Demo script for the Matlab/Octave MEX wrapper for ManyMouse. +% Please see the file LICENSE.txt in the source's root directory. +% Thomas Weibel, 2012/12/20 + + +clear all +mm = ManyMouse(); + +availableMice = mm.init() +driverName = mm.driverName() +deviceNames = mm.deviceName() + +i = 0; +while i < 100 + event = mm.pollEvent(); + if ~ strcmp( event.event, 'MANYMOUSE_NO_EVENT' ) + disp( event ); i = i+1; + end +end +% If this isn't called on Windows before calling 'ManyMouse_Init' again, +% only restarting Matlab will make it work again. So always call +% 'ManyMouse_Quit' on Windows ... +mm.quit(); diff --git a/contrib/matlab/demo_mex.m b/contrib/matlab/demo_mex.m new file mode 100755 index 0000000..214547c --- /dev/null +++ b/contrib/matlab/demo_mex.m @@ -0,0 +1,24 @@ +%% Example for mex function call. Should work both in Octave and Matlab. + +% Demo script for the Matlab/Octave MEX wrapper for ManyMouse. +% Please see the file LICENSE.txt in the source's root directory. +% Thomas Weibel, 2012/12/20 + +clear all +more off; + +availableMice = manymouse_mex( 'ManyMouse_Init' ) +driverName = manymouse_mex( 'ManyMouse_DriverName' ) +deviceNames = manymouse_mex( 'ManyMouse_DeviceName' ) + +i = 0; +while i < 100 + event = manymouse_mex( 'ManyMouse_PollEvent' ); + if ~ strcmp( event.event, 'MANYMOUSE_NO_EVENT' ) + disp( event ); i = i+1; + end +end +% If this isn't called on Windows before calling 'ManyMouse_Init' again, +% only restarting Matlab will make it work again. So always call +% 'ManyMouse_Quit' on Windows ... +manymouse_mex( 'ManyMouse_Quit' ); diff --git a/contrib/matlab/manymouse_mex.cpp b/contrib/matlab/manymouse_mex.cpp new file mode 100755 index 0000000..dbedc0e --- /dev/null +++ b/contrib/matlab/manymouse_mex.cpp @@ -0,0 +1,125 @@ +/* + * A Matlab / Octave MEX wrapper for ManyMouse. + * + * Please see the file LICENSE.txt in the source's root directory. + * + * Thomas Weibel, 2012/12/20 + */ + +#include +#include +#include + +#include "manymouse.h" + +#include +#include + + +// Convert mxArray* to an std::string +void convert( const mxArray* ma, std::string& sString ) +{ + if( !mxIsChar( ma ) ) + mexErrMsgTxt( "!mxIsChar" ); + char *str = mxArrayToString( ma ); + sString = std::string( str ); +} + +//! Converts a double (or int, ...) scalar to mxArray +mxArray* convert( const double& scalar, mxArray*& ma ) +{ + ma = mxCreateDoubleScalar( (double) scalar ); + return ma; +} + +// MEX gateway function +void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) +{ + if( nrhs != 1 ) + mexErrMsgTxt( "manymouse_mex: nrhs != 1.\n" ); + + std::string sMethod; + convert( prhs[0], sMethod ); + static ManyMouseEvent event; + static int available_mice; + + if( sMethod == "ManyMouse_Init" ) + { + ManyMouse_Quit(); + available_mice = ManyMouse_Init(); + if( available_mice == 0 ) + { + ManyMouse_Quit(); + mexErrMsgTxt( "manymouse_mex: Found no mice ...\n" ); + } + else if (available_mice < 0) + { + ManyMouse_Quit(); + mexErrMsgTxt( "Error initializing ManyMouse!\n" ); + } + convert( available_mice, plhs[0] ); + } + else if( sMethod == "ManyMouse_Quit" ) + { + ManyMouse_Quit(); + } + else if( sMethod == "ManyMouse_DriverName" ) + { + plhs[0] = mxCreateString( ManyMouse_DriverName() ); + } + else if( sMethod == "ManyMouse_DeviceName" ) + { + plhs[0] = mxCreateCellMatrix( available_mice, 1 ); + for (int i = 0; i < available_mice; i++) + mxSetCell( plhs[0], i, mxCreateString( ManyMouse_DeviceName(i) ) ); + } + else if( sMethod == "ManyMouse_PollEvent" ) + { + if( ManyMouse_PollEvent(&event) ) + { + const char* fieldnames[] = {"device", "event", "item", "value" }; + plhs[0] = mxCreateStructMatrix(1,1,4,fieldnames); + + mxSetField( plhs[0], 0, "device", mxCreateDoubleScalar( (double) event.device ) ); + // Could also return item as integer ... + //mxSetField( plhs[0], 0, "event", mxCreateDoubleScalar( (double) event.type ) ); + mxSetField( plhs[0], 0, "item", mxCreateDoubleScalar( (double) event.item ) ); + mxSetField( plhs[0], 0, "value", mxCreateDoubleScalar( (double) event.value ) ); + + if (event.type == MANYMOUSE_EVENT_RELMOTION) + { + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_EVENT_RELMOTION" ) ); + } + else if (event.type == MANYMOUSE_EVENT_ABSMOTION) + { + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_EVENT_ABSMOTION" ) ); + } + else if (event.type == MANYMOUSE_EVENT_BUTTON) + { + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_EVENT_BUTTON" ) ); + } + else if (event.type == MANYMOUSE_EVENT_SCROLL) + { + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_EVENT_SCROLL" ) ); + } + else if (event.type == MANYMOUSE_EVENT_DISCONNECT) + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_EVENT_DISCONNECT" ) ); + else + { + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_UNHANDLED_EVENT" ) ); + } + } + else + { + const char* fieldnames[] = {"device", "event", "item", "value" }; + plhs[0] = mxCreateStructMatrix(1,1,4,fieldnames); + mxSetField( plhs[0], 0, "device", mxCreateDoubleScalar( -1 ) ); + mxSetField( plhs[0], 0, "event", mxCreateString( "MANYMOUSE_NO_EVENT" ) ); + mxSetField( plhs[0], 0, "item", mxCreateDoubleScalar( -1 ) ); + mxSetField( plhs[0], 0, "value", mxCreateDoubleScalar( -1 ) ); + } + } + else + mexErrMsgTxt( "manymouse_mex: Not a supported method." ); +} +