Using GraphicsServices to send keyboard/mouse events hooked into Springboard

Discussion in 'iOS Development' started by legolover64, Jun 29, 2010.

  1. legolover64

    legolover64 New Member

    Joined:
    Jun 29, 2010
    Messages:
    1
    Likes Received:
    0
    Hi there,

    I'm writing my first mobilesubstrate extension. I used a template that I found here to start me off on the right foot, and I have successfully hooked into Springboard.

    I want this extension to be able to send fake touch and keyboard events to Springboard, to be interpreted by the OS or by the currently running app. Here's my code for doing the mouse event handling (this is mostly from Saurik's Veency):
    Code:
    void handleMouseEventAtPoint(CGPoint point, int buttons)
    {
        // NOTE: Must store button state for comparision, port for
        //       mouse dragging and button up
        static int buttons_;
        static mach_port_t port_;
    	
        int diff = buttons_ ^ buttons;
        bool twas = ((buttons_ & 0x1) != 0);
        bool tis = ((buttons & 0x1) != 0);
        buttons_ = buttons;
    	
        // Round point values to prevent subpixel coordinates
        point.x = roundf(point.x);
        point.y = roundf(point.y);
    	
        // Check for mouse button events
        mach_port_t purple;
    	
        if ((diff & 0x10) != 0) {
            // Simulate Headset button press
            struct GSEventRecord record;
    		
            memset(&record, 0, sizeof(record));
    		
            record.type = (buttons & 0x4) != 0 ?
    		kGSEventHeadsetButtonDown :
    		kGSEventHeadsetButtonUp;
    		
            record.timestamp = GSCurrentEventTimestamp();
    		FixRecord(&record);
            GSSendSystemEvent(&record);
        }
    	
        if ((diff & buttonThree) != 0) {
            // Simulate Home button press
            struct GSEventRecord record;
    		
            memset(&record, 0, sizeof(record));
    		
            record.type = (buttons & buttonThree) != 0 ?
    		kGSEventMenuButtonDown :
    		kGSEventMenuButtonUp;
    		
            record.timestamp = GSCurrentEventTimestamp();
    		FixRecord(&record);
            GSSendSystemEvent(&record);
        }
    	
        if ((diff & buttonTwo) != 0) 
    	{
            // Simulate Sleep/Wake button press
            struct GSEventRecord record;
    		
            memset(&record, 0, sizeof(record));
    		
            record.type = (buttons & buttonTwo) != 0 ?
    		kGSEventLockButtonDown :
    		kGSEventLockButtonUp;
    		
            record.timestamp = GSCurrentEventTimestamp();
    		FixRecord(&record);
            GSSendSystemEvent(&record);
        }
    	
        if (twas != tis || tis) {
            // Main (left button) state changed, or was dragged
            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 = twas == tis ?
    		kGSHandInfoTypeTouchDragged :
            tis ?
    		kGSHandInfoTypeTouchDown :
    		kGSHandInfoTypeTouchUp;
    		
            event.data.info.handInfo._0x44 = 0x1;
            event.data.info.handInfo._0x48 = tis ? 0x1 : 0x0;
    		
            event.data.info.pathPositions = 1;
    		
            event.data.path.pathIndex = 0x01;
            event.data.path.pathIdentity = 0x02;
            event.data.path.pathProximity = tis ? 0x03 : 0x00;
            event.data.path.pathLocation = event.record.windowLocation;
    		
            if (twas != tis && tis) 
    		{
                // Button down and was not down before
                port_ = 0;
    			
    			CAWindowServer *server;
    
    			server = [CAWindowServer serverIfRunning];
    			char svrptrstr [255];
    			sprintf(svrptrstr, "%p", server);
    			
    			NSLog(@"One!");
    			
                if (server = [CAWindowServer serverIfRunning]) 
    				//if (true)
    			{
    				NSLog(@"Two!");
    				//NSArray *displays([server displays]);
    				NSArray *displays = [server displays];
                    if (displays != nil && [displays count] != 0)
    				{
    					NSLog(@"Three!");
    					//CAWindowServer *display;
                        if (CAWindowServerDisplay *display = [displays objectAtIndex:0])
    					{
    						NSLog(@"Four!");
    						port_ = [display clientPortAtPosition:point];
    					}
    				}
                }
    			
                if (port_ == 0) 
    			{
                    // Is SpringBoard
                    if (purple == 0)
    				{
                        purple = GSGetPurpleSystemEventPort();
    					port_ = purple;
    					
    				}
    			}
            }
    		
    		FixRecord(&event.record);
            
    		GSSendEvent(&event.record, port_);
    		NSLog(@"Event sent!");
    		//GSSendSystemEvent(&event.record);
    		//GSSendEvent(&event.record, purple);
    	}
    	
        if (purple != 0 && PurpleAllocated)
    	{
            mach_port_deallocate(mach_task_self(), purple);
    		NSLog(@"Deallocated mach_port!");
    	}
    }
    
    I call this function like this in Springboard's applicationDidFinishLaunching:

    Code:
    handleMouseEventAtPoint(CGPointMake(42, 460), 0x1);
    For whatever reason, I get the NSLog() messages in the device's Console, but the event isn't sent (I think it's supposed to touch the phone icon). Am I missing something?

    Any and all help would be greatly greatly appreciated!

Share This Page