SCDoc: Use proper static string constants instead of comparing string literals.
[supercollider.git] / SCClassLibrary / Platform / linux / LID.sc
blob259a2ab1b136eef4450864e35de68a9247d2fb8e
1 LIDInfo {
2         var <name, <bustype, <vendor, <product, <version, <physical, <unique;
4         printOn { | stream |
5                 super.printOn(stream);
6                 stream << $( << name << ", ";
7                 [
8                         bustype,
9                         vendor,
10                         product,
11                         version,
13                 ].collect({ | x | "0x" ++ x.asHexString(4) }).printItemsOn(stream);
14                 stream << ", " << physical << ", " << unique;
15                 stream.put($));
16         }
19 LIDAbsInfo {
20         var <value = 0, <min = 0, <max = 0, <fuzz = 0, <flat = 0;
22         printOn { | stream |
23                 stream
24                 << this.class.name << $(
25                 << "value: " << value << ", "
26                 << "min: " << min << ", "
27                 << "max: " << max << ", "
28                 << "fuzz: " << fuzz << ", "
29                 << "flat: " << flat << $)
30         }
33 LID {
34         var dataPtr, <path, <info, <caps, <spec, <slots, <isGrabbed=false, <>action;
35         var <>closeAction;
36         classvar all, eventTypes, <>specs, <>deviceRoot = "/dev/input", deviceList;
37         classvar < eventLoopIsRunning = true;
39         *initClass {
40                 all = [];
41                 specs = IdentityDictionary.new;
42                 eventTypes = [
43                         // maps event type (index) to max code value
44                         0x0001,         // EV_SYN
45                         0x02ff,         // EV_KEY
46                         0x000f,         // EV_REL
47                         0x003f,         // EV_ABS
48                         0x0007,         // EV_MSC
49                         0x000f,     // EV_SW (switch) added by nescivi
51                         nil, nil, nil,
52                         nil, nil, nil, nil,
53                         nil, nil, nil, nil,
55                         0x000f,         // EV_LED
56                         0x0007,         // EV_SND
58                         nil,
60                         0x0001,         // EV_REP
61                         0x007f,         // EV_FF
62                         0x0000,         // EV_PWR
63                         0x0001,         // EV_FF_STATUS
65                         nil, nil, nil, nil,
66                         nil, nil, nil
67                 ];
68                 ShutDown.add {
69                         this.closeAll;
70                         this.prStopEventLoop;
71                 };
72                 this.prStartEventLoop;
73         }
75         *buildDeviceTable{ |name|
76                 "WARNING: buildDeviceTable is obsolete, please use buildDeviceList".postln;
77                 ^LID.buildDeviceList( name );
78         }
80         *deviceTable{
81                 "WARNING: deviceTable is obsolete, please use deviceList".postln;
82                 ^deviceList;
83         }
85         *deviceList{
86                 ^deviceList;
87         }
89         *buildDeviceList{ |name|
90                 var table, devices, d, open;
91                 name = name ? "event";
92                 devices = (deviceRoot++"/"++name++"*").pathMatch;
93                 deviceList = Array.fill( devices.size, 0 );
94                 devices.do{ |it,i|
95                         open = false;
96                         if ( all.detect({ | dev | dev.path == it }).notNil,
97                                 {open = true});
98                         d = try { LID( it ) };
99                         if ( d != nil,
100                                 {
101                                         deviceList[i] = [ it, d.info, d.slots ];
102                                         if ( open.not,
103                                                 {d.close});
104                                 },
105                                 {
106                                         deviceList[i] = [ it, "could not open device" ];
107                                 });
108                 };
109                 ^deviceList;
110         }
112         *mouseDeviceSpec {
113                 ^(
114                         // key
115                         b1: #[0x0001, 0x0110],  // left button
116                         b2: #[0x0001, 0x0111],  // middle button
117                         b3: #[0x0001, 0x0112],  // right button
118                         // rel
119                         x: #[0x0002, 0x0000],   // x axis
120                         y: #[0x0002, 0x0001],   // y axis
121                         s: #[0x0002, 0x0008]    // scroll wheel
122                 )
123         }
124         *keyboardDeviceSpec {
125                 ^(
126                         esc: [1, 1],
127                         one:  [1, 2], two: [1, 3], three: [1, 4], four: [1, 5],
128                         five: [1, 6], six: [1, 7], seven: [1, 8], eight: [1, 9],
129                         nine: [1, 10], zero: [1, 11], minus: [1, 12], equal: [1, 13],
130                         backspace: [1, 14],
131                         tab: [1, 15], q: [1, 16], w: [1, 17], e: [1, 18],
132                         r: [1, 19], t: [1, 20], y: [1, 21], u: [1, 22], i: [1, 23],
133                         o: [1, 24], p: [1, 25], leftbrace: [1, 26], rightbrace: [1, 27],
134                         enter: [1, 28],
135                         leftctrl: [1, 29],
136                         a: [1, 30], s: [1, 31], d: [1, 32], f: [1, 33], g: [1, 34],
137                         h: [1, 35], j: [1, 36], k: [1, 37], l: [1, 38], semicolon: [1, 39],
138                         apostrophe: [1, 40],
139                         grave: [1, 41],
140                         leftshift: [1, 42],
141                         backslash: [1, 43],
142                         z: [1, 44], x: [1, 45], c: [1, 46], v: [1, 47], b: [1, 48],
143                         n: [1, 49], m: [1, 50], comma: [1, 51], dot: [1, 52],
144                         slash: [1, 53], rightshift: [1, 54],
145                         kpasterisk: [1, 55],
146                         leftalt: [1, 56], space: [1, 57], capslock: [1, 58],
147                         f1: [1, 59], f2: [1, 60], f3: [1, 61], f4: [1, 62],
148                         f5: [1, 63], f6: [1, 64], f7: [1, 65], f8: [1, 66],
149                         f9: [1, 67], f10: [1, 68], numlock: [1, 69], scrolllock: [1, 70],
150                         kp7: [1, 71], kp8: [1, 72], kp9: [1, 73], kpminus: [1, 74],
151                         kp4: [1, 75], kp5: [1, 76], kp6: [1, 77], kpplus: [1, 78],
152                         kp1: [1, 79], kp2: [1, 80], kp3: [1, 81],
153                         kp0: [1, 82], kpdot: [1, 83],
154                         zenkakuhankaku: [1, 85],
155                         the102nd: [1, 86],
156                         f11: [1, 87],
157                         f12: [1, 88],
158                         ro: [1, 89],
159                         katakana: [1, 90],
160                         hiragana: [1, 91],
161                         henkan: [1, 92],
162                         katakanahiragana: [1, 93],
163                         muhenkan: [1, 94],
164                         kpjpcomma: [1, 95],
165                         kpenter: [1, 96],
166                         rightctrl: [1, 97],
167                         kpslash: [1, 98],
168                         sysrq: [1, 99],
169                         rightalt: [1, 100],
170                         linefeed: [1, 101],
171                         home: [1, 102],
172                         up: [1, 103],
173                         pageup: [1, 104],
174                         left: [1, 105],
175                         right: [1, 106],
176                         end: [1, 107],
177                         down: [1, 108],
178                         pagedown: [1, 109],
179                         insert: [1, 110],
180                         delete: [1, 111],
181                         macro: [1, 112],
182                         mute: [1, 113],
183                         volumedown: [1, 114],
184                         volumeup: [1, 115],
185                         power: [1, 116],
186                         kpequal: [1, 117],
187                         kpplusminus: [1, 118],
188                         pause: [1, 119],
189                         kpcomma: [1, 121],
190                         hanguel: [1, 122],
191                         hanja: [1, 123],
192                         yen: [1, 124],
193                         leftmeta: [1, 125],
194                         rightmeta: [1, 126],
195                         compose: [1, 127],
196                         stop: [1, 128],
197                         again: [1, 129],
198                         props: [1, 130],
199                         undo: [1, 131],
200                         front: [1, 132],
201                         copy: [1, 133],
202                         open: [1, 134],
203                         paste: [1, 135],
204                         find: [1, 136],
205                         cut: [1, 137],
206                         help: [1, 138],
207                         menu: [1, 139],
208                         calc: [1, 140],
209                         setup: [1, 141],
210                         sleep: [1, 142],
211                         wakeup: [1, 143],
212                         file: [1, 144],
213                         sendfile: [1, 145],
214                         deletefile: [1, 146],
215                         xfer: [1, 147],
216                         prog1: [1, 148],
217                         prog2: [1, 149],
218                         www: [1, 150],
219                         msdos: [1, 151],
220                         coffee: [1, 152],
221                         direction: [1, 153],
222                         cyclewindows: [1, 154],
223                         mail: [1, 155],
224                         bookmarks: [1, 156],
225                         computer: [1, 157],
226                         back: [1, 158],
227                         forward: [1, 159],
228                         closecd: [1, 160],
229                         ejectcd: [1, 161],
230                         ejectclosecd: [1, 162],
231                         nextsong: [1, 163],
232                         playpause: [1, 164],
233                         previoussong: [1, 165],
234                         stopcd: [1, 166],
235                         record: [1, 167],
236                         rewind: [1, 168],
237                         phone: [1, 169],
238                         iso: [1, 170],
239                         config: [1, 171],
240                         homepage: [1, 172],
241                         refresh: [1, 173],
242                         exit: [1, 174],
243                         move: [1, 175],
244                         edit: [1, 176],
245                         scrollup: [1, 177],
246                         scrolldown: [1, 178],
247                         kpleftparen: [1, 179],
248                         kprightparen: [1, 180],
249                         new: [1, 181],
250                         redo: [1, 182],
251                         f13: [1, 183],
252                         f14: [1, 184],
253                         f15: [1, 185],
254                         f16: [1, 186],
255                         f17: [1, 187],
256                         f18: [1, 188],
257                         f19: [1, 189],
258                         f20: [1, 190],
259                         f21: [1, 191],
260                         f22: [1, 192],
261                         f23: [1, 193],
262                         f24: [1, 194],
263                         playcd: [1, 200],
264                         pausecd: [1, 201],
265                         prog3: [1, 202],
266                         prog4: [1, 203],
267                         suspend: [1, 205],
268                         close: [1, 206],
269                         play: [1, 207],
270                         fastforward: [1, 208],
271                         bassboost: [1, 209],
272                         print: [1, 210],
273                         hp: [1, 211],
274                         camera: [1, 212],
275                         sound: [1, 213],
276                         question: [1, 214],
277                         email: [1, 215],
278                         chat: [1, 216],
279                         search: [1, 217],
280                         connect: [1, 218],
281                         finance: [1, 219],
282                         sport: [1, 220],
283                         shop: [1, 221],
284                         alterase: [1, 222],
285                         cancel: [1, 223],
286                         brightnessdown: [1, 224],
287                         brightnessup: [1, 225],
288                         media: [1, 226],
289                         switchvideomode: [1, 227],
290                         kbdillumtoggle: [1, 228],
291                         kbdillumdown: [1, 229],
292                         kbdillumup: [1, 230],
293                         send: [1, 231],
294                         reply: [1, 232],
295                         forwardmail: [1, 233],
296                         save: [1, 234],
297                         documents: [1, 235]
298                 )
299         }
300         *all {
301                 ^all.copy
302         }
303         *closeAll {
304                 all.copy.do({ | dev | dev.close });
305         }
306         *register { | name, spec |
307                 specs[name] = spec;
308         }
309         *new { | path |
310                 path = PathName(path);
311                 if (path.isRelativePath) {
312                         path = (deviceRoot ++ "/" ++ path.fullPath).standardizePath
313                 }{
314                         path = path.fullPath;
315                 };
316                 ^all.detect({ | dev | dev.path == path }) ?? { super.new.prInit(path) }
317         }
318         isOpen {
319                 ^dataPtr.notNil
320         }
321         close {
322                 if (this.isOpen) {
323                         this.prClose;
324                         all.remove(this);
325                 };
326         }
327         dumpCaps {
328                 caps.keys.do { | evtType |
329                         Post << "0x" << evtType.asHexString << ":\n";
330                         caps[evtType].do { | evtCode |
331                                 Post << $\t << "0x" << evtCode.asHexString << "\n";
332                         }
333                 }
334         }
335         dumpEvents {
336                 action = { | evtType, evtCode, value |
337                         [evtType.asHexString, evtCode.asHexString, value].postln;
338                 }
339         }
340         slot { | evtType, evtCode |
341                 ^slots.atFail(evtType, {
342                         Error("event type not supported").throw
343                 }).atFail(evtCode, {
344                         Error("event code not supported").throw
345                 })
346         }
347         at { | controlName |
348                 ^this.slot(*spec.atFail(controlName, {
349                         Error("invalid control name").throw
350                 }))
351         }
352         getAbsInfo { | evtCode |
353                 ^this.prGetAbsInfo(evtCode, LIDAbsInfo.new)
354         }
355         getKeyState { | evtCode |
356                 ^this.prGetKeyState(evtCode)
357         }
358         getLEDState { | evtCode |
359                 ^0
360         }
361         setLEDState { |evtCode, evtValue |
362                 ^this.prSetLedState( evtCode, evtValue )
363         }
364         setMSCState { |evtCode, evtValue |
365                 ^this.prSetMscState( evtCode, evtValue )
366         }
367         grab { | flag = true |
368                 // useful when using mouse or keyboard. be sure to have an
369                 // 'exit point', or your desktop will be rendered useless ...
370                 if (isGrabbed != flag) {
371                         this.prGrab(flag);
372                         isGrabbed = flag;
373                 };
374         }
375         ungrab {
376                 this.grab(false)
377         }
379         // PRIVATE
380         *prStartEventLoop {
381                 _LID_Start
382                 ^this.primitiveFailed
383         }
384         *prStopEventLoop {
385                 _LID_Stop
386                 ^this.primitiveFailed
387         }
388         prInit { | argPath |
389                 this.prOpen(argPath);
390                 all = all.add(this);
391                 closeAction = {};
392                 path = argPath;
393                 info = this.prGetInfo(LIDInfo.new);
394                 spec = specs.atFail(info.name, { IdentityDictionary.new });
395                 caps = IdentityDictionary.new;
396                 slots = IdentityDictionary.new;
397                 eventTypes.do { | evtTypeMax, evtType |
398                         // nescivi: below was evtType.notNil, but since that is the index, that makes no sense... however evtTypeMax can be nil, and should be skipped if it is... so I'm changing it.
399                         if (evtTypeMax.notNil and: { this.prEventTypeSupported(evtType) }) {
400                                 caps[evtType] = List.new;
401                                 slots[evtType] = IdentityDictionary.new;
402                                 for (0, evtTypeMax, { | evtCode |
403                                         if (this.prEventCodeSupported(evtType, evtCode)) {
404                                                 caps[evtType].add(evtCode);
405                                                 slots[evtType][evtCode] = LIDSlot.new(
406                                                         this, evtType, evtCode
407                                                 );
408                                         };
409                                 });
410                                 caps[evtType].sort;
411                         }
412                 };
413         }
414         prOpen { | path |
415                 _LID_Open
416                 ^this.primitiveFailed
417         }
418         prClose {
419                 _LID_Close
420                 ^this.primitiveFailed
421         }
422         prEventTypeSupported { | evtType |
423                 _LID_EventTypeSupported
424                 ^this.primitiveFailed
425         }
426         prEventCodeSupported { | evtType, evtCode |
427                 _LID_EventCodeSupported
428                 ^this.primitiveFailed
429         }
430         prGetInfo { | info |
431                 _LID_GetInfo
432                 ^this.primitiveFailed
433         }
434         prGetKeyState { | evtCode |
435                 _LID_GetKeyState
436                 ^this.primitiveFailed
437         }
438         prGetAbsInfo { | evtCode, absInfo |
439                 _LID_GetAbsInfo
440                 ^this.primitiveFailed
441         }
442         prGrab { | flag |
443                 _LID_Grab
444                 ^this.primitiveFailed
445         }
446         prHandleEvent { | evtType, evtCode, evtValue |
447                 // not either or for the device action. Do slot actions in any case:
448                 slots[evtType][evtCode].value_(evtValue);
449                 // event callback
450                 if (action.notNil) {
451                         action.value(evtType, evtCode, evtValue, slots[evtType][evtCode].value);
452                 };
453         }
455         // this prevents a high cpu cycle when device was detached; added by marije
456         prReadError{
457                 this.close;
458                 ("WARNING: Device was removed: " + this.path + this.info).postln;
459                 closeAction.value;
460         }
462         prSetLedState { |evtCode, evtValue|     // added by Marije Baalman
463                 // set LED value
464                 _LID_SetLedState
465                 ^this.primitiveFailed
466         }
467         prSetMscState { |evtCode, evtValue|
468                 // set MSC value
469                 _LID_SetMscState
470                 ^this.primitiveFailed
471         }
474 LIDSlot {
475         var <device, <type, <code, value=0, <spec, <>action;
476         classvar slotTypeMap, <slotTypeStrings;
478         *initClass {
479                 slotTypeMap = IdentityDictionary.new.addAll([
480                         0x0001 -> LIDKeySlot,
481                         0x0002 -> LIDRelSlot,
482                         0x0003 -> LIDAbsSlot,
483                         0x0011 -> LIDLedSlot
484                 ]);
485                 slotTypeStrings = IdentityDictionary.new.addAll([
486                         0x0000 -> "Syn",
487                         0x0001 -> "Button",
488                         0x0002 -> "Relative",
489                         0x0003 -> "Absolute",
490                         0x0004 -> "MSC",
491                         0x0011 -> "LED",
492                         0x0012 -> "Sound",
493                         0x0014 -> "Rep",
494                         0x0015 -> "Force Feedback",
495                         0x0016 -> "Power",
496                         0x0017 -> "Force Feedback Status"
497                 ]);
498         }
499         *new { | device, evtType, evtCode |
500                 ^(slotTypeMap[evtType] ? this).newCopyArgs(device, evtType, evtCode).initSpec
501         }
502         initSpec {
503                 spec = ControlSpec(0, 1, \lin, 1, 0);
504         }
505         rawValue {
506                 ^value
507         }
508         value {
509                 ^spec.unmap(value)
510         }
511         value_ { | rawValue |
512                 value = rawValue;
513                 action.value(this);
514         }
515         next {
516                 ^this.value
517         }
520 LIDKeySlot : LIDSlot {
521         initSpec {
522                 super.initSpec;
523                 value = device.getKeyState(code);
524         }
527 LIDRelSlot : LIDSlot {
528         var delta, <>deltaAction;
530         initSpec { }
531         value { ^value }
532         value_ { | dta |
533                 delta = dta;
534                 value = value + delta;
535                 action.value(this);
536                 deltaAction.value(this);
537         }
539         delta { ^delta }
542 LIDLedSlot : LIDSlot {
544         initSpec { }
545         value { ^value }
546         value_ { | v |
547                 value = v;
548                 device.setLEDState( code, value );
549                 action.value(this);
550         }
553 LIDAbsSlot : LIDSlot {
554         var <info;
556         initSpec {
557                 info = device.getAbsInfo(code);
558                 spec = ControlSpec(info.min, info.max, \lin, 1);
559                 spec.default = spec.map(0.5).asInteger;
560                 value = info.value;
561         }
564 // EOF