1

Here's a screenshot application. Compiled with 1.8 JDK, works perfectly well in 64 bit systems, but lags and hangs in two iterations in 32 bit systems.

Basically this application takes a screenshot using robot class, takes the file name from user which is a URL. Truncates and removes all illegal characters from it and saves it using a save as dialog box with time-stamp as the prefix.

I am using Windows Low Level KeyHook to initiate the screenshot with PrtSc key.

Error in 32 bit systems: It only takes 2 screenshots and then does not respond when I press PrtSc for the 3rd time. Can JFrame cause any problems, it certainly loads up slow. Should I use any alternate text box than JFrame or is it because I have complied in java 1.8 jdk 64 bit environment, which wont work in lower versions of jdk or 32 bit systems.

public class KeyHook {
private static HHOOK hhk;
private static LowLevelKeyboardProc keyboardHook;
static JFileChooser fileChooser = new JFileChooser();
public static void main(String[] args) {
    final User32 lib = User32.INSTANCE;
    HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
    keyboardHook = new LowLevelKeyboardProc() {
        public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT info) {
            if (nCode >= 0) {
                switch(wParam.intValue()) {
                case WinUser.WM_KEYUP:
                case WinUser.WM_KEYDOWN:
                case WinUser.WM_SYSKEYUP:
                case WinUser.WM_SYSKEYDOWN:

                 if (info.vkCode == 44) { 


                        try {

                            Robot robot = new Robot();
                            // Capture the screen shot of the area of the screen defined by the rectangle
                             BufferedImage bi=robot.createScreenCapture(new Rectangle(0,25,1366,744));

                             JFrame frame = new JFrame();
                             JFrame.setDefaultLookAndFeelDecorated(true);
                             frame.toFront();
                             frame.requestFocus();
                             frame.setAlwaysOnTop(true);
                             frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                             // prompt the user to enter their name
                             String name = JOptionPane.showInputDialog(frame, "Enter file name");
                            // frame.pack();

                             frame.dispose();
                             String fileName= dovalidateFile(name);

                             FileNameExtensionFilter filter = new FileNameExtensionFilter("PNG", ".png");
                               fileChooser.setFileFilter(filter);
                             fileChooser.setSelectedFile(new File (fileName));


                             int returnVal = fileChooser.showSaveDialog(null);
                             if ( returnVal == JFileChooser.APPROVE_OPTION ){

                                File file = fileChooser.getSelectedFile();


                                 file = validateFile(file);
                                 System.out.println(file);
                                 ImageIO.write(bi, "png", file);

                             }



                      }
                        catch (NullPointerException e1)
                        {e1.printStackTrace(); }
                        catch (AWTException e1) {
                            e1.printStackTrace();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                    }
                }

            return lib.CallNextHookEx(hhk, nCode, wParam, info.getPointer());
        }

        private File validateFile(File file) {
            DateFormat dateFormat = new SimpleDateFormat("HH.mm.ss.ddMMMMMyyyy");
               //get current date time with Calendar()
               Calendar cal = Calendar.getInstance();
              // System.out.println(dateFormat.format(cal.getTime()));
            String filePath = file.getAbsolutePath();

            if (filePath.indexOf(".png") == -1) {
                filePath += "." + dateFormat.format(cal.getTime()) + ".png";
            }
            //System.out.println("File Path :" + filePath);
            file = new File(filePath);
            if (file.exists()) {
                file.delete();
            }
            try {
                file.createNewFile();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return file;

                    }

        private String dovalidateFile(String name) {

            String input = name.replace("https://www.","");  
            input = input.replaceAll("http://www.","");   
            input = input.replaceAll("https://","");    
            input = input.replace("http://","");
            input = input.replace("/?",".");
            input = input.replace("/",".");
            input = input.replace("|",".") ;
            input = input.replace("%",".");
            input = input.replace("<",".");
            input = input.replace(">",".");
            input = input.replaceAll("\\?",".");
            input = input.replaceAll("\\*",".");
            input = input.replace(":",".");
            input = input.replace("\\",".");
            input = Character.toUpperCase(input.charAt(0)) + input.substring(1);
            return input;
        } 
    };
    hhk = lib.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardHook, hMod, 0);

    if(!SystemTray.isSupported()){
        return ;
    }
    SystemTray systemTray = SystemTray.getSystemTray();
    Image image = Toolkit.getDefaultToolkit().getImage(KeyHook.class.getResource("/images/icon.png"));

    //popupmenu
    PopupMenu trayPopupMenu = new PopupMenu();

    MenuItem close = new MenuItem("Exit");
    close.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.err.println("unhook and exit");
            lib.UnhookWindowsHookEx(hhk);
            System.exit(0);

        }
    });
    trayPopupMenu.add(close);

    //setting tray icon
    TrayIcon trayIcon = new TrayIcon(image, "captur", trayPopupMenu);
    //adjust to default size as per system recommendation 
    trayIcon.setImageAutoSize(true);

    try{
        systemTray.add(trayIcon);
    }catch(AWTException awtException){
        awtException.printStackTrace();
    }

    int result;
    MSG msg = new MSG();
    while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
        if (result == -1) {
            System.err.println("error in get message");
            break;
        }
        else {
            System.err.println("got message");
            lib.TranslateMessage(msg);
            lib.DispatchMessage(msg);
        }
      }
         lib.UnhookWindowsHookEx(hhk);

    }
 }
4

1 回答 1

1

我对 JNA 没有任何经验,但是您的代码有几处错误 - 我认为我没有全部了解,但这里有一些:

  1. close.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    
        System.exit(0);   
        quit=true;
    }
    });
    

    quit=true永远不会到达,因为您的程序在exit()它到达那里之前就已经存在。

  2. 2.
     new Thread() {
         public void run() {
             while (!quit) {
                 try { Thread.sleep(10); } catch(Exception e) { }
             }
             System.err.println("unhook and exit");
             lib.UnhookWindowsHookEx(hhk);
             System.exit(0);
         }
     }.start();

没有任何意义,因为quit将永远不会true。此外,在变量上旋转以检测变化会严重减慢您的应用程序(尤其是 10 毫秒的睡眠时间)。为什么不解开你的ActionListener?

    3.
    while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {

在这里我不太确定,因为我没有使用 JNA 和 windows 事件系统的经验。该方法等待发送到指定窗口的消息,但由于您没有指定任何(第二个参数是null),我认为您永远不会得到一个。

  1. 对于每个回调,您都在创建一个新JFrame的,但在方法结束时您只使用frame.setVisible(false);. 因为它仍然被各种 Swing 类引用,所以它永远不会被垃圾收集。这会造成内存泄漏,从而减慢您的应用程序。你将不得不打电话frame.dispose()摆脱它。
于 2015-10-29T08:14:48.117 回答