Ejemplo n.º 1
0
def run_event_loop():
    LOG.info("try to load mac hotkey event loop")
    import Quartz
    from AppKit import NSSystemDefined

    # Set up a tap, with type of tap, location, options and event mask
    tap = Quartz.CGEventTapCreate(
        Quartz.kCGSessionEventTap,  # Session level is enough for our needs
        Quartz.kCGHeadInsertEventTap,  # Insert wherever, we do not filter
        Quartz.kCGEventTapOptionDefault,
        # NSSystemDefined for media keys
        Quartz.CGEventMaskBit(NSSystemDefined),
        keyboard_tap_callback,
        None
    )

    run_loop_source = Quartz.CFMachPortCreateRunLoopSource(
        None, tap, 0)
    Quartz.CFRunLoopAddSource(
        Quartz.CFRunLoopGetCurrent(),
        run_loop_source,
        Quartz.kCFRunLoopDefaultMode
    )
    # Enable the tap
    Quartz.CGEventTapEnable(tap, True)
    # and run! This won't return until we exit or are terminated.
    Quartz.CFRunLoopRun()
    LOG.error('Mac hotkey event loop exit')
    return []
Ejemplo n.º 2
0
def filter_input():
    logging.info('Filtering all keys and mouse movements...')

    typed_keys = ''

    def keyboard_cb(proxy, type_, event, refcon):
        nonlocal typed_keys

        if not event:
            return None

        # Convert the Quartz CGEvent into something more useful
        ns_event = AppKit.NSEvent.eventWithCGEvent_(event)

        if not ns_event:
            return None

        if ns_event.type() == Quartz.kCGEventKeyDown:
            typed_keys += ns_event.characters()

            if typed_keys.endswith(EXIT_STRING):
                logging.info('Emergency exit!')

                Quartz.CFRunLoopStop(Quartz.CFRunLoopGetCurrent())

        # Filter every event
        return None

    logging.info('Creating tap...')
    # Set up a tap, with type of tap, location, options and event mask
    tap = Quartz.CGEventTapCreate(
        Quartz.kCGSessionEventTap,
        # Insert at the head so we can filter
        Quartz.kCGHeadInsertEventTap,
        # Enable filtering
        Quartz.kCGEventTapOptionDefault,
        # Act on all key and mouse events
        Quartz.kCGAnyInputEventType,
        # Our callback function
        keyboard_cb,
        None)

    runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)

    Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(),
                              runLoopSource,
                              Quartz.kCFRunLoopDefaultMode)

    Quartz.CGEventTapEnable(tap, True)

    logging.info('Starting run loop...')
    Quartz.CFRunLoopRun()

    logging.info('Run loop finished.')
Ejemplo n.º 3
0
def run_event_loop(player):
    LOG.info("try to load mac hotkey event loop")
    import Quartz
    from AppKit import NSKeyUp, NSSystemDefined, NSEvent

    def keyboard_tap_callback(proxy, type_, event, refcon):
        if type_ < 0 or type_ > 0x7fffffff:
            LOG.error('Unkown mac event')
            Quartz.CFRunLoopRun()
            return run_event_loop(ControllerApi.player)
        try:
            key_event = NSEvent.eventWithCGEvent_(event)
        except:
            LOG.info("mac event cast error")
            return event
        if key_event.subtype() == 8:
            key_code = (key_event.data1() & 0xFFFF0000) >> 16
            key_state = (key_event.data1() & 0xFF00) >> 8
            if key_code is 16 or key_code is 19 or key_code is 20:
                # 16 for play-pause, 19 for next, 20 for previous
                if key_state == NSKeyUp:
                    if key_code is 19:
                        player.play_next()
                    elif key_code is 20:
                        player.play_last()
                    elif key_code is 16:
                        player.play_or_pause()
                return None
        return event

    # Set up a tap, with type of tap, location, options and event mask
    tap = Quartz.CGEventTapCreate(
        Quartz.kCGSessionEventTap,  # Session level is enough for our needs
        Quartz.kCGHeadInsertEventTap,  # Insert wherever, we do not filter
        Quartz.kCGEventTapOptionDefault,
        # NSSystemDefined for media keys
        Quartz.CGEventMaskBit(NSSystemDefined),
        keyboard_tap_callback,
        None
    )

    run_loop_source = Quartz.CFMachPortCreateRunLoopSource(
        Quartz.kCFAllocatorDefault, tap, 0)
    Quartz.CFRunLoopAddSource(
        Quartz.CFRunLoopGetCurrent(),
        run_loop_source,
        Quartz.kCFRunLoopDefaultMode
    )
    # Enable the tap
    Quartz.CGEventTapEnable(tap, True)
    # and run! This won't return until we exit or are terminated.
    Quartz.CFRunLoopRun()
    LOG.error('Mac hotkey exit event ')
Ejemplo n.º 4
0
def run_event_loop():
    logger.info('try to load mac hotkey event loop')

    # Set up a tap, with type of tap, location, options and event mask

    def create_tap():
        return Quartz.CGEventTapCreate(
            Quartz.kCGSessionEventTap,  # Session level is enough for our needs
            Quartz.kCGHeadInsertEventTap,  # Insert wherever, we do not filter
            Quartz.kCGEventTapOptionDefault,
            # NSSystemDefined for media keys
            Quartz.CGEventMaskBit(NSSystemDefined),
            keyboard_tap_callback,
            None)

    tap = create_tap()
    if tap is None:
        logger.error('Error occurred when trying to listen global hotkey. '
                     'trying to popup a prompt dialog to ask for permission.')
        # we do not use pyobjc-framework-ApplicationServices directly, since it
        # causes segfault when call AXIsProcessTrustedWithOptions function
        import objc
        AS = objc.loadBundle(
            'CoreServices', globals(),
            '/System/Library/Frameworks/ApplicationServices.framework')
        objc.loadBundleFunctions(AS, globals(),
                                 [('AXIsProcessTrustedWithOptions', b'Z@')])
        objc.loadBundleVariables(AS, globals(),
                                 [('kAXTrustedCheckOptionPrompt', b'@')])
        trusted = AXIsProcessTrustedWithOptions(
            {kAXTrustedCheckOptionPrompt: True})  # noqa
        if not trusted:
            logger.info(
                'Have popuped a prompt dialog to ask for accessibility.'
                'You can restart feeluown after you grant access to it.')
        else:
            logger.warning('Have already grant accessibility, '
                           'but we still can not listen global hotkey,'
                           'theoretically, this should not happen.')
        return

    run_loop_source = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
    Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(), run_loop_source,
                              Quartz.kCFRunLoopDefaultMode)
    # Enable the tap
    Quartz.CGEventTapEnable(tap, True)
    # and run! This won't return until we exit or are terminated.
    Quartz.CFRunLoopRun()
    logger.error('mac hotkey event loop exit')
    return []
    def start_event_loop(self):
        """
        Start event loop.

        This method will not return until the event loop is stopped by \
        calling :paramref:`stop_event_loop`.

        :return: None.
        """
        # Enable the tap
        Quartz.CGEventTapEnable(self._tap, True)

        # Run the current run loop
        Quartz.CFRunLoopRun()
Ejemplo n.º 6
0
    def on(self):
        mask = Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown)
        tap = Quartz.CGEventTapCreate(Quartz.kCGSessionEventTap,
                                      Quartz.kCGHeadInsertEventTap, 0, mask,
                                      self._event_call_back, None)

        assert tap, "failed to create event tap"

        run_loop_source = Quartz.CFMachPortCreateRunLoopSource(
            Quartz.kCFAllocatorDefault, tap, 0)
        Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(),
                                  run_loop_source,
                                  Quartz.kCFRunLoopCommonModes)
        Quartz.CGEventTapEnable(tap, True)
        Quartz.CFRunLoopRun()
Ejemplo n.º 7
0
    def runEventsCapture(self):
        import AppKit
        pool = AppKit.NSAutoreleasePool.alloc().init()
        from AppKit import NSSystemDefined

        import Quartz
        self.runLoopRef = Quartz.CFRunLoopGetCurrent()

        while True:
            # https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
            try:
                tap = Quartz.CGEventTapCreate(
                    Quartz.
                    kCGSessionEventTap,  # Quartz.kCGSessionEventTap or kCGHIDEventTap
                    Quartz.
                    kCGHeadInsertEventTap,  # Insert wherever, we do not filter
                    Quartz.
                    kCGEventTapOptionDefault,  # we can't listen-only because we want to consume it
                    Quartz.CGEventMaskBit(
                        NSSystemDefined),  # NSSystemDefined for media keys
                    self.eventTap,
                    None)
            except TypeError:
                # wrong number of args? I got this on MacOSX 10.6,
                # where it expected 5 args (instead of 6).
                # however, it crashes when I call it without the last arg!
                assert False, "CGEventTapCreate has an invalid signature on your system. This is fixed in later MacOSX versions. It should work in at least >=MacOSX 10.8. It is known to be broken in MacOSX 10.6."
            assert tap

            # Create a runloop source and add it to the current loop
            runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
            Quartz.CFRunLoopAddSource(self.runLoopRef, runLoopSource,
                                      Quartz.kCFRunLoopDefaultMode)

            # Enable the tap
            Quartz.CGEventTapEnable(tap, True)

            try:
                # and run! This won't return until we exit or are terminated.
                Quartz.CFRunLoopRun()
            except Exception:
                sys.excepthook(*sys.exc_info())
                continue  # rerun

            # this is a regular quit
            break

        del pool
Ejemplo n.º 8
0
def keyHook():
    tap = Quartz.CGEventTapCreate(Quartz.kCGHIDEventTap,
                                  Quartz.kCGHeadInsertEventTap,
                                  Quartz.kCGEventTapOptionDefault,
                                  Quartz.kCGEventMaskForAllEvents,
                                  keyboardTapCallback, None)

    if tap is None:
        print('failed to create event tap!')
        sys.exit(1)

    runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
    Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(), runLoopSource,
                              Quartz.kCFRunLoopDefaultMode)

    Quartz.CGEventTapEnable(tap, True)

    Quartz.CFRunLoopRun()
Ejemplo n.º 9
0
 def runEventsCapture(cls, controlPath):
     tapHandler = cls(controlPath)
     tap = Quartz.CGEventTapCreate(
         Quartz.kCGSessionEventTap,  # Session level is enough for our needs
         Quartz.kCGHeadInsertEventTap,  # Insert wherever, we do not filter
         Quartz.kCGEventTapOptionListenOnly,  # Listening is enough
         # NSSystemDefined for media keys
         Quartz.CGEventMaskBit(NSSystemDefined),
         tapHandler.eventTap,
         None)
     # Create a runloop source and add it to the current loop
     runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
     Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(), runLoopSource,
                               Quartz.kCFRunLoopDefaultMode)
     # Enable the tap
     Quartz.CGEventTapEnable(tap, True)
     # and run! This won't return until we exit or are terminated.
     Quartz.CFRunLoopRun()
Ejemplo n.º 10
0
class EventTap(object):
    """ wraps a Quartz keyboard event tap """
    def __init__(self, cb, block_cb):
        self.runner = EventTapRunner.alloc().init()

        self.setup_event_tap(cb, block_cb)

    def setup_event_tap(self, callback, should_block):
        def keyboardTapCallback(proxy, type_, event, refcon):
            if type_ == Quartz.kCGEventTapDisabledByTimeout & 0xffffffff:
                # event tap timed out, re-enable.
                Quartz.CGEventTapEnable(self.tap, True)
                NSLog('event tap timed out, re-enabling')
                return None

            # Convert the Quartz CGEvent into something more useful
            keyEvent = NSEvent.eventWithCGEvent_(event)
            try:
                selector = objc.selector(self.runner.call_, signature='v@:@')
                self.runner.performSelectorOnMainThread_withObject_waitUntilDone_(
                    selector, (callback, keyEvent), False)

                if should_block(keyEvent):
                    return None
            except Exception, e:
                tb = sys.exc_info()
                print ''.join(traceback.format_exception(*tb))
                print 'Exception: ' + e.message

            return event

        self.tap = Quartz.CGEventTapCreate(
            Quartz.kCGSessionEventTap, Quartz.kCGHeadInsertEventTap,
            Quartz.kCGEventTapOptionDefault,
            Quartz.CGEventMaskBit(Quartz.kCGEventKeyDown), keyboardTapCallback,
            None)

        runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, self.tap, 0)
        Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(), runLoopSource,
                                  Quartz.kCFRunLoopDefaultMode)
        # Enable the tap
        Quartz.CGEventTapEnable(self.tap, True)

        Quartz.CFRunLoopRun()
Ejemplo n.º 11
0
    def runEventsCapture(self):
        import AppKit, Quartz
        from AppKit import NSSystemDefined
        pool = AppKit.NSAutoreleasePool.alloc().init()

        self.runLoopRef = Quartz.CFRunLoopGetCurrent()

        while True:
            # https://developer.apple.com/library/mac/#documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html
            tap = Quartz.CGEventTapCreate(
                Quartz.
                kCGSessionEventTap,  # Quartz.kCGSessionEventTap or kCGHIDEventTap
                Quartz.
                kCGHeadInsertEventTap,  # Insert wherever, we do not filter
                Quartz.
                kCGEventTapOptionDefault,  #Quartz.kCGEventTapOptionListenOnly,
                Quartz.CGEventMaskBit(
                    NSSystemDefined),  # NSSystemDefined for media keys
                self.eventTap,
                None)
            assert tap

            # Create a runloop source and add it to the current loop
            runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
            Quartz.CFRunLoopAddSource(self.runLoopRef, runLoopSource,
                                      Quartz.kCFRunLoopDefaultMode)

            # Enable the tap
            Quartz.CGEventTapEnable(tap, True)

            try:
                # and run! This won't return until we exit or are terminated.
                Quartz.CFRunLoopRun()
            except Exception:
                # I got this one here once:
                # error: NSInternalInconsistencyException - Invalid parameter not satisfying: cgsEvent.type > 0 && cgsEvent.type <= kCGSLastEventType
                sys.excepthook(*sys.exc_info())
                continue  # rerun

            # this is a regular quit
            break

        del pool
Ejemplo n.º 12
0
    def run(self):
        self._tap = Quartz.CGEventTapCreate(
            Quartz.kCGSessionEventTap, # Session level is enough for our needs
            Quartz.kCGHeadInsertEventTap, # Insert wherever, we do not filter
            # Active, to swallow the play/pause event is enough
            Quartz.kCGEventTapOptionDefault,
            # NSSystemDefined for media keys
            Quartz.CGEventMaskBit(NSSystemDefined),
            self._event_tap,
            None
        )

        # the above can fail
        if self._tap is None:
            self._event.set()
            return

        self._loop = Quartz.CFRunLoopGetCurrent()

        # add an observer so we know when we can stop it
        # without a race condition
        self._observ = Quartz.CFRunLoopObserverCreate(
            None, Quartz.kCFRunLoopEntry, False, 0, self._loop_start, None)
        Quartz.CFRunLoopAddObserver(
            self._loop, self._observ, Quartz.kCFRunLoopCommonModes)

        # Create a runloop source and add it to the current loop
        self._runLoopSource = Quartz.CFMachPortCreateRunLoopSource(
            None, self._tap, 0)

        Quartz.CFRunLoopAddSource(
            self._loop,
            self._runLoopSource,
            Quartz.kCFRunLoopDefaultMode
        )

        # Enable the tap
        Quartz.CGEventTapEnable(self._tap, True)

        # runrunrun
        Quartz.CFRunLoopRun()
Ejemplo n.º 13
0
 def keyboard_tap_callback(proxy, type_, event, refcon):
     if type_ < 0 or type_ > 0x7fffffff:
         LOG.error('Unkown mac event')
         Quartz.CFRunLoopRun()
         return run_event_loop(ControllerApi.player)
     try:
         key_event = NSEvent.eventWithCGEvent_(event)
     except:
         LOG.info("mac event cast error")
         return event
     if key_event.subtype() == 8:
         key_code = (key_event.data1() & 0xFFFF0000) >> 16
         key_state = (key_event.data1() & 0xFF00) >> 8
         if key_code is 16 or key_code is 19 or key_code is 20:
             # 16 for play-pause, 19 for next, 20 for previous
             if key_state == NSKeyUp:
                 if key_code is 19:
                     player.play_next()
                 elif key_code is 20:
                     player.play_last()
                 elif key_code is 16:
                     player.play_or_pause()
             return None
     return event
Ejemplo n.º 14
0
import Quartz


def MyFunction(p, t, e, c):
    print e


tap = Quartz.CGEventTapCreate(
    Quartz.kCGHIDEventTap, Quartz.kCGHeadInsertEventTap,
    Quartz.kCGEventTapOptionListenOnly,
    Quartz.CGEventMaskBit(Quartz.kCGEventLeftMouseDown), MyFunction, None)

runLoopSource = Quartz.CFMachPortCreateRunLoopSource(None, tap, 0)
Quartz.CFRunLoopAddSource(Quartz.CFRunLoopGetCurrent(), runLoopSource,
                          Quartz.kCFRunLoopDefaultMode)
Quartz.CGEventTapEnable(tap, True)

Quartz.CFRunLoopRun()