Wednesday, December 28, 2016

Create a Youtube metadata crawler using Java

This blog post will extract metadata information from youtube using Java. It makes use of JSoup library.

Youtube Video Metadata Crawled:
1) Comments
2) Likes/Dislikes
3) Number of user subscribed
4) Video Title
5) Number of views for video
6) Video Description

Language Used:
Java

POM Dependency:
  <dependency>  
       <groupId>org.jsoup</groupId>  
       <artifactId>jsoup</artifactId>  
       <version>1.8.3</version>  
  </dependency>  

Git Repo:
https://github.com/csanuragjain/extra/tree/master/YoutubeMetadataExtractor

Program:

main Method:
      public static void main(String[] args) {  
           String link="";  
           Scanner s=new Scanner(System.in);  
           // TODO Auto-generated method stub  
           try {  
                System.out.println("Enter the youtube video for which metadata need to be extracted");  
                link=s.nextLine();  
                Document doc = Jsoup.connect(link).ignoreContentType(true).timeout(5000).get();  
                YoutubeMetadataCrawler ymc=new YoutubeMetadataCrawler();  
                String title=ymc.getTitle(doc);  
                String desc=ymc.getDesc(doc);  
                String views=ymc.getViews(doc);  
                String subscribed=ymc.getPeopleSubscribed(doc);  
                int liked=ymc.getPeopleLiked(doc);  
                int disliked=ymc.getPeopleDisliked(doc);  
                String vid=ymc.getVideoId(link);  
                List<String> comments=ymc.getCommentsDesc(link,vid);  
                System.out.println(title);  
                System.out.println(desc);  
                System.out.println("Video Views: \n"+views);  
                System.out.println("People subscribed: \n"+subscribed);  
                System.out.println("People who liked the video: \n"+liked);  
                System.out.println("People who disliked the video: \n"+disliked);  
                System.out.println("Top Comments: ");  
                int i=0;  
                for(String comment:comments)  
                {  
                     System.out.println(++i+") "+comment);  
                }  
           } catch (IOException e) {  
                System.out.println("JSoup is unable to connect to the website");  
           }  
           finally  
           {  
                s.close();  
           }  
      }  

How it works:
1) We use the scanner object to obtain the youtube video url from user
2) We use JSOUP to connect to youtube video
3) We call the several modules for obtaining title, comments, title, description, likes etc and print the same to user.

removeUTFCharacters method:
      public static String removeUTFCharacters(String data){  
           Pattern p = Pattern.compile("\\\\u(\\p{XDigit}{4})");  
           Matcher m = p.matcher(data);  
           StringBuffer buf = new StringBuffer(data.length());  
           while (m.find()) {  
           String ch = String.valueOf((char) Integer.parseInt(m.group(1), 16));  
           m.appendReplacement(buf, Matcher.quoteReplacement(ch));  
           }  
           m.appendTail(buf);  
           return new String(buf);  
           }  

How it works:
1) This module removes the UTF characters.
2) It tries to find if any unicode character is present in the string passed.
3) If it finds any unicode character then it will replace it will its corresponding string

getCommentToken method:
      public String getCommentToken(Response res)  
      {  
           String pageSource=res.body();  
           String commentToken=pageSource=pageSource.substring(pageSource.indexOf("COMMENTS_TOKEN': \"")+18);  
           commentToken=commentToken.substring(0,commentToken.indexOf("\""));  
           commentToken=commentToken.replaceAll("%", "%25");  
           return commentToken;  
      }  

How it works:
1) If you open any youtube video, you will find below token in page source which is used by youtube for extracting comments.
 'COMMENTS_TOKEN': "SOME_TOKEN",  
2) We obtain a response object as argument. This contains the response details when user provided youtube video is opened.
3)  In our module, first we obtain the page source of the youtube video page by calling body method over the response object obtained as argument.
4) Now we search for the text COMMENTS_TOKEN': " in the page source and extract the string upto ". This will extract the comment token.
5) Comment token is returned.


getSessionToken method:
 public String getSessionToken(Response res)  
      {  
           String pageSource=res.body();  
           String xsrfToken=pageSource=pageSource.substring(pageSource.indexOf("XSRF_TOKEN': \"")+14);  
           xsrfToken=xsrfToken.substring(0,xsrfToken.indexOf("\""));  
           return xsrfToken;  
      }  

How it works:
1) If you open any youtube video, you will find below token in page source which is used by youtube for csrf protection.
 'XSRF_TOKEN':"SOME_TOKEN",  
2) We obtain a response object as argument. This contains the response details when user provided youtube video is opened.
3)  In our module, first we obtain the page source of the youtube video page by calling body method over the response object obtained as argument.
4) Now we search for the text 'XSRF_TOKEN':" in the page source and extract the string upto ". This will extract the xsrf token.
5) XSRF token is returned.

getVideoId method:
 public String getVideoId(String url)  
      {  
           url=url.substring(url.indexOf("v=")+2);  
           if(url.contains("?"))  
           {  
                url=url.substring(0,url.indexOf("?"));  
           }  
           return url;  
      }  

How it works:
1) Youtube url contains a param named v which contains the video id
2) We find the location of word v= and extract its value and return the same.

getTitle method:
 public String getTitle(Document doc)  
      {  
           return doc.select("#eow-title").text();  
      }  

How it works:
1) Youtube video contains the video title in HTML element with id as eow-title
 <span id="eow-title" class="watch-title" dir="ltr" title="Dangal | Official Trailer | Aamir Khan | In Cinemas Dec 23, 2016">  
   Dangal | Official Trailer | Aamir Khan | In Cinemas Dec 23, 2016  
  </span>  
2) Document object contains the document detail of the youtube video.
3) We use the document object to find the text from the HTML tag containing id as eow-title
4) We return the title

getViews method:
 public String getViews(Document doc)  
      {  
           return doc.select(".watch-view-count").text();  
      }  

How it works:
1) Youtube video contains the video views in HTML element with class as watch-view-count
 <div class="watch-view-count">40,095,041 views</div>  
2) Document object contains the document detail of the youtube video.
3) We use the document object to find the text from the HTML tag containing class as watch-view-count
4) We return the views

getDesc method:
 public String getDesc(Document doc)  
      {  
           return doc.select("#watch-description-clip").text();  
      }  

How it works:
1) Youtube video contains the video description in HTML element with id as watch-description-clip
 <div id="watch-description-clip"><div id="watch-uploader-info"><strong class="watch-time-text">Some description  
2) Document object contains the document detail of the youtube video.
3) We use the document object to find the text from the HTML tag containing id as watch-description-clip
4) We return the video description

getPeopleSubscribed method:
 public int getPeopleSubscribed(Document doc)  
      {  
           return doc.select(".yt-subscriber-count").text().replace(",", "");  
      }  

How it works:
1) Youtube video contains the user subscribed in HTML element with class as yt-subscriber-count
 <span class="yt-subscription-button-subscriber-count-branded-horizontal yt-subscriber-count" title="1,057,873" aria-label="1,057,873" tabindex="0">1,057,873</span>  
2) Document object contains the document detail of the youtube video.
3) We use the document object to find the text from the HTML tag containing class as yt-subscriber-count
4) We return the video subscription count

getPeopleLiked method:
 public int getPeopleLiked(Document doc)  
      {  
           return Integer.parseInt(doc.select("button.like-button-renderer-like-button-unclicked span").text().replace(",", ""));  
      }  

How it works:
1) Youtube video contains the people who liked video in HTML element with class as like-button-renderer-like-button-unclicked
 <button class="yt-uix-button yt-uix-button-size-default yt-uix-button-opacity yt-uix-button-has-icon no-icon-markup like-button-renderer-like-button like-button-renderer-like-button-unclicked yt-uix-clickcard-target  yt-uix-tooltip" type="button" onclick=";return false;" title="I like this" aria-label="like this video along with 327,229 other people" data-force-position="true" data-orientation="vertical" data-position="bottomright" data-tooltip-text="I like this" aria-labelledby="yt-uix-tooltip620-arialabel"><span class="yt-uix-button-content">327,229</span></button>  
2) Document object contains the document detail of the youtube video.
3) We use the document object to find the text from the HTML tag containing class as like-button-renderer-like-button-unclicked
4) We return the video like count

getPeopleDisliked method:
 public int getPeopleDisliked(Document doc)  
      {  
           return Integer.parseInt(doc.select("button.like-button-renderer-dislike-button-unclicked span").text().replace(",", ""));  
      }  

How it works:
1) Youtube video contains the people who disliked video in HTML element with class as like-button-renderer-dislike-button-unclicked
 <button class="yt-uix-button yt-uix-button-size-default yt-uix-button-opacity yt-uix-button-has-icon no-icon-markup like-button-renderer-dislike-button like-button-renderer-dislike-button-unclicked yt-uix-clickcard-target  yt-uix-tooltip" type="button" onclick=";return false;" title="I dislike this" aria-label="dislike this video along with 28,697 other people" data-force-position="true" data-orientation="vertical" data-position="bottomright" data-tooltip-text="I dislike this" aria-labelledby="yt-uix-tooltip621-arialabel"><span class="yt-uix-button-content">28,697</span></button>  
2) Document object contains the document detail of the youtube video.
3) We use the document object to find the text from the HTML tag containing class as like-button-renderer-dislike-button-unclicked
4) We return the video dislike count

Output:
 Enter the youtube video for which metadata need to be extracted  
 https://www.youtube.com/watch?v=x_7YlGv9u1g  
 Dangal | Official Trailer | Aamir Khan | In Cinemas Dec 23, 2016  
 Published on Oct 19, 2016 Dangal is an extraordinary true story based on the life of Mahavir Singh and his two daughters, Geeta and Babita Phogat. The film traces the inspirational journey of a father who trains his daughters to become world class wrestlers. Release Date: 23rd December 2016 Starring: Aamir Khan, Sakshi Tanwar, Fatima Sana Shaikh, Sanya Malhotra, Zaira Wasim, Suhani Bhatnagar Directed By: Nitesh Tiwari Written By: Nitesh Tiwari, Shreyas Jain, Piyush Gupta, Nikhil Mehrotra Produced By: Aamir Khan, Kiran Rao & Siddharth Roy Kapur Music: Pritam Lyrics: Amitabh Bhattacharya Director of Photography: Setu Production Designer: Laxmi Keluskar & Sandeep Meher Editor: Ballu Saluja Casting Director: Mukesh Chhabra Costume Designer: Maxima Basu Wrestling Choreography and Coach: Kripashankar Patel Bishnoi Action Director: Sham Kaushal Sound Designer: Shajith Koyeri SUBSCRIBE UTV Motion Pictures: http://www.youtube.com/utvmotionpictures Keep up with UTV Motion Pictures on: TWITTER: https://twitter.com/utvfilms FACEBOOK: https://www.facebook.com/utvmotionpic... INSTAGRAM: http://instagram.com/utvfilms GOOGLE+: https://plus.google.com/+UTVMotionPic... PINTEREST: http://pinterest.com/utvfilms/ Category Entertainment License Standard YouTube License  
 Video Views:   
 42,718,537 views  
 People subscribed:   
 1072189  
 People who liked the video:   
 333530  
 People who disliked the video:   
 29338  
 Top Comments:   
 1) Where are the haters who wanted to boycott this movie. The movie has already crossed 100 crores in 3 days.  
 2) No Words To Express The AWESOMENESS Of This Movie...😘😍😎😯  
 3) AWESOME MOVIE BEST MOVIE OF 2016 YALL WATCH IT  

Full Program:
 package com.cooltrickshome;  
 import java.io.IOException;  
 import java.util.ArrayList;  
 import java.util.List;  
 import java.util.Scanner;  
 import java.util.regex.Matcher;  
 import java.util.regex.Pattern;  
 import org.jsoup.Connection.Response;  
 import org.jsoup.Jsoup;  
 import org.jsoup.nodes.Document;  
 import org.jsoup.nodes.Element;  
 import org.jsoup.select.Elements;  
 public class YoutubeMetadataCrawler {  
      /**  
       * @param args  
       */  
      public static void main(String[] args) {  
           String link="";  
           Scanner s=new Scanner(System.in);  
           // TODO Auto-generated method stub  
           try {  
                System.out.println("Enter the youtube video for which metadata need to be extracted");  
                link=s.nextLine();  
                Document doc = Jsoup.connect(link).ignoreContentType(true).timeout(5000).get();  
                YoutubeMetadataCrawler ymc=new YoutubeMetadataCrawler();  
                String title=ymc.getTitle(doc);  
                String desc=ymc.getDesc(doc);  
                String views=ymc.getViews(doc);  
                String subscribed=ymc.getPeopleSubscribed(doc);  
                int liked=ymc.getPeopleLiked(doc);  
                int disliked=ymc.getPeopleDisliked(doc);  
                String vid=ymc.getVideoId(link);  
                List<String> comments=ymc.getCommentsDesc(link,vid);  
                System.out.println(title);  
                System.out.println(desc);  
                System.out.println("Video Views: \n"+views);  
                System.out.println("People subscribed: \n"+subscribed);  
                System.out.println("People who liked the video: \n"+liked);  
                System.out.println("People who disliked the video: \n"+disliked);  
                System.out.println("Top Comments: ");  
                int i=0;  
                for(String comment:comments)  
                {  
                     System.out.println(++i+") "+comment);  
                }  
           } catch (IOException e) {  
                System.out.println("JSoup is unable to connect to the website");  
           }  
           finally  
           {  
                s.close();  
           }  
      }  
      public static String removeUTFCharacters(String data){  
           Pattern p = Pattern.compile("\\\\u(\\p{XDigit}{4})");  
           Matcher m = p.matcher(data);  
           StringBuffer buf = new StringBuffer(data.length());  
           while (m.find()) {  
           String ch = String.valueOf((char) Integer.parseInt(m.group(1), 16));  
           m.appendReplacement(buf, Matcher.quoteReplacement(ch));  
           }  
           m.appendTail(buf);  
           return new String(buf);  
           }  
      public String getTitle(Document doc)  
      {  
           return doc.select("#eow-title").text();  
      }  
      public String getViews(Document doc)  
      {  
           return doc.select(".watch-view-count").text();  
      }  
      public String getDesc(Document doc)  
      {  
           return doc.select("#watch-description-clip").text();  
      }  
      public List<String> getCommentsDesc(String link, String vid)  
      {  
           List<String> comments=new ArrayList<>();  
           try {  
                Response response = Jsoup.connect(link).ignoreContentType(true).timeout(5000).execute();  
                Document doc = Jsoup.connect("https://www.youtube.com/watch_fragments_ajax?v="+vid+"&tr=time&distiller=1&ctoken="+getCommentToken(response)+"&frags=comments&spf=load")  
                     .ignoreContentType(true)  
                     .cookies(response.cookies())  
                     .header("X-Client-Data", "")  
                     .timeout(5000)  
                     .data("session_token",getSessionToken(response))  
                     .post();  
                String commentSource=doc.body().text();  
                while(commentSource.indexOf("comment-renderer-text-content")>-1)  
                {  
                     int pos=commentSource.indexOf("comment-renderer-text-content")+37;  
                     commentSource=commentSource.substring(pos);  
                     //System.out.println(commentSource);  
                     String comment=commentSource.substring(0,commentSource.indexOf("div")-8);  
                     comments.add(removeUTFCharacters(comment));  
                }  
           Elements e= doc.select(".comment-renderer-text-content");  
           for(Element e1:e)  
           {  
                comments.add(e1.text());  
           }  
           } catch (IOException e2) {  
                System.out.println("Unable to retrieve comments "+e2.getMessage());  
                e2.printStackTrace();  
           }  
           return comments;  
      }  
      public String getCommentToken(Response res)  
      {  
           String pageSource=res.body();  
           String commentToken=pageSource=pageSource.substring(pageSource.indexOf("COMMENTS_TOKEN': \"")+18);  
           commentToken=commentToken.substring(0,commentToken.indexOf("\""));  
           commentToken=commentToken.replaceAll("%", "%25");  
           return commentToken;  
      }  
      public String getSessionToken(Response res)  
      {  
           String pageSource=res.body();  
           String xsrfToken=pageSource=pageSource.substring(pageSource.indexOf("XSRF_TOKEN': \"")+14);  
           xsrfToken=xsrfToken.substring(0,xsrfToken.indexOf("\""));  
           return xsrfToken;  
      }  
      public String getVideoId(String url)  
      {  
           url=url.substring(url.indexOf("v=")+2);  
           if(url.contains("?"))  
           {  
                url=url.substring(0,url.indexOf("?"));  
           }  
           return url;  
      }  
      public int getPeopleSubscribed(Document doc)  
      {  
           return doc.select(".yt-subscriber-count").text().replace(",", "");  
      }  
      public int getPeopleLiked(Document doc)  
      {  
           return Integer.parseInt(doc.select("button.like-button-renderer-like-button-unclicked span").text().replace(",", ""));  
      }  
      public int getPeopleDisliked(Document doc)  
      {  
           return Integer.parseInt(doc.select("button.like-button-renderer-dislike-button-unclicked span").text().replace(",", ""));  
      }  
 }  


Hope it helps :)

Sunday, December 18, 2016

Create your own Free Screen Recorder using Java

Their are many commercial software which allows you to record your desktop screen and save the video.
In this post we will learn how to create a simple screen recorder using Java. This recorder will be capable of recording full screen or record the user selected region.

How it works:
1) When user starts the recording then program starts 2 threads.
2) The first thread keeps on taking screenshot of the screen and saves them into local disk mentioned in variable inputImgDir
3) The second thread continuously looks over the inputImageDir and adds all the new images into the video.
4) When user press stop recording then both threads stop and final video is retrieved.

Language Used:
Java

Git Repo:
https://github.com/csanuragjain/recorder/tree/master/ScreenRecorder

POM Dependency:
Please add the below pom dependency from https://mvnrepository.com/artifact/org.bytedeco/javacv:
<dependency>   
   <groupId>org.bytedeco</groupId>   
   <artifactId>javacv</artifactId>   
   <version>1.0</version>   
  </dependency>  

Reference:
https://cooltrickshome.blogspot.in/2016/11/convert-movie-to-images-using-java.html
https://cooltrickshome.blogspot.in/2016/11/create-desktop-screenshot-maker.html

Program:

Variables:
      public static boolean videoComplete=false;  
      public static String inputImageDir="inputImgFolder"+File.separator;  
      public static String inputImgExt="png";  
      public static String outputVideo="recording.mp4";   
      public static int counter=0;  
      public static int imgProcessed=0;  
      public static FFmpegFrameRecorder recorder=null;  
      public static int videoWidth=1920;  
      public static int videoHeight=1080;  
      public static int videoFrameRate=3;  
      public static int videoQuality=0; // 0 is the max quality  
      public static int videoBitRate=9000;  
      public static String videoFormat="mp4";  
      public static int videoCodec=avcodec.AV_CODEC_ID_MPEG4;  
      public static Thread t1=null;  
      public static Thread t2=null;  
      public static JFrame frame=null;  
      public static boolean isRegionSelected=false;  
      public static int c1=0;  
      public static int c2=0;  
      public static int c3=0;  
      public static int c4=0;  


Explanation:
1) videoComplete variables tells if user has stopped the recording or not.
2) inputImageDir defines the input directory where screenshots will be stored which would be utilized by the video thread
3) inputImgExt denotes the extension of the image taken for screenshot.
4) outputVideo is the name of the recorded video file
5) counter is used for numbering the screenshots when stored in input directory.
6) recorder is used for starting and stopping the video recording
7) videoWidth, videoFrameRate etc define output video param
8) If user wants to record only a selected region then c1,c2,c3,c4 denotes the coordinate

getRecorder method:
      public static FFmpegFrameRecorder getRecorder() throws Exception  
      {  
            if(recorder!=null)  
            {  
                 return recorder;  
            }  
            recorder = new FFmpegFrameRecorder(outputVideo,videoWidth,videoHeight);  
            try  
            {  
            recorder.setFrameRate(videoFrameRate);  
      recorder.setVideoCodec(videoCodec);  
      recorder.setVideoBitrate(videoBitRate);  
      recorder.setFormat(videoFormat);  
      recorder.setVideoQuality(videoQuality); // maximum quality  
      recorder.start();  
            }  
            catch(Exception e)  
            {  
                 JOptionPane.showMessageDialog(frame, "Exception while starting the recorder object "+e.getMessage());  
                 System.out.println("Exception while starting the recorder object "+e.getMessage());  
                 throw new Exception("Unable to start recorder");  
            }  
      return recorder;  
      }  

Explanation:
1) This method is used to get the Recorder object.
2) We create an object of FFmpegFrameRecorder named "Recorder" and then set all its video parameters.
3) Lastly we start the recorder and then return the object.

getRobot method:
      public static Robot getRobot() throws Exception  
      {  
           Robot r=null;  
           try {  
                r = new Robot();  
                return r;  
           } catch (AWTException e) {  
                JOptionPane.showMessageDialog(frame, "Issue while initiating Robot object "+e.getMessage());  
                System.out.println("Issue while initiating Robot object "+e.getMessage());  
                throw new Exception("Issue while initiating Robot object");  
           }  
      }  

Explanation:
1) This method retrieves an object of Robot class which could be further utilized by remaining methods.

main Method:
      public static void main(String[] args) {  
           try {  
                if(getRecorder()==null)  
                {  
                     System.out.println("Cannot make recorder object, Exiting program");  
                     System.exit(0);  
                }  
                if(getRobot()==null)  
                {  
                     System.out.println("Cannot make robot object, Exiting program");  
                     System.exit(0);  
                }  
                File scanFolder=new File(inputImageDir);  
                scanFolder.delete();  
                scanFolder.mkdirs();  
                createGUI();  
           } catch (Exception e) {  
                System.out.println("Exception in program "+e.getMessage());  
           }  
      }  

Explanation:
1) We initialize the recorder and Robot object.
2) We create the input image folder.
3) Now we open up the GUI which will allow user to start/stop the recording.

createGUI method:
      public static void createGUI()  
      {  
           frame=new JFrame("Screen Recorder");  
           JButton b1=new JButton("Select Region for Recording");  
           JButton b2=new JButton("Start Recording");  
           JButton b3=new JButton("Stop Recording");  
           JLabel l1=new JLabel("<html><br/>If you dont select a region then full screen recording <br/> will be made when you click on Start Recording</html>");  
           l1.setFont (l1.getFont ().deriveFont (20.0f));  
           b1.addActionListener(new ActionListener() {  
       @Override  
       public void actionPerformed(ActionEvent e) {  
            try {  
                 JOptionPane.showMessageDialog(frame, "A new window will open. Use your mouse to select the region you like to record");  
                          new CropRegion().getImage();  
                     } catch (Exception e1) {  
                          // TODO Auto-generated catch block  
                          System.out.println("Issue while trying to call the module to crop region");  
                          e1.printStackTrace();  
                     }   
       }  
     });  
           b2.addActionListener(new ActionListener() {  
       @Override  
       public void actionPerformed(ActionEvent e) {  
            counter=0;  
         startRecording();  
       }  
     });  
           b3.addActionListener(new ActionListener() {  
       @Override  
       public void actionPerformed(ActionEvent e) {  
         stopRecording();  
         System.out.print("Exiting...");  
         System.exit(0);  
       }  
     });  
           frame.add(b1);  
           frame.add(b2);  
           frame.add(b3);  
           frame.add(l1);  
           frame.setLayout(new FlowLayout(0));  
           frame.setVisible(true);  
           frame.setSize(1000, 170);  
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
      }  

Explanation:
1) We make a JFrame with the button for staring and stopping the recording. One more button is added for allowing user to record only a selected portion of screen
2) If user clicks to select only certain region then we call a class CropRegion method getImage which helps in retrieving the coordinate of the region selected by user and update the same in variable c1,c2,c3,c4
3) If user clicks on start recording then startRecording method is called
4) If user clicks on stoprecording then stopRecording method is called

startRecording method:
      public static void startRecording()  
      {  
           t1=new Thread()  
           {  
             public void run() {  
               try {  
                          takeScreenshot(getRobot());  
                     } catch (Exception e) {  
                          JOptionPane.showMessageDialog(frame, "Cannot make robot object, Exiting program "+e.getMessage());  
                          System.out.println("Cannot make robot object, Exiting program "+e.getMessage());  
                          System.exit(0);  
                     }  
             }  
           };  
           t2=new Thread()  
           {  
             public void run() {  
               prepareVideo();  
             }  
           };  
           t1.start();  
           t2.start();  
           System.out.println("Started recording at "+new Date());  
      }  


Explanation:
1) Two threads are started in this module when user starts the recording
2) First thread calls the takeScreenshot module which keeps on taking screenshot of user screen and saves them on local disk.
3) Second thread calls the prepareVideo which monitors the screenshot created in step 2 and add them continuously on the video.

takeScreenshot method:
      public static void takeScreenshot(Robot r)  
      {  
           Dimension size = Toolkit.getDefaultToolkit().getScreenSize();  
           Rectangle rec=new Rectangle(size);  
           if(isRegionSelected)  
           {  
                rec=new Rectangle(c1, c2, c3-c1, c4-c2);  
           }  
           while(!videoComplete)  
           {  
           counter++;  
           BufferedImage img = r.createScreenCapture(rec);  
           try {  
                ImageIO.write(img, inputImgExt, new File(inputImageDir+counter+"."+inputImgExt));  
           } catch (IOException e) {  
                JOptionPane.showMessageDialog(frame, "Got an issue while writing the screenshot to disk "+e.getMessage());  
                System.out.println("Got an issue while writing the screenshot to disk "+e.getMessage());  
                counter--;  
           }  
           }  
      }  

Explanation:
1) If user has selected a region for recording then we set the rectangle with the coordinate value of c1,c2,c3,c4. Otherwise we set the rectangle to be full screen
2) Now we run a loop until videoComplete is false (remains false until user press stop recording.
3) Now we capture the region and write the same to the input image directory.
4) So when user starts the recording this method keeps on taking screenshot and saves them into disk.

prepareVideo method:
      public static void prepareVideo()  
      {  
           File scanFolder=new File(inputImageDir);  
           while(!videoComplete)  
           {  
                File[] inputFiles=scanFolder.listFiles();  
                try {  
                     getRobot().delay(500);  
                } catch (Exception e) {  
                }  
                //for(int i=0;i<scanFolder.list().length;i++)  
                for(int i=0;i<inputFiles.length;i++)  
                {  
                     //imgProcessed++;  
                     addImageToVideo(inputFiles[i].getAbsolutePath());  
                     //String imgToAdd=scanFolder.getAbsolutePath()+File.separator+imgProcessed+"."+inputImgExt;  
                     //addImageToVideo(imgToAdd);  
                     //new File(imgToAdd).delete();  
                     inputFiles[i].delete();  
                }  
           }  
           File[] inputFiles=scanFolder.listFiles();  
           for(int i=0;i<inputFiles.length;i++)  
           {  
                addImageToVideo(inputFiles[i].getAbsolutePath());  
                inputFiles[i].delete();  
           }  
      }  

Explanation:
1) We start a loop which will run until video complete is set true (done only when user press stop recording)
2) We keep on monitoring the input  Image directory
3) We traverse each file found in the input image directory and add those images to video using the addImageToVideo method. After the image has been added we delete the image
4) Using the loop in step1 we keep on repeating step 2 and 3 so that each image gets added to video. We added a delay of 500ms so that this module does not picks a half created image from the takeScreenshot module
5) When user press stop recording the loop gets broken. Now we finally traverse the input image directory and add the remaining images to video.

addImageToVideo method:
      public static void addImageToVideo(String imgPath)  
      {  
           try {  
                getRecorder().record(getFrameConverter().convert(cvLoadImage(imgPath)));  
           } catch (Exception e) {  
                JOptionPane.showMessageDialog(frame, "Exception while adding image to video "+e.getMessage());  
                System.out.println("Exception while adding image to video "+e.getMessage());  
           }  
      }  

Explanation:
1) cvLoadImage is used to load the image passed as argument
2) We call the convert method to convert the image to frame which could be used by the recorder
3) We pass the frame obtained in step 2 and add the same in the recorder by calling the record method.

getFrameConverter method:
      public static OpenCVFrameConverter.ToIplImage getFrameConverter()  
      {  
           OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();  
           return grabberConverter;  
      }  

Explanation:
1) We make an object of OpenCVFrameConverter.ToIplImage named grabberConverter and returns this object for other modules.

stopRecording method:
      public static void stopRecording()  
      {  
           try {  
                videoComplete=true;  
                System.out.println("Stopping recording at "+new Date());  
                t1.join();  
                System.out.println("Screenshot thread complete");  
                t2.join();  
                System.out.println("Video maker thread complete");  
                getRecorder().stop();  
                System.out.println("Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());  
                JOptionPane.showMessageDialog(frame, "Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());  
           } catch (Exception e) {  
                System.out.println("Exception while stopping the recorder "+e.getMessage());  
           }  
      }  


Explanation:
1) After user press the stop recording, we wait for both the threads to complete.
2) After thread completes, we stop the recorder and show the video path to user.

Output:

 Started recording at Sun Dec 18 18:29:36 IST 2016  
 Stopping recording at Sun Dec 18 18:29:51 IST 2016  
 Screenshot thread complete  
 Video maker thread complete  
 Recording has been saved successfully at C:\Users\anjain\workspace\BrowserMobProxy\cooltrickshome\recording.mp4  
 Exiting...libpng error: PNG unsigned integer out of range  
 Output #0, mp4, to 'recording.mp4':  
   Stream #0:0: Video: mpeg4, yuv420p, 1920x1080, q=2-31, 9 kb/s, 3 tbn, 3 tbc  

Full Program:

ScreenRecorder.java
 package com.cooltrickshome;  
 import static org.bytedeco.javacpp.opencv_imgcodecs.cvLoadImage;  
 import java.awt.AWTException;  
 import java.awt.Dimension;  
 import java.awt.FlowLayout;  
 import java.awt.Rectangle;  
 import java.awt.Robot;  
 import java.awt.Toolkit;  
 import java.awt.event.ActionEvent;  
 import java.awt.event.ActionListener;  
 import java.awt.image.BufferedImage;  
 import java.io.File;  
 import java.io.IOException;  
 import java.util.Date;  
 import javax.imageio.ImageIO;  
 import javax.swing.JButton;  
 import javax.swing.JFrame;  
 import javax.swing.JLabel;  
 import javax.swing.JOptionPane;  
 import org.bytedeco.javacpp.avcodec;  
 import org.bytedeco.javacv.FFmpegFrameRecorder;  
 import org.bytedeco.javacv.OpenCVFrameConverter;  
 public class ScreenRecorder{  
      public static boolean videoComplete=false;  
      public static String inputImageDir="inputImgFolder"+File.separator;  
      public static String inputImgExt="png";  
      public static String outputVideo="recording.mp4";   
      public static int counter=0;  
      public static int imgProcessed=0;  
      public static FFmpegFrameRecorder recorder=null;  
      public static int videoWidth=1920;  
      public static int videoHeight=1080;  
      public static int videoFrameRate=3;  
      public static int videoQuality=0; // 0 is the max quality  
      public static int videoBitRate=9000;  
      public static String videoFormat="mp4";  
      public static int videoCodec=avcodec.AV_CODEC_ID_MPEG4;  
      public static Thread t1=null;  
      public static Thread t2=null;  
      public static JFrame frame=null;  
      public static boolean isRegionSelected=false;  
      public static int c1=0;  
      public static int c2=0;  
      public static int c3=0;  
      public static int c4=0;  
      public static void main(String[] args) {  
           try {  
                if(getRecorder()==null)  
                {  
                     System.out.println("Cannot make recorder object, Exiting program");  
                     System.exit(0);  
                }  
                if(getRobot()==null)  
                {  
                     System.out.println("Cannot make robot object, Exiting program");  
                     System.exit(0);  
                }  
                File scanFolder=new File(inputImageDir);  
                scanFolder.delete();  
                scanFolder.mkdirs();  
                createGUI();  
           } catch (Exception e) {  
                System.out.println("Exception in program "+e.getMessage());  
           }  
      }  
      public static void createGUI()  
      {  
           frame=new JFrame("Screen Recorder");  
           JButton b1=new JButton("Select Region for Recording");  
           JButton b2=new JButton("Start Recording");  
           JButton b3=new JButton("Stop Recording");  
           JLabel l1=new JLabel("<html><br/>If you dont select a region then full screen recording <br/> will be made when you click on Start Recording</html>");  
           l1.setFont (l1.getFont ().deriveFont (20.0f));  
           b1.addActionListener(new ActionListener() {  
       @Override  
       public void actionPerformed(ActionEvent e) {  
            try {  
                 JOptionPane.showMessageDialog(frame, "A new window will open. Use your mouse to select the region you like to record");  
                          new CropRegion().getImage();  
                     } catch (Exception e1) {  
                          // TODO Auto-generated catch block  
                          System.out.println("Issue while trying to call the module to crop region");  
                          e1.printStackTrace();  
                     }   
       }  
     });  
           b2.addActionListener(new ActionListener() {  
       @Override  
       public void actionPerformed(ActionEvent e) {  
            counter=0;  
         startRecording();  
       }  
     });  
           b3.addActionListener(new ActionListener() {  
       @Override  
       public void actionPerformed(ActionEvent e) {  
         stopRecording();  
         System.out.print("Exiting...");  
         System.exit(0);  
       }  
     });  
           frame.add(b1);  
           frame.add(b2);  
           frame.add(b3);  
           frame.add(l1);  
           frame.setLayout(new FlowLayout(0));  
           frame.setVisible(true);  
           frame.setSize(1000, 170);  
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
      }  
      public static void startRecording()  
      {  
           t1=new Thread()  
           {  
             public void run() {  
               try {  
                          takeScreenshot(getRobot());  
                     } catch (Exception e) {  
                          JOptionPane.showMessageDialog(frame, "Cannot make robot object, Exiting program "+e.getMessage());  
                          System.out.println("Cannot make robot object, Exiting program "+e.getMessage());  
                          System.exit(0);  
                     }  
             }  
           };  
           t2=new Thread()  
           {  
             public void run() {  
               prepareVideo();  
             }  
           };  
           t1.start();  
           t2.start();  
           System.out.println("Started recording at "+new Date());  
      }  
      public static Robot getRobot() throws Exception  
      {  
           Robot r=null;  
           try {  
                r = new Robot();  
                return r;  
           } catch (AWTException e) {  
                JOptionPane.showMessageDialog(frame, "Issue while initiating Robot object "+e.getMessage());  
                System.out.println("Issue while initiating Robot object "+e.getMessage());  
                throw new Exception("Issue while initiating Robot object");  
           }  
      }  
      public static void takeScreenshot(Robot r)  
      {  
           Dimension size = Toolkit.getDefaultToolkit().getScreenSize();  
           Rectangle rec=new Rectangle(size);  
           if(isRegionSelected)  
           {  
                rec=new Rectangle(c1, c2, c3-c1, c4-c2);  
           }  
           while(!videoComplete)  
           {  
           counter++;  
           BufferedImage img = r.createScreenCapture(rec);  
           try {  
                ImageIO.write(img, inputImgExt, new File(inputImageDir+counter+"."+inputImgExt));  
           } catch (IOException e) {  
                JOptionPane.showMessageDialog(frame, "Got an issue while writing the screenshot to disk "+e.getMessage());  
                System.out.println("Got an issue while writing the screenshot to disk "+e.getMessage());  
                counter--;  
           }  
           }  
      }  
      public static void prepareVideo()  
      {  
           File scanFolder=new File(inputImageDir);  
           while(!videoComplete)  
           {  
                File[] inputFiles=scanFolder.listFiles();  
                try {  
                     getRobot().delay(500);  
                } catch (Exception e) {  
                }  
                //for(int i=0;i<scanFolder.list().length;i++)  
                for(int i=0;i<inputFiles.length;i++)  
                {  
                     //imgProcessed++;  
                     addImageToVideo(inputFiles[i].getAbsolutePath());  
                     //String imgToAdd=scanFolder.getAbsolutePath()+File.separator+imgProcessed+"."+inputImgExt;  
                     //addImageToVideo(imgToAdd);  
                     //new File(imgToAdd).delete();  
                     inputFiles[i].delete();  
                }  
           }  
           File[] inputFiles=scanFolder.listFiles();  
           for(int i=0;i<inputFiles.length;i++)  
           {  
                addImageToVideo(inputFiles[i].getAbsolutePath());  
                inputFiles[i].delete();  
           }  
      }  
      public static FFmpegFrameRecorder getRecorder() throws Exception  
      {  
            if(recorder!=null)  
            {  
                 return recorder;  
            }  
            recorder = new FFmpegFrameRecorder(outputVideo,videoWidth,videoHeight);  
            try  
            {  
            recorder.setFrameRate(videoFrameRate);  
      recorder.setVideoCodec(videoCodec);  
      recorder.setVideoBitrate(videoBitRate);  
      recorder.setFormat(videoFormat);  
      recorder.setVideoQuality(videoQuality); // maximum quality  
      recorder.start();  
            }  
            catch(Exception e)  
            {  
                 JOptionPane.showMessageDialog(frame, "Exception while starting the recorder object "+e.getMessage());  
                 System.out.println("Exception while starting the recorder object "+e.getMessage());  
                 throw new Exception("Unable to start recorder");  
            }  
      return recorder;  
      }  
      public static OpenCVFrameConverter.ToIplImage getFrameConverter()  
      {  
           OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();  
           return grabberConverter;  
      }  
      public static void addImageToVideo(String imgPath)  
      {  
           try {  
                getRecorder().record(getFrameConverter().convert(cvLoadImage(imgPath)));  
           } catch (Exception e) {  
                JOptionPane.showMessageDialog(frame, "Exception while adding image to video "+e.getMessage());  
                System.out.println("Exception while adding image to video "+e.getMessage());  
           }  
      }  
      public static void stopRecording()  
      {  
           try {  
                videoComplete=true;  
                System.out.println("Stopping recording at "+new Date());  
                t1.join();  
                System.out.println("Screenshot thread complete");  
                t2.join();  
                System.out.println("Video maker thread complete");  
                getRecorder().stop();  
                System.out.println("Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());  
                JOptionPane.showMessageDialog(frame, "Recording has been saved successfully at "+new File(outputVideo).getAbsolutePath());  
           } catch (Exception e) {  
                System.out.println("Exception while stopping the recorder "+e.getMessage());  
           }  
      }  
 }  

CropRegion.java
 package com.cooltrickshome;  
 import java.awt.AWTException;  
 import java.awt.Dimension;  
 import java.awt.FlowLayout;  
 import java.awt.Graphics;  
 import java.awt.Rectangle;  
 import java.awt.Robot;  
 import java.awt.Toolkit;  
 import java.awt.event.MouseEvent;  
 import java.awt.event.MouseListener;  
 import java.awt.event.MouseMotionListener;  
 import java.awt.image.BufferedImage;  
 import java.io.IOException;  
 import javax.swing.JFrame;  
 import javax.swing.JLabel;  
 import javax.swing.JOptionPane;  
 public class CropRegion implements MouseListener,  
           MouseMotionListener {  
      int drag_status = 0;  
      int c1;  
      int c2;  
      int c3;  
      int c4;  
      JFrame frame=null;  
      static int counter=0;  
      JLabel background=null;  
      public void getImage() throws AWTException, IOException, InterruptedException {  
           Dimension size = Toolkit.getDefaultToolkit().getScreenSize();  
        Robot robot = new Robot();  
        BufferedImage img = robot.createScreenCapture(new Rectangle(size));  
        ImagePanel panel = new ImagePanel(img);  
        frame=new JFrame();  
        frame.add(panel);  
        frame.setLocation(0, 0);  
        frame.setSize(size);  
        frame.setLayout(new FlowLayout());  
        frame.setUndecorated(true);  
        frame.setVisible(true);  
        frame.addMouseListener(this);  
        frame.addMouseMotionListener(this);  
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);  
      }  
      public void draggedScreen() throws Exception {  
           ScreenRecorder.c1=c1;  
           ScreenRecorder.c2=c2;  
           ScreenRecorder.c3=c3;  
           ScreenRecorder.c4=c4;  
           ScreenRecorder.isRegionSelected=true;  
           JOptionPane.showMessageDialog(frame, "Region Selected.Please click on Start Recording button to record the selected region.");  
           frame.dispose();  
      }  
      public void mouseClicked(MouseEvent arg0) {  
      }  
      public void mouseEntered(MouseEvent arg0) {  
      }  
      public void mouseExited(MouseEvent arg0) {  
      }  
      public void mousePressed(MouseEvent arg0) {  
           paint();  
           this.c1 = arg0.getX();  
           this.c2 = arg0.getY();  
      }  
      public void mouseReleased(MouseEvent arg0) {  
           paint();  
           if (this.drag_status == 1) {  
                this.c3 = arg0.getX();  
                this.c4 = arg0.getY();  
                try {  
                     draggedScreen();  
                } catch (Exception e) {  
                     e.printStackTrace();  
                }  
           }  
      }  
      public void mouseDragged(MouseEvent arg0) {  
           paint();  
           this.drag_status = 1;  
           this.c3 = arg0.getX();  
           this.c4 = arg0.getY();  
      }  
      public void mouseMoved(MouseEvent arg0) {  
      }  
      public void paint() {  
           Graphics g = frame.getGraphics();  
           frame.repaint();  
           int w = this.c1 - this.c3;  
           int h = this.c2 - this.c4;  
           w *= -1;  
           h *= -1;  
           if (w < 0) {  
                w *= -1;  
           }  
           g.drawRect(this.c1, this.c2, w, h);  
      }  
 }  

ImagePanel.java
 package com.cooltrickshome;  
 import java.awt.Dimension;  
 import java.awt.Graphics;  
 import java.awt.Image;  
 import javax.swing.ImageIcon;  
 import javax.swing.JPanel;  
 class ImagePanel  
  extends JPanel  
 {  
  private Image img;  
  public ImagePanel(String img)  
  {  
   this(new ImageIcon(img).getImage());  
  }  
  public ImagePanel(Image img)  
  {  
   this.img = img;  
   Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));  
   setPreferredSize(size);  
   setMinimumSize(size);  
   setMaximumSize(size);  
   setSize(size);  
   setLayout(null);  
  }  
  public void paintComponent(Graphics g)  
  {  
   g.drawImage(this.img, 0, 0, null);  
  }  
 }  


Note:
I am not sure if there could be a way to reduce the resulting video size. If you have please let me know
Right now I am using an int variable named counter to name the screenshot. For a long recording this will cause an issue since int range will be exhausted. Need to think about an alternative for same.
I have recorded for few minutes but haven't tested for longer duration.

If you have any suggestions on this, please feel free to contact me via comments or directly at my email cs.anurag.jain@gmail.com :)

Hope it helps :)

Sunday, December 11, 2016

Images to Movie Converter using Java

This blog post will help you to convert your images to a video using Java.

Language Used:
Java

Git Location:
https://github.com/csanuragjain/converter/tree/master/ImageToMovie

Reference:
http://stackoverflow.com/questions/13643046/how-to-convert-images-into-video-in-android-using-javacv
http://stackoverflow.com/questions/28721396/convert-images-to-video-in-android
http://stackoverflow.com/questions/15867696/javacv-opencv-cvloadimage-not-working

Pom Dependency:
Please add the below pom dependency from https://mvnrepository.com/artifact/org.bytedeco/javacv :
  <dependency>   
   <groupId>org.bytedeco</groupId>   
   <artifactId>javacv</artifactId>   
   <version>1.0</version>   
  </dependency>   

Program:

Main method:
       public static void main(String []args)  
        {  
                 Scanner s=new Scanner(System.in);  
                 System.out.println("Enter the directory path of images (for eg c:\\test)");  
                 String imgPath=s.nextLine();  
                 System.out.println("Enter the directory with video file name where resulting video will be saved (for eg c:\\test\\abc.mp4)");  
                 String vidPath=s.nextLine();  
                 ArrayList<String> links = new ArrayList<>();  
                 File f=new File(imgPath);  
                 File[] f2=f.listFiles();  
                 for(File f3:f2)  
                 {  
                      links.add(f3.getAbsolutePath());  
                 }  
                 convertJPGtoMovie(links, vidPath);  
                 System.out.println("Video has been created at "+vidPath);  
                 s.close();  
        }  

How it works:
1) We make a simple scanner object to get user input
2) We ask the directory containing the images to be converted to video
3) We ask user the resulting directory along with video file name from user.
4) We scan the directory obtained from step 2 and save all the image path in a ArrayList.
5) Now we call convertJPGtoMovie along with the ArrayList (containing all images path) and the resulting video path

convertJPGtoMovie method:
       public static void convertJPGtoMovie(ArrayList<String> links, String vidPath)  
       {  
            OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();  
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(vidPath,640,720);  
            try {  
                 recorder.setFrameRate(1);  
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);  
        recorder.setVideoBitrate(9000);  
        recorder.setFormat("mp4");  
        recorder.setVideoQuality(0); // maximum quality  
        recorder.start();  
              for (int i=0;i<links.size();i++)  
              {  
               recorder.record(grabberConverter.convert(cvLoadImage(links.get(i))));  
              }  
              recorder.stop();  
             }  
             catch (org.bytedeco.javacv.FrameRecorder.Exception e){  
               e.printStackTrace();  
             }  
       }  

How it works:
1) We make an object of ToIplImage named grabberConverter which we are going to use later for converting from IplImage to Frame Object
2) We make a FFmpegFrameRecorder object named recorder which would help to convert our images to video. It takes 3 argument. First is the video file path which need to be created. Second argument defines the image width and third argument defines the image height.
3) We define the frame rate of the resulting video. Similarly we need to set other video parameters like video codec, bitrate, format, quality.
4) After video configuration has been made we start the recording by calling the start method.
5) Now cvLodImage method takes the image we passed and convert them into IplImage. Now we use grabberConverter from step1 to convert the IplImage into Frame.
6) We utilise the record method of FFmpegFrameRecorder which takes the Frame from step5 and place it in the resulting video. This way our video has the first image.
7) Step5 and Step6 are repeated over loop covering all the images which need to be embedded into the video.
8) After all images are covered, we call the stop button which marks the completion of our video.

Output:
 Enter the directory path of images (for eg c:\test)  
 C:\Users\anurag\Desktop\images\extra  
 Enter the directory where resulting video will be saved (for eg c:\test\abc.mp4)  
 C:\Users\anjain\Desktop\images\extra\5.mp4  
 Video has been created at C:\Users\anurag\Desktop\images\extra\5.mp4  
 Output #0, mp4, to 'C:\Users\anjain\Desktop\images\extra\5.mp4':  
   Stream #0:0: Video: mpeg4, yuv420p, 640x720, q=2-31, 9 kb/s, 1 tbn, 1 tbc  

Full Program:
 package com.cooltrickshome;  
 import static org.bytedeco.javacpp.opencv_imgcodecs.*;  
 import java.io.File;  
 import java.io.IOException;  
 import java.util.ArrayList;  
 import java.util.Scanner;  
 import org.bytedeco.javacpp.avcodec;  
 import org.bytedeco.javacv.FFmpegFrameRecorder;  
 import org.bytedeco.javacv.OpenCVFrameConverter;  
 public class ImageToMovie {  
      /**  
       * @param args  
       * @throws IOException   
       */  
       public static void main(String []args)  
        {  
                 Scanner s=new Scanner(System.in);  
                 System.out.println("Enter the directory path of images (for eg c:\\test)");  
                 String imgPath=s.nextLine();  
                 System.out.println("Enter the directory with video file name where resulting video will be saved (for eg c:\\test\\abc.mp4)");  
                 String vidPath=s.nextLine();  
                 ArrayList<String> links = new ArrayList<>();  
                 File f=new File(imgPath);  
                 File[] f2=f.listFiles();  
                 for(File f3:f2)  
                 {  
                      links.add(f3.getAbsolutePath());  
                 }  
                 convertJPGtoMovie(links, vidPath);  
                 System.out.println("Video has been created at "+vidPath);  
                 s.close();  
        }  
       public static void convertJPGtoMovie(ArrayList<String> links, String vidPath)  
       {  
            OpenCVFrameConverter.ToIplImage grabberConverter = new OpenCVFrameConverter.ToIplImage();  
            FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(vidPath,640,720);  
            try {  
                 recorder.setFrameRate(1);  
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4);  
        recorder.setVideoBitrate(9000);  
        recorder.setFormat("mp4");  
        recorder.setVideoQuality(0); // maximum quality  
        recorder.start();  
              for (int i=0;i<links.size();i++)  
              {  
               recorder.record(grabberConverter.convert(cvLoadImage(links.get(i))));  
              }  
              recorder.stop();  
             }  
             catch (org.bytedeco.javacv.FrameRecorder.Exception e){  
               e.printStackTrace();  
             }  
       }  
 }  

Hope it helps :)

Wednesday, December 7, 2016

Global Tracking and Controlling your mouse using Java

This post will help you track your mouse movements. It will also help you to re-position your mouse or make mouse clicks through program..
This can be used as a base for creating game modules where you would like to control your mouse or restrict your mouse movements

Features of program:
1) Program opens a small frame.
2) Program makes the mouse click on frame and drag it
2) On moving mouse inside frame, mouse coordinate will be shown.
3) This program will also track movement of mouse even it is outside frame window

Reference:
http://stackoverflow.com/questions/18321877/tracking-mouse-movement-in-java
http://omtlab.com/java-control-the-mouse-pointer-and-click/

Language Used:
Java

Git Location:
https://github.com/csanuragjain/extra/tree/master/MouseControllerTracker

Program:

Variable declaration:
      JLabel coordinate=null;  
      final static int frameWidth=500;  
      final static int frameHeight=500;  
      static int frameStartPosX=0;  
      static int frameStartPosY=0;  
      static int frameEndPosX=0;  
      static int frameEndPosY=0;  
      static int mouseRecenterPosX=0;  
      static int mouseRecenterPosY=0;  

How it works:
1) coordinate is the JLabel shown in JFrame
2) frameWidth is the width of the JFrame and frameHeight is height of JFrame
3) frameStartPosX and frameStartPosY will show the starting coordinate of JFrame
4) frameEndPosX and frameEndPosY will show the ending coordinate of JFrame
5) mouseRecenterPosX and mouseRecenterPosY is an arbitrary position where we will drag the frame.

main method:
      public static void main(String[] args) {  
           try {  
           Robot r=new Robot();  
           MouseControllerTracker mt=new MouseControllerTracker();  
           JFrame f=mt.showFrame(frameWidth,frameHeight);  
           mt.trackFrame(f);  
           mt.moveFrameUsingMouse(r);  
           while(true)  
           {  
                mt.trackMouse(r);  
           }  
           } catch (AWTException e) {  
                System.out.println("There was an issue while instantiating Robot class "+e.getMessage());  
           }  
      }  

How it works:
1) We make an object of Robot class which will be used by the helper functions
2) We call the showFrame function which will create a new JFrame with the passed width and height value. It will also return the instance of JFrame created.
3) We call the trackFrame method which tracks the current frame position and update the global variables.
4) We call moveFrameUsingMouse which makes mouse to drag the frame and bring it to certain position
5) We call trackMouse which keeps a track of mouse movement and update in GUI

showFrame method:
      public JFrame showFrame(int frameWidth, int frameHeight)  
      {  
           JFrame f=new JFrame();  
           coordinate=new JLabel();  
           f.add(coordinate);  
           f.setSize(frameWidth, frameHeight);  
           f.setLayout(new FlowLayout(0));  
           f.setVisible(true);  
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
           return f;  
      }  

How it works:
1) We create a Jframe object and add the JLabel.
2) The size of frame is set from the argument values

trackFrame method:
      public void trackFrame(JFrame f)  
      {  
           Point p=f.getLocationOnScreen();  
           frameStartPosX=p.x;  
           frameStartPosY=p.y;  
           frameEndPosX=frameStartPosX+frameWidth;  
           frameEndPosY=frameStartPosY+frameHeight;  
           mouseRecenterPosX=(frameStartPosX+frameEndPosX)/2;  
           mouseRecenterPosY=(frameStartPosY+frameEndPosY)/2;  
      }  

How it works:
1) getLocationOnScreen is used to determine the current start frame coordinates
2) We copy the coordinate in frameStartPosX & frameStartPosY
3) Since we have already defined the frameWidth and frameHeight, so we use the same to get the frame end position and update frameEndPosX and frameEndPosY
4) We update mouseRecenterPosX and mouseRecenterPosY to be at center position.

moveFrameUsingMouse method:
      public void moveFrameUsingMouse(Robot robot)  
      {  
           robot.mouseMove(mouseRecenterPosX, frameStartPosY+10);  
           robot.mousePress(InputEvent.BUTTON1_MASK);  
           for(int i=0;i<200;i++){  
                robot.mouseMove(mouseRecenterPosX+i, mouseRecenterPosY+i);  
                robot.delay(10);  
           }  
           robot.mouseRelease(InputEvent.BUTTON1_MASK);  
      }  

How it works:
1) mouseMove method is used to move the mouse. It takes x and y coordinate as the argument. So firstly we move mouse over frame title bar
2) mousePress is used to make a mouseClick. Here mouse Button1 would be click on frame
3) Now in a loop we make the mouse move to different coordinate so that it makes a feeling of mouse dragging the frame. We introduced a delay so that drag is visible and not happen instantly
4) Finally after drag is done we release the mouse.

trackMouse method:
      public void trackMouse(Robot r)  
      {  
           PointerInfo inf = MouseInfo.getPointerInfo();  
           Point p = inf.getLocation();  
           coordinate.setText("Mouse moved to ("+p.x+","+p.y+")");  
      }  

How it works:
1) We use getPonterInfo method to extract the information about mouse pointer
2) We call getLocation to get current mouse coordinate
3) We update the JLabel on frame to the current coordinate of mouse.

Full Program:
 package com.cooltrickshome;  
 import java.awt.AWTException;  
 import java.awt.FlowLayout;  
 import java.awt.MouseInfo;  
 import java.awt.Point;  
 import java.awt.PointerInfo;  
 import java.awt.Robot;  
 import java.awt.event.InputEvent;  
 import javax.swing.JFrame;  
 import javax.swing.JLabel;  
 public class MouseControllerTracker{  
      JLabel coordinate=null;  
      final static int frameWidth=500;  
      final static int frameHeight=500;  
      static int frameStartPosX=0;  
      static int frameStartPosY=0;  
      static int frameEndPosX=0;  
      static int frameEndPosY=0;  
      static int mouseRecenterPosX=0;  
      static int mouseRecenterPosY=0;  
      public static void main(String[] args) {  
           try {  
           Robot r=new Robot();  
           MouseControllerTracker mt=new MouseControllerTracker();  
           JFrame f=mt.showFrame(frameWidth,frameHeight);  
           mt.trackFrame(f);  
           mt.moveFrameUsingMouse(r);  
           while(true)  
           {  
                mt.trackMouse(r);  
           }  
           } catch (AWTException e) {  
                System.out.println("There was an issue while instantiating Robot class "+e.getMessage());  
           }  
      }  
      public JFrame showFrame(int frameWidth, int frameHeight)  
      {  
           JFrame f=new JFrame();  
           coordinate=new JLabel();  
           f.add(coordinate);  
           f.setSize(frameWidth, frameHeight);  
           f.setLayout(new FlowLayout(0));  
           f.setVisible(true);  
           f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
           return f;  
      }  
      public void trackFrame(JFrame f)  
      {  
           Point p=f.getLocationOnScreen();  
           frameStartPosX=p.x;  
           frameStartPosY=p.y;  
           frameEndPosX=frameStartPosX+frameWidth;  
           frameEndPosY=frameStartPosY+frameHeight;  
           mouseRecenterPosX=(frameStartPosX+frameEndPosX)/2;  
           mouseRecenterPosY=(frameStartPosY+frameEndPosY)/2;  
      }  
      public void moveFrameUsingMouse(Robot robot)  
      {  
           robot.mouseMove(mouseRecenterPosX, frameStartPosY+10);  
           robot.mousePress(InputEvent.BUTTON1_MASK);  
           for(int i=0;i<200;i++){  
                robot.mouseMove(mouseRecenterPosX+i, mouseRecenterPosY+i);  
                robot.delay(10);  
           }  
           robot.mouseRelease(InputEvent.BUTTON1_MASK);  
      }  
      public void trackMouse(Robot r)  
      {  
           PointerInfo inf = MouseInfo.getPointerInfo();  
           Point p = inf.getLocation();  
           coordinate.setText("Mouse moved to ("+p.x+","+p.y+")");  
      }  
 }  

Hope it helps :)

Tuesday, December 6, 2016

Emulate keyboard keys using Java

This post will help you emulate your keyboard keys using Java. This program opens up notepad and start typing on notepad. The best part is we introduced delay after typing of each letter which makes it look like a bot is typing.

Features of program:
1) Program first runs notepad
3) Program will type a message letter by letter with small delay on notepad
4) For example it display a message "Hi, Did you watch the Terminator. The second part was awesome."

Reference:
http://stackoverflow.com/questions/1248510/convert-string-to-keyevents

Language Used:
Java

Git Location:
https://github.com/csanuragjain/extra/tree/master/EmulateKeyboard

Program:

Constructor:
 private Robot robot;  
   public EmulateKeyboard() throws AWTException {  
     this.robot = new Robot();  
   }  
   public EmulateKeyboard(Robot robot) {  
     this.robot = robot;  
   }  


How it works:
1) EmulateKeyboard is the name of class
2) Robot is a predefined class which actually provides the functionality of typing keyboard events
3) We define 2 constructor which instantiate the Robot class object.

main method:
 public static void main(String[] args) throws Exception {  
        Runtime.getRuntime().exec("notepad.exe");  
        EmulateKeyboard keyboard = new EmulateKeyboard();  
     keyboard.type("Hi, Did you watch the Terminator?\nThe second part was awesome.",50);  
   }  

How it works:
1) We open notepad using Runtime.getRuntime.exec function
2) We make an object of our class and call the type function
3) type function take 2 argument
4) The first argument denote the message to be written
5) Second argument tells the delay belay typing of each letter of message to be printed.
6) So, program will open notepad and will start writing each letter of message with a delay of 50ms

type method:
   public void type(CharSequence characters,int delay) {  
     int length = characters.length();  
     for (int i = 0; i < length; i++) {  
       char character = characters.charAt(i);  
       typeChar(character);  
       this.robot.delay(delay);  
     }  
   }  

How it works:
1) We convert the string into character array
2) For each character we call typeChar which actually types the character.
3) After the character is written we call the delay method of Robot class which introduces a delay of milliseconds passed in 2nd argument
4) After delay is completed next characters goes again through step2 & step3

typeChar method:
   public void typeChar(char character) {  
     switch (character) {  
     case 'a': doType(KeyEvent.VK_A); break;  
     case 'b': doType(KeyEvent.VK_B); break;  
     case 'c': doType(KeyEvent.VK_C); break;  
     case 'd': doType(KeyEvent.VK_D); break;  
     case 'e': doType(KeyEvent.VK_E); break;  
     case 'f': doType(KeyEvent.VK_F); break;  
     case 'g': doType(KeyEvent.VK_G); break;  
     case 'h': doType(KeyEvent.VK_H); break;  
     case 'i': doType(KeyEvent.VK_I); break;  
     case 'j': doType(KeyEvent.VK_J); break;  
     case 'k': doType(KeyEvent.VK_K); break;  
     case 'l': doType(KeyEvent.VK_L); break;  
     case 'm': doType(KeyEvent.VK_M); break;  
     case 'n': doType(KeyEvent.VK_N); break;  
     case 'o': doType(KeyEvent.VK_O); break;  
     case 'p': doType(KeyEvent.VK_P); break;  
     case 'q': doType(KeyEvent.VK_Q); break;  
     case 'r': doType(KeyEvent.VK_R); break;  
     case 's': doType(KeyEvent.VK_S); break;  
     case 't': doType(KeyEvent.VK_T); break;  
     case 'u': doType(KeyEvent.VK_U); break;  
     case 'v': doType(KeyEvent.VK_V); break;  
     case 'w': doType(KeyEvent.VK_W); break;  
     case 'x': doType(KeyEvent.VK_X); break;  
     case 'y': doType(KeyEvent.VK_Y); break;  
     case 'z': doType(KeyEvent.VK_Z); break;  
     case 'A': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_A); break;  
     case 'B': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_B); break;  
     case 'C': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_C); break;  
     case 'D': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_D); break;  
     case 'E': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_E); break;  
     case 'F': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_F); break;  
     case 'G': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_G); break;  
     case 'H': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_H); break;  
     case 'I': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_I); break;  
     case 'J': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_J); break;  
     case 'K': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_K); break;  
     case 'L': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_L); break;  
     case 'M': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_M); break;  
     case 'N': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_N); break;  
     case 'O': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_O); break;  
     case 'P': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_P); break;  
     case 'Q': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_Q); break;  
     case 'R': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_R); break;  
     case 'S': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_S); break;  
     case 'T': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_T); break;  
     case 'U': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_U); break;  
     case 'V': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_V); break;  
     case 'W': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_W); break;  
     case 'X': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_X); break;  
     case 'Y': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_Y); break;  
     case 'Z': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_Z); break;  
     case '`': doType(KeyEvent.VK_BACK_QUOTE); break;  
     case '0': doType(KeyEvent.VK_0); break;  
     case '1': doType(KeyEvent.VK_1); break;  
     case '2': doType(KeyEvent.VK_2); break;  
     case '3': doType(KeyEvent.VK_3); break;  
     case '4': doType(KeyEvent.VK_4); break;  
     case '5': doType(KeyEvent.VK_5); break;  
     case '6': doType(KeyEvent.VK_6); break;  
     case '7': doType(KeyEvent.VK_7); break;  
     case '8': doType(KeyEvent.VK_8); break;  
     case '9': doType(KeyEvent.VK_9); break;  
     case '-': doType(KeyEvent.VK_MINUS); break;  
     case '=': doType(KeyEvent.VK_EQUALS); break;  
     case '~': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_QUOTE); break;  
     case '!': doType(KeyEvent.VK_EXCLAMATION_MARK); break;  
     case '@': doType(KeyEvent.VK_AT); break;  
     case '#': doType(KeyEvent.VK_NUMBER_SIGN); break;  
     case '$': doType(KeyEvent.VK_DOLLAR); break;  
     case '%': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_5); break;  
     case '^': doType(KeyEvent.VK_CIRCUMFLEX); break;  
     case '&': doType(KeyEvent.VK_AMPERSAND); break;  
     case '*': doType(KeyEvent.VK_ASTERISK); break;  
     case '(': doType(KeyEvent.VK_LEFT_PARENTHESIS); break;  
     case ')': doType(KeyEvent.VK_RIGHT_PARENTHESIS); break;  
     case '_': doType(KeyEvent.VK_UNDERSCORE); break;  
     case '+': doType(KeyEvent.VK_PLUS); break;  
     case '\t': doType(KeyEvent.VK_TAB); break;  
     case '\n': doType(KeyEvent.VK_ENTER); break;  
     case '[': doType(KeyEvent.VK_OPEN_BRACKET); break;  
     case ']': doType(KeyEvent.VK_CLOSE_BRACKET); break;  
     case '\\': doType(KeyEvent.VK_BACK_SLASH); break;  
     case '{': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_OPEN_BRACKET); break;  
     case '}': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_CLOSE_BRACKET); break;  
     case '|': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_SLASH); break;  
     case ';': doType(KeyEvent.VK_SEMICOLON); break;  
     case ':': doType(KeyEvent.VK_COLON); break;  
     case '\'': doType(KeyEvent.VK_QUOTE); break;  
     case '"': doType(KeyEvent.VK_QUOTEDBL); break;  
     case ',': doType(KeyEvent.VK_COMMA); break;  
     case '<': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_COMMA); break;  
     case '.': doType(KeyEvent.VK_PERIOD); break;  
     case '>': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_PERIOD); break;  
     case '/': doType(KeyEvent.VK_SLASH); break;  
     case '?': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_SLASH); break;  
     case ' ': doType(KeyEvent.VK_SPACE); break;  
     default:  
       throw new IllegalArgumentException("Cannot type character " + character);  
     }  
   }  

How it works:
1) This method receives the character to be written
2) It passes the character to a simple switch
3) So for instance if character was 'a' then first case will call doType method with argument KeyEvent.VK_A
4) KeyEvent.VK_A is the keycode for letter 'a'
5) For cases like 'A' the trick is to pass 2 keys to be pressed which are KeyEvent.VK_SHIFT & KeyEvent.VK_A. This makes program to press shift+a which becomes A

doType method:
   protected void doType(int... keyCodes) {  
     doTypeChar(keyCodes, 0, keyCodes.length);  
   }  

How it works:
1) This function obtains the keycode from typeChar function. Now this could be single value('a') or multiple keycodes ('A')
2) This makes a call to dotypechar along with the keycodes and its start and offset value
3) Changing this function as protected so that it can be called by other classes.

dotypeChar method:
   private void doTypeChar(int[] keyCodes, int offset, int length) {  
     if (length == 0) {  
       return;  
     }  
     robot.keyPress(keyCodes[offset]);  
     doTypeChar(keyCodes, offset + 1, length - 1);  
     robot.keyRelease(keyCodes[offset]);  
   }  

How it works:
1) This method finally writes the keycodes
2) First we check if the keycode length is not zero. If zero then nothing to do
3) keypress method comes with Robot class which emulates a key press. It takes the keycode to be typed
4) Here we call the keypress method and pass the keycode[0] we got in argument
5) We make a recursive call to doTypeChar so that if we have 2 keycodes like 'shift+a' then shift had been taken care at step4 but for printing a we again need to make recursive call. In case this function was called to print only single keycode like for only letter 'a' then recursive call to dotypechar will do nothing since length would be zero as checked in step2
6) Now we call keyrelease method of Robot class which releases the key pressed at previous step.

You can also override the typeChar method to add more characters along with the old one's using below method in your subclass:
   @Override  
   public void typeChar(char character) {  
     switch (character) {  
     case 'a': doType(KeyEvent.VK_A); return;  
     }  
     super.typeChar(character);  
   }   

Output:


Full Program:
 package com.cooltrickshome;  
 import java.awt.AWTException;  
 import java.awt.Robot;  
 import java.awt.event.KeyEvent;  
 public class EmulateKeyboard {  
   private Robot robot;  
   public static void main(String[] args) throws Exception {  
        Runtime.getRuntime().exec("notepad.exe");  
        EmulateKeyboard keyboard = new EmulateKeyboard();  
     keyboard.type("Hi, Did you watch the Terminator?\nThe second part was awesome.",50);  
   }  
   public EmulateKeyboard() throws AWTException {  
     this.robot = new Robot();  
   }  
   public EmulateKeyboard(Robot robot) {  
     this.robot = robot;  
   }  
   public void type(CharSequence characters,int delay) {  
     int length = characters.length();  
     for (int i = 0; i < length; i++) {  
       char character = characters.charAt(i);  
       typeChar(character);  
       this.robot.delay(delay);  
     }  
   }  
   public void typeChar(char character) {  
     switch (character) {  
     case 'a': doType(KeyEvent.VK_A); break;  
     case 'b': doType(KeyEvent.VK_B); break;  
     case 'c': doType(KeyEvent.VK_C); break;  
     case 'd': doType(KeyEvent.VK_D); break;  
     case 'e': doType(KeyEvent.VK_E); break;  
     case 'f': doType(KeyEvent.VK_F); break;  
     case 'g': doType(KeyEvent.VK_G); break;  
     case 'h': doType(KeyEvent.VK_H); break;  
     case 'i': doType(KeyEvent.VK_I); break;  
     case 'j': doType(KeyEvent.VK_J); break;  
     case 'k': doType(KeyEvent.VK_K); break;  
     case 'l': doType(KeyEvent.VK_L); break;  
     case 'm': doType(KeyEvent.VK_M); break;  
     case 'n': doType(KeyEvent.VK_N); break;  
     case 'o': doType(KeyEvent.VK_O); break;  
     case 'p': doType(KeyEvent.VK_P); break;  
     case 'q': doType(KeyEvent.VK_Q); break;  
     case 'r': doType(KeyEvent.VK_R); break;  
     case 's': doType(KeyEvent.VK_S); break;  
     case 't': doType(KeyEvent.VK_T); break;  
     case 'u': doType(KeyEvent.VK_U); break;  
     case 'v': doType(KeyEvent.VK_V); break;  
     case 'w': doType(KeyEvent.VK_W); break;  
     case 'x': doType(KeyEvent.VK_X); break;  
     case 'y': doType(KeyEvent.VK_Y); break;  
     case 'z': doType(KeyEvent.VK_Z); break;  
     case 'A': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_A); break;  
     case 'B': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_B); break;  
     case 'C': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_C); break;  
     case 'D': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_D); break;  
     case 'E': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_E); break;  
     case 'F': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_F); break;  
     case 'G': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_G); break;  
     case 'H': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_H); break;  
     case 'I': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_I); break;  
     case 'J': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_J); break;  
     case 'K': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_K); break;  
     case 'L': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_L); break;  
     case 'M': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_M); break;  
     case 'N': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_N); break;  
     case 'O': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_O); break;  
     case 'P': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_P); break;  
     case 'Q': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_Q); break;  
     case 'R': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_R); break;  
     case 'S': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_S); break;  
     case 'T': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_T); break;  
     case 'U': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_U); break;  
     case 'V': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_V); break;  
     case 'W': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_W); break;  
     case 'X': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_X); break;  
     case 'Y': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_Y); break;  
     case 'Z': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_Z); break;  
     case '`': doType(KeyEvent.VK_BACK_QUOTE); break;  
     case '0': doType(KeyEvent.VK_0); break;  
     case '1': doType(KeyEvent.VK_1); break;  
     case '2': doType(KeyEvent.VK_2); break;  
     case '3': doType(KeyEvent.VK_3); break;  
     case '4': doType(KeyEvent.VK_4); break;  
     case '5': doType(KeyEvent.VK_5); break;  
     case '6': doType(KeyEvent.VK_6); break;  
     case '7': doType(KeyEvent.VK_7); break;  
     case '8': doType(KeyEvent.VK_8); break;  
     case '9': doType(KeyEvent.VK_9); break;  
     case '-': doType(KeyEvent.VK_MINUS); break;  
     case '=': doType(KeyEvent.VK_EQUALS); break;  
     case '~': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_QUOTE); break;  
     case '!': doType(KeyEvent.VK_EXCLAMATION_MARK); break;  
     case '@': doType(KeyEvent.VK_AT); break;  
     case '#': doType(KeyEvent.VK_NUMBER_SIGN); break;  
     case '$': doType(KeyEvent.VK_DOLLAR); break;  
     case '%': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_5); break;  
     case '^': doType(KeyEvent.VK_CIRCUMFLEX); break;  
     case '&': doType(KeyEvent.VK_AMPERSAND); break;  
     case '*': doType(KeyEvent.VK_ASTERISK); break;  
     case '(': doType(KeyEvent.VK_LEFT_PARENTHESIS); break;  
     case ')': doType(KeyEvent.VK_RIGHT_PARENTHESIS); break;  
     case '_': doType(KeyEvent.VK_UNDERSCORE); break;  
     case '+': doType(KeyEvent.VK_PLUS); break;  
     case '\t': doType(KeyEvent.VK_TAB); break;  
     case '\n': doType(KeyEvent.VK_ENTER); break;  
     case '[': doType(KeyEvent.VK_OPEN_BRACKET); break;  
     case ']': doType(KeyEvent.VK_CLOSE_BRACKET); break;  
     case '\\': doType(KeyEvent.VK_BACK_SLASH); break;  
     case '{': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_OPEN_BRACKET); break;  
     case '}': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_CLOSE_BRACKET); break;  
     case '|': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_BACK_SLASH); break;  
     case ';': doType(KeyEvent.VK_SEMICOLON); break;  
     case ':': doType(KeyEvent.VK_COLON); break;  
     case '\'': doType(KeyEvent.VK_QUOTE); break;  
     case '"': doType(KeyEvent.VK_QUOTEDBL); break;  
     case ',': doType(KeyEvent.VK_COMMA); break;  
     case '<': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_COMMA); break;  
     case '.': doType(KeyEvent.VK_PERIOD); break;  
     case '>': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_PERIOD); break;  
     case '/': doType(KeyEvent.VK_SLASH); break;  
     case '?': doType(KeyEvent.VK_SHIFT, KeyEvent.VK_SLASH); break;  
     case ' ': doType(KeyEvent.VK_SPACE); break;  
     default:  
       throw new IllegalArgumentException("Cannot type character " + character);  
     }  
   }  
   protected void doType(int... keyCodes) {  
     doTypeChar(keyCodes, 0, keyCodes.length);  
   }  
   private void doTypeChar(int[] keyCodes, int offset, int length) {  
     if (length == 0) {  
       return;  
     }  
     robot.keyPress(keyCodes[offset]);  
     doTypeChar(keyCodes, offset + 1, length - 1);  
     robot.keyRelease(keyCodes[offset]);  
   }  
 }  

Hope it helps :)