2 /*----------------------------------------------------------------------------
3 ChucK Concurrent, On-the-fly Audio Programming Language
4 Compiler and Virtual Machine
6 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
7 http://chuck.cs.princeton.edu/
8 http://soundlab.cs.princeton.edu/
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
24 -----------------------------------------------------------------------------*/
26 //-----------------------------------------------------------------------------
27 // file: hidio_sdl.cpp
28 // desc: HID io over SDL
30 // author: Spencer Salazar (ssalazar@cs.princeton.edu)
31 // Ge Wang (gewang@cs.princeton.edu)
32 // Ananya Misra (amisra@cs.princeton.edu)
33 // Perry R. Cook (prc@cs.princeton.edu)
35 //-----------------------------------------------------------------------------
36 #include "hidio_sdl.h"
38 #include "chuck_errmsg.h"
40 #ifndef __PLATFORM_WIN32__
43 #include "chuck_def.h"
51 Chuck_Hid_Driver
* default_drivers
= NULL
;
58 t_CKBOOL
open( t_CKINT type
, t_CKUINT number
);
59 t_CKBOOL
read( t_CKINT element_type
, t_CKINT element_num
, HidMsg
* msg
);
60 t_CKBOOL
send( const HidMsg
* msg
);
64 t_CKBOOL
query_element( HidMsg
* query
);
66 t_CKBOOL
register_client( HidIn
* client
);
67 t_CKBOOL
unregister_client( HidIn
* client
);
70 CBufferAdvance
* cbuf
;
76 std::vector
< HidIn
* > clients
;
86 //-----------------------------------------------------------------------------
88 //-----------------------------------------------------------------------------
89 // per-physical device buffer size
90 #define BUFFER_SIZE 8192
92 std::vector
< std::vector
<PhyHidDevIn
*> > HidInManager::the_matrix
;
93 XThread
* HidInManager::the_thread
= NULL
;
94 t_CKBOOL
HidInManager::thread_going
= FALSE
;
95 t_CKBOOL
HidInManager::has_init
= FALSE
;
96 CBufferSimple
* HidInManager::msg_buffer
= NULL
;
97 std::vector
<PhyHidDevOut
*> HidOutManager::the_phouts
;
99 //-----------------------------------------------------------------------------
100 // name: PhyHidDevIn()
102 //-----------------------------------------------------------------------------
103 PhyHidDevIn::PhyHidDevIn()
105 device_type
= CK_HID_DEV_NONE
;
111 //-----------------------------------------------------------------------------
112 // name: ~PhyHidDevIn()
114 //-----------------------------------------------------------------------------
115 PhyHidDevIn::~PhyHidDevIn()
118 if( device_type
!= CK_HID_DEV_NONE
)
123 //-----------------------------------------------------------------------------
125 // desc: opens the device of specified type and id
126 //-----------------------------------------------------------------------------
127 t_CKBOOL
PhyHidDevIn::open( t_CKINT type
, t_CKUINT number
)
132 if( device_type
!= CK_HID_DEV_NONE
)
135 EM_log( CK_LOG_WARNING
, "PhyHidDevIn: open() failed -> already open!" );
139 if( type
<= CK_HID_DEV_NONE
|| type
>= CK_HID_DEV_COUNT
)
142 EM_log( CK_LOG_WARNING
,
143 "PhyHidDevIn: open() failed -> invalid device type %d",
148 if( !default_drivers
[type
].open
)
150 EM_log( CK_LOG_WARNING
,
151 "PhyHidDevIn: open() failed -> %s does not support open",
152 default_drivers
[type
].driver_name
);
156 if( default_drivers
[type
].open( ( int ) number
) )
158 EM_log( CK_LOG_WARNING
,
159 "PhyHidDevIn: open() failed -> invalid %s number %d",
160 default_drivers
[type
].driver_name
,
165 // allocate the buffer
166 cbuf
= new CBufferAdvance
;
167 if( !cbuf
->initialize( BUFFER_SIZE
, sizeof(HidMsg
) ) )
170 EM_log( CK_LOG_WARNING
, "PhyHidDevIn: open operation failed: cannot initialize buffer" );
181 //-----------------------------------------------------------------------------
183 // desc: query specific elements of the hid device
184 //-----------------------------------------------------------------------------
185 t_CKBOOL
PhyHidDevIn::read( t_CKINT element_type
, t_CKINT element_num
, HidMsg
* msg
)
187 if( !default_drivers
[device_type
].read
)
189 EM_log( CK_LOG_WARNING
,
190 "PhyHidDevIn: read() failed -> %s does not support read",
191 default_drivers
[device_type
].driver_name
);
195 if( default_drivers
[device_type
].read( device_num
, element_type
,
198 EM_log( CK_LOG_WARNING
,
199 "PhyHidDevIn: read() failed for %s %i, element type %i, element number %i",
200 default_drivers
[device_type
].driver_name
, device_num
,
201 element_type
, element_num
);
208 //-----------------------------------------------------------------------------
210 // desc: send message to a HID device
211 //-----------------------------------------------------------------------------
212 t_CKBOOL
PhyHidDevIn::send( const HidMsg
* msg
)
214 if( !default_drivers
[device_type
].send
)
216 EM_log( CK_LOG_WARNING
,
217 "PhyHidDevIn: send() failed -> %s does not support send",
218 default_drivers
[device_type
].driver_name
);
222 if( default_drivers
[device_type
].send( device_num
, msg
) )
224 EM_log( CK_LOG_WARNING
,
225 "PhyHidDevIn: send() failed for %s %i",
226 default_drivers
[device_type
].driver_name
, device_num
);
233 //-----------------------------------------------------------------------------
235 // desc: closes the device, deallocates all associated data
236 //-----------------------------------------------------------------------------
237 t_CKBOOL
PhyHidDevIn::close()
244 // TODO: release references from cbuf?
247 if( device_type
<= CK_HID_DEV_NONE
|| device_type
>= CK_HID_DEV_COUNT
)
250 EM_log( CK_LOG_WARNING
,
251 "PhyHidDevIn: close() failed -> invalid device type %d",
256 if( !default_drivers
[device_type
].close
)
258 EM_log( CK_LOG_WARNING
,
259 "PhyHidDevIn: close() failed -> %s does not support close",
260 default_drivers
[device_type
].driver_name
);
264 if( default_drivers
[device_type
].close( ( int ) device_num
) )
266 EM_log( CK_LOG_WARNING
,
267 "PhyHidDevIn: close() failed -> invalid %s number %d",
268 default_drivers
[device_type
].driver_name
,
273 device_type
= CK_HID_DEV_NONE
;
279 //-----------------------------------------------------------------------------
281 // desc: retrieve device name
282 //-----------------------------------------------------------------------------
283 string
PhyHidDevIn::name()
285 if( device_type
== CK_HID_DEV_NONE
)
288 if( device_type
<= CK_HID_DEV_NONE
|| device_type
>= CK_HID_DEV_COUNT
)
291 EM_log( CK_LOG_WARNING
,
292 "PhyHidDevIn: name() failed -> invalid device type %d",
297 if( !default_drivers
[device_type
].name
)
298 return default_drivers
[device_type
].driver_name
;
302 if( !( _name
= default_drivers
[device_type
].name( ( int ) device_num
) ) )
304 EM_log( CK_LOG_WARNING
,
305 "PhyHidDevIn: name() failed -> invalid %s number %d",
306 default_drivers
[device_type
].driver_name
,
314 //-----------------------------------------------------------------------------
317 //-----------------------------------------------------------------------------
320 // phout = new PhyHidDevOut;
323 m_suppress_output
= FALSE
;
329 //-----------------------------------------------------------------------------
332 //-----------------------------------------------------------------------------
335 if( phout
) this->close();
336 SAFE_DELETE( phout
);
342 //-----------------------------------------------------------------------------
345 //-----------------------------------------------------------------------------
346 t_CKUINT
HidOut::send( const HidMsg
* msg
)
348 if( !m_valid
) return 0;
356 //-----------------------------------------------------------------------------
358 // desc: open HID output
359 //-----------------------------------------------------------------------------
360 t_CKBOOL
HidOut::open( t_CKUINT device_num
)
362 // close if already opened
366 return m_valid
= HidOutManager::open( this, (t_CKINT
)device_num
);
372 //-----------------------------------------------------------------------------
374 // desc: close HID output
375 //-----------------------------------------------------------------------------
376 t_CKBOOL
HidOut::close( )
382 // HidOutManager::close( this );
392 //-----------------------------------------------------------------------------
395 //-----------------------------------------------------------------------------
403 m_suppress_output
= FALSE
;
410 //-----------------------------------------------------------------------------
413 //-----------------------------------------------------------------------------
417 // SAFE_DELETE( min );
423 //-----------------------------------------------------------------------------
426 //-----------------------------------------------------------------------------
427 t_CKBOOL
HidIn::open( t_CKINT device_type
, t_CKINT device_num
)
429 // close if already opened
434 return m_valid
= HidInManager::open( this, device_type
, device_num
);
440 void HidInManager::init()
442 if( has_init
== FALSE
)
445 EM_log( CK_LOG_INFO
, "initializing HID..." );
448 init_default_drivers();
450 // allocate the matrix
451 the_matrix
.resize( CK_HID_DEV_COUNT
);
452 // resize each vector
453 for( vector
<vector
<PhyHidDevIn
*> >::size_type i
= 0; i
< the_matrix
.size(); i
++ )
456 the_matrix
[i
].resize( CK_MAX_HID_DEVICES
);
459 msg_buffer
= new CBufferSimple
;
460 msg_buffer
->initialize( 1000, sizeof( HidMsg
) );
462 #ifndef __MACOSX_CORE__
464 #endif // __MACOSX_CORE__
466 for( size_t j
= 0; j
< CK_HID_DEV_COUNT
; j
++ )
468 if( default_drivers
[j
].init
)
469 default_drivers
[j
].init();
472 #ifdef __MACOSX_CORE__
474 if( the_thread
== NULL
)
477 the_thread
= new XThread
;
481 the_thread
->start( cb_hid_input
, NULL
);
491 void HidInManager::init_default_drivers()
493 default_drivers
= new Chuck_Hid_Driver
[CK_HID_DEV_COUNT
];
495 memset( default_drivers
, 0, CK_HID_DEV_COUNT
* sizeof( Chuck_Hid_Driver
) );
497 default_drivers
[CK_HID_DEV_JOYSTICK
].init
= Joystick_init
;
498 default_drivers
[CK_HID_DEV_JOYSTICK
].quit
= Joystick_quit
;
499 default_drivers
[CK_HID_DEV_JOYSTICK
].count
= Joystick_count
;
500 default_drivers
[CK_HID_DEV_JOYSTICK
].count_elements
= Joystick_count_elements
;
501 default_drivers
[CK_HID_DEV_JOYSTICK
].open
= Joystick_open
;
502 default_drivers
[CK_HID_DEV_JOYSTICK
].close
= Joystick_close
;
503 default_drivers
[CK_HID_DEV_JOYSTICK
].name
= Joystick_name
;
504 default_drivers
[CK_HID_DEV_JOYSTICK
].driver_name
= "joystick";
506 default_drivers
[CK_HID_DEV_MOUSE
].init
= Mouse_init
;
507 default_drivers
[CK_HID_DEV_MOUSE
].quit
= Mouse_quit
;
508 default_drivers
[CK_HID_DEV_MOUSE
].count
= Mouse_count
;
509 default_drivers
[CK_HID_DEV_MOUSE
].count_elements
= Mouse_count_elements
;
510 default_drivers
[CK_HID_DEV_MOUSE
].open
= Mouse_open
;
511 default_drivers
[CK_HID_DEV_MOUSE
].close
= Mouse_close
;
512 default_drivers
[CK_HID_DEV_MOUSE
].name
= Mouse_name
;
513 default_drivers
[CK_HID_DEV_MOUSE
].driver_name
= "mouse";
515 default_drivers
[CK_HID_DEV_KEYBOARD
].init
= Keyboard_init
;
516 default_drivers
[CK_HID_DEV_KEYBOARD
].quit
= Keyboard_quit
;
517 default_drivers
[CK_HID_DEV_KEYBOARD
].count
= Keyboard_count
;
518 default_drivers
[CK_HID_DEV_KEYBOARD
].count_elements
= Keyboard_count_elements
;
519 default_drivers
[CK_HID_DEV_KEYBOARD
].open
= Keyboard_open
;
520 default_drivers
[CK_HID_DEV_KEYBOARD
].close
= Keyboard_close
;
521 default_drivers
[CK_HID_DEV_KEYBOARD
].send
= Keyboard_send
;
522 default_drivers
[CK_HID_DEV_KEYBOARD
].name
= Keyboard_name
;
523 default_drivers
[CK_HID_DEV_KEYBOARD
].driver_name
= "keyboard";
525 default_drivers
[CK_HID_DEV_WIIREMOTE
].init
= WiiRemote_init
;
526 default_drivers
[CK_HID_DEV_WIIREMOTE
].quit
= WiiRemote_quit
;
527 default_drivers
[CK_HID_DEV_WIIREMOTE
].count
= WiiRemote_count
;
528 default_drivers
[CK_HID_DEV_WIIREMOTE
].open
= WiiRemote_open
;
529 default_drivers
[CK_HID_DEV_WIIREMOTE
].close
= WiiRemote_close
;
530 default_drivers
[CK_HID_DEV_WIIREMOTE
].send
= WiiRemote_send
;
531 default_drivers
[CK_HID_DEV_WIIREMOTE
].name
= WiiRemote_name
;
532 default_drivers
[CK_HID_DEV_WIIREMOTE
].driver_name
= "wii remote";
534 default_drivers
[CK_HID_DEV_TILTSENSOR
].init
= TiltSensor_init
;
535 default_drivers
[CK_HID_DEV_TILTSENSOR
].quit
= TiltSensor_quit
;
536 default_drivers
[CK_HID_DEV_TILTSENSOR
].count
= TiltSensor_count
;
537 default_drivers
[CK_HID_DEV_TILTSENSOR
].open
= TiltSensor_open
;
538 default_drivers
[CK_HID_DEV_TILTSENSOR
].close
= TiltSensor_close
;
539 default_drivers
[CK_HID_DEV_TILTSENSOR
].read
= TiltSensor_read
;
540 default_drivers
[CK_HID_DEV_TILTSENSOR
].name
= TiltSensor_name
;
541 default_drivers
[CK_HID_DEV_TILTSENSOR
].driver_name
= "tilt sensor";
544 void HidInManager::cleanup()
547 EM_log( CK_LOG_INFO
, "shutting down HID..." );
552 for( vector
<vector
<PhyHidDevIn
*> >::size_type i
= 0; i
< the_matrix
.size(); i
++ )
555 for( vector
<PhyHidDevIn
*>::size_type j
= 0; j
< the_matrix
[i
].size(); j
++ )
557 // deallocate devices
558 SAFE_DELETE( the_matrix
[i
][j
] );
563 thread_going
= FALSE
;
569 if( the_thread
!= NULL
)
570 SAFE_DELETE( the_thread
);
572 // clean up subsystems
573 for( size_t j
= 0; j
< CK_HID_DEV_COUNT
; j
++ )
575 if( default_drivers
[j
].quit
)
576 default_drivers
[j
].quit();
581 msg_buffer
->cleanup();
582 SAFE_DELETE( msg_buffer
);
592 t_CKBOOL
HidInManager::open( HidIn
* hin
, t_CKINT device_type
, t_CKINT device_num
)
595 if( has_init
== FALSE
)
601 if( device_type
< 1 || device_type
>= CK_HID_DEV_COUNT
)
604 EM_log( CK_LOG_WARNING
, "HidInManager: open() failed -> invalid type '%d'...",
610 if( the_thread
== NULL
)
613 the_thread
= new XThread
;
617 the_thread
->start( cb_hid_input
, NULL
);
621 vector
<PhyHidDevIn
*> & v
= the_matrix
[device_type
];
623 // see if port not already open
624 if( device_num
>= (t_CKINT
)v
.capacity() || !v
[device_num
] )
627 PhyHidDevIn
* phin
= new PhyHidDevIn
;
629 if( !phin
->open( device_type
, device_num
) )
632 // should this use EM_log instead, with a higher log level?
633 EM_error2( 0, "HidIn: couldn't open %s %d...",
634 default_drivers
[device_type
].driver_name
, device_num
);
640 if( device_num
>= (t_CKINT
)v
.capacity() )
642 t_CKINT size
= v
.capacity() * 2;
643 if( device_num
>= size
) size
= device_num
+ 1;
647 // put cbuf and rtmin in vector for future generations
648 v
[device_num
] = phin
;
652 hin
->phin
= v
[device_num
];
654 hin
->m_buffer
= v
[device_num
]->cbuf
;
655 // get an index into your (you are min here) own buffer,
656 // and a free ticket to your own workshop
657 hin
->m_read_index
= hin
->m_buffer
->join( (Chuck_Event
*)hin
->SELF
);
658 hin
->m_device_num
= (t_CKUINT
)device_num
;
664 //-----------------------------------------------------------------------------
667 //-----------------------------------------------------------------------------
668 t_CKBOOL
HidIn::close()
674 //HidInManager::close( this );
681 //-----------------------------------------------------------------------------
684 //-----------------------------------------------------------------------------
685 t_CKBOOL
HidIn::empty()
687 if( !m_valid
) return TRUE
;
688 return m_buffer
->empty( m_read_index
);
694 //-----------------------------------------------------------------------------
696 // desc: receive message
697 //-----------------------------------------------------------------------------
698 t_CKUINT
HidIn::recv( HidMsg
* msg
)
700 if( !m_valid
) return FALSE
;
701 return m_buffer
->get( msg
, 1, m_read_index
);
704 //-----------------------------------------------------------------------------
707 //-----------------------------------------------------------------------------
708 t_CKBOOL
HidIn::read( t_CKINT type
, t_CKINT num
, HidMsg
* msg
)
710 if( !m_valid
|| !phin
)
714 return phin
->read( type
, num
, msg
);
717 //-----------------------------------------------------------------------------
720 //-----------------------------------------------------------------------------
721 t_CKBOOL
HidIn::send( const HidMsg
* msg
)
723 if( !m_valid
|| !phin
)
727 return phin
->send( msg
);
730 //-----------------------------------------------------------------------------
732 // desc: get device name
733 //-----------------------------------------------------------------------------
734 std::string
HidIn::name()
736 if( m_valid
&& phin
)
741 //-----------------------------------------------------------------------------
742 // name: cb_hid_input
743 // desc: called by device implementations to push a message onto the buffer
744 //-----------------------------------------------------------------------------
745 void HidInManager::push_message( HidMsg
& msg
)
748 if( the_matrix
[msg
.device_type
][msg
.device_num
] != NULL
)
750 CBufferAdvance
* cbuf
= the_matrix
[msg
.device_type
][msg
.device_num
]->cbuf
;
753 cbuf
->put( &msg
, 1 );
757 extern "C" void push_message( HidMsg msg
)
759 HidInManager::push_message( msg
);
762 //-----------------------------------------------------------------------------
763 // name: cb_hid_input
765 //-----------------------------------------------------------------------------
766 #ifndef __PLATFORM_WIN32__
767 void * HidInManager::cb_hid_input( void * stuff
)
769 unsigned __stdcall
HidInManager::cb_hid_input( void * stuff
)
772 #ifdef __MACOSX_CORE__
777 while( thread_going
)
783 EM_log( CK_LOG_INFO
, "HID thread exiting..." );
788 //-----------------------------------------------------------------------------
789 // name: probeHidIn()
791 //-----------------------------------------------------------------------------
792 void HidInManager::probeHidIn()
794 t_CKBOOL do_cleanup
= !has_init
;
798 for( size_t i
= 0; i
< CK_HID_DEV_COUNT
; i
++ )
800 if( !default_drivers
[i
].count
)
803 int count
= default_drivers
[i
].count();
807 EM_error2b( 0, "------( chuck -- %i %s device%s )------",
808 count
, default_drivers
[i
].driver_name
,
809 count
> 1 ? "s" : "" );
811 for( int j
= 0; j
< count
; j
++ )
814 if( default_drivers
[i
].name
)
815 name
= default_drivers
[i
].name( j
);
819 EM_error2b( 0, " [%i] : \"%s\"", j
, name
);
831 //-----------------------------------------------------------------------------
832 // name: probeHidOut()
834 //-----------------------------------------------------------------------------
835 void HidInManager::probeHidOut()
840 HidOutManager::HidOutManager()
842 the_phouts
.resize( 1024 );
846 HidOutManager::~HidOutManager()
852 t_CKBOOL
HidOutManager::open( HidOut
* hout
, t_CKINT device_num
)
854 // see if port not already open
855 if( device_num
>= (t_CKINT
)the_phouts
.capacity() || !the_phouts
[device_num
] )
858 PhyHidDevOut
* phout
= new PhyHidDevOut
;
861 if( device_num
>= (t_CKINT
)the_phouts
.capacity() )
863 t_CKINT size
= the_phouts
.capacity() * 2;
864 if( device_num
>= size
) size
= device_num
+ 1;
865 the_phouts
.resize( size
);
868 // put rtmout in vector for future generations
869 the_phouts
[device_num
] = phout
;
872 // found (always) (except when it doesn't get here)
873 hout
->phout
= the_phouts
[device_num
];
874 hout
->m_device_num
= (t_CKUINT
)device_num
;