这是一个屏幕截图应用程序。使用 1.8 JDK 编译,在64位系统中运行良好,但在32位系统中的两次迭代中滞后和挂起。
基本上这个应用程序使用机器人类获取屏幕截图,从用户获取文件名,这是一个URL。截断并删除所有非法字符,并使用带有时间戳作为前缀的另存为对话框进行保存。
我正在使用 Windows低级KeyHook 以 PrtSc 键启动屏幕截图。
32位系统出错: 它只需要2个屏幕截图,然后在第3次按 PrtSc 时没有响应。 JFrame可以导致任何问题,它肯定加载缓慢。我应该使用除JFrame之外的任何备用文本框,还是因为我已经在java 1.8 jdk 64位环境中编写,这在jdk或32位系统的低版本中无法使用。
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);
}
}
答案 0 :(得分:1)
我没有JNA的任何经验,但是你的代码有几个问题 - 我不认为我得到了所有这些,但是这里有一些:
close.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
quit=true;
}
});
quit=true
将永远无法联系到exit()
,因为您的计划 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
永远不会是ActionListener
。同时旋转变量以检测变化将严重降低应用程序的速度(特别是睡眠时间为10毫秒)。为什么不在 while ((result = lib.GetMessage(msg, null, 0, 0)) != 0) {
中取消挂钩?
null
我不太确定,因为我没有JNA和Windows事件系统的经验。该方法等待发送到指定窗口的消息,但由于您没有指定任何消息(第二个参数是JFrame
),我认为您永远不会得到消息。
frame.setVisible(false);
,但在方法结束时,您只能使用frame.dispose()
隐藏它。由于它仍然是从各种Swing类引用的,因此它永远不会被垃圾收集。这会造成内存泄漏,从而降低应用程序的速度。您必须致电toDateString()
才能摆脱它。