Compare commits
4 Commits
59cad38f74
...
83e3c53ebc
| Author | SHA1 | Date |
|---|---|---|
|
|
83e3c53ebc | |
|
|
b8f64ad4ba | |
|
|
a9ba42d24c | |
|
|
4836e4c4c0 |
|
|
@ -0,0 +1,2 @@
|
||||||
|
class MIA { //TODO: Semantic Kernel Class
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
import javax.sound.sampled.AudioFormat
|
||||||
|
import javax.sound.sampled.AudioSystem
|
||||||
|
import javax.sound.sampled.DataLine
|
||||||
|
import javax.sound.sampled.TargetDataLine
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class Microphone {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private val source = getSource()
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private val audioFormat = getFormat()
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun startCapture() {
|
||||||
|
source.start()
|
||||||
|
//TODO: Start processing loop in new coroutine and check if it could be moved into own file
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun stopCapture() {
|
||||||
|
source.stop()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun closeSource() {
|
||||||
|
source.close()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private fun getFormat(): AudioFormat {
|
||||||
|
return AudioFormat( //TODO: Get format settings from user settings
|
||||||
|
16000.0f, // 16000 Required
|
||||||
|
16,
|
||||||
|
2,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private fun getSource(): TargetDataLine {
|
||||||
|
val info = DataLine.Info(
|
||||||
|
TargetDataLine::class.java,
|
||||||
|
audioFormat
|
||||||
|
)
|
||||||
|
val source = AudioSystem.getLine(info) as TargetDataLine
|
||||||
|
source.open(audioFormat)
|
||||||
|
|
||||||
|
return source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
import org.vosk.Model
|
||||||
|
import org.vosk.Recognizer
|
||||||
|
import java.nio.file.Paths
|
||||||
|
/**
|
||||||
|
* TODO: Documentation
|
||||||
|
*/
|
||||||
|
class STT {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private val model = Model(getModelPath())
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private val recognizer = Recognizer(model, 16000.0f)
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun parseBuffer(buffer: ByteArray, audioBytes: Int): String? {
|
||||||
|
return if (recognizer.acceptWaveForm(buffer, audioBytes)) {
|
||||||
|
recognizer.result
|
||||||
|
} else {
|
||||||
|
recognizer.partialResult
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun closeModel() {
|
||||||
|
recognizer.close()
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private fun getModelPath(): String {
|
||||||
|
return Paths.get(
|
||||||
|
javaClass.getResource("STT-model")!!.toURI()
|
||||||
|
).toFile().absolutePath
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Install model into dir from resource link
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package window_control
|
||||||
|
|
||||||
|
enum class OS {
|
||||||
|
Windows,
|
||||||
|
Mac,
|
||||||
|
Linux
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package window_control
|
||||||
|
|
||||||
|
import com.sun.jna.Library
|
||||||
|
import com.sun.jna.Native
|
||||||
|
import com.sun.jna.platform.win32.WinDef
|
||||||
|
import com.sun.jna.win32.W32APIOptions
|
||||||
|
import java.awt.Point
|
||||||
|
import java.awt.Robot
|
||||||
|
import java.awt.event.KeyEvent
|
||||||
|
|
||||||
|
class WindowController { //TODO: Class that controls program window
|
||||||
|
private val os = OS.valueOf(System.getProperty("os.name"))
|
||||||
|
private val inputController = Robot()
|
||||||
|
|
||||||
|
fun setActiveWindow(windowName: String) {
|
||||||
|
when (os) {
|
||||||
|
OS.Windows -> activateWindowsWindow(windowName)
|
||||||
|
OS.Mac -> activateMacWindow(windowName)
|
||||||
|
OS.Linux -> activateLinuxWindow(windowName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendKeyPresses(keyCodes: Array<Int>) {
|
||||||
|
keyCodes.iterator().forEach { keyCode ->
|
||||||
|
inputController.keyPress(keyCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun sendKeyReleases(keyCodes: Array<Int>) {
|
||||||
|
keyCodes.iterator().forEach { keyCode ->
|
||||||
|
inputController.keyRelease(keyCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun sendKeyStrokes(keyCodes: Array<Int>, delay: Int?) { //TODO: Create KeyList Class
|
||||||
|
keyCodes.iterator().forEach { keyCode ->
|
||||||
|
sendKeyPresses(arrayOf(keyCode))
|
||||||
|
inputController.delay(delay!!)
|
||||||
|
sendKeyReleases(arrayOf(keyCode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMultiKeyStrokes(commands: Array<Array<Int>>, delay: Int?) { //TODO: Create MultiKeyList Class
|
||||||
|
commands.iterator().forEach { command ->
|
||||||
|
sendMousePresses(command)
|
||||||
|
inputController.delay(delay!!)
|
||||||
|
sendMouseReleases(command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sendMousePresses(buttonCodes: Array<Int>) { //TODO: Create ButtonList Class
|
||||||
|
buttonCodes.iterator().forEach { buttonCode ->
|
||||||
|
inputController.mousePress(buttonCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun sendMouseReleases(buttonCodes: Array<Int>) {
|
||||||
|
buttonCodes.iterator().forEach { buttonCode ->
|
||||||
|
inputController.mouseRelease(buttonCode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun sendMouseLocation(location: Point) {
|
||||||
|
inputController.mouseMove(location.x, location.y)
|
||||||
|
}
|
||||||
|
fun sendMouseStrokes(buttonCodes: Array<Int>, delay: Int?) {
|
||||||
|
buttonCodes.iterator().forEach { buttonCode ->
|
||||||
|
sendMousePresses(arrayOf(buttonCode))
|
||||||
|
inputController.delay(delay!!)
|
||||||
|
sendMouseReleases(arrayOf(buttonCode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun sendMouseStrokesAtLocation(buttonCodes: Array<Int>, delay: Int?, location: Point) {
|
||||||
|
sendMouseLocation(location)
|
||||||
|
buttonCodes.iterator().forEach { buttonCode ->
|
||||||
|
sendMouseStrokes(arrayOf(buttonCode), delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fun sendMouseStrokesAtLocations(commands: Array<Pair<Point,Array<Int>>>, delay: Int?) {
|
||||||
|
commands.iterator().forEach { command ->
|
||||||
|
sendMouseLocation(command.first)
|
||||||
|
sendMouseStrokes(command.second, delay)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun activateWindowsWindow(windowName: String) {
|
||||||
|
val window = User32.INSTANCE.findWindow(null, windowName)
|
||||||
|
User32.INSTANCE.setActiveWindow(window)
|
||||||
|
}
|
||||||
|
private fun activateMacWindow(windowName: String) {
|
||||||
|
val command = arrayOf("osascript", "-e", "tell application \"$windowName\" to activate") //TODO: double check how this command works to ensure it works
|
||||||
|
Runtime.getRuntime().exec(command).waitFor()
|
||||||
|
}
|
||||||
|
private fun activateLinuxWindow(windowName: String) {
|
||||||
|
val xorgFlag = System.getenv("DISPLAY")
|
||||||
|
val hyprlandFlag = System.getenv("HYPRLAND_CMD") //TODO: User override of default checks, and add sway compatibility
|
||||||
|
|
||||||
|
if (hyprlandFlag != null) {
|
||||||
|
val command = arrayOf("hyprctl", "dispatch", "focuswindow", windowName) //TODO: need to check both class regex and title regex (look at hyprland wiki)
|
||||||
|
Runtime.getRuntime().exec(command).waitFor()
|
||||||
|
}
|
||||||
|
else if (xorgFlag != null) {
|
||||||
|
val command = arrayOf("xdotool", "search", "--name", windowName, "windowactivate")
|
||||||
|
Runtime.getRuntime().exec(command).waitFor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface User32: Library {
|
||||||
|
companion object {
|
||||||
|
val INSTANCE: User32 = Native.load("user32", User32::class.java, W32APIOptions.DEFAULT_OPTIONS)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun findWindow(className: String?, windowName: String?): WinDef.HWND
|
||||||
|
fun setActiveWindow(window: WinDef.HWND): Boolean
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue