From c3ba2983ddb95ac66056b8b617115e6fc2348b6d Mon Sep 17 00:00:00 2001 From: DaniTheSkunk Date: Tue, 27 Sep 2022 04:41:21 +0200 Subject: [PATCH] added winapi type stuff --- Test.java | 15 +++ com/danitheskunk/skunkworks/windows/Dwm.java | 32 +++++ .../skunkworks/windows/TITLEBARINFO.java | 27 ++++ .../skunkworks/windows/User32Extra.java | 67 ++++++++++ .../skunkworks/windows/Window.java | 120 ++++++++++++++++++ notes.md | 21 ++- 6 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 com/danitheskunk/skunkworks/windows/Dwm.java create mode 100644 com/danitheskunk/skunkworks/windows/TITLEBARINFO.java create mode 100644 com/danitheskunk/skunkworks/windows/User32Extra.java create mode 100644 com/danitheskunk/skunkworks/windows/Window.java diff --git a/Test.java b/Test.java index 9b9758b..e695f0f 100644 --- a/Test.java +++ b/Test.java @@ -1,7 +1,21 @@ import com.danitheskunk.skunkworks.*; +import com.danitheskunk.skunkworks.windows.*; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.User32; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinUser; + +import java.util.ArrayList; public class Test { public static void main(String[] args) { + var windows = Window.getAllVisible(); + + System.out.printf("%d Open Windows:\n", windows.size()); + for(var window: windows) { + System.out.printf("%s -- %s -- %s\n", window.getTitle(), window.getClassName(), window.getExecutableName()); + } + /* var engine = new Engine(); var window = engine.openWindow(new Vec2i(1280, 720), "Skunkworks"); var img = engine.loadImage("C:\\Users\\dani\\Videos\\Screenshot 2022-06-25 17-00-59.png"); @@ -34,5 +48,6 @@ public class Test { renderContext.drawString(new Vec2i(710, 140), "hello world mew", font2); window.renderFinish(renderContext); } + */ } } diff --git a/com/danitheskunk/skunkworks/windows/Dwm.java b/com/danitheskunk/skunkworks/windows/Dwm.java new file mode 100644 index 0000000..6614d90 --- /dev/null +++ b/com/danitheskunk/skunkworks/windows/Dwm.java @@ -0,0 +1,32 @@ +package com.danitheskunk.skunkworks.windows; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.win32.W32APIOptions; + +public interface Dwm extends Library { + Dwm INSTANCE = Native.load("dwmapi", Dwm.class, W32APIOptions.DEFAULT_OPTIONS); + + + WinDef.DWORD DWMWA_NCRENDERING_ENABLED = new WinDef.DWORD(1); + WinDef.DWORD DWMWA_NCRENDERING_POLICY = new WinDef.DWORD(2); + WinDef.DWORD DWMWA_TRANSITIONS_FORCEDISABLED = new WinDef.DWORD(3); + WinDef.DWORD DWMWA_ALLOW_NCPAINT = new WinDef.DWORD(4); + WinDef.DWORD DWMWA_CAPTION_BUTTON_BOUNDS = new WinDef.DWORD(5); + WinDef.DWORD DWMWA_NONCLIENT_RTL_LAYOUT = new WinDef.DWORD(6); + WinDef.DWORD DWMWA_FORCE_ICONIC_REPRESENTATION = new WinDef.DWORD(7); + WinDef.DWORD DWMWA_FLIP3D_POLICY = new WinDef.DWORD(8); + WinDef.DWORD DWMWA_EXTENDED_FRAME_BOUNDS = new WinDef.DWORD(9); + WinDef.DWORD DWMWA_HAS_ICONIC_BITMAP = new WinDef.DWORD(10); + WinDef.DWORD DWMWA_DISALLOW_PEEK = new WinDef.DWORD(11); + WinDef.DWORD DWMWA_EXCLUDED_FROM_PEEK = new WinDef.DWORD(12); + WinDef.DWORD DWMWA_CLOAK = new WinDef.DWORD(13); + WinDef.DWORD DWMWA_CLOAKED = new WinDef.DWORD(14); + WinDef.DWORD DWMWA_FREEZE_REPRESENTATION = new WinDef.DWORD(15); + WinDef.DWORD DWMWA_LAST = new WinDef.DWORD(16); + + WinNT.HRESULT DwmGetWindowAttribute(WinDef.HWND hwnd, WinDef.DWORD dwAttribute, Pointer pvAttribute, WinDef.DWORD cbAttribute); +} diff --git a/com/danitheskunk/skunkworks/windows/TITLEBARINFO.java b/com/danitheskunk/skunkworks/windows/TITLEBARINFO.java new file mode 100644 index 0000000..4c443a2 --- /dev/null +++ b/com/danitheskunk/skunkworks/windows/TITLEBARINFO.java @@ -0,0 +1,27 @@ +package com.danitheskunk.skunkworks.windows; + +import com.sun.jna.Structure; +import com.sun.jna.platform.win32.WinDef; + +@Structure.FieldOrder({"cbSize", "rcTitleBar", "rgstate"}) +public class TITLEBARINFO extends Structure { + public int cbSize; + public WinDef.RECT rcTitleBar; + public int[] rgstate; + + public TITLEBARINFO() { + rgstate = new int[CCHILDREN_TITLEBAR + 1]; + cbSize = size(); + } + + // Index constants + public static final int TITLE_BAR = 0; + public static final int RESERVED = 1; + public static final int MINIMIZE_BUTTON = 2; + public static final int MAXIMIZE_BUTTON = 3; + public static final int HELP_BUTTON = 4; + public static final int CLOSE_BUTTON = 5; + + // Child amount constant + public static final int CCHILDREN_TITLEBAR = 5; +} \ No newline at end of file diff --git a/com/danitheskunk/skunkworks/windows/User32Extra.java b/com/danitheskunk/skunkworks/windows/User32Extra.java new file mode 100644 index 0000000..f13a171 --- /dev/null +++ b/com/danitheskunk/skunkworks/windows/User32Extra.java @@ -0,0 +1,67 @@ +package com.danitheskunk.skunkworks.windows; + +import com.sun.jna.Native; +import com.sun.jna.platform.win32.User32; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.win32.W32APIOptions; + +public interface User32Extra extends User32 { + User32Extra INSTANCE = Native.load("user32", User32Extra.class, W32APIOptions.DEFAULT_OPTIONS); + + // States + int STATE_SYSTEM_FOCUSABLE = 0x00100000; + int STATE_SYSTEM_INVISIBLE = 0x00008000; + int STATE_SYSTEM_OFFSCREEN = 0x00010000; + int STATE_SYSTEM_UNAVAILABLE = 0x00000001; + int STATE_SYSTEM_PRESSED = 0x00000008; + + // Extended Styles + // https://docs.microsoft.com/en-gb/windows/desktop/winmsg/extended-window-styles + int WS_EX_ACCEPTFILES = 0x00000010; + int WS_EX_APPWINDOW = 0x00040000; + int WS_EX_CLIENTEDGE = 0x00000200; + int WS_EX_COMPOSITED = 0x02000000; + int WS_EX_CONTEXTHELP = 0x00000400; + int WS_EX_CONTROLPARENT = 0x00010000; + int WS_EX_DLGMODALFRAME = 0x00000001; + int WS_EX_LAYERED = 0x00080000; + int WS_EX_LAYOUTRTL = 0x00400000; + int WS_EX_LEFT = 0x00000000; + int WS_EX_LEFTSCROLLBAR = 0x00004000; + int WS_EX_LTRREADING = 0x00000000; + int WS_EX_MDICHILD = 0x00000040; + int WS_EX_NOACTIVATE = 0x08000000; + int WS_EX_NOINHERITLAYOUT = 0x00100000; + int WS_EX_NOPARENTNOTIFY = 0x00000004; + int WS_EX_NOREDIRECTIONBITMAP = 0x00200000; + int WS_EX_RIGHT = 0x00001000; + int WS_EX_RIGHTSCROLLBAR = 0x00000000; + int WS_EX_RTLREADING = 0x00002000; + int WS_EX_STATICEDGE = 0x00020000; + int WS_EX_TOOLWINDOW = 0x00000080; + int WS_EX_TOPMOST = 0x00000008; + int WS_EX_TRANSPARENT = 0x00000020; + int WS_EX_WINDOWEDGE = 0x00000100; + + long WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE); + long WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST); + + // https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes + int VK_LBUTTON = 0x01; + int VK_RBUTTON = 0x02; + int VK_MBUTTON = 0x04; + + // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-gettitlebarinfo + boolean GetTitleBarInfo(WinDef.HWND hwnd, TITLEBARINFO titlebarinfo); + + // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getlastactivepopup + WinDef.HWND GetLastActivePopup(WinDef.HWND hwnd); + + // https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-isiconic + boolean IsIconic(WinDef.HWND hwnd); + + HCURSOR GetCursor(); + + WinDef.HWND GetTopWindow(HWND hWnd); + WinDef.HWND GetWindow(HWND hWnd, int flag); +} diff --git a/com/danitheskunk/skunkworks/windows/Window.java b/com/danitheskunk/skunkworks/windows/Window.java new file mode 100644 index 0000000..af00a7c --- /dev/null +++ b/com/danitheskunk/skunkworks/windows/Window.java @@ -0,0 +1,120 @@ +package com.danitheskunk.skunkworks.windows; + + +import com.danitheskunk.skunkworks.Util; +import com.sun.jna.Pointer; +import com.sun.jna.platform.win32.*; +import com.sun.jna.ptr.IntByReference; +import com.sun.jna.ptr.PointerByReference; + +import java.util.ArrayList; +import java.util.List; + +public class Window { + private WinDef.HWND hwnd; + + public Window(WinDef.HWND hwnd) { + this.hwnd = hwnd; + } + + public String getClassName() { + var user32 = User32Extra.INSTANCE; + char[] chars = new char[1024]; + + user32.GetClassName(hwnd, chars, 1024); + return Util.nullTerminatedCharArrayToString(chars); + } + + public String getExecutableName() { + var user32 = User32Extra.INSTANCE; + var kernel32 = Kernel32.INSTANCE; + var handle = kernel32.OpenProcess(WinNT.PROCESS_QUERY_LIMITED_INFORMATION, false, getProcessId()); + char[] chars = new char[1024]; + var len = new IntByReference(); + len.setValue(1024); + + kernel32.QueryFullProcessImageName(handle, 0, chars, len); + return Util.nullTerminatedCharArrayToString(chars); + } + + private int getStyle() { + var user32 = User32Extra.INSTANCE; + return user32.GetWindowLong(hwnd, WinUser.GWL_STYLE); + } + + private boolean isTitleBarVisible() { + var tb = getTitleBarInfo(); + return (tb.rgstate[0] & User32Extra.STATE_SYSTEM_INVISIBLE) == 0; + } + + public String getTitle() { + var user32 = User32Extra.INSTANCE; + char[] chars = new char[1024]; + + user32.GetWindowText(hwnd, chars, 1024); + return Util.nullTerminatedCharArrayToString(chars); + } + + private TITLEBARINFO getTitleBarInfo() { + var user32 = User32Extra.INSTANCE; + var tb = new TITLEBARINFO(); + user32.GetTitleBarInfo(hwnd, tb); + return tb; + } + + private int getProcessId() { + var user32 = User32Extra.INSTANCE; + var ref = new IntByReference(); + user32.GetWindowThreadProcessId(hwnd, ref); + return ref.getValue(); + } + + public boolean isDwmCloaked() { + var user32 = User32Extra.INSTANCE; + var dwm = Dwm.INSTANCE; + var out = new IntByReference(); + dwm.DwmGetWindowAttribute(hwnd, Dwm.DWMWA_CLOAKED, out.getPointer(), new WinDef.DWORD(WinDef.DWORD.SIZE)); + var val = out.getValue(); + return val != 0; + } + public boolean isInAltTabList() { + var user32 = User32Extra.INSTANCE; + var walk = user32.GetAncestor(hwnd, WinUser.GA_ROOTOWNER); + WinDef.HWND test; + + while(!(test = user32.GetLastActivePopup(walk)).equals(test)) { + if(user32.IsWindowVisible(test)) + break; + walk = test; + } + var window = new Window(hwnd); + return walk.equals(hwnd) && user32.IsWindowVisible(hwnd) && window.getTitle().length() > 0 && !window.isToolWindow() && !window.isDwmCloaked() && !window.getClassName().equals("Progman"); + } + + public boolean isToolWindow() { + return (getStyle() & User32Extra.WS_EX_TOOLWINDOW) != 0; + } + + //static functions + public static List getAllVisible() { + var user32 = User32Extra.INSTANCE; + var windows = new ArrayList(); + + user32.EnumWindows(new WinUser.WNDENUMPROC() { + @Override + public boolean callback(WinDef.HWND hwnd, Pointer pointer) { + var window = new Window(hwnd); + //if(user32.IsWindowVisible(hwnd) && user32.GetWindow(hwnd, new WinDef.DWORD(User32.GW_OWNER)) == null) { + if(window.isInAltTabList()) { + //if(title.length() > 0) { + //windows.add(window.getTitle() + " -- " + window.getClassName()); + windows.add(window); + //} + } + return true; + } + }, null); + + return windows; + } +} diff --git a/notes.md b/notes.md index ad7f6bd..6b18b62 100644 --- a/notes.md +++ b/notes.md @@ -4,6 +4,13 @@ Just a basic oldschool opengl backend. Not about performance, just about simple implementation. Acting as a proof of concept, and a fallback backend. +## Modding +### Java-style +Not sandboxed, exposing internals and OS apis. +### Scripting-style +Sandboxed, could auto download from server. Which +scripting language to use? Lua? Ruby? Javascript? A +system that allows all of them? ## Networking ### Message style Serialise class, send over network in binary form. @@ -12,8 +19,14 @@ In style of unreal engine 1-3, or enet. Figure out some sort of class decoration for automatic replication? # Todo -## Tileset -Cut image in software in parts, let texture atlas handle -everything, return a List -## Text Rendering ## Gui Toolkit +### Themes +Theme system based on 9-slice. +#### Default theme +#### Fancy themes, like scifi or fantasy +#### CDE? giggle +## Fake terminal mode +Any font possible, but tilesetfonts are perfect for it. +What about multi resolution terminal? like half-width +characters, so text for text, and text for map/actors is +different size. \ No newline at end of file