Page 1 of 1

Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 5:08 pm
by Quin
I found this Stack Overflow answer about how to eliminate the frankly incredibly annoying message beep that occurs when doing many actions in an EditorGadget/rich text control. However, COM in PB terrifies me and I'm frankly horrible at it, and have no idea how to do any of this. I figured one of the wizards here might have already done this and/or know how?
Thanks in advance for any help!

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 5:59 pm
by breeze4me
The converted code.

Code: Select all

Interface ITextServices Extends IUnknown
  ; 	//@cmember Generic Send Message interface
  TxSendMessage.l(msg.l,  wparam,  lparam, *plresult)
  ; 	
  ; 	//@cmember Rendering
  TxDraw.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcBounds, *lprcWBounds, *lprcUpdate, pfnContinue, dwContinue.l, lViewId.l)
  ; 
  ; 	//@cmember Horizontal scrollbar support
  TxGetHScroll.l(*plMin, *plMax, *plPos, *plPage, *pfEnabled)
  ; 
  ; 	//@cmember Horizontal scrollbar support
  TxGetVScroll.l(*plMin, *plMax, *plPos, *plPage, *pfEnabled)
  ; 
  ; 	//@cmember Setcursor
  OnTxSetCursor.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcClient, x.l, y.l)
  ; 
  ; 	//@cmember Hit-test
  TxQueryHitPoint.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcClient, x.l, y.l, *pHitResult)
  ; 
  ; 	//@cmember Inplace activate notification
  OnTxInPlaceActivate.l(*prcClient)
  ; 
  ; 	//@cmember Inplace deactivate notification
  OnTxInPlaceDeactivate.l()
  ; 
  ; 	//@cmember UI activate notification
  OnTxUIActivate.l()
  ; 
  ; 	//@cmember UI deactivate notification
  OnTxUIDeactivate.l()
  ; 
  ; 	//@cmember Get text in control
  TxGetText.l(*pbstrText)
  ; 
  ; 	//@cmember Set text in control
  TxSetText.l(pszText.s)
  ; 	
  ; 	//@cmember Get x position of 
  TxGetCurTargetX.l(*result)
  ; 	//@cmember Get baseline position
  TxGetBaseLinePos.l(*result)
  ; 
  ; 	//@cmember Get Size to fit / Natural size
  TxGetNaturalSize.l(dwAspect.l, hdcDraw, hicTargetDev, *ptd, dwMode.l, *psizelExtent, *pwidth, *pheight)
  ; 
  ; 	//@cmember Drag & drop
  TxGetDropTarget.l(*ppDropTarget)
  ; 
  ; 	//@cmember Bulk bit property change notifications
  OnTxPropertyBitsChange.l(dwMask.l, dwBits.l)
  ; 
  ; 	//@cmember Fetch the cached drawing size .l(logical not physical)
  TxGetCachedSize.l(*pdwWidth, *pdwHeight)
EndInterface

#TXTBIT_ALLOWBEEP = 2048

DataSection
  IID_ITextServices: ; 8d33f740-cf58-11ce-a89d-00aa006cadc5
  Data.l $8d33f740
  Data.w $cf58, $11ce
  Data.b $a8, $9d, $00, $aa, $00, $6c, $ad, $c5
EndDataSection


If OpenWindow(0, 0, 0, 322, 150, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  EditorGadget(0, 8, 8, 306, 133)
  
  If SendMessage_(GadgetID(0), #EM_GETOLEINTERFACE, 0, @Unk.IUnknown)
    If Unk
      If unk\QueryInterface(?IID_ITextServices, @TxtSrv.ITextServices) = #S_OK
        If TxtSrv
          If TxtSrv\OnTxPropertyBitsChange(#TXTBIT_ALLOWBEEP, 0) = #S_OK
            Debug "OK"
          EndIf
          TxtSrv\Release()
        EndIf
      EndIf
      Unk\Release()
    EndIf
  EndIf
  
  For a = 0 To 5
    AddGadgetItem(0, a, "Line "+Str(a))
  Next
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 6:52 pm
by Fred
Nice code, as always @breeze4me

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 7:03 pm
by Quin
Hi breeze4me,
This works great, thanks for sharing!
When I try to use it in an app that uses dialogs however, more specifically DynamicDialogs, the beeps stay enabled. Is this a limitation of the dialog library?

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 8:03 pm
by RASHAD
Nice code breeze4me but it works only for PB x64
Simple approach

Code: Select all

  If OpenWindow(0, 0, 0, 400,300, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(0, 8, 8, 306, 133)
    For a = 0 To 5
      AddGadgetItem(0, a, "Line "+Str(a))
    Next
    ButtonGadget(1,10,260,150,24,"Sound On/Off",#PB_Button_Toggle)
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Quit = 1
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case 1
              If GetGadgetState(1) = 1
                keybd_event_($AD, 0, 1, 0)
              Else
                keybd_event_($AD, 0, 1, 0)
              EndIf
                
          EndSelect    
      EndSelect
    Until Quit = 1    
  EndIf

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 8:32 pm
by Quin
RASHAD wrote: Mon Apr 14, 2025 8:03 pm Nice code breeze4me but it works only for PB x64
Simple approach

Code: Select all

  If OpenWindow(0, 0, 0, 400,300, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    EditorGadget(0, 8, 8, 306, 133)
    For a = 0 To 5
      AddGadgetItem(0, a, "Line "+Str(a))
    Next
    ButtonGadget(1,10,260,150,24,"Sound On/Off",#PB_Button_Toggle)
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Quit = 1
          
        Case #PB_Event_Gadget
          Select EventGadget()
            Case 1
              If GetGadgetState(1) = 1
                keybd_event_($AD, 0, 1, 0)
              Else
                keybd_event_($AD, 0, 1, 0)
              EndIf
                
          EndSelect    
      EndSelect
    Until Quit = 1    
  EndIf
This does not work, the reason you think it disables the sound is because it floods you with windows message beeps for the entire time you're focused on that gadget so much that it entirely eliminates any audio coming to your soundcard.
Source: blind user, tried this and lost my screen reader and any system audio.

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 9:11 pm
by RASHAD
Hi Quin
Don't give-up :)
You can use AddKeyboardShortcut()
For example delete back it will disable sound when no char to delete
But of course you need to code for the delete back
What are the error messages you want to eliminate ?

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Mon Apr 14, 2025 9:28 pm
by Quin
Hi,
I want to get rid of all of them. You hit them when hitting the edge of the field, when pressing home and already at the beginning of the line, and so on. The original StackOverflow post I linked talks about this in more detail

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Tue Apr 15, 2025 9:04 am
by breeze4me
After analyzing it, it seems that the interface uses the "thiscall" calling convention, which causes an error when compiling in PB x86.
Therefore, to make it work properly, the method must be called with a series of assembly instructions, as shown in the code below.
I don't know how to call it in the C backend. :(

When using the Dialog Library, you need to specify a name in the "name" attribute of an editor gadget, and use the DialogGadget function to get the gadget number.
This is an example using the DynamicDialogs module.

Edit:
Added x86 C backend part.

Edit 2:
Added to use GCC native keyword for x86 thiscall.
https://gcc.gnu.org/onlinedocs/gcc/x86- ... 02c-x86-32

Code: Select all

Interface ITextServices Extends IUnknown
  ; //@cmember Generic Send Message interface
  TxSendMessage.l(msg.l, wparam, lparam, *plresult)
  ; 
  ; //@cmember Rendering
  TxDraw.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcBounds, *lprcWBounds, *lprcUpdate, pfnContinue, dwContinue.l, lViewId.l)
  ; 
  ; //@cmember Horizontal scrollbar support
  TxGetHScroll.l(*plMin, *plMax, *plPos, *plPage, *pfEnabled)
  ; 
  ; //@cmember Horizontal scrollbar support
  TxGetVScroll.l(*plMin, *plMax, *plPos, *plPage, *pfEnabled)
  ; 
  ; //@cmember Setcursor
  OnTxSetCursor.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcClient, x.l, y.l)
  ; 
  ; //@cmember Hit-test
  TxQueryHitPoint.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcClient, x.l, y.l, *pHitResult)
  ; 
  ; //@cmember Inplace activate notification
  OnTxInPlaceActivate.l(*prcClient)
  ; 
  ; //@cmember Inplace deactivate notification
  OnTxInPlaceDeactivate.l()
  ; 
  ; //@cmember UI activate notification
  OnTxUIActivate.l()
  ; 
  ; //@cmember UI deactivate notification
  OnTxUIDeactivate.l()
  ; 
  ; //@cmember Get text in control
  TxGetText.l(*pbstrText)
  ; 
  ; //@cmember Set text in control
  TxSetText.l(pszText.s)
  ; 
  ; //@cmember Get x position of 
  TxGetCurTargetX.l(*result)
  ; 
  ; //@cmember Get baseline position
  TxGetBaseLinePos.l(*result)
  ; 
  ; //@cmember Get Size to fit / Natural size
  TxGetNaturalSize.l(dwAspect.l, hdcDraw, hicTargetDev, *ptd, dwMode.l, *psizelExtent, *pwidth, *pheight)
  ; 
  ; //@cmember Drag & drop
  TxGetDropTarget.l(*ppDropTarget)
  ; 
  ; //@cmember Bulk bit property change notifications
  OnTxPropertyBitsChange.l(dwMask.l, dwBits.l)
  ; 
  ; //@cmember Fetch the cached drawing size .l(logical not physical)
  TxGetCachedSize.l(*pdwWidth, *pdwHeight)
EndInterface

#TXTBIT_ALLOWBEEP = 2048

DataSection
  IID_ITextServices: ; 8d33f740-cf58-11ce-a89d-00aa006cadc5
  Data.l $8d33f740
  Data.w $cf58, $11ce
  Data.b $a8, $9d, $00, $aa, $00, $6c, $ad, $c5
EndDataSection

Procedure TurnOffRichEditBeep(Gadget)
  Protected Unk.IUnknown, TxtSrv.ITextServices
  Protected result
  
  If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Editor
    If SendMessage_(GadgetID(Gadget), #EM_GETOLEINTERFACE, 0, @Unk)
      If Unk
        If Unk\QueryInterface(?IID_ITextServices, @TxtSrv) = #S_OK
          If TxtSrv
            
            CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
              Protected Func = @TxtSrv\OnTxPropertyBitsChange()
              
              ; thiscall
              CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
                EnableASM
                mov eax, Func
                mov ecx, TxtSrv
                push 0
                push 2048
                call eax
                mov result, eax
                DisableASM
                
              CompilerElse
                ;! int __attribute__ ((thiscall)) (*func)(int, int, int) = v_func;
                ! int __thiscall (*func)(int, int, int) = v_func;
                ! v_result = func(v_txtsrv, 2048, 0);
                
;                 !__asm__ __volatile__ (
;                 !".intel_syntax noprefix;"
;                 
;                 !"mov eax, %1;"
;                 !"mov ecx, %2;"
;                 !"push 0;"
;                 !"push 2048;"
;                 !"call eax;"
;                 !"mov %0, eax;"
;                 
;                 !".att_syntax" 
;                 !:"=r" (v_result)
;                 !:"r" (v_func), "r" (v_txtsrv)
;                 !:"eax", "ecx"
;                 !);
                
              CompilerEndIf
              
              result = Bool(result = #S_OK)
              
            CompilerElse
              If TxtSrv\OnTxPropertyBitsChange(#TXTBIT_ALLOWBEEP, 0) = #S_OK
                result = 1
              EndIf
            CompilerEndIf
            
            TxtSrv\Release()
          EndIf
        EndIf
        Unk\Release()
      EndIf
    EndIf
  EndIf
  ProcedureReturn result
EndProcedure

XIncludeFile "../DynamicDialogs_suffixed.pbi"

UseModule	DynamicDialogs					; to enable the 'general' commands
UseModule	DynamicDialogs_suffixed		; to enable the XML-Elements with 'suffixed' syntax

ClearXML()	; make sure, the XML-Dialog is empty before you begin a new one

; --- Create the Dialog ---

Window__(#PB_Any, "", "DynamicDialog Example", #PB_Window_SizeGadget | #PB_Window_SystemMenu)	; create a resizeable window
	vBox__(1)																; create a vertical-Box, where only the first Element in the vBox will be auto-resized
		Editor__(#PB_Ignore, "myEditorGadget","",0,0,180)		; create an EditorGadget() with the 'Name': "myEditorGadget"
		Button__(1,"","Click me ...")									; create a Button with Gadget-Number = 1
	EndVBox__()																; End-Tag for the previously opened vBox
EndWindow__()																; End-Tag for the window

UnuseModule	DynamicDialogs_suffixed									; we don't need the XML-Elements any more

If OpenDialogWindow(1, GetXML())		; Open the last created Window (or specify the Window by ID or Name$)
  
  MyEdGadget = DialogGadget(1,"myEditorGadget")
  If TurnOffRichEditBeep(MyEdGadget)
    Debug "OK"
  EndIf
  
	For n = 1 To 10		; Fill Editor-Gadget with some content. Adress the Editor-Gadget by using its Name => "myEditorGadget"
		SetGadgetText(DialogGadget(1,"myEditorGadget"),GetGadgetText(DialogGadget(1,"myEditorGadget"))+"Line "+Str(n)+#LF$)
	Next
	
	Repeat : Until	WaitWindowEvent() = #PB_Event_CloseWindow
EndIf

Re: Disabling message beeps in EditorGadget() on Windows?

Posted: Tue Apr 15, 2025 8:34 pm
by Quin
breeze4me wrote: Tue Apr 15, 2025 9:04 am After analyzing it, it seems that the interface uses the "thiscall" calling convention, which causes an error when compiling in PB x86.
Therefore, to make it work properly, the method must be called with a series of assembly instructions, as shown in the code below.
I don't know how to call it in the C backend. :(

When using the Dialog Library, you need to specify a name in the "name" attribute of an editor gadget, and use the DialogGadget function to get the gadget number.
This is an example using the DynamicDialogs module.

Edit:
Added x86 C backend part.

Code: Select all

Interface ITextServices Extends IUnknown
  ; //@cmember Generic Send Message interface
  TxSendMessage.l(msg.l, wparam, lparam, *plresult)
  ; 
  ; //@cmember Rendering
  TxDraw.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcBounds, *lprcWBounds, *lprcUpdate, pfnContinue, dwContinue.l, lViewId.l)
  ; 
  ; //@cmember Horizontal scrollbar support
  TxGetHScroll.l(*plMin, *plMax, *plPos, *plPage, *pfEnabled)
  ; 
  ; //@cmember Horizontal scrollbar support
  TxGetVScroll.l(*plMin, *plMax, *plPos, *plPage, *pfEnabled)
  ; 
  ; //@cmember Setcursor
  OnTxSetCursor.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcClient, x.l, y.l)
  ; 
  ; //@cmember Hit-test
  TxQueryHitPoint.l(dwDrawAspect.l, lindex.l, *pvAspect, *ptd, hdcDraw, hicTargetDev, *lprcClient, x.l, y.l, *pHitResult)
  ; 
  ; //@cmember Inplace activate notification
  OnTxInPlaceActivate.l(*prcClient)
  ; 
  ; //@cmember Inplace deactivate notification
  OnTxInPlaceDeactivate.l()
  ; 
  ; //@cmember UI activate notification
  OnTxUIActivate.l()
  ; 
  ; //@cmember UI deactivate notification
  OnTxUIDeactivate.l()
  ; 
  ; //@cmember Get text in control
  TxGetText.l(*pbstrText)
  ; 
  ; //@cmember Set text in control
  TxSetText.l(pszText.s)
  ; 
  ; //@cmember Get x position of 
  TxGetCurTargetX.l(*result)
  ; 
  ; //@cmember Get baseline position
  TxGetBaseLinePos.l(*result)
  ; 
  ; //@cmember Get Size to fit / Natural size
  TxGetNaturalSize.l(dwAspect.l, hdcDraw, hicTargetDev, *ptd, dwMode.l, *psizelExtent, *pwidth, *pheight)
  ; 
  ; //@cmember Drag & drop
  TxGetDropTarget.l(*ppDropTarget)
  ; 
  ; //@cmember Bulk bit property change notifications
  OnTxPropertyBitsChange.l(dwMask.l, dwBits.l)
  ; 
  ; //@cmember Fetch the cached drawing size .l(logical not physical)
  TxGetCachedSize.l(*pdwWidth, *pdwHeight)
EndInterface

#TXTBIT_ALLOWBEEP = 2048

DataSection
  IID_ITextServices: ; 8d33f740-cf58-11ce-a89d-00aa006cadc5
  Data.l $8d33f740
  Data.w $cf58, $11ce
  Data.b $a8, $9d, $00, $aa, $00, $6c, $ad, $c5
EndDataSection

Procedure TurnOffRichEditBeep(Gadget)
  Protected Unk.IUnknown, TxtSrv.ITextServices
  Protected result
  
  If IsGadget(Gadget) And GadgetType(Gadget) = #PB_GadgetType_Editor
    If SendMessage_(GadgetID(Gadget), #EM_GETOLEINTERFACE, 0, @Unk)
      If Unk
        If Unk\QueryInterface(?IID_ITextServices, @TxtSrv) = #S_OK
          If TxtSrv
            
            CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
              Protected Func = @TxtSrv\OnTxPropertyBitsChange()
              
              ; thiscall
              CompilerIf #PB_Compiler_Backend = #PB_Backend_Asm
                EnableASM
                mov eax, Func
                mov ecx, TxtSrv
                push 0
                push 2048
                call eax
                mov result, eax
                DisableASM
                
              CompilerElse
                !__asm__ __volatile__ (
                !".intel_syntax noprefix;"
                
                !"mov eax, %1;"
                !"mov ecx, %2;"
                !"push 0;"
                !"push 2048;"
                !"call eax;"
                !"mov %0, eax;"
                
                !".att_syntax" 
                !:"=r" (v_result)
                !:"r" (v_func), "r" (v_txtsrv)
                !:"eax", "ecx"
                !);
                
              CompilerEndIf
              
              result = Bool(result = #S_OK)
              
            CompilerElse
              If TxtSrv\OnTxPropertyBitsChange(#TXTBIT_ALLOWBEEP, 0) = #S_OK
                result = 1
              EndIf
            CompilerEndIf
            
            TxtSrv\Release()
          EndIf
        EndIf
        Unk\Release()
      EndIf
    EndIf
  EndIf
  ProcedureReturn result
EndProcedure

XIncludeFile "../DynamicDialogs_suffixed.pbi"

UseModule	DynamicDialogs					; to enable the 'general' commands
UseModule	DynamicDialogs_suffixed		; to enable the XML-Elements with 'suffixed' syntax

ClearXML()	; make sure, the XML-Dialog is empty before you begin a new one

; --- Create the Dialog ---

Window__(#PB_Any, "", "DynamicDialog Example", #PB_Window_SizeGadget | #PB_Window_SystemMenu)	; create a resizeable window
	vBox__(1)																; create a vertical-Box, where only the first Element in the vBox will be auto-resized
		Editor__(#PB_Ignore, "myEditorGadget","",0,0,180)		; create an EditorGadget() with the 'Name': "myEditorGadget"
		Button__(1,"","Click me ...")									; create a Button with Gadget-Number = 1
	EndVBox__()																; End-Tag for the previously opened vBox
EndWindow__()																; End-Tag for the window

UnuseModule	DynamicDialogs_suffixed									; we don't need the XML-Elements any more

If OpenDialogWindow(1, GetXML())		; Open the last created Window (or specify the Window by ID or Name$)
  
  MyEdGadget = DialogGadget(1,"myEditorGadget")
  If TurnOffRichEditBeep(MyEdGadget)
    Debug "OK"
  EndIf
  
	For n = 1 To 10		; Fill Editor-Gadget with some content. Adress the Editor-Gadget by using its Name => "myEditorGadget"
		SetGadgetText(DialogGadget(1,"myEditorGadget"),GetGadgetText(DialogGadget(1,"myEditorGadget"))+"Line "+Str(n)+#LF$)
	Next
	
	Repeat : Until	WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
This works amazingly, thanks for your work! I only target x64 C-backend, so removed the ASM and it all works flawlessly!
It works with DynamicDialogs, too :)