System-wide tap simulation on iOS - iphone

I would like to achieve system-wide tap simulation on iOS, via a MobileSubstrate plugin. The idea is to be able to simulate touches (in a first time single touch, then multitouch) on a system-wide level, in iOS 5.1.1 .
I've been successful in implementing this article to simulate touches on a specific view, I now would like to be able to simulate them system-wide.
I understand I should use the private MobileServices framework to do so, and I've documented myself on GSEvent (I've also looked at Veency & MouseSupport sourcecodes).
I tried to hook up a view to intercept UIEvents and look at the underlying structure :
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
GSEventRef eventRef = (GSEventRef)[event performSelector:#selector( _gsEvent)];
GSEventRecord record = *_GSEventGetGSEventRecord(eventRef);
< breakpoint here to look at record >
}
and the result is extremely similar to the old (iOS 3) structure detailled above.
I then tried to fire up those events myself (on a Standalone app, not a MS tweak for now) :
+(void)simulateTouchDown:(CGPoint)point{
point.x = roundf(point.x);
point.y = roundf(point.y);
GSEventRecord record;
memset(&record, 0, sizeof(record));
record.type = kGSEventHand;
record.windowLocation = point;
record.timestamp = GSCurrentEventTimestamp();
GSSendSystemEvent(&record);
}
Now, that doesn't work at all (doesn't crash either).
Most codes (MouseSupport, Veency) look like this
// Create & populate a GSEvent
struct {
struct GSEventRecord record;
struct {
struct GSEventRecordInfo info;
struct GSPathInfo path;
} data;
} event;
memset(&event, 0, sizeof(event));
event.record.type = kGSEventHand;
event.record.windowLocation = point;
event.record.timestamp = GSCurrentEventTimestamp();
event.record.infoSize = sizeof(event.data);
event.data.info.handInfo.type = kGSHandInfoTypeTouchDown;
event.data.info.handInfo._0x44 = 0x1;
event.data.info.handInfo._0x48 = 0x1;
event.data.info.pathPositions = 1;
event.data.path.pathIndex = 0x01;
event.data.path.pathIdentity = 0x02;
event.data.path.pathProximity = 0x00;
event.data.path.pathLocation = event.record.windowLocation;
GSSendSystemEvent(&event.record);
Only :
GSEventRecordInfo is unknown (and I can't find where it might be defined)
I don't see the point of making a whole event to only pass the record
Please someone who's been through this on iOS 5 guide me.

GSEventRecordInfo may have been introduced since iOS 3.2 (that's where the Graphics Services headers you linked to are from). class-dump the framework that's actually on your device on iOS 5.1.1 and see if it's defined there?

Related

Handling Multi-Touch events in Emscripten in Safari

I am using Emscripten to get a number of C++ games running under HTML5. The client requires that these games also run in a mobile web browser, they do not want to make a native app.
The games require me to properly handle multitouch events - if the user applies three fingers to the screen, I have to react accordingly to all three fingers. However, I'm seeing an issue when testing on Safari on an iPad Mini, and I expect it happens elsewhere as well (though so far I'm not seeing it on Android).
What I'm finding is that when a touch callback is hit, for instance if I set a callback via emscripten_set_touchend_callback, then whenever a touchend event occurs, that callback gets hit with all active touchpoints included in the EmscriptenTouchEvent. As such, I don't know which touchpoint the event applies to. For instance if three fingers are down, and you lift the second finger, all three touchpoints are passed to the touchend callback. Is there a way for me to determine which touchpoint the touchend event applies to? If this is a bug, is there a known workaround?
Thank you in advance.
Okay, after doing some research I found a solution on this website:
https://github.com/kripken/emscripten/issues/5012
They suggest that you edit library_html5.js in the Emscripten code and change:
var touches = {};
for(var i = 0; i < e.touches.length; ++i) {
var touch = e.touches[i];
touches[touch.identifier] = touch;
}
for(var i = 0; i < e.changedTouches.length; ++i) {
var touch = e.changedTouches[i];
touches[touch.identifier] = touch;
touch.changed = true;
}
With this:
var touches = {};
for(var i = 0; i < e.touches.length; ++i) {
var touch = e.touches[i];
touches[touch.identifier] = touch;
touch.changed = 0;
}
for(var i = 0; i < e.changedTouches.length; ++i) {
var touch = e.changedTouches[i];
touches[touch.identifier] = touch;
touch.changed = 1;
}
I applied the change and confirmed that it fixes multi-touch on iOS platforms.

Phaser multitouch (on laptop trackpad)

I'm confused by how to skip the following condition when 1) holding down, and then 2) another tap on the screen to release the aim. I think the secondary tap becomes the activePointer so I'm quite puzzled.
var holding_down = game.input.activePointer.isDown;
if (holding_down && game.input.pointer2.isUp) { cue.aiming = true; }
UPDATE: Please note that for the solution accepted, I had to differentiate between desktop and mobile usage. pointer1 & pointer2 work fine on mobile, but on desktop I had to do the following.
if (desktop) {
var holding_down = game.input.activePointer.leftButton.isDown;
var second_tap = spacebar.isDown;
} else {
var holding_down = game.input.pointer1.isDown;
var second_tap = game.input.pointer2.isDown;
}
Also note you need to declare the desktop var after intantating the game object. I then set the var in the preload() function: desktop = game.device.desktop;, otherwise it was giving the wrong value. Thanks!
You're correct in that the secondary tap becomes the activePointer. Per the documentation, activePointer is "[t]he most recently active Pointer object."
Therefore, you'll want to make your checks against game.input.pointer1 and game.input.pointer2 instead.
So replace activePointer in your code with pointer1 and that might get you closer to what you were looking for.

How can I get a fake 'current location' when creating an IOS Map with Xamarin Studio and the iPhone Emulator?

Problem:
When using the Xamarin iPhone emulator, the current location is not getting set on the map.
Details:
I'm trying to plot my current location on a Map, in a sample iPhone app I'm learning with Xamarin Studio and the iPhone emulator.
I have the map displayed but there's no current location getting set.
I did get asked to use my Current Location (which I'm sure I said yes/ok to) .. but it keeps centering it in San Fran, near union square :(
When ever I run my emulato, I see this text pop up:
2013-10-22 09:27:45.018 MyApp [6018:1503] MonoTouch: Socket error while connecting to MonoDevelop on 127.0.0.1:10000: Connection refused
So i'm not sure if that has something to do with it?
Ok, so lets look at some code I've got.
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
map.MapType = MKMapType.Standard;
map.ShowsUserLocation = true;
map.ZoomEnabled = true;
map.ScrollEnabled = true;
map.DidUpdateUserLocation += (sender, e) => {
if (map.UserLocation != null)
{
CentreMapAtLocation(map.UserLocation.Coordinate.Latitude,
map.UserLocation.Coordinate.Longitude);
}
// User denied permission, or device doesn't have GPS/location ability.
if (!map.UserLocationVisible)
{
// TODO: Send the map somewhere or hide the map and show another message.
//CLLocationCoordinate2D coords = new CLLocationCoordinate2D(37.33233141,-122.0312186); // cupertino
//MKCoordinateSpan span = new MKCoordinateSpan(MilesToLatitudeDegrees(20), MilesToLongitudeDegrees(20, coords.Latitude));
//mapView.Region = new MKCoordinateRegion(coords, span);
}
};
private void CentreMapAtLocation(double latitude, double longitude)
{
CLLocationCoordinate2D mapCenter = new CLLocationCoordinate2D (latitude, longitude);
MKCoordinateRegion mapRegion = MKCoordinateRegion.FromDistance (mapCenter, 10000, 10000);
map.CenterCoordinate = mapCenter;
map.Region = mapRegion;
}
So it's nothing too crazy, IMO.
Anyone have any suggestions?
Have you tried setting the custom location within the simulator?
I tend to use a combination of the Custom Location setting and this tool when I need to verify locations within the iOs simulator. You won't need to make any changes to your code for this to work; it just pipes the set location into the location manager within iOs.
To my knowledge, the simulator does not support GPS or WiFi based location therefore it can't use your current location like a physical device. Perhaps someone else can clarify this.
For further information, see:
Set the location in iPhone Simulator
http://bencoding.com/2011/12/28/setting-you-location-in-the-ios-5-0-simulator/

How can i use void ContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) method in our application?

I dont know how to use this metnod in my application
void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
b2WorldManifold worldManifold;
contact->GetWorldManifold(&worldManifold);
b2PointState state1[2], state2[2];
b2GetPointStates(state1, state2, oldManifold, contact->GetManifold());
//NSLog(#"Presolving");
if (state2[0] == b2_addState)
{
const b2Body* bodyA = contact->GetFixtureA()->GetBody();
const b2Body* bodyB = contact->GetFixtureB()->GetBody();
b2Vec2 point = worldManifold.points[0];
b2Vec2 vA = bodyA->GetLinearVelocityFromWorldPoint(point);
b2Vec2 vB = bodyB->GetLinearVelocityFromWorldPoint(point);
b2Vec2 rV = vB - vA;
float32 approachVelocity = b2Dot(rV, worldManifold.normal);
if (-1.5f < approachVelocity && approachVelocity < 0.0f)
{
//MyPlayCollisionSound();
NSLog(#"Not Playing Sound");
}
else
{
NSLog(#"playing the sound");
}
}
}
How can I use this code in my HelloWorldLayer.mm Please help me...
I have a problem here, I have a scene where some bodies falls and hit a static body, edges alike, I implemented the b2ContactListener, and in my tick method Im checking for contacts and play the sound, the problem with this approach is that when a body is constantly in contact with the static body, the sound plays indefinitely overlaying the previous one, so at the end I have huge noise..
What can I do to avoid this situation?
Please help me thanks......
You just used following method into your update method and declare its object before schedule update method call.
Like in HelloWorldLayer.h
MyContactListener *contactListener;
And in HelloworldLayer.mm
Before
[self scheduleupdate];
contactListener=new MyContactListener();
world->setContactListener(contactListener);
Than this type of error not occur.
When two bodies collide, the b2ContactListener methods are called in the following sequence:
BeginContact
PreSolve
PostSolve
PreSolve
PostSolve
...etc
EndContact
So if you want to detect collision between the bodies once for each collision, use BeginContact or EndContact instead. These methods only take a single b2Contact parameter though so you might need to do away with using the oldManifold value in your calculation.

How to start Audio file from certain location using AudioQueue?

I have analyzed "SpeakHere" sample code of iPhone dev forum.
There is a code for starting AudioQueue as following..
AudioTimeStamp ats = {0};
AudioQueueStart(mQueue, &ats);
But I have no idea that how to start middle of file.
I changed AudioTimeStamp with various values include negative. But it does not works.
Please let me know your great opinion. Thanks.
AudioQueueStart is not the function that will help you to do that. The time there is like a delay, if you pass NULL then it means that the queue will start ASAP.
You have to pass the frame you want to play and enqueue it, to calculate that you have to know the number of frames your file has and the (relative) position you want to play.
These are instructions how to make it in SpeakHere
In the new (objc++ based) SpeakHere
In AQPlayer.h add a private instance variable:
UInt64 mPacketCount;
and a public method:
void SetQueuePosition(float position) { mCurrentPacket = mPacketCount*position; };
In AQPlayer.mm inside AQPlayer::SetupNewQueue() before mIsInitialized = true; add:
// get the total number of packets
UInt32 sizeOfPacketsCount = sizeof(mPacketCount);
XThrowIfError (AudioFileGetProperty (mAudioFile, kAudioFilePropertyAudioDataPacketCount, &sizeOfPacketsCount, &mPacketCount), "get packet count");
Now you have to use it (In SpeakHereControler.mm add this and link it to a UISlider for example):
- (IBAction) sliderValueChanged:(UISlider *) sender
{
float value = [sender value];
player->SetQueuePosition(position);
}
Why this works:
The playback callback function AudioQueueOutputCallback that feeds the queue with new packets and which in the new SpeakHere is: void AQPlayer::AQBufferCallback( , , ) calls AudioFileReadPackets to read and enqueue a certain part of a file. For that task mCurrentPacket is used and that is what we just adjusted in above methods, hence the part you wanted to play is read, enqueued and finally played :)
Just for historical reasons :)
In the old (objc based) SpeakHere
In AudioPlayer.h add an instance variable:
UInt64 totalFrames;
AudioPlayer.m inside
- (void) openPlaybackFile: (CFURLRef) soundFile
add:
UInt32 sizeOfTotalFrames = sizeof(UInt64);
AudioFileGetProperty (
[self audioFileID],
kAudioFilePropertyAudioDataPacketCount,
&sizeOfTotalFrames,
&totalFrames
);
Then add a method to AudioPlayer.h and .m
- (void) setRelativePlaybackPosition: (float) position
{
startingPacketNumber = totalFrames * position;
}
Now you have to use it (In AudioViewController add this and link it to a UISlider for example):
- (IBAction) setPlaybackPosition: (UISlider *) sender
{
float value = [sender value];
[audioPlayer setRelativePlaybackPosition: value];
}
When value is 0 you will play from the beggining, 0.5 from the middle, etc.
Hope this helps.