# Note: This talk is not due to be presented until 2003-06-18 at
# Birmingham Perl Mongers, so no peeking, m'kay

=meta consider_old 100

=meta link_base /~richardc/talks/dea/

=head1 Cool tricks with AT codes

=head2 With the power of my mind

=over

=item

L<image:Mind Control|mind_control.gif>

=item

I shall make music play

=item

I shall make it sunny outside

=item

I shall make this page magically change

=back


=head2 Okay, so I precanned my mind

=over

=item

I wrote a script which calls on L<Device::Ericsson::AccessoryMenu> to
allow me to trigger things from my phone.

=item

L<image:Connect|c_2.jpg>
L<image:Accessories|c_3.jpg>
L<image:XMMS Remote|c_7.jpg>

Images stolen from L<http://www.linuxbrit.net/bluexmms/>

=back


=head2 Clicker / Romeo

=over

=item 

Mac OS X applications

L<image:Clicker|SEC_Phone_Menu.gif>

=item

You write your actions in applescript

 try
   tell application "iTunes"
     try
       set the current_track to get current track
     on error
       error "No current track."
     end try
     set the track_count to (the count of tracks of the current playlist) as string
     next track
     try
       set this_track to get current track
     on error
       play current_track
       set this_track to the current_track
       play track 1 of current playlist
       set this_track to get current track
     end try
     set the track_index to (the index of this_track) as string
     set this_title to the name of this_track as string
     return (track_index & "/" & track_count & "  " & this_title)
   end tell
 on error error_message
   return error_message
 end try

That's how you tell iTunes to play the next track

=back


=head2 Two Drawbacks

=over

=item

This machine is not running Mac OS X

L<image:imacquarium|imacquarium.jpg>

=item

I don't speak applescript

=back


=head2 BlueXMMS

=over

=item

Ruby program that remote controls XMMS

=item

Grokable, but very entwined code

=item

So for the first version of my code I stole mostly from that,
splitting up the AT-slinging code from the actions

=back


=head2 A simple XMMS remote

=over

=item

 #!/usr/local/bin/perl -w
 use strict;
 use Device::Ericsson::AccessoryMenu;
 use Device::SerialPort;
 use Xmms::Remote;
 
 my $xmms = Xmms::Remote->new;
 my $menu = Device::Ericsson::AccessoryMenu->new(
     port => Device::SerialPort->new( '/dev/rfcomm0' ) || die,
     menu => [ XMMS => [
                  "Play/Pause" => sub {
                       $xmms->is_playing ? $xmms->pause : $xmms->play;
                   },
                   Back => sub { $xmms->playlist_prev },
                   Next => sub { $xmms->playlist_next },
                   Stop => sub { $xmms->stop },
                 ],
	     ],
 );

 $menu->register_menu;

 $menu->control while 1;

=back


=head2 Slight return:  The unholy power of Perl

=over

=item

$music_player, kindly play the next track.

=item applescript

 try
   tell application "iTunes"
     try
       set the current_track to get current track
     on error
       error "No current track."
     end try
     set the track_count to (the count of tracks of the current playlist) as string
     next track
     try
       set this_track to get current track
     on error
       play current_track
       set this_track to the current_track
       play track 1 of current playlist
       set this_track to get current track
     end try
     set the track_index to (the index of this_track) as string
     set this_title to the name of this_track as string
     return (track_index & "/" & track_count & "  " & this_title)
   end tell
 on error error_message
   return error_message
 end try

=item Perl

 use Xmms::Remote;
 my $xmms = Xmms::Remote->new;
 $xmms->playlist_next;

=back


=head2 Sliders

=over

=item

We can invoke other kinds of widgets too, like this volume slider

L<image:Volume control|c_5.jpg>

=item

              Volume => sub {
                  my $r = shift;
                  $r->percent_slider(
                      title    => 'Volume',
                      value    => $xmms->get_main_volume,
                      steps    => 10,
                      callback => sub {
                          $xmms->set_main_volume( shift )
                      },
                  );
                  return;
	      },

=back


=head2 Event Loops

=over

=item

L<image:red arrows|arrow3.jpg>

=item

Everything likes to have its own event loop; L<Tk>, L<GTK>, L<POE>
certainly do.

=item

As a lowly utility module we want to stay out of the way of those, and
not trap the user into a(nother) busy loop.

=back


=head2 Mmmm, Statey

=over

=item

L<image:states|us-state-map.gif>

=item

Since we expect the phone to send different messages when it's
displaying a C<Slider> than when it's displaying a C<Menu> we can either:

=item

Continue to kludge tests into a really big if/then/else statement.
Eventually go insane.

=item

Do something stateful.

=back


=head2 I like pie

=over

=item

L<image:Pie!|apple-pie.jpeg>

=item

I also like state machines

=item

C<enter_state> we push a new state onto the stack, and call its
C<on_enter> method

=item

C<exit_state> - we pop the top, call it's C<on_exit> method, and the
new tops C<on_enter>

=item

in C<control> we call the topmost states C<handle> method

=back

=head2 Inside the Text state

=over

=item

C<Text> is probably the simplest state:

Set up the parentage, and add some accessors

 use strict;
 package Device::Ericsson::AccessoryMenu::Text;
 use base 'Device::Ericsson::AccessoryMenu::State';
 __PACKAGE__->mk_accessors( qw( title lines ) );

C<on_enter> we just send the dialog over

 sub on_enter {
     my $self = shift;

     my $title = $self->title;
     $self->send( join ',',
                  qq{AT*EAID=14,2,"$title"},
                  map { qq{"$_"} } @{ $self->lines }
                 );
     $self->expect( 'OK' );
 }

And whatever value our C<handler> gets, it means I<leave this state>

 sub handle {
     my $self = shift;
     $self->exit_state;
 }
 
 1;

That's all there is to it.

=back


=head2 Bob's your Uncle

=over

=item

L<image:Bob Holness|bobholness_card.gif>

=back


=head2 What you can control

=over

=item XMMS

L<Xmms::Remote> is your underdocumented friend.

=item Galeon

You just write bookmarklets and invoke them via C<system>

=item Everything else

Well, anything you can write Perl for at least.

Check out
L<examples/remote|http://unixbeard.net/svn/richardc/perl/Device-Ericsson-AccessoryMenu/examples/remote>
in the L<Device::Ericsson::AccessoryMenu> distribution.  It's the
remote I'm using for this presentation, and already includes XMMS and
Galeon menus.

=back


=head2 X11

=over

=item

It's fairly straightforward to use the C<Mouse> state and remap the
events into X11 keypresses.

 #!/usr/local/bin/perl -w
 use lib qw(lib);
 use strict;
 use Device::Ericsson::AccessoryMenu;
 use Device::SerialPort;
 use X11::GUITest qw(PressKey ReleaseKey);

 my $port = shift || '/dev/rfcomm0';

 my %keymap1 = ( ... );
 my %keymap2 = ( ... );

 sub translate_keys {
     my $remote = shift;
     my %keymap = @_;
     $remote->mouse_mode( callback => sub {
                              my ($key, $updown) = @_;
                              return unless exists $keymap{$key};
                              $updown ? PressKey($keymap{$key})
                                      : ReleaseKey($keymap{$key});
                          });
 }


 my $menu = Device::Ericsson::AccessoryMenu->new(
     port => Device::SerialPort->new( $port ) || die,
     menu => [ XKeys => [
         Map1 => sub { translate_keys( shift, %keymap1 ) },
         Map2 => sub { translate_keys( shift, %keymap2 ) },
        ],
     ],
    );

=item

Being Perl this naturally has a real and practical application.

=back


=head2 What's next

=over

=item

Couple more dialog types to add, if they're useful.

=item

With luck someone will write a nice frontend for building menus,
possibly shipping a bunch of precanned menus

=item

More pie

L<image:Pie!|apple-pie.jpeg>

=back

=head1 Footer

More than you ever needed to know about L<Device::Ericsson::AccessoryMenu>.

E<copy> 2003, Richard Clamp
