2 classvar <>all, <>verbose=false;
3 classvar <scheme, <schemes;
6 schemes = IdentityDictionary.new;
9 *new { arg key; ^scheme.perform( key )}
16 ^schemes[ id.asSymbol ];
23 *use { arg aScheme, func;
26 ^func.protect({ scheme = recent });
29 *useID { arg id, func;
30 ^this.use( schemes[ id.asSymbol ], func );
33 *open { |dev| ^scheme.open(dev); }
35 // maybe better define interface here instead,
36 // rather than doesNotUnderstand.
37 *doesNotUnderstand { arg selector ... args;
38 // ["GeneralHID forwarding to scheme:", selector, args].postln;
39 ^scheme.performList( selector, args );
47 schemes.put( aScheme.id, aScheme );
48 if( scheme.isNil, { // first registration = first default kit
51 scheme = schemes[ scheme.id ]; // in case we are updating an existing scheme
56 var newScheme = schemes[ id.asSymbol ];
57 if( newScheme.notNil, {
60 if(thisProcess.platform.name != \windows){ // on win we know it's not yet supported
61 ("GeneralHID.fromID : The HID scheme '" ++ id ++ "' is not installed\n" ++
62 "The current scheme is still '" ++ if( scheme.notNil, { scheme.id }) ++ "'!").warn;
67 // find a device by its info properties
68 *findBy { |vendorID, productID, locID, versionID|
69 if ( locID.isKindOf( String ), { locID = locID.asSymbol } );
70 ^this.deviceList.detect { |pair|
71 var dev, info; #dev, info = pair;
72 (info.vendor == vendorID)
73 and: { productID.isNil or: { info.product == productID } }
74 and: { locID.isNil or: { info.physical == locID } }
75 and: { versionID.isNil or: { info.version == versionID } }
81 var <name, <bustype, <vendor, <product, <version, <physical, <unique;
83 *new{arg name="", bustype=0, vendor=0, product=0, version=0, physical=0, unique=0;
84 ^super.newCopyArgs( name, bustype, vendor, product, version, physical, unique ).init;
91 ^[ vendor, product, physical, version ];
95 super.printOn(stream);
96 stream << $( << name << ", ";
97 // " VendorID: " << vendor << ", ProductID: " << product << ", locID: " << physical << ", version: " << version << $);
103 ].collect({ | x | "0x" ++ x.asHexString(4) }).printItemsOn(stream);
104 stream << ", " << physical << ", " << unique;
116 // specs = IdentityDictionary.new;
122 all.copy.do({ | dev | dev.close });
124 /* *register { | name, spec |
128 ^all.detect({ | dev | dev.device == newDevice }) ?? { super.new.init(newDevice) }
132 slots = device.getSlots;
133 info = device.getInfo;
134 spec = GeneralHIDSpec.new( this );
146 debug_{ |onoff,allslots=true|
147 device.class.debug_( onoff );
148 // is this necessary? to also turn on/off all the slot debugging?
151 sl.do{ |slt| slt.debug_( onoff ) }
158 sl.do{ |slt| "\t".post; slt.asString.postln; } };
167 hidDeviceAction_{ |func|
168 device.hidDeviceAction = func;
172 ^device.hidDeviceAction;
181 spec.fromFile( name );
185 spec.add( key, slot );
201 spec.value_( key, value );
204 action_{ |key,action|
205 if ( (key.class == Function) and: action.isNil,{
208 spec.action_( key, action );
212 createBus{ |name,server|
213 spec.createBus( name, server );
217 spec.freeBus( name );
220 createAllBuses{ |server|
221 spec.createAllBuses( server );
229 ^GeneralHIDDeviceGUI.new( this );
236 var <type, <id, <device, <devSlot;
239 var <bus, <busAction;
244 // typeMap is modeled after Linux input system.
245 // to get the Mac work in a similar way, some tricks will be needed
246 typeMap = IdentityDictionary.new.addAll([
249 0x0002 -> "Relative",
250 0x0003 -> "Absolute",
251 0x0004 -> "Miscellaneous",
255 0x0015 -> "Force Feedback",
257 0x0017 -> "Force Feedback Status",
262 *new{ |type,id,device,devSlot|
263 ^super.newCopyArgs( type, id, device, devSlot ).init;
270 devSlot.action = { |v| this.debugAction.value(v); this.busAction.value(v); this.action.value(v) };
287 // this.action_({ |slot| [ slot.type, slot.code, slot.value, key ].postln; });
288 this.debugAction_({ |slot| [ slot.type, slot.code, slot.value, key ].postln; });
291 this.debugAction_({});
295 debugAction_{ |actionFunc|
296 debugAction = actionFunc;
299 action_{ |actionFunc|
301 // devSlot.action = { |v| this.action.value(v); this.busAction.value(v); this.debugAction.value(v) };
305 s = s ? Server.default;
307 bus = Bus.control( s, 1 );
309 if ( bus.index.isNil, {
310 bus = Bus.control( s, 1 );
313 /* if ( s.serverRunning.not and: s.isLocal, {
314 "Server seems not running, so bus will be invalid".warn;
316 busAction = { |v| bus.set( v.value ); };
317 // devSlot.action = { |v| action.value(v); busAction.value(v); };
327 << this.class.name << $(
328 << this.class.typeMap[type] << ", "
329 << "type: " << type << ", "
330 << "id: " << id << ", "
331 << "value: " << this.value << $)