. You'll still need the MS Agent components you can download from
pType is a Windows-only application that enables handicapped people
who have only little possibilities to operate a computer to write and
speak using an on-screen keyboard, by using only two controls: the left
and right mousebuttons.
The left mousebutton is used to select an item, the right mousebutton
is used to move the selection to the next item.
You have to choose a row which contains the item you want to select
first, then you can choose the item within the row. If a row is accidentally selected you can return to rowselection using the up-arrow.
In order to use the application, the mousecursor should be pointed
on the 'background', not on one of the items on the screen. Just
point the mouse somewhere on the white background.
There are three 'general' controls: 'talk', to speak the text that
is entered, 'backspace' to remove the last character, and 'again'
to clear the text.
To control the application, you can either use mousebuttons (by
clicking on the white background of the application) or the Adremo
electric wheelchair (using the headsupport)
The bottom of the code shows three seperate files: ptype_en.po and ptype_nl.po, which are used for the multi-langual part, and ptype.ini, defining the keyboard layout. If you want to execute this, you need to save those in the directory you're running pType from.
Apart from the modules listed, you may need two more files: ptype.ico (the icon) and inpout32.dll (only if you select Adremo support). You can download these from
October 14, 2002: 1.0a Added the possibility to return to rowselection using the 'up' arrow
October 22, 2002: 1.0c Added multi-language support and made it more configurable
#!/usr/bin/perl
use warnings;
use strict;
######################################################################
+#
package main;
our $ADREMO_PARPORT_MASK = 0xf8;
our $PARPORT_ADDRESS = 0x379;
my $wxobj = pType->new();
$wxobj->MainLoop();
######################################################################
+#
package pType;
use Wx qw(wxDefaultPosition wxDefaultSize);
use base qw(Wx::App);
#---------------------------------------------------------------------
+-
sub OnInit
{
my $self = shift;
my $Appname = "pType";
my $Appvendor = "pVoice Applications - Jouke Visser";
$self->SetAppName('pType');
$self->SetVendorName($Appvendor);
# We get the configuration from the Windows registry
# If it's not initialized, we provide some defaults
my $config = Wx::ConfigBase::Get;
my $Appversion = $config->Read('Appversion', '1.0c');
my $Appicon = $config->Read('Appicon', 'ptype.ico');
my $iniFile = $config->Read('iniFile', 'ptype.ini');
# $init represents if we have initialized the app before
my $init = not $config->Read('Device');
my $Device = $config->Read('Device', 'icon');
# icon = mouse left/right buttons
# adremo = electric wheelchair adremo
my $Agentchar = $config->Read('Agentchar', 'Merlin');
my $Language = $config->Read('Language', 'English (US)');
my $L10N = $config->Read('L10N', 'en');
my $Voice = $config->Read('Voice', 'Adult Female #1')
+;
my $Interval = $config->ReadInt('Interval', 10);
# We update the registry
$config->Write('Appversion', $Appversion);
$config->Write('Appicon', $Appicon);
$config->Write('iniFile', $iniFile);
$config->Write('Device', $Device);
$config->Write('Agentchar',$Agentchar);
$config->Write('Language', $Language);
$config->Write('L10N', $L10N);
$config->Write('Voice', $Voice);
$config->WriteInt('Interval', $Interval);
if ($init)
{
my $pref = PrefFrame->new( undef, #parent
-1, # id
'Preferences', # title
wxDefaultPosition, # position
wxDefaultSize); # size
$pref->Show(1);
}
else
{
my $frame = pTypeFrame->new( undef, # Parent windo
+w
-1, # Window id
$self->GetAppName. ' '.
$config->Read('Appversion'),
# Title
wxDefaultPosition, # position X,
+Y
wxDefaultSize # size X, Y
);
$frame->Show(1); # Show the frame
}
}
######################################################################
+#
package pTypeFrame;
use Wx qw(:everything);
use Wx::Image;
use Wx::Event qw( EVT_LEFT_UP
EVT_RIGHT_UP
EVT_MENU
EVT_TIMER
EVT_CLOSE);
use Image::Info qw(image_info);
use IO::File;
use Win32::MSAgent;
use Win32::API;
use base qw(Wx::Frame);
#---------------------------------------------------------------------
+-
sub new
{
my $class = shift;
my $self = $class->SUPER::new(@_);
# Get the registry handler into $self->{config}
$self->{config} = Wx::ConfigBase::Get;
# Get the language for internationalization
$self->{lh} = L10N->get_handle($self->{config}->Read('L10N'));
# Set the frame's icon
my $icon=Wx::Icon->new( $self->{config}->Read('Appicon'), # name
wxBITMAP_TYPE_ICO); # type
$self->SetIcon($icon );
# to get the right dimensions for the items, se maximize the
# window, show it, get the dimensions, and hide it again
$self->Maximize(1);
$self->Show(1);
my ($x, $y) = ( $self->GetClientSize()->GetWidth(),
$self->GetClientSize()->GetHeight() );
$self->Show(0);
# Initialize the Image handlers
Wx::InitAllImageHandlers;
$self->{MAX_X} = 150;
$self->{MAX_Y} = 150;
my $key_id = 10_000;
# create a new panel
$self->{panel} = Wx::Panel->new($self, -1);
$self->{panel}->SetBackgroundColour(wxWHITE);
# Initialize the MS Agent stuff
$self->{agent} = Win32::MSAgent->new();
$self->{agent}
->Characters->Load($self->{config}->Read('Agentchar'),
$self->{config}->Read('Agentchar').".acs")
+;
# To be able to access the character from the $self->{panel}'s
# action methods, we have to define it as a property of that
$self->{panel}->{char} = $self->{agent}
->Characters($self->{config}
->Read('Agentchar'))
+;
$self->{panel}->{char}->Voice($self->{config}->Read('Language'),
$self->{config}->Read('Voice'));
$self->{panel}->{char}->MoveTo(0, 350);
$self->{tls} = Wx::FlexGridSizer->new(0,1);
my ($ids, $buttons, @rows);
# Read they key-layout from the inifile
open(KEYS, $self->{config}->Read('iniFile'))
|| die $self->{lh}->maketext("Can't open ").$self->{config}->
+Read('iniFile').": $!";
while (<KEYS>)
{
chomp;
my @row = split(/\s/, $_);
push @rows, \@row;
}
close(KEYS);
# Draw the screen
my $i;
for ($i =0; $i < @rows; $i++)
{
my $row = $rows[$i];
($self->{panel}->{panels}->{$i},
$key_id,
$ids,
$buttons) = $self->AddRow( $self->{panel}, # parent
$key_id, # lowest id
wxDefaultPosition, # position
[$x,80], # size
$row); # rowcontents
$self->{panel}->{panels}->{$i}->SetBackgroundColour(wxWHITE);
# update the button and actionlist
$self->{panel}->{buttons}->{$i} = $buttons;
@{$self->{panel}->{actions}->{$i}} = map {$_ = ' '
if $_ eq 'space'
+;
$_} 'up', @$row;
$self->{tls}->Add($self->{panel}->{panels}->{$i}, # what to ad
+d
0, # unused
wxALL|wxALIGN_CENTRE, # style
2); # padding
}
# This panel is the panel with the control buttons Talk, Delete an
+d
# Again
$self->{panel}
->{panels}->{$i}=Wx::Panel->new($self->{panel}, # paren
+t
-1, # id
wxDefaultPosition, # pos
[$x,$self->{MAX_Y}]); # size
$self->{panel}->{panels}->{$i}->SetBackgroundColour(wxWHITE);
my $sizer = Wx::FlexGridSizer->new(1,0);
my $tbutton = Wx::BitmapButton->new
($self->{panel}
->{panels}->{$i}, # parent
-1, # id
$self->getimgfile("./img/talk.jpg")
+,
# image
wxDefaultPosition, # position
wxDefaultSize, # size
wxSUNKEN_BORDER); # style
$tbutton->SetBackgroundColour(wxWHITE);
$sizer->Add($tbutton, 0, wxALL|wxALIGN_CENTRE, 2);
# update the button and action list
push @{$self->{panel}->{buttons}->{$i}}, $tbutton;
push @{$self->{panel}->{actions}->{$i}}, 'talk';
my $dbutton = Wx::BitmapButton->new
($self->{panel}
->{panels}->{$i}, # parent
-1, # id
$self->getimgfile("./img/delete.jpg")
+,
# image
wxDefaultPosition, # position
wxDefaultSize, # size
wxSUNKEN_BORDER); # style
$dbutton->SetBackgroundColour(wxWHITE);
$sizer->Add($dbutton, 0, wxALL|wxALIGN_CENTRE, 2);
# update the button and actionlist
push @{$self->{panel}->{buttons}->{$i}}, $dbutton;
push @{$self->{panel}->{actions}->{$i}}, 'delete';
my $abutton = Wx::BitmapButton->new
($self->{panel}
->{panels}->{$i}, # parent
-1, # id
$self->getimgfile("./img/again.jpg")
+,
# image
wxDefaultPosition, # position
wxDefaultSize, # size
wxSUNKEN_BORDER); # style
$abutton->SetBackgroundColour(wxWHITE);
$sizer->Add($abutton, 0, wxALL|wxALIGN_CENTRE, 2);
# update teh button and actionlist
push @{$self->{panel}->{actions}->{$i}}, 'again';
push @{$self->{panel}->{buttons}->{$i}}, $abutton;
$self->{panel}->{panels}->{$i}->SetSizer($sizer);
$self->{panel}->{panels}->{$i}->SetAutoLayout(1);
$sizer->Fit($self->{panel}->{panels}->{$i});
$self->{tls}->Add( $self->{panel}->{panels}->{$i}, # what to add
0, # unused
wxALL|wxALIGN_CENTRE, # style
2); # padding
$self->{panel}->{lastrow} = $i;
# Create the TextControl
my $font = Wx::Font->new( 24, # font size
wxSWISS, # font family
wxNORMAL, # style
wxNORMAL, # weight
0, # underline?
'Comic Sans MS'); # face name
my $ta = Wx::TextAttr->new( Wx::Colour->new(0,0,0), # textcol
Wx::Colour->new(255,255,255),# backgr.
$font); # font
$self->{rowsizer} = Wx::FlexGridSizer->new(1,0);
$self->{panel}->{text} = Wx::TextCtrl->new
( $self->{panel}, # parent
-1, # id
'', # text
wxDefaultPosition,# position
[$x,60], # size
wxTE_RICH|
wxTE_MULTILINE); # style
# set the text-attributes
$self->{panel}->{text}->SetDefaultStyle($ta);
$self->{rowsizer}->Add($self->{panel}->{text}, # what to add
0, # unused
wxALL|wxALIGN_CENTRE, # style
2); # padding
$self->{tls}->Add($self->{rowsizer}, 0, wxALL|wxALIGN_CENTRE, 2);
# Set the sizer for the overall panel
$self->{panel}->SetSizer($self->{tls});
$self->{panel}->SetAutoLayout(1);
# Select the first row
$self->{panel}->{selectedrow} = 0;
$self->{panel}->{selecteditem} = 0;
$self->{panel}->{panels}->{$self->{panel}->{selectedrow}}
->SetBackgroundColour(wxRED);
$self->{panel}->{rowselection} = 1;
# Create three menus
my $mfile = Wx::Menu->new();
my $mhelp = Wx::Menu->new();
my $medit = Wx::Menu->new();
# With one item each
my( $ID_ABOUT, $ID_PREFS, $ID_EXIT ) = ( 1..100);
$mhelp->Append( $ID_ABOUT, $self->{lh}->maketext('&About...'));
$medit->Append( $ID_PREFS, $self->{lh}->maketext('&Preferences...
+'));
$mfile->Append( $ID_EXIT, $self->{lh}->maketext('E&xit...'));
# Create the menubar and append the individual menus
my $mbar = Wx::MenuBar->new();
$mbar->Append($mfile, $self->{lh}->maketext("&File"));
$mbar->Append($medit, $self->{lh}->maketext("&Edit"));
$mbar->Append($mhelp, $self->{lh}->maketext("&Help"));
# Assign the menu to our frame
$self->SetMenuBar($mbar);
# declare the events
EVT_MENU($self, $ID_EXIT, \&OnQuit);
EVT_MENU($self, $ID_ABOUT, \&OnAbout);
EVT_MENU($self, $ID_PREFS, \&OnPrefs);
# Show the MS Agent
$self->{panel}->{char}->Show();
# save the parent in the panel's properties
$self->{panel}->{parent} = $self;
# The events for the icon device
EVT_LEFT_UP($self->{panel}, \&OnLeft);
EVT_RIGHT_UP($self->{panel}, \&OnRight);
# The event for the adremo device
$self->{timer} = Wx::Timer->new($self,1);
$self->{timer}->Start($self->{config}->ReadInt('Interval'));
EVT_TIMER($self, 1, \&MonitorPort);
# Our close handler for exiting the application nicely
EVT_CLOSE($self, \&OnExit);
return $self;
}
#---------------------------------------------------------------------
+-
# This sub is used to monitor the parallel port for the adremo device
sub MonitorPort
{
my ($self, $event) = @_;
# do nothing if the device is not adremo or
# if we're already running
return if $self->{config}->Read('Device') eq 'icon';
return if $self->{monitorrun};
$self->{monitorrun} = 1;
$self->{getportval} = Win32::API->new( "inpout32", # dll
"Inp32", # function
["I"], # Parameterlis
+t
"I") # returnvalue
if not exists $self->{getportval};
my $curvalue = ($self->{getportval}
->Call($main::PARPORT_ADDRESS) &
$main::ADREMO_PARPORT_MASK);
if (not defined $curvalue)
{
$self->{monitorrun} = 0;
return
}
$self->{lastvalue} = 0 if not exists $self->{lastvalue};
if ($curvalue != $self->{lastvalue})
{
# 0x38 means a headmove to the right
$self->OnNext if $curvalue == 0x38;
# 0xf8 means a headmove to the left
$self->OnSelect if $curvalue == 0xf8;
$self->{lastvalue} = $curvalue;
}
$self->{monitorrun} = 0;
}
#---------------------------------------------------------------------
+-
# This sub is being called when the left mousebutton is clicked
sub OnLeft
{
my ($self, $event) = @_;
# do nothing if we're not using the icon device
return if $self->{parent}->{config}->Read('Device') eq 'adremo';
$self->{parent}->OnSelect;
}
#---------------------------------------------------------------------
+-
# This sub is being called when the right mousebutton is clicked
sub OnRight
{
my ($self, $event) = @_;
# do nothing if we're not using the icon device
return if $self->{parent}->{config}->Read('Device') eq 'adremo';
$self->{parent}->OnNext;
}
#---------------------------------------------------------------------
+-
# This sub is being called when the next row or next item should be
# highlighted
sub OnNext
{
my $self = $_[0]->{panel};
if ($self->{rowselection})
# select the next row if we're using rowselection
{
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxWHITE);
$self->{selectedrow} = $self->{selectedrow} < $self->{lastrow}
+?
$self->{selectedrow} + 1 :
0;
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxRED);
}
else
# select the next item in the row if we're not in rowselection
{
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxWHITE);
$self->{selecteditem} = $self->{selecteditem} <
$#{$self->{buttons}
->{$self->{selectedrow}}} ?
$self->{selecteditem} + 1 :
0;
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxRED);
}
$self->Refresh();
}
#---------------------------------------------------------------------
+-
# This sub is being called when a row or item is selected
sub OnSelect
{
my ($self) = $_[0]->{panel};
if ($self->{rowselection})
{
if (scalar @{$self->{buttons}->{$self->{selectedrow}}} != 1)
# leave rowselection mode if there is more than one item
# in this row
{
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxWHITE);
$self->{selecteditem} = 0;
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxRED);
$self->{rowselection} = 0;
}
else
# Just do the action associated with the item in the row
# if there is just one item
{
if ($self->{actions}->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'talk')
# Speak the text inside the textcontrol
{
$self->{char}->Speak($self->{text}->GetValue())
}
elsif ($self->{actions}
->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'delete')
# Do a 'backspace'
{
$self->{text}->SetValue(substr($self->{text}
->GetValue,0, -1))
}
elsif ($self->{actions}
->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'again')
# Empty the textcontrol
{
$self->{text}->SetValue('')
}
elsif ($self->{actions}
->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'up')
# go back into rowselection
{
$self->{rowselection}=1;
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxWHITE);
$self->{selecteditem} = 0;
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxRED);
}
else
# Add the selected character to the textcontrol
{
$self->{text}->AppendText($self->{actions}
->{$self->{selectedrow}}
->[$self->{selecteditem}]
+)
}
$self->{rowselection}=1;
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxWHITE);
$self->{selecteditem} = 0;
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxRED);
}
}
else
# We are not in rowselection, so do the action associated with
# the item
{
if ($self->{actions}->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'talk')
# speak the text in the textcontrol
{
$self->{char}->Speak($self->{text}->GetValue())
}
elsif ($self->{actions}->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'delete')
# do a 'backspace'
{
$self->{text}->SetValue(substr($self->{text}
->GetValue,0, -1))
}
elsif ($self->{actions}->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'again')
# empty the text control
{
$self->{text}->SetValue('')
}
elsif ($self->{actions}->{$self->{selectedrow}}
->[$self->{selecteditem}] eq 'up')
# the up arrow is for going back to rowselection
{
$self->{rowselection}=1;
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxWHITE);
$self->{selecteditem} = 0;
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxRED);
}
else
# add the character selected to the textcontrol
{
$self->{text}->AppendText( $self->{actions}
->{$self->{selectedrow}}
->[$self->{selecteditem}])
}
# go back into rowselection
$self->{rowselection}=1;
$self->{buttons}->{$self->{selectedrow}}
->[$self->{selecteditem}]
->SetBackgroundColour(wxWHITE);
$self->{selecteditem} = 0;
$self->{panels}->{$self->{selectedrow}}
->SetBackgroundColour(wxRED);
}
# update the screen
$self->Refresh();
}
#---------------------------------------------------------------------
+-
# This sub gets a file from disk, resizes it if nessecary
# and returns the Wx-internal bitmap
sub getimgfile
{
my $self = shift;
my $file = shift;
# Determine the imagetype
my $info = image_info($file);
my $contenttype = $info->{file_media_type};
if (my $image = Wx::Image->new($file, $contenttype))
# we can load the image
{
my ($x,$y) = ($image->GetWidth, $image->GetHeight);
# resize only if it's larger than MAX_X and MAX_Y
if (($x > $self->{MAX_X}) || ($y > $self->{MAX_Y}))
{
if ($x >= $y)
{
my $factor = $x/$self->{MAX_X};
$image = $image->Scale($self->{MAX_X},$y/$factor);
}
else
{
my $factor = $y/$self->{MAX_Y};
$image = $image->Scale($x/$factor, $self->{MAX_Y});
}
}
#and return the image
return $image->ConvertToBitmap();
}
else
{
# if we can't open the file, warn and return nothing
warn "Can't open $file: $!";
return undef;
}
}
#---------------------------------------------------------------------
+-
# This sub adds a row to the screen, given the starting number
# for the ids, the position (as an arrayref), the size of the
# entire row and the letters of the keys.
# It returns the panel it created, the last id used, the arrayref
# of ids used and the arrayref of buttons created.
sub AddRow
{
my ($self, $parent, $id, $position, $size, $keys) = @_;
# Create a new panel
my $panel = Wx::Panel->new($parent, -1, $position, $size);
my $sizer = Wx::FlexGridSizer->new(1,0);
my $ids = {};
my @buttons = ();
# Add the 'up' button
my $button = Wx::BitmapButton->new
($panel, # parent
$id++, # id
$self->getimgfile("./img/up.jpg"),
# image
wxDefaultPosition, # position
wxDefaultSize, # size
wxSUNKEN_BORDER); # style
$button->SetBackgroundColour(wxWHITE);
$sizer->Add($button, 0, wxALL|wxALIGN_CENTRE, 2);
push @buttons, $button;
# Add the defined keys for this row
for (@$keys)
{
$ids->{$id} = $_;
$ids->{$id} = ' ' if $_ eq 'space';
my $button = Wx::BitmapButton->new
($panel, # parent
$id++, # id
$self->getimgfile("./img/$_.jpg")
+,
# image
wxDefaultPosition, # position
wxDefaultSize, # size
wxSUNKEN_BORDER); # style
$button->SetBackgroundColour(wxWHITE);
$sizer->Add($button, 0, wxALL|wxALIGN_CENTRE, 2);
push @buttons, $button;
}
$panel->SetSizer($sizer);
$panel->SetAutoLayout(1);
$sizer->Fit($panel);
return $panel, $id, $ids, \@buttons;
}
#---------------------------------------------------------------------
+-
# This sub is being called when the 'File'-'Exit' is selected
sub OnQuit
{
my ($self, $event) = @_;
# Let the MS Agent character wave to the user
$self->{panel}->{char}->Play("Wave");
$self->{panel}->{char}->Speak("\\Emp\\".$self->{lh}->maketext("Bye
+")."!");
sleep(4);
# and close
$self->Close( 1 );
}
#---------------------------------------------------------------------
+-
# This sub is being called when the application is closed
sub OnExit
{
my ($self, $event) = @_;
# stop the timer for the port monitor
$self->{timer}->Stop();
$self->Destroy();
}
#---------------------------------------------------------------------
+-
# This sub is being called when 'Help'-'About' is selected
sub OnAbout
{
my ($self, $event) = @_;
my $appname = $self->{config}->GetAppName;
my $wxperlstr = $self->{lh}->maketext('Uses wxPerl');
my $message = <<MSG;
$appname
Copyright (c) 2002 Jouke Visser
$wxperlstr $Wx::VERSION
MSG
# display a simple about box
Wx::MessageBox( $message.wxVERSION_STRING, # message
$self->{lh}->maketext('About ').
$self->{config}->GetAppName, # title
wxOK |wxICON_INFORMATION, # style
$self ); # parent
}
#---------------------------------------------------------------------
+-
# This sub is being called when 'Edit'-'Preferences' is selected
sub OnPrefs
{
my ($self, $event) = @_;
$self->{prefs} = PrefFrame->new($self, # parent
-1, # id
$self->{lh} # title
->maketext("Preferences"));
$self->{prefs}->Show(1);
}
######################################################################
+#
package PrefFrame;
use Wx qw(:everything);
use Wx::Event qw(EVT_BUTTON EVT_COMBOBOX);
use File::Find;
use Win32::MSAgent;
use base qw(Wx::MiniFrame);
#---------------------------------------------------------------------
+-
sub new
{
my $class = shift;
# call the superclass' constructor
my $self = $class->SUPER::new(@_);
$self->{config} = Wx::ConfigBase::Get;
# Get the language for internationalization
$self->{lh} = L10N->get_handle($self->{config}->Read('L10N'));
# set the frame's icon
my $icon=Wx::Icon->new( $self->{config}->Read('Appicon'),
wxBITMAP_TYPE_ICO);
$self->SetIcon($icon );
# create a new panel
$self->{panel} = Wx::Panel->new($self, -1);
$self->{tls} = Wx::FlexGridSizer->new(0,1);
$self->{device} = Wx::RadioBox
->new($self->{panel}, # paren
+t
-1, # id
$self->{lh}->maketext('Control'),# label
wxDefaultPosition, # pos
wxDefaultSize, # size
[$self->{lh}->maketext('Mousebuttons'),
$self->{lh}->maketext('Adremo')],# item
+s
2, # max
wxRA_SPECIFY_COLS); # cols
$self->{tls}->Add($self->{device}, 0, wxGROW|wxALL, 2);
# preselect the right item
if ($self->{config}->Read('Device') eq 'adremo')
{
$self->{device}->SetSelection(1);
}
else
{
$self->{device}->SetSelection(0);
}
$self->{intervallabel} =
Wx::StaticText->new($self->{panel}, # parent
-1, # id
$self->{lh}->maketext('Interval'));
# label
$self->{tls}->Add($self->{intervallabel}, 0, wxGROW|wxALL, 2);
$self->{interval} = Wx::TextCtrl->new($self->{panel}, # parent
-1, # id
$self->{config}
->ReadInt('Interval'));
# default
$self->{tls}->Add($self->{interval}, 0, wxGROW|wxALL, 2);
$self->{L10N} = Wx::RadioBox->new($self->{panel}, # parent
-1, # id
$self->{lh} # label
->maketext('Language'),
wxDefaultPosition, # pos
wxDefaultSize, # size
[$self->{lh} # items
->maketext('English'),
$self->{lh}
->maketext('Dutch')],
2, # max
wxRA_SPECIFY_COLS);# cols
$self->{tls}->Add($self->{L10N}, 0, wxGROW|wxALL, 2);
# preselect the right item
if ($self->{config}->Read('L10N') eq 'nl')
{
$self->{L10N}->SetSelection(1);
}
else
{
$self->{L10N}->SetSelection(0);
}
$self->{agentcharlabel} =
Wx::StaticText->new($self->{panel}, # parent
-1, # id
$self->{lh} # label
->maketext('Agent character'));
$self->{tls}->Add($self->{agentcharlabel}, 0, wxGROW|wxALL, 2);
# Find installed characters on this system
my $systemroot = $ENV{SYSTEMROOT} || $ENV{WINDIR} || 'C:\WINDOWS';
my (@chars, %chars);
find(sub {$chars{ucfirst(lc($1))} = $File::Find::name if $_=~ /(.*
+)?\.acs$/i; },
"$systemroot\\msagent");
@chars = keys %chars;
my $selchar=0;
for (my $i=0; $i<@chars; $i++)
{
$selchar = $i if $chars[$i] eq $self->{config}->Read('Agentcha
+r');
}
$self->{chars} = Wx::ComboBox->new( $self->{panel}, # parent
-1, # id
'', # text
wxDefaultPosition, # position
wxDefaultSize, # size
\@chars, # list
wxCB_DROPDOWN|
wxCB_READONLY); # style
$self->{tls}->Add($self->{chars}, 0, wxGROW|wxALL, 2);
$self->{chars}->SetSelection($selchar);
$self->{agentlanglabel} =
Wx::StaticText->new($self->{panel}, # parent
-1, # id
$self->{lh} # label
->maketext('Agent language'));
$self->{tls}->Add($self->{agentlanglabel}, 0, wxGROW|wxALL, 2);
# Translate all available languages for MS Agent
$self->{alllangs} = [ 'English (US)',
'English (British)',
'Dutch',
'French',
'German',
'Italian',
'Japanese',
'Korean',
'Portuguese (Brazil)',
'Russian',
'Spanish'];
my @translangs = map {$self->{lh}->maketext($_)} @{$self->{alllang
+s}};
# Find the index of the current language
my $sellang=0;
for (my $i=0; $i<@{$self->{alllangs}}; $i++)
{
$sellang = $i if $self->{alllangs}->[$i] eq
$self->{config}->Read('Language');
}
$self->{langs} = Wx::ComboBox->new( $self->{panel}, # parent
-1, # id
'', # text
wxDefaultPosition, # position
wxDefaultSize, # size
\@translangs, # list
wxCB_DROPDOWN|
wxCB_READONLY); # style
$self->{tls}->Add($self->{langs}, 0, wxGROW|wxALL, 2);
# Select the current selected language
$self->{langs}->SetSelection($sellang);
$self->{agentvoicelabel} =
Wx::StaticText->new($self->{panel}, # parent
-1, # id
$self->{lh} # label
->maketext('Agent Voice'));
$self->{tls}->Add($self->{agentvoicelabel}, 0, wxGROW|wxALL, 2);
# Retrieve all voices for the current language
my @allvoices =Win32::MSAgent->new
->Characters
->ListVoices($self->{config}
->Read('Language'))
+;
$self->{allvoices} = \@allvoices;
# Find the index of the current selected voice
my $selvoice=0;
for (my $i=0; $i<@{$self->{allvoices}}; $i++)
{
$selvoice = $i if $self->{allvoices}->[$i] eq
$self->{config}->Read('Voice');
}
$self->{voices} = Wx::ComboBox->new( $self->{panel}, # parent
-1, # id
'', # text
wxDefaultPosition, # position
wxDefaultSize, # size
$self->{allvoices}, # list
wxCB_DROPDOWN|
wxCB_READONLY); # style
$self->{tls}->Add($self->{voices}, 0, wxGROW|wxALL, 2);
# Select the voice that is currently used
$self->{voices}->SetSelection($selvoice);
$self->{button} = Wx::Button->new( $self->{panel}, # parent
-1, # id
'OK'); # label
$self->{tls}->Add($self->{button},0, wxGROW|wxALL, 2);
$self->{NBlabel} =
Wx::StaticText->new($self->{panel}, # parent
-1, # id
$self->{lh} # label
->maketext('Change notice'));
$self->{tls}->Add($self->{NBlabel}, 0, wxGROW|wxALL, 2);
$self->{panel}->SetSizer($self->{tls});
$self->{panel}->SetAutoLayout(1);
$self->{tls}->Fit($self);
# What to do if the button is clicked
EVT_BUTTON($self, $self->{button}, \&OnButton);
EVT_COMBOBOX($self, $self->{langs}, \&OnCBLang);
return $self;
}
#---------------------------------------------------------------------
+-
# This sub is being called when the language combobox has changed
sub OnCBLang
{
my ($self, $event) = @_;
my $lang = $self->{alllangs}->[$self->{langs}->GetSelection];
# Retrieve all voices for the current language
my @allvoices =Win32::MSAgent->new
->Characters
->ListVoices($lang);
$self->{allvoices} = \@allvoices;
# clear the voices CB
$self->{voices}->Clear;
# and fill it with the voices for this language
$self->{voices}->Append($_) foreach @{$self->{allvoices}};
$self->{voices}->SetSelection(0);
}
#---------------------------------------------------------------------
+-
# This sub is called when the 'ok' button is selected to apply the
# changes of the preferences
sub OnButton
{
my ($self, $event) = @_;
if ($self->{device}->GetSelection == 0)
# we want to use the 'icon' device
{
$self->OnMB()
}
else
# we want to use the 'adremo' device
{
$self->OnAdremo()
}
# update the interval
$self->OnIntervalChange($self->{interval}->GetValue);
if ($self->{L10N}->GetSelection == 0)
# we want to use the 'english' language
{
$self->OnL10NChange('en')
}
else
# we want to use the 'dutch' language
{
$self->OnL10NChange('nl')
}
# update the agentcharacter
$self->OnCharChange($self->{chars}->GetStringSelection);
# update the agentlanguage
$self->OnLangChange($self->{alllangs}->[$self->{langs}->GetSelecti
+on]);
# update the agentvoice
$self->OnVoiceChange($self->{voices}->GetStringSelection);
# If this frame has no parent, we have been called before pType
# itself has started, so we start the pType frame now
if (not defined $self->GetParent)
{
my $frame = pTypeFrame->new( undef, # Parent windo
+w
-1, # Window id
$self->{config}->GetAppName. ' '.
$self->{config}->Read('Appversion
+'),
wxDefaultPosition, # position X,
+Y
wxDefaultSize # size X, Y
);
$frame->Show(1); # Show the frame
}
# close the window
$self->Close();
}
#---------------------------------------------------------------------
+-
# This sub is being called to indicate we want to use the 'Icon' devic
+e
sub OnMB
{
my ($self) = @_;
$self->{config}->Write('Device','icon');
}
#---------------------------------------------------------------------
+-
# This sub is being called to indicate we want to use the 'Adremo'
sub OnAdremo
{
my ($self) = @_;
$self->{config}->Write('Device','adremo');
}
#---------------------------------------------------------------------
+-
# This sub is being called when we want to change the Adremo interval
sub OnIntervalChange
{
my ($self, $interval) = @_;
$self->{config}->WriteInt('Interval', $interval);
}
#---------------------------------------------------------------------
+-
# This sub is being called when we want to change the Agent Character
sub OnCharChange
{
my ($self, $char) = @_;
return if not $char;
$self->{config}->Write('Agentchar', $char);
}
#---------------------------------------------------------------------
+-
# This sub is being called when we want to change the Agent Language
sub OnLangChange
{
my ($self, $lang) = @_;
return if not $lang;
$self->{config}->Write('Language', $lang);
}
#---------------------------------------------------------------------
+-
# This sub is being called when we want to change the Agent Voice
sub OnVoiceChange
{
my ($self, $voice) = @_;
return if not $voice;
$self->{config}->Write('Voice', $voice);
}
#---------------------------------------------------------------------
+-
# This sub is being called when we want to change the L10N language
sub OnL10NChange
{
my ($self, $L10N) = @_;
$self->{config}->Write('L10N', $L10N);
}
######################################################################
+#
package L10N;
use base 'Locale::Maketext';
use Locale::Maketext::Lexicon {nl => [Gettext => 'ptype_nl.po'],
en => [Gettext => 'ptype_en.po']};
======================================================================
file ptype_en.po:
msgid "&About..."
msgstr "&About..."
msgid "E&xit..."
msgstr "E&xit\tCtrl-X"
msgid "&Preferences..."
msgstr "&Preferences\tCtrl-P"
msgid "Can't open "
msgstr "Can't open "
msgid "&File"
msgstr "&File"
msgid "&Edit"
msgstr "&Edit"
msgid "&Help"
msgstr "&Help"
msgid "Bye"
msgstr "Bye-bye"
msgid "Uses wxPerl"
msgstr "Uses wxPerl"
msgid "About "
msgstr "About "
msgid "Preferences"
msgstr "Preferences"
msgid "Control"
msgstr "Control"
msgid "Mousebuttons"
msgstr "Mousebuttons"
msgid "Adremo"
msgstr "Adremo"
msgid "Interval"
msgstr "Adremo refresh-interval (ms)"
msgid "Language"
msgstr "Language"
msgid "English"
msgstr "English"
msgid "Dutch"
msgstr "Dutch"
msgid "Agent character"
msgstr "Agent character"
msgid "Agent language"
msgstr "Agent language (speechsynthesis)"
msgid "Change notice"
msgstr "Most changes become active only after restarting the applicati
+on"
msgid "English (US)"
msgstr "English (US)"
msgid "English (British)"
msgstr "English (British)"
msgid "French"
msgstr "French"
msgid "German"
msgstr "German"
msgid "Italian"
msgstr "Italian"
msgid "Japanese"
msgstr "Japanese"
msgid "Korean"
msgstr "Korean"
msgid "Portuguese (Brazil)"
msgstr "Portuguese (Brazil)"
msgid "Russian"
msgstr "Russian"
msgid "Spanish"
msgstr "Spanish"
msgid "Agent Voice"
msgstr "MS Agent Voice"
======================================================================
file ptype_nl.po:
msgid "&About..."
msgstr "&Over..."
msgid "E&xit..."
msgstr "&Afsluiten\tCtrl-A"
msgid "&Preferences..."
msgstr "&Voorkeuren\tCtrl-V"
msgid "Can't open "
msgstr "Fout bij het openen van "
msgid "&File"
msgstr "&Bestand"
msgid "&Edit"
msgstr "B&ewerken"
msgid "&Help"
msgstr "&Help"
msgid "Bye"
msgstr "Doei"
msgid "Uses wxPerl"
msgstr "Gebruikt wxPerl"
msgid "About "
msgstr "Over "
msgid "Preferences"
msgstr "Voorkeuren"
msgid "Control"
msgstr "Besturing"
msgid "Mousebuttons"
msgstr "Muisknoppen"
msgid "Adremo"
msgstr "Adremo"
msgid "Interval"
msgstr "Adremo verversings-interval (ms)"
msgid "Language"
msgstr "Taal"
msgid "English"
msgstr "Engels"
msgid "Dutch"
msgstr "Nederlands"
msgid "Agent character"
msgstr "Agent karakter"
msgid "Agent language"
msgstr "Agent taal (spraaksynthese)"
msgid "Change notice"
msgstr "De meeste wijzigingen worden pas actief nadat de applicatie is
+ herstart"
msgid "English (US)"
msgstr "Engels (VS)"
msgid "English (British)"
msgstr "Engels (Brits)"
msgid "French"
msgstr "Frans"
msgid "German"
msgstr "Duits"
msgid "Italian"
msgstr "Italiaans"
msgid "Japanese"
msgstr "Japans"
msgid "Korean"
msgstr "Koreaans"
msgid "Portuguese (Brazil)"
msgstr "Portuguees (Brazilie)"
msgid "Russian"
msgstr "Russisch"
msgid "Spanish"
msgstr "Spaans"
msgid "Agent Voice"
msgstr "MS Agent Stem"
======================================================================
file ptype.ini:
a b c d e f g h i
j k l m n o p q r
s t u v w x y z
space