Acme-KeyboardMarathon

 view release on metacpan or  search on metacpan

lib/Acme/KeyboardMarathon.pm  view on Meta::CPAN

package Acme::KeyboardMarathon;
$Acme::KeyboardMarathon::VERSION = '1.27';

use Carp;
use Data::Dumper;
use Math::BigInt;

use integer;
use warnings;
use strict;

sub new {
  my @args = @_;
  my $class = shift @args;
  my $self = {};
  bless($self,$class);

  croak("Odd number of arguments") if @args%2;
  my %args = @args;
  my $layout = delete $args{layout} || 'qwerty';
  croak("Unsupported layout $layout")
    unless $layout =~ /^(?:qwerty|dvorak)\z/;

  croak "Unknown options: " . join ", ", keys(%args) if keys %args;

  # all measures in 100ths of a cm

  my $depress_distance = 25;
  my $shift_distance = 200;

  # horizontal distances

  $self->{k} = {};

  no warnings 'qw';
  map { $self->{k}->{$_} = 550 } ( '\\', '|' );
  map { $self->{k}->{$_} = 500 } ( qw/6 ^ ` ~/ );
  map { $self->{k}->{$_} = 450 } ( qw/= +/ );
  map { $self->{k}->{$_} = 400 } ( qw/] 1 2 3 4 7 8 9 0 5 - _ ! @ # $ % & * ( ) }/ );
  map { $self->{k}->{$_} = 350 } ( qw/B b/ );
  map { $self->{k}->{$_} = 230 } ( qw/[ {/ );
  map { $self->{k}->{$_} = 200 } ( qw/Q q W w G g H h E e R r T t Y y U u I i O o P p Z z X x C c V v N n M m , < > . \/ ? ' "/ );
  map { $self->{k}->{$_} =   0 } ( qw/A a S s D d F f J j K k L l ; :/ );

  if ($layout eq 'dvorak') {
    map { $self->{k}->{$_} = 550 } ( '\\', '|' );
    map { $self->{k}->{$_} = 500 } ( qw/6 ^ ` ~/ );
    map { $self->{k}->{$_} = 450 } ( qw/] }/ );
    map { $self->{k}->{$_} = 400 } ( qw/+ = 1 2 3 4 7 8 9 0 5 [ { ! @ # $ % & * ( )/ );
    map { $self->{k}->{$_} = 350 } ( qw/X x/ );
    map { $self->{k}->{$_} = 230 } ( qw/? \// );
    map { $self->{k}->{$_} = 200 } ( qw/" ' < , I i D d > . P p Y y F f G g C c R r L l : ; Q q J j K k B b M m W w V v Z z - _/ );
    map { $self->{k}->{$_} =   0 } ( qw/A a O o E e U u H h T t N n S s/ );
  }

  $self->{k}->{"\n"} = 400;
  $self->{k}->{"\t"} = 230;
  $self->{k}->{' '}  =   0;

  # Add the depress distance
  for my $key ( keys %{$self->{k}} ) {
    $self->{k}->{$key} += $depress_distance;
  }

  # Add shift distance
  for my $key ( qw/! @ # $ % ^ & * ( ) _ + < > ? : " { } | ~ '/, 'A' .. 'Z' ) {
    $self->{k}->{$key} += $shift_distance;
  }

  # override
  $self->{k}->{"\a"} = 0; # alarm
  $self->{k}->{"\b"} = 0; # backspace
  $self->{k}->{"\e"} = 0; # escape
  $self->{k}->{"\f"} = 0; # form feed
  $self->{k}->{"\r"} = 0; # carriage return

  return $self;
}

# split is 2m27.476s for 9.3megs of text (9754400 chars)
sub distance {
  my $k = shift->{k};

  my $bint = Math::BigInt->bzero;
  my $int  = 0;

  for my $i (0 .. $#_) {
    croak "FAR OUT! A REFERENCE: $_[$i]" if ref $_[$i];

    for ( split '', $_[$i] ) {
      unless ( defined $k->{$_} ) {
        carp 'WHOAH! I DON\'T KNOW WHAT THIS IS: [' . sprintf('%2.2x',ord($_)) . " : $_] assigning it a 2.5 cm distance\n";

        $k->{$_} = 250;
      }

      $int += $k->{$_};

      # Hold the value in a native int until it reaches an unsafe limit.
      # Then add to the BigInt, this avoids repeated slow calls to badd.
      #
      # To play it safe, this value is the max signed 32bit int minus
      # the max distance a key can be (| - 550), i.e.
      #   2 ** 31 - 551 = 2_147_483_097
      if ( $int >= 2_147_483_097 ) {
        $bint->badd($int);

        $int = 0;
      }
    }
  }

  # Add whatever remaining value we have in the native int.



( run in 1.256 second using v1.01-cache-2.11-cpan-39bf76dae61 )