Hold onto your hats kids, it's the biggest little refactor this side of the
Pecos. I'll sort out the per-project niggling bits in just a moment. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4209 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -1,141 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
import com.samskivert.util.ResultListener;
|
||||
import com.samskivert.util.RunAnywhere;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Encapsulates a bunch of hackery needed to invoke an external web browser
|
||||
* from within a Java application.
|
||||
*/
|
||||
public class BrowserUtil
|
||||
{
|
||||
/**
|
||||
* Opens the user's web browser with the specified URL.
|
||||
*
|
||||
* @param url the URL to display in an external browser.
|
||||
* @param listener a listener to be notified if we failed to launch the
|
||||
* browser. <em>Note:</em> it will not be notified of success.
|
||||
*/
|
||||
public static void browseURL (URL url, ResultListener listener)
|
||||
{
|
||||
browseURL(url, listener, "firefox");
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the user's web browser with the specified URL.
|
||||
*
|
||||
* @param url the URL to display in an external browser.
|
||||
* @param listener a listener to be notified if we failed to launch the
|
||||
* browser. <em>Note:</em> it will not be notified of success.
|
||||
* @param genagent the path to the browser to execute on non-Windows,
|
||||
* non-MacOS.
|
||||
*/
|
||||
public static void browseURL (
|
||||
URL url, ResultListener listener, String genagent)
|
||||
{
|
||||
String[] cmd;
|
||||
if (RunAnywhere.isWindows()) {
|
||||
// TODO: test this on Vinders 98
|
||||
// cmd = new String[] { "rundll32", "url.dll,FileProtocolHandler",
|
||||
// url.toString() };
|
||||
String osName = System.getProperty("os.name");
|
||||
if (osName.indexOf("9") != -1 || osName.indexOf("Me") != -1) {
|
||||
cmd = new String[] { "command.com", "/c", "start",
|
||||
"\"" + url.toString() + "\"" };
|
||||
} else {
|
||||
cmd = new String[] { "cmd.exe", "/c", "start", "\"\"",
|
||||
"\"" + url.toString() + "\"" };
|
||||
}
|
||||
|
||||
} else if (RunAnywhere.isMacOS()) {
|
||||
cmd = new String[] { "open", url.toString() };
|
||||
|
||||
} else { // Linux, Solaris, etc
|
||||
cmd = new String[] { genagent, url.toString() };
|
||||
}
|
||||
|
||||
Log.info("Browsing URL [cmd=" + StringUtil.join(cmd, " ") + "].");
|
||||
try {
|
||||
Process process = Runtime.getRuntime().exec(cmd);
|
||||
BrowserTracker tracker = new BrowserTracker(process, url, listener);
|
||||
tracker.start();
|
||||
} catch (Exception e) {
|
||||
Log.warning("Failed to launch browser [url=" + url +
|
||||
", error=" + e + "].");
|
||||
listener.requestFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class BrowserTracker extends Thread
|
||||
{
|
||||
public BrowserTracker (Process process, URL url, ResultListener rl) {
|
||||
super("BrowserLaunchWaiter");
|
||||
setDaemon(true);
|
||||
_process = process;
|
||||
_url = url;
|
||||
_listener = rl;
|
||||
}
|
||||
|
||||
public void run () {
|
||||
try {
|
||||
_process.waitFor();
|
||||
int rv = _process.exitValue();
|
||||
if (rv == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
String errmsg = "Launched browser failed [rv=" + rv + "].";
|
||||
Log.warning(errmsg);
|
||||
if (!RunAnywhere.isWindows()) {
|
||||
_listener.requestFailed(new Exception(errmsg));
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're on windows, make a last ditch effort
|
||||
String[] cmd = new String[] {
|
||||
"C:\\Program Files\\Internet Explorer\\" +
|
||||
"IEXPLORE.EXE", "\"" + _url.toString() + "\""};
|
||||
Process process = Runtime.getRuntime().exec(cmd);
|
||||
process.waitFor();
|
||||
rv = process.exitValue();
|
||||
if (rv != 0) {
|
||||
errmsg = "Failed to launch iexplore.exe [rv=" + rv + "].";
|
||||
Log.warning(errmsg);
|
||||
_listener.requestFailed(new Exception(errmsg));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.logStackTrace(e);
|
||||
_listener.requestFailed(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected Process _process;
|
||||
protected URL _url;
|
||||
protected ResultListener _listener;
|
||||
};
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
/**
|
||||
* A single, top-level location for the definition of compass direction
|
||||
* constants, which are used by a variety of Narya services.
|
||||
*/
|
||||
public interface DirectionCodes
|
||||
{
|
||||
/** A direction code indicating no direction. */
|
||||
public static final int NONE = -1;
|
||||
|
||||
/** A direction code indicating moving left. */
|
||||
public static final int LEFT = 0;
|
||||
|
||||
/** A direction code indicating moving right. */
|
||||
public static final int RIGHT = 1;
|
||||
|
||||
/** A direction code indicating a counter-clockwise rotation. */
|
||||
public static final int CCW = 0;
|
||||
|
||||
/** A direction code indicating a clockwise rotation. */
|
||||
public static final int CW = 1;
|
||||
|
||||
/** A direction code indicating horizontal movement. */
|
||||
public static final int HORIZONTAL = 0;
|
||||
|
||||
/** A direction code indicating vertical movement. */
|
||||
public static final int VERTICAL = 1;
|
||||
|
||||
/** A direction code indicating southwest. */
|
||||
public static final int SOUTHWEST = 0;
|
||||
|
||||
/** A direction code indicating west. */
|
||||
public static final int WEST = 1;
|
||||
|
||||
/** A direction code indicating northwest. */
|
||||
public static final int NORTHWEST = 2;
|
||||
|
||||
/** A direction code indicating north. */
|
||||
public static final int NORTH = 3;
|
||||
|
||||
/** A direction code indicating northeast. */
|
||||
public static final int NORTHEAST = 4;
|
||||
|
||||
/** A direction code indicating east. */
|
||||
public static final int EAST = 5;
|
||||
|
||||
/** A direction code indicating southeast. */
|
||||
public static final int SOUTHEAST = 6;
|
||||
|
||||
/** A direction code indicating south. */
|
||||
public static final int SOUTH = 7;
|
||||
|
||||
/** The number of basic compass directions. */
|
||||
public static final int DIRECTION_COUNT = 8;
|
||||
|
||||
/** A direction code indicating west by southwest. */
|
||||
public static final int WESTSOUTHWEST = 8;
|
||||
|
||||
/** A direction code indicating west by northwest. */
|
||||
public static final int WESTNORTHWEST = 9;
|
||||
|
||||
/** A direction code indicating north by northwest. */
|
||||
public static final int NORTHNORTHWEST = 10;
|
||||
|
||||
/** A direction code indicating north by northeast. */
|
||||
public static final int NORTHNORTHEAST = 11;
|
||||
|
||||
/** A direction code indicating east by northeast. */
|
||||
public static final int EASTNORTHEAST = 12;
|
||||
|
||||
/** A direction code indicating east by southeast. */
|
||||
public static final int EASTSOUTHEAST = 13;
|
||||
|
||||
/** A direction code indicating south by southeast. */
|
||||
public static final int SOUTHSOUTHEAST = 14;
|
||||
|
||||
/** A direction code indicating south by southwest. */
|
||||
public static final int SOUTHSOUTHWEST = 15;
|
||||
|
||||
/** The number of fine compass directions. */
|
||||
public static final int FINE_DIRECTION_COUNT = 16;
|
||||
}
|
||||
@@ -1,338 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.awt.Point;
|
||||
|
||||
import com.samskivert.util.IntListUtil;
|
||||
|
||||
/**
|
||||
* Direction related utility functions.
|
||||
*/
|
||||
public class DirectionUtil implements DirectionCodes
|
||||
{
|
||||
/**
|
||||
* Returns an array of names corresponding to each direction constant.
|
||||
*/
|
||||
public static String[] getDirectionNames ()
|
||||
{
|
||||
return DIR_STRINGS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the supplied direction code.
|
||||
*/
|
||||
public static String toString (int direction)
|
||||
{
|
||||
return ((direction >= 0) && (direction < FINE_DIRECTION_COUNT)) ?
|
||||
DIR_STRINGS[direction] : "INVALID";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an abbreviated string representation of the supplied
|
||||
* direction code.
|
||||
*/
|
||||
public static String toShortString (int direction)
|
||||
{
|
||||
return ((direction >= 0) && (direction < FINE_DIRECTION_COUNT)) ?
|
||||
SHORT_DIR_STRINGS[direction] : "?";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the direction code that corresponds to the supplied string
|
||||
* or {@link #NONE} if the string does not correspond to a known
|
||||
* direction code.
|
||||
*/
|
||||
public static int fromString (String dirstr)
|
||||
{
|
||||
for (int ii = 0; ii < FINE_DIRECTION_COUNT; ii++) {
|
||||
if (DIR_STRINGS[ii].equals(dirstr)) {
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the direction code that corresponds to the supplied short
|
||||
* string or {@link #NONE} if the string does not correspond to a
|
||||
* known direction code.
|
||||
*/
|
||||
public static int fromShortString (String dirstr)
|
||||
{
|
||||
for (int ii = 0; ii < FINE_DIRECTION_COUNT; ii++) {
|
||||
if (SHORT_DIR_STRINGS[ii].equals(dirstr)) {
|
||||
return ii;
|
||||
}
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of an array of direction codes. The
|
||||
* directions are represented by the abbreviated names.
|
||||
*/
|
||||
public static String toString (int[] directions)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder("{");
|
||||
for (int i = 0; i < directions.length; i++) {
|
||||
if (i > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append(toShortString(directions[i]));
|
||||
}
|
||||
return buf.append("}").toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the requested <em>fine</em> direction constant clockwise by
|
||||
* the requested number of ticks.
|
||||
*/
|
||||
public static int rotateCW (int direction, int ticks)
|
||||
{
|
||||
for (int ii = 0; ii < ticks; ii++) {
|
||||
direction = FINE_CW_ROTATE[direction];
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates the requested <em>fine</em> direction constant
|
||||
* counter-clockwise by the requested number of ticks.
|
||||
*/
|
||||
public static int rotateCCW (int direction, int ticks)
|
||||
{
|
||||
for (int ii = 0; ii < ticks; ii++) {
|
||||
direction = FINE_CCW_ROTATE[direction];
|
||||
}
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the opposite of the specified direction.
|
||||
*/
|
||||
public static int getOpposite (int direction)
|
||||
{
|
||||
return rotateCW(direction, FINE_CW_ROTATE.length/2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direction closest to the specified direction, out of
|
||||
* the directions in the possible list (preferring a clockwise match).
|
||||
*/
|
||||
public static int getClosest (int direction, int[] possible)
|
||||
{
|
||||
return getClosest(direction, possible, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direction closest to the specified direction, out of
|
||||
* the directions in the possible list.
|
||||
*
|
||||
* @param preferCW whether to prefer a clockwise match or a
|
||||
* counter-clockwise match.
|
||||
*/
|
||||
public static int getClosest (int direction, int[] possible,
|
||||
boolean preferCW)
|
||||
{
|
||||
// rotate a tick at a time, looking for matches
|
||||
int first = direction;
|
||||
int second = direction;
|
||||
for (int ii = 0; ii <= FINE_DIRECTION_COUNT / 2; ii++) {
|
||||
if (IntListUtil.contains(possible, first)) {
|
||||
return first;
|
||||
}
|
||||
|
||||
if (ii != 0 && IntListUtil.contains(possible, second)) {
|
||||
return second;
|
||||
}
|
||||
|
||||
first = preferCW ? rotateCW(first, 1) : rotateCCW(first, 1);
|
||||
second = preferCW ? rotateCCW(second, 1) : rotateCW(second, 1);
|
||||
}
|
||||
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the eight compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getDirection (Point a, Point b)
|
||||
{
|
||||
return getDirection(a.getX(), a.getY(), b.getX(), b.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the eight compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getDirection (int ax, int ay, int bx, int by)
|
||||
{
|
||||
return getDirection(Math.atan2(by-ay, bx-ax));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the eight compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getDirection (double ax, double ay, double bx, double by)
|
||||
{
|
||||
return getDirection(Math.atan2(by-ay, bx-ax));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the eight compass directions is associated with
|
||||
* the specified angle theta. <em>Note:</em> that the angle supplied
|
||||
* is assumed to increase clockwise around the origin (which screen
|
||||
* angles do) rather than counter-clockwise around the origin (which
|
||||
* cartesian angles do) and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getDirection (double theta)
|
||||
{
|
||||
theta = ((theta + Math.PI) * 4) / Math.PI;
|
||||
return (int)(Math.round(theta) + WEST) % 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the sixteen compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getFineDirection (Point a, Point b)
|
||||
{
|
||||
return getFineDirection(a.x, a.y, b.x, b.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the sixteen compass directions that point
|
||||
* <code>b</code> lies in from point <code>a</code> as one of the
|
||||
* {@link DirectionCodes} direction constants. <em>Note:</em> that the
|
||||
* coordinates supplied are assumed to be logical (screen) rather than
|
||||
* cartesian coordinates and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getFineDirection (int ax, int ay, int bx, int by)
|
||||
{
|
||||
return getFineDirection(Math.atan2(by-ay, bx-ax));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which of the sixteen compass directions is associated with
|
||||
* the specified angle theta. <em>Note:</em> that the angle supplied
|
||||
* is assumed to increase clockwise around the origin (which screen
|
||||
* angles do) rather than counter-clockwise around the origin (which
|
||||
* cartesian angles do) and <code>NORTH</code> is considered to point
|
||||
* toward the top of the screen.
|
||||
*/
|
||||
public static int getFineDirection (double theta)
|
||||
{
|
||||
theta = ((theta + Math.PI) * 8) / Math.PI;
|
||||
return ANGLE_MAP[(int)Math.round(theta) % FINE_DIRECTION_COUNT];
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the specified point in the specified screen direction,
|
||||
* adjusting by the specified adjustments. Fine directions are
|
||||
* not supported.
|
||||
*/
|
||||
public static void moveDirection (Point p, int direction, int dx, int dy)
|
||||
{
|
||||
if (direction >= DIRECTION_COUNT) {
|
||||
throw new IllegalArgumentException(
|
||||
"Fine coordinates not supported.");
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case NORTH: case NORTHWEST: case NORTHEAST: p.y -= dy;
|
||||
}
|
||||
switch (direction) {
|
||||
case SOUTH: case SOUTHWEST: case SOUTHEAST: p.y += dy;
|
||||
}
|
||||
switch (direction) {
|
||||
case WEST: case SOUTHWEST: case NORTHWEST: p.x -= dx;
|
||||
}
|
||||
switch (direction) {
|
||||
case EAST: case SOUTHEAST: case NORTHEAST: p.x += dx;
|
||||
}
|
||||
}
|
||||
|
||||
/** Direction constant string names. */
|
||||
protected static final String[] DIR_STRINGS = {
|
||||
"SOUTHWEST", "WEST", "NORTHWEST", "NORTH",
|
||||
"NORTHEAST", "EAST", "SOUTHEAST", "SOUTH",
|
||||
"WESTSOUTHWEST", "WESTNORTHWEST", "NORTHNORTHWEST", "NORTHNORTHEAST",
|
||||
"EASTNORTHEAST", "EASTSOUTHEAST", "SOUTHSOUTHEAST", "SOUTHSOUTHWEST",
|
||||
};
|
||||
|
||||
/** Abbreviated direction constant string names. */
|
||||
protected static final String[] SHORT_DIR_STRINGS = {
|
||||
"SW", "W", "NW", "N", "NE", "E", "SE", "S",
|
||||
"WSW", "WNW", "NNW", "NNE", "ENE", "ESE", "SSE", "SSW",
|
||||
};
|
||||
|
||||
/** Used to rotate a fine compass direction clockwise. */
|
||||
protected static final int[] FINE_CW_ROTATE = {
|
||||
/* SW -> */ WESTSOUTHWEST, /* W -> */ WESTNORTHWEST,
|
||||
/* NW -> */ NORTHNORTHWEST, /* N -> */ NORTHNORTHEAST,
|
||||
/* NE -> */ EASTNORTHEAST, /* E -> */ EASTSOUTHEAST,
|
||||
/* SE -> */ SOUTHSOUTHEAST, /* S -> */ SOUTHSOUTHWEST,
|
||||
/* WSW -> */ WEST, /* WNW -> */ NORTHWEST,
|
||||
/* NNW -> */ NORTH, /* NNE -> */ NORTHEAST,
|
||||
/* ENE -> */ EAST, /* ESE -> */ SOUTHEAST,
|
||||
/* SSE -> */ SOUTH, /* SSW -> */ SOUTHWEST
|
||||
};
|
||||
|
||||
/** Used to rotate a fine compass direction counter-clockwise. */
|
||||
protected static final int[] FINE_CCW_ROTATE = {
|
||||
/* SW -> */ SOUTHSOUTHWEST, /* W -> */ WESTSOUTHWEST,
|
||||
/* NW -> */ WESTNORTHWEST, /* N -> */ NORTHNORTHWEST,
|
||||
/* NE -> */ NORTHNORTHEAST, /* E -> */ EASTNORTHEAST,
|
||||
/* SE -> */ EASTSOUTHEAST, /* S -> */ SOUTHSOUTHEAST,
|
||||
/* WSW -> */ SOUTHWEST, /* WNW -> */ WEST,
|
||||
/* NNW -> */ NORTHWEST, /* NNE -> */ NORTH,
|
||||
/* ENE -> */ NORTHEAST, /* ESE -> */ EAST,
|
||||
/* SSE -> */ SOUTHEAST, /* SSW -> */ SOUTH
|
||||
};
|
||||
|
||||
/** Used to map an angle to a fine compass direction. */
|
||||
protected static final int[] ANGLE_MAP = {
|
||||
WEST, WESTNORTHWEST, NORTHWEST, NORTHNORTHWEST, NORTH, NORTHNORTHEAST,
|
||||
NORTHEAST, EASTNORTHEAST, EAST, EASTSOUTHEAST, SOUTHEAST,
|
||||
SOUTHSOUTHEAST, SOUTH, SOUTHSOUTHWEST, SOUTHWEST, WESTSOUTHWEST };
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2006 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.AWTEventListener;
|
||||
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.RunQueue;
|
||||
|
||||
/**
|
||||
* Used to track user idleness in an AWT application.
|
||||
*/
|
||||
public abstract class IdleTracker
|
||||
{
|
||||
/**
|
||||
* Creates an idle tracker that will report idleness (via {@link
|
||||
* #idledOut}) after <code>toIdleTime</code> milliseconds have elapsed.
|
||||
* After an additional <code>toAbandonTime</code> milliseconds have
|
||||
* elapsed, we will report that the user has {@link #abandonedShip}.
|
||||
*/
|
||||
public IdleTracker (long toIdleTime, long toAbandonTime)
|
||||
{
|
||||
_toIdleTime = toIdleTime;
|
||||
_toAbandonTime = toAbandonTime;
|
||||
|
||||
// initialize our last event time
|
||||
_lastEvent = getTimeStamp();
|
||||
}
|
||||
|
||||
public void start (KeyboardManager keymgr, RunQueue rqueue)
|
||||
{
|
||||
// we want to observe all mouse and keyboard events
|
||||
long eventMask =
|
||||
AWTEvent.MOUSE_EVENT_MASK |
|
||||
AWTEvent.MOUSE_MOTION_EVENT_MASK |
|
||||
AWTEvent.MOUSE_WHEEL_EVENT_MASK |
|
||||
AWTEvent.KEY_EVENT_MASK;
|
||||
|
||||
// add the global event listener
|
||||
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
|
||||
public void eventDispatched (AWTEvent event) {
|
||||
handleUserActivity();
|
||||
}
|
||||
}, eventMask);
|
||||
|
||||
// and tie into the keyboard manager if one is provided
|
||||
if (keymgr != null) {
|
||||
keymgr.registerKeyObserver(new KeyboardManager.KeyObserver() {
|
||||
public void handleKeyEvent (
|
||||
int id, int keyCode, long timestamp) {
|
||||
handleUserActivity();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// register an interval to periodically check our last activity time
|
||||
new Interval(rqueue) {
|
||||
public void expired () {
|
||||
checkIdle();
|
||||
}
|
||||
}.schedule(_toIdleTime/3, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the client has been idle for {@link #_toIdleTime}
|
||||
* milliseconds.
|
||||
*/
|
||||
protected abstract void idledOut ();
|
||||
|
||||
/**
|
||||
* Called when the client becomes non-idle after we have previously
|
||||
* reported their idleness.
|
||||
*/
|
||||
protected abstract void idledIn ();
|
||||
|
||||
/**
|
||||
* Called when the client has been idle for {@link #_toIdleTime} plus
|
||||
* {@link #_toAbandonTime} milliseconds.
|
||||
*/
|
||||
protected abstract void abandonedShip ();
|
||||
|
||||
/**
|
||||
* This should return a timestamp. We would use {@link
|
||||
* System#getCurrentTimeMillis} except that on Windows that sometimes does
|
||||
* strange things like leap forward in time causing immediate idleness.
|
||||
*/
|
||||
protected abstract long getTimeStamp ();
|
||||
|
||||
/**
|
||||
* Called with any keyboard or mouse events performed on the frame so
|
||||
* as to note user activity as it pertains to tracking the client idle
|
||||
* state.
|
||||
*/
|
||||
protected void handleUserActivity ()
|
||||
{
|
||||
// note the time of the last user action
|
||||
_lastEvent = getTimeStamp();
|
||||
|
||||
// idle-in if appropriate
|
||||
if (_state != ACTIVE) {
|
||||
_state = ACTIVE;
|
||||
idledIn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the last user event time and posts a command to idle them
|
||||
* out if they've been inactive for too long, or log them out if
|
||||
* they've been idle for too long.
|
||||
*/
|
||||
protected void checkIdle ()
|
||||
{
|
||||
long now = getTimeStamp();
|
||||
|
||||
switch (_state) {
|
||||
case ACTIVE:
|
||||
// check whether they've idled out
|
||||
if (now >= (_lastEvent + _toIdleTime)) {
|
||||
Log.info("User idle for " + (now-_lastEvent) + "ms.");
|
||||
_state = IDLE;
|
||||
idledOut();
|
||||
}
|
||||
break;
|
||||
|
||||
case IDLE:
|
||||
// check whether they've been idle for too long
|
||||
if (now >= (_lastEvent + _toIdleTime + _toAbandonTime)) {
|
||||
Log.info("User idle for " + (now-_lastEvent) + "ms. " +
|
||||
"Abandoning ship.");
|
||||
_state = ABANDONED;
|
||||
abandonedShip();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// /** The user's current state. */
|
||||
// protected static enum State { ACTIVE, IDLE, ABANDONED };
|
||||
|
||||
/** The duration after which we declare the user to be idle. */
|
||||
protected long _toIdleTime;
|
||||
|
||||
/** The duration after which we declare the user to have abandoned ship. */
|
||||
protected long _toAbandonTime;
|
||||
|
||||
/** The time of the last mouse or keyboard event; used to track
|
||||
* whether the user is idle. */
|
||||
protected long _lastEvent;
|
||||
|
||||
/** Whether the user is currently active, idle or abandoned. */
|
||||
protected int _state = ACTIVE;
|
||||
|
||||
protected static final int ACTIVE = 0;
|
||||
protected static final int IDLE = 1;
|
||||
protected static final int ABANDONED = 2;
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Window;
|
||||
import java.awt.KeyEventDispatcher;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowFocusListener;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import javax.swing.JRootPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import javax.swing.event.AncestorListener;
|
||||
import javax.swing.text.JTextComponent;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
|
||||
/**
|
||||
* Handles dispatching special global key pressed and released events to
|
||||
* those that care to monitor and process such things.
|
||||
*
|
||||
* <p> A {@link JTextComponent} may registered as a "chat grabber" via
|
||||
* {@link #pushChatGrabber} so as to capture typed chat characters
|
||||
* regardless of which component currently has the focus.
|
||||
*
|
||||
* <p> Components may also register as global {@link KeyListener}s via
|
||||
* {@link #addGlobalKeyListener} to always be notified of key press and
|
||||
* release events for all keys.
|
||||
*/
|
||||
public class KeyDispatcher
|
||||
implements KeyEventDispatcher, AncestorListener, WindowFocusListener
|
||||
{
|
||||
/**
|
||||
* Constructs a key dispatcher.
|
||||
*/
|
||||
public KeyDispatcher (Window window)
|
||||
{
|
||||
// save things off
|
||||
_window = window;
|
||||
|
||||
// listen to window events on our main window so that we can release
|
||||
// keys when the mouse leaves the window
|
||||
_window.addWindowFocusListener(this);
|
||||
|
||||
// monitor key events from the central dispatch mechanism
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().
|
||||
addKeyEventDispatcher(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shuts down the key dispatcher.
|
||||
*/
|
||||
public void shutdown ()
|
||||
{
|
||||
// cease monitoring key events
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().
|
||||
removeKeyEventDispatcher(this);
|
||||
|
||||
// cease observing our window
|
||||
_window.removeWindowFocusListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the specified component the new grabber of key typed events
|
||||
* that look like they're chat-related per {@link #isChatCharacter}.
|
||||
*/
|
||||
public void pushChatGrabber (JTextComponent comp)
|
||||
{
|
||||
// note this component as the new chat grabber
|
||||
_curChatGrabber = comp;
|
||||
|
||||
// add the component to the list of grabbers
|
||||
_chatGrabbers.addLast(comp);
|
||||
comp.addAncestorListener(this);
|
||||
|
||||
// and request to give the new component the focus since that's a
|
||||
// sensible thing to do as it's aiming to nab all key events
|
||||
// henceforth
|
||||
comp.requestFocusInWindow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified component from the list of chat grabbers so
|
||||
* that it will no longer be notified of chat-like key events.
|
||||
*/
|
||||
public void removeChatGrabber (JTextComponent comp)
|
||||
{
|
||||
// remove the component from the list of grabbers
|
||||
comp.removeAncestorListener(this);
|
||||
_chatGrabbers.remove(comp);
|
||||
|
||||
// update the current chat grabbing component
|
||||
_curChatGrabber = _chatGrabbers.isEmpty() ? null :
|
||||
_chatGrabbers.getLast();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the key listener to receive all key events at all times.
|
||||
*/
|
||||
public void addGlobalKeyListener (KeyListener listener)
|
||||
{
|
||||
_listeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified global key listener.
|
||||
*/
|
||||
public void removeGlobalKeyListener (KeyListener listener)
|
||||
{
|
||||
_listeners.remove(listener);
|
||||
}
|
||||
|
||||
// documentation inherited from interface KeyEventDispatcher
|
||||
public boolean dispatchKeyEvent (KeyEvent e)
|
||||
{
|
||||
int lsize = _listeners.size();
|
||||
|
||||
switch (e.getID()) {
|
||||
case KeyEvent.KEY_TYPED:
|
||||
// dispatch to all the global listeners
|
||||
for (int ii = 0; ii < lsize; ii++) {
|
||||
_listeners.get(ii).keyTyped(e);
|
||||
}
|
||||
|
||||
// see if a chat grabber needs to grab it
|
||||
if (_curChatGrabber != null) {
|
||||
Component target = e.getComponent();
|
||||
// if the key was typed on a non-text component or one
|
||||
// that wasn't editable...
|
||||
if (isChatCharacter(e.getKeyChar()) &&
|
||||
!isTypableTarget(target)) {
|
||||
// focus our grabby component, and redirect this
|
||||
// key event there
|
||||
_curChatGrabber.requestFocusInWindow();
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().
|
||||
redispatchEvent(_curChatGrabber, e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case KeyEvent.KEY_PRESSED:
|
||||
if (lsize > 0) {
|
||||
for (int ii = 0; ii < lsize; ii++) {
|
||||
_listeners.get(ii).keyPressed(e);
|
||||
}
|
||||
// remember the key event..
|
||||
_downKeys.put(e.getKeyCode(), e);
|
||||
}
|
||||
break;
|
||||
|
||||
case KeyEvent.KEY_RELEASED:
|
||||
if (lsize > 0) {
|
||||
for (int ii = 0; ii < lsize; ii++) {
|
||||
((KeyListener) _listeners.get(ii)).keyReleased(e);
|
||||
}
|
||||
// forget the key event
|
||||
_downKeys.remove(e.getKeyCode());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified target component supports being typed
|
||||
* into, and thus we shouldn't steal focus away from it if the user
|
||||
* starts typing.
|
||||
*/
|
||||
protected boolean isTypableTarget (Component target)
|
||||
{
|
||||
return target.isShowing() &&
|
||||
(((target instanceof JTextComponent) &&
|
||||
((JTextComponent) target).isEditable()) ||
|
||||
(target instanceof JTable) ||
|
||||
(target instanceof JRootPane));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified character is a chat character.
|
||||
*/
|
||||
protected boolean isChatCharacter (char c)
|
||||
{
|
||||
return (Character.isLetterOrDigit(c) || ('/' == c));
|
||||
}
|
||||
|
||||
// documentation inherited from interface WindowFocusListener
|
||||
public void windowGainedFocus (WindowEvent e)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
// documentation inherited from interface WindowFocusListener
|
||||
public void windowLostFocus (WindowEvent e)
|
||||
{
|
||||
// un-press any keys that were left down
|
||||
if (!_downKeys.isEmpty()) {
|
||||
long now = System.currentTimeMillis();
|
||||
for (KeyEvent down : _downKeys.values()) {
|
||||
KeyEvent up = new KeyEvent(
|
||||
down.getComponent(), KeyEvent.KEY_RELEASED, now,
|
||||
down.getModifiers(), down.getKeyCode(), down.getKeyChar(),
|
||||
down.getKeyLocation());
|
||||
for (int ii = 0, nn = _listeners.size(); ii < nn; ii++) {
|
||||
_listeners.get(ii).keyReleased(up);
|
||||
}
|
||||
}
|
||||
_downKeys.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface AncestorListener
|
||||
public void ancestorAdded (AncestorEvent ae)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
// documentation inherited from interface AncestorListener
|
||||
public void ancestorMoved (AncestorEvent ae)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
// documentation inherited from interface AncestorListener
|
||||
public void ancestorRemoved (AncestorEvent ae)
|
||||
{
|
||||
removeChatGrabber((JTextComponent) ae.getComponent());
|
||||
}
|
||||
|
||||
/** The main window for which we're observing key events. */
|
||||
protected Window _window;
|
||||
|
||||
/** The current most-recently pushed component that wants to grab
|
||||
* alphanumeric key presses. */
|
||||
protected JTextComponent _curChatGrabber;
|
||||
|
||||
/** The stack of grabbers. */
|
||||
protected LinkedList<JTextComponent> _chatGrabbers =
|
||||
new LinkedList<JTextComponent>();
|
||||
|
||||
/** Global key listeners. */
|
||||
protected ArrayList<KeyListener> _listeners = new ArrayList<KeyListener>();
|
||||
|
||||
/** Keys that are currently held down. */
|
||||
protected HashIntMap<KeyEvent> _downKeys = new HashIntMap<KeyEvent>();
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* The key translator interface provides a means whereby the keyboard
|
||||
* manager can map a key code to the logical {@link
|
||||
* com.samskivert.swing.Controller} action command that it represents.
|
||||
*/
|
||||
public interface KeyTranslator
|
||||
{
|
||||
/**
|
||||
* Returns whether there is an action command for the key
|
||||
* corresponding to the given keycode. The translator may have an
|
||||
* action command for either a key press or a key release of the key,
|
||||
* or both.
|
||||
*/
|
||||
public boolean hasCommand (int keyCode);
|
||||
|
||||
/**
|
||||
* Returns the action command string associated with a key press of
|
||||
* the key corresponding to the given key code, or <code>null</code>
|
||||
* if there is no associated command.
|
||||
*/
|
||||
public String getPressCommand (int keyCode);
|
||||
|
||||
/**
|
||||
* Returns the action command string associated with a key release of
|
||||
* the key corresponding to the given key code, or <code>null</code>
|
||||
* if there is no associated command.
|
||||
*/
|
||||
public String getReleaseCommand (int keyCode);
|
||||
|
||||
/**
|
||||
* Returns the number of times each second that key presses are to be
|
||||
* automatically repeated while the key is held down, or
|
||||
* <code>0</code> to disable auto-repeat for the key.
|
||||
*/
|
||||
public int getRepeatRate (int keyCode);
|
||||
|
||||
/**
|
||||
* Returns the delay in milliseconds before generating auto-repeated
|
||||
* key press events for the specified key.
|
||||
*/
|
||||
public long getRepeatDelay (int keyCode);
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the available press
|
||||
* commands.
|
||||
*/
|
||||
public Iterator enumeratePressCommands ();
|
||||
|
||||
/**
|
||||
* Returns an iterator that iterates over the available release
|
||||
* commands.
|
||||
*/
|
||||
public Iterator enumerateReleaseCommands ();
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
|
||||
/**
|
||||
* A basic implementation of the {@link KeyTranslator} interface that
|
||||
* provides facilities for mapping key codes to action command strings for
|
||||
* use by the {@link KeyboardManager}.
|
||||
*/
|
||||
public class KeyTranslatorImpl implements KeyTranslator
|
||||
{
|
||||
/**
|
||||
* Adds a mapping from a key press to an action command string that
|
||||
* will auto-repeat at a default repeat rate.
|
||||
*/
|
||||
public void addPressCommand (int keyCode, String command)
|
||||
{
|
||||
addPressCommand(keyCode, command, DEFAULT_REPEAT_RATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping from a key press to an action command string that
|
||||
* will auto-repeat at the specified repeat rate. Overwrites any
|
||||
* existing mapping and repeat rate that may have already been
|
||||
* registered.
|
||||
*
|
||||
* @param rate the number of times each second that the key press
|
||||
* should be repeated while the key is down, or <code>0</code> to
|
||||
* disable auto-repeat for the key.
|
||||
*/
|
||||
public void addPressCommand (int keyCode, String command, int rate)
|
||||
{
|
||||
addPressCommand(keyCode, command, rate, DEFAULT_REPEAT_DELAY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping from a key press to an action command string that
|
||||
* will auto-repeat at the specified repeat rate after the specified
|
||||
* auto-repeat delay has expired. Overwrites any existing mapping for
|
||||
* the specified key code that may have already been registered.
|
||||
*
|
||||
* @param rate the number of times each second that the key press
|
||||
* should be repeated while the key is down; passing <code>0</code>
|
||||
* will result in no repeating.
|
||||
* @param repeatDelay the delay in milliseconds before auto-repeating
|
||||
* key press events will be generated for the key.
|
||||
*/
|
||||
public void addPressCommand (
|
||||
int keyCode, String command, int rate, long repeatDelay)
|
||||
{
|
||||
KeyRecord krec = getKeyRecord(keyCode);
|
||||
krec.pressCommand = command;
|
||||
krec.repeatRate = rate;
|
||||
krec.repeatDelay = repeatDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a mapping from a key release to an action command string.
|
||||
* Overwrites any existing mapping that may already have been
|
||||
* registered.
|
||||
*/
|
||||
public void addReleaseCommand (int keyCode, String command)
|
||||
{
|
||||
KeyRecord krec = getKeyRecord(keyCode);
|
||||
krec.releaseCommand = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key record for the specified key, creating it and
|
||||
* inserting it in the key table if necessary.
|
||||
*/
|
||||
protected KeyRecord getKeyRecord (int keyCode)
|
||||
{
|
||||
KeyRecord krec = (KeyRecord)_keys.get(keyCode);
|
||||
if (krec == null) {
|
||||
krec = new KeyRecord();
|
||||
_keys.put(keyCode, krec);
|
||||
}
|
||||
return krec;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean hasCommand (int keyCode)
|
||||
{
|
||||
return (_keys.get(keyCode) != null);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public String getPressCommand (int keyCode)
|
||||
{
|
||||
KeyRecord krec = (KeyRecord)_keys.get(keyCode);
|
||||
return (krec == null) ? null : krec.pressCommand;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public String getReleaseCommand (int keyCode)
|
||||
{
|
||||
KeyRecord krec = (KeyRecord)_keys.get(keyCode);
|
||||
return (krec == null) ? null : krec.releaseCommand;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getRepeatRate (int keyCode)
|
||||
{
|
||||
KeyRecord krec = (KeyRecord)_keys.get(keyCode);
|
||||
return (krec == null) ? DEFAULT_REPEAT_RATE : krec.repeatRate;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public long getRepeatDelay (int keyCode)
|
||||
{
|
||||
KeyRecord krec = (KeyRecord)_keys.get(keyCode);
|
||||
return (krec == null) ? DEFAULT_REPEAT_DELAY : krec.repeatDelay;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Iterator enumeratePressCommands ()
|
||||
{
|
||||
ArrayList commands = new ArrayList();
|
||||
Iterator iter = _keys.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
KeyRecord krec = (KeyRecord)iter.next();
|
||||
commands.add(krec.pressCommand);
|
||||
}
|
||||
return commands.iterator();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Iterator enumerateReleaseCommands ()
|
||||
{
|
||||
ArrayList commands = new ArrayList();
|
||||
Iterator iter = _keys.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
KeyRecord krec = (KeyRecord)iter.next();
|
||||
commands.add(krec.releaseCommand);
|
||||
}
|
||||
return commands.iterator();
|
||||
}
|
||||
|
||||
protected static class KeyRecord
|
||||
{
|
||||
/** The command to be posted when the key is pressed. */
|
||||
public String pressCommand;
|
||||
|
||||
/** The command to be posted when the key is released. */
|
||||
public String releaseCommand;
|
||||
|
||||
/** The rate in presses per second at which the key is to be
|
||||
* auto-repeated. */
|
||||
public int repeatRate;
|
||||
|
||||
/** The delay in milliseconds that must expire with the key still
|
||||
* pressed before auto-repeated key presses will begin. */
|
||||
public long repeatDelay;
|
||||
}
|
||||
|
||||
/** The keys for which commands are registered. */
|
||||
protected HashIntMap _keys = new HashIntMap();
|
||||
|
||||
/** The default key press repeat rate. */
|
||||
protected static final int DEFAULT_REPEAT_RATE = 5;
|
||||
|
||||
/** The default delay in milliseconds before auto-repeated key presses
|
||||
* will begin. */
|
||||
protected static final long DEFAULT_REPEAT_DELAY = 500L;
|
||||
}
|
||||
@@ -1,720 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.awt.KeyEventDispatcher;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Window;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.WindowFocusListener;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import javax.swing.event.AncestorListener;
|
||||
|
||||
import com.samskivert.swing.Controller;
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.ObserverList;
|
||||
import com.samskivert.util.RunAnywhere;
|
||||
|
||||
import com.threerings.util.keybd.Keyboard;
|
||||
|
||||
/**
|
||||
* The keyboard manager observes keyboard actions on a particular
|
||||
* component and posts commands associated with the key presses to the
|
||||
* {@link Controller} hierarchy. It allows specifying the key repeat
|
||||
* rate, and will begin repeating a key immediately after it is held down
|
||||
* rather than depending on the system-specific key repeat delay/rate.
|
||||
*/
|
||||
public class KeyboardManager
|
||||
implements KeyEventDispatcher, AncestorListener, WindowFocusListener
|
||||
{
|
||||
/**
|
||||
* An interface to be implemented by those that care to be notified
|
||||
* whenever an event (either a key press or a key release) occurs for
|
||||
* any key while the keyboard manager is active. We use this custom
|
||||
* interface rather than the more standard {@link
|
||||
* java.awt.event.KeyListener} interface so that we needn't create key
|
||||
* pressed and released event objects each time a (potentially
|
||||
* artificially-generated) event occurs.
|
||||
*/
|
||||
public interface KeyObserver
|
||||
{
|
||||
/**
|
||||
* Called whenever a key event occurs for a particular key.
|
||||
*/
|
||||
public void handleKeyEvent (int id, int keyCode, long timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a keyboard manager that is initially disabled. The
|
||||
* keyboard manager should not be enabled until it has been supplied
|
||||
* with a target component and translator via {@link #setTarget}.
|
||||
*/
|
||||
public KeyboardManager ()
|
||||
{
|
||||
// capture low-level keyboard events via the keyboard focus manager
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().
|
||||
addKeyEventDispatcher(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the keyboard manager, clearing any target and key translator
|
||||
* in use and disabling the keyboard manager if it is currently
|
||||
* active.
|
||||
*/
|
||||
public void reset ()
|
||||
{
|
||||
setEnabled(false);
|
||||
_target = null;
|
||||
_xlate = null;
|
||||
_focus = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the keyboard manager with the supplied target component
|
||||
* and key translator and disables the keyboard manager if it is
|
||||
* currently active.
|
||||
*
|
||||
* @param target the component whose keyboard events are to be observed.
|
||||
* @param xlate the key translator used to map keyboard events to
|
||||
* controller action commands.
|
||||
*/
|
||||
public void setTarget (JComponent target, KeyTranslator xlate)
|
||||
{
|
||||
setEnabled(false);
|
||||
|
||||
// save off references
|
||||
_target = target;
|
||||
_xlate = xlate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a key observer that will be notified of all key events
|
||||
* while the keyboard manager is active.
|
||||
*/
|
||||
public void registerKeyObserver (KeyObserver obs)
|
||||
{
|
||||
_observers.add(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the supplied key observer from the list of observers to be
|
||||
* notified of all key events while the keyboard manager is active.
|
||||
*/
|
||||
public void removeKeyObserver (KeyObserver obs)
|
||||
{
|
||||
_observers.remove(obs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the keyboard manager processes keyboard input.
|
||||
*/
|
||||
public void setEnabled (boolean enabled)
|
||||
{
|
||||
// report incorrect usage
|
||||
if (enabled && _target == null) {
|
||||
Log.warning("Attempt to enable uninitialized keyboard manager!");
|
||||
Thread.dumpStack();
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore NOOPs
|
||||
if (enabled == _enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!enabled) {
|
||||
if (Keyboard.isAvailable()) {
|
||||
// restore the original key auto-repeat settings
|
||||
Keyboard.setKeyRepeat(_nativeRepeat);
|
||||
}
|
||||
|
||||
// clear out all of our key states
|
||||
releaseAllKeys();
|
||||
_keys.clear();
|
||||
|
||||
// cease listening to all of our business
|
||||
if (_window != null) {
|
||||
_window.removeWindowFocusListener(this);
|
||||
_window = null;
|
||||
}
|
||||
_target.removeAncestorListener(this);
|
||||
|
||||
// note that we no longer have the focus
|
||||
_focus = false;
|
||||
|
||||
} else {
|
||||
// listen to ancestor events so that we can cease our business
|
||||
// if we lose the focus
|
||||
_target.addAncestorListener(this);
|
||||
|
||||
// if we're already showing, listen to window focus events,
|
||||
// else we have to wait until the target is added since it
|
||||
// doesn't currently have a window
|
||||
if (_target.isShowing() && _window == null) {
|
||||
_window = SwingUtilities.getWindowAncestor(_target);
|
||||
if (_window != null) {
|
||||
_window.addWindowFocusListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
// assume the keyboard focus since we were just enabled
|
||||
_focus = true;
|
||||
|
||||
if (Keyboard.isAvailable()) {
|
||||
// note whether key auto-repeating was enabled
|
||||
_nativeRepeat = Keyboard.isKeyRepeatEnabled();
|
||||
|
||||
// disable native key auto-repeating so that we can
|
||||
// definitively ascertain key pressed/released events
|
||||
Keyboard.setKeyRepeat(false);
|
||||
}
|
||||
}
|
||||
|
||||
// save off our new enabled state
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected delay in milliseconds between each key
|
||||
* press/release event the keyboard manager should expect to receive
|
||||
* while a key is repeating.
|
||||
*/
|
||||
public void setRepeatDelay (long delay)
|
||||
{
|
||||
_repeatDelay = delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases all keys and ceases any hot repeating action that may be
|
||||
* going on.
|
||||
*/
|
||||
public void releaseAllKeys ()
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
Iterator iter = _keys.elements();
|
||||
while (iter.hasNext()) {
|
||||
((KeyInfo)iter.next()).release(now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the keyboard manager gains focus and should begin
|
||||
* handling keys again if it was previously enabled.
|
||||
*/
|
||||
protected void gainedFocus ()
|
||||
{
|
||||
if (Keyboard.isAvailable()) {
|
||||
// disable key auto-repeating
|
||||
Keyboard.setKeyRepeat(false);
|
||||
}
|
||||
|
||||
// note that we've regained the focus
|
||||
_focus = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the keyboard manager loses focus and should cease
|
||||
* handling keys.
|
||||
*/
|
||||
protected void lostFocus ()
|
||||
{
|
||||
if (Keyboard.isAvailable()) {
|
||||
// restore key auto-repeating
|
||||
Keyboard.setKeyRepeat(_nativeRepeat);
|
||||
}
|
||||
|
||||
// clear out all of our keyboard state
|
||||
releaseAllKeys();
|
||||
// note that we no longer have the focus
|
||||
_focus = false;
|
||||
}
|
||||
|
||||
// documentation inherited from interface KeyEventDispatcher
|
||||
public boolean dispatchKeyEvent (KeyEvent e)
|
||||
{
|
||||
// bail if we're not enabled, we haven't the focus, or we're not
|
||||
// showing on-screen
|
||||
if (!_enabled || !_focus || !_target.isShowing()) {
|
||||
// Log.info("dispatchKeyEvent [enabled=" + _enabled +
|
||||
// ", focus=" + _focus +
|
||||
// ", showing=" + ((_target == null) ? "N/A" :
|
||||
// "" + _target.isShowing()) + "].");
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle key press and release events
|
||||
switch (e.getID()) {
|
||||
case KeyEvent.KEY_PRESSED:
|
||||
return keyPressed(e);
|
||||
|
||||
case KeyEvent.KEY_RELEASED:
|
||||
return keyReleased(e);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Swing notifies us that a key has been pressed while the
|
||||
* keyboard manager is active.
|
||||
*
|
||||
* @return true to swallow the key event
|
||||
*/
|
||||
protected boolean keyPressed (KeyEvent e)
|
||||
{
|
||||
logKey("keyPressed", e);
|
||||
|
||||
// get the action command associated with this key
|
||||
int keyCode = e.getKeyCode();
|
||||
boolean hasCommand = _xlate.hasCommand(keyCode);
|
||||
if (hasCommand) {
|
||||
// get the info object for this key, creating one if necessary
|
||||
KeyInfo info = (KeyInfo)_keys.get(keyCode);
|
||||
if (info == null) {
|
||||
info = new KeyInfo(keyCode);
|
||||
_keys.put(keyCode, info);
|
||||
}
|
||||
|
||||
// remember the last time this key was pressed
|
||||
info.setPressTime(RunAnywhere.getWhen(e));
|
||||
}
|
||||
|
||||
// notify any key observers of the key press
|
||||
notifyObservers(KeyEvent.KEY_PRESSED, e.getKeyCode(),
|
||||
RunAnywhere.getWhen(e));
|
||||
|
||||
return hasCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when Swing notifies us that a key has been released while
|
||||
* the keyboard manager is active.
|
||||
*
|
||||
* @return true to swallow the key event
|
||||
*/
|
||||
protected boolean keyReleased (KeyEvent e)
|
||||
{
|
||||
logKey("keyReleased", e);
|
||||
|
||||
// get the info object for this key
|
||||
KeyInfo info = (KeyInfo)_keys.get(e.getKeyCode());
|
||||
if (info != null) {
|
||||
// remember the last time we received a key release
|
||||
info.setReleaseTime(RunAnywhere.getWhen(e));
|
||||
}
|
||||
|
||||
// notify any key observers of the key release
|
||||
notifyObservers(KeyEvent.KEY_RELEASED, e.getKeyCode(),
|
||||
RunAnywhere.getWhen(e));
|
||||
|
||||
return (info != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies all registered key observers of the supplied key event.
|
||||
* This method provides a thread-safe manner in which to notify the
|
||||
* observers, which is necessary since the {@link KeyInfo} objects do
|
||||
* various antics from the interval manager thread whilst we may do
|
||||
* other notification from the AWT thread when normal key events are
|
||||
* handled.
|
||||
*/
|
||||
protected synchronized void notifyObservers (
|
||||
int id, int keyCode, long timestamp)
|
||||
{
|
||||
_keyOp.init(id, keyCode, timestamp);
|
||||
_observers.apply(_keyOp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the given message and key.
|
||||
*/
|
||||
protected void logKey (String msg, KeyEvent e)
|
||||
{
|
||||
if (DEBUG_EVENTS) {
|
||||
int keyCode = e.getKeyCode();
|
||||
Log.info(msg + " [key=" + KeyEvent.getKeyText(keyCode) + "].");
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface AncestorListener
|
||||
public void ancestorAdded (AncestorEvent e)
|
||||
{
|
||||
gainedFocus();
|
||||
|
||||
if (_window == null) {
|
||||
_window = SwingUtilities.getWindowAncestor(_target);
|
||||
_window.addWindowFocusListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface AncestorListener
|
||||
public void ancestorMoved (AncestorEvent e)
|
||||
{
|
||||
// nothing for now
|
||||
}
|
||||
|
||||
// documentation inherited from interface AncestorListener
|
||||
public void ancestorRemoved (AncestorEvent e)
|
||||
{
|
||||
lostFocus();
|
||||
|
||||
if (_window != null) {
|
||||
_window.removeWindowFocusListener(this);
|
||||
_window = null;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface WindowFocusListener
|
||||
public void windowGainedFocus (WindowEvent e)
|
||||
{
|
||||
gainedFocus();
|
||||
}
|
||||
|
||||
// documentation inherited from interface WindowFocusListener
|
||||
public void windowLostFocus (WindowEvent e)
|
||||
{
|
||||
lostFocus();
|
||||
}
|
||||
|
||||
protected class KeyInfo extends Interval
|
||||
{
|
||||
/**
|
||||
* Constructs a key info object for the given key code.
|
||||
*/
|
||||
public KeyInfo (int keyCode)
|
||||
{
|
||||
_keyCode = keyCode;
|
||||
_keyText = KeyEvent.getKeyText(_keyCode);
|
||||
_pressCommand = _xlate.getPressCommand(_keyCode);
|
||||
_releaseCommand = _xlate.getReleaseCommand(_keyCode);
|
||||
int rate = _xlate.getRepeatRate(_keyCode);
|
||||
_pressDelay = (rate == 0) ? 0 : (1000L / rate);
|
||||
_repeatDelay = _xlate.getRepeatDelay(_keyCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last time the key was pressed.
|
||||
*/
|
||||
public synchronized void setPressTime (long time)
|
||||
{
|
||||
if (_lastPress == 0 && _pressCommand != null) {
|
||||
// post the initial key press command
|
||||
postPress(time);
|
||||
}
|
||||
|
||||
if (!_scheduled && _pressDelay > 0) {
|
||||
// register an interval to post the key press command
|
||||
// until the key is decidedly released
|
||||
if (_repeatDelay > 0) {
|
||||
schedule(_repeatDelay, _pressDelay);
|
||||
|
||||
} else {
|
||||
schedule(_pressDelay, true);
|
||||
}
|
||||
_scheduled = true;
|
||||
|
||||
if (DEBUG_EVENTS) {
|
||||
Log.info("Pressing key [key=" + _keyText + "].");
|
||||
}
|
||||
}
|
||||
|
||||
_lastPress = time;
|
||||
_lastRelease = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last time the key was released.
|
||||
*/
|
||||
public synchronized void setReleaseTime (long time)
|
||||
{
|
||||
release(time);
|
||||
_lastRelease = time;
|
||||
|
||||
// handle key release events received so quickly after the key
|
||||
// press event that the press/release times are exactly equal
|
||||
// and, in intervalExpired(), we would therefore be unable to
|
||||
// distinguish between the key being initially pressed and the
|
||||
// actual true key release that's taken place.
|
||||
|
||||
// the only case I can think of that might result in this
|
||||
// happening is if the event manager class queues up a key
|
||||
// press and release event succession while other code is
|
||||
// executing, and when it comes time for it to dispatch the
|
||||
// events in its queue it manages to dispatch both of them to
|
||||
// us really-lickety-split. one would still think at least a
|
||||
// few milliseconds should pass between the press and release,
|
||||
// but in any case, we arguably ought to be watching for and
|
||||
// handling this case for posterity even though it would seem
|
||||
// unlikely or impossible, and so, now we do, which is a good
|
||||
// thing since it appears this does in fact happen, and not so
|
||||
// infrequently.
|
||||
if (_lastPress == _lastRelease) {
|
||||
if (DEBUG_EVENTS) {
|
||||
Log.warning("Insta-releasing key due to equal key " +
|
||||
"press/release times [key=" + _keyText + "].");
|
||||
}
|
||||
release(time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the key if pressed and cancels any active key repeat
|
||||
* interval.
|
||||
*/
|
||||
public synchronized void release (long timestamp)
|
||||
{
|
||||
// bail if we're not currently pressed
|
||||
if (_lastPress == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG_EVENTS) {
|
||||
Log.info("Releasing key [key=" + _keyText + "].");
|
||||
}
|
||||
|
||||
// remove the repeat interval
|
||||
if (_scheduled) {
|
||||
cancel();
|
||||
_scheduled = false;
|
||||
}
|
||||
|
||||
if (_releaseCommand != null) {
|
||||
// post the key release command
|
||||
postRelease(timestamp);
|
||||
}
|
||||
|
||||
// clear out the last press and release timestamps
|
||||
_lastPress = _lastRelease = 0;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public synchronized void expired ()
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
long deltaPress = now - _lastPress;
|
||||
long deltaRelease = now - _lastRelease;
|
||||
|
||||
if (KeyboardManager.DEBUG_INTERVAL) {
|
||||
Log.info("Interval [key=" + _keyText +
|
||||
", deltaPress=" + deltaPress +
|
||||
", deltaRelease=" + deltaRelease + "].");
|
||||
}
|
||||
|
||||
// handle a normal interval where we either (a) create a
|
||||
// sub-interval if we can't yet determine definitively
|
||||
// whether the key is still down, (b) cease repeating if
|
||||
// we're certain the key is now up, or (c) repeat the key
|
||||
// command if we're certain the key is still down
|
||||
if (_lastRelease != _lastPress) {
|
||||
// if (deltaRelease < _repeatDelay) {
|
||||
// // register a one-shot sub-interval to
|
||||
// // definitively check whether the key was released
|
||||
// long delay = _repeatDelay - deltaRelease;
|
||||
// _siid = IntervalManager.register(
|
||||
// this, delay, Long.valueOf(_lastPress), false);
|
||||
// if (KeyboardManager.DEBUG_INTERVAL) {
|
||||
// Log.info("Registered sub-interval " +
|
||||
// "[id=" + _siid + "].");
|
||||
// }
|
||||
|
||||
// } else {
|
||||
// we know the key was released, so cease repeating
|
||||
release(now);
|
||||
// }
|
||||
|
||||
} else if (_lastPress != 0 && _pressCommand != null) {
|
||||
// post the key press command again
|
||||
postPress(now);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Old stuff- sub interval stuff was commented out prior to my
|
||||
* reworking of Interval, I'll be damned if I'm going to convert this
|
||||
* code that wasn't even being used.
|
||||
} else if (id == _siid) {
|
||||
// handle the sub-interval that checks whether the key has
|
||||
// really been released since the normal interval expired
|
||||
// at an inopportune time for a definitive check
|
||||
|
||||
// clear out the non-recurring sub-interval identifier
|
||||
_siid = -1;
|
||||
|
||||
// make sure the key hasn't been pressed again since the
|
||||
// sub-interval was registered
|
||||
if (_lastPress != ((Long)arg).longValue()) {
|
||||
if (KeyboardManager.DEBUG_INTERVAL) {
|
||||
Log.warning("Key pressed since sub-interval was " +
|
||||
"registered, aborting release check " +
|
||||
"[key=" + _keyText + "].");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// provide the last word on whether the key was released
|
||||
if ((_lastRelease != _lastPress) &&
|
||||
deltaRelease >= _repeatDelay) {
|
||||
release(now);
|
||||
|
||||
} else if (_pressCommand != null) {
|
||||
// post the key command again
|
||||
postPress(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
**/
|
||||
|
||||
/**
|
||||
* Posts the press command for this key and notifies all key
|
||||
* observers of the key press.
|
||||
*/
|
||||
protected void postPress (long timestamp)
|
||||
{
|
||||
notifyObservers(KeyEvent.KEY_PRESSED, _keyCode, timestamp);
|
||||
Controller.postAction(_target, _pressCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts the release command for this key and notifies all key
|
||||
* observers of the key release.
|
||||
*/
|
||||
protected void postRelease (long timestamp)
|
||||
{
|
||||
notifyObservers(KeyEvent.KEY_RELEASED, _keyCode, timestamp);
|
||||
Controller.postAction(_target, _releaseCommand);
|
||||
}
|
||||
|
||||
/** Returns a string representation of the key info object. */
|
||||
public String toString ()
|
||||
{
|
||||
return "[key=" + _keyText + "]";
|
||||
}
|
||||
|
||||
/** True if we are a scheduled interval. */
|
||||
protected boolean _scheduled = false;
|
||||
|
||||
/** The last time a key released event was received for this key. */
|
||||
protected long _lastRelease;
|
||||
|
||||
/** The last time a key pressed event was received for this key. */
|
||||
protected long _lastPress;
|
||||
|
||||
/** The press action command associated with this key. */
|
||||
protected String _pressCommand;
|
||||
|
||||
/** The release action command associated with this key. */
|
||||
protected String _releaseCommand;
|
||||
|
||||
/** A text representation of this key. */
|
||||
protected String _keyText;
|
||||
|
||||
/** The key code associated with this key info object. */
|
||||
protected int _keyCode;
|
||||
|
||||
/** The milliseconds to sleep between sending repeat key commands. */
|
||||
protected long _pressDelay;
|
||||
|
||||
/** The delay in milliseconds before auto-repeating the key press. */
|
||||
protected long _repeatDelay;
|
||||
}
|
||||
|
||||
/** An observer operation to notify observers of a key event. */
|
||||
protected static class KeyObserverOp implements ObserverList.ObserverOp
|
||||
{
|
||||
/** Initialized the operation with its parameters. */
|
||||
public void init (int id, int keyCode, long timestamp)
|
||||
{
|
||||
_id = id;
|
||||
_keyCode = keyCode;
|
||||
_timestamp = timestamp;
|
||||
}
|
||||
|
||||
// documentation inherited from interface ObserverList.ObserverOp
|
||||
public boolean apply (Object observer)
|
||||
{
|
||||
((KeyObserver)observer).handleKeyEvent(_id, _keyCode, _timestamp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** The key event id. */
|
||||
protected int _id;
|
||||
|
||||
/** The key code. */
|
||||
protected int _keyCode;
|
||||
|
||||
/** The key event timestamp. */
|
||||
protected long _timestamp;
|
||||
}
|
||||
|
||||
/** Whether to output debugging info for individual key events. */
|
||||
protected static final boolean DEBUG_EVENTS = false;
|
||||
|
||||
/** Whether to output debugging info for interval callbacks. */
|
||||
protected static final boolean DEBUG_INTERVAL = false;
|
||||
|
||||
/** The default repeat delay. */
|
||||
protected static final long DEFAULT_REPEAT_DELAY = 50L;
|
||||
|
||||
/** The expected approximate milliseconds between each key
|
||||
* release/press event while the key is being auto-repeated. */
|
||||
protected long _repeatDelay = DEFAULT_REPEAT_DELAY;
|
||||
|
||||
/** A hashtable mapping key codes to {@link KeyInfo} objects. */
|
||||
protected HashIntMap _keys = new HashIntMap();
|
||||
|
||||
/** Whether the keyboard manager currently has the keyboard focus. */
|
||||
protected boolean _focus;
|
||||
|
||||
/** Whether the keyboard manager is accepting keyboard input. */
|
||||
protected boolean _enabled;
|
||||
|
||||
/** The window containing our target component whose focus events we
|
||||
* care to observe, or null if we're not observing a window. */
|
||||
protected Window _window;
|
||||
|
||||
/** The component that receives keyboard events and that we associate
|
||||
* with posted controller commands. */
|
||||
protected JComponent _target;
|
||||
|
||||
/** The translator that maps keyboard events to controller commands. */
|
||||
protected KeyTranslator _xlate;
|
||||
|
||||
/** The list of key observers. */
|
||||
protected ObserverList _observers =
|
||||
new ObserverList(ObserverList.FAST_UNSAFE_NOTIFY);
|
||||
|
||||
/** The operation used to notify observers of actual key events. */
|
||||
protected KeyObserverOp _keyOp = new KeyObserverOp();
|
||||
|
||||
/** Whether native key auto-repeating was enabled when the keyboard
|
||||
* manager was last enabled. */
|
||||
protected boolean _nativeRepeat;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.samskivert.swing.Controller;
|
||||
import com.samskivert.util.CollectionUtil;
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.RandomUtil;
|
||||
|
||||
/**
|
||||
* The robot player is a computer player with truly rudimentary artificial
|
||||
* intelligence that periodically posts random commands selected from the
|
||||
* available key press and release commands to the target component.
|
||||
*
|
||||
* Note that {@link java.awt.Robot} could have been used to post key
|
||||
* events to the target component rather than commands, but not all key
|
||||
* events can be simulated in that fashion (e.g., a right shift key
|
||||
* press), and this seemed somehow more proper in any case.
|
||||
*/
|
||||
public class RobotPlayer extends Interval
|
||||
{
|
||||
/**
|
||||
* Constructs a robot player.
|
||||
*/
|
||||
public RobotPlayer (Component target, KeyTranslator xlate)
|
||||
{
|
||||
// save off references
|
||||
_target = target;
|
||||
_xlate = xlate;
|
||||
|
||||
// build the list of available commands
|
||||
CollectionUtil.addAll(_press, _xlate.enumeratePressCommands());
|
||||
CollectionUtil.addAll(_release, _xlate.enumerateReleaseCommands());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the robot player is actively posting action commands.
|
||||
*/
|
||||
public void setActive (boolean active)
|
||||
{
|
||||
if (active != _active) {
|
||||
if (active) {
|
||||
schedule(_robotDelay, true);
|
||||
} else {
|
||||
cancel(); // stop the robot player
|
||||
}
|
||||
_active = active;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the delay in milliseconds between posting each action command.
|
||||
*/
|
||||
public void setRobotDelay (long delay)
|
||||
{
|
||||
_robotDelay = delay;
|
||||
|
||||
// if the robot is active, reset it with the new delay time
|
||||
if (isActive()) {
|
||||
setActive(false);
|
||||
setActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the robot is currently active and periodically
|
||||
* posting action commands.
|
||||
*/
|
||||
public boolean isActive ()
|
||||
{
|
||||
return _active;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void expired ()
|
||||
{
|
||||
// post a random key press command
|
||||
int idx = RandomUtil.getInt(_press.size());
|
||||
String command = (String)_press.get(idx);
|
||||
// Log.info("Posting artificial command [cmd=" + command + "].");
|
||||
Controller.postAction(_target, command);
|
||||
}
|
||||
|
||||
/** The default robot delay. */
|
||||
protected static final long DEFAULT_ROBOT_DELAY = 500L;
|
||||
|
||||
/** Whether the robot is active or not. */
|
||||
protected boolean _active = false;
|
||||
|
||||
/** The milliseconds between posting each action command. */
|
||||
protected long _robotDelay = DEFAULT_ROBOT_DELAY;
|
||||
|
||||
/** The list of available key press action commands. */
|
||||
protected ArrayList _press = new ArrayList();
|
||||
|
||||
/** The list of available key release action commands. */
|
||||
protected ArrayList _release = new ArrayList();
|
||||
|
||||
/** The key translator that describes available keys and commands. */
|
||||
protected KeyTranslator _xlate;
|
||||
|
||||
/** The target component associated with game action commands. */
|
||||
protected Component _target;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util.keybd;
|
||||
|
||||
import com.threerings.util.Log;
|
||||
|
||||
/**
|
||||
* Provides access to the native operating system's auto-repeat keyboard
|
||||
* settings.
|
||||
*/
|
||||
public class Keyboard
|
||||
{
|
||||
/**
|
||||
* Sets whether key auto-repeating is enabled.
|
||||
*/
|
||||
public static native void setKeyRepeat (boolean enabled);
|
||||
|
||||
/**
|
||||
* Returns whether key auto-repeating is enabled.
|
||||
*/
|
||||
public static native boolean isKeyRepeatEnabled ();
|
||||
|
||||
/**
|
||||
* Tests keyboard functionality.
|
||||
*/
|
||||
public static void main (String[] args)
|
||||
{
|
||||
boolean enabled = (args.length > 0 && args[0].equals("on"));
|
||||
Keyboard.setKeyRepeat(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the native keyboard interface is available.
|
||||
*/
|
||||
public static boolean isAvailable ()
|
||||
{
|
||||
return _haveLib;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the library and returns true if it successfully did so.
|
||||
*/
|
||||
protected static native boolean init ();
|
||||
|
||||
/** Whether the keyboard native library was successfully loaded. */
|
||||
protected static boolean _haveLib;
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("keybd");
|
||||
_haveLib = init();
|
||||
if (_haveLib) {
|
||||
Log.info("Loaded native keyboard library.");
|
||||
} else {
|
||||
Log.info("Native keyboard library initialization failed.");
|
||||
}
|
||||
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
Log.warning("Failed to load native keyboard library " +
|
||||
"[e=" + e + "].");
|
||||
_haveLib = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
|
||||
#
|
||||
# Executable definitions
|
||||
|
||||
CC=gcc
|
||||
RM=rm
|
||||
CP=cp
|
||||
MKDIR=mkdir
|
||||
|
||||
#
|
||||
# Directory definitions
|
||||
|
||||
ROOT=../../../../../../..
|
||||
LIBRARIES_PATH=-L/usr/X11R6/lib
|
||||
INSTALL_PATH=${ROOT}/dist/lib/i686-Linux
|
||||
|
||||
#
|
||||
# Parameter and file definitions
|
||||
|
||||
INCLUDES=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
|
||||
LIBRARIES=-lX11
|
||||
TARGET=libkeybd.so
|
||||
|
||||
#
|
||||
# Target definitions
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
install: ${TARGET}
|
||||
@${MKDIR} -p ${INSTALL_PATH}
|
||||
cp ${TARGET} ${INSTALL_PATH}
|
||||
|
||||
${TARGET}: com_threerings_util_keybd_Keyboard.c
|
||||
@echo Compiling Keyboard.c
|
||||
@${CC} ${INCLUDES} -c com_threerings_util_keybd_Keyboard.c \
|
||||
-o com_threerings_util_keybd_Keyboard.o
|
||||
@echo Creating libkeybd.so
|
||||
@${CC} -o ${TARGET} com_threerings_util_keybd_Keyboard.o \
|
||||
${LIBRARIES} ${LIBRARIES_PATH} -shared
|
||||
|
||||
clean:
|
||||
-${RM} -f *.o ${TARGET}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <jni.h>
|
||||
#include "com_threerings_util_keybd_Keyboard.h"
|
||||
|
||||
/* defines */
|
||||
#define MESSAGE_LENGTH (256)
|
||||
|
||||
/* prototype definitions */
|
||||
Display* getXDisplay (JNIEnv* env);
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_keybd_Keyboard_init (
|
||||
JNIEnv* env, jclass class, jboolean enabled)
|
||||
{
|
||||
Display* display = getXDisplay(env);
|
||||
if (display == NULL) {
|
||||
/* If we are unable to open a display, we can't function. */
|
||||
return JNI_FALSE;
|
||||
} else {
|
||||
XCloseDisplay(display);
|
||||
return JNI_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_keybd_Keyboard_setKeyRepeat (
|
||||
JNIEnv* env, jclass class, jboolean enabled)
|
||||
{
|
||||
Display* display = getXDisplay(env);
|
||||
if (display == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* set the desired key auto-repeat state. */
|
||||
if (enabled) {
|
||||
XAutoRepeatOn(display);
|
||||
} else {
|
||||
XAutoRepeatOff(display);
|
||||
}
|
||||
|
||||
/* close the display to save our changes */
|
||||
XCloseDisplay(display);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_keybd_Keyboard_isKeyRepeatEnabled (
|
||||
JNIEnv* env, jclass class)
|
||||
{
|
||||
XKeyboardState values;
|
||||
Display* display = getXDisplay(env);
|
||||
if (display == NULL) {
|
||||
/* for now, assume auto-repeat is enabled */
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/* get the current keyboard control information */
|
||||
XGetKeyboardControl(display, &values);
|
||||
|
||||
/* close the display */
|
||||
XCloseDisplay(display);
|
||||
|
||||
return (values.global_auto_repeat) ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns a pointer to the X display, or null if an error occurred.
|
||||
*/
|
||||
Display*
|
||||
getXDisplay (JNIEnv* env)
|
||||
{
|
||||
char* disp = NULL;
|
||||
Display* dpy = XOpenDisplay(disp);
|
||||
if (dpy == NULL) {
|
||||
char message[MESSAGE_LENGTH];
|
||||
snprintf(message, MESSAGE_LENGTH,
|
||||
"Unable to open display [display=%s].\n", XDisplayName(disp));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* printf("Opened display [disp=%s].\n", XDisplayName(disp)); */
|
||||
return dpy;
|
||||
}
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# $Id: Makefile 3331 2005-02-03 01:25:21Z mdb $
|
||||
#
|
||||
# Placeholder Makefile
|
||||
|
||||
install:
|
||||
@echo Nothing to see here. Move it along.
|
||||
@@ -1 +0,0 @@
|
||||
keybd.dll
|
||||
@@ -1,27 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
|
||||
CROSSTOOLS_PATH=/usr/local/cross-tools
|
||||
MINGW_PATH=${CROSSTOOLS_PATH}/i386-mingw32msvc
|
||||
WIN32API_PATH=${CROSSTOOLS_PATH}/w32api
|
||||
|
||||
CC=${MINGW_PATH}/bin/gcc
|
||||
RM=rm
|
||||
|
||||
INCLUDES=-I.. -I/usr/local/jdk1.4/include -I/usr/local/jdk1.4/include/linux \
|
||||
-I${CROSSTOOLS_PATH}/include -I${WIN32API_PATH}/include
|
||||
LIBRARIES_PATH=-L${CROSSTOOLS_PATH}/lib -L${WIN32API_PATH}/lib
|
||||
LIBRARIES=
|
||||
TARGET=keybd.dll
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
${TARGET}: com_threerings_util_keybd_Keyboard.c
|
||||
${CC} ${INCLUDES} -c com_threerings_util_keybd_Keyboard.c \
|
||||
-o com_threerings_util_keybd_Keyboard.o
|
||||
${CC} -o ${TARGET} com_threerings_util_keybd_Keyboard.o \
|
||||
${LIBRARIES} ${LIBRARIES_PATH} -shared
|
||||
|
||||
clean:
|
||||
-${RM} *.o
|
||||
-${RM} ${TARGET}
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <windows.h>
|
||||
#include "com_threerings_util_keybd_Keyboard.h"
|
||||
|
||||
/* prototype definitions */
|
||||
LRESULT CALLBACK KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam);
|
||||
LRESULT CALLBACK LowLevelKeyboardProc (int nCode, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
/* static global variables */
|
||||
static HHOOK gKeyHook;
|
||||
static HINSTANCE gHInst;
|
||||
|
||||
BOOL WINAPI
|
||||
DllMain (HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved)
|
||||
{
|
||||
/* save off our instance handle */
|
||||
fprintf(stderr, "In DllMain.\n");
|
||||
gHInst = (HINSTANCE)hinstDLL;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_keybd_Keyboard_setKeyRepeat (
|
||||
JNIEnv* env, jclass class, jboolean enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
if (gKeyHook != NULL) {
|
||||
fprintf(stderr, "Removing windows keyboard hook.\n");
|
||||
/* remove the keyboard hook */
|
||||
UnhookWindowsHookEx(gKeyHook);
|
||||
gKeyHook = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* install the hook with which we usurp all keyboard events */
|
||||
/* gKeyHook = SetWindowsHookEx( */
|
||||
/* WH_KEYBOARD_LL, LowLevelKeyboardProc, hinstExe, 0); */
|
||||
|
||||
fprintf(stderr, "Setting windows keyboard hook.\n");
|
||||
gKeyHook = SetWindowsHookEx(
|
||||
WH_KEYBOARD, KeyboardProc, gHInst, 0);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_keybd_Keyboard_isKeyRepeatEnabled (
|
||||
JNIEnv* env, jclass class)
|
||||
{
|
||||
/* since windows has no global key repeat enable/disable facility, we
|
||||
* simply always return true here so that we'll be sure to "re-enable"
|
||||
* key repeat, which will result in our properly removing the keyboard
|
||||
* hook with which we trap key events. */
|
||||
fprintf(stderr, "isKeyRepeatEnabled stderr.\n");
|
||||
printf("isKeyRepeatEnabled stdout.\n");
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The keyboard event hook that eats all repeated keystrokes.
|
||||
*/
|
||||
LRESULT CALLBACK
|
||||
KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
int repeatCount = (lParam & KF_REPEAT);
|
||||
fprintf(stderr, "Key down [key=%d, repeatCount=%d].\n",
|
||||
wParam, repeatCount);
|
||||
return (repeatCount > 1) ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/*
|
||||
* The low-level keyboard event hook that eats all keystrokes.
|
||||
*/
|
||||
LRESULT CALLBACK
|
||||
LowLevelKeyboardProc (int nCode, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
BOOL fEatKeystroke = FALSE;
|
||||
|
||||
if (nCode == HC_ACTION) {
|
||||
switch (wParam) {
|
||||
case WM_KEYDOWN:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYUP:
|
||||
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam;
|
||||
fEatKeystroke =
|
||||
((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) ||
|
||||
((p->vkCode == VK_ESCAPE) &&
|
||||
((p->flags & LLKHF_ALTDOWN) != 0)) ||
|
||||
((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) &
|
||||
0x8000) != 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (fEatKeystroke) ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,29 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_threerings_util_keybd_Keyboard */
|
||||
|
||||
#ifndef _Included_com_threerings_util_keybd_Keyboard
|
||||
#define _Included_com_threerings_util_keybd_Keyboard
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Class: com_threerings_util_keybd_Keyboard
|
||||
* Method: setKeyRepeat
|
||||
* Signature: (Z)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_threerings_util_keybd_Keyboard_setKeyRepeat
|
||||
(JNIEnv *, jclass, jboolean);
|
||||
|
||||
/*
|
||||
* Class: com_threerings_util_keybd_Keyboard
|
||||
* Method: isKeyRepeatEnabled
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_threerings_util_keybd_Keyboard_isKeyRepeatEnabled
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,45 +0,0 @@
|
||||
#
|
||||
# $Id: Makefile 3332 2005-02-03 01:30:33Z mdb $
|
||||
|
||||
#
|
||||
# Executable definitions
|
||||
|
||||
CC=gcc
|
||||
RM=rm
|
||||
CP=cp
|
||||
MKDIR=mkdir
|
||||
|
||||
#
|
||||
# Directory definitions
|
||||
|
||||
ROOT=../../../../../../..
|
||||
LIBRARIES_PATH=
|
||||
OSINCDIR!=uname -s | tr 'A-Z' 'a-z'
|
||||
INSTALL_PATH=${ROOT}/dist/lib/i386-FreeBSD
|
||||
|
||||
#
|
||||
# Parameter and file definitions
|
||||
|
||||
INCLUDES=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/${OSINCDIR}
|
||||
LIBRARIES=
|
||||
TARGET=libunsafe.so
|
||||
|
||||
#
|
||||
# Target definitions
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
install: ${TARGET}
|
||||
@${MKDIR} -p ${INSTALL_PATH}
|
||||
cp ${TARGET} ${INSTALL_PATH}
|
||||
|
||||
${TARGET}: com_threerings_util_unsafe_Unsafe.c
|
||||
@echo "Compiling Unsafe.c"
|
||||
@${CC} ${INCLUDES} -c com_threerings_util_unsafe_Unsafe.c \
|
||||
-o com_threerings_util_unsafe_Unsafe.o
|
||||
@echo "Creating libunsafe.so"
|
||||
@${CC} -o ${TARGET} com_threerings_util_unsafe_Unsafe.o \
|
||||
${LIBRARIES} ${LIBRARIES_PATH} -shared
|
||||
|
||||
clean:
|
||||
-${RM} -f *.o ${TARGET}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* $Id: com_threerings_util_unsafe_Unsafe.c 3653 2005-07-21 19:10:08Z mdb $
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <jvmpi.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "com_threerings_util_unsafe_Unsafe.h"
|
||||
|
||||
/* global jvmpi interface pointer */
|
||||
static JVMPI_Interface* jvmpi;
|
||||
|
||||
/** A sleep method that uses select(). This seems to have about 10ms
|
||||
* granularity where nanosleep() has about 20ms. Sigh. */
|
||||
static int select_sleep (int millisecs)
|
||||
{
|
||||
fd_set dummy;
|
||||
struct timeval toWait;
|
||||
FD_ZERO(&dummy);
|
||||
toWait.tv_sec = millisecs / 1000;
|
||||
toWait.tv_usec = (millisecs % 1000) * 1000;
|
||||
return select(0, &dummy, NULL, NULL, &toWait);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_enableGC (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
jvmpi->EnableGC();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_disableGC (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
jvmpi->DisableGC();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSleep (
|
||||
JNIEnv* env, jclass clazz, jint millis)
|
||||
{
|
||||
/* struct timespec tmspec; */
|
||||
/* tmspec.tv_sec = millis/1000; */
|
||||
/* tmspec.tv_nsec = (millis%1000)*1000000; */
|
||||
/* if (nanosleep(&tmspec, NULL) < 0) { */
|
||||
/* fprintf(stderr, "nanosleep() failed: %s\n", strerror(errno)); */
|
||||
/* } */
|
||||
if (select_sleep(millis) < 0) {
|
||||
fprintf(stderr, "select_sleep() failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSetuid (
|
||||
JNIEnv* env, jclass clazz, jint uid)
|
||||
{
|
||||
if (setuid((uid_t)uid) != 0) {
|
||||
fprintf(stderr, "setuid(%d) failed: %s\n", uid, strerror(errno));
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSetgid (
|
||||
JNIEnv* env, jclass clazz, jint gid)
|
||||
{
|
||||
if (setgid((gid_t)gid) != 0) {
|
||||
fprintf(stderr, "setgid(%d) failed: %s\n", gid, strerror(errno));
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_init (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
JavaVM* jvm;
|
||||
|
||||
if ((*env)->GetJavaVM(env, &jvm) > 0) {
|
||||
fprintf(stderr, "Failed to get JavaVM from env.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/* get jvmpi interface pointer */
|
||||
if (((*jvm)->GetEnv(jvm, (void**)&jvmpi, JVMPI_VERSION_1)) < 0) {
|
||||
fprintf(stderr, "Failed to get JVMPI from JavaVM.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
Binary file not shown.
@@ -1,44 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
|
||||
#
|
||||
# Executable definitions
|
||||
|
||||
CC=gcc
|
||||
RM=rm
|
||||
CP=cp
|
||||
MKDIR=mkdir
|
||||
|
||||
#
|
||||
# Directory definitions
|
||||
|
||||
ROOT=../../../../../../..
|
||||
LIBRARIES_PATH=-L/usr/X11R6/lib
|
||||
INSTALL_PATH=${ROOT}/dist/lib/i686-Linux
|
||||
|
||||
#
|
||||
# Parameter and file definitions
|
||||
|
||||
INCLUDES=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
|
||||
LIBRARIES=-lX11
|
||||
TARGET=libunsafe.so
|
||||
|
||||
#
|
||||
# Target definitions
|
||||
|
||||
all: ${TARGET}
|
||||
|
||||
install: ${TARGET}
|
||||
@${MKDIR} -p ${INSTALL_PATH}
|
||||
cp ${TARGET} ${INSTALL_PATH}
|
||||
|
||||
${TARGET}: com_threerings_util_unsafe_Unsafe.c
|
||||
@echo Compiling Unsafe.c
|
||||
@${CC} ${INCLUDES} -c com_threerings_util_unsafe_Unsafe.c \
|
||||
-o com_threerings_util_unsafe_Unsafe.o
|
||||
@echo Creating ${TARGET}
|
||||
@${CC} -o ${TARGET} com_threerings_util_unsafe_Unsafe.o \
|
||||
${LIBRARIES} ${LIBRARIES_PATH} -shared
|
||||
|
||||
clean:
|
||||
-${RM} -f *.o ${TARGET}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <jvmpi.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "com_threerings_util_unsafe_Unsafe.h"
|
||||
|
||||
/* global jvmpi interface pointer */
|
||||
static JVMPI_Interface* jvmpi;
|
||||
|
||||
/** A sleep method that uses select(). This seems to have about 10ms
|
||||
* granularity where nanosleep() has about 20ms. Sigh. */
|
||||
static int select_sleep (int millisecs)
|
||||
{
|
||||
fd_set dummy;
|
||||
struct timeval toWait;
|
||||
FD_ZERO(&dummy);
|
||||
toWait.tv_sec = millisecs / 1000;
|
||||
toWait.tv_usec = (millisecs % 1000) * 1000;
|
||||
return select(0, &dummy, NULL, NULL, &toWait);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_enableGC (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
jvmpi->EnableGC();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_disableGC (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
jvmpi->DisableGC();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSleep (
|
||||
JNIEnv* env, jclass clazz, jint millis)
|
||||
{
|
||||
/* struct timespec tmspec; */
|
||||
/* tmspec.tv_sec = millis/1000; */
|
||||
/* tmspec.tv_nsec = (millis%1000)*1000000; */
|
||||
/* if (nanosleep(&tmspec, NULL) < 0) { */
|
||||
/* fprintf(stderr, "nanosleep() failed: %s\n", strerror(errno)); */
|
||||
/* } */
|
||||
if (select_sleep(millis) < 0) {
|
||||
fprintf(stderr, "select_sleep() failed: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSetuid (
|
||||
JNIEnv* env, jclass clazz, jint uid)
|
||||
{
|
||||
if (setuid((uid_t)uid) != 0) {
|
||||
fprintf(stderr, "setuid(%d) failed: %s\n", uid, strerror(errno));
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSetgid (
|
||||
JNIEnv* env, jclass clazz, jint gid)
|
||||
{
|
||||
if (setgid((gid_t)gid) != 0) {
|
||||
fprintf(stderr, "setgid(%d) failed: %s\n", gid, strerror(errno));
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return JNI_TRUE;
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_init (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
JavaVM* jvm;
|
||||
|
||||
if ((*env)->GetJavaVM(env, &jvm) > 0) {
|
||||
fprintf(stderr, "Failed to get JavaVM from env.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/* get jvmpi interface pointer */
|
||||
if (((*jvm)->GetEnv(jvm, (void**)&jvmpi, JVMPI_VERSION_1)) < 0) {
|
||||
fprintf(stderr, "Failed to get JVMPI from JavaVM.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
Binary file not shown.
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# $Id: Makefile 3331 2005-02-03 01:25:21Z mdb $
|
||||
#
|
||||
# Placeholder Makefile
|
||||
|
||||
install:
|
||||
@echo Nothing to see here. Move it along.
|
||||
@@ -1,144 +0,0 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://www.threerings.net/code/narya/
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License as published
|
||||
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public
|
||||
// License along with this library; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
package com.threerings.util.unsafe;
|
||||
|
||||
import com.threerings.util.Log;
|
||||
import com.samskivert.util.RunAnywhere;
|
||||
|
||||
/**
|
||||
* A native library for doing unsafe things. Don't use this library. If
|
||||
* you must ignore that warning, then be sure you use it sparingly and
|
||||
* only in very well considered cases.
|
||||
*/
|
||||
public class Unsafe
|
||||
{
|
||||
/**
|
||||
* Enables or disables garbage collection. <em>Warning:</em> you will
|
||||
* be fucked if you leave it disabled for too long. Do not do this
|
||||
* unless you are dang sure about what you're doing and are prepared
|
||||
* to test your code on every platform this side of Nantucket.
|
||||
*
|
||||
* <p> Calls to this method do not nest. Regardless of how many times
|
||||
* you disable GC, only one call is required to reenable it.
|
||||
*/
|
||||
public static void setGCEnabled (boolean enabled)
|
||||
{
|
||||
// we don't support nesting, NOOP if the state doesn't change
|
||||
if (_loaded && enabled != _gcEnabled) {
|
||||
if (_gcEnabled = enabled) {
|
||||
enableGC();
|
||||
} else {
|
||||
disableGC();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes the current thread to block for the specified number of
|
||||
* milliseconds. This exists primarily to work around the fact that on
|
||||
* Linux, {@link Thread#sleep} is only accurate to around 12ms which
|
||||
* is wholly unacceptable.
|
||||
*/
|
||||
public static void sleep (int millis)
|
||||
{
|
||||
if (_loaded && RunAnywhere.isLinux()) {
|
||||
nativeSleep(millis);
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException ie) {
|
||||
Log.info("Thread.sleep(" + millis + ") interrupted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the processes uid to the specified value.
|
||||
*
|
||||
* @return true if the uid was changed, false if we were unable to do so.
|
||||
*/
|
||||
public static boolean setuid (int uid)
|
||||
{
|
||||
if (_loaded && !RunAnywhere.isWindows()) {
|
||||
return nativeSetuid(uid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the processes uid to the specified value.
|
||||
*
|
||||
* @return true if the uid was changed, false if we were unable to do so.
|
||||
*/
|
||||
public static boolean setgid (int gid)
|
||||
{
|
||||
if (_loaded && !RunAnywhere.isWindows()) {
|
||||
return nativeSetgid(gid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reenable garbage collection after a call to {@link #disableGC}.
|
||||
*/
|
||||
protected static native void enableGC ();
|
||||
|
||||
/**
|
||||
* Disables garbage collection.
|
||||
*/
|
||||
protected static native void disableGC ();
|
||||
|
||||
/**
|
||||
* Sleeps the current thread for the specified number of milliseconds.
|
||||
*/
|
||||
protected static native void nativeSleep (int millis);
|
||||
|
||||
/**
|
||||
* Calls through to the native OS system call to change our uid.
|
||||
*/
|
||||
protected static native boolean nativeSetuid (int uid);
|
||||
|
||||
/**
|
||||
* Calls through to the native OS system call to change our gid.
|
||||
*/
|
||||
protected static native boolean nativeSetgid (int gid);
|
||||
|
||||
/**
|
||||
* Called to initialize our library.
|
||||
*/
|
||||
protected static native boolean init ();
|
||||
|
||||
/** The current state of GC enablement. */
|
||||
protected static boolean _gcEnabled = true;
|
||||
|
||||
/** Whether or not we were able to load and initialize our library. */
|
||||
protected static boolean _loaded;
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("unsafe");
|
||||
_loaded = init();
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
Log.warning("Failed to load 'unsafe' library: " + e + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
*.def
|
||||
@@ -1,49 +0,0 @@
|
||||
#
|
||||
# $Id$
|
||||
|
||||
NAME=unsafe
|
||||
|
||||
#
|
||||
# Executable definitions
|
||||
|
||||
CC=i586-mingw32msvc-gcc
|
||||
RM=rm
|
||||
CP=cp
|
||||
MKDIR=mkdir
|
||||
DLLWRAP=i586-mingw32msvc-dllwrap
|
||||
#
|
||||
# Directory definitions
|
||||
|
||||
ROOT=../../../../../../..
|
||||
INSTALL_PATH=${ROOT}/dist/lib/i686-Windows
|
||||
|
||||
#
|
||||
# Source files
|
||||
|
||||
SRCS = com_threerings_util_unsafe_Unsafe.c
|
||||
OBJS = ${SRCS:.c=.o}
|
||||
|
||||
#
|
||||
# Parameter and file definitions
|
||||
|
||||
INCLUDES=
|
||||
CFLAGS=-I.. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux
|
||||
|
||||
LDFLAGS=-L/usr/X11R6/lib
|
||||
LIBS=
|
||||
TARGET=${NAME}.dll
|
||||
INSTALL_TARGET=${INSTALL_PATH}/${TARGET}
|
||||
|
||||
#
|
||||
# Target definitions
|
||||
|
||||
all: ${INSTALL_TARGET}
|
||||
|
||||
${INSTALL_TARGET}: ${OBJS}
|
||||
@${MKDIR} -p ${INSTALL_PATH}
|
||||
${DLLWRAP} --output-def ${NAME}.def --add-stdcall-alias \
|
||||
-o ${INSTALL_TARGET} -s ${OBJS}
|
||||
|
||||
clean:
|
||||
-${RM} ${OBJS}
|
||||
-${RM} ${INSTALL_TARGET}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <jni.h>
|
||||
#include <jvmpi.h>
|
||||
|
||||
#include "com_threerings_util_unsafe_Unsafe.h"
|
||||
|
||||
/* global jvmpi interface pointer */
|
||||
static JVMPI_Interface* jvmpi;
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_enableGC (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
fprintf(stderr, "Reenabling GC.\n");
|
||||
jvmpi->EnableGC();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_disableGC (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
fprintf(stderr, "Disabling GC.\n");
|
||||
jvmpi->DisableGC();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_nativeSleep (
|
||||
JNIEnv* env, jclass clazz, jint millis)
|
||||
{
|
||||
/* not supported */
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_threerings_util_unsafe_Unsafe_init (JNIEnv* env, jclass clazz)
|
||||
{
|
||||
JavaVM* jvm;
|
||||
|
||||
if ((*env)->GetJavaVM(env, &jvm) > 0) {
|
||||
fprintf(stderr, "Failed to get JavaVM from env.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
/* get jvmpi interface pointer */
|
||||
if (((*jvm)->GetEnv(jvm, (void**)&jvmpi, JVMPI_VERSION_1)) < 0) {
|
||||
fprintf(stderr, "Failed to get JVMPI from JavaVM.\n");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
return JNI_TRUE;
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||
#include <jni.h>
|
||||
/* Header for class com_threerings_util_unsafe_Unsafe */
|
||||
|
||||
#ifndef _Included_com_threerings_util_unsafe_Unsafe
|
||||
#define _Included_com_threerings_util_unsafe_Unsafe
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/* Inaccessible static: _gcEnabled */
|
||||
/* Inaccessible static: _loaded */
|
||||
/*
|
||||
* Class: com_threerings_util_unsafe_Unsafe
|
||||
* Method: enableGC
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_threerings_util_unsafe_Unsafe_enableGC
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_threerings_util_unsafe_Unsafe
|
||||
* Method: disableGC
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_threerings_util_unsafe_Unsafe_disableGC
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: com_threerings_util_unsafe_Unsafe
|
||||
* Method: nativeSleep
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_com_threerings_util_unsafe_Unsafe_nativeSleep
|
||||
(JNIEnv *, jclass, jint);
|
||||
|
||||
/*
|
||||
* Class: com_threerings_util_unsafe_Unsafe
|
||||
* Method: init
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_com_threerings_util_unsafe_Unsafe_init
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user