PyObjC CoreHaptics Framework
This library provides Python bindings for Apple's CoreHaptics framework on macOS, allowing developers to integrate sophisticated haptic feedback into their applications. As part of the larger PyObjC bridge, it enables direct interaction with Objective-C APIs from Python. The current version is 12.1, and releases generally follow macOS SDK updates and Python version support changes.
Warnings
- breaking PyObjC versions 11.0 and 12.0 dropped support for older Python versions. Specifically, PyObjC 11.0 dropped Python 3.8, and PyObjC 12.0 dropped Python 3.9. Attempting to install or run PyObjC 11.x on Python 3.8 or PyObjC 12.x on Python 3.9 will result in compatibility errors.
- breaking As of PyObjC 11.1, the core bridge's Automatic Reference Counting (ARC) behavior for 'init' family methods (e.g., methods starting with `init`) has been aligned with clang's documentation. Methods in the 'init' family now correctly steal a reference to `self` and return a new one. This is a fundamental change in object lifecycle management for Objective-C classes implemented in Python.
- gotcha PyObjC 10.3 initially removed support for calling `__init__` on classes where PyObjC implicitly provides `__new__`. While PyObjC 10.3.1 restored `__init__` functionality if *your code* explicitly defines `__new__` in the Python class, `__init__` still cannot be used for classes solely relying on PyObjC's default `__new__` method for Objective-C object creation.
- gotcha PyObjC versions 10.3 and 11.0 introduced experimental support for Python 3.13 but explicitly state that they do not fully support the experimental free-threading (PEP 703) features. Significant internal changes were made, but stability with free-threading is not guaranteed and could lead to crashes or undefined behavior.
Install
-
pip install pyobjc-framework-corehaptics
Imports
- CHHapticEngine
from CoreHaptics import CHHapticEngine
- CHHapticEvent
from CoreHaptics import CHHapticEvent
- CHHapticPattern
from CoreHaptics import CHHapticPattern
- CHHapticEventParameterID
from CoreHaptics import CHHapticEventParameterID
- NSArray
from Foundation import NSArray
- NSThread
from Foundation import NSThread
- objc
import objc
Quickstart
import objc
from CoreHaptics import (
CHHapticEngine, CHHapticPattern, CHHapticEvent,
CHHapticEventParameter, CHHapticEventParameterID, CHHapticEventType
)
from Foundation import NSArray, NSThread
def play_haptic_feedback():
"""
Initializes a CHHapticEngine and plays a simple haptic impact.
Requires macOS and haptic feedback enabled.
"""
print("Attempting to play haptic feedback...")
# Create an error holder (PyObjC will populate if an error occurs)
error = objc.nil
# 1. Initialize the haptic engine
engine = CHHapticEngine.alloc().initAndReturnError_(objc.ptr(error))
if engine is None:
print(f"Error initializing CHHapticEngine: {error[0] if error else 'Unknown error'}")
return
# 2. Set an error handler for the engine
engine.setErrorHandler_(lambda err: print(f"CHHapticEngine encountered an error: {err}"))
# 3. Start the engine
success, error = engine.startAndReturnError_(objc.ptr(error))
if not success:
print(f"Error starting CHHapticEngine: {error[0] if error else 'Unknown error'}")
return
print("CHHapticEngine started.")
# 4. Create haptic event parameters
intensity_param = CHHapticEventParameter.alloc().initWithParameterID_value_(
CHHapticEventParameterID.CHHapticEventParameterIDHapticIntensity, 0.8
)
sharpness_param = CHHapticEventParameter.alloc().initWithParameterID_value_(
CHHapticEventParameterID.CHHapticEventParameterIDHapticSharpness, 0.6
)
# 5. Create a haptic event (a transient impact)
event = CHHapticEvent.alloc().initWithEventType_parameters_relativeTime_duration_(
CHHapticEventType.CHHapticEventTypeHapticTransient,
NSArray.arrayWithArray_([intensity_param, sharpness_param]),
0.0,
0.1
)
# 6. Create a haptic pattern from the event
pattern = CHHapticPattern.alloc().initWithEvents_parameters_error_(
NSArray.arrayWithArray_([event]),
objc.nil,
objc.ptr(error)
)
if pattern is None:
print(f"Error creating CHHapticPattern: {error[0] if error else 'Unknown error'}")
engine.stopWithCompletionHandler_(objc.nil)
return
# 7. Create a player for the pattern
player, error = engine.createPlayerWithPattern_error_(pattern, objc.ptr(error))
if player is None:
print(f"Error creating CHHapticPatternPlayer: {error[0] if error else 'Unknown error'}")
engine.stopWithCompletionHandler_(objc.nil)
return
# 8. Start the player
success, error = player.startAtTime_error_(0, objc.ptr(error))
if not success:
print(f"Error starting CHHapticPatternPlayer: {error[0] if error else 'Unknown error'}")
engine.stopWithCompletionHandler_(objc.nil)
return
print("Haptic pattern started playing.")
# 9. Keep the script alive long enough for the haptic to play
NSThread.sleepForTimeInterval_(1.5)
# 10. Stop the engine gracefully
success, error = engine.stopAndReturnError_(objc.ptr(error))
if not success:
print(f"Error stopping CHHapticEngine: {error[0] if error else 'Unknown error'}")
print("CHHapticEngine stopped.")
if __name__ == "__main__":
play_haptic_feedback()