Main > Linux
Attempting to hack and document GunCon2 for Linux, FreeBSD, and MacOS X.
Numbski:
Okay, as I have posted elsewhere, this may be the closest I could ever hope to come to personally writing a driver for the GunCon2. This script identifies your position on the screen, and whatever button presses are done. The only presumption is makes is that you already have a character device to access the gun. FreeBSD does it by default, and I know how to do it on Gentoo, although I haven't tested it. Hopefully someone can pick this up and write legit drivers with it.
Come to think of it, I could probably use a bit more perl "glue" and map the buttons to keystrokes, but I don't know how I would use the values for X and Y axis to move the mouse around. Never tried it. :P
--- Code: ---#!/usr/bin/perl
use Term::Cap;
# What is the character device for the gun?
$guncon = '/dev/ugen0.1';
# clearing out our status...just in case.
$status = undef;
$value = undef;
$tempvalue = undef;
# Define our byte hash
$byte{ '0' } = 'Buttons';
$byte{ '1' } = 'Buttons';
$byte{ '2' } = 'Horizontal1';
$byte{ '3' } = 'Horizontal2';
$byte{ '4' } = 'Vertical1';
$byte{ '5' } = 'Vertical2';
# Check to make sure this is a character device AND that
# you actually have permission to read from it.
if (!-c $guncon) {
print "$guncon is not a character device!\n";
exit;
}
if (!-r $guncon) {
print "$guncon exists, but you aren't allowed to read it!\n";
exit;
}
# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else. This is so that
# we can refresh your display correctly.
$OSPEED = 9600;
eval {
require POSIX;
my $termios = POSIX::Termios->new();
$termios->getattr;
$OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
$clear = $terminal->Tputs('cl');
# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";
print "$guncon opened successfully. Proceeding to read...\n";
# Switch us to binary mode Scotty! Read the status and print it.
while(1){
binmode GUN;
# Read in 6 bytes, which is precisely the length of the
# GunCon2's updates. Probably could just use read and
# not sysread here, but I was getting some funky behavior
# before.
sysread(GUN,$status, 6);
# $i is just a counter to keep track of what byte we're on.
$i=0;
# More paranoia to make sure we have a clean slate to work from.
$value=undef
$tempvalue=undef;
# Our bytes are split and handled individually...
foreach $value(split(//, $status)) {
# If this is one of the button bytes, use binary,
# otherwise use decimal.
if($i >= 2){
$tempvalue = sprintf("%04d ", ord($value));
}
else{
$tempvalue = sprintf("%08b ", ord($value));
}
# Work with the buttons on the first byte.
if($i == 0){
@digits = split(undef,$tempvalue);
$tempvalue = "";
if ($digits[0] == 0){
$tempvalue .= " Left"
}
if ($digits[1] == 0){
$tempvalue .= " Down"
}
if ($digits[2] == 0){
$tempvalue .= " Right"
}
if ($digits[3] == 0){
$tempvalue .= " Up"
}
if ($digits[4] == 0){
$tempvalue .= " A"
}
if ($digits[5] == 0){
$tempvalue .= " B"
}
if ($digits[6] == 0){
$tempvalue .= " C"
}
}
# And then the buttons on the second byte.
if($i == 1){
@digits = split(undef,$tempvalue);
$tempvalue = "";
if ($digits[0] == 0){
$tempvalue .= " Start"
}
if ($digits[1] == 0){
$tempvalue .= " Select"
}
if ($digits[2] == 0){
$tempvalue .= " Trigger"
}
}
if ($i == 2){
$tempvalue = $tempvalue - 1;
}
if ($i == 4){
$tempvalue = $tempvalue - 5;
}
print "$byte{$i}:\t$tempvalue\n";
# Increment our byte counter.
$i++;
}
# Clean the slate for the next update.
$status = undef;
$value = undef;
$tempvalue=undef;
# Print the rest of the status screen and clear it for the next
# iteration.
print "\nPress Ctrl-C to exit\n";
print $clear;
}
--- End code ---
Numbski:
One last thing, here's all of the pertinent data about the device as per MacOS X. :)
Numbski:
Heh, I got impatient. :)
I found a module - X11::GuiTest that allows me to force mouse movement and clicks from the script. It works well enough that I too get to experience the "rolling x" problem. :D
(UPDATE!!! No rolling X! I had a typo on one of my variables. It WOIKS! Lags like all get out, but it does in fact work!)
For grins, here's that code:
--- Code: ---#!/usr/bin/perl
use Term::Cap;
use X11::GUITest qw/
ClickMouseButton
MoveMouseAbs
/;
# What is the character device for the gun?
$guncon = '/dev/ugen0.1';
# clearing out our status...just in case.
$status = undef;
$value = undef;
$tempvalue = undef;
# Define our byte hash
$byte{ '0' } = 'Buttons';
$byte{ '1' } = 'Buttons';
$byte{ '2' } = 'X-Axis';
$byte{ '3' } = 'X-Mult';
$byte{ '4' } = 'Y-Axis';
$byte{ '5' } = 'Y-Mult';
# Check to make sure this is a character device AND that
# you actually have permission to read from it.
if (!-c $guncon) {
print "$guncon is not a character device!\n";
exit;
}
if (!-r $guncon) {
print "$guncon exists, but you aren't allowed to read it!\n";
exit;
}
# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else. This is so that
# we can refresh your display correctly.
$OSPEED = 9600;
eval {
require POSIX;
my $termios = POSIX::Termios->new();
$termios->getattr;
$OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
$clear = $terminal->Tputs('cl');
# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";
print "$guncon opened successfully. Proceeding to read...\n";
# Switch us to binary mode Scotty! Read the status and print it.
while(1){
binmode GUN;
# Read in 6 bytes, which is precisely the length of the
# GunCon2's updates. Probably could just use read and
# not sysread here, but I was getting some funky behavior
# before.
sysread(GUN,$status, 6);
# $i is just a counter to keep track of what byte we're on.
$i=0;
# More paranoia to make sure we have a clean slate to work from.
$value=undef
$tempvalue=undef;
# Our bytes are split and handled individually...
foreach $value(split(//, $status)) {
# If this is one of the button bytes, use binary,
# otherwise use decimal.
if($i >= 2){
$tempvalue = sprintf("%04d ", ord($value));
}
else{
$tempvalue = sprintf("%08b ", ord($value));
}
# Work with the buttons on the first byte.
if($i == 0){
@digits = split(undef,$tempvalue);
$tempvalue = "";
if ($digits[0] == 0){
$tempvalue .= " Left"
}
if ($digits[1] == 0){
$tempvalue .= " Down"
}
if ($digits[2] == 0){
$tempvalue .= " Right"
}
if ($digits[3] == 0){
$tempvalue .= " Up"
}
if ($digits[4] == 0){
$tempvalue .= " A"
}
if ($digits[5] == 0){
$tempvalue .= " B"
}
if ($digits[6] == 0){
$tempvalue .= " C"
}
}
# And then the buttons on the second byte.
if($i == 1){
@digits = split(undef,$tempvalue);
$tempvalue = "";
if ($digits[0] == 0){
$tempvalue .= " Start"
}
if ($digits[1] == 0){
$tempvalue .= " Select"
}
if ($digits[2] == 0){
$tempvalue .= " Trigger";
ClickMouseButton(1);
}
}
if ($i == 2){
$tempvalue = $tempvalue - 1;
$xpos = $tempvalue;
if ($i == 3){
if($tempvalue > 0){
$xmult = $tempvalue;
}
}
}
if ($i == 4){
$tempvalue = $tempvalue - 5;
$ypos = $tempvalue;
}
if ($i == 5){
if($tempvalue > 0){
$ymult = $tempvalue;
}
}
print "$byte{$i}:\t$tempvalue\n";
# If we got both X and Y coordinates, move the mouse.
if($xmult){
$xpos=$xpos*$xmult;
}
if($ymult){
$xpos=$xpos*$xmult;
}
if ($xpos && $ypos){
MoveMouseAbs $xpos,$ypos;
}
# Increment our byte counter.
$i++;
}
# Clean the slate for the next update.
$status = undef;
$value = undef;
$tempvalue=undef;
$xpos = undef;
$ypos = undef;
$xmult = undef;
$ymult = undef;
# Print the rest of the status screen and clear it for the next
# iteration.
print "\nPress Ctrl-C to exit\n";
print $clear;
}
--- End code ---
Now....how the heck does one fix the "rolling x"? ;)
Numbski:
Hmm. Fixed the lag. Now the gun is just plain inaccurate depending upon where on-screen I'm firing. Sometimes it's dead on. Other times....eh, not so much.
I fixed the lag by only moving the mouse when the trigger gets pulled rather than trying to constantly track. Now results are more or less instantaneous, but off-target. Hey, I've already gotten MUCH further than I'd anticipated possible. So there. :P
--- Code: ---#!/usr/bin/perl
use Term::Cap;
use X11::GUITest qw/
ClickMouseButton
MoveMouseAbs
/;
# What is the character device for the gun?
$guncon = '/dev/ugen0.1';
# clearing out our status...just in case.
$status = undef;
$value = undef;
$tempvalue = undef;
# Define our byte hash
$byte{ '0' } = 'Buttons';
$byte{ '1' } = 'Buttons';
$byte{ '2' } = 'X-Axis';
$byte{ '3' } = 'X-Mult';
$byte{ '4' } = 'Y-Axis';
$byte{ '5' } = 'Y-Mult';
# Check to make sure this is a character device AND that
# you actually have permission to read from it.
if (!-c $guncon) {
print "$guncon is not a character device!\n";
exit;
}
if (!-r $guncon) {
print "$guncon exists, but you aren't allowed to read it!\n";
exit;
}
# See if we can figure out what your terminal speed is...
# We'll presume 9600bps if nothing else. This is so that
# we can refresh your display correctly.
$OSPEED = 9600;
eval {
require POSIX;
my $termios = POSIX::Termios->new();
$termios->getattr;
$OSPEED = $termios->getospeed;
};
$terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED});
$clear = $terminal->Tputs('cl');
# Try to open a filehandle to the gun character device.
print "Attempting to open gun at $guncon...\n";
open GUN, $guncon or die "Can't open $guncon : $!\n";
print "$guncon opened successfully. Proceeding to read...\n";
# Switch us to binary mode Scotty! Read the status and print it.
while(1){
binmode GUN;
# Read in 6 bytes, which is precisely the length of the
# GunCon2's updates. Probably could just use read and
# not sysread here, but I was getting some funky behavior
# before.
sysread(GUN,$status, 6);
# $i is just a counter to keep track of what byte we're on.
$i=0;
# More paranoia to make sure we have a clean slate to work from.
$value=undef
$tempvalue=undef;
# Our bytes are split and handled individually...
foreach $value(split(//, $status)) {
# Determines whether we're firing this time or not.
$fire = 0;
# If this is one of the button bytes, use binary,
# otherwise use decimal.
if($i >= 2){
$tempvalue = sprintf("%04d ", ord($value));
}
else{
$tempvalue = sprintf("%08b ", ord($value));
}
# Work with the buttons on the first byte.
if($i == 0){
@digits = split(undef,$tempvalue);
$tempvalue = "";
if ($digits[0] == 0){
$tempvalue .= " Left";
}
if ($digits[1] == 0){
$tempvalue .= " Down";
}
if ($digits[2] == 0){
$tempvalue .= " Right";
}
if ($digits[3] == 0){
$tempvalue .= " Up";
}
if ($digits[4] == 0){
$tempvalue .= " A";
}
if ($digits[5] == 0){
$tempvalue .= " B";
}
if ($digits[6] == 0){
$tempvalue .= " C";
}
}
# And then the buttons on the second byte.
if($i == 1){
@digits = split(undef,$tempvalue);
$tempvalue = "";
if ($digits[0] == 0){
$tempvalue .= " Start";
}
if ($digits[1] == 0){
$tempvalue .= " Select";
}
if ($digits[2] == 0){
$tempvalue .= " Trigger";
$fire = 1;
}
}
if ($i == 2){
$tempvalue = $tempvalue - 1;
$xpos = $tempvalue;
if ($i == 3){
if($tempvalue > 0){
$xmult = $tempvalue;
}
}
}
if ($i == 4){
$tempvalue = $tempvalue - 5;
$ypos = $tempvalue;
}
if ($i == 5){
if($tempvalue > 0){
$ymult = $tempvalue;
}
}
print "$byte{$i}:\t$tempvalue\n";
if($fire >= 1){
# If we got both X and Y coordinates, move the mouse.
if($xmult >= 1){
$xpos=$xpos+($xmult*256);
}
# if($ymult){
# $xpos=$xpos*$xmult;
# }
MoveMouseAbs $xpos , $ypos;
print "Mouse Moved to $xpos x $ypos\n";
ClickMouseButton(1);
}
# Increment our byte counter.
$i++;
}
# Clean the slate for the next update.
$status = undef;
$value = undef;
$tempvalue=undef;
# Print the rest of the status screen and clear it for the next
# iteration.
print "\nPress Ctrl-C to exit\n";
print $clear;
}
--- End code ---
Numbski:
Now that I've had some time to play with my own hack, I'm noticing some very peculiar behavior.
On the X-Axis, I start at 001 decimal, with my third place holding at 0. It then immediately jumps to 35, with the third placeholder at 1. It then increments as expected to 255, then the third placeholder becomes 2. We get 0-255 on that, third placeholder becomes a 3. Then it gets odd. Right around dead center of the screen. With the third placeholder at 3, I get 0-~35, then it jumps back to the third placeholder being a 0 again, and starts counting from 0-255, then the third placeholder becomes a 1.
The problem is relatively obvious: there are areas of the X-Axis that repeat! But how? Why on earth is the guncon detecting the same X-Axis twice? I have the screen resolution set relatively low as it is.
Given what I'm seeing here, it has 0,0-255, 1,0-255, 2,0-255, and 3,0-32.
800 pixels wide, yet my screen is nowhere NEAR 800 pixels wide the way I'm testing. Plus, I'm getting repeats. Grr...have no idea how this thing tracks on the X-Axis. Y-Axis seems to be behaving just fine.
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version