Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Comment on

( #3333=superdoc: print w/ replies, xml ) Need Help??
#!/usr/bin/perl # $version 0.3 =head2 Description usage: perl ptest.pl -d DEVICENAME [--primary_axis] [--led] Needs to be run sudo or as root. -d Device name should be in the form of /dev/input/event[num] or a sym +link to the event --primary_axis will make it act as there is one axis, whichever is dom +inant --led will light the leds Prerequisites from CPAN: Linux::Input Linux::Input::Info Originally based on spacenavi.c by Simon Budig. http://www.home.unix-ag.org/simon/files/spacenavi.c This is a skeleton program to interact with a 3DConnexion Space Naviga +tor through evdev It supports calibration, scaling of inputs, action debouncing and more +. =head1 Modes of Operation Normal Operation: In normal operation, it will simply report back device input based on +configuration. If the movement is < mindeflect, the axis will be treated as having no + movement. Movement is not acknowledged until the Axis has been acted on longer t +han debounce time. Primary Axis: If "Primary Axis" is enabled, the pointer will act as 8 buttons. Only +the axis most acted upon will be acknowledged. If the Axis determined to be primary differs fro +m the previous, a release event will be generated for the previous primary axis (as if you had let it +go). LEDs: The sub that handles the LEDs (set_spnvled) has the input event format + hardcoded. Not portable. =head1 TODO Add a lot more command line options for individual axes and options Add support for reading in calibration data. Better docs, read the code for now :) =head1 AUTHOR Lee Pumphret http://www.leeland.net/3d-space-navigator-linux.html =cut use strict; use warnings; no warnings qw/uninitialized/; use Time::HiRes qw/time/; # Need higher res time for debouncing use Linux::Input::Info; use Linux::Input v1.03; use Getopt::Long; use Fcntl; our( $USE_PRIMARY_AXIS, $DEV, $LED_STATE ); #$SIG{ALRM} = sub { die "timeout" }; # Set defaults $USE_PRIMARY_AXIS = 0; # If true, we pretend that each Axis is s +eparate, # and only one can be active at a given t +ime. GetOptions( 'd=s' => \$DEV, 'use_primary' => \$USE_PRIMARY_AXIS, 'led' => \$LED_STATE, ); # Should cajole Linux::Input::Info to export these, constants from inp +ut.h use constant { EV_SYN => 0x00, EV_KEY => 0x01, EV_REL => 0x02, EV_LED => 0x11, REL_X => 0x00, REL_RZ => 0x05, LED_MISC => 0x08, BTN_0 => 0x100, BTN_1 => 0x101, }; use constant { # Axis/button names for array indexes, SPN_LR => 0, # Left/Right SPN_FB => 1, # Fwd/Back SPN_UD => 2, # Up/Down SPN_TILT_FB => 3, # Tilt Fwd/Back SPN_TILT_LR => 4, # Tilt Left/Right (evdev reports this + to - # instead of - to + as we would expect, we f +lip it SPN_ROT_LR => 5, # Rotation Left/Right SPN_BUTTON_1 => 6, SPN_BUTTON_2 => 7, }; use constant { SPN_SCALE => 1000, # We scale the inputs so they are all ~ +/- S +PN_SCALE/2 SPN_MIN_DEFLECTION => 250, # Default minimum delflection, we ignore movement less t +han this SPN_DEBOUNCE => 0.02, # Fractional seconds to debounce actions SPN_AXIS_MAX => 5, # How many axes does the device have? }; # Where we store device Axis info # Eventually, a hash of array refs, keyed by application, all data fro +m config files my @ax_info = ( #SPN_LR() { label => 'SPN_LR', # Name for printing for convience val => 0, # Where we keep the value of the +axis cmin => -342, # Calibration minimum cmax => 382, # Calibration maximum mindeflect => 200, # Movement < this ignored sensitivity => SPN_SCALE, # 0 - SPN_SCALE, higher is more s +ensitive. # let's us favor say, tilt front/back over movement front +/back active => 0, # Internally set, flag if axis is active, l +eave it ;) press_time => 0, # time we went active, leave it ;) event_sent => 0, # Internally set, if an event was generated + yet evebt ignore => 0, # If true, axis is ignored }, #SPN_FB() { label => 'SPN_FB', val => 0, cmin => -412, cmax => 371, mindeflect => 200, sensitivity => SPN_SCALE, active => 0, press_time => 0, event_sent => 0, ignore => 0, }, #SPN_UD() { label => 'SPN_UD', val => 0, cmin => -448, cmax => 397, mindeflect => 200, sensitivity => SPN_SCALE, active => 0, press_time => 0, event_sent => 0, ignore => 0, }, #SPN_TILT_FB() { label => 'SPN_TILT_FB', val => 0, cmin => -374, cmax => 393, mindeflect => 200, sensitivity => SPN_SCALE, active => 0, press_time => 0, event_sent => 0, ignore => 0, }, #SPN_TILT_LR() { label => 'SPN_TILT_LR', val => 0, cmin => 369, cmax => -374, mindeflect => 200, sensitivity => SPN_SCALE, active => 0, press_time => 0, event_sent => 0, ignore => 0, }, #SPN_ROT_LR() { label => 'SPN_ROT_LR', val => 0, cmin => -439, cmax => 381, mindeflect => 200, sensitivity => SPN_SCALE, active => 0, press_time => 0, event_sent => 0, ignore => 0, }, { label => 'SPN_BUTTON_1', val => 0, }, { label => 'SPN_BUTTON_2', val => 0, }, ); ############################################# # Generate scaling data from calibration # ############################################# for my $c ( 0 .. SPN_AXIS_MAX ) { my $mul = $ax_info[$c]->{sensitivity} / ( $ax_info[$c]->{cmin} - $ax_info[$c]->{cmax} ); # Range check here if ( $ax_info[$c]{mindeflect} >= SPN_SCALE / 2 ) { warn "Axis:$c minimum deflection too high!, ignoring\n"; $ax_info[$c]{mindeflect} = SPN_MIN_DEFLECTION; } $ax_info[$c]{mindeflect} = SPN_MIN_DEFLECTION unless exists $ax_info[$c]{mindeflect}; printf( "% 4d : % 4d\n", $ax_info[$c]{cmin} * $mul, $ax_info[$c]{cmax} * $mul ); $ax_info[$c]{scale} = $mul; } die "No device specified!" unless $DEV; # Whoops, no input device my $en = $DEV; if ( -l $en ) { # If symlink, get the actual name. I use udev to symlink it $en = readlink($DEV) or die $!; } die "$en doesn't look like a valid input!" unless ( $en =~ s#^.*event(\d+)$#$1# ); # Should look like eventN # Get dev info for debugging my $i = Linux::Input::Info->new($en); printf "$DEV\n"; printf "\tbustype : %s\n", $i->bustype; printf "\tvendor : 0x%x\n", $i->vendor; printf "\tproduct : 0x%x\n", $i->product; printf "\tversion : %d\n", $i->version; printf "\tname : %s\n", $i->name; printf "\tuniq : %s\n", $i->uniq; printf "\tphys : %s\n", $i->phys; printf "\tbits ev :"; printf " %s", $i->ev_name($_) for $i->bits; printf "\n"; set_spnvled( $DEV, $LED_STATE ); # Get a handle for the input device my $spnv = Linux::Input->new($DEV); # Open the input device print "Press Ctrl-C to quit\n"; while (1) { # Event loop my ( $max_axis, @min, @max ); # Used to figure which axis is +primary my @generated_events; while ( my @events = $spnv->poll(0.001) ) { # Check for an even +t foreach my $e (@events) { # Process 'em my $max_val = 0; if ( $e->{type} == EV_REL ) { # Relative moment e +vent if ( $e->{code} <= REL_RZ ) { # Scale and save the data unless we are set to ign +ore my $axis = $e->{code} - REL_X; $ax_info[$axis]{val} = $ax_info[$axis]{ignore} ? 0 : $e->{value} * $ax_info[$axis]{scale}; } else { warn "Unknown code: $e->{code}!\n"; } } elsif ( $e->{type} == EV_KEY ) { # Button press or rele +ase if ( $e->{code} >= BTN_0 && $e->{code} <= BTN_1 ) { my $button = $e->{code} - BTN_0 ? SPN_BUTTON_2: SPN_BUTTON_1; push @generated_events, [ $button, $e->{'value'} ? 1 : -1, $ax_info[$button]{val} ]; print $ax_info[ $button]{label}, $e->{'value'} ? " pressed!\n" : " released!\n"; } else { warn "Unknown button: $e->{code}!\n"; } } elsif ( $e->{type} == EV_SYN ) { # EV_SYN = sync, the kernel has passed as all the axis +/button info for my $m ( 0 .. SPN_AXIS_MAX ) { if ( abs( $ax_info[$m]{val} ) < $ax_info[$m]{minde +flect} ) { $ax_info[$m]{val} = 0; # Set value to 0 if < Axis mindeflect } if ( $ax_info[$m]{val} ) { # We have an event we care about if ( $ax_info[$m]{press_time} and !$ax_info[$m]{active} ) { # Debounce if ( time() - $ax_info[$m]{press_time} > SPN_DEBOUNCE ) { # It's been active long enough, genera +te an event $ax_info[$m]{active} = $ax_info[$m]{val} > 0 ? -1 : 1; push @generated_events, [ $m, 1, $ax_info[$m]{val} ]; } } else { # Wasn't active, is now, set time $ax_info[$m]{press_time} = time(); # Cha +nge to app } } else { # Clean up as needed if ( $ax_info[$m]{active} ) { # Generate release $ax_info[$m]{active} = 0; push @generated_events, [ $m, -1, $ax_info[$m]{val} ] if $ax_info[$m]{event_sent}; } $ax_info[$m]{press_time} = undef; # Reset p +ress time } if ( $max_val < abs( $ax_info[$m]{val} ) ) { # Save the primary axis $max_axis = $m; $max_val = abs $ax_info[$m]{val}; } } } } } # Now we have that events that need to be processed if (@generated_events) { # If we want only a primary axis, we need to make sure to send # a release event for any Axis previously considered active if ($USE_PRIMARY_AXIS) { @generated_events = grep { $_->[0] == $max_axis or $_->[1] < 0 # Allow primary and release event +s } @generated_events; # Filter pending events # Fake release events for any other axis still active for ( 0 .. SPN_AXIS_MAX ) { next if $_ == $max_axis; # Skip the primary # Generate a release even if a "press" has been s +ent push @generated_events, [ $_, -1, $ax_info[$_]{value} +] if $ax_info[$_]{active} and $ax_info[$_]{event_sent}; } } while (@generated_events) { my $e = shift @generated_events; # Track that the event has been sent so we can surpress # false releases due to USE_PRIMARY_AXIS as needed if ( $e->[1] == 1 ) { $ax_info[ $e->[0] ]{event_sent} = 1; #! Here is where you would actually do something on pr +ess print $ax_info[ $e->[0] ]{label}, " pressed!\n"; } else { $ax_info[ $e->[0] ]{event_sent} = 0; #! Here is where you would actually do something on pr +ess print $ax_info[ $e->[0] ]{label}, " released!\n"; } } } } set_spnvled( $en, 0 ); sub set_spnvled { my ( $dev, $state ) = @_; sysopen( DEV, $dev, O_WRONLY ) or die "Couldn't open $dev for writing: $!\n"; # Highly unportable, need to match struct input_event event in in +put.h my $ev = pack( 'L!L!S!S!i!', time(), '0', EV_LED, LED_MISC, $state + ); my $written = syswrite( DEV, $ev ); die "Write failed:[$written] != [" . length($ev) . "] $!" unless $written == length $ev; }

In reply to Linux 3D Space Navigator control by shotgunefx

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.
  • Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this? | Other CB clients
    Other Users?
    Others rifling through the Monastery: (7)
    As of 2015-07-31 06:33 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









      Results (274 votes), past polls