Skip to content

Commit

Permalink
[Feat] Free move overlay window (#20)
Browse files Browse the repository at this point in the history
* move overlay around freely

* change font and remove commented code
  • Loading branch information
Danil0v3s authored Oct 26, 2024
1 parent 25fb4b8 commit 27f29df
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 105 deletions.
6 changes: 6 additions & 0 deletions core/native/src/main/kotlin/hwinfo/HwInfoReader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ import kotlinx.coroutines.flow.flow
import util.getByteBuffer
import util.readString
import win32.WindowsService
import java.lang.foreign.Arena
import java.lang.foreign.MemorySegment
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.channels.FileChannel
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import kotlin.coroutines.cancellation.CancellationException

private const val MEMORY_MAP_FILE_NAME = "Global\\HWiNFO_SENS_SM2"
Expand Down
12 changes: 9 additions & 3 deletions core/native/src/main/kotlin/win32/WindowsService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,16 @@ class WindowsService {
}

companion object {
fun makeComponentTransparent(w: Component) {
fun changeWindowTransparency(w: Component, isTransparent: Boolean) {
val hwnd = HWND().apply { pointer = Native.getComponentPointer(w) }
val wl =
User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE) or WinUser.WS_EX_LAYERED or WinUser.WS_EX_TRANSPARENT
val wl = if (isTransparent) {
User32.INSTANCE.GetWindowLong(
hwnd,
WinUser.GWL_EXSTYLE
) or WinUser.WS_EX_LAYERED or WinUser.WS_EX_TRANSPARENT
} else {
User32.INSTANCE.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE) or WinUser.WS_EX_LAYERED and WinUser.WS_EX_TRANSPARENT.inv()
}
User32.INSTANCE.SetWindowLong(hwnd, WinUser.GWL_EXSTYLE, wl)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package br.com.firstsoft.target.server

import PreferencesRepository
import androidx.compose.foundation.window.WindowDraggableArea
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
Expand All @@ -10,6 +11,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.ApplicationScope
Expand All @@ -35,6 +37,8 @@ import ui.app.Settings
import win32.WindowsService
import java.awt.GraphicsEnvironment
import java.awt.Toolkit
import java.awt.event.ComponentAdapter
import java.awt.event.ComponentEvent

val positions = listOf(
Alignment.TopStart,
Expand All @@ -59,9 +63,7 @@ private fun loadOverlaySettings(): OverlaySettings {
return settings
}

fun main() {
val channel = Channel<Unit>()

private fun registerKeyboardHook(onHotkey: () -> Unit) {
GlobalScreen.registerNativeHook()
GlobalScreen.addNativeKeyListener(object : NativeKeyListener {
override fun nativeKeyReleased(nativeEvent: NativeKeyEvent) {
Expand All @@ -70,26 +72,53 @@ fun main() {
val isF10 = nativeEvent.keyCode == NativeKeyEvent.VC_F10

if (isCtrl && isAlt && isF10) {
channel.trySend(Unit)
onHotkey()
}
}
})
}

fun main() {
val channel = Channel<Unit>()

registerKeyboardHook { channel.trySend(Unit) }

application {
var overlaySettings by remember { mutableStateOf(loadOverlaySettings()) }
var overlayPosition by remember {
mutableStateOf(
IntOffset(
overlaySettings.positionX,
overlaySettings.positionY
)
)
}

OverlayWindow(channel, overlaySettings)
OverlayWindow(
channel = channel,
overlaySettings = overlaySettings,
onPositionChanged = {
if (!overlaySettings.isPositionLocked) {
overlayPosition = it
}
},
)

SettingsWindow(overlaySettings, {
overlaySettings = it
})
SettingsWindow(
overlaySettings = overlaySettings,
onOverlaySettings = {
overlaySettings = it
},
getOverlayPosition = { overlayPosition }
)
}
}

@Composable
private fun ApplicationScope.OverlayWindow(
channel: Channel<Unit>,
overlaySettings: OverlaySettings
overlaySettings: OverlaySettings,
onPositionChanged: (IntOffset) -> Unit
) {
var isVisible by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
Expand All @@ -101,6 +130,7 @@ private fun ApplicationScope.OverlayWindow(
val overlayState = rememberWindowState().apply {
size = if (overlaySettings.isHorizontal) DpSize(1280.dp, 80.dp) else DpSize(350.dp, 1280.dp)
placement = WindowPlacement.Floating
position = WindowPosition.Absolute(overlaySettings.positionX.dp,overlaySettings.positionY.dp)
}

val graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment()
Expand All @@ -117,9 +147,15 @@ private fun ApplicationScope.OverlayWindow(
alwaysOnTop = true,
transparent = true,
undecorated = true,
focusable = false,
enabled = false,
focusable = !overlaySettings.isPositionLocked,
enabled = !overlaySettings.isPositionLocked,
) {
window.addComponentListener(object : ComponentAdapter() {
override fun componentMoved(e: ComponentEvent) {
onPositionChanged(IntOffset(e.component.x, e.component.y))
}
})

LaunchedEffect(overlaySettings) {
if (overlaySettings.positionIndex < 6) {
val alignment = positions[overlaySettings.positionIndex]
Expand Down Expand Up @@ -155,27 +191,25 @@ private fun ApplicationScope.OverlayWindow(
overlayState.position = WindowPosition.Aligned(alignment)
window.setLocation(location.width, location.height)
} else {
val relativeX = graphicsConfiguration.bounds.x + (graphicsConfiguration.bounds.width * (overlaySettings.positionX / 100f)) - (window.bounds.width / 2)
val relativeY = graphicsConfiguration.bounds.y + (graphicsConfiguration.bounds.height * (overlaySettings.positionY / 100f)) - window.bounds.height - taskbarHeight
val x = relativeX.coerceIn(graphicsConfiguration.bounds.x.toFloat(), (graphicsConfiguration.bounds.x + graphicsConfiguration.bounds.width - window.bounds.width).toFloat())
val y = relativeY.coerceIn(graphicsConfiguration.bounds.y.toFloat(), (graphicsConfiguration.bounds.y + graphicsConfiguration.bounds.height - window.bounds.height - taskbarHeight).toFloat())

overlayState.position = WindowPosition.PlatformDefault
window.setLocation(x.toInt(),y.toInt())
overlayState.position = WindowPosition.Absolute(overlaySettings.positionX.dp,overlaySettings.positionY.dp)
}

window.toFront()
}

WindowsService.makeComponentTransparent(window)
Overlay(overlaySettings = overlaySettings)
WindowsService.changeWindowTransparency(window, overlaySettings.isPositionLocked)

WindowDraggableArea {
Overlay(overlaySettings = overlaySettings)
}
}
}

@Composable
private fun ApplicationScope.SettingsWindow(
overlaySettings: OverlaySettings,
onOverlaySettings: (OverlaySettings) -> Unit
onOverlaySettings: (OverlaySettings) -> Unit,
getOverlayPosition: () -> IntOffset,
) {
var isVisible by remember {
mutableStateOf(
Expand Down Expand Up @@ -203,7 +237,8 @@ private fun ApplicationScope.SettingsWindow(
overlaySettings = overlaySettings,
onOverlaySettings = onOverlaySettings,
onCloseRequest = { isVisible = false },
onMinimizeRequest = { state.isMinimized = true }
onMinimizeRequest = { state.isMinimized = true },
getOverlayPosition = getOverlayPosition
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.WindowScope
Expand All @@ -56,21 +57,13 @@ import ui.AppSettingsUi

const val OVERLAY_SETTINGS_PREFERENCE_KEY = "OVERLAY_SETTINGS_PREFERENCE_KEY"

val positionsLabels = listOf(
"Top Start",
"Top Center",
"Top End",
"Bottom Start",
"Bottom Center",
"Bottom End",
)

@Composable
fun WindowScope.Settings(
overlaySettings: OverlaySettings,
onCloseRequest: () -> Unit,
onMinimizeRequest: () -> Unit,
onOverlaySettings: (OverlaySettings) -> Unit,
getOverlayPosition: () -> IntOffset
) = AppTheme {
LaunchedEffect(overlaySettings) {
PreferencesRepository.setPreference(OVERLAY_SETTINGS_PREFERENCE_KEY, Json.encodeToString(overlaySettings))
Expand Down Expand Up @@ -122,7 +115,7 @@ fun WindowScope.Settings(

when (selectedTabIndex) {
0 -> OverlaySettingsUi(overlaySettings, onOverlaySettings)
1 -> StyleUi(overlaySettings, onOverlaySettings)
1 -> StyleUi(overlaySettings, onOverlaySettings, getOverlayPosition)
2 -> AppSettingsUi()
else -> Unit
}
Expand Down Expand Up @@ -248,6 +241,7 @@ data class OverlaySettings(
val progressType: ProgressType = ProgressType.Circular,
val positionX: Int = 0,
val positionY: Int = 0,
val isPositionLocked: Boolean = true,
val upRate: Boolean = false,
val downRate: Boolean = false,
val netGraph: Boolean = false,
Expand Down
Loading

0 comments on commit 27f29df

Please sign in to comment.