Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

comment on

( [id://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":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (7)
As of 2024-04-19 11:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found