]> gitweb.factorcode.org Git - factor.git/commitdiff
game-input vocab w/ iokit backend
authorJoe Groff <arcata@gmail.com>
Sat, 19 Jul 2008 18:04:07 +0000 (11:04 -0700)
committerJoe Groff <arcata@gmail.com>
Sat, 19 Jul 2008 18:04:07 +0000 (11:04 -0700)
extra/game-input/backend/iokit/iokit.factor [new file with mode: 0644]
extra/game-input/game-input.factor [new file with mode: 0644]
extra/iokit/hid/hid.factor

diff --git a/extra/game-input/backend/iokit/iokit.factor b/extra/game-input/backend/iokit/iokit.factor
new file mode 100644 (file)
index 0000000..cc4cc31
--- /dev/null
@@ -0,0 +1,273 @@
+USING: cocoa cocoa.plists core-foundation iokit iokit.hid
+kernel cocoa.enumeration destructors math.parser cocoa.application 
+sequences locals combinators.short-circuit game-input threads
+symbols namespaces assocs hashtables arrays combinators
+core-foundation.run-loop accessors sequences.private
+alien.c-types math ;
+IN: game-input.backend.iokit
+
+SINGLETON: iokit-game-input-backend
+
+: hid-manager-matching ( matching-seq -- alien )
+    f 0 IOHIDManagerCreate
+    [ swap >plist IOHIDManagerSetDeviceMatchingMultiple ]
+    keep ;
+
+: devices-from-hid-manager ( manager -- vector )
+    [
+        IOHIDManagerCopyDevices
+        [ &CFRelease NSFastEnumeration>vector ] [ f ] if*
+    ] with-destructors ;
+
+: game-devices-matching-seq
+    {
+        H{ { "DeviceUsage" 4 } { "DeviceUsagePage" 1 } } ! joysticks
+        H{ { "DeviceUsage" 5 } { "DeviceUsagePage" 1 } } ! gamepads
+        H{ { "DeviceUsage" 6 } { "DeviceUsagePage" 1 } } ! keyboards
+    } ; inline
+
+: buttons-matching-hash
+    H{ { "UsagePage" 9 } { "Type" 2 } } ; inline
+: keys-matching-hash
+    H{ { "UsagePage" 7 } { "Type" 2 } } ; inline
+: x-axis-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 30 } { "Type" 1 } } ; inline
+: y-axis-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 31 } { "Type" 1 } } ; inline
+: z-axis-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 32 } { "Type" 1 } } ; inline
+: rx-axis-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 33 } { "Type" 1 } } ; inline
+: ry-axis-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 34 } { "Type" 1 } } ; inline
+: rz-axis-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 35 } { "Type" 1 } } ; inline
+: slider-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 36 } { "Type" 1 } } ; inline
+: hat-switch-matching-hash
+    H{ { "UsagePage" 1 } { "Usage" HEX: 39 } { "Type" 1 } } ; inline
+
+: device-elements-matching ( device matching-hash -- vector )
+    [
+        >plist 0 IOHIDDeviceCopyMatchingElements
+        [ &CFRelease NSFastEnumeration>vector ] [ f ] if*
+    ] with-destructors ;
+
+: button-count ( device -- button-count )
+    buttons-matching-hash device-elements-matching length ;
+
+: ?axis ( device hash -- axis/f )
+    device-elements-matching dup empty? [ drop f ] [ first ] if ;
+
+: ?x-axis ( device -- ? )
+    x-axis-matching-hash ?axis ;
+: ?y-axis ( device -- ? )
+    y-axis-matching-hash ?axis ;
+: ?z-axis ( device -- ? )
+    z-axis-matching-hash ?axis ;
+: ?rx-axis ( device -- ? )
+    rx-axis-matching-hash ?axis ;
+: ?ry-axis ( device -- ? )
+    ry-axis-matching-hash ?axis ;
+: ?rz-axis ( device -- ? )
+    rz-axis-matching-hash ?axis ;
+: ?slider ( device -- ? )
+    slider-matching-hash ?axis ;
+: ?hat-switch ( device -- ? )
+    hat-switch-matching-hash ?axis ;
+
+: hid-manager-matching-game-devices ( -- alien )
+    game-devices-matching-seq hid-manager-matching ;
+
+: device-property ( device key -- value )
+    [
+        <NSString> IOHIDDeviceGetProperty
+        [ &CFRelease plist> ] [ f ] if*
+    ] with-destructors ;
+: element-property ( element key -- value )
+    [
+        <NSString> IOHIDElementGetProperty
+        [ &CFRelease plist> ] [ f ] if*
+    ] with-destructors ;
+: set-element-property ( element key value -- )
+    [ <NSString> ] [ >plist ] bi* IOHIDElementSetProperty drop ;
+: transfer-element-property ( element from-key to-key -- )
+    [ dupd element-property ] dip swap set-element-property ;
+
+: controller-device? ( device -- ? )
+    {
+        [ 1 4 IOHIDDeviceConformsTo ]
+        [ 1 5 IOHIDDeviceConformsTo ]
+    } 1|| ;
+
+: element-usage ( element -- {usage-page,usage} )
+    [ IOHIDElementGetUsagePage ] [ IOHIDElementGetUsage ] bi
+    2array ;
+
+: button? ( {usage-page,usage} -- ? )
+    first 9 = ;
+: keyboard-key? ( {usage-page,usage} -- ? )
+    first 7 = ;
+: x-axis? ( {usage-page,usage} -- ? )
+    { 1 HEX: 30 } = ;
+: y-axis? ( {usage-page,usage} -- ? )
+    { 1 HEX: 31 } = ;
+: z-axis? ( {usage-page,usage} -- ? )
+    { 1 HEX: 32 } = ;
+: rx-axis? ( {usage-page,usage} -- ? )
+    { 1 HEX: 33 } = ;
+: ry-axis? ( {usage-page,usage} -- ? )
+    { 1 HEX: 34 } = ;
+: rz-axis? ( {usage-page,usage} -- ? )
+    { 1 HEX: 35 } = ;
+: slider? ( {usage-page,usage} -- ? )
+    { 1 HEX: 36 } = ;
+: hat-switch? ( {usage-page,usage} -- ? )
+    { 1 HEX: 39 } = ;
+
+: button-value ( value -- f/(0,1] )
+    IOHIDValueGetIntegerValue dup zero? [ drop f ] when ;
+! XXX calibration
+: axis-value ( value -- [-1,1] )
+    kIOHIDValueScaleTypeCalibrated IOHIDValueGetScaledValue ;
+: slider-value ( value -- [0,1] )
+    kIOHIDValueScaleTypeCalibrated IOHIDValueGetScaledValue
+    1.0 + 0.5 * ;
+: pov-value ( value -- pov-direction )
+    ! XXX
+    IOHIDValueGetIntegerValue ;
+
+: record-controller ( controller-state value -- )
+    dup IOHIDValueGetElement element-usage {
+        { [ dup button? ] [ [ button-value ] [ second 1- ] bi* rot buttons>> set-nth ] } 
+        { [ dup x-axis? ] [ drop axis-value >>x drop ] }
+        { [ dup y-axis? ] [ drop axis-value >>y drop ] }
+        { [ dup z-axis? ] [ drop axis-value >>z drop ] }
+        { [ dup rx-axis? ] [ drop axis-value >>rx drop ] }
+        { [ dup ry-axis? ] [ drop axis-value >>ry drop ] }
+        { [ dup rz-axis? ] [ drop axis-value >>rz drop ] }
+        { [ dup slider? ] [ drop slider-value >>slider drop ] }
+        { [ dup hat-switch? ] [ drop pov-value >>pov drop ] }
+        [ 3drop ]
+    } cond ;
+
+SYMBOLS: +hid-manager+ +keyboard-state+ +controller-states+ ;
+
+: ?set-nth ( value nth seq -- )
+    2dup bounds-check? [ set-nth-unsafe ] [ 3drop ] if ;
+
+: record-keyboard ( value -- )
+    dup IOHIDValueGetElement element-usage keyboard-key? [
+        [ IOHIDValueGetIntegerValue c-bool> ]
+        [ IOHIDValueGetElement IOHIDElementGetUsage ] bi
+        +keyboard-state+ get ?set-nth
+    ] [ drop ] if ;
+
+: default-calibrate-saturation ( element -- )
+    [ kIOHIDElementMinKey kIOHIDElementCalibrationSaturationMinKey transfer-element-property ]
+    [ kIOHIDElementMaxKey kIOHIDElementCalibrationSaturationMaxKey transfer-element-property ]
+    bi ;
+
+: default-calibrate-axis ( element -- )
+    [ kIOHIDElementCalibrationMinKey -1.0 set-element-property ]
+    [ kIOHIDElementCalibrationMaxKey 1.0 set-element-property ]
+    [ default-calibrate-saturation ]
+    tri ;
+
+: default-calibrate-slider ( element -- )
+    [ kIOHIDElementCalibrationMinKey 0.0 set-element-property ]
+    [ kIOHIDElementCalibrationMaxKey 1.0 set-element-property ]
+    [ default-calibrate-saturation ]
+    tri ;
+
+: (default) ( ? quot -- )
+    [ f ] if* ; inline
+
+: <device-controller-state> ( device -- controller-state )
+    {
+        [ ?x-axis [ default-calibrate-axis 0.0 ] (default) ]
+        [ ?y-axis [ default-calibrate-axis 0.0 ] (default) ]
+        [ ?z-axis [ default-calibrate-axis 0.0 ] (default) ]
+        [ ?rx-axis [ default-calibrate-axis 0.0 ] (default) ]
+        [ ?ry-axis [ default-calibrate-axis 0.0 ] (default) ]
+        [ ?rz-axis [ default-calibrate-axis 0.0 ] (default) ]
+        [ ?slider [ default-calibrate-slider 0.0 ] (default) ]
+        [ ?hat-switch pov-neutral and ]
+        [ button-count f <array> ]
+    } cleave controller-state boa ;
+
+: device-matched-callback ( -- alien )
+    [| context result sender device |
+        device controller-device? [
+            device <device-controller-state>
+            device +controller-states+ get set-at
+        ] when
+    ] IOHIDDeviceCallback ;
+
+: device-removed-callback ( -- alien )
+    [| context result sender device |
+        device +controller-states+ get delete-at
+    ] IOHIDDeviceCallback ;
+
+: device-input-callback ( -- alien )
+    [| context result sender value |
+        sender controller-device?
+        [ sender +controller-states+ get at value record-controller ]
+        [ value record-keyboard ]
+        if
+    ] IOHIDValueCallback ;
+
+: initialize-variables ( manager -- )
+    +hid-manager+ set-global
+    4 <hashtable> +controller-states+ set-global
+    256 f <array> +keyboard-state+ set-global ;
+
+M: iokit-game-input-backend open-game-input
+    hid-manager-matching-game-devices {
+        [ initialize-variables ]
+        [ device-matched-callback f IOHIDManagerRegisterDeviceMatchingCallback ]
+        [ device-removed-callback f IOHIDManagerRegisterDeviceRemovalCallback ]
+        [ device-input-callback f IOHIDManagerRegisterInputValueCallback ]
+        [ 0 IOHIDManagerOpen mach-error ]
+        [
+            CFRunLoopGetMain CFRunLoopDefaultMode
+            IOHIDManagerScheduleWithRunLoop
+        ]
+    } cleave ;
+
+! XXX while game-input is open, we need to reset-game-input and open-game-input as a
+! boot image hook
+M: iokit-game-input-backend close-game-input
+    +hid-manager+ global [ 
+        [ 0 IOHIDManagerClose drop ]
+        [ CFRelease ] bi
+        f
+    ] change-at
+    f +keyboard-state+ set-global
+    f +controller-states+ set-global ;
+
+M: iokit-game-input-backend get-controllers ( -- sequence )
+    +controller-states+ get keys [ controller boa ] map ;
+
+M: iokit-game-input-backend manufacturer ( controller -- string )
+    handle>> kIOHIDManufacturerKey device-property ;
+M: iokit-game-input-backend product ( controller -- string )
+    handle>> kIOHIDProductKey device-property ;
+M: iokit-game-input-backend vendor-id ( controller -- integer )
+    handle>> kIOHIDVendorIDKey device-property ;
+M: iokit-game-input-backend product-id ( controller -- integer )
+    handle>> kIOHIDProductIDKey device-property ;
+M: iokit-game-input-backend location-id ( controller -- integer )
+    handle>> kIOHIDLocationIDKey device-property ;
+
+M: iokit-game-input-backend read-controller ( controller -- controller-state )
+    handle>> +controller-states+ get at clone ;
+
+M: iokit-game-input-backend read-keyboard ( -- keyboard-state )
+    +keyboard-state+ get clone keyboard-state boa ;
+
+M: iokit-game-input-backend calibrate-controller ( controller -- )
+    ! XXX
+    drop ;
+
+iokit-game-input-backend game-input-backend set-global
diff --git a/extra/game-input/game-input.factor b/extra/game-input/game-input.factor
new file mode 100644 (file)
index 0000000..a2884b0
--- /dev/null
@@ -0,0 +1,39 @@
+USING: arrays accessors continuations kernel symbols ;
+IN: game-input
+
+SYMBOL: game-input-backend
+
+HOOK: open-game-input game-input-backend ( -- )
+HOOK: close-game-input game-input-backend ( -- )
+
+: with-game-input ( quot -- )
+    open-game-input [ close-game-input ] [ ] cleanup ;
+
+TUPLE: controller handle ;
+TUPLE: controller-state x y z rx ry rz slider pov buttons ;
+
+M: controller-state clone
+    call-next-method dup buttons>> clone >>buttons ;
+
+SYMBOLS:
+    pov-neutral
+    pov-up pov-up-left pov-left pov-down-left
+    pov-down pov-down-right pov-right pov-up-right ;
+
+HOOK: get-controllers game-input-backend ( -- sequence )
+
+HOOK: manufacturer game-input-backend ( controller -- string )
+HOOK: product game-input-backend ( controller -- string )
+HOOK: vendor-id game-input-backend ( controller -- integer )
+HOOK: product-id game-input-backend ( controller -- integer )
+HOOK: location-id game-input-backend ( controller -- integer )
+
+HOOK: read-controller game-input-backend ( controller -- controller-state )
+HOOK: calibrate-controller game-input-backend ( controller -- )
+
+TUPLE: keyboard-state keys ;
+
+M: keyboard-state clone
+    call-next-method dup keys>> clone >>keys ;
+
+HOOK: read-keyboard game-input-backend ( -- keyboard-state )
index 79c3516b4e0ad3d2adc0cd8b89abb874c5730115..11ba5d3687c99c920c5da94c2b9112caf44a2aa2 100644 (file)
@@ -20,8 +20,8 @@ IN: iokit.hid
 : kIOHIDPrimaryUsageKey               "PrimaryUsage" ; inline
 : kIOHIDPrimaryUsagePageKey           "PrimaryUsagePage" ; inline
 : kIOHIDMaxInputReportSizeKey         "MaxInputReportSize" ; inline
-: kIOHIDMaxOutputReportSizeKey       "MaxOutputReportSize" ; inline
-: kIOHIDMaxFeatureReportSizeKey              "MaxFeatureReportSize" ; inline
+: kIOHIDMaxOutputReportSizeKey       "MaxOutputReportSize" ; inline
+: kIOHIDMaxFeatureReportSizeKey       "MaxFeatureReportSize" ; inline
 : kIOHIDReportIntervalKey             "ReportInterval" ; inline
 
 : kIOHIDElementKey                    "Elements" ; inline
@@ -77,7 +77,7 @@ IN: iokit.hid
 : kIOHIDElementTypeFeature           257 ; inline
 : kIOHIDElementTypeCollection        513 ; inline
 
-: kIOHIDElementCollectionTypePhysical      HEX: 00 ; inline
+: kIOHIDElementCollectionTypePhysical     HEX: 00 ; inline
 : kIOHIDElementCollectionTypeApplication    HEX: 01 ; inline
 : kIOHIDElementCollectionTypeLogical        HEX: 02 ; inline
 : kIOHIDElementCollectionTypeReport         HEX: 03 ; inline
@@ -90,10 +90,10 @@ IN: iokit.hid
 : kIOHIDReportTypeFeature  2 ; inline
 : kIOHIDReportTypeCount    3 ; inline
 
-: kIOHIDOptionsTypeNone               HEX: 00 ; inline
+: kIOHIDOptionsTypeNone        HEX: 00 ; inline
 : kIOHIDOptionsTypeSeizeDevice HEX: 01 ; inline
 
-: kIOHIDQueueOptionsTypeNone      HEX: 00 ; inline
+: kIOHIDQueueOptionsTypeNone    HEX: 00 ; inline
 : kIOHIDQueueOptionsTypeEnqueueAll HEX: 01 ; inline
 
 : kIOHIDElementFlagsConstantMask        HEX: 0001 ; inline
@@ -269,3 +269,4 @@ FUNCTION: IOHIDValueRef IOHIDTransactionGetValue ( IOHIDTransactionRef transacti
 FUNCTION: IOReturn IOHIDTransactionCommit ( IOHIDTransactionRef transaction ) ;
 FUNCTION: IOReturn IOHIDTransactionCommitWithCallback ( IOHIDTransactionRef transaction, CFTimeInterval timeout, IOHIDCallback callback, void* context ) ;
 FUNCTION: void IOHIDTransactionClear ( IOHIDTransactionRef transaction ) ;
+