diff --git a/java/build.gradle b/java/build.gradle
new file mode 100644
index 0000000..a81b2f9
--- /dev/null
+++ b/java/build.gradle
@@ -0,0 +1,16 @@
+subprojects {
+ apply plugin: 'java'
+ apply plugin: 'eclipse'
+
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ }
+
+ version = '0.1'
+
+ jar {
+ }
+}
diff --git a/java/itunescontroller/.classpath b/java/itunescontroller/.classpath
new file mode 100644
index 0000000..4589d57
--- /dev/null
+++ b/java/itunescontroller/.classpath
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/java/itunescontroller/.project b/java/itunescontroller/.project
new file mode 100644
index 0000000..3e38131
--- /dev/null
+++ b/java/itunescontroller/.project
@@ -0,0 +1,18 @@
+
+
+ itunescontroller
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.springsource.ide.eclipse.gradle.core.nature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java/itunescontroller/build.gradle b/java/itunescontroller/build.gradle
new file mode 100644
index 0000000..9c99f6a
--- /dev/null
+++ b/java/itunescontroller/build.gradle
@@ -0,0 +1,3 @@
+dependencies {
+ compile 'net.sf.jacob-project:jacob:1.+'
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtwork.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtwork.java
new file mode 100644
index 0000000..53846c9
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtwork.java
@@ -0,0 +1,55 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a artwork.
+ *
+ * Defines a single piece of artwork.
+ *
+ * Artwork is always associated with an individual track.
+ * To add a piece of artwork to a track, use IITTrack::AddArtworkFromFile().
+ * The IITTrack::Artwork property
+ *
+ * To get a collection of artwork associated with a track call
+ * ITTrack.getArtwork().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITArtwork extends ITObject {
+
+ public ITArtwork (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Delete this object.
+ */
+ public void delete() {
+ Dispatch.call(object, "Delete");
+ }
+
+ /**
+ * Returns the kind of the object.
+ * @return Returns the kind of the object.
+ */
+ public ITArtworkFormat getFormat() {
+ return ITArtworkFormat.values()[Dispatch.get(object, "Format").getInt()];
+ }
+
+ // TODO: Comments
+
+ public boolean getIsDownloadedArtwork() {
+ return Dispatch.get(object, "IsDownloadedArtwork").getBoolean();
+ }
+
+ public String getDescription() {
+ return Dispatch.get(object, "Description").getString();
+
+ }
+
+ public void SaveArtworkToFile(String filePath) {
+ Dispatch.call(object, "SaveArtworkToFile",filePath);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtworkCollection.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtworkCollection.java
new file mode 100644
index 0000000..c1d8afa
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtworkCollection.java
@@ -0,0 +1,55 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of Artwork objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the Artworks defined for a source using
+ * ITSource.getArtwork().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITArtworkCollection {
+
+ protected Dispatch object;
+
+ public ITArtworkCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of playlists in the collection.
+ * @return Returns the number of playlists in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITArtwork object corresponding to the given index (1-based).
+ * @param index Index of the playlist to retrieve, must be less than or
+ * equal to ITArtworkCollection.getCount().
+ * @return Returns an ITArtwork object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITArtwork getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITArtwork(item);
+ }
+
+ /**
+ * Returns an ITArtwork object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITArtwork object with the specified persistent ID.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITArtwork getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITArtwork(item);
+ }
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtworkFormat.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtworkFormat.java
new file mode 100644
index 0000000..ed4b61e
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITArtworkFormat.java
@@ -0,0 +1,13 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the Artwork kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITArtworkFormat {
+ ITArtworkFormatUnknown,
+ ITArtworkFormatJPEG,
+ ITArtworkFormatPNG,
+ ITArtworkFormatBMP;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITAudioCDPlaylist.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITAudioCDPlaylist.java
new file mode 100644
index 0000000..bc12943
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITAudioCDPlaylist.java
@@ -0,0 +1,76 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an audio CD playlist.
+ *
+ * An audio CD playlist is always associated with an IITSource of kind
+ * ITSourceKindAudioCD.
+ *
+ * You can retrieve all the playlists defined for a source using
+ * ITSource.getPlaylists().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITAudioCDPlaylist extends ITPlaylist {
+
+ public ITAudioCDPlaylist(Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the audio CD's artist.
+ * @return Returns the audio CD's artist.
+ */
+ public String getArtist() {
+ return Dispatch.get(object, "Artist").getString();
+ }
+
+ /**
+ * Returns true if this audio CD is a compilation album.
+ * @return Returns true if this audio CD is a compilation album.
+ */
+ public boolean isCompilation() {
+ return Dispatch.get(object, "Compilation").getBoolean();
+ }
+
+ /**
+ * Returns the audio CD's composer.
+ * @return Returns the audio CD's composer.
+ */
+ public String getComposer() {
+ return Dispatch.get(object, "Composer").getString();
+ }
+
+ /**
+ * Returns the total number of discs in this CD's album.
+ * @return Returns the total number of discs in this CD's album.
+ */
+ public long getDiscCount() {
+ return Dispatch.get(object, "DiscCount").getLong();
+ }
+
+ /**
+ * Returns the index of the CD disc in the source album.
+ * @return Returns the index of the CD disc in the source album.
+ */
+ public long getDiscNumber() {
+ return Dispatch.get(object, "DiscNumber").getLong();
+ }
+
+ /**
+ * Returns the audio CD's genre.
+ * @return Returns the audio CD's genre.
+ */
+ public String getGenre() {
+ return Dispatch.get(object, "Genre").getString();
+ }
+
+ /**
+ * Reveals the CD playlist in the main browser window.
+ */
+ public void reveal() {
+ Dispatch.call(object, "Reveal");
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITBrowserWindow.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITBrowserWindow.java
new file mode 100644
index 0000000..16dc6cf
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITBrowserWindow.java
@@ -0,0 +1,45 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents the main browser window.
+ *
+ * You can retrieve the main browser window using
+ * iTunes.BrowserWindow().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+
+public class ITBrowserWindow extends ITWindow {
+
+ public ITBrowserWindow (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the kind of the object.
+ * @return Returns the kind of the object.
+ */
+ public boolean getMiniPlayer() {
+ return Dispatch.get(object, "MiniPlayer").getBoolean();
+ }
+
+ // TODO: Comments
+
+ public ITTrackCollection getSelectedTracks() {
+ Dispatch collection = Dispatch.call(object, "SelectedTracks").getDispatch();
+ return new ITTrackCollection(collection);
+ }
+
+ public ITPlaylist getSelectedPlaylist() {
+ Dispatch playlist = Dispatch.get(object, "SelectedPlaylist").toDispatch();
+ return new ITPlaylist(playlist);
+ }
+
+ public void setSelectedPlaylist(ITPlaylist playlist) {
+ Dispatch dispatchRef = playlist.fetchDispatch();
+ Dispatch.put(object, "SelectedPlaylist", dispatchRef);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITCOMDisabledReason.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITCOMDisabledReason.java
new file mode 100644
index 0000000..500280c
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITCOMDisabledReason.java
@@ -0,0 +1,12 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the reason the COM interface is being disabled.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITCOMDisabledReason {
+ ITCOMDisabledReasonOther,
+ ITCOMDisabledReasonDialog,
+ ITCOMDisabledReasonQuitting;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITEQPreset.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITEQPreset.java
new file mode 100644
index 0000000..1d00cfb
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITEQPreset.java
@@ -0,0 +1,236 @@
+package com.dt.iTunesController;
+
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an equalizer preset.
+ * You can retrieve or set the currently selected EQ preset using the
+ * iTunes.getCurrentEQPreset() method.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITEQPreset {
+
+ protected Dispatch object;
+
+ public ITEQPreset(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the name of the EQ Preset (e.g. "Acoustic").
+ * @return Returns the name of the EQ Preset (e.g. "Acoustic").
+ */
+ public String getName() {
+ return Dispatch.get(object, "Name").getString();
+ }
+
+ /**
+ * Returns true if the EQ preset can be modified.
+ * @return True if the EQ preset can be modified.
+ */
+ public boolean getModifiable() {
+ return Dispatch.get(object, "Modifiable").getBoolean();
+ }
+
+ /**
+ * Set the equalizer preamp level (-12.0 db to +12.0 db).
+ * @param level The new equalizer preamp level (-12.0 db to +12.0 db).
+ */
+ public void setPreamp(double level) {
+ Dispatch.put(object, "Preamp", level);
+ }
+
+ /**
+ * Returns the equalizer preamp level (-12.0db to +12.0db).
+ * @return Returns the equalizer preamp level (-12.0db to +12.0db).
+ */
+ public double getPreamp() {
+ return Dispatch.get(object, "Preamp").getDouble();
+ }
+
+ /**
+ * Set the equalizer 32Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 32Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand1(double level) {
+ Dispatch.put(object, "Band1", level);
+ }
+
+ /**
+ * Returns the equalizer 32Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 32Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand1() {
+ return Dispatch.get(object, "Band1").getDouble();
+ }
+
+ /**
+ * Set the equalizer 64Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 64Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand2(double level) {
+ Dispatch.put(object, "Band2", level);
+ }
+
+ /**
+ * Returns the equalizer 64Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 64Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand2() {
+ return Dispatch.get(object, "Band2").getDouble();
+ }
+
+ /**
+ * Set the equalizer 125Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 125Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand3(double level) {
+ Dispatch.put(object, "Band3", level);
+ }
+
+ /**
+ * Returns the equalizer 125Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 125Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand3() {
+ return Dispatch.get(object, "Band3").getDouble();
+ }
+
+ /**
+ * Set the equalizer 250Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 250Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand4(double level) {
+ Dispatch.put(object, "Band4", level);
+ }
+
+ /**
+ * Returns the equalizer 250Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 250Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand4() {
+ return Dispatch.get(object, "Band4").getDouble();
+ }
+
+ /**
+ * Set the equalizer 500Hz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 500Hz level (-12.0 db to +12.0db).
+ */
+ public void setBand5(double level) {
+ Dispatch.put(object, "Band5", level);
+ }
+
+ /**
+ * Returns the equalizer 500Hz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 500Hz level (-12.0 db to +12.0 db).
+ */
+ public double getBand5() {
+ return Dispatch.get(object, "Band5").getDouble();
+ }
+
+ /**
+ * Set the equalizer 1KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 1KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand6(double level) {
+ Dispatch.put(object, "Band6", level);
+ }
+
+ /**
+ * Returns the equalizer 1KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 1KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand6() {
+ return Dispatch.get(object, "Band6").getDouble();
+ }
+
+ /**
+ * Set the equalizer 2KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 2KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand7(double level) {
+ Dispatch.put(object, "Band7", level);
+ }
+
+ /**
+ * Returns the equalizer 2KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 2KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand7() {
+ return Dispatch.get(object, "Band7").getDouble();
+ }
+
+ /**
+ * Set the equalizer 4KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 4KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand8(double level) {
+ Dispatch.put(object, "Band8", level);
+ }
+
+ /**
+ * Returns the equalizer 4KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 4KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand8() {
+ return Dispatch.get(object, "Band8").getDouble();
+ }
+
+ /**
+ * Set the equalizer 8KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 8KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand9(double level) {
+ Dispatch.put(object, "Band9", level);
+ }
+
+ /**
+ * Returns the equalizer 8KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 8KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand9() {
+ return Dispatch.get(object, "Band9").getDouble();
+ }
+
+ /**
+ * Set the equalizer 16KHz level (-12.0 db to +12.0 db).
+ * @param level The new equalizer 16KHz level (-12.0 db to +12.0db).
+ */
+ public void setBand10(double level) {
+ Dispatch.put(object, "Band10", level);
+ }
+
+ /**
+ * Returns the equalizer 16KHz level (-12.0 db to +12.0 db).
+ * @return Returns the equalizer 16KHz level (-12.0 db to +12.0 db).
+ */
+ public double getBand10() {
+ return Dispatch.get(object, "Band10").getDouble();
+ }
+
+ /**
+ * Delete this EQ Preset.
+ * Any EQ preset can be deleted, including built-in presets, except for the
+ * Manual preset.
+ * @param updateAllTracks If true, any tracks that use this EQ preet will be
+ * set to have no assigned EQ preset.
+ */
+ public void delete(boolean updateAllTracks) {
+ Dispatch.call(object, "Delete", updateAllTracks);
+ }
+
+ /**
+ * Rename this EQ Preset.
+ * The name of any EQ preset can be changed, including built-in presets,
+ * except for the Manual preset.
+ * EQ preset names cannot start with leading spaces. If you specify a name
+ * that starts with leading spaces they will be stripped out.
+ * @param updateAllTracks If true, any tracks that use this EQ preet will be
+ * updated with the new preset name.
+ */
+ public void rename(String newName, boolean updateAllTracks) {
+ Dispatch.call(object, "Rename", newName, updateAllTracks);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITFileOrCDTrack.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITFileOrCDTrack.java
new file mode 100644
index 0000000..570896c
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITFileOrCDTrack.java
@@ -0,0 +1,39 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a file or CD track.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITFileOrCDTrack extends ITTrack {
+
+ public ITFileOrCDTrack (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Reveals the track in the main browser window.
+ */
+ public void reveal() {
+ Dispatch.call(object, "Reveal");
+ }
+
+ public ITVideoKind getVideoKind() {
+ return ITVideoKind.values()[Dispatch.get(object, "VideoKind").getInt()];
+ }
+
+ public ITRatingKind getRatingKind() {
+ return ITRatingKind.values()[Dispatch.get(object, "RatingKind").getInt()];
+ }
+
+ public String getLocation() {
+ return Dispatch.get(object, "Location").getString();
+ }
+
+ public ITArtworkCollection getArtworks() {
+ Dispatch artworks = Dispatch.get(object, "Artwork").toDispatch();
+ return new ITArtworkCollection(artworks);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITLibraryPlaylist.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITLibraryPlaylist.java
new file mode 100644
index 0000000..c19cba8
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITLibraryPlaylist.java
@@ -0,0 +1,20 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a library playlist.
+ *
+ * A library playlist consists of all the tracks in a user's library.
+ *
+ * For convenience, you can retrieve the main library playlist using
+ * iTunes.getLibraryPlaylist().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITLibraryPlaylist extends ITPlaylist {
+
+ public ITLibraryPlaylist(Dispatch d) {
+ super(d);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITObject.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITObject.java
new file mode 100644
index 0000000..27475fd
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITObject.java
@@ -0,0 +1,112 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Defines a source, playlist or track.
+ *
+ * An ITObject uniquely identifies a source, playlist, or track in iTunes using
+ * four separate IDs. These are runtime IDs, they are only valid while the
+ * current instance of iTunes is running.
+ *
+ * As of iTunes 7.7, you can also identify an ITObject using a 64-bit persistent
+ * ID, which is valid across multiple invocations of iTunes.
+ *
+ * The main use of the ITObject interface is to allow clients to track iTunes
+ * database changes using
+ * iTunesEventsInterface.onDatabaseChangedEvent().
+ *
+ * You can retrieve an ITObject with a specified runtime ID using
+ * iTunes.getITObjectByID().
+ *
+ * An ITObject will always have a valid, non-zero source ID.
+ *
+ * An ITObject corresponding to a playlist or track will always have a valid
+ * playlist ID. The playlist ID will be zero for a source.
+ *
+ * An ITObject corresponding to a track will always have a valid track and
+ * track database ID. These IDs will be zero for a source or playlist.
+ *
+ * A track ID is unique within the track's playlist. A track database ID is
+ * unique across all playlists. For example, if the same music file is in two
+ * different playlists, each of the tracks could have different track IDs, but
+ * they will have the same track database ID.
+ *
+ * An ITObject also has a 64-bit persistent ID which can be used to identify
+ * the ITObject across multiple invocations of iTunes.
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITObject {
+
+ protected Dispatch object;
+
+ public ITObject(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the JACOB Dispatch object for this object.
+ * @return Returns the JACOB Dispatch object for this object.
+ */
+ public Dispatch fetchDispatch() {
+ return object;
+ }
+
+ /**
+ * Set the name of the object.
+ * @param name The new name of the object.
+ */
+ public void setName (String name) {
+ Dispatch.put(object, "Name", name);
+ }
+
+ /**
+ * Returns the name of the object.
+ * @return Returns the name of the object.
+ */
+ public String getName() {
+ return Dispatch.get(object, "Name").getString();
+ }
+
+ /**
+ * Returns the index of the object in internal application order.
+ * @return The index of the object in internal application order.
+ */
+ public int getIndex() {
+ return Dispatch.get(object, "Index").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the source.
+ * @return Returns the ID that identifies the source.
+ */
+ public int getSourceID() {
+ return Dispatch.get(object, "SourceID").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the playlist.
+ * @return Returns the ID that identifies the playlist.
+ */
+ public int getPlaylistID() {
+ return Dispatch.get(object, "PlaylistID").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the track within the playlist.
+ * @return Returns the ID that identifies the track within the playlist.
+ */
+ public int getTrackID() {
+ return Dispatch.get(object, "TrackID").getInt();
+ }
+
+ /**
+ * Returns the ID that identifies the track, independent of its playlist.
+ * @return Returns the ID that identifies the track, independent of its playlist.
+ */
+ public int getTrackDatabaseID() {
+ return Dispatch.get(object, "TrackDatabaseID").getInt();
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITObjectPersistentID.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITObjectPersistentID.java
new file mode 100644
index 0000000..e5c674b
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITObjectPersistentID.java
@@ -0,0 +1,53 @@
+package com.dt.iTunesController;
+
+/**
+ * Simple utility wrapper class to represent the persistent object identity
+ * ID numbers. Use the getHigh() and getLow() methods individually to get
+ * each ID, or the combined hex string through toString().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITObjectPersistentID {
+
+ private long High;
+ private long Low;
+ private String hexString;
+
+ /**
+ * Create the ITObjectPersistentID. This class is not intended to be created
+ * manually, and this function should only be used by classes implementing
+ * this utility.
+ * @param high The High Persistent ID
+ * @param low The Low Persistent ID
+ */
+ public ITObjectPersistentID(long high, long low) {
+ this.High=high;
+ this.Low=low;
+ this.hexString = String.format("%8s%8s",Long.toHexString(this.High),Long.toHexString(this.Low)).toUpperCase().replace(' ','0');
+ }
+
+ /**
+ * Returns the high persistent ID.
+ * @return The high persistent ID.
+ */
+ public long getHigh() {
+ return this.High;
+ }
+
+ /**
+ * Returns the low persistent ID.
+ * @return The low persistent ID.
+ */
+ public long getLow() {
+ return this.Low;
+ }
+
+ /**
+ * Return a string representation (in hex) of the persistent IDs.
+ * @return String representation of the persistent IDs.
+ */
+ public String toString() {
+ return this.hexString;
+ }
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITOperationStatus.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITOperationStatus.java
new file mode 100644
index 0000000..cf764aa
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITOperationStatus.java
@@ -0,0 +1,62 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents the status of an asynchronous add or convert operation.
+ *
+ * When a track is added using TLibraryPlaylist.addFile(),
+ * ITLibraryPlaylist.AddFiles(), IITUserPlaylist.addFile(), or
+ * ITUserPlaylist.addFiles(), the add may not complete immediately if iTunes
+ * needs to make a copy of the file.
+ *
+ * Similarly, when converting or importing a file or track using
+ * iTunes.convertFile(), iTunes.convertFiles(),
+ * iTunes.convertTrack() or iTunes.convertTracks(),
+ * the conversion will never complete immediately.
+ *
+ * These methods return an ITOperationStatus object, which can be
+ * polled todetermine when the operation is done. This object will also return
+ * the collection of newly added or converted tracks.
+ *
+ * As of version 1.1 of the iTunes type library, you should use
+ * iTunes.convertFile2(), iTunes.convertFiles2(),
+ * iTunes.convertTrack2() or iTunes.convertTracks2()
+ * instead of the original convert methods. These new methods return an
+ * ITConvertOperationStatus object to allow clients to retrieve
+ * additional conversion progress information.
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITOperationStatus {
+
+ protected Dispatch object;
+
+ public ITOperationStatus(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns true if the operation is still in progress.
+ * You cannot retrieve the ITOperationStatus.getTracks()
+ * property until the operation completes.
+ * @return Returns true if the operation is still in progress.
+ */
+ public boolean getInProgress() {
+ return Dispatch.get(object, "InProgress").getBoolean();
+ }
+
+ /**
+ * Returns a collection containing the tracks that were generated by the
+ * operation.
+ * You cannot retrieve this property until
+ * ITOperationStatus.getInProgress() returns false
+ * @return Returns a collection containing the tracks that were generated by
+ * the operation.
+ */
+ public ITTrackCollection getTracks() {
+ Dispatch tracks = Dispatch.get(object, "Tracks").toDispatch();
+ return new ITTrackCollection(tracks);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlayerState.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlayerState.java
new file mode 100644
index 0000000..4be2a70
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlayerState.java
@@ -0,0 +1,13 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the state of the player.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlayerState {
+ ITPlayerStateStopped,
+ ITPlayerStatePlaying,
+ ITPlayerStateFastForward,
+ ITPlayerStateRewind;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylist.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylist.java
new file mode 100644
index 0000000..6c937cf
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylist.java
@@ -0,0 +1,180 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a playlist.
+ *
+ * A playlist is always associated with an ITSource.
+ *
+ * You can retrieve all the playlists defined for a source using
+ * ITSource.getPlaylists().
+ *
+ * For convenience, you can retrieve the main library playlist using
+ * iTunes.getLibraryPlaylist().
+ *
+ * You can create a new playlist using iTunes.createPlaylist().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITPlaylist extends ITObject {
+
+ public ITPlaylist (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Delete this object.
+ */
+ public void delete() {
+ Dispatch.call(object, "Delete");
+ }
+
+ /**
+ * Start playing the first track in this object.
+ */
+ public void playFirstTrack() {
+ Dispatch.call(object, "PlayFirstTrack");
+ }
+
+ /**
+ * Print this object.
+ * @param showPrintDialog If true, display the print dialog.
+ * @param printKind The printout kind.
+ * @param theme The name of the theme to use. This corresponds to the name
+ * of a Theme combo box item in the print dialog for the specified printKind
+ * (e.g. "Track length"). This string cannot be longer than 255 characters,
+ * but it may be empty.
+ */
+ public void print(boolean showPrintDialog, ITPlaylistPrintKind printKind, String theme) {
+ Dispatch.call(object, "Print", showPrintDialog, printKind.ordinal(), theme);
+ }
+
+ /**
+ * Returns a collection containing the tracks with the specified text.
+ * @param searchText The text to search for. This string cannot be longer
+ * than 255 chracters.
+ * @param searchFields Specifies which fields of each track should be
+ * searched for searchText.
+ * @return Collection of IITTrack objects. This will be NULL if no tracks
+ * meet the search criteria.
+ */
+ public ITTrackCollection search (String searchText, ITPlaylistSearchField searchFields) {
+ Dispatch collection = Dispatch.call(object, "Search", searchText, searchFields.ordinal()).getDispatch();
+ return new ITTrackCollection(collection);
+ }
+
+ /**
+ * Returns the kind of the object.
+ * @return Returns the kind of the object.
+ */
+ public ITPlaylistKind getKind() {
+ return ITPlaylistKind.values()[Dispatch.get(object, "Kind").getInt()];
+ }
+
+ /**
+ * Returns an ITSource object corresponding to the source that contains the
+ * object.
+ * @return Returns an ITSource object corresponding to the source that
+ * contains the object.
+ */
+ public ITSource getSource() {
+ Dispatch source = Dispatch.get(object, "Source").toDispatch();
+ return new ITSource(source);
+ }
+
+ /**
+ * Returns the total length of all songs in the object (in seconds).
+ * @return Returns the total length of all songs in the object (in
+ * seconds).
+ */
+ public int getDuration() {
+ return Dispatch.get(object, "Duration").getInt();
+ }
+
+ /**
+ * Set whether songs in the object should be played in random order.
+ * @param shouldShuffle True if songs in the object should be played in
+ * random order.
+ */
+ public void setShuffle(boolean shouldShuffle) {
+ Dispatch.put(object, "Shuffle", shouldShuffle);
+ }
+
+ /**
+ * Returns the total size of all songs in the object (in bytes).
+ * @return Returns the total size of all songs in the object (in bytes).
+ */
+ public double getSize() {
+ return Dispatch.get(object, "Size").getDouble();
+ }
+
+ /**
+ * Sets the playback repeat mode.
+ * @param repeatMode The new playback repeat mode.
+ */
+ public void setSongRepeat(ITPlaylistRepeatMode repeatMode) {
+ Dispatch.put(object, "SongRepeat", repeatMode.ordinal());
+ }
+
+ /**
+ * Cycle repeat modes.
+ */
+ public void cycleSongRepeat() {
+ int repeat = Dispatch.get(object, "SongRepeat").getInt();
+ Dispatch.put(object, "SongRepeat", (repeat + 1) % 3);
+ }
+
+ /**
+ * Returns the playback repeat mode.
+ * @return Returns the playback repeat mode.
+ */
+ public ITPlaylistRepeatMode getSongRepeat() {
+ return ITPlaylistRepeatMode.values()[Dispatch.get(object, "SongRepeat").getInt()];
+ }
+
+ /**
+ * Returns the total length of all songs in the object (in MM:SS format).
+ * @return Returns the total length of all songs in the object (in
+ * MM:SS format).
+ */
+ public String getTime() {
+ return Dispatch.get(object, "Time").getString();
+ }
+
+ /**
+ * Returns true if the object is visible in the sources list.
+ * @return True if the object is visible in the sources list.
+ */
+ public boolean getVisible() {
+ return Dispatch.get(object, "Visible").getBoolean();
+ }
+
+ /**
+ * Returns a collection containing the tracks in this object.
+ * @return Collection of ITTrack objects.
+ */
+ public ITTrackCollection getTracks() {
+ Dispatch tracks = Dispatch.get(object, "Tracks").toDispatch();
+ return new ITTrackCollection(tracks);
+ }
+
+ /**
+ * Returns the shuffle state.
+ * @return true if current state is shuffle.
+ */
+ public boolean getShuffle() {
+ return Dispatch.get(object, "Shuffle").getBoolean();
+ }
+
+ /**
+ * Toggle the shuffle state.
+ */
+ public void toggleShuffle() {
+ setShuffle(!getShuffle());
+ }
+
+ public boolean containsTrack(ITTrack track) {
+ return getTracks().containsTrack(track);
+ }
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistCollection.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistCollection.java
new file mode 100644
index 0000000..3717735
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistCollection.java
@@ -0,0 +1,67 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of playlist objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the playlists defined for a source using
+ * ITSource.getPlaylists().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITPlaylistCollection {
+
+ protected Dispatch object;
+
+ public ITPlaylistCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of playlists in the collection.
+ * @return Returns the number of playlists in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITPlaylist object corresponding to the given index (1-based).
+ * @param index Index of the playlist to retrieve, must be less than or
+ * equal to ITPlaylistCollection.getCount().
+ * @return Returns an ITPlaylist object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITPlaylist getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITPlaylist(item);
+ }
+
+ /**
+ * Returns an ITPlaylist object withthe specified name.
+ * @param name The name of the playlist to retrieve.
+ * @return Returns an ITPlaylist object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITPlaylist ItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITPlaylist(item);
+ }
+
+ /**
+ * Returns an ITPlaylist object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITPlaylist object with the specified persistent ID.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITPlaylist getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITPlaylist(item);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistKind.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistKind.java
new file mode 100644
index 0000000..e6f685f
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistKind.java
@@ -0,0 +1,15 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the playlist kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistKind {
+ ITPlaylistKindUnknown,
+ ITPlaylistKindLibrary,
+ ITPlaylistKindUser,
+ ITPlaylistKindCD,
+ ITPlaylistKindDevice,
+ ITPlaylistKindRadioTuner;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistPrintKind.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistPrintKind.java
new file mode 100644
index 0000000..6fc8ef8
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistPrintKind.java
@@ -0,0 +1,14 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the kind of playlist printout.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistPrintKind {
+
+ ITPlaylistPrintKindPlaylist,
+ ITPlaylistPrintKindAlbumlist,
+ ITPlaylistPrintKindInsert;
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistRepeatMode.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistRepeatMode.java
new file mode 100644
index 0000000..4b6fc16
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistRepeatMode.java
@@ -0,0 +1,14 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the playlist playback repeat mode.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistRepeatMode {
+
+ ITPlaylistRepeatModeOff,
+ ITPlaylistRepeatModeOne,
+ ITPlaylistRepeatModeAll;
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistSearchField.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistSearchField.java
new file mode 100644
index 0000000..420b305
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITPlaylistSearchField.java
@@ -0,0 +1,16 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the fields in each track that will be searched by
+ * ITPlaylist.search().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITPlaylistSearchField {
+ ITPlaylistSearchFieldAll,
+ ITPlaylistSearchFieldVisible,
+ ITPlaylistSearchFieldArtists,
+ ITPlaylistSearchFieldAlbums,
+ ITPlaylistSearchFieldComposers,
+ ITPlaylistSearchFieldSongNames;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITRatingKind.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITRatingKind.java
new file mode 100644
index 0000000..7d1cb22
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITRatingKind.java
@@ -0,0 +1,11 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the rating kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITRatingKind {
+ ITRatingKindUser,
+ ITRatingKindComputed;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSource.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSource.java
new file mode 100644
index 0000000..b0d93fc
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSource.java
@@ -0,0 +1,51 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an entry in the Source list (music library, CD, device, etc.).
+ * You can retrieve all the sources using iTunes.getSources().
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITSource extends ITObject {
+
+ public ITSource(Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the kind of the source.
+ * @return Returns the kind of the source.
+ */
+ public ITSourceKind getKind() {
+ return ITSourceKind.values()[Dispatch.get(object, "Kind").getInt()];
+ }
+
+ /**
+ * Returns the total size of the source, if it has a fixed size.
+ * @return Returns the total size of the source, if it has a fixed size.
+ */
+ public double getCapacity() {
+ return Dispatch.get(object, "Capacity").getDouble();
+ }
+
+ /**
+ * Returns the free space on the source, if it has a fixed size.
+ * @return Returns the free space on the source, if it has a fixed size.
+ */
+ public double getFreespace() {
+ return Dispatch.get(object, "Freespace").getDouble();
+ }
+
+ /**
+ * Returns a collection containing the playlists in this source.
+ * The source's primary playlist is always the first playlist in the
+ * collection.
+ * @return Collection of IITPlaylist objects.
+ */
+ public ITPlaylistCollection getPlaylists() {
+ Dispatch playlists = Dispatch.get(object, "Playlists").toDispatch();
+ return new ITPlaylistCollection(playlists);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSourceCollection.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSourceCollection.java
new file mode 100644
index 0000000..357bdec
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSourceCollection.java
@@ -0,0 +1,66 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of source objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the sources using ITSource.getSources().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITSourceCollection {
+
+ protected Dispatch object;
+
+ public ITSourceCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of sources in the collection.
+ * @return Returns the number of sources in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITSource object corresponding to the given index (1-based).
+ * @param index Index of the source to retrieve, must be less than or
+ * equal to ITSourceCollection.getCount().
+ * @return Returns an ITSource object corresponding to the given index.
+ * Will be set to NULL if no source could be retrieved.
+ */
+ public ITSource getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITSource(item);
+ }
+
+ /**
+ * Returns an ITSource object withthe specified name.
+ * @param name The name of the source to retrieve.
+ * @return Returns an ITSource object corresponding to the given index.
+ * Will be set to NULL if no source could be retrieved.
+ */
+ public ITSource getItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITSource(item);
+ }
+
+ /**
+ * Returns an ITSource object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITSource object with the specified persistent ID.
+ * Will be set to NULL if no source could be retrieved.
+ */
+ public ITSource getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITSource(item);
+ }
+
+}
\ No newline at end of file
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSourceKind.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSourceKind.java
new file mode 100644
index 0000000..f332249
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITSourceKind.java
@@ -0,0 +1,17 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the source kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITSourceKind {
+ ITSourceKindUnknown,
+ ITSourceKindLibrary,
+ ITSourceKindIPod,
+ ITSourceKindAudioCD,
+ ITSourceKindMP3CD,
+ ITSourceKindDevice,
+ ITSourceKindRadioTuner,
+ ITSourceKindSharedLibrary;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrack.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrack.java
new file mode 100644
index 0000000..57bb11b
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrack.java
@@ -0,0 +1,493 @@
+package com.dt.iTunesController;
+import java.util.Date;
+
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a track.
+ *
+ * A track represents a song in a single playlist. A song may be in more than
+ * one playlist, in which case it would be represented by multiple tracks.
+ *
+ * You can retrieve the currently targeted (playing) track using
+ * iTunes.getCurrentTrack().
+ *
+ * Typically, an ITrack is accessed through an ITTrackCollection.
+ *
+ * You can retrieve all the tracks defined for a playlist using
+ * ITPlaylist.getTracks().
+ *
+ * You can retrieve the currently selected track or tracks using
+ * iTunes.getSelectedTracks().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITTrack extends ITObject {
+
+ public ITTrack (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Delete this object.
+ */
+ public void delete() {
+ Dispatch.call(object, "Delete");
+ }
+
+ /**
+ * Start playing this object.
+ */
+ public void play() {
+ Dispatch.call(object, "Play");
+ }
+
+ /**
+ * Set the name of the album containing the object.;
+ * @param album The new name of the album containing the object.
+ */
+ public void setAlbum(String album) {
+ Dispatch.put(object, "Album", album);
+ }
+
+ /**
+ * Returns the name of the album containing the object.
+ * @return Returns the name of the album containing the object.
+ */
+ public String getAlbum() {
+ return Dispatch.get(object, "Album").getString();
+ }
+
+ /**
+ * Set the name of the artist/source of the object.
+ * @param artist The new artist/source of the object.
+ */
+ public void setArtist(String artist) {
+ Dispatch.put(object, "Artist", artist);
+ }
+
+ /**
+ * Returns the name of the artist/source of the object.
+ * @return Returns the name of the artist/source of the object.
+ */
+ public String getArtist() {
+ return Dispatch.get(object, "Artist").getString();
+ }
+
+ /**
+ * Returns the bit rate of the object (in kbps).
+ * @return Returns the bit rate of the object (in kbps).
+ */
+ public int getBitRate() {
+ return Dispatch.get(object, "BitRate").getInt();
+ }
+
+ /**
+ * Set the tempo of the object (in beats per minute).
+ * @param beatsPerMinute The new tempo of the object (in beats per minute).
+ */
+ public void setBPM(int beatsPerMinute) {
+ Dispatch.put(object, "BPM", beatsPerMinute);
+ }
+
+ /**
+ * Returns the tempo of the object (in beats per minute).
+ * @return Returns the tempo of the object (in beats per minute).
+ */
+ public int getBPM() {
+ return Dispatch.get(object, "BPM").getInt();
+ }
+
+ /**
+ * Set freeform notes about the object.
+ * @param comment The new freeform notes about the object.
+ */
+ public void setComment(String comment) {
+ Dispatch.put(object, "Comment", comment);
+ }
+
+ /**
+ * Returns freeform notes about the object.
+ * @return Returns freeform notes about the object.
+ */
+ public String getComment() {
+ return Dispatch.get(object, "Comment").getString();
+ }
+
+ /**
+ * Set whether this object is from a compilation album.
+ * @param isCompilation True if this object should be from a compilation album.
+ */
+ public void setCompilation(boolean isCompilation) {
+ Dispatch.put(object, "Compilation", isCompilation);
+ }
+
+ /**
+ * Returns true if this object is from a compilation album.
+ * @return Returns true if this object is from a compilation album.
+ */
+ public boolean getCompilation() {
+ return Dispatch.get(object, "Compilation").getBoolean();
+ }
+
+ /**
+ * Set the composer of the object.
+ * @param composer The new composer of the object.
+ */
+ public void setComposer (String composer) {
+ Dispatch.put(object, "Composer", composer);
+ }
+
+ /**
+ * Returns the composer of the object.
+ * @return Returns the composer of the object.
+ */
+ public String getComposer() {
+ return Dispatch.get(object, "Composer").getString();
+ }
+
+ /**
+ * Returns the date the object was added to the playlist.
+ * @return Returns the date the object was added to the playlist.
+ */
+ public Date getDateAdded() {
+ return Dispatch.get(object, "DateAdded").getJavaDate();
+ }
+
+ /**
+ * Set the total number of discs in the source album.
+ * @param discCount The new total number of discs in the source album.
+ */
+ public void setDiscCount (int discCount) {
+ Dispatch.put(object, "DiscCount", discCount);
+ }
+
+ /**
+ * Returns the total number of discs in the source album.
+ * @return Returns the total number of discs in the source album.
+ */
+ public int getDiscCount() {
+ return Dispatch.get(object, "DiscCount").getInt();
+ }
+
+ /**
+ * Set the index of the disc containing the object on the source album.
+ * @param discNumber The new index of the disc containing the object on the
+ * source album.
+ */
+ public void setDiscNumber (int discNumber) {
+ Dispatch.put(object, "DiscNumber", discNumber);
+ }
+
+ /**
+ * Returns the index of the disc containing the object on the source album.
+ * @return Returns the index of the disc containing the object on the source
+ * album.
+ */
+ public int getDiscNumber() {
+ return Dispatch.get(object, "DiscNumber").getInt();
+ }
+
+ /**
+ * Returns the length of the object (in seconds).
+ * @return Returns the length of the object (in seconds).
+ */
+ public int getDuration() {
+ return Dispatch.get(object, "Duration").getInt();
+ }
+
+ /**
+ * Set whether this object is checked for playback.
+ * @param shouldBeEnabled True if the object should be checked for playback.
+ */
+ public void setEnabled (boolean shouldBeEnabled) {
+ Dispatch.put(object, "Enabled", shouldBeEnabled);
+ }
+
+ /**
+ * Returns true if the object is checked for playback.
+ * @return Returns true if the object is checked for playback.
+ */
+ public boolean getEnabled() {
+ return Dispatch.get(object, "Enabled").getBoolean();
+ }
+
+ /**
+ * Set the name of the EQ preset of the object.
+ * @param eq The new name of the EQ preset of the object.
+ */
+ public void setEQ (String eq) {
+ Dispatch.put(object, "EQ", eq);
+ }
+
+ /**
+ * Returns the name of the EQ preset of the object.
+ * @return Returns the name of the EQ preset of the object.
+ */
+ public String getEQ() {
+ return Dispatch.get(object, "EQ").getString();
+ }
+
+ /**
+ * Set the stop time of the object (in seconds).
+ * @param finish The new stop time of the object (in seconds).
+ */
+ public void setFinish(int finish) {
+ Dispatch.put(object, "Finish", finish);
+ }
+
+ /**
+ * Returns the stop time of the object (in seconds).
+ * @return Returns the stop time of the object (in seconds).
+ */
+ public int getFinish() {
+ return Dispatch.get(object, "Finish").getInt();
+ }
+
+ /**
+ * Returns the music/audio genre (category) of the object.
+ * @param genre Returns the music/audio genre (category) of the object.
+ */
+ public void setGenre(String genre) {
+ Dispatch.put(object, "Genre", genre);
+ }
+
+ /**
+ * Set the music/audio genre (category) of the object.
+ * @return The new music/audio genre (category) of the object.
+ */
+ public String getGenre() {
+ return Dispatch.get(object, "Genre").getString();
+ }
+
+ /**
+ * Set the grouping (piece) of the object.
+ * Generally used to denote movements within classical work.
+ * @param grouping The new grouping (piece) of the object.
+ */
+ public void setGrouping (String grouping) {
+ Dispatch.put(object, "Grouping", grouping);
+ }
+
+ /**
+ * Returns the grouping (piece) of the object.
+ * Generally used to denote movements within classical work.
+ * @return Returns the grouping (piece) of the object.
+ */
+ public String getGrouping() {
+ return Dispatch.get(object, "Grouping").getString();
+ }
+
+ public ITTrackKind getKind() {
+ return ITTrackKind.values()[Dispatch.get(object, "Kind").getInt()];
+ }
+
+ /**
+ * Returns the text description of the object (e.g. "AAC audio file").
+ * @return Returns the text description of the object (e.g. "AAC audio file").
+ */
+ public String getKindAsString() {
+ return Dispatch.get(object, "KindAsString").getString();
+ }
+
+ /**
+ * Returns the modification date of the content of the object.
+ * @return Returns the modification date of the content of the object.
+ */
+ public Date getModificationDate() {
+ return Dispatch.get(object, "ModificationDate").getJavaDate();
+ }
+
+ /**
+ * Set the number of times the object has been played. This property cannot
+ * be set if the object is not playable (e.g. a PDF file).
+ * @param playedCount The new number of times the object has been played.
+ */
+ public void setPlayedCount (int playedCount) {
+ Dispatch.put(object, "PlayedCount", playedCount);
+ }
+
+ /**
+ * Returns the number of times the object has been played.
+ * @return Returns the number of times the object has been played.
+ */
+ public int getPlayedCount() {
+ return Dispatch.get(object, "PlayedCount").getInt();
+ }
+
+ /**
+ * Set the date and time the object was last played. This property cannot be
+ * set if the object is not playable (e.g. a PDF file).
+ * A value of zero means no played date.
+ * @param playedDate The new date and time the object was last played.
+ */
+ public void setPlayedDate (Date playedDate) {
+ Dispatch.put(object, "PlayedDate", playedDate);
+ }
+
+ /**
+ * Returns the date and time the object was last played.
+ * A value of zero means no played date.
+ * @return Returns the date and time the object was last played.
+ */
+ public Date getPlayedDate() {
+ return Dispatch.get(object, "PlayedDate").getJavaDate();
+ }
+
+ /**
+ * Returns an ITPlaylist object corresponding to the playlist that contains
+ * the object. Use ITFileOrCDTrack::Playlists() or IITURLTrack::Playlists()
+ * to get the collection of all playlists that contain the song this object
+ * represents.
+ * @return Returns an ITPlaylist object corresponding to the playlist that
+ * contains the object.
+ */
+ public ITPlaylist getPlaylist() {
+ Dispatch playlist = Dispatch.get(object, "Playlist").toDispatch();
+ return new ITPlaylist(playlist);
+ }
+
+ /**
+ * Returns the play order index of the object in the owner playlist
+ * (1-based).
+ * You can pass this index to IITTrackCollection::ItemByPlayOrder() for the
+ * collection returned by ITPlaylist::Tracks() to retrieve an ITTrack
+ * object corresponding to this object.
+ * @return Returns the play order index of the object in the owner playlist.
+ */
+ public int getPlayOrderIndex() {
+ return Dispatch.get(object, "PlayOrderIndex").getInt();
+ }
+
+ /**
+ * Set the rating of the object (0 to 100). If the object rating is set to 0,
+ * it will be computed based on the album rating.
+ * @param rating The new rating of the object (0 to 100).
+ */
+ public void setRating (int rating) {
+ Dispatch.put(object, "Rating", rating);
+ }
+
+ /**
+ * Returns the rating of the object (0 to 100). If the object rating has never
+ * been set, or has been set to 0, it will be computed based on the album
+ * rating.
+ * @return Returns the rating of the object (0 to 100).
+ */
+ public int getRating() {
+ return Dispatch.get(object, "Rating").getInt();
+ }
+
+ /**
+ * Returns the sample rate of the object (in Hz).
+ * @return Returns the sample rate of the object (in Hz).
+ */
+ public int getSampleRate() {
+ return Dispatch.get(object, "SampleRate").getInt();
+ }
+
+ /**
+ * Returns the size of the object (in bytes).
+ * @return Returns the size of the object (in bytes).
+ */
+ public int getSize() {
+ return Dispatch.get(object, "Size").getInt();
+ }
+
+ /**
+ * Set the start time of the object (in seconds).
+ * @param start The new start time of the object (in seconds).
+ */
+ public void setStart (int start) {
+ Dispatch.put(object, "Start", start);
+ }
+
+ /**
+ * Returns the start time of the object (in seconds).
+ * @return Returns the start time of the object (in seconds).
+ */
+ public int getStart() {
+ return Dispatch.get(object, "Start").getInt();
+ }
+
+ /**
+ * Returns the length of the object (in MM:SS format).
+ * @return Returns the length of the object (in MM:SS format).
+ */
+ public String getTime() {
+ return Dispatch.get(object, "Time").getString();
+ }
+
+ /**
+ * Set the total number of tracks on the source album.
+ * @param trackCount The new total number of tracks on the source album.
+ */
+ public void setTrackCount (int trackCount) {
+ Dispatch.put(object, "TrackCount", trackCount);
+ }
+
+ /**
+ * Returns the total number of tracks on the source album.
+ * @return Returns the total number of tracks on the source album.
+ */
+ public int getTrackCount() {
+ return Dispatch.get(object, "TrackCount").getInt();
+ }
+
+ /**
+ * Set the index of the object on the source album.
+ * @param trackNumber The new index of the object on the source album.
+ */
+ public void setTrackNumber (int trackNumber) {
+ Dispatch.put(object, "TrackNumber", trackNumber);
+ }
+
+ /**
+ * Returns the index of the object on the source album.
+ * @return Returns the index of the object on the source album.
+ */
+ public int getTrackNumber() {
+ return Dispatch.get(object, "TrackNumebr").getInt();
+ }
+
+ /**
+ * Set the relative volume adjustment of the object (-100% to 100%).
+ * @param volumeAdjustment Set the relative volume adjustment of the object
+ * (-100% to 100%).
+ */
+ public void setVolumeAdjustment (int volumeAdjustment) {
+ Dispatch.put(object, "VolumeAdjustment", volumeAdjustment);
+ }
+
+ /**
+ * Returns the relative volume adjustment of the object (-100% to 100%).
+ * @return Returns the relative volume adjustment of the object (-100% to 100%).
+ */
+ public int getVolumeAdjustment() {
+ return Dispatch.get(object, "VolumeAdjustment").getInt();
+ }
+
+ /**
+ * Set the year the object was recorded/released.
+ * @param year The new year the object was recorded/released.
+ */
+ public void setYear (int year) {
+ Dispatch.put(object, "Year", year);
+ }
+
+ /**
+ * Returns the year the object was recorded/released.
+ * @return Returns the year the object was recorded/released.
+ */
+ public int getYear() {
+ return Dispatch.get(object, "Year").getInt();
+ }
+
+ public ITArtworkCollection getArtwork() {
+ Dispatch art = Dispatch.get(object, "Artwork").toDispatch();
+ return new ITArtworkCollection(art);
+
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrackCollection.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrackCollection.java
new file mode 100644
index 0000000..3e1f3bf
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrackCollection.java
@@ -0,0 +1,99 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of track objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the tracks defined for a playlist using
+ * ITPlaylist.getTracks().
+ *
+ * You can retrieve the currently selected track or tracks using
+ * iTunes.getSelectedTracks().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITTrackCollection {
+
+ protected Dispatch object;
+
+ public ITTrackCollection(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the number of tracks in the collection.
+ * @return Returns the number of tracks in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITTrack object corresponding to the given index (1-based).
+ * @param index Index of the track to retrieve, must be less than or
+ * equal to ITTrackCollection.getCount().
+ * @return Returns an ITTrack object corresponding to the given index.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ ITTrack track = new ITTrack(item);
+ if (track.getKind()==ITTrackKind.ITTrackKindFile) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindCD) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindURL ) {
+ return new ITURLTrack(item);
+ } else {
+ return track;
+ }
+ }
+
+ /**
+ * Returns an ITTrack object corresponding to the given index (1-based).
+ * @param index Index of the track to retrieve, must be less than or
+ * equal to ITTrackCollection.getCount().
+ * @return Returns an ITTrack object corresponding to the given index.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack getItemByPlayOrder(int index) {
+ Dispatch item = Dispatch.call(object, "ItemByPlayOrder", index).toDispatch();
+ return new ITTrack(item);
+ }
+
+ /**
+ * Returns an ITTrack object withthe specified name.
+ * @param name The name of the track to retrieve.
+ * @return Returns an ITTrack object corresponding to the given index.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack ItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITTrack(item);
+ }
+
+ /**
+ * Returns an ITTrack object with the specified persistent ID. See the
+ * documentation on ITObject for more information on persistent IDs.
+ * @param highID The high 32 bits of the 64-bit persistent ID.
+ * @param lowID The low 32 bits of the 64-bit persistent ID.
+ * @return Returns an ITTrack object with the specified persistent ID.
+ * Will be set to NULL if no track could be retrieved.
+ */
+ public ITTrack getItemByPersistentID (int highID, int lowID) {
+ Dispatch item = Dispatch.call(object, "ItemByPersistentID", highID, lowID).toDispatch();
+ return new ITTrack(item);
+ }
+
+ public boolean containsTrack(ITTrack track) {
+ String name = track.getName();
+ try {
+ return ItemByName(name).getName().equals(name);
+ } catch (IllegalStateException e) {
+ return false;
+ }
+ }
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrackKind.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrackKind.java
new file mode 100644
index 0000000..ec233a1
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITTrackKind.java
@@ -0,0 +1,15 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the track kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITTrackKind {
+ ITTrackKindUnknown,
+ ITTrackKindFile,
+ ITTrackKindCD,
+ ITTrackKindURL,
+ ITTrackKindDevice,
+ ITTrackKindSharedLibrary;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITURLTrack.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITURLTrack.java
new file mode 100644
index 0000000..9829190
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITURLTrack.java
@@ -0,0 +1,175 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a URL track.
+ *
+ * A URL track references a network audio stream.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITURLTrack extends ITTrack {
+
+ public ITURLTrack (Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Returns the URL of the stream represented by this track.
+ * @return The URL of the stream represented by this track.
+ */
+ public String getURL () {
+ return Dispatch.get(object, "URL").getString();
+ }
+
+ /**
+ * Set the URL of the stream represented by this track.
+ * @param url The URL of the stream represented by this track.
+ */
+ public void setURL (String url) {
+ Dispatch.call(object, "URL", url);
+ }
+
+ /**
+ * Returns true if this track is a podcast track. If a podcast track is an
+ * IITURLTrack, the podcast episode has not been downloaded.
+ * @return Returns true if this track is a podcast track.
+ */
+ public boolean isPodcast () {
+ return Dispatch.get(object, "Podcast").getBoolean();
+ }
+
+ /**
+ * Returns the category for the track.
+ * @return Returns the category for the track.
+ */
+ public String getCategory () {
+ return Dispatch.get(object, "Category").getString();
+ }
+
+ /**
+ * Sets the category for the track.
+ * @param category Sets the category for the track.
+ */
+ public void setCategory (String category) {
+ Dispatch.call(object, "Category", category);
+ }
+
+ /**
+ * Returns the description for the track.
+ * @return Returns the description for the track.
+ */
+ public String getDescription () {
+ return Dispatch.get(object, "Description").getString();
+ }
+
+ /**
+ * Sets the description for the track.
+ * @param description The new description for the track.
+ */
+ public void setDescription (String description) {
+ Dispatch.call(object, "Description", description);
+ }
+
+ /**
+ * Returns the long description for the track.
+ * @return Returns the description for the track.
+ */
+ public String getLongDescription () {
+ return Dispatch.get(object, "LongDescription").getString();
+ }
+
+ /**
+ * Sets the long description for the track.
+ * @param longDescription The new long description for the track.
+ */
+ public void setLongDescription (String longDescription) {
+ Dispatch.call(object, "LongDescription", longDescription);
+ }
+
+ /**
+ * Returns the user or computed rating of the album that this track belongs
+ * to (0 to 100). If the album rating has never been set, or has been set to
+ * 0, it will be computed based on the ratings of tracks in the album.
+ * @return Returns the album rating of the album that this track belongs to (0 to 100).
+ */
+ public long getAlbumRating () {
+ return Dispatch.get(object, "AlbumRating").getLong();
+ }
+
+ /**
+ * Set the album rating of the album that this track belongs to (0 to 100).
+ * If the album rating is set to 0, it will be computed based on the ratings
+ * of tracks in the album.
+ * @param albumRating The new album rating of the album that this track
+ * belongs to (0 to 100). If rating is outside this range, it will be
+ * pinned.
+ */
+ public void setAlbumRating (long albumRating) {
+ Dispatch.call(object, "AlbumRating", albumRating);
+ }
+
+ /**
+ * Returns the album rating kind. If the album rating has never been set, or
+ * has been set to 0, the kind is ITRatingKindComputed. Otherwise, the kind
+ * is ITRatingKindUser.
+ * @return Returns the album rating kind.
+ */
+ public ITRatingKind getAlbumRatingKind () {
+ return ITRatingKind.values()[Dispatch.get(object, "AlbumRatingKind").getInt()];
+ }
+
+ /**
+ * Returns the track rating kind. If the track rating has never been set, or
+ * has been set to 0, the kind is ITRatingKindComputed. Otherwise, the kind
+ * is ITRatingKindUser.
+ * @return Returns the track rating kind.
+ */
+ public ITRatingKind getRatingKind () {
+ return ITRatingKind.values()[Dispatch.get(object, "RatingKind").getInt()];
+ }
+
+ /**
+ * Returns a collection of playlists that contain the song that this track
+ * represents.
+ *
+ * This is the same collection of playlists that are shown in the "Show in
+ * Playlist" contextual menu for a track, plus the specific playlist that
+ * contains this track.
+ *
+ * A track represents a song in a single playlist, use
+ * ITTrack.getPlaylist() to get the specific playlist that
+ * contains this track.
+ * @return Collection of ITPlaylist objects.
+ */
+ public ITPlaylistCollection getPlaylists () {
+ Dispatch playlists = Dispatch.get(object, "Playlists").toDispatch();
+ return new ITPlaylistCollection(playlists);
+ }
+
+ /**
+ * Update the podcast feed for this track. This is equivalent to the user
+ * choosing Update Podcast from the contextual menu for the podcast feed
+ * that contains this track.
+ */
+ public void updatePodcastFeed () {
+ Dispatch.call(object, "UpdatePodcastFeed");
+ }
+
+ /**
+ * Start downloading the podcast episode that corresponds to this track.
+ * This is equivalent to the user clicking the Get button next to this
+ * track.
+ */
+ public void downloadPodcastEpisode () {
+ Dispatch.call(object, "DownloadPodcastEpisode");
+ }
+
+ /**
+ * Reveals the track in the main browser window.
+ */
+ public void reveal() {
+ Dispatch.call(object, "Reveal");
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITUserPlaylist.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITUserPlaylist.java
new file mode 100644
index 0000000..b4025cf
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITUserPlaylist.java
@@ -0,0 +1,60 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a user-defined playlist.
+ *
+ * A user playlist includes both smart and manual user-defined playlists.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITUserPlaylist extends ITPlaylist {
+
+ public ITUserPlaylist(Dispatch d) {
+ super(d);
+ }
+
+ /**
+ * Add a file or files inside a folder to the playlist.
+ * You cannot use this method to add a file that requires conversion to be
+ * added (e.g. a CD track), use iTunes.convertFile() or
+ * iTunes.convertFile2() instead. If you add a folder that
+ * contains files that require conversion, they will be skipped.
+ * @param filePath The full path to the file or folder to add.
+ * @return Returns an ITOperationStatus object corresponding to the
+ * asynchronous operation. If an error occurs, or no files were added, this
+ * will be set to NULL.
+ */
+ public ITOperationStatus addFile (String filePath) {
+ Dispatch status = Dispatch.call(object, "AddFile", filePath).toDispatch();
+ return new ITOperationStatus(status);
+ }
+
+ /**
+ * Add a streaming audio URL to the playlist.
+ * @param url The URL to add. The length of the URL can be 255 characters or
+ * less.
+ * @return Returns an ITURLTrack object corresponding to the new track.
+ */
+ public ITURLTrack addURL (String url) {
+ Dispatch URLTrack = Dispatch.call(object, "AddURL", url).toDispatch();
+ return new ITURLTrack(URLTrack);
+ }
+
+ /**
+ * Add an existing track to the playlist.
+ * You cannot use this method to add a CD track (ITTrackKindCD) to another
+ * playlist, use iTunes.convertTrack() or
+ * iTunes.convertTrack2() instead.
+ * You cannot add a shared library track (ITTrackKindSharedLibrary) to
+ * another playlist.
+ * @param track The track to add.
+ * @return Returns an IITTrack object corresponding to the new track.
+ */
+ public ITTrack addTrack (ITTrack track) {
+ Dispatch trackToAdd = track.fetchDispatch();
+ Dispatch addedTrack = Dispatch.call(object, "AddTrack", trackToAdd).toDispatch();
+ return new ITTrack(addedTrack);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITVideoKind.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITVideoKind.java
new file mode 100644
index 0000000..d318724
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITVideoKind.java
@@ -0,0 +1,13 @@
+package com.dt.iTunesController;
+
+/**
+ * Specifies the Video kind.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public enum ITVideoKind {
+ ITVideoKindNone,
+ ITVideoKindMovie,
+ ITVideoKindMusicVideo,
+ ITVideoKindTVShow;
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITWindow.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITWindow.java
new file mode 100644
index 0000000..4af825f
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITWindow.java
@@ -0,0 +1,32 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents an iTunes window.
+ */
+
+public class ITWindow {
+
+ protected Dispatch object;
+
+ public ITWindow(Dispatch d) {
+ object = d;
+ }
+
+ /**
+ * Returns the JACOB Dispatch object for this object.
+ * @return Returns the JACOB Dispatch object for this object.
+ */
+ public Dispatch fetchDispatch() {
+ return object;
+ }
+
+ /**
+ * Returns the name of the object.
+ * @return Returns the name of the object.
+ */
+ public String getName() {
+ return Dispatch.get(object, "Name").getString();
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/ITWindowCollection.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITWindowCollection.java
new file mode 100644
index 0000000..df1f3cf
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/ITWindowCollection.java
@@ -0,0 +1,55 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+
+/**
+ * Represents a collection of window objects.
+ *
+ * Note that collection indices are always 1-based.
+ *
+ * You can retrieve all the windows using
+ * iTunes.getWindows().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class ITWindowCollection {
+
+ protected Dispatch object;
+
+ public ITWindowCollection(Dispatch d) {
+ object = d;
+ }
+
+ // TODO: iTunes.getWindows()
+
+ /**
+ * Returns the number of playlists in the collection.
+ * @return Returns the number of playlists in the collection.
+ */
+ public int getCount() {
+ return Dispatch.get(object, "Count").getInt();
+ }
+
+ /**
+ * Returns an ITWindow object corresponding to the given index (1-based).
+ * @param index Index of the playlist to retrieve, must be less than or
+ * equal to ITWindowCollection.getCount().
+ * @return Returns an ITWindow object corresponding to the given index.
+ * Will be set to NULL if no playlist could be retrieved.
+ */
+ public ITWindow getItem (int index) {
+ Dispatch item = Dispatch.call(object, "Item", index).toDispatch();
+ return new ITWindow(item);
+ }
+ /**
+ * Returns an ITWindow object with the specified name.
+ * @param name The name of the window to retrieve.
+ * @return Returns an ITWindow object corresponding to the given index.
+ * Will be set to NULL if no ITWindow could be retrieved.
+ */
+ public ITWindow ItemByName (String name) {
+ Dispatch item = Dispatch.call(object, "ItemByName", name).toDispatch();
+ return new ITWindow(item);
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunes.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunes.java
new file mode 100644
index 0000000..6a54d07
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunes.java
@@ -0,0 +1,539 @@
+package com.dt.iTunesController;
+
+import com.jacob.activeX.ActiveXComponent;
+import com.jacob.com.ComThread;
+import com.jacob.com.Dispatch;
+import com.jacob.com.DispatchEvents;
+
+/**
+ * Defines the top-level iTunes application object.
+ *
+ * This interface defines the top-level iTunes application object. All other
+ * iTunes interfaces are accessed through this object.
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class iTunes {
+ ActiveXComponent iTunes;
+ iTunesEvents iTunesEvents;
+ DispatchEvents dispatchEvents;
+
+ /**
+ * Initiate iTunes Controller.
+ * @return
+ */
+ public void connect() {
+ iTunes = new ActiveXComponent("iTunes.Application");
+ }
+
+ /**
+ * Add an event handler to the iTunes controller.
+ * @param itef The class that will handle the iTunes events.
+ */
+ public void addEventHandler(iTunesEventsInterface itef) {
+ iTunesEvents = new iTunesEvents(itef);
+ dispatchEvents = new DispatchEvents(iTunes, iTunesEvents);
+ //System.out.println("New event handler added.");
+ }
+
+ /**
+ * Reposition to the beginning of the current track or go to the previous
+ * track if already at start of current track.
+ */
+ public void backTrack() {
+ iTunes.invoke("BackTrack");
+ }
+
+ /**
+ * Skip forward in a playing track.
+ */
+ public void fastForward() {
+ iTunes.invoke("FastForward");
+ }
+
+ /**
+ * Advance to the next track in the current playlist.
+ */
+ public void nextTrack() {
+ iTunes.invoke("NextTrack");
+ }
+
+ /**
+ * Pause playback.
+ */
+ public void pause() {
+ iTunes.invoke("Pause");
+ }
+
+ /**
+ * Play the currently targeted track.
+ */
+ public void play() {
+ iTunes.invoke("ASDSDPlay");
+ }
+
+ /**
+ * Play the specified file path, adding it to the library if not already
+ * present.
+ */
+ public void playFile(String filePath) {
+ iTunes.invoke("PlayFile", filePath);
+ }
+
+ /**
+ * Toggle the playing/paused state of the current track.
+ */
+ public void playPause() {
+ iTunes.invoke("PlayPause");
+ }
+
+ /**
+ * Return to the previous track in the current playlist.
+ */
+ public void previousTrack() {
+ iTunes.invoke("PreviousTrack");
+ }
+
+ /**
+ * Disable fast forward/rewind and resume playback, if playing.
+ */
+ public void resume() {
+ iTunes.invoke("Resume");
+ }
+
+ /**
+ * Skip backwards in a playing track.
+ */
+ public void rewind() {
+ iTunes.invoke("Rewind");
+ }
+
+ /**
+ * Stop playback.
+ */
+ public void stop() {
+ iTunes.invoke("Stop");
+ }
+
+ /**
+ * Retrieves the current state of the player buttons in the window
+ * containing the currently targeted track. If there is no currently
+ * targeted track, returns the current state of the player buttons
+ * in the main browser window.
+ */
+ public void getPlayerButtonsState(boolean previousEnabled,
+ String playPause, boolean nextEnabled) {
+
+ }
+
+ /**
+ * Returns true if this version of the iTunes type library is compatible
+ * with the specified version.
+ * @param majorVersion Major version of iTunes interface.
+ * @param minorVersion Minor version of iTunes interface.
+ * @return Returns true if this version is compatible with the indicated
+ * interface version.
+ */
+ public boolean getCheckVersion (int majorVersion, int minorVersion) {
+ return iTunes.invoke("CheckVersion", majorVersion, minorVersion).getBoolean();
+ }
+
+ /**
+ * Returns an IITObject corresponding to the specified IDs.
+ * The object may be a source, playlist, or track.
+ * @param sourceID The ID that identifies the source. Valid for a source,
+ * playlist, or track.
+ * @param playlistID The ID that identifies the playlist. Valid for a
+ * playlist or track. Must be zero for a source.
+ * @param trackID The ID that identifies the track within the playlist.
+ * Valid for a track. Must be zero for a source or playlist.
+ * @param databaseID The ID that identifies the track, independent of its
+ * playlist. Valid for a track. Must be zero for a source or playlist.
+ * @return Returns an IITObject object corresponding to the specified IDs.
+ * Will be set to NULL if no object could be retrieved.
+ */
+ public ITObject getITObjectByID(int sourceID, int playlistID, int trackID, int databaseID) {
+ Dispatch object = Dispatch.call(iTunes, "GetITObjectByID", sourceID, playlistID, trackID, databaseID).toDispatch();
+ return new ITObject(object);
+ }
+
+ /**
+ * Creates a new playlist in the main library.
+ * @param playlistName The name of the new playlist (may be empty).
+ * @return Returns an ITPlaylist object corresponding to the new playlist.
+ */
+ public ITPlaylist createPlaylist(String playlistName) {
+ Dispatch cplaylist = Dispatch.call(iTunes, "CreatePlaylist", playlistName).toDispatch();
+ ITPlaylist playlist = new ITPlaylist(cplaylist);
+ ITPlaylistKind playlistKind = playlist.getKind();
+ if (playlistKind == ITPlaylistKind.ITPlaylistKindCD)
+ return new ITAudioCDPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindLibrary)
+ return new ITLibraryPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindUser)
+ return new ITUserPlaylist(cplaylist);
+ else
+ return playlist;
+ }
+
+ /**
+ * Open the specified iTunes Store or streaming audio URL.
+ * @param url The URL to open. The length of the URL cannot exceed 512
+ * characters. iTunes Store URLs start with itms:// or itmss://. Streaming
+ * audio URLs start with http://.
+ */
+ public void openURL (String url) {
+ iTunes.invoke("OpenURL", url);
+ }
+
+ /**
+ * Go to the iTunes Store home page.
+ */
+ public void gotoMusicStoreHomePage() {
+ iTunes.invoke("GoToMusicStoreHomePage");
+ }
+
+ /**
+ * Update the contents of the iPod.
+ */
+ public void updateIPod() {
+ iTunes.invoke("UpdateIPod");
+ }
+
+ /**
+ * Exits the iTunes application.
+ */
+ public void quit() {
+ iTunes.invoke("Quit");
+ }
+
+ /**
+ * Creates a new EQ preset.
+ * The EQ preset will be created "flat", i.e. the preamp and all band levels
+ * will be set to 0.
+ * EQ preset names cannot start with leading spaces. If you specify a name
+ * that starts with leading spaces they will be stripped out.
+ * If eqPresetName is empty, the EQ preset will be created with
+ * a default name.
+ * @param eqPresetName The name of the new EQ Preset (may be empty)
+ * @return Returns an ITEQPreset object corresponding to the new EQ Preset.
+ */
+ public ITEQPreset createEQPreset(String eqPresetName) {
+ Dispatch eqPreset = Dispatch.call(iTunes, "CreateEQPreset", eqPresetName).toDispatch();
+ return new ITEQPreset(eqPreset);
+ }
+
+ /**
+ * Creates a new playlist in an existing source.
+ * You may not be able to create a playlist in every source. For example,
+ * you cannot create a playlist in an audio CD source, or in an iPod source
+ * if it is in auto update mode.
+ * If playlistName is empty, the playlist will be created with
+ * a default name.
+ * @param playlistName The name of the new playlist (may be empty).
+ * @param source The source that will contain the new playlist.
+ * @return Returns an ITPlaylist object corresponding to the new playlist.
+ */
+ public ITPlaylist createPlaylistInSource(String playlistName, ITSource source) {
+ Dispatch cplaylist = Dispatch.call(iTunes, "CreatePlaylistInSource", playlistName, source.fetchDispatch()).toDispatch();
+ ITPlaylist playlist = new ITPlaylist(cplaylist);
+ ITPlaylistKind playlistKind = playlist.getKind();
+ if (playlistKind == ITPlaylistKind.ITPlaylistKindCD)
+ return new ITAudioCDPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindLibrary)
+ return new ITLibraryPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindUser)
+ return new ITUserPlaylist(cplaylist);
+ else
+ return playlist;
+ }
+
+ /**
+ * Subscribes to the specified podcast feed URL. Any "unsafe" characters in
+ * the URL should already be converted into their corresponding escape
+ * sequences, iTunes will not do this.
+ * @param url The URL to subscribe to.
+ */
+ public void subscribeToPodcast(String url) {
+ iTunes.invoke("SubscribeToPodcast", url);
+ }
+
+ /**
+ * Updates all podcast feeds. This is equivalent to the user pressing the
+ * Update button when Podcasts is selected in the Source list.
+ */
+ public void updatePodcastFeeds() {
+ iTunes.invoke("UpdatePodcastFeeds");
+ }
+
+ /**
+ * Creates a new folder in the main library.
+ * If folderName is empty, the folder will be created with a
+ * default name.
+ * @param folderName The name of the new folder (may be empty).
+ * @return Returns an ITPlaylist object corresponding to the new folder.
+ */
+ public ITUserPlaylist createFolder(String folderName) {
+ Dispatch folder = Dispatch.call(iTunes, "CreateFolder", folderName).toDispatch();
+ return new ITUserPlaylist(folder);
+ }
+
+ /**
+ * Creates a new folder in an existing source.
+ * You may not be able to create a folder in every source. For example, you
+ * cannot create a folder in an audio CD source, or in an iPod source if it
+ * is in auto update mode.
+ * If folderName is empty, the folder will be created with a
+ * default name.
+ * @param folderName The name of the new folder (may be empty)
+ * @param iSource The source that will contain the new folder.
+ * @return Returns an ITPlaylist object corresponding to the new folder.
+ */
+ public ITUserPlaylist createFolderInSource(String folderName, ITSource iSource) {
+ Dispatch folder = Dispatch.call(iTunes, "CreateFolderInSource", folderName, iSource.fetchDispatch()).toDispatch();
+ return new ITUserPlaylist(folder);
+ }
+
+ /**
+ * Returns a collection of music sources (music library, CD, device, etc.).
+ * @return Collection of ITSource objects.
+ */
+ public ITSourceCollection getSources() {
+ Dispatch sources = Dispatch.call(iTunes, "Sources").toDispatch();
+ return new ITSourceCollection(sources);
+ }
+
+ /**
+ * Sets the sound output volume (0=minimum, 100=maximum).
+ * @param volume New sound output volume
+ */
+ public void setSoundVolume(int volume) {
+ iTunes.setProperty("SoundVolume", volume);
+ }
+
+ /**
+ * Returns the sound output volume (0=minimum, 100=maximum).
+ * @return Current sound output volume
+ */
+ public int getSoundVolume() {
+ return iTunes.getPropertyAsInt("SoundVolume");
+ }
+
+ /**
+ * Sets sound output mute state.
+ * @param shouldMute If true, sound output will be muted.
+ */
+ public void setMute(boolean shouldMute) {
+ iTunes.setProperty("Mute", shouldMute);
+ }
+
+ /**
+ * Returns true if the sound output is muted.
+ * @return True if sound output is muted.
+ */
+ public boolean getMute() {
+ return iTunes.getPropertyAsBoolean("Mute");
+ }
+
+ /**
+ * Toggle the mute state.
+ */
+ public void toggleMute() {
+ setMute(!getMute());
+ }
+
+ /**
+ * Toggle the shuffle state.
+ */
+ public void toggleShuffle() {
+ getCurrentPlaylist().toggleShuffle();
+ }
+
+ /**
+ * Returns the current player state.
+ * @return Returns the current player state.
+ */
+ public ITPlayerState getPlayerState() {
+ return ITPlayerState.values()[Dispatch.get(iTunes, "PlayerState").getInt()];
+ }
+
+ /**
+ * Sets the player's position within the currently playing track in
+ * seconds.
+ * If playerPos specifies a position before the beginning of the track,
+ * the position will be set to the beginning. If playerPos specifies a
+ * position after the end of the track, the position will be set to the
+ * end.
+ * @param playerPos The player's position within the currently playing
+ * track in seconds.
+ */
+ public void setPlayerPosition(int playerPos) {
+ iTunes.setProperty("playerPosition", playerPos);
+ }
+
+ /**
+ * Returns the player's position within the currently playing track in
+ * seconds.
+ * @return The player's position within the currently playing track in
+ * seconds.
+ */
+ public int getPlayerPosition() {
+ return iTunes.getPropertyAsInt("playerPosition");
+ }
+
+ /**
+ * Returns the source that represents the main library.
+ * You can also find the main library source by iterating over
+ * iTunes.getSources() and looking for an ITSource
+ * of kind ITSourceKindLibrary.
+ * @return Returns the source that represents the main library.
+ */
+ public ITSource getLibrarySource() {
+ Dispatch lsource = iTunes.getProperty("LibrarySource").toDispatch();
+ return new ITSource(lsource);
+ }
+
+ /**
+ * Returns the main library playlist in the main library source.
+ * @return An IITLibraryPlaylist object corresponding to the main library
+ * playlist.
+ */
+ public ITLibraryPlaylist getLibraryPlaylist() {
+ Dispatch lplaylist = iTunes.getProperty("LibraryPlaylist").toDispatch();
+ return new ITLibraryPlaylist(lplaylist);
+ }
+
+ /**
+ * Returns the currently targetd track.
+ * @return An ITTrack object corresponding to the currently targeted track.
+ * Will be set to NULL if there is no currently targeted track.
+ */
+ public ITTrack getCurrentTrack() {
+ Dispatch item = iTunes.getProperty("CurrentTrack").toDispatch();
+ ITTrack track = new ITTrack(item);
+ if (track.getKind()==ITTrackKind.ITTrackKindFile) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindCD) {
+ return new ITFileOrCDTrack(item);
+ } else if (track.getKind()==ITTrackKind.ITTrackKindURL ) {
+ return new ITURLTrack(item);
+ } else {
+ return track;
+ }
+ }
+
+ /**
+ * Returns the playlist containing the currently targeted track.
+ * @return An ITPlaylist object corresponding to the playlist containing the
+ * currently targeted track.
+ * Will be set to NULL if there is no currently targeted playlist.
+ */
+ public ITPlaylist getCurrentPlaylist() {
+ Dispatch cplaylist = iTunes.getProperty("CurrentPlaylist").toDispatch();
+ ITPlaylist playlist = new ITPlaylist(cplaylist);
+ ITPlaylistKind playlistKind = playlist.getKind();
+ if (playlistKind == ITPlaylistKind.ITPlaylistKindCD)
+ return new ITAudioCDPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindLibrary)
+ return new ITLibraryPlaylist(cplaylist);
+ else if (playlist.getKind() == ITPlaylistKind.ITPlaylistKindUser)
+ return new ITUserPlaylist(cplaylist);
+ else
+ return playlist;
+ }
+
+ /**
+ * Returns a collection containing the currently selected track or tracks.
+ * The frontmost visible window in iTunes must be a browser or playlist
+ * window. If there is no frontmost visible window (e.g. iTunes is minimized
+ * to the system tray), the main browser window is used.
+ * @return Collection of ITrack objects.
+ * Will be set to NULL if there is no current selection.
+ */
+ public ITTrackCollection getSelectedTracks() {
+ Dispatch stracks = iTunes.getProperty("SelectedTracks").toDispatch();
+ return new ITTrackCollection(stracks);
+ }
+
+ /**
+ * Returns the version of the iTunes application.
+ * @return
+ */
+ public String getVersion() {
+ return iTunes.getPropertyAsString("Version");
+ }
+
+ /**
+ * Returns the high 32 bits of the persistent ID of the specified IITObject.
+ * See the documentation on IITObject for more information on persistent
+ * IDs.
+ *
+ * The object may be a source, playlist, or track.
+ * @param iObject The object to fetch the High Persistent ID.
+ * @return The high 32 bits of the 64-bit persistent ID.
+ */
+ public long getITObjectPersistentIDHigh (ITObject iObject) {
+ Dispatch object = iObject.fetchDispatch();
+ return Dispatch.call(object, "GetObjectPersistentIDHigh", object).getLong();
+ }
+
+ /**
+ * Returns the low 32 bits of the persistent ID of the specified IITObject.
+ * See the documentation on IITObject for more information on persistent
+ * IDs.
+ *
+ * The object may be a source, playlist, or track.
+ * @param iObject The object to fetch the Low Persistent ID.
+ * @return The low 32 bits of the 64-bit persistent ID.
+ */
+ public long getITObjectPersistentIDLow (ITObject iObject) {
+ Dispatch object = iObject.fetchDispatch();
+ return Dispatch.call(object, "GetObjectPersistentIDLow", object).getLong();
+ }
+
+ public ITObjectPersistentID getObjectPersistentIDs(ITObject iObject){
+ return new ITObjectPersistentID(getITObjectPersistentIDHigh(iObject),getITObjectPersistentIDLow(iObject));
+ }
+
+ public ITBrowserWindow getBrowserWindow(){
+ Dispatch window = iTunes.getProperty("BrowserWindow").toDispatch();
+ return new ITBrowserWindow(window);
+ }
+
+ public void cycleSongRepeat() {
+ getCurrentPlaylist().cycleSongRepeat();
+ }
+
+ public ITPlaylist getPlaylist(String name) {
+ ITPlaylistCollection playlistCollection = getLibrarySource().getPlaylists();
+ ITPlaylist playlist = playlistCollection.ItemByName(name);
+ try {
+ playlist.getName();
+ } catch (IllegalStateException e) {
+ playlist = createPlaylist(name);
+ }
+ return playlist;
+ }
+
+ public ITUserPlaylist getUserPlaylist(String name) {
+ ITPlaylist playlist = getPlaylist(name);
+ ITUserPlaylist userPlaylist = new ITUserPlaylist(playlist.fetchDispatch());
+ return userPlaylist;
+ }
+
+ public void playlistAddTrack(String name, ITTrack track) {
+ ITUserPlaylist userPlaylist = getUserPlaylist(name);
+ if (!userPlaylist.containsTrack(track)) {
+ userPlaylist.addTrack(track);
+ }
+ }
+
+ public void playlistAddCurrentTrack(String name) {
+ playlistAddTrack(name, getCurrentTrack());
+ }
+
+ public void release() {
+ ComThread.Release();
+ }
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunesEvents.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunesEvents.java
new file mode 100644
index 0000000..ddbee23
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunesEvents.java
@@ -0,0 +1,62 @@
+package com.dt.iTunesController;
+import com.jacob.com.Dispatch;
+import com.jacob.com.Variant;
+
+/**
+ * This class is used to forward all iTunes COM Events to a class that
+ * implements iTunesEventsInterface. To receive events, create
+ * a class that implements the interface, and then use
+ * iTunes.addEventHandler().
+ *
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public class iTunesEvents {
+
+ private iTunesEventsInterface eventHandler;
+
+ public iTunesEvents (iTunesEventsInterface itef) {
+ eventHandler = itef;
+ }
+
+ public void OnDatabaseChangedEvent(Variant[] args) {
+ // Not currently implemented
+ }
+
+ public void OnPlayerPlayEvent(Variant[] args) {
+ ITTrack itt = new ITTrack((Dispatch)args[0].getDispatch());
+ eventHandler.onPlayerPlayEvent(itt);
+ }
+
+ public void OnPlayerStopEvent(Variant[] args) {
+ ITTrack itt = new ITTrack((Dispatch)args[0].getDispatch());
+ eventHandler.onPlayerStopEvent(itt);
+ }
+
+ public void OnPlayerPlayingTrackChangedEvent(Variant[] args) {
+ ITTrack itt = new ITTrack((Dispatch)args[0].getDispatch());
+ eventHandler.onPlayerPlayingTrackChangedEvent(itt);
+ }
+
+ public void OnCOMCallsDisabledEvent(Variant[] args) {
+ ITCOMDisabledReason reason = ITCOMDisabledReason.values()[args[0].getInt()];
+ eventHandler.onCOMCallsDisabledEvent(reason);
+ }
+
+ public void OnCOMCallsEnabledEvent(Variant[] args) {
+ eventHandler.onCOMCallsEnabledEvent();
+ }
+
+ public void OnQuittingEvent(Variant[] args) {
+ eventHandler.onQuittingEvent();
+ }
+
+ public void OnAboutToPromptUserToQuitEvent(Variant[] args) {
+ eventHandler.onAboutToPromptUserToQuitEvent();
+ }
+
+ public void OnSoundVolumeChangedEvent(Variant[] args) {
+ eventHandler.onSoundVolumeChangedEvent(args[0].getInt());
+ }
+
+}
diff --git a/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunesEventsInterface.java b/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunesEventsInterface.java
new file mode 100644
index 0000000..3d8f17e
--- /dev/null
+++ b/java/itunescontroller/src/main/java/com/dt/iTunesController/iTunesEventsInterface.java
@@ -0,0 +1,115 @@
+package com.dt.iTunesController;
+
+/**
+ * Interface for receiving iTunes events.
+ * @author Steve Eyre
+ * @version 0.2
+ */
+public interface iTunesEventsInterface {
+
+ /**
+ * Not currently implemented.
+ *
+ * The ITEventDatabaseChanged event is fired when the iTunes database is
+ * changed.
+ *
+ * Each parameter is a two-dimensional array of integers. The first
+ * dimension is the number of objects. The second dimension is always 4 and
+ * specifies each of the 4 ITObject IDs, where index 0 is the source ID,
+ * index 1 is the playlist ID, index 2 is the track ID, and index 3 is the
+ * track database ID. For more information on object IDs, see
+ * ITObject.
+ *
+ * Note that you can use iTunes.getITObjectByID() to retrieve
+ * changed ITObject, but not for deleted objects (since they no longer
+ * exist).
+ *
+ * @param deletedObjectIDs
+ * @param changedObjectIDs
+ */
+ public void onDatabaseChangedEvent(int[][] deletedObjectIDs, int[][] changedObjectIDs);
+
+ /**
+ * The ITEventPlayerPlay event is fired when a track begins playing.
+ * @param iTrack An ITTrack object corresponding to the track that has
+ * started playing.
+ */
+ public void onPlayerPlayEvent (ITTrack iTrack);
+
+ /**
+ * The ITEventPlayerStop event is fired when a track stops playing.
+ * @param iTrack An ITTrack object corresponding to the track that has
+ * stopped playing.
+ */
+ public void onPlayerStopEvent (ITTrack iTrack);
+
+ /**
+ * The ITEventPlayerPlayingTrackChanged event is fired when information
+ * about the currently playing track has changed.
+ * This event is fired when the user changes information about the currently
+ * playing track (e.g. the name of the track).
+ * This event is also fired when iTunes plays the next joined CD track in a
+ * CD playlist, since joined CD tracks are treated as a single track.
+ * @param iTrack An ITTrack object corresponding to the track that is now
+ * playing.
+ */
+ public void onPlayerPlayingTrackChangedEvent(ITTrack iTrack);
+
+ /**
+ * The ITEventCOMCallsDisabled event is fired when calls to the iTunes COM
+ * interface will be deferred.
+ * Typically, iTunes will defer COM calls when any modal dialog is being
+ * displayed. When the user dismisses the last modal dialog, COM calls will
+ * be enabled again, and any deferred COM calls will be executed. You can
+ * use this event to avoid making a COM call which will be deferred.
+ * @param reason The reason the COM interface is being disabled. This is
+ * typically ITCOMDisabledReasonDialog.
+ */
+ public void onCOMCallsDisabledEvent(ITCOMDisabledReason reason);
+
+ /**
+ * The ITEventCOMCallsEnabled event is fired when calls to the iTunes COM
+ * interface will no longer be deferred.
+ * Typically, iTunes will defer COM calls when any modal dialog is being
+ * displayed. When the user dismisses the last modal dialog, COM calls will
+ * be enabled again, and any deferred COM calls will be executed.
+ */
+ public void onCOMCallsEnabledEvent();
+
+ /**
+ * The ITEventQuitting event is fired when iTunes is about to quit.
+ * If the user attempts to quit iTunes while a client still has outstanding
+ * iTunes COM objects instantiated, iTunes will display a warning dialog.
+ * The user can still choose to quit iTunes anyway, in which case this event
+ * will be fired. After this event is fired, any existing iTunes COM objects
+ * will no longer be valid.
+ * This event is only used to notify clients that iTunes is quitting,
+ * clients cannot prevent this from happening.
+ */
+ public void onQuittingEvent();
+
+ /**
+ * The ITEventAboutToPromptUserToQuit event is fired when iTunes is about
+ * prompt the user to quit.
+ * This event gives clients the opportunity to prevent the warning dialog
+ * prompt from occurring.
+ * If the user attempts to quit iTunes while a client still has outstanding
+ * iTunes COM objects instantiated, iTunes will display a warning dialog.
+ * This event is fired just before the warning dialog is shown. iTunes will
+ * then wait up to 5 seconds for clients to release any outstanding iTunes
+ * COM objects. If all objects are released during this time, the warning
+ * dialog will not be shown and iTunes will quit immediately.
+ * Otherwise, the warning dialog will be shown. If the user chooses to quit
+ * iTunes anyway, the ITEventQuitting event is fired. See
+ * iTunesEventsInterface.onQuittingEvent() for more details.
+ */
+ public void onAboutToPromptUserToQuitEvent();
+
+ /**
+ * The ITEventSoundVolumeChanged event is fired when the sound output volume
+ * has changed.
+ * @param newVolume The new sound output volume (0 = minimum, 100 = maximum).
+ */
+ public void onSoundVolumeChangedEvent(int newVolume);
+
+}
diff --git a/java/mimis/.classpath b/java/mimis/.classpath
new file mode 100644
index 0000000..c80843f
--- /dev/null
+++ b/java/mimis/.classpath
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/mimis/.project b/java/mimis/.project
new file mode 100644
index 0000000..e30efa6
--- /dev/null
+++ b/java/mimis/.project
@@ -0,0 +1,18 @@
+
+
+ mimis
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.springsource.ide.eclipse.gradle.core.nature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java/mimis/DelcomDLL.dll b/java/mimis/DelcomDLL.dll
new file mode 100644
index 0000000..ecfa470
Binary files /dev/null and b/java/mimis/DelcomDLL.dll differ
diff --git a/java/mimis/WiiPair.exe b/java/mimis/WiiPair.exe
new file mode 100644
index 0000000..f16c97d
Binary files /dev/null and b/java/mimis/WiiPair.exe differ
diff --git a/java/mimis/build.gradle b/java/mimis/build.gradle
new file mode 100644
index 0000000..427e0f1
--- /dev/null
+++ b/java/mimis/build.gradle
@@ -0,0 +1,35 @@
+import java.util.jar.JarEntry;
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'cpp-lib'
+
+version = '0.1'
+
+sourceCompatibility = 1.6
+targetCompatibility = 1.6
+
+def mainClass = 'mimis.Main'
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ compile project(':itunescontroller')
+ compile project(':wiiusej')
+ compile project(':wiigee')
+
+ compile 'commons-collections:commons-collections:3.+'
+ compile 'commons-logging:commons-logging:1.+'
+ compile 'log4j:log4j:1.2.17'
+ compile 'com.melloware:jintellitype:1.3.7'
+
+ compile fileTree(dir: 'lib', include: '*.jar')
+}
+
+jar {
+ manifest {
+ attributes 'Main-Class': mainClass
+ }
+}
\ No newline at end of file
diff --git a/java/mimis/build.xml b/java/mimis/build.xml
new file mode 100644
index 0000000..4d47af4
--- /dev/null
+++ b/java/mimis/build.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/mimis/client.jar b/java/mimis/client.jar
new file mode 100644
index 0000000..a16b1bd
Binary files /dev/null and b/java/mimis/client.jar differ
diff --git a/java/mimis/irtoy.exe b/java/mimis/irtoy.exe
new file mode 100644
index 0000000..0dc97e5
Binary files /dev/null and b/java/mimis/irtoy.exe differ
diff --git a/java/mimis/jacob-1.15-M3-x86.dll b/java/mimis/jacob-1.15-M3-x86.dll
new file mode 100644
index 0000000..34876a0
Binary files /dev/null and b/java/mimis/jacob-1.15-M3-x86.dll differ
diff --git a/java/mimis/jintellitype.dll b/java/mimis/jintellitype.dll
new file mode 100644
index 0000000..839236b
Binary files /dev/null and b/java/mimis/jintellitype.dll differ
diff --git a/java/mimis/jxinput.dll b/java/mimis/jxinput.dll
new file mode 100644
index 0000000..720b9bb
Binary files /dev/null and b/java/mimis/jxinput.dll differ
diff --git a/java/mimis/launch4j.xml b/java/mimis/launch4j.xml
new file mode 100644
index 0000000..d3043f1
--- /dev/null
+++ b/java/mimis/launch4j.xml
@@ -0,0 +1,22 @@
+
+ false
+ gui
+ main.jar
+ mimis.exe
+ Mimis
+
+
+ normal
+ http://java.com/download
+
+ true
+ false
+
+ resource\M.ico
+
+
+ 1.6.0
+
+ preferJre
+
+
\ No newline at end of file
diff --git a/java/mimis/lib/jxinput.jar b/java/mimis/lib/jxinput.jar
new file mode 100644
index 0000000..dbb035a
Binary files /dev/null and b/java/mimis/lib/jxinput.jar differ
diff --git a/java/mimis/main.jar b/java/mimis/main.jar
new file mode 100644
index 0000000..ba79a74
Binary files /dev/null and b/java/mimis/main.jar differ
diff --git a/java/mimis/mimis.dll b/java/mimis/mimis.dll
new file mode 100644
index 0000000..25ef12a
Binary files /dev/null and b/java/mimis/mimis.dll differ
diff --git a/java/mimis/mimis.exe b/java/mimis/mimis.exe
new file mode 100644
index 0000000..93a6acf
Binary files /dev/null and b/java/mimis/mimis.exe differ
diff --git a/java/mimis/src/main/java/mimis/Client.java b/java/mimis/src/main/java/mimis/Client.java
new file mode 100644
index 0000000..c784918
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/Client.java
@@ -0,0 +1,25 @@
+package mimis;
+
+import mimis.exception.worker.ActivateException;
+import mimis.router.GlobalRouter;
+import mimis.util.swing.Dialog;
+
+public class Client extends Main {
+ public static final String IP = "127.0.0.1";
+ public static final int PORT = 6789;
+
+ public Client(String ip, int port) {
+ super();
+ router = new GlobalRouter(ip, port);
+ }
+
+ public void activate() throws ActivateException {
+ super.activate();
+ }
+
+ public static void main(String[] args) {
+ String ip = Dialog.question("Server IP:", IP);
+ int port = Integer.valueOf(Dialog.question("Server Port:", PORT));
+ new Client(ip, port).start();
+ }
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/Gui.java b/java/mimis/src/main/java/mimis/Gui.java
new file mode 100644
index 0000000..193ecea
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/Gui.java
@@ -0,0 +1,98 @@
+package mimis;
+
+import java.awt.GridLayout;
+import java.awt.TextArea;
+import java.awt.event.WindowEvent;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.WindowConstants;
+
+import mimis.exception.worker.ActivateException;
+import mimis.input.Feedback;
+import mimis.input.Input;
+import mimis.manager.ButtonManager;
+import mimis.util.Swing;
+import mimis.worker.Component;
+
+public class Gui extends Component {
+ public static final String ICON = "M.png";
+ public static final String TITLE = "MIMIS Manager";
+
+ protected JFrame frame;
+ protected Component component;
+ protected TextArea textArea;
+
+ public Gui(final Component component, ButtonManager... buttonManagerArray) {
+ frame = new JFrame(TITLE) {
+ protected static final long serialVersionUID = 1L;
+ protected void processWindowEvent(WindowEvent event) {
+ if (event.getID() == WindowEvent.WINDOW_CLOSING) {
+ log.debug("Window closing");
+ component.exit();
+ }
+ }
+ };
+ this.component = component;
+ frame.setIconImage(Swing.getImage(ICON));
+ createFrame(buttonManagerArray);
+ }
+
+ protected void activate() throws ActivateException {
+ listen(Feedback.class);
+ super.activate();
+ }
+
+ public void exit() {
+ super.exit();
+ frame.dispose();
+ }
+
+ protected void createFrame(ButtonManager... buttonManagerArray) {
+ frame.setLayout(new GridLayout(0, 1));
+ JPanel controlPanel = createControlPanel(buttonManagerArray);
+ frame.add(controlPanel);
+ JPanel feedbackPanel = createTextPanel();
+ frame.add(feedbackPanel);
+ frame.setResizable(false);
+ frame.setVisible(true);
+ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ frame.pack();
+ }
+
+ protected JPanel createControlPanel(ButtonManager... buttonManagerArray) {
+ JPanel controlPanel = new JPanel(new GridLayout(1, 0));
+ for (ButtonManager buttonManager : buttonManagerArray) {
+ if (buttonManager.count() > 0) {
+ controlPanel.add(buttonManager.createPanel());
+ }
+ }
+ return controlPanel;
+ }
+
+ protected JPanel createTextPanel() {
+ JPanel textPanel = new JPanel();
+ textArea = new TextArea();
+ textArea.setEditable(false);
+ textPanel.add(textArea);
+ return textPanel;
+ }
+
+ public void input(Input input) {
+ if (input instanceof Feedback) {
+ writeLine(((Feedback) input).getText());
+ }
+ }
+
+ public void write(String string) {
+ textArea.append(string);
+ }
+
+ public void writeLine(String string) {
+ write(string + "\n");
+ }
+
+ public void clear() {
+ textArea.setText(null);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/Main.java b/java/mimis/src/main/java/mimis/Main.java
new file mode 100644
index 0000000..fa2d92f
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/Main.java
@@ -0,0 +1,102 @@
+package mimis;
+
+import java.util.ArrayList;
+import java.util.ServiceLoader;
+
+import javax.swing.UIManager;
+
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.input.Task;
+import mimis.manager.ButtonManager;
+import mimis.manager.CurrentButtonManager;
+import mimis.value.Action;
+import mimis.worker.Component;
+
+public class Main extends Mimis {
+ protected CurrentButtonManager applicationManager;
+ protected ButtonManager deviceManager;
+ protected Gui gui;
+
+ static {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception e) {}
+
+ }
+
+ public static Component[] getApplications() {
+ return getComponents(mimis.application.Application.class);
+ }
+
+ public static Component[] getDevices() {
+ return getComponents(mimis.device.Device.class);
+ }
+
+ public static Component[] getComponents(Class> clazz) {
+ ArrayList componentList = new ArrayList();
+ for (Object object : ServiceLoader.load(clazz)) {
+ if (object instanceof Component) {
+ componentList.add((Component) object);
+ }
+ }
+ return componentList.toArray(new Component[]{});
+ }
+
+ public Main() {
+ super(getApplications());
+
+ /* Create gui from application and device managers */
+ applicationManager = new CurrentButtonManager(router, componentCycle, "Applications", currentArray);
+ deviceManager = new ButtonManager("Devices", initialize(false, getDevices()));
+ gui = new Gui(this, applicationManager, deviceManager);
+ manager.add(initialize(false, gui));
+ }
+
+ public void activate() throws ActivateException {
+ super.activate();
+ listen(Task.class);
+
+ /* Start managers */
+ applicationManager.start();
+ deviceManager.start();
+
+ /* Force display of current component when gui started */
+ gui.start();
+ while (!gui.active());
+ end(Action.CURRENT);
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+
+ log.debug("Stop managers");
+ applicationManager.stop();
+ deviceManager.stop();
+ }
+
+ public void exit() {
+ super.exit();
+
+ log.debug("Exit managers");
+ applicationManager.exit();
+ deviceManager.exit();
+ }
+
+ public void end(Action action) {
+ super.end(action);
+ switch (action) {
+ case CURRENT:
+ case NEXT:
+ case PREVIOUS:
+ applicationManager.currentChanged();
+ break;
+ default:
+ break;
+ }
+ }
+
+ public static void main(String[] args) {
+ new Main().start(false);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/Mimis.java b/java/mimis/src/main/java/mimis/Mimis.java
new file mode 100644
index 0000000..3185c4f
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/Mimis.java
@@ -0,0 +1,81 @@
+package mimis;
+
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.input.Feedback;
+import mimis.input.Task;
+import mimis.manager.Manager;
+import mimis.parser.Parser;
+import mimis.router.Router;
+import mimis.util.ArrayCycle;
+import mimis.value.Action;
+import mimis.value.Target;
+import mimis.worker.Component;
+
+public abstract class Mimis extends Component {
+ protected Component[] currentArray;
+ protected Manager manager;
+
+ protected ArrayCycle componentCycle;
+
+ public Mimis(Component... currentArray) {
+ this.currentArray = initialize(false, currentArray);
+ componentCycle = new ArrayCycle(currentArray);
+ router = new Router();
+ manager = new Manager(initialize(true, router, new Parser()));
+ }
+
+ public void activate() throws ActivateException {
+ manager.start();
+ super.activate();
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ manager.stop();
+ }
+
+ public void exit() {
+ super.exit();
+ manager.exit();
+ }
+
+ public Component[] initialize(boolean start, Component... componentArray) {
+ for (Component component : componentArray) {
+ component.setRouter(router);
+ if (start) {
+ component.start();
+ }
+ }
+ return componentArray;
+ }
+
+ public void task(Task task) {
+ if (task.getTarget().equals(Target.CURRENT)) {
+ componentCycle.current().add(task);
+ } else {
+ super.task(task);
+ }
+ }
+
+ public void end(Action action) {
+ switch (action) {
+ case CURRENT:
+ route(new Feedback("Current component: " + componentCycle.current().getTitle()));
+ break;
+ case NEXT:
+ log.debug("Next component");
+ route(new Feedback("Next component: " + componentCycle.next().getTitle()));
+ break;
+ case PREVIOUS:
+ log.debug("Previous component");
+ route(new Feedback("Previous component: " + componentCycle.previous().getTitle()));
+ break;
+ case EXIT:
+ exit();
+ break;
+ default:
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/application/Application.java b/java/mimis/src/main/java/mimis/application/Application.java
new file mode 100644
index 0000000..8dc6e15
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/Application.java
@@ -0,0 +1,6 @@
+package mimis.application;
+
+
+public interface Application {
+
+}
diff --git a/java/mimis/src/main/java/mimis/application/cmd/CMDApplication.java b/java/mimis/src/main/java/mimis/application/cmd/CMDApplication.java
new file mode 100644
index 0000000..bd518f3
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/cmd/CMDApplication.java
@@ -0,0 +1,80 @@
+package mimis.application.cmd;
+
+import java.io.IOException;
+import java.util.Map;
+
+import mimis.application.Application;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.util.Native;
+import mimis.value.Registry;
+import mimis.worker.Component;
+
+public abstract class CMDApplication extends Component implements Application {
+ protected final static Registry REGISTRY = Registry.LOCAL_MACHINE;
+ protected final static String KEY = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths";
+
+ protected String program;
+ protected String title;
+ protected Process process;
+ protected boolean detect, running;
+
+ public CMDApplication(String program, String title) {
+ super(title);
+ this.program = program;
+ this.title = title;
+ detect = true;
+ }
+
+ protected void activate() throws ActivateException {
+ detect = true;
+ if (!running) {
+ String path = getPath();
+ if (path == null) {
+ throw new ActivateException();
+ }
+ try {
+ String command = path.startsWith("\"") ? path : String.format("\"%s\"", path);
+ command = replaceVariables(command);
+ process = Runtime.getRuntime().exec(command);
+ } catch (IOException e) {
+ log.error(e);
+ throw new ActivateException();
+ }
+ }
+ super.activate();
+ }
+
+ public boolean active() {
+ if (detect) {
+ running = Native.isRunning(program);
+ if (!active && running) {
+ active = true;
+ start();
+ }
+ }
+ return active;
+ }
+
+ protected synchronized void deactivate() throws DeactivateException {
+ detect = false;
+ super.deactivate();
+ if (process != null) {
+ process.destroy();
+ }
+ }
+
+ public String getPath() {
+ String key = String.format("%s\\%s", KEY, program);
+ System.out.println(Native.getValue(REGISTRY, key));
+ return Native.getValue(REGISTRY, key);
+ }
+
+ public static String replaceVariables(String string) {
+ Map env = System.getenv();
+ for (String key : env.keySet()) {
+ string = string.replace(String.format("%%%s%%", key), env.get(key));
+ }
+ return string;
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/application/cmd/windows/WindowsApplication.java b/java/mimis/src/main/java/mimis/application/cmd/windows/WindowsApplication.java
new file mode 100644
index 0000000..673f396
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/cmd/windows/WindowsApplication.java
@@ -0,0 +1,100 @@
+package mimis.application.cmd.windows;
+
+import mimis.application.cmd.CMDApplication;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.util.Native;
+import mimis.value.Command;
+import mimis.value.Key;
+import mimis.value.Type;
+import mimis.value.Windows;
+
+public abstract class WindowsApplication extends CMDApplication {
+ protected final static int TERMINATE_SLEEP = 500;
+ protected final static int START_SLEEP = 500;
+
+ protected String window;
+ protected int handle;
+
+ public WindowsApplication(String title, String window) {
+ this(null, title, window);
+ }
+
+ public WindowsApplication(String program, String title, String window) {
+ super(program, title);
+ this.window = window;
+ handle = 0;
+ }
+
+ protected void activate() throws ActivateException {
+ if (program != null) {
+ super.activate();
+ }
+ handle = Native.getHandle(window);
+ if (handle < 1) {
+ sleep(START_SLEEP);
+ handle = Native.getHandle(window);
+ }
+ active = handle > 0;
+ if (!active) {
+ throw new ActivateException();
+ }
+ }
+
+ public boolean active() {
+ if (!active || program == null) {
+ handle = Native.getHandle(window);
+ if (handle > 0 && program == null) {
+ start();
+ }
+ }
+ return program == null ? handle > 0 : super.active();
+ }
+
+ protected void deactivate() throws DeactivateException {
+ if (process == null) {
+ active = false;
+ } else {
+ super.deactivate();
+ }
+ close();
+ }
+
+ protected void close() {
+ Native.sendMessage(handle, Windows.WM_CLOSE, 0, 0);
+ }
+
+ protected void command(Command command) {
+ Native.sendMessage(handle, Windows.WM_APPCOMMAND, handle, command.getCode() << 16);
+ }
+
+ protected void command(int command) {
+ Native.sendMessage(handle, Windows.WM_COMMAND, command, 0);
+ }
+
+ protected int user(int wParam, int lParam) {
+ return Native.sendMessage(handle, Windows.WM_USER, wParam, lParam);
+ }
+
+ protected void system(Command.System system) {
+ system(system, 0);
+ }
+
+ protected void system(Command.System system, int lParam) {
+ Native.sendMessage(handle, Windows.WM_SYSCOMMAND, system.getCode(), lParam);
+ }
+
+ protected void key(Type type, int code) {
+ int scanCode = Native.mapVirtualKey(code, Windows.MAPVK_VK_TO_VSC);
+ Native.postMessage(handle, type.getCode(), code, 1 | (scanCode << 16) | 1 << 30);
+ sleep(200);
+ }
+
+ protected void key(Type type, char character) {
+ key(type, (int) Character.toUpperCase(character));
+ }
+
+ protected void key(Type key, Key virtualKey) {
+ key(key, virtualKey.getCode());
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java b/java/mimis/src/main/java/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java
new file mode 100644
index 0000000..0ea28e0
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/cmd/windows/gomplayer/GomPlayerApplication.java
@@ -0,0 +1,127 @@
+package mimis.application.cmd.windows.gomplayer;
+
+import mimis.application.cmd.windows.WindowsApplication;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.value.Action;
+import mimis.value.Amount;
+import mimis.worker.Worker;
+
+public class GomPlayerApplication extends WindowsApplication {
+ protected final static String PROGRAM = "GOM.exe";
+ protected final static String TITLE = "GOM Player";
+ protected final static String WINDOW = "GomPlayer1.x";
+
+ protected static final int VOLUME_SLEEP = 100;
+ protected static final int SEEK_SLEEP = 100;
+
+ protected VolumeWorker volumeWorker;
+ protected SeekWorker seekWorker;
+
+ public GomPlayerApplication() {
+ super(PROGRAM, TITLE, WINDOW);
+ volumeWorker = new VolumeWorker();
+ seekWorker = new SeekWorker();
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ volumeWorker.stop();
+ seekWorker.stop();
+ }
+
+ public void exit() {
+ super.exit();
+ volumeWorker.exit();
+ seekWorker.exit();
+ }
+
+ public void begin(Action action) {
+ log.trace("GomPlayerApplication begin: " + action);
+ switch (action) {
+ case VOLUME_UP:
+ volumeWorker.start();
+ break;
+ case VOLUME_DOWN:
+ volumeWorker.start();
+ break;
+ case FORWARD:
+ seekWorker.start(Amount.SMALL, 1);
+ break;
+ case REWIND:
+ seekWorker.start(Amount.SMALL, -1);
+ break;
+ case NEXT:
+ seekWorker.start(Amount.MEDIUM, 1);
+ break;
+ case PREVIOUS:
+ seekWorker.start(Amount.MEDIUM, -1);
+ break;
+ }
+ }
+
+ public void end(Action action) {
+ log.trace("GomPlayerApplication end: " + action);
+ switch (action) {
+ case PLAY:
+ command(0x800C);
+ break;
+ case MUTE:
+ command(0x8016);
+ break;
+ case FORWARD:
+ case REWIND:
+ case NEXT:
+ case PREVIOUS:
+ seekWorker.stop();
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ case FULLSCREEN:
+ command(0x8154);
+ break;
+ }
+ }
+
+ protected class VolumeWorker extends Worker {
+ protected int volumeChangeSign;
+
+ public void start(int volumeChangeSign) throws ActivateException {
+ super.start();
+ this.volumeChangeSign = volumeChangeSign;
+ }
+
+ public void work() {
+ command(volumeChangeSign > 0 ? 0x8014 : 0x8013);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+
+ protected class SeekWorker extends Worker {
+ protected Amount amount;
+ protected int seekDirection;
+
+ public void start(Amount amount, int seekDirection) {
+ super.start();
+ this.amount = amount;
+ this.seekDirection = seekDirection;
+ }
+
+ public void work() {
+ switch (amount) {
+ case SMALL:
+ command(seekDirection > 0 ? 0x8009 : 0x8008);
+ break;
+ case MEDIUM:
+ command(seekDirection > 0 ? 0x800B : 0x800A);
+ break;
+ case LARGE:
+ command(seekDirection > 0 ? 0x8012 : 0x8011);
+ break;
+ }
+ sleep(SEEK_SLEEP);
+ }
+ };
+}
diff --git a/java/mimis/src/main/java/mimis/application/cmd/windows/photoviewer/PhotoViewerApplication.java b/java/mimis/src/main/java/mimis/application/cmd/windows/photoviewer/PhotoViewerApplication.java
new file mode 100644
index 0000000..d59bd9c
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/cmd/windows/photoviewer/PhotoViewerApplication.java
@@ -0,0 +1,110 @@
+package mimis.application.cmd.windows.photoviewer;
+
+import mimis.application.cmd.windows.WindowsApplication;
+import mimis.exception.worker.DeactivateException;
+import mimis.value.Action;
+import mimis.value.Key;
+import mimis.value.Type;
+import mimis.worker.Worker;
+
+public class PhotoViewerApplication extends WindowsApplication {
+ protected final static String TITLE = "Photo Viewer";
+ protected final static String WINDOW = "Photo_Lightweight_Viewer";
+
+ protected static final int ZOOM_SLEEP = 100;
+ protected static final int DELETE_SLEEP = 2000;
+
+ protected ZoomWorker zoomWorker;
+ protected boolean fullscreen;
+
+ public PhotoViewerApplication() {
+ super(TITLE, WINDOW);
+ zoomWorker = new ZoomWorker();
+ fullscreen = false;
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ zoomWorker.stop();
+ }
+
+ public void exit() {
+ super.exit();
+ zoomWorker.exit();
+ }
+
+ public void begin(Action action) {
+ switch (action) {
+ case VOLUME_UP:
+ zoomWorker.start(1);
+ break;
+ case VOLUME_DOWN:
+ zoomWorker.start(-1);
+ break;
+ }
+ }
+
+ public void end(Action action) {
+ log.trace("PhotoViewerApplication end: " + action);
+ switch (action) {
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ zoomWorker.stop();
+ break;
+ case NEXT:
+ key(Type.DOWN, Key.RIGHT);
+ break;
+ case PREVIOUS:
+ key(Type.DOWN, Key.LEFT);
+ break;
+ case FORWARD:
+ key(Type.DOWN, Key.CONTROL);
+ //key(Type.DOWN, '.');
+ //key(Type.DOWN, Key.DECIMAL);
+ key(Type.DOWN, Key.OEM_PERIOD);
+ //key(Type.UP, Key.OEM_PERIOD);
+ //key(Type.UP, Key.CONTROL);
+ break;
+ case MUTE:
+ key(Type.DOWN, Key.CONTROL);
+ key(Type.DOWN, Key.NUMPAD0);
+ //press(Key.CONTROL);
+ //press(Key.NUMPAD0);
+ //release(Key.CONTROL);
+ break;
+ case FULLSCREEN:
+ key(Type.DOWN, fullscreen ? Key.ESCAPE : Key.F11);
+ fullscreen = !fullscreen;
+ break;
+ case DISLIKE:
+ /*boolean restore = false;
+ if (fullscreen) {
+ end(Action.FULLSCREEN);
+ sleep(DELETE_SLEEP);
+ restore = true;
+ }
+ key(Type.DOWN, Key.F16);
+ key(Type.DOWN, 'Y');
+ if (restore) {
+ sleep(DELETE_SLEEP);
+ end(Action.FULLSCREEN);
+ }*/
+ break;
+ }
+ }
+
+ protected class ZoomWorker extends Worker {
+ protected int zoomDirection;
+
+ public void start(int zoomDirection) {
+ super.start();
+ this.zoomDirection = zoomDirection;
+ }
+
+ public void work() {
+ Key key = zoomDirection > 0 ? Key.ADD : Key.SUBTRACT;
+ key(Type.DOWN, key);
+ sleep(ZOOM_SLEEP);
+ }
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/application/cmd/windows/winamp/WinampApplication.java b/java/mimis/src/main/java/mimis/application/cmd/windows/winamp/WinampApplication.java
new file mode 100644
index 0000000..975c352
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/cmd/windows/winamp/WinampApplication.java
@@ -0,0 +1,181 @@
+package mimis.application.cmd.windows.winamp;
+
+import mimis.application.cmd.windows.WindowsApplication;
+import mimis.exception.worker.DeactivateException;
+import mimis.value.Action;
+import mimis.value.Command;
+import mimis.worker.Worker;
+
+public class WinampApplication extends WindowsApplication {
+ protected final static String PROGRAM = "winamp.exe";
+ protected final static String TITLE = "Winamp";
+ protected final static String WINDOW = "Winamp v1.x";
+
+ protected final static int STATUS_PLAYING = 1;
+ protected final static int STATUS_PAUSED = 3;
+ protected final static int STATUS_STOPPED = 0;
+
+ protected final static int IPC_ISPLAYING = 104;
+ protected final static int IPC_GETOUTPUTTIME = 105;
+ protected final static int IPC_SETVOLUME = 122;
+
+ protected final static int WINAMP_FILE_QUIT = 40001;
+ protected final static int WINAMP_FILE_REPEAT = 40022;
+ protected final static int WINAMP_FILE_SHUFFLE = 40023;
+ protected final static int WINAMP_BUTTON1 = 40044;
+ protected final static int WINAMP_BUTTON2 = 40045;
+ protected final static int WINAMP_BUTTON3 = 40046;
+ protected final static int WINAMP_BUTTON5 = 40048;
+ protected final static int WINAMP_VOLUMEUP = 40058;
+ protected final static int WINAMP_VOLUMEDOWN = 40059;
+ protected final static int WINAMP_FFWD5S = 40060;
+ protected final static int WINAMP_REW5S = 40061;
+ protected final static int WINAMP_BUTTON4_SHIFT = 40147;
+ protected final static int WINAMP_VISPLUGIN = 40192;
+
+ protected static final int VOLUME_SLEEP = 50;
+ protected static final int SEEK_SLEEP = 100;
+
+ protected VolumeWorker volumeWorker;
+ protected SeekWorker seekWorker;
+ protected double volume;
+ protected boolean muted;
+
+ public WinampApplication() {
+ super(PROGRAM, TITLE, WINDOW);
+ volume = getVolume();
+ muted = volume == 0;
+ volumeWorker = new VolumeWorker();
+ seekWorker = new SeekWorker();
+ }
+
+ public void deactivate() throws DeactivateException {
+ super.deactivate();
+ volumeWorker.stop();
+ seekWorker.stop();
+ }
+
+ public void exit() {
+ super.exit();
+ volumeWorker.exit();
+ seekWorker.exit();
+ }
+
+ public void begin(Action action) {
+ log.trace("WinampApplication begin: " + action);
+ switch (action) {
+ case VOLUME_UP:
+ volumeWorker.start(1);
+ break;
+ case VOLUME_DOWN:
+ volumeWorker.start(-1);
+ break;
+ case FORWARD:
+ seekWorker.start(1);
+ break;
+ case REWIND:
+ seekWorker.start(-1);
+ break;
+ }
+ }
+
+ public void end(Action action) {
+ log.trace("WinampApplication end: " + action);
+ switch (action) {
+ case PLAY:
+ log.debug("play");
+ switch (user(0, IPC_ISPLAYING)) {
+ case STATUS_STOPPED:
+ command(WINAMP_BUTTON2);
+ break;
+ default:
+ command(WINAMP_BUTTON3);
+ break;
+ }
+ break;
+ case NEXT:
+ command(WINAMP_BUTTON5);
+ break;
+ case PREVIOUS:
+ command(WINAMP_BUTTON1);
+ break;
+ case FORWARD:
+ case REWIND:
+ seekWorker.stop();
+ break;
+ case MUTE:
+ if (muted) {
+ setVolume(volume);
+ } else {
+ volume = getVolume();
+ setVolume(0);
+ }
+ muted = !muted;
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ case SHUFFLE:
+ command(WINAMP_FILE_SHUFFLE);
+ break;
+ case REPEAT:
+ command(WINAMP_FILE_REPEAT);
+ break;
+ case FADEOUT:
+ command(WINAMP_BUTTON4_SHIFT);
+ break;
+ case QUIT:
+ command(WINAMP_FILE_QUIT);
+ break;
+ case VISUALISER:
+ system(Command.System.MAXIMIZE);
+ command(WINAMP_VISPLUGIN);
+ break;
+ }
+ }
+
+ public double getVolume() {
+ return user(-666, IPC_SETVOLUME) / 255f;
+ }
+
+ public void setVolume(double volume) {
+ user((int) Math.ceil(volume * 255), IPC_SETVOLUME);
+ }
+
+ public int getDuration() {
+ return user(1, IPC_GETOUTPUTTIME);
+ }
+
+ public int getElapsed() {
+ return user(0, IPC_GETOUTPUTTIME) / 1000;
+ }
+
+ protected class VolumeWorker extends Worker {
+ protected int volumeChangeSign;
+
+ public void start(int volumeChangeSign) {
+ super.start();
+ this.volumeChangeSign = volumeChangeSign;
+ }
+
+ public void work() {
+ command(volumeChangeSign > 0 ? WINAMP_VOLUMEUP : WINAMP_VOLUMEDOWN);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+
+ protected class SeekWorker extends Worker {
+ protected int seekDirection;
+
+ public void start(int seekDirection) {
+ super.start();
+ this.seekDirection = seekDirection;
+ }
+
+ public void work() {
+ command(seekDirection > 0 ? WINAMP_FFWD5S : WINAMP_REW5S);
+ sleep(SEEK_SLEEP);
+ }
+ };
+}
diff --git a/java/mimis/src/main/java/mimis/application/cmd/windows/wmp/WMPApplication.java b/java/mimis/src/main/java/mimis/application/cmd/windows/wmp/WMPApplication.java
new file mode 100644
index 0000000..484d830
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/cmd/windows/wmp/WMPApplication.java
@@ -0,0 +1,86 @@
+package mimis.application.cmd.windows.wmp;
+
+import mimis.application.cmd.windows.WindowsApplication;
+import mimis.value.Action;
+import mimis.worker.Worker;
+
+public class WMPApplication extends WindowsApplication {
+ protected final static String PROGRAM = "wmplayer.exe";
+ protected final static String TITLE = "Windows Media Player";
+ protected final static String WINDOW = "WMPlayerApp";
+
+ protected static final int VOLUME_SLEEP = 120;
+
+ protected VolumeWorker volumeWorker;
+
+ public WMPApplication() {
+ super(PROGRAM, TITLE, WINDOW);
+ volumeWorker = new VolumeWorker();
+ }
+
+ public void begin(Action action) {
+ log.trace("WMPApplication begin: " + action);
+ switch (action) {
+ case PLAY:
+ command(18808);
+ break;
+ case NEXT:
+ command(18811);
+ break;
+ case PREVIOUS:
+ command(18810);
+ break;
+ case FORWARD:
+ command(18813);
+ break;
+ case REWIND:
+ command(18812);
+ break;
+ case MUTE:
+ command(18817);
+ break;
+ case VOLUME_UP:
+ volumeWorker.start(1);
+ break;
+ case VOLUME_DOWN:
+ volumeWorker.start(-1);
+ break;
+ case SHUFFLE:
+ command(18842);
+ break;
+ case REPEAT:
+ command(18843);
+ break;
+ }
+ }
+
+ public void end(Action action) {
+ log.trace("WMPApplication end: " + action);
+ switch (action) {
+ case FORWARD:
+ command(18813);
+ break;
+ case REWIND:
+ command(18812);
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ }
+ }
+
+ protected class VolumeWorker extends Worker {
+ protected int volumeChangeSign;
+
+ public void start(int volumeChangeSign) {
+ super.start();
+ this.volumeChangeSign = volumeChangeSign;
+ }
+
+ public void work() {
+ command (volumeChangeSign > 0 ? 18815 : 18816);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+}
diff --git a/java/mimis/src/main/java/mimis/application/itunes/iTunesApplication.java b/java/mimis/src/main/java/mimis/application/itunes/iTunesApplication.java
new file mode 100644
index 0000000..3b3de7f
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/itunes/iTunesApplication.java
@@ -0,0 +1,177 @@
+package mimis.application.itunes;
+
+import mimis.application.Application;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.value.Action;
+import mimis.worker.Component;
+import mimis.worker.Worker;
+
+import com.dt.iTunesController.ITCOMDisabledReason;
+import com.dt.iTunesController.ITTrack;
+import com.dt.iTunesController.iTunes;
+import com.dt.iTunesController.iTunesEventsInterface;
+
+public class iTunesApplication extends Component implements Application, iTunesEventsInterface {
+ protected static final String TITLE = "iTunes";
+ protected static final boolean EVENTS = false;
+
+ protected static final int VOLUME_CHANGE_RATE = 5;
+ protected static final int VOLUME_SLEEP = 100;
+ protected static final String PLAYLIST_LIKE = "Like";
+ protected static final String PLAYLIST_DISLIKE = "Dislike";
+
+ protected iTunes iTunes;
+ protected VolumeWorker volumeWorker;
+ protected boolean events;
+
+ public iTunesApplication() {
+ this(EVENTS);
+ }
+
+ public iTunesApplication(boolean events) {
+ super(TITLE);
+ this.events = events;
+ volumeWorker = new VolumeWorker();
+ }
+
+ protected synchronized void activate() throws ActivateException {
+ iTunes = new iTunes();
+ iTunes.connect();
+ if (events) {
+ iTunes.addEventHandler(this);
+ }
+ super.activate();
+ }
+
+ public synchronized boolean active() {
+ try {
+ iTunes.getMute();
+ active = true;
+ } catch (Exception e) {
+ active = false;
+ }
+ return active;
+ }
+
+ protected synchronized void deactivate() throws DeactivateException {
+ if (events) {
+ exit();
+ } else {
+ super.deactivate();
+ volumeWorker.stop();
+ try {
+ iTunes.release();
+ } catch (Exception e) {
+ log.error(e);
+ throw new DeactivateException();
+ }
+ }
+ }
+
+ public synchronized void exit() {
+ try {
+ iTunes.quit();
+ } catch (Exception e) {}
+ volumeWorker.exit();
+ super.exit();
+ }
+
+ protected void begin(Action action) {
+ log.trace("iTunesApplication begin: " + action);
+ if (!active) return;
+ switch (action) {
+ case FORWARD:
+ iTunes.fastForward();
+ break;
+ case REWIND:
+ iTunes.rewind();
+ break;
+ case VOLUME_UP:
+ volumeWorker.start(VOLUME_CHANGE_RATE);
+ break;
+ case VOLUME_DOWN:
+ volumeWorker.start(-VOLUME_CHANGE_RATE);
+ break;
+ }
+ }
+
+ protected void end(Action action) {
+ log.trace("iTunesApplication end: " + action);
+ if (!active) return;
+ switch (action) {
+ case PLAY:
+ iTunes.playPause();
+ break;
+ case NEXT:
+ iTunes.nextTrack();
+ break;
+ case PREVIOUS:
+ iTunes.previousTrack();
+ break;
+ case FORWARD:
+ iTunes.resume();
+ break;
+ case REWIND:
+ iTunes.resume();
+ break;
+ case MUTE:
+ iTunes.toggleMute();
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ case SHUFFLE:
+ iTunes.toggleShuffle();
+ break;
+ case REPEAT:
+ iTunes.cycleSongRepeat();
+ break;
+ case LIKE:
+ iTunes.playlistAddCurrentTrack(PLAYLIST_LIKE);
+ break;
+ case DISLIKE:
+ iTunes.playlistAddCurrentTrack(PLAYLIST_DISLIKE);
+ break;
+ }
+ }
+
+ protected int getVolume() {
+ return iTunes.getSoundVolume();
+ }
+
+ public void onDatabaseChangedEvent(int[][] deletedObjectIDs, int[][] changedObjectIDs) {}
+ public void onPlayerPlayEvent(ITTrack iTrack) {
+ if (active) {
+ log.trace("iTunesEvent: play");
+ }
+ }
+
+ public void onPlayerStopEvent(ITTrack iTrack) {
+ if (active) {
+ log.trace("iTunesEvent: stop");
+ }
+ }
+
+ public void onPlayerPlayingTrackChangedEvent(ITTrack iTrack) {}
+ public void onCOMCallsDisabledEvent(ITCOMDisabledReason reason) {}
+ public void onCOMCallsEnabledEvent() {}
+ public void onQuittingEvent() {}
+ public void onAboutToPromptUserToQuitEvent() {}
+ public void onSoundVolumeChangedEvent(int newVolume) {}
+
+ protected class VolumeWorker extends Worker {
+ protected int volumeChangeRate;
+
+ public void start(int volumeChangeRate) {
+ super.start();
+ this.volumeChangeRate = volumeChangeRate;
+ }
+
+ public void work() {
+ iTunes.setSoundVolume(getVolume() + volumeChangeRate);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/application/lirc/LircApplication.java b/java/mimis/src/main/java/mimis/application/lirc/LircApplication.java
new file mode 100644
index 0000000..dd4d45e
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/lirc/LircApplication.java
@@ -0,0 +1,42 @@
+package mimis.application.lirc;
+
+import mimis.application.Application;
+import mimis.device.lirc.LircButton;
+import mimis.device.lirc.LircService;
+import mimis.device.lirc.remote.WC02IPOButton;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.worker.Component;
+
+public class LircApplication extends Component implements Application {
+ protected LircService lircService;
+
+ public LircApplication(String title) {
+ super(title);
+ lircService = new LircService();
+ lircService.put(WC02IPOButton.NAME, WC02IPOButton.values());
+ }
+
+ public void activate() throws ActivateException {
+ lircService.activate();
+ super.activate();
+ }
+
+ public boolean active() {
+ return active = lircService.active();
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ lircService.stop();
+ }
+
+ public void exit() {
+ super.exit();
+ lircService.exit();
+ }
+
+ public void send(LircButton button) {
+ lircService.send(button);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/application/lirc/ipod/iPodApplication.java b/java/mimis/src/main/java/mimis/application/lirc/ipod/iPodApplication.java
new file mode 100644
index 0000000..58b758f
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/lirc/ipod/iPodApplication.java
@@ -0,0 +1,86 @@
+package mimis.application.lirc.ipod;
+
+import mimis.application.lirc.LircApplication;
+import mimis.device.lirc.remote.WC02IPOButton;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.value.Action;
+import mimis.worker.Worker;
+
+public class iPodApplication extends LircApplication {
+ protected static final String TITLE = "iPod";
+ protected static final int VOLUME_SLEEP = 100;
+
+ protected VolumeWorker volumeWorker;
+
+ public iPodApplication() {
+ super(TITLE);
+ volumeWorker = new VolumeWorker();
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ volumeWorker.stop();
+ }
+
+ public void exit() {
+ super.exit();
+ volumeWorker.exit();
+ }
+
+ protected void begin(Action action) {
+ log.trace("iPodApplication begin: " + action);
+ if (!active) return;
+ switch (action) {
+ case VOLUME_UP:
+ try {
+ volumeWorker.activate(1);
+ } catch (ActivateException e) {
+ log.error(e);
+ }
+ break;
+ case VOLUME_DOWN:
+ try {
+ volumeWorker.activate(-1);
+ } catch (ActivateException e) {
+ log.error(e);
+ }
+ break;
+ }
+ }
+
+ protected void end(Action action) {
+ log.trace("iPodApplication end: " + action);
+ if (!active) return;
+ switch (action) {
+ case PLAY:
+ send(WC02IPOButton.PLAY);
+ break;
+ case NEXT:
+ send(WC02IPOButton.NEXT);
+ break;
+ case PREVIOUS:
+ send(WC02IPOButton.PREVIOUS);
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ }
+ }
+
+ protected class VolumeWorker extends Worker {
+ protected int volumeChangeRate;
+
+ public void activate(int volumeChangeRate) throws ActivateException {
+ super.activate();
+ this.volumeChangeRate = volumeChangeRate;
+ send(volumeChangeRate > 0 ? WC02IPOButton.PLUS : WC02IPOButton.MINUS);
+ }
+
+ public void work() {
+ lircService.send(WC02IPOButton.HOLD);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/application/mpc/MPCApplication.java b/java/mimis/src/main/java/mimis/application/mpc/MPCApplication.java
new file mode 100644
index 0000000..be2b3c8
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/mpc/MPCApplication.java
@@ -0,0 +1,102 @@
+package mimis.application.mpc;
+
+import mimis.application.cmd.windows.WindowsApplication;
+import mimis.value.Action;
+import mimis.worker.Worker;
+
+public class MPCApplication extends WindowsApplication {
+ protected final static String PROGRAM = "mpc-hc.exe";
+ protected final static String TITLE = "Media Player Classic";
+ protected final static String WINDOW = "MediaPlayerClassicW";
+
+ protected static final int VOLUME_SLEEP = 50;
+ protected static final int SEEK_SLEEP = 50;
+
+ protected VolumeWorker volumeWorker;
+ protected SeekWorker seekWorker;
+
+ public MPCApplication() {
+ super(PROGRAM, TITLE, WINDOW);
+ volumeWorker = new VolumeWorker();
+ seekWorker = new SeekWorker();
+ }
+
+ public void begin(Action action) {
+ log.trace("MPCApplication: " + action);
+ switch (action) {
+ case FORWARD:
+ seekWorker.start(1);
+ break;
+ case REWIND:
+ seekWorker.start(-1);
+ break;
+ case VOLUME_UP:
+ volumeWorker.start(1);
+ break;
+ case VOLUME_DOWN:
+ volumeWorker.start(-1);
+ break;
+ }
+ }
+
+ public void end(Action action) {
+ log.trace("MPCApplication: " + action);
+ switch (action) {
+ case PLAY:
+ command(889);
+ break;
+ case NEXT:
+ command(921);
+ break;
+ case PREVIOUS:
+ command(920);
+ break;
+ case FORWARD:
+ case REWIND:
+ seekWorker.stop();
+ break;
+ case MUTE:
+ command(909);
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ case FULLSCREEN:
+ command(830);
+ break;
+ }
+ }
+
+ public String getTitle() {
+ return TITLE;
+ }
+
+ protected class VolumeWorker extends Worker {
+ protected int volumeChangeSign;
+
+ public void start(int volumeChangeSign) {
+ super.start();
+ this.volumeChangeSign = volumeChangeSign;
+ }
+
+ public void work() {
+ command(volumeChangeSign > 0 ? 907 : 908);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+
+ protected class SeekWorker extends Worker {
+ protected int seekDirection;
+
+ public void start(int seekDirection) {
+ super.start();
+ this.seekDirection = seekDirection;
+ }
+
+ public void work() {
+ command(seekDirection > 0 ? 900 : 889);
+ sleep(SEEK_SLEEP);
+ }
+ };
+}
diff --git a/java/mimis/src/main/java/mimis/application/robot/RobotApplication.java b/java/mimis/src/main/java/mimis/application/robot/RobotApplication.java
new file mode 100644
index 0000000..5fa456b
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/robot/RobotApplication.java
@@ -0,0 +1,35 @@
+package mimis.application.robot;
+
+import java.awt.AWTException;
+import java.awt.Robot;
+
+import mimis.exception.worker.ActivateException;
+import mimis.value.Key;
+import mimis.worker.Component;
+
+public class RobotApplication extends Component {
+ protected Robot robot;
+
+ public void activate() throws ActivateException {
+ try {
+ robot = new Robot();
+ robot.setAutoWaitForIdle(true);
+ } catch (AWTException e) {
+ log.error(e);
+ throw new ActivateException();
+ }
+ super.activate();
+ }
+
+ public void press(Key key) {
+ robot.keyPress(key.getCode());
+ }
+
+ public void press(char key) {
+ robot.keyPress(key);
+ }
+
+ public void release(Key key) {
+ robot.keyRelease(key.getCode());
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/application/vlc/VLCApplication.java b/java/mimis/src/main/java/mimis/application/vlc/VLCApplication.java
new file mode 100644
index 0000000..e04c096
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/application/vlc/VLCApplication.java
@@ -0,0 +1,198 @@
+package mimis.application.vlc;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import mimis.application.cmd.CMDApplication;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.util.Native;
+import mimis.value.Action;
+import mimis.value.Amount;
+import mimis.value.Registry;
+import mimis.worker.Worker;
+
+public class VLCApplication extends CMDApplication {
+ protected final static Registry REGISTRY = Registry.CLASSES_ROOT;
+ protected final static String KEY = "Applications\\vlc.exe\\shell\\Open\\command";
+ protected final static String PROGRAM = "vlc.exe";
+ protected final static String TITLE = "VLC media player";
+
+ protected static final int POSTION_CHANGE_RATE = 1;
+ protected static final int VOLUME_CHANGE_RATE = 20;
+
+ protected static final String HOST = "localhost";
+ protected static final int PORT = 8080;
+
+ protected static final int VOLUME_SLEEP = 100;
+ protected static final int SEEK_SLEEP = 100;
+
+ protected VolumeWorker volumeWorker;
+ protected SeekWorker seekWorker;
+
+ protected int volume = 255;
+ protected boolean muted = false;
+
+ public VLCApplication() {
+ super(PROGRAM, TITLE);
+ volumeWorker = new VolumeWorker();
+ seekWorker = new SeekWorker();
+ }
+
+ public String getPath() {
+ Pattern pattern = Pattern.compile("\"([^\"]+)\"");
+ Matcher matcher = pattern.matcher(Native.getValue(REGISTRY, KEY));
+ return matcher.find() ? matcher.group(1) : null;
+ }
+
+ public void command(String command) {
+ String request = String.format("http://%s:%d/requests/status.xml?command=%s", HOST, PORT, command);
+ try {
+ URL url = new URL(request);
+ HttpURLConnection httpUrlConnection = (HttpURLConnection) url.openConnection();
+ int response = httpUrlConnection.getResponseCode();
+ log.trace("Response: " + response);
+ } catch (MalformedURLException e) {
+ log.error(e);
+ } catch (IOException e) {
+ log.error(e);
+ }
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ volumeWorker.stop();
+ seekWorker.stop();
+ Native.terminate(program);
+ }
+
+ public void exit() {
+ super.exit();
+ volumeWorker.exit();
+ seekWorker.exit();
+ }
+
+ public void begin(Action action) {
+ log.trace("VLCApplication begin: " + action);
+ try {
+ switch (action) {
+ case VOLUME_UP:
+ volumeWorker.activate("+");
+ break;
+ case VOLUME_DOWN:
+ volumeWorker.activate("-");
+ break;
+ case FORWARD:
+ seekWorker.start(Amount.SMALL, "+");
+ break;
+ case REWIND:
+ seekWorker.start(Amount.SMALL, "-");
+ break;
+ }
+ } catch (ActivateException e) {
+ log.error(e);
+ }
+ }
+
+ public void end(Action action) {
+ log.trace("VLCApplication end: " + action);
+ switch (action) {
+ case PLAY:
+ command("pl_pause");
+ break;
+ case PAUSE:
+ command("pl_pause");
+ break;
+ case NEXT:
+ command("pl_next");
+ break;
+ case PREVIOUS:
+ command("pl_previous");
+ break;
+ case FORWARD:
+ case REWIND:
+ seekWorker.stop();
+ break;
+ case MUTE:
+ command("volume&val=" + toggleMute());
+ break;
+ case VOLUME_UP:
+ case VOLUME_DOWN:
+ volumeWorker.stop();
+ break;
+ case SHUFFLE:
+ command("command=pl_random");
+ break;
+ case REPEAT:
+ command("command=pl_repeat");
+ break;
+ }
+ }
+
+ protected void volumeUp() {
+ if (!muted) {
+ volume += VOLUME_CHANGE_RATE;
+ command("volume&val=+" + VOLUME_CHANGE_RATE);
+ }
+ }
+
+ protected void volumeDown() {
+ if (!muted) {
+ volume -= VOLUME_CHANGE_RATE;
+ command("volume&val=-" + VOLUME_CHANGE_RATE);
+ }
+ }
+
+ protected int toggleMute() {
+ return (muted = !muted) ? 0 : volume;
+ }
+
+ public String getTitle() {
+ return TITLE;
+ }
+
+ protected class VolumeWorker extends Worker {
+ protected String volumeChangeSign;
+
+ public void activate(String volumeChangeSign) throws ActivateException {
+ super.activate();
+ this.volumeChangeSign = volumeChangeSign;
+ }
+
+ public void work() {
+ volume += VOLUME_CHANGE_RATE;
+ command("volume&val=" + volumeChangeSign + VOLUME_CHANGE_RATE);
+ sleep(VOLUME_SLEEP);
+ }
+ };
+
+ protected class SeekWorker extends Worker {
+ protected Amount amount;
+ protected String seekDirection;
+
+ public void start(Amount amount, String seekDirection) {
+ super.start();
+ this.amount = amount;
+ this.seekDirection = seekDirection;
+ }
+
+ public void work() {
+ switch (amount) {
+ case SMALL:
+ command("command=seek&val=" + seekDirection + POSTION_CHANGE_RATE);
+ break;
+ case MEDIUM:
+ command("command=seek&val=" + seekDirection + POSTION_CHANGE_RATE * 2);
+ break;
+ case LARGE:
+ command("command=seek&val=" + seekDirection + POSTION_CHANGE_RATE * 3);
+ break;
+ }
+ sleep(SEEK_SLEEP);
+ }
+ };
+}
diff --git a/java/mimis/src/main/java/mimis/device/Device.java b/java/mimis/src/main/java/mimis/device/Device.java
new file mode 100644
index 0000000..4f0cffd
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/Device.java
@@ -0,0 +1,5 @@
+package mimis.device;
+
+public interface Device {
+
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/DirectionButton.java b/java/mimis/src/main/java/mimis/device/javainput/DirectionButton.java
new file mode 100644
index 0000000..7cf7916
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/DirectionButton.java
@@ -0,0 +1,39 @@
+package mimis.device.javainput;
+
+import mimis.input.Button;
+import mimis.exception.button.UnknownDirectionException;
+import de.hardcode.jxinput.event.JXInputDirectionalEvent;
+
+public enum DirectionButton implements Button {
+ NORTH (0),
+ NORTHEAST (45),
+ EAST (90),
+ SOUTHEAST (135),
+ SOUTH (180),
+ SOUTHWEST (225),
+ WEST (270),
+ NORTHWEST (315);
+
+ protected int code;
+
+ private DirectionButton(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public static DirectionButton create(int angle) throws UnknownDirectionException {
+ for (DirectionButton button : DirectionButton.values()) {
+ if (button.getCode() == angle) {
+ return button;
+ }
+ }
+ throw new UnknownDirectionException();
+ }
+
+ public static DirectionButton create(JXInputDirectionalEvent event) throws UnknownDirectionException {
+ return create(event.getDirectional().getDirection() / 100);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/JavaInputDevice.java b/java/mimis/src/main/java/mimis/device/javainput/JavaInputDevice.java
new file mode 100644
index 0000000..8798ac8
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/JavaInputDevice.java
@@ -0,0 +1,85 @@
+package mimis.device.javainput;
+
+import mimis.device.Device;
+import mimis.exception.ButtonException;
+import mimis.exception.button.UnknownButtonException;
+import mimis.exception.button.UnknownDirectionException;
+import mimis.exception.device.DeviceNotFoundException;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.input.Button;
+import mimis.input.state.Press;
+import mimis.input.state.Release;
+import mimis.worker.Component;
+import de.hardcode.jxinput.JXInputDevice;
+import de.hardcode.jxinput.JXInputManager;
+import de.hardcode.jxinput.event.JXInputAxisEvent;
+import de.hardcode.jxinput.event.JXInputButtonEvent;
+import de.hardcode.jxinput.event.JXInputDirectionalEvent;
+
+public abstract class JavaInputDevice extends Component implements Device {
+ protected String name;
+
+ public JavaInputDevice(String title, String name) {
+ super(title);
+ this.name = name;
+ }
+
+ protected JavaInputListener javaInputListener;
+ protected Button previousDirectionalButton;
+
+ protected void activate() throws ActivateException {
+ super.activate();
+ try {
+ JXInputDevice jxinputDevice = getDevice(name);
+ log.debug(jxinputDevice);
+ javaInputListener = new JavaInputListener(this, jxinputDevice);
+ } catch (DeviceNotFoundException e) {
+ active = false;
+ throw new ActivateException();
+ }
+ javaInputListener.start();
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ javaInputListener.stop();
+ }
+
+ public void processEvent(JXInputAxisEvent event) {}
+
+ public void processEvent(JXInputButtonEvent event) throws ButtonException {
+ Button button = getButton(event);
+ if (event.getButton().getState()) {
+ route(new Press(button));
+ } else {
+ route(new Release(button));
+ }
+ }
+
+ public void processEvent(JXInputDirectionalEvent event) throws UnknownDirectionException {
+ Button button = getButton(event);
+ if (event.getDirectional().isCentered()) {
+ if (previousDirectionalButton != null) {
+ route(new Release(previousDirectionalButton));
+ }
+ } else {
+ route(new Press(button));
+ previousDirectionalButton = button;
+ }
+ }
+
+ protected abstract Button getButton(JXInputButtonEvent event) throws UnknownButtonException;
+ protected abstract Button getButton(JXInputDirectionalEvent event) throws UnknownDirectionException;
+
+ public static JXInputDevice getDevice(String name) throws DeviceNotFoundException {
+ int numberOfDevices = JXInputManager.getNumberOfDevices();
+ for (int i = 0; i < numberOfDevices; ++i) {
+ JXInputDevice device = JXInputManager.getJXInputDevice(i);
+ if (device.getName().startsWith(name)) {
+ return device;
+ }
+ }
+ throw new DeviceNotFoundException();
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/JavaInputListener.java b/java/mimis/src/main/java/mimis/device/javainput/JavaInputListener.java
new file mode 100644
index 0000000..e771cd4
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/JavaInputListener.java
@@ -0,0 +1,85 @@
+package mimis.device.javainput;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import mimis.exception.ButtonException;
+import mimis.worker.Worker;
+import de.hardcode.jxinput.Button;
+import de.hardcode.jxinput.Directional;
+import de.hardcode.jxinput.JXInputDevice;
+import de.hardcode.jxinput.JXInputManager;
+import de.hardcode.jxinput.event.JXInputAxisEvent;
+import de.hardcode.jxinput.event.JXInputAxisEventListener;
+import de.hardcode.jxinput.event.JXInputButtonEvent;
+import de.hardcode.jxinput.event.JXInputButtonEventListener;
+import de.hardcode.jxinput.event.JXInputDirectionalEvent;
+import de.hardcode.jxinput.event.JXInputDirectionalEventListener;
+import de.hardcode.jxinput.event.JXInputEventManager;
+
+public class JavaInputListener extends Worker implements Runnable, JXInputAxisEventListener, JXInputButtonEventListener, JXInputDirectionalEventListener {
+ protected JavaInputDevice javaInputDevice;
+ protected JXInputDevice jxinputDevice;
+ protected Queue axisEventQueue;
+ protected Queue buttonEventQueue;
+ protected Queue directionalEventQueue;
+
+ public JavaInputListener(JavaInputDevice javaInputDevice, JXInputDevice jxinputDevice) {
+ this.javaInputDevice = javaInputDevice;
+ this.jxinputDevice = jxinputDevice;
+ axisEventQueue = new LinkedList();
+ buttonEventQueue = new LinkedList();
+ directionalEventQueue = new LinkedList();
+ addListeners();
+ }
+
+ protected void addListeners() {
+ /*for (int i = 0; i < jxinputDevice.getMaxNumberOfAxes(); ++i) {
+ Axis axis = jxinputDevice.getAxis(i);
+ if (axis != null) {
+ JXInputEventManager.addListener(this, axis);
+ }
+ }*/
+ for (int i = 0; i < jxinputDevice.getMaxNumberOfButtons(); ++i) {
+ Button button = jxinputDevice.getButton(i);
+ if (button != null) {
+ JXInputEventManager.addListener(this, button);
+ }
+ }
+ for (int i = 0; i < jxinputDevice.getMaxNumberOfDirectionals(); ++i) {
+ Directional directional = jxinputDevice.getDirectional(i);
+ if (directional != null) {
+ JXInputEventManager.addListener(this, directional);
+ }
+ }
+ }
+
+ public void changed(JXInputAxisEvent event) {
+ axisEventQueue.add(event);
+ }
+
+ public void changed(JXInputButtonEvent event) {
+ buttonEventQueue.add(event);
+ }
+
+ public void changed(JXInputDirectionalEvent event) {
+ directionalEventQueue.add(event);
+ }
+
+ public void work() {
+ JXInputManager.updateFeatures();
+ if (!axisEventQueue.isEmpty()) {
+ javaInputDevice.processEvent(axisEventQueue.poll());
+ } else if (!buttonEventQueue.isEmpty()) {
+ try {
+ javaInputDevice.processEvent(buttonEventQueue.poll());
+ } catch (ButtonException e) {}
+ } else if (!directionalEventQueue.isEmpty()) {
+ try {
+ javaInputDevice.processEvent(directionalEventQueue.poll());
+ } catch (ButtonException e) {}
+ } else {
+ sleep();
+ }
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DButton.java b/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DButton.java
new file mode 100644
index 0000000..90a5d7f
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DButton.java
@@ -0,0 +1,43 @@
+package mimis.device.javainput.extreme3d;
+
+import mimis.exception.button.UnknownButtonException;
+import mimis.input.Button;
+import de.hardcode.jxinput.event.JXInputButtonEvent;
+
+public enum Extreme3DButton implements Button {
+ ONE ("Button 0"),
+ TWO ("Button 1"),
+ THREE ("Button 2"),
+ FOUR ("Button 3"),
+ FIVE ("Button 4"),
+ SIX ("Button 5"),
+ SEVEN ("Button 6"),
+ EIGHT ("Button 7"),
+ NINE ("Button 8"),
+ TEN ("Button 9"),
+ ELEVEN ("Button 10"),
+ TWELVE ("Button 11");
+
+ protected String code;
+
+ private Extreme3DButton(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public static Extreme3DButton create(String code) throws UnknownButtonException {
+ for (Extreme3DButton button : Extreme3DButton.values()) {
+ if (button.getCode().equals(code)) {
+ return button;
+ }
+ }
+ throw new UnknownButtonException();
+ }
+
+ public static Extreme3DButton create(JXInputButtonEvent event) throws UnknownButtonException {
+ return create(event.getButton().getName());
+ }
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DDevice.java b/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DDevice.java
new file mode 100644
index 0000000..d0654a4
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DDevice.java
@@ -0,0 +1,38 @@
+package mimis.device.javainput.extreme3d;
+
+import mimis.device.javainput.DirectionButton;
+import mimis.device.javainput.JavaInputDevice;
+import mimis.exception.button.UnknownButtonException;
+import mimis.exception.button.UnknownDirectionException;
+import mimis.exception.worker.ActivateException;
+import mimis.input.Button;
+import mimis.value.Action;
+import de.hardcode.jxinput.event.JXInputButtonEvent;
+import de.hardcode.jxinput.event.JXInputDirectionalEvent;
+
+public class Extreme3DDevice extends JavaInputDevice {
+ protected static final String TITLE = "Extreme 3D";
+ protected static final String NAME = "Logitech Extreme 3D";
+
+ protected static Extreme3DTaskMapCycle taskMapCycle;
+
+ public Extreme3DDevice() {
+ super(TITLE, NAME);
+ taskMapCycle = new Extreme3DTaskMapCycle();
+ }
+
+ protected void activate() throws ActivateException {
+ super.activate();
+ parser(Action.ADD, taskMapCycle.mimis);
+ parser(Action.ADD, taskMapCycle.player);
+ parser(Action.ADD, taskMapCycle.like);
+ }
+
+ protected Button getButton(JXInputButtonEvent event) throws UnknownButtonException {
+ return Extreme3DButton.create(event);
+ }
+
+ protected Button getButton(JXInputDirectionalEvent event) throws UnknownDirectionException {
+ return DirectionButton.create(event);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DTaskMapCycle.java b/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DTaskMapCycle.java
new file mode 100644
index 0000000..8e0eb54
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/extreme3d/Extreme3DTaskMapCycle.java
@@ -0,0 +1,70 @@
+package mimis.device.javainput.extreme3d;
+
+import mimis.device.javainput.DirectionButton;
+import mimis.input.Task;
+import mimis.input.state.Press;
+import mimis.state.TaskMap;
+import mimis.state.TaskMapCycle;
+import mimis.value.Action;
+import mimis.value.Target;
+
+public class Extreme3DTaskMapCycle extends TaskMapCycle {
+ protected static final long serialVersionUID = 1L;
+
+ public TaskMap mimis, player, like;
+
+ public Extreme3DTaskMapCycle() {
+ /* Mimis */
+ mimis = new TaskMap();
+ mimis.add(
+ new Press(Extreme3DButton.SEVEN),
+ new Task(Action.PREVIOUS, Target.MAIN));
+ mimis.add(
+ new Press(Extreme3DButton.EIGHT),
+ new Task(Action.NEXT, Target.MAIN));
+ add(mimis);
+
+ /* Player */
+ player = new TaskMap();
+ player.add(
+ new Press(Extreme3DButton.ONE),
+ new Task(Action.PLAY, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.TWO),
+ new Task(Action.MUTE, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.NINE),
+ new Task(Action.SHUFFLE, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.TEN),
+ new Task(Action.REPEAT, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.SIX),
+ new Task(Action.NEXT, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.FOUR),
+ new Task(Action.PREVIOUS, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.FIVE),
+ new Task(Action.FORWARD, Target.CURRENT));
+ player.add(
+ new Press(Extreme3DButton.THREE),
+ new Task(Action.REWIND, Target.CURRENT));
+ player.add(
+ new Press(DirectionButton.SOUTH),
+ new Task(Action.VOLUME_DOWN, Target.CURRENT));
+ player.add(
+ new Press(DirectionButton.NORTH),
+ new Task(Action.VOLUME_UP, Target.CURRENT));
+ add(player);
+
+ like = new TaskMap();
+ like.add(
+ new Press(Extreme3DButton.ELEVEN),
+ new Task(Action.LIKE, Target.CURRENT));
+ like.add(
+ new Press(Extreme3DButton.TWELVE),
+ new Task(Action.DISLIKE, Target.CURRENT));
+ add(like);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadButton.java b/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadButton.java
new file mode 100644
index 0000000..65d8851
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadButton.java
@@ -0,0 +1,41 @@
+package mimis.device.javainput.rumblepad;
+
+import mimis.exception.button.UnknownButtonException;
+import mimis.input.Button;
+import de.hardcode.jxinput.event.JXInputButtonEvent;
+
+public enum RumblepadButton implements Button {
+ ONE ("Button 0"),
+ TWO ("Button 1"),
+ THREE ("Button 2"),
+ FOUR ("Button 3"),
+ FIVE ("Button 4"),
+ SIX ("Button 5"),
+ SEVEN ("Button 6"),
+ EIGHT ("Button 7"),
+ NINE ("Button 8"),
+ TEN ("Button 9");
+
+ protected String code;
+
+ private RumblepadButton(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return code;
+ }
+
+ public static RumblepadButton create(String code) throws UnknownButtonException {
+ for (RumblepadButton button : RumblepadButton.values()) {
+ if (button.getCode().equals(code)) {
+ return button;
+ }
+ }
+ throw new UnknownButtonException();
+ }
+
+ public static RumblepadButton create(JXInputButtonEvent event) throws UnknownButtonException {
+ return create(event.getButton().getName());
+ }
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadDevice.java b/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadDevice.java
new file mode 100644
index 0000000..5d03046
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadDevice.java
@@ -0,0 +1,38 @@
+package mimis.device.javainput.rumblepad;
+
+import mimis.device.javainput.DirectionButton;
+import mimis.device.javainput.JavaInputDevice;
+import mimis.exception.button.UnknownButtonException;
+import mimis.exception.button.UnknownDirectionException;
+import mimis.exception.worker.ActivateException;
+import mimis.input.Button;
+import mimis.value.Action;
+import de.hardcode.jxinput.event.JXInputButtonEvent;
+import de.hardcode.jxinput.event.JXInputDirectionalEvent;
+
+public class RumblepadDevice extends JavaInputDevice {
+ protected static final String TITLE = "RumblePad";
+ protected static final String NAME = "Logitech RumblePad 2 USB";
+
+ protected static RumblepadTaskMapCycle taskMapCycle;
+
+ public RumblepadDevice() {
+ super(TITLE, NAME);
+ taskMapCycle = new RumblepadTaskMapCycle();
+ }
+
+ protected void activate() throws ActivateException {
+ super.activate();
+ parser(Action.ADD, taskMapCycle.mimis);
+ parser(Action.ADD, taskMapCycle.player);
+ parser(Action.ADD, taskMapCycle.like);
+ }
+
+ protected Button getButton(JXInputButtonEvent event) throws UnknownButtonException {
+ return RumblepadButton.create(event);
+ }
+
+ protected Button getButton(JXInputDirectionalEvent event) throws UnknownDirectionException {
+ return DirectionButton.create(event);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadTaskMapCycle.java b/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadTaskMapCycle.java
new file mode 100644
index 0000000..a66f244
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/javainput/rumblepad/RumblepadTaskMapCycle.java
@@ -0,0 +1,70 @@
+package mimis.device.javainput.rumblepad;
+
+import mimis.device.javainput.DirectionButton;
+import mimis.input.Task;
+import mimis.input.state.Press;
+import mimis.state.TaskMap;
+import mimis.state.TaskMapCycle;
+import mimis.value.Action;
+import mimis.value.Target;
+
+public class RumblepadTaskMapCycle extends TaskMapCycle {
+ protected static final long serialVersionUID = 1L;
+
+ public TaskMap mimis, player, like;
+
+ public RumblepadTaskMapCycle() {
+ /* Mimis */
+ mimis = new TaskMap();
+ mimis.add(
+ new Press(RumblepadButton.ONE),
+ new Task(Action.PREVIOUS, Target.MAIN));
+ mimis.add(
+ new Press(RumblepadButton.THREE),
+ new Task(Action.NEXT, Target.MAIN));
+ add(mimis);
+
+ /* Player */
+ player = new TaskMap();
+ player.add(
+ new Press(DirectionButton.WEST),
+ new Task(Action.PLAY, Target.CURRENT));
+ player.add(
+ new Press(DirectionButton.EAST),
+ new Task(Action.MUTE, Target.CURRENT));
+ player.add(
+ new Press(RumblepadButton.NINE),
+ new Task(Action.SHUFFLE, Target.CURRENT));
+ player.add(
+ new Press(RumblepadButton.TEN),
+ new Task(Action.REPEAT, Target.CURRENT));
+ player.add(
+ new Press(RumblepadButton.EIGHT),
+ new Task(Action.NEXT, Target.CURRENT));
+ player.add(
+ new Press(RumblepadButton.SIX),
+ new Task(Action.PREVIOUS, Target.CURRENT));
+ player.add(
+ new Press(RumblepadButton.SEVEN),
+ new Task(Action.FORWARD, Target.CURRENT));
+ player.add(
+ new Press(RumblepadButton.FIVE),
+ new Task(Action.REWIND, Target.CURRENT));
+ player.add(
+ new Press(DirectionButton.SOUTH),
+ new Task(Action.VOLUME_DOWN, Target.CURRENT));
+ player.add(
+ new Press(DirectionButton.NORTH),
+ new Task(Action.VOLUME_UP, Target.CURRENT));
+ add(player);
+
+ like = new TaskMap();
+ like.add(
+ new Press(RumblepadButton.FOUR),
+ new Task(Action.LIKE, Target.CURRENT));
+ like.add(
+ new Press(RumblepadButton.TWO),
+ new Task(Action.DISLIKE, Target.CURRENT));
+ add(like);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/jintellitype/CommandButton.java b/java/mimis/src/main/java/mimis/device/jintellitype/CommandButton.java
new file mode 100644
index 0000000..734de34
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/jintellitype/CommandButton.java
@@ -0,0 +1,74 @@
+package mimis.device.jintellitype;
+
+import mimis.exception.button.UnknownButtonException;
+import mimis.input.Button;
+
+import com.melloware.jintellitype.JIntellitype;
+
+
+public enum CommandButton implements Button {
+ BROWSER_BACKWARD (JIntellitype.APPCOMMAND_BROWSER_BACKWARD),
+ BROWSER_FORWARD (JIntellitype.APPCOMMAND_BROWSER_FORWARD),
+ BROWSER_REFRESH (JIntellitype.APPCOMMAND_BROWSER_REFRESH),
+ BROWSER_STOP (JIntellitype.APPCOMMAND_BROWSER_STOP),
+ BROWSER_SEARCH (JIntellitype.APPCOMMAND_BROWSER_SEARCH),
+ BROWSER_FAVOURITES (JIntellitype.APPCOMMAND_BROWSER_FAVOURITES),
+ BROWSER_HOME (JIntellitype.APPCOMMAND_BROWSER_HOME),
+ VOLUME_MUTE (JIntellitype.APPCOMMAND_VOLUME_MUTE),
+ VOLUME_DOWN (JIntellitype.APPCOMMAND_VOLUME_DOWN),
+ VOLUME_UP (JIntellitype.APPCOMMAND_VOLUME_UP),
+ MEDIA_NEXTTRACK (JIntellitype.APPCOMMAND_MEDIA_NEXTTRACK),
+ MEDIA_PREVIOUSTRACK (JIntellitype.APPCOMMAND_MEDIA_PREVIOUSTRACK),
+ MEDIA_STOP (JIntellitype.APPCOMMAND_MEDIA_STOP),
+ MEDIA_PLAY_PAUSE (JIntellitype.APPCOMMAND_MEDIA_PLAY_PAUSE),
+ LAUNCH_MAIL (JIntellitype.APPCOMMAND_LAUNCH_MAIL),
+ LAUNCH_MEDIA_SELECT (JIntellitype.APPCOMMAND_LAUNCH_MEDIA_SELECT),
+ LAUNCH_APP1 (JIntellitype.APPCOMMAND_LAUNCH_APP1),
+ LAUNCH_APP2 (JIntellitype.APPCOMMAND_LAUNCH_APP2),
+ BASS_DOWN (JIntellitype.APPCOMMAND_BASS_DOWN),
+ BASS_BOOST (JIntellitype.APPCOMMAND_BASS_BOOST),
+ BASS_UP (JIntellitype.APPCOMMAND_BASS_UP),
+ TREBLE_DOWN (JIntellitype.APPCOMMAND_TREBLE_DOWN),
+ TREBLE_UP (JIntellitype.APPCOMMAND_TREBLE_UP),
+ MICROPHONE_VOLUME_MUTE (JIntellitype.APPCOMMAND_MICROPHONE_VOLUME_MUTE),
+ MICROPHONE_VOLUME_DOWN (JIntellitype.APPCOMMAND_MICROPHONE_VOLUME_DOWN),
+ MICROPHONE_VOLUME_UP (JIntellitype.APPCOMMAND_MICROPHONE_VOLUME_UP),
+ HELP (JIntellitype.APPCOMMAND_HELP),
+ FIND (JIntellitype.APPCOMMAND_FIND),
+ NEW (JIntellitype.APPCOMMAND_NEW),
+ OPEN (JIntellitype.APPCOMMAND_OPEN),
+ CLOSE (JIntellitype.APPCOMMAND_CLOSE),
+ SAVE (JIntellitype.APPCOMMAND_SAVE),
+ PRINT (JIntellitype.APPCOMMAND_PRINT),
+ UNDO (JIntellitype.APPCOMMAND_UNDO),
+ REDO (JIntellitype.APPCOMMAND_REDO),
+ COPY (JIntellitype.APPCOMMAND_COPY),
+ CUT (JIntellitype.APPCOMMAND_CUT),
+ PASTE (JIntellitype.APPCOMMAND_PASTE),
+ REPLY_TO_MAIL (JIntellitype.APPCOMMAND_REPLY_TO_MAIL),
+ FORWARD_MAIL (JIntellitype.APPCOMMAND_FORWARD_MAIL),
+ SEND_MAIL (JIntellitype.APPCOMMAND_SEND_MAIL),
+ SPELL_CHECK (JIntellitype.APPCOMMAND_SPELL_CHECK),
+ DICTATE_OR_COMMAND_CONTROL_TOGGLE (JIntellitype.APPCOMMAND_DICTATE_OR_COMMAND_CONTROL_TOGGLE),
+ MIC_ON_OFF_TOGGLE (JIntellitype.APPCOMMAND_MIC_ON_OFF_TOGGLE),
+ CORRECTION_LIST (JIntellitype.APPCOMMAND_CORRECTION_LIST);
+
+ protected int code;
+
+ private CommandButton(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public static CommandButton create(int code) throws UnknownButtonException {
+ for (CommandButton button : CommandButton.values()) {
+ if (button.getCode() == code) {
+ return button;
+ }
+ }
+ throw new UnknownButtonException();
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/jintellitype/Hotkey.java b/java/mimis/src/main/java/mimis/device/jintellitype/Hotkey.java
new file mode 100644
index 0000000..08846c5
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/jintellitype/Hotkey.java
@@ -0,0 +1,46 @@
+package mimis.device.jintellitype;
+
+import java.util.ArrayList;
+
+import mimis.input.Button;
+import mimis.value.Key;
+
+import com.melloware.jintellitype.JIntellitype;
+
+public class Hotkey implements Button {
+ protected static final long serialVersionUID = 1L;
+
+ protected static ArrayList hotkeyList;
+ protected static JIntellitype jit;
+
+ public Hotkey(int modifier, int keycode) {
+ int id = hotkeyList.size();
+ jit.registerHotKey(id, modifier, keycode);
+ hotkeyList.add(this);
+ }
+
+ public Hotkey(int modifier, char character) {
+ this(modifier, (int) Character.toUpperCase(character));
+ }
+
+ public Hotkey(char character) {
+ this(0, (int) Character.toUpperCase(character));
+ }
+
+ public Hotkey(int keycode) {
+ this(0, keycode);
+ }
+
+ public Hotkey(Key key) {
+ this(key.getCode());
+ }
+
+ public Hotkey(int modifier, Key key) {
+ this(modifier, key.getCode());
+ }
+
+ public static void initialise(ArrayList actionList, JIntellitype jit) {
+ Hotkey.hotkeyList = actionList;
+ Hotkey.jit = jit;
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/jintellitype/JIntellitypeDevice.java b/java/mimis/src/main/java/mimis/device/jintellitype/JIntellitypeDevice.java
new file mode 100644
index 0000000..92ae185
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/jintellitype/JIntellitypeDevice.java
@@ -0,0 +1,71 @@
+package mimis.device.jintellitype;
+
+import java.util.ArrayList;
+
+import mimis.device.Device;
+import mimis.exception.button.UnknownButtonException;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.input.state.Press;
+import mimis.input.state.Release;
+import mimis.value.Action;
+import mimis.worker.Component;
+
+import com.melloware.jintellitype.HotkeyListener;
+import com.melloware.jintellitype.IntellitypeListener;
+import com.melloware.jintellitype.JIntellitype;
+
+public class JIntellitypeDevice extends Component implements Device, HotkeyListener, IntellitypeListener {
+ protected static final String TITLE = "Keyboard";
+
+ protected JIntellitypeTaskMapCycle taskMapCycle;
+ protected ArrayList hotkeyList;
+ protected JIntellitype jit;
+
+ public JIntellitypeDevice() {
+ super(TITLE);
+ hotkeyList = new ArrayList();
+ jit = JIntellitype.getInstance();
+ Hotkey.initialise(hotkeyList, jit);
+ taskMapCycle = new JIntellitypeTaskMapCycle();
+ }
+
+ protected void activate() throws ActivateException {
+ super.activate();
+ jit.addHotKeyListener(this);
+ jit.addIntellitypeListener(this);
+ parser(Action.ADD, taskMapCycle.mimis);
+ parser(Action.ADD, taskMapCycle.player);
+ }
+
+ public void onIntellitype(int command) {
+ if (active) {
+ try {
+ CommandButton commandButton = CommandButton.create(command);
+ route(new Press(commandButton));
+ route(new Release(commandButton));
+ } catch (UnknownButtonException e) {
+ log.error(e);
+ }
+ }
+ }
+
+ public void onHotKey(int id) {
+ if (active) {
+ Hotkey hotkey = hotkeyList.get(id);
+ route(new Press(hotkey));
+ route(new Release(hotkey));
+ }
+ }
+
+ protected void deactivate() throws DeactivateException {
+ super.deactivate();
+ jit.removeHotKeyListener(this);
+ jit.removeIntellitypeListener(this);
+ }
+
+ public void exit() {
+ super.exit();
+ jit.cleanUp();
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/jintellitype/JIntellitypeTaskMapCycle.java b/java/mimis/src/main/java/mimis/device/jintellitype/JIntellitypeTaskMapCycle.java
new file mode 100644
index 0000000..ac30c74
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/jintellitype/JIntellitypeTaskMapCycle.java
@@ -0,0 +1,45 @@
+package mimis.device.jintellitype;
+
+import mimis.input.Task;
+import mimis.state.TaskMap;
+import mimis.state.TaskMapCycle;
+import mimis.value.Action;
+import mimis.value.Key;
+import mimis.value.Target;
+
+public class JIntellitypeTaskMapCycle extends TaskMapCycle {
+ protected static final long serialVersionUID = 1L;
+
+ public TaskMap mimis, player;
+
+ public JIntellitypeTaskMapCycle() {
+ /* Mimis */
+ mimis = new TaskMap();
+ mimis.add(
+ new Hotkey(Key.PRIOR),
+ new Task(Action.PREVIOUS, Target.MAIN));
+ mimis.add(
+ new Hotkey(Key.NEXT),
+ new Task(Action.NEXT, Target.MAIN));
+ add(mimis);
+
+ /* Player */
+ player = new TaskMap();
+ player.add(
+ CommandButton.VOLUME_DOWN,
+ new Task(Action.VOLUME_DOWN, Target.APPLICATIONS));
+ player.add(
+ CommandButton.VOLUME_UP,
+ new Task(Action.VOLUME_UP, Target.APPLICATIONS));
+ player.add(
+ new Hotkey(Modifier.CTRL | Modifier.WIN, 'x'),
+ new Task(Action.EXIT, Target.MAIN));
+ player.add(
+ new Hotkey(Modifier.CTRL | Modifier.SHIFT | Modifier.WIN, 'n'),
+ new Task(Action.NEXT, Target.CURRENT));
+ player.add(
+ new Hotkey(Modifier.CTRL | Modifier.SHIFT | Modifier.WIN, 'p'),
+ new Task(Action.PREVIOUS, Target.CURRENT));
+ add(player);
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/jintellitype/Modifier.java b/java/mimis/src/main/java/mimis/device/jintellitype/Modifier.java
new file mode 100644
index 0000000..ca64f51
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/jintellitype/Modifier.java
@@ -0,0 +1,25 @@
+package mimis.device.jintellitype;
+
+import mimis.input.Button;
+
+import com.melloware.jintellitype.JIntellitype;
+
+public class Modifier implements Button {
+ protected static final long serialVersionUID = 1L;
+
+ public static final int
+ ALT = JIntellitype.MOD_ALT,
+ CTRL = JIntellitype.MOD_CONTROL,
+ SHIFT = JIntellitype.MOD_SHIFT,
+ WIN = JIntellitype.MOD_WIN;
+
+ protected int code;
+
+ protected Modifier(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+}
diff --git a/java/mimis/src/main/java/mimis/device/lirc/LircButton.java b/java/mimis/src/main/java/mimis/device/lirc/LircButton.java
new file mode 100644
index 0000000..5e18d4f
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/lirc/LircButton.java
@@ -0,0 +1,10 @@
+package mimis.device.lirc;
+
+import mimis.input.Button;
+
+public interface LircButton extends Button {
+ public static final String NAME = null;
+
+ public String getCode();
+ public String getName();
+}
diff --git a/java/mimis/src/main/java/mimis/device/lirc/LircButtonListener.java b/java/mimis/src/main/java/mimis/device/lirc/LircButtonListener.java
new file mode 100644
index 0000000..3927f7e
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/lirc/LircButtonListener.java
@@ -0,0 +1,5 @@
+package mimis.device.lirc;
+
+public interface LircButtonListener {
+ public void add(LircButton lircButton);
+}
\ No newline at end of file
diff --git a/java/mimis/src/main/java/mimis/device/lirc/LircDevice.java b/java/mimis/src/main/java/mimis/device/lirc/LircDevice.java
new file mode 100644
index 0000000..a09cb4e
--- /dev/null
+++ b/java/mimis/src/main/java/mimis/device/lirc/LircDevice.java
@@ -0,0 +1,108 @@
+package mimis.device.lirc;
+
+import mimis.application.cmd.CMDApplication;
+import mimis.device.Device;
+import mimis.device.lirc.remote.DenonRC176Button;
+import mimis.device.lirc.remote.PhiliphsRCLE011Button;
+import mimis.device.lirc.remote.SamsungBN5901015AButton;
+import mimis.exception.worker.ActivateException;
+import mimis.exception.worker.DeactivateException;
+import mimis.input.Button;
+import mimis.input.button.ColorButton;
+import mimis.input.button.NumberButton;
+import mimis.input.state.Press;
+import mimis.input.state.Release;
+import mimis.util.Multiplexer;
+import mimis.util.Native;
+import mimis.util.multiplexer.SignalListener;
+import mimis.value.Action;
+import mimis.value.Signal;
+
+public class LircDevice extends CMDApplication implements Device, LircButtonListener, SignalListener