mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2026-06-15 21:31:12 +00:00
Convert Limelight to command line application
This commit is contained in:
@@ -4,14 +4,8 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
|
|
||||||
import com.limelight.binding.LibraryHelper;
|
import com.limelight.binding.LibraryHelper;
|
||||||
import com.limelight.binding.PlatformBinding;
|
import com.limelight.binding.PlatformBinding;
|
||||||
import com.limelight.gui.MainFrame;
|
|
||||||
import com.limelight.gui.StreamFrame;
|
|
||||||
import com.limelight.input.gamepad.Gamepad;
|
import com.limelight.input.gamepad.Gamepad;
|
||||||
import com.limelight.input.gamepad.GamepadListener;
|
import com.limelight.input.gamepad.GamepadListener;
|
||||||
import com.limelight.input.gamepad.NativeGamepad;
|
import com.limelight.input.gamepad.NativeGamepad;
|
||||||
@@ -19,9 +13,14 @@ import com.limelight.nvstream.NvConnection;
|
|||||||
import com.limelight.nvstream.NvConnectionListener;
|
import com.limelight.nvstream.NvConnectionListener;
|
||||||
import com.limelight.nvstream.StreamConfiguration;
|
import com.limelight.nvstream.StreamConfiguration;
|
||||||
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
import com.limelight.nvstream.av.video.VideoDecoderRenderer;
|
||||||
|
import com.limelight.nvstream.http.NvHTTP;
|
||||||
import com.limelight.settings.PreferencesManager;
|
import com.limelight.settings.PreferencesManager;
|
||||||
import com.limelight.settings.PreferencesManager.Preferences;
|
import com.limelight.settings.PreferencesManager.Preferences;
|
||||||
import com.limelight.settings.PreferencesManager.Preferences.Resolution;
|
import com.limelight.settings.PreferencesManager.Preferences.Resolution;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main class for Limelight-pc contains methods for starting the application as well
|
* Main class for Limelight-pc contains methods for starting the application as well
|
||||||
@@ -31,13 +30,10 @@ import com.limelight.settings.PreferencesManager.Preferences.Resolution;
|
|||||||
*/
|
*/
|
||||||
public class Limelight implements NvConnectionListener {
|
public class Limelight implements NvConnectionListener {
|
||||||
public static final double VERSION = 1.0;
|
public static final double VERSION = 1.0;
|
||||||
public static boolean COMMAND_LINE_LAUNCH = false;
|
|
||||||
|
|
||||||
private String host;
|
private String host;
|
||||||
private StreamFrame streamFrame;
|
|
||||||
private NvConnection conn;
|
private NvConnection conn;
|
||||||
private boolean connectionTerminating;
|
private boolean connectionTerminating;
|
||||||
private static JFrame limeFrame;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new instance based on the given host
|
* Constructs a new instance based on the given host
|
||||||
@@ -51,11 +47,8 @@ public class Limelight implements NvConnectionListener {
|
|||||||
* Creates a connection to the host and starts up the stream.
|
* Creates a connection to the host and starts up the stream.
|
||||||
*/
|
*/
|
||||||
private void startUp(StreamConfiguration streamConfig, boolean fullscreen) {
|
private void startUp(StreamConfiguration streamConfig, boolean fullscreen) {
|
||||||
streamFrame = new StreamFrame();
|
|
||||||
|
|
||||||
conn = new NvConnection(host, this, streamConfig);
|
conn = new NvConnection(host, this, streamConfig);
|
||||||
streamFrame.build(this, conn, streamConfig, fullscreen);
|
conn.start(PlatformBinding.getDeviceName(), null,
|
||||||
conn.start(PlatformBinding.getDeviceName(), streamFrame,
|
|
||||||
VideoDecoderRenderer.FLAG_PREFER_QUALITY,
|
VideoDecoderRenderer.FLAG_PREFER_QUALITY,
|
||||||
PlatformBinding.getAudioRenderer(),
|
PlatformBinding.getAudioRenderer(),
|
||||||
PlatformBinding.getVideoDecoderRenderer());
|
PlatformBinding.getVideoDecoderRenderer());
|
||||||
@@ -63,6 +56,46 @@ public class Limelight implements NvConnectionListener {
|
|||||||
GamepadListener.getInstance().addDeviceListener(new Gamepad(conn));
|
GamepadListener.getInstance().addDeviceListener(new Gamepad(conn));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void pair() {
|
||||||
|
String macAddress;
|
||||||
|
try {
|
||||||
|
macAddress = NvConnection.getMacAddressString();
|
||||||
|
} catch (SocketException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macAddress == null) {
|
||||||
|
displayError("Pair", "Couldn't find a MAC address");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
NvHTTP httpConn;
|
||||||
|
|
||||||
|
try {
|
||||||
|
httpConn = new NvHTTP(InetAddress.getByName(host),
|
||||||
|
macAddress, PlatformBinding.getDeviceName());
|
||||||
|
try {
|
||||||
|
if (httpConn.getPairState()) {
|
||||||
|
displayError("Pair", "Already paired");
|
||||||
|
} else {
|
||||||
|
int session = httpConn.getSessionId();
|
||||||
|
if (session == 0) {
|
||||||
|
displayError("Pair", "Pairing was declined by the target");
|
||||||
|
} else {
|
||||||
|
displayMessage("Pairing was successful");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
displayError("Pair", e.getMessage());
|
||||||
|
} catch (XmlPullParserException e) {
|
||||||
|
displayError("Pair", e.getMessage());
|
||||||
|
}
|
||||||
|
} catch (UnknownHostException e1) {
|
||||||
|
displayError("Pair", "Failed to resolve host");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Creates a StreamConfiguration given a Resolution.
|
* Creates a StreamConfiguration given a Resolution.
|
||||||
* Used to specify what kind of stream will be used.
|
* Used to specify what kind of stream will be used.
|
||||||
@@ -82,15 +115,6 @@ public class Limelight implements NvConnectionListener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the main frame for the application.
|
|
||||||
*/
|
|
||||||
private static void createFrame() {
|
|
||||||
MainFrame main = new MainFrame();
|
|
||||||
main.build();
|
|
||||||
limeFrame = main.getLimeFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance and starts the stream.
|
* Creates a new instance and starts the stream.
|
||||||
@@ -111,50 +135,16 @@ public class Limelight implements NvConnectionListener {
|
|||||||
* @param args unused.
|
* @param args unused.
|
||||||
*/
|
*/
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
// Redirect logging to a file if we're running from a JAR
|
|
||||||
if (LibraryHelper.isRunningFromJar()) {
|
|
||||||
try {
|
|
||||||
System.setErr(new PrintStream(new File("error.log")));
|
|
||||||
System.setOut(new PrintStream(new File("output.log")));
|
|
||||||
} catch (IOException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//fix the menu bar if we are running in osx
|
|
||||||
if (System.getProperty("os.name").contains("Mac OS X")) {
|
|
||||||
// take the menu bar off the jframe
|
|
||||||
System.setProperty("apple.laf.useScreenMenuBar", "true");
|
|
||||||
|
|
||||||
// set the name of the application menu item
|
|
||||||
System.setProperty("com.apple.mrj.application.apple.menu.about.name", "Limelight");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
System.out.println("Unable to set cross platform look and feel.");
|
|
||||||
e.printStackTrace();
|
|
||||||
System.exit(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LibraryHelper.prepareNativeLibraries();
|
LibraryHelper.prepareNativeLibraries();
|
||||||
|
|
||||||
NativeGamepad.addListener(GamepadListener.getInstance());
|
parseCommandLine(args);
|
||||||
NativeGamepad.start();
|
|
||||||
|
|
||||||
// launching with command line arguments
|
|
||||||
if (args.length > 0) {
|
|
||||||
parseCommandLine(args);
|
|
||||||
} else {
|
|
||||||
createFrame();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: make this less jank
|
//TODO: make this less jank
|
||||||
private static void parseCommandLine(String[] args) {
|
private static void parseCommandLine(String[] args) {
|
||||||
String host = null;
|
String host = null;
|
||||||
boolean fullscreen = false;
|
boolean fullscreen = false;
|
||||||
|
boolean pair = false;
|
||||||
int resolution = 720;
|
int resolution = 720;
|
||||||
int refresh = 30;
|
int refresh = 30;
|
||||||
|
|
||||||
@@ -167,6 +157,8 @@ public class Limelight implements NvConnectionListener {
|
|||||||
System.out.println("Syntax error: hostname or ip address expected after -host");
|
System.out.println("Syntax error: hostname or ip address expected after -host");
|
||||||
System.exit(3);
|
System.exit(3);
|
||||||
}
|
}
|
||||||
|
} else if (args[i].equals("-pair")) {
|
||||||
|
pair = true;
|
||||||
} else if (args[i].equals("-fs")) {
|
} else if (args[i].equals("-fs")) {
|
||||||
fullscreen = true;
|
fullscreen = true;
|
||||||
} else if (args[i].equals("-720")) {
|
} else if (args[i].equals("-720")) {
|
||||||
@@ -187,7 +179,7 @@ public class Limelight implements NvConnectionListener {
|
|||||||
System.exit(5);
|
System.exit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
Resolution streamRes = null;
|
Resolution streamRes = Resolution.RES_720_30;
|
||||||
|
|
||||||
if (resolution == 720 && refresh == 30) {
|
if (resolution == 720 && refresh == 30) {
|
||||||
streamRes = Resolution.RES_720_30;
|
streamRes = Resolution.RES_720_30;
|
||||||
@@ -202,8 +194,10 @@ public class Limelight implements NvConnectionListener {
|
|||||||
StreamConfiguration streamConfig = createConfiguration(streamRes);
|
StreamConfiguration streamConfig = createConfiguration(streamRes);
|
||||||
|
|
||||||
Limelight limelight = new Limelight(host);
|
Limelight limelight = new Limelight(host);
|
||||||
limelight.startUp(streamConfig, fullscreen);
|
if (!pair)
|
||||||
COMMAND_LINE_LAUNCH = true;
|
limelight.startUp(streamConfig, fullscreen);
|
||||||
|
else
|
||||||
|
limelight.pair();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -219,7 +213,6 @@ public class Limelight implements NvConnectionListener {
|
|||||||
@Override
|
@Override
|
||||||
public void stageStarting(Stage stage) {
|
public void stageStarting(Stage stage) {
|
||||||
System.out.println("Starting "+stage.getName());
|
System.out.println("Starting "+stage.getName());
|
||||||
streamFrame.showSpinner(stage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,7 +230,6 @@ public class Limelight implements NvConnectionListener {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void stageFailed(Stage stage) {
|
public void stageFailed(Stage stage) {
|
||||||
streamFrame.dispose();
|
|
||||||
conn.stop();
|
conn.stop();
|
||||||
displayError("Connection Error", "Starting " + stage.getName() + " failed");
|
displayError("Connection Error", "Starting " + stage.getName() + " failed");
|
||||||
}
|
}
|
||||||
@@ -247,7 +239,6 @@ public class Limelight implements NvConnectionListener {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void connectionStarted() {
|
public void connectionStarted() {
|
||||||
streamFrame.hideSpinner();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -272,7 +263,6 @@ public class Limelight implements NvConnectionListener {
|
|||||||
new Thread(new Runnable() {
|
new Thread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
streamFrame.dispose();
|
|
||||||
displayError("Connection Terminated", "The connection failed unexpectedly");
|
displayError("Connection Terminated", "The connection failed unexpectedly");
|
||||||
}
|
}
|
||||||
}).start();
|
}).start();
|
||||||
@@ -285,7 +275,7 @@ public class Limelight implements NvConnectionListener {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void displayMessage(String message) {
|
public void displayMessage(String message) {
|
||||||
JOptionPane.showMessageDialog(limeFrame, message, "Limelight", JOptionPane.INFORMATION_MESSAGE);
|
System.out.println(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -294,7 +284,7 @@ public class Limelight implements NvConnectionListener {
|
|||||||
* @param message the message to show the user
|
* @param message the message to show the user
|
||||||
*/
|
*/
|
||||||
public void displayError(String title, String message) {
|
public void displayError(String title, String message) {
|
||||||
JOptionPane.showMessageDialog(limeFrame, message, title, JOptionPane.ERROR_MESSAGE);
|
System.err.println(title + " " + message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,342 +0,0 @@
|
|||||||
package com.limelight.gui;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.GridLayout;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.WindowAdapter;
|
|
||||||
import java.awt.event.WindowEvent;
|
|
||||||
import java.awt.event.WindowListener;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
|
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.border.LineBorder;
|
|
||||||
|
|
||||||
import com.limelight.input.Device;
|
|
||||||
import com.limelight.input.DeviceListener;
|
|
||||||
import com.limelight.input.gamepad.GamepadComponent;
|
|
||||||
import com.limelight.input.gamepad.GamepadListener;
|
|
||||||
import com.limelight.input.gamepad.GamepadMapping;
|
|
||||||
import com.limelight.input.gamepad.GamepadMapping.Mapping;
|
|
||||||
import com.limelight.input.gamepad.SourceComponent;
|
|
||||||
import com.limelight.settings.GamepadSettingsManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A frame used to configure the gamepad mappings.
|
|
||||||
* @author Diego Waxemberg
|
|
||||||
*/
|
|
||||||
public class GamepadConfigFrame extends JFrame {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private boolean configChanged = false;
|
|
||||||
|
|
||||||
private MappingThread mappingThread;
|
|
||||||
private GamepadMapping config;
|
|
||||||
private HashMap<Box, Mapping> componentMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new config frame. The frame is initially invisible and will <br>
|
|
||||||
* be made visible after all components are built by calling <code>build()</code>
|
|
||||||
*/
|
|
||||||
public GamepadConfigFrame() {
|
|
||||||
super("Gamepad Settings");
|
|
||||||
System.out.println("Creating Settings Frame");
|
|
||||||
this.setSize(850, 550);
|
|
||||||
this.setResizable(false);
|
|
||||||
this.setAlwaysOnTop(true);
|
|
||||||
config = GamepadSettingsManager.getSettings();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds all components of the config frame and sets the frame visible.
|
|
||||||
*/
|
|
||||||
public void build() {
|
|
||||||
componentMap = new HashMap<Box, Mapping>();
|
|
||||||
|
|
||||||
GridLayout layout = new GridLayout(GamepadComponent.values().length/2 + 1, 2);
|
|
||||||
layout.setHgap(60);
|
|
||||||
layout.setVgap(3);
|
|
||||||
JPanel mainPanel = new JPanel(layout);
|
|
||||||
|
|
||||||
GamepadComponent[] components = GamepadComponent.values();
|
|
||||||
|
|
||||||
for (int i = 0; i < components.length; i++) {
|
|
||||||
|
|
||||||
Mapping mapping = config.get(components[i]);
|
|
||||||
if (mapping == null) {
|
|
||||||
mapping = config.new Mapping(components[i], false, false);
|
|
||||||
config.insertMapping(mapping, null);
|
|
||||||
}
|
|
||||||
Box componentBox = createComponentBox(mapping);
|
|
||||||
|
|
||||||
mainPanel.add(componentBox);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
|
|
||||||
|
|
||||||
this.setLocation(dim.width/2-this.getSize().width/2, dim.height/2-this.getSize().height/2);
|
|
||||||
this.setLayout(new BorderLayout());
|
|
||||||
|
|
||||||
this.getContentPane().add(mainPanel, "Center");
|
|
||||||
this.getContentPane().add(Box.createVerticalStrut(20), "North");
|
|
||||||
this.getContentPane().add(Box.createVerticalStrut(20), "South");
|
|
||||||
this.getContentPane().add(Box.createHorizontalStrut(20), "East");
|
|
||||||
this.getContentPane().add(Box.createHorizontalStrut(20), "West");
|
|
||||||
|
|
||||||
this.addWindowListener(createWindowListener());
|
|
||||||
this.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the box that holds the button and checkboxes
|
|
||||||
*/
|
|
||||||
private Box createComponentBox(Mapping mapping) {
|
|
||||||
Box componentBox = Box.createHorizontalBox();
|
|
||||||
|
|
||||||
JButton mapButton = new JButton();
|
|
||||||
JCheckBox invertBox = new GamepadCheckBox("Invert", GamepadCheckBox.Type.INVERT);
|
|
||||||
JCheckBox triggerBox = new GamepadCheckBox("Trigger", GamepadCheckBox.Type.TRIGGER);
|
|
||||||
|
|
||||||
Dimension buttonSize = new Dimension(110, 24);
|
|
||||||
mapButton.setMaximumSize(buttonSize);
|
|
||||||
mapButton.setMinimumSize(buttonSize);
|
|
||||||
mapButton.setPreferredSize(buttonSize);
|
|
||||||
mapButton.addActionListener(createMapListener());
|
|
||||||
|
|
||||||
setButtonText(mapButton, config.getMapping(mapping.padComp));
|
|
||||||
|
|
||||||
invertBox.setSelected(mapping.invert);
|
|
||||||
invertBox.addActionListener(createCheckboxListener());
|
|
||||||
invertBox.setName(mapping.padComp.name());
|
|
||||||
|
|
||||||
triggerBox.setSelected(mapping.trigger);
|
|
||||||
triggerBox.addActionListener(createCheckboxListener());
|
|
||||||
triggerBox.setName(mapping.padComp.name());
|
|
||||||
triggerBox.setToolTipText("If this component should act as a trigger. (one-way axis)");
|
|
||||||
|
|
||||||
componentBox.add(Box.createHorizontalStrut(5));
|
|
||||||
componentBox.add(mapping.padComp.getLabel());
|
|
||||||
componentBox.add(Box.createHorizontalGlue());
|
|
||||||
componentBox.add(mapButton);
|
|
||||||
componentBox.add(invertBox);
|
|
||||||
componentBox.add(triggerBox);
|
|
||||||
componentBox.add(Box.createHorizontalStrut(5));
|
|
||||||
|
|
||||||
componentBox.setBorder(new LineBorder(Color.GRAY, 1, true));
|
|
||||||
|
|
||||||
componentMap.put(componentBox, mapping);
|
|
||||||
|
|
||||||
return componentBox;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the listener for the checkbox
|
|
||||||
*/
|
|
||||||
private ActionListener createCheckboxListener() {
|
|
||||||
return new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
JCheckBox clicked = (JCheckBox)e.getSource();
|
|
||||||
GamepadComponent padComp = GamepadComponent.valueOf(clicked.getName());
|
|
||||||
Mapping currentMapping = config.get(padComp);
|
|
||||||
if (currentMapping == null) {
|
|
||||||
//this makes more semantic sense to me than using !=
|
|
||||||
clicked.setSelected(!(clicked.isSelected()));
|
|
||||||
} else {
|
|
||||||
((GamepadCheckBox)clicked).setValue(currentMapping, clicked.isSelected());
|
|
||||||
configChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the listener for the window.
|
|
||||||
* It will save configs on exit and restart controller threads
|
|
||||||
*/
|
|
||||||
private WindowListener createWindowListener() {
|
|
||||||
return new WindowAdapter() {
|
|
||||||
@Override
|
|
||||||
public void windowClosing(WindowEvent e) {
|
|
||||||
if (mappingThread != null && mappingThread.isAlive()) {
|
|
||||||
mappingThread.interrupt();
|
|
||||||
}
|
|
||||||
if (configChanged) {
|
|
||||||
updateConfigs();
|
|
||||||
}
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the listener for the map button
|
|
||||||
*/
|
|
||||||
private ActionListener createMapListener() {
|
|
||||||
return new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
Box toMap = (Box)((JButton)e.getSource()).getParent();
|
|
||||||
|
|
||||||
if (GamepadListener.getInstance().deviceCount() == 0) {
|
|
||||||
JOptionPane.showMessageDialog(GamepadConfigFrame.this, "No Gamepad Detected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
map(toMap);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Maps a gamepad component to the clicked component
|
|
||||||
*/
|
|
||||||
private void map(final Box toMap) {
|
|
||||||
if (mappingThread == null || !mappingThread.isAlive()) {
|
|
||||||
|
|
||||||
//a little janky, could probably be fixed up a bit
|
|
||||||
final JButton buttonPressed = getButton(toMap);
|
|
||||||
final Mapping mappingToMap = componentMap.get(toMap);
|
|
||||||
|
|
||||||
buttonPressed.setSelected(true);
|
|
||||||
|
|
||||||
buttonPressed.setText("Select Input");
|
|
||||||
|
|
||||||
mappingThread = new MappingThread(buttonPressed, mappingToMap);
|
|
||||||
mappingThread.start();
|
|
||||||
|
|
||||||
GamepadListener.getInstance().addDeviceListener(mappingThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to get the box component that contains the given a mapping
|
|
||||||
*/
|
|
||||||
private Box getBox(Mapping mapping) {
|
|
||||||
for (Entry<Box, Mapping> entry : componentMap.entrySet()) {
|
|
||||||
if (entry.getValue() == mapping) {
|
|
||||||
return entry.getKey();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper method to get the button out of the box component
|
|
||||||
*/
|
|
||||||
private JButton getButton(Box componentBox) {
|
|
||||||
for (java.awt.Component comp : componentBox.getComponents()) {
|
|
||||||
if (comp instanceof JButton)
|
|
||||||
return (JButton)comp;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Writes the current cofig to the configs on disk.
|
|
||||||
*/
|
|
||||||
private void updateConfigs() {
|
|
||||||
GamepadSettingsManager.writeSettings(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setButtonText(JButton button, SourceComponent comp) {
|
|
||||||
if (comp == null) {
|
|
||||||
button.setText("");
|
|
||||||
} else {
|
|
||||||
button.setText(comp.getType().name() + " " + comp.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MappingThread extends Thread implements DeviceListener {
|
|
||||||
private SourceComponent newMapping = null;
|
|
||||||
private JButton buttonPressed;
|
|
||||||
private Mapping mappingToMap;
|
|
||||||
|
|
||||||
public MappingThread(JButton buttonPressed, Mapping mappingToMap) {
|
|
||||||
super("Gamepad Mapping Thread");
|
|
||||||
this.buttonPressed = buttonPressed;
|
|
||||||
this.mappingToMap = mappingToMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
|
|
||||||
while (newMapping == null) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(100);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
setButtonText(buttonPressed, config.getMapping(mappingToMap.padComp));
|
|
||||||
GamepadListener.getInstance().removeListener(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Mapping oldConfig = config.get(newMapping);
|
|
||||||
if (oldConfig != null) {
|
|
||||||
getButton(getBox(oldConfig)).setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
config.insertMapping(mappingToMap, newMapping);
|
|
||||||
|
|
||||||
setButtonText(buttonPressed, newMapping);
|
|
||||||
configChanged = true;
|
|
||||||
|
|
||||||
GamepadListener.getInstance().removeListener(this);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleButton(Device device, int buttonId, boolean pressed) {
|
|
||||||
if (pressed) {
|
|
||||||
newMapping = new SourceComponent(SourceComponent.Type.BUTTON, buttonId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handleAxis(Device device, int axisId, float newValue,
|
|
||||||
float lastValue) {
|
|
||||||
if (Math.abs(newValue) > 0.75) {
|
|
||||||
newMapping = new SourceComponent(SourceComponent.Type.AXIS, axisId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class GamepadCheckBox extends JCheckBox {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private enum Type { TRIGGER, INVERT }
|
|
||||||
private Type type;
|
|
||||||
|
|
||||||
public GamepadCheckBox(String text, Type type) {
|
|
||||||
super(text);
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setValue(Mapping mapping, boolean value) {
|
|
||||||
switch (type) {
|
|
||||||
case TRIGGER:
|
|
||||||
mapping.trigger = value;
|
|
||||||
break;
|
|
||||||
case INVERT:
|
|
||||||
mapping.invert = value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
System.out.println("You did something terrible and should feel terrible.");
|
|
||||||
System.out.println("Fix it or the checkbox gods will smite you!");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
package com.limelight.gui;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Container;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
|
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.BoxLayout;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuBar;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
|
|
||||||
import org.xmlpull.v1.XmlPullParserException;
|
|
||||||
|
|
||||||
import com.limelight.Limelight;
|
|
||||||
import com.limelight.binding.PlatformBinding;
|
|
||||||
import com.limelight.nvstream.NvConnection;
|
|
||||||
import com.limelight.nvstream.http.NvHTTP;
|
|
||||||
import com.limelight.settings.PreferencesManager;
|
|
||||||
import com.limelight.settings.PreferencesManager.Preferences;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main frame of Limelight that allows the user to specify the host and begin the stream.
|
|
||||||
* @author Diego Waxemberg
|
|
||||||
* <br>Cameron Gutman
|
|
||||||
*/
|
|
||||||
public class MainFrame {
|
|
||||||
private JTextField hostField;
|
|
||||||
private JButton pair;
|
|
||||||
private JButton stream;
|
|
||||||
private JFrame limeFrame;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the actual JFrame this class creates
|
|
||||||
* @return the JFrame that is the main frame
|
|
||||||
*/
|
|
||||||
public JFrame getLimeFrame() {
|
|
||||||
return limeFrame;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds all components of the frame, including the frame itself and displays it to the user.
|
|
||||||
*/
|
|
||||||
public void build() {
|
|
||||||
limeFrame = new JFrame("Limelight");
|
|
||||||
limeFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
|
||||||
Container mainPane = limeFrame.getContentPane();
|
|
||||||
|
|
||||||
mainPane.setLayout(new BorderLayout());
|
|
||||||
|
|
||||||
JPanel centerPane = new JPanel();
|
|
||||||
centerPane.setLayout(new BoxLayout(centerPane, BoxLayout.Y_AXIS));
|
|
||||||
|
|
||||||
Preferences prefs = PreferencesManager.getPreferences();
|
|
||||||
|
|
||||||
hostField = new JTextField();
|
|
||||||
hostField.setMaximumSize(new Dimension(Integer.MAX_VALUE, 24));
|
|
||||||
hostField.setToolTipText("Enter host name or IP address");
|
|
||||||
hostField.setText(prefs.getHost());
|
|
||||||
hostField.setSelectionStart(0);
|
|
||||||
hostField.setSelectionEnd(hostField.getText().length());
|
|
||||||
|
|
||||||
stream = new JButton("Start Streaming");
|
|
||||||
stream.addActionListener(createStreamButtonListener());
|
|
||||||
stream.setToolTipText("Start the GeForce stream");
|
|
||||||
|
|
||||||
pair = new JButton("Pair");
|
|
||||||
pair.addActionListener(createPairButtonListener());
|
|
||||||
pair.setToolTipText("Send pair request to GeForce PC");
|
|
||||||
|
|
||||||
Box streamBox = Box.createHorizontalBox();
|
|
||||||
streamBox.add(Box.createHorizontalGlue());
|
|
||||||
streamBox.add(stream);
|
|
||||||
streamBox.add(Box.createHorizontalGlue());
|
|
||||||
|
|
||||||
Box pairBox = Box.createHorizontalBox();
|
|
||||||
pairBox.add(Box.createHorizontalGlue());
|
|
||||||
pairBox.add(pair);
|
|
||||||
pairBox.add(Box.createHorizontalGlue());
|
|
||||||
|
|
||||||
Box hostBox = Box.createHorizontalBox();
|
|
||||||
hostBox.add(Box.createHorizontalStrut(20));
|
|
||||||
hostBox.add(hostField);
|
|
||||||
hostBox.add(Box.createHorizontalStrut(20));
|
|
||||||
|
|
||||||
|
|
||||||
Box contentBox = Box.createVerticalBox();
|
|
||||||
contentBox.add(Box.createVerticalStrut(20));
|
|
||||||
contentBox.add(hostBox);
|
|
||||||
contentBox.add(Box.createVerticalStrut(5));
|
|
||||||
contentBox.add(streamBox);
|
|
||||||
contentBox.add(Box.createVerticalStrut(10));
|
|
||||||
contentBox.add(pairBox);
|
|
||||||
|
|
||||||
contentBox.add(Box.createVerticalGlue());
|
|
||||||
|
|
||||||
centerPane.add(contentBox);
|
|
||||||
mainPane.add(centerPane, "Center");
|
|
||||||
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
|
|
||||||
|
|
||||||
limeFrame.setJMenuBar(createMenuBar());
|
|
||||||
limeFrame.getRootPane().setDefaultButton(stream);
|
|
||||||
limeFrame.setSize(300, 200);
|
|
||||||
limeFrame.setLocation(dim.width/2-limeFrame.getSize().width/2, dim.height/2-limeFrame.getSize().height/2);
|
|
||||||
limeFrame.setResizable(false);
|
|
||||||
limeFrame.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the menu bar for the user to go to preferences, mappings, etc.
|
|
||||||
*/
|
|
||||||
private JMenuBar createMenuBar() {
|
|
||||||
JMenuBar menuBar = new JMenuBar();
|
|
||||||
JMenu optionsMenu = new JMenu("Options");
|
|
||||||
JMenuItem gamepadSettings = new JMenuItem("Gamepad Settings");
|
|
||||||
JMenuItem generalSettings = new JMenuItem("Preferences");
|
|
||||||
|
|
||||||
gamepadSettings.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
new GamepadConfigFrame().build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
generalSettings.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
new PreferencesFrame().build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
optionsMenu.add(gamepadSettings);
|
|
||||||
optionsMenu.add(generalSettings);
|
|
||||||
|
|
||||||
menuBar.add(optionsMenu);
|
|
||||||
|
|
||||||
return menuBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the listener for the stream button- starts the stream process
|
|
||||||
*/
|
|
||||||
private ActionListener createStreamButtonListener() {
|
|
||||||
return new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
String host = hostField.getText();
|
|
||||||
Preferences prefs = PreferencesManager.getPreferences();
|
|
||||||
if (!host.equals(prefs.getHost())) {
|
|
||||||
prefs.setHost(host);
|
|
||||||
PreferencesManager.writePreferences(prefs);
|
|
||||||
}
|
|
||||||
Limelight.createInstance(host);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Creates the listener for the pair button- requests a pairing with the specified host
|
|
||||||
*/
|
|
||||||
private ActionListener createPairButtonListener() {
|
|
||||||
return new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent arg0) {
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String macAddress;
|
|
||||||
try {
|
|
||||||
macAddress = NvConnection.getMacAddressString();
|
|
||||||
} catch (SocketException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (macAddress == null) {
|
|
||||||
System.out.println("Couldn't find a MAC address");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
NvHTTP httpConn;
|
|
||||||
String message;
|
|
||||||
try {
|
|
||||||
httpConn = new NvHTTP(InetAddress.getByName(hostField.getText()),
|
|
||||||
macAddress, PlatformBinding.getDeviceName());
|
|
||||||
try {
|
|
||||||
if (httpConn.getPairState()) {
|
|
||||||
message = "Already paired";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int session = httpConn.getSessionId();
|
|
||||||
if (session == 0) {
|
|
||||||
message = "Pairing was declined by the target";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message = "Pairing was successful";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
message = e.getMessage();
|
|
||||||
} catch (XmlPullParserException e) {
|
|
||||||
message = e.getMessage();
|
|
||||||
}
|
|
||||||
} catch (UnknownHostException e1) {
|
|
||||||
message = "Failed to resolve host";
|
|
||||||
}
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(limeFrame, message, "Limelight", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package com.limelight.gui;
|
|
||||||
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.WindowAdapter;
|
|
||||||
import java.awt.event.WindowEvent;
|
|
||||||
|
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.BoxLayout;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
|
|
||||||
import com.limelight.settings.PreferencesManager;
|
|
||||||
import com.limelight.settings.PreferencesManager.Preferences;
|
|
||||||
import com.limelight.settings.PreferencesManager.Preferences.Resolution;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A frame that holds user preferences such as streaming resolution
|
|
||||||
* @author Diego Waxemberg
|
|
||||||
*/
|
|
||||||
public class PreferencesFrame extends JFrame {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private JComboBox resolution;
|
|
||||||
private JCheckBox fullscreen;
|
|
||||||
private Preferences prefs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construcs a new frame and loads the saved preferences.
|
|
||||||
* <br>The frame is not made visible until a call to <br>build()</br> is made.
|
|
||||||
*/
|
|
||||||
public PreferencesFrame() {
|
|
||||||
super("Preferences");
|
|
||||||
this.setSize(200, 100);
|
|
||||||
this.setResizable(false);
|
|
||||||
this.setAlwaysOnTop(true);
|
|
||||||
prefs = PreferencesManager.getPreferences();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs all components of the frame and makes the frame visible to the user.
|
|
||||||
*/
|
|
||||||
public void build() {
|
|
||||||
|
|
||||||
JPanel mainPanel = new JPanel();
|
|
||||||
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
|
|
||||||
|
|
||||||
resolution = new JComboBox();
|
|
||||||
for (Resolution res : Resolution.values()) {
|
|
||||||
resolution.addItem(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolution.setSelectedItem(prefs.getResolution());
|
|
||||||
|
|
||||||
fullscreen = new JCheckBox("Fullscreen");
|
|
||||||
fullscreen.setSelected(prefs.getFullscreen());
|
|
||||||
|
|
||||||
Box resolutionBox = Box.createHorizontalBox();
|
|
||||||
resolutionBox.add(Box.createHorizontalGlue());
|
|
||||||
resolutionBox.add(resolution);
|
|
||||||
resolutionBox.add(Box.createHorizontalGlue());
|
|
||||||
|
|
||||||
Box fullscreenBox = Box.createHorizontalBox();
|
|
||||||
fullscreenBox.add(Box.createHorizontalGlue());
|
|
||||||
fullscreenBox.add(fullscreen);
|
|
||||||
fullscreenBox.add(Box.createHorizontalGlue());
|
|
||||||
|
|
||||||
mainPanel.add(Box.createVerticalStrut(10));
|
|
||||||
mainPanel.add(resolutionBox);
|
|
||||||
mainPanel.add(Box.createVerticalStrut(5));
|
|
||||||
mainPanel.add(fullscreenBox);
|
|
||||||
mainPanel.add(Box.createVerticalGlue());
|
|
||||||
|
|
||||||
this.addWindowListener(new WindowAdapter() {
|
|
||||||
@Override
|
|
||||||
public void windowClosing(WindowEvent e) {
|
|
||||||
super.windowClosing(e);
|
|
||||||
if (prefsChanged()) {
|
|
||||||
writePreferences();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.getContentPane().add(mainPanel);
|
|
||||||
|
|
||||||
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
|
|
||||||
//center on screen
|
|
||||||
this.setLocation((int)dim.getWidth()/2-this.getWidth()/2, (int)dim.getHeight()/2-this.getHeight()/2);
|
|
||||||
|
|
||||||
this.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Checks if the preferences have changed from the cached preferences.
|
|
||||||
*/
|
|
||||||
private boolean prefsChanged() {
|
|
||||||
return (prefs.getResolution() != resolution.getSelectedItem()) ||
|
|
||||||
(prefs.getFullscreen() != fullscreen.isSelected());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Writes the preferences to the disk.
|
|
||||||
*/
|
|
||||||
private void writePreferences() {
|
|
||||||
prefs.setFullscreen(fullscreen.isSelected());
|
|
||||||
prefs.setResolution((Resolution)resolution.getSelectedItem());
|
|
||||||
PreferencesManager.writePreferences(prefs);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,287 +0,0 @@
|
|||||||
package com.limelight.gui;
|
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Container;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.DisplayMode;
|
|
||||||
import java.awt.GraphicsDevice;
|
|
||||||
import java.awt.GraphicsEnvironment;
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.WindowAdapter;
|
|
||||||
import java.awt.event.WindowEvent;
|
|
||||||
import java.awt.event.WindowListener;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.BoxLayout;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JProgressBar;
|
|
||||||
|
|
||||||
import com.limelight.Limelight;
|
|
||||||
import com.limelight.input.KeyboardHandler;
|
|
||||||
import com.limelight.input.MouseHandler;
|
|
||||||
import com.limelight.nvstream.NvConnection;
|
|
||||||
import com.limelight.nvstream.NvConnectionListener.Stage;
|
|
||||||
import com.limelight.nvstream.StreamConfiguration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The frame to which the video is rendered
|
|
||||||
* @author Diego Waxemberg
|
|
||||||
* <br>Cameron Gutman
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class StreamFrame extends JFrame {
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final double DESIRED_ASPECT_RATIO = 16.0/9.0;
|
|
||||||
private static final double ALTERNATE_ASPECT_RATIO = 16.0/10.0;
|
|
||||||
|
|
||||||
private KeyboardHandler keyboard;
|
|
||||||
private MouseHandler mouse;
|
|
||||||
private JProgressBar spinner;
|
|
||||||
private JLabel spinnerLabel;
|
|
||||||
private Cursor noCursor;
|
|
||||||
private Limelight limelight;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Frees the mouse ie. makes it visible and allowed to move outside the frame.
|
|
||||||
*/
|
|
||||||
public void freeMouse() {
|
|
||||||
mouse.free();
|
|
||||||
showCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Captures the mouse ie. makes it invisible and not allowed to leave the frame
|
|
||||||
*/
|
|
||||||
public void captureMouse() {
|
|
||||||
mouse.capture();
|
|
||||||
hideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the components of this frame with the specified configurations.
|
|
||||||
* @param conn the connection this frame belongs to
|
|
||||||
* @param streamConfig the configurations for this frame
|
|
||||||
* @param fullscreen if the frame should be made fullscreen
|
|
||||||
*/
|
|
||||||
public void build(Limelight limelight, NvConnection conn, StreamConfiguration streamConfig, boolean fullscreen) {
|
|
||||||
this.limelight = limelight;
|
|
||||||
|
|
||||||
keyboard = new KeyboardHandler(conn, this);
|
|
||||||
mouse = new MouseHandler(conn, this);
|
|
||||||
|
|
||||||
this.addKeyListener(keyboard);
|
|
||||||
this.addMouseListener(mouse);
|
|
||||||
this.addMouseMotionListener(mouse);
|
|
||||||
|
|
||||||
this.setFocusTraversalKeysEnabled(false);
|
|
||||||
|
|
||||||
this.setSize(streamConfig.getWidth(), streamConfig.getHeight());
|
|
||||||
|
|
||||||
this.setBackground(Color.BLACK);
|
|
||||||
this.getContentPane().setBackground(Color.BLACK);
|
|
||||||
this.getRootPane().setBackground(Color.BLACK);
|
|
||||||
|
|
||||||
this.addWindowListener(createWindowListener());
|
|
||||||
|
|
||||||
if (fullscreen) {
|
|
||||||
makeFullScreen(streamConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
hideCursor();
|
|
||||||
this.setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ArrayList<DisplayMode> getDisplayModesByAspectRatio(DisplayMode[] configs, double aspectRatio) {
|
|
||||||
ArrayList<DisplayMode> matchingConfigs = new ArrayList<DisplayMode>();
|
|
||||||
|
|
||||||
for (DisplayMode config : configs) {
|
|
||||||
if ((double)config.getWidth()/(double)config.getHeight() == aspectRatio) {
|
|
||||||
matchingConfigs.add(config);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matchingConfigs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DisplayMode getBestDisplay(StreamConfiguration targetConfig, DisplayMode[] configs) {
|
|
||||||
int targetDisplaySize = targetConfig.getWidth()*targetConfig.getHeight();
|
|
||||||
|
|
||||||
// Try to match the target aspect ratio
|
|
||||||
ArrayList<DisplayMode> aspectMatchingConfigs = getDisplayModesByAspectRatio(configs, DESIRED_ASPECT_RATIO);
|
|
||||||
if (aspectMatchingConfigs.size() == 0) {
|
|
||||||
// No matches for the target, so try the alternate
|
|
||||||
aspectMatchingConfigs = getDisplayModesByAspectRatio(configs, ALTERNATE_ASPECT_RATIO);
|
|
||||||
if (aspectMatchingConfigs.size() == 0) {
|
|
||||||
// No matches for either, so just use all of them
|
|
||||||
aspectMatchingConfigs = new ArrayList<DisplayMode>(Arrays.asList(configs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort by display size
|
|
||||||
Collections.sort(aspectMatchingConfigs, new Comparator<DisplayMode>() {
|
|
||||||
@Override
|
|
||||||
public int compare(DisplayMode o1, DisplayMode o2) {
|
|
||||||
if (o1.getWidth()*o1.getHeight() > o2.getWidth()*o2.getHeight()) {
|
|
||||||
return -1;
|
|
||||||
} else if (o2.getWidth()*o2.getHeight() > o1.getWidth()*o1.getHeight()) {
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Find the aspect-matching config with the closest matching display size
|
|
||||||
DisplayMode bestConfig = null;
|
|
||||||
for (DisplayMode config : aspectMatchingConfigs) {
|
|
||||||
if (config.getWidth()*config.getHeight() >= targetDisplaySize) {
|
|
||||||
bestConfig = config;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bestConfig != null) {
|
|
||||||
System.out.println("Using full-screen display mode "+bestConfig.getWidth()+"x"+bestConfig.getHeight()+
|
|
||||||
" for "+targetConfig.getWidth()+"x"+targetConfig.getHeight()+" stream");
|
|
||||||
}
|
|
||||||
|
|
||||||
return bestConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void makeFullScreen(StreamConfiguration streamConfig) {
|
|
||||||
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
|
|
||||||
if (gd.isFullScreenSupported()) {
|
|
||||||
this.setUndecorated(true);
|
|
||||||
gd.setFullScreenWindow(this);
|
|
||||||
|
|
||||||
if (gd.isDisplayChangeSupported()) {
|
|
||||||
DisplayMode config = getBestDisplay(streamConfig, gd.getDisplayModes());
|
|
||||||
if (config != null) {
|
|
||||||
gd.setDisplayMode(config);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this,
|
|
||||||
"Unable to change display resolution. \nThis may not be the correct resolution",
|
|
||||||
"Display Resolution",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this,
|
|
||||||
"Your operating system does not support fullscreen.",
|
|
||||||
"Fullscreen Unsupported",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the mouse cursor invisible
|
|
||||||
*/
|
|
||||||
public void hideCursor() {
|
|
||||||
if (noCursor == null) {
|
|
||||||
// Transparent 16 x 16 pixel cursor image.
|
|
||||||
BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
|
|
||||||
// Create a new blank cursor.
|
|
||||||
noCursor = Toolkit.getDefaultToolkit().createCustomCursor(
|
|
||||||
cursorImg, new Point(0, 0), "blank cursor");
|
|
||||||
}
|
|
||||||
// Set the blank cursor to the JFrame.
|
|
||||||
this.setCursor(noCursor);
|
|
||||||
this.getContentPane().setCursor(noCursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the mouse cursor visible
|
|
||||||
*/
|
|
||||||
public void showCursor() {
|
|
||||||
this.setCursor(Cursor.getDefaultCursor());
|
|
||||||
this.getContentPane().setCursor(Cursor.getDefaultCursor());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a progress bar with a label underneath that tells the user what
|
|
||||||
* loading stage the stream is at.
|
|
||||||
* @param stage the currently loading stage
|
|
||||||
*/
|
|
||||||
public void showSpinner(Stage stage) {
|
|
||||||
|
|
||||||
if (spinner == null) {
|
|
||||||
Container c = this.getContentPane();
|
|
||||||
JPanel panel = new JPanel();
|
|
||||||
panel.setBackground(Color.BLACK);
|
|
||||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
|
||||||
|
|
||||||
spinner = new JProgressBar();
|
|
||||||
spinner.setIndeterminate(true);
|
|
||||||
spinner.setMaximumSize(new Dimension(150, 30));
|
|
||||||
|
|
||||||
spinnerLabel = new JLabel();
|
|
||||||
spinnerLabel.setForeground(Color.white);
|
|
||||||
|
|
||||||
Box spinBox = Box.createHorizontalBox();
|
|
||||||
spinBox.add(Box.createHorizontalGlue());
|
|
||||||
spinBox.add(spinner);
|
|
||||||
spinBox.add(Box.createHorizontalGlue());
|
|
||||||
|
|
||||||
Box lblBox = Box.createHorizontalBox();
|
|
||||||
lblBox.add(Box.createHorizontalGlue());
|
|
||||||
lblBox.add(spinnerLabel);
|
|
||||||
lblBox.add(Box.createHorizontalGlue());
|
|
||||||
|
|
||||||
panel.add(Box.createVerticalGlue());
|
|
||||||
panel.add(spinBox);
|
|
||||||
panel.add(Box.createVerticalStrut(10));
|
|
||||||
panel.add(lblBox);
|
|
||||||
panel.add(Box.createVerticalGlue());
|
|
||||||
|
|
||||||
c.setLayout(new BorderLayout());
|
|
||||||
c.add(panel, "Center");
|
|
||||||
}
|
|
||||||
spinnerLabel.setText("Starting " + stage.getName() + "...");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the listener for the window.
|
|
||||||
* It terminates the connection when the window is closed
|
|
||||||
*/
|
|
||||||
private WindowListener createWindowListener() {
|
|
||||||
return new WindowAdapter() {
|
|
||||||
@Override
|
|
||||||
public void windowClosing(WindowEvent e) {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hides the spinner and the label
|
|
||||||
*/
|
|
||||||
public void hideSpinner() {
|
|
||||||
spinner.setVisible(false);
|
|
||||||
spinnerLabel.setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops the stream and destroys the frame
|
|
||||||
*/
|
|
||||||
public void close() {
|
|
||||||
limelight.stop();
|
|
||||||
dispose();
|
|
||||||
if (Limelight.COMMAND_LINE_LAUNCH) {
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user