Skip to content

Commit

Permalink
Add DisplayDevices + Update overlay to use relative position
Browse files Browse the repository at this point in the history
  • Loading branch information
SaifAqqad committed Jul 9, 2023
1 parent 12ba396 commit 65deead
Show file tree
Hide file tree
Showing 3 changed files with 456 additions and 113 deletions.
172 changes: 172 additions & 0 deletions src/Lib/DisplayDevices.ahk
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#Requires AutoHotkey v1.1.35+

class DisplayDevices {
static _wmiPath := "winmgmts:{impersonationLevel=impersonate}!\\" A_ComputerName "\root\wmi"
, _length_DisplayDevice := 4 + 4 + ((32 + 128 + 128 + 128) * 2)
, _offset_DeviceString := 4 + (32 * 2)
, _length_DeviceString := 128
, _offset_DeviceID := 4 + 4 + ((32 + 128) * 2)
, _length_DeviceID := 128
, _cachedDisplays := ""
, _primaryDisplayId := ""

_NewEnum() {
return new DisplayDevices.DisplayEnumerator(DisplayDevices._cachedDisplays)
}

getById(id) {
return DisplayDevices._cachedDisplays[id]`
}

getPrimary() {
return DisplayDevices._cachedDisplays[DisplayDevices._primaryDisplayId]
}

getByPosition(x, y) {
if (DisplayDevices.isRelativePosition(x, y))
return ""

for id, display in DisplayDevices._cachedDisplays {
if (display.isInBounds(x, y))
return display
}
}

updateCachedDisplays() {
Critical, On

util_log("[DisplayDevices] Updating cached displays")

DisplayDevices._cachedDisplays := {}

SysGet, primaryIndex, MonitorPrimary
SysGet, displayCount, MonitorCount

Loop %displayCount% {
SysGet, mPos, Monitor, %A_Index%

VarSetCapacity(lpDisplayDevice, this._length_DisplayDevice, 0)
Numput(this._length_DisplayDevice, lpDisplayDevice, 0, "UInt")

VarSetCapacity(lpDevice, this._length_DeviceString * 2, 0)
SysGet, dName, MonitorName, %A_Index%
StrPut(dName, &lpDevice, this._length_DeviceString)

DllCall("EnumDisplayDevices", "Ptr", &lpDevice, "UInt", 0, "Ptr", &lpDisplayDevice, "UInt", 0x00000001)
displayName := StrGet(&lpDisplayDevice + this._offset_DeviceString, this._length_DeviceString)
displayPath := StrGet(&lpDisplayDevice + this._offset_DeviceID, this._length_DeviceID)

displayInstanceName := this._parseInstanceName(displayPath)
displaySerialNum:= this._getSerialNumber(displayInstanceName)

display:= new DisplayDevices.Display(displayName, displaySerialNum, A_Index = primaryIndex, mPosTop, mPosRight, mPosLeft, mPosBottom)

DisplayDevices._cachedDisplays[display.Id] := display

if (display.Primary)
DisplayDevices._primaryDisplayId := display.Id
}

Critical, Off
}

isRelativePosition(x, y) {
return (x > 0 && x < 1 && y > 0 && y < 1)
}

_parseInstanceName(path) {
local
pos:=1, M:= ""

while (pos := RegExMatch(path, "(?<=#).*?(?=#)", M, pos+StrLen(M))) {
M%A_Index% := M
}

return Format("DISPLAY\{}\{}", M1, M2)
}

_getSerialNumber(instance) {
displaysQuery := ComObjGet(this._wmiPath).ExecQuery("Select * from WmiMonitorID")

for display in displaysQuery {
if(!InStr(display.InstanceName, instance))
Continue

displaySerialNum := ""

for char in display.SerialNumberID
displaySerialNum .= chr(char)

return displaySerialNum
}

return ""
}

class Display {
__New(name, serialNumber, primary, topPos, rightPos, leftPos, bottomPos) {
this.Name := Trim(name)
this.SerialNumber := Trim(serialNumber)

this.Id := this.Name "_" this.SerialNumber
this.Primary := primary

this.Width := Abs(rightPos - leftPos)
this.Height := Abs(bottomPos - topPos)

this.Bounds := { "Left": leftPos, "Right": rightPos, "Top": topPos, "Bottom": bottomPos }
}

isInBounds(x, y) {
return (x >= this.Bounds.Left && x <= this.Bounds.Right && y >= this.Bounds.Top && y <= this.Bounds.Bottom)
}

getRelativePosition(x, y) {
if (DisplayDevices.isRelativePosition(x, y))
return { "X" : x, "Y" : y }

if (!this.isInBounds(x,y))
return ""

position := { "X" : x - this.Bounds.Left, "Y" : y - this.Bounds.Top, "DisplayId" : this.Id }

position.X := Abs(position.X) / this.Width
position.Y := Abs(position.Y) / this.Height

return position
}

getAbsolutePosition(x, y) {
if (!DisplayDevices.isRelativePosition(x, y)){
if (this.isInBounds(x,y))
return { "X" : x, "Y" : y, "DisplayId" : this.Id }

return ""
}

position := { "X" : x * this.Width, "Y" : y * this.Height, "DisplayId" : this.Id }

position.X := this.Bounds.Left + position.X
position.Y := this.Bounds.Top + position.Y

return position
}
}

class DisplayEnumerator {
__New(displays) {
this.displays := displays
this.innerEnum := displays._NewEnum()
this.index := 1
}

Next(ByRef key, ByRef value) {
retValue := this.innerEnum.Next(key, value)
key := this.index++
return retValue
}
}
}

DisplayDevices.updateCachedDisplays()
OnMessage(0x007E, ObjBindMethod(DisplayDevices, "updateCachedDisplays"), -1)
27 changes: 14 additions & 13 deletions src/MicMute.ahk
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ SetWorkingDir %A_ScriptDir%
#Include, <StackSet>
#Include, <AuraSync>
#Include, <SoundPlayer>
#Include, <DisplayDevices>
#Include, <B64>
#Include, <IPC>

Expand Down Expand Up @@ -106,6 +107,7 @@ Global A_startupTime:= A_TickCount
, updater_UI:=""
, WM_SETTINGCHANGE:= 0x001A
, WM_DEVICECHANGE := 0x0219
, WM_DISPLAYCHANGE := 0x007E

; parse cli args
parseArgs()
Expand Down Expand Up @@ -139,7 +141,6 @@ if(A_IsCompiled && !arg_reload && config_obj.AllowUpdateChecker=1){
A_startupTime:= A_TickCount - A_startupTime
util_log("[Main] MicMute startup took " A_startupTime "ms")


initilizeMicMute(default_profile:="", exportConfig:=1){
util_log("[Main] Initilizing MicMute")

Expand All @@ -148,7 +149,7 @@ initilizeMicMute(default_profile:="", exportConfig:=1){
for _i,mic in mic_controllers
mic.disableController()

;destroy existing guis
;destroy existing guis
overlay_wnd.destroy()
osd_wnd.destroy()

Expand Down Expand Up @@ -189,7 +190,7 @@ initilizeMicMute(default_profile:="", exportConfig:=1){

;enable linked apps timer
SetTimer, checkLinkedApps, % watched_profiles.Length()? 3000 : "Off"
;enable checkConfigDiff timer
;enable checkConfigDiff timer
setTimer, checkConfigDiff, 3000

;update theme variables
Expand Down Expand Up @@ -222,7 +223,7 @@ switchProfile(p_name:=""){
;turn off profile-specific timers
try SetTimer, checkIsIdle, Off

;destroy existing guis
;destroy existing guis
overlay_wnd.destroy()
osd_wnd.destroy()
sound_player.__free()
Expand Down Expand Up @@ -320,7 +321,7 @@ switchProfile(p_name:=""){
for _i, registration in registrations {
registration.callbackObj.force_current_state:= 1
}
}
}
}
}else{
if(current_profile.OnscreenOverlay.Enabled){
Expand Down Expand Up @@ -372,7 +373,7 @@ showFeedback(microphone){
if (current_profile.SoundFeedback){
file:= resources_obj.getSoundFile(microphone.state, microphone.isPushToTalk)
sound_player.play(file)
}
}

if (current_profile.OnscreenFeedback)
osd_wnd.showAndHide(microphone.getStateString(), !microphone.state)
Expand All @@ -392,7 +393,7 @@ editConfig(){
try osd_wnd.destroy()
Thread, NoTimers, 1
if(current_profile){
for _i, mic in mic_controllers
for _i, mic in mic_controllers
mic.disableController()
overlay_wnd.destroy()
SetTimer, checkIsIdle, Off
Expand Down Expand Up @@ -479,7 +480,7 @@ onUpdateState(microphone){
} else {
tray_defaults()
}

for _i, action in mic_actions {
action.run(microphone)
}
Expand All @@ -505,7 +506,7 @@ exitMicMute(){
}

reloadMicMute(p_profile:=""){
args:= Format("/reload=1 ""/profile={1:}"" /debug={2:} /noui={3:} ""/logFile={4:}"""
args:= Format("/reload=1 ""/profile={1:}"" /debug={2:} /noui={3:} ""/logFile={4:}"""
, p_profile, arg_isDebug, arg_noUI, arg_logFile)
util_log("[Main] Reloading MicMute with args (" args ")")
if(A_IsCompiled)
Expand All @@ -521,17 +522,17 @@ parseArgs(){
if(!match)
continue
switch val1 {
case "debug":
case "debug":
arg_isDebug:= (val3=""? 1 : val3)
args_str.= val " "
case "noui":
case "noui":
arg_noUI:= (val3=""? 1 : val3)
args_str.= val " "
case "profile":
case "profile":
arg_profile:= val3
args_str.= val " "
case "reload": arg_reload:= (val3=""? 1 : val3)
case "logFile":
case "logFile":
arg_logFile:= val3
args_str.= val " "
case "updater": arg_isUpdater:= (val3=""? 1 : val3)
Expand Down
Loading

0 comments on commit 65deead

Please sign in to comment.