Diacritic letters (accents) with configuration file

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
mslonik
Posts: 144
Joined: 21 Feb 2019, 04:38
Location: Poland
Contact:

Diacritic letters (accents) with configuration file

Post by mslonik » 05 Mar 2020, 17:12

Dear Forum,

it's my pleasure to present you Diacritic.ahk:

Code: Select all

/*
Author:      Maciej Słojewski, mslonik, http://mslonik.pl
Purpose:     Facilitate normal operation for company desktop.
Description: Hotkeys and hotstrings for my everyday professional activities and office cockpit.
License:     GNU GPL v.3
*/
;                 I N T R O D U C T I O N
;~ Simple script used to get diacritic letters (https://en.wikipedia.org/wiki/Diacritic) without usage of AltGr key (right alt, see https://en.wikipedia.org/wiki/AltGr_key#Polish for further details):
;~ * double press a key configured to correspond to diacritic key, e.g. in Polish ee converts into ę
;~ * special sequence for double letters within words: <letter><letter><letter>, e.g. zaaawansowany converts into zaawansowany
;~ * configuration file (.ini) is generated by default,
;~ * optionally sounds and tooltips are generated upon key presses.
;~ 
;~ WHY:
;~ a. "programmers keyboard" layout and Diacritic with old ANSI 101 keys keyboard, where AltGr is unergonomically shifted to the right side of keyboard is cumbersome and decrease touch typing speed,
;~ b. all other "programmers keyboard" when one doesn't want to press AltGr or use just one hand to press all letters of alphabet.
;~
;~ Author: Maciej Słojewski, 2020-02-27
;~
;~ Base for all actions are "Hotstrings" generated dynamically (hotstring function).

#NoEnv  						; Recommended for performance and compatibility with future AutoHotkey releases.
#Warn  							; Enable warnings to assist with detecting common errors.
SendMode Input  				; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%		; Ensures a consistent starting directory.
#SingleInstance force 			; only one instance of this script may run at a time!

;~ - - - - - - - - - - Global Variables - - - - - - - - - - -
ApplicationName     := "Diacritic"
English_USA 		:= 0x0409   ; see AutoHotkey help: Language Codes
;~ - - - - - - - - - - End of Global Variables - - - - - - - - - - -

Menu, Tray, Icon, imageres.dll, 123     ; this line will turn the H icon into a small red a letter-looking thing.
Gosub, TRAYMENU                         ; Jumps to the specified label and continues execution until Return is encountered

ProcessInputArgs()
#Hotstring c b0 ? * 

;~ read global variables from .ini file
IniRead, _AmericanLayout,                   % A_ScriptDir . "\" . A_Args[1], Global, AmericanLayout
IniRead, _AllTooltips,                      % A_ScriptDir . "\" . A_Args[1], Global, AllTooltips
IniRead, _AllBeeps,                         % A_ScriptDir . "\" . A_Args[1], Global, AllBeeps
IniRead, _DiacriticWord,                     % A_ScriptDir . "\" . A_Args[1], Global, DiacriticWord
IniRead, _DoubleWord,                       % A_ScriptDir . "\" . A_Args[1], Global, DoubleWord

;~ switch to AmericanLayout (neutral)?
if (_AmericanLayout = "yes")
    SetDefaultKeyboard(English_USA)
if (_AllTooltips = "on")
    F_AllKeyboardKeys()     ; Set dynamic hotkeys for all keys of 60% keyboard, ANSI layout    

;~ determine how many [Diacritic] sections are in .ini file
DiacriticSectionCounter := 0
Loop, Read, % A_ScriptDir . "\" . A_Args[1]
    {
    if (InStr(A_LoopReadLine, "[Diacritic"))
        {
        DiacriticSectionCounter++
        }
    }

;~ MsgBox, % "DiacriticSectionCounter: " . DiacriticSectionCounter
;~ read all the rest of configuration parameters from .ini file and create hotstrings

;~ Initialization of parameters
BaseKey        = ""
ShiftBaseKey   = ""
Diacritic       = ""
ShiftDiacritic  = ""
Tooltip        = ""

Loop, %DiacriticSectionCounter%
    {
    IniRead, _BaseKey,                      % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, BaseKey
    IniRead, _ShiftBaseKey,                 % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, ShiftBaseKey
    if (_ShiftBaseKey = "")
        {
        MsgBox, 16, %ApplicationName%.ahk, % "Warning!`nConfiguration file (" . A_Args[1] . ")`, section: " . A_Index . ", parameter name: ShiftBaseKey is empty. This could cause application malfunction. Application will now exit. Correct the " . A_Args[1] . " file in specified place and try again."
        ExitApp, 0
        }
    IniRead, _Diacritic,                     % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, Diacritic
    IniRead, _ShiftDiacritic,                % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, ShiftDiacritic
    IniRead, _Tooltip,                      % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, Tooltip
    
    ;~ MsgBox, % _BaseKey . " " . _Diacritic . " " . _ShiftDiacritic . " "
    IniRead, _BaseKey_SoundBeep_Frequency,  % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, BaseKey_SoundBeep_Frequency
    ;~ MsgBox, %_BaseKey_SoundBeep_Frequency%
    IniRead, _BaseKey_SoundBeep_Duration,   % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, BaseKey_SoundBeep_Duration
    ;~ MsgBox, %_BaseKey_SoundBeep_Duration%
    IniRead, _Diacritic_SoundBeep_Frequency, % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, Diacritic_SoundBeep_Frequency
    ;~ MsgBox, %_Diacritic_SoundBeep_Frequency%
    IniRead, _Diacritic_SoundBeep_Duration,  % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, Diacritic_SoundBeep_Duration
    ;~ MsgBox, %_Diacritic_SoundBeep_Duration%
    IniRead, _Double_SoundBeep_Frequency,   % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, Double_SoundBeep_Frequency
    ;~ MsgBox, %_Double_SoundBeep_Frequency%
    IniRead, _Double_SoundBeep_Duration,    % A_ScriptDir . "\" . A_Args[1], % "Diacritic" . A_Index, Double_SoundBeep_Duration
    ;~ MsgBox, %_Double_SoundBeep_Duration%

    ;~ MsgBox, % _BaseKey . " " . _Diacritic . " " . _Diacritic_SoundBeep_Frequency . " "  _Diacritic_SoundBeep_Duration . " " . _Tooltip
    ;~ MsgBox, % A_Index
    ;~ if (A_Index = 6)
        ;~ MsgBox, Po raz 6
    
    Hotstring(":zx:" . _BaseKey . _BaseKey . _BaseKey,                func("DoubleLetter").bind(_BaseKey, _Double_SoundBeep_Frequency, _Double_SoundBeep_Duration))
    Hotstring(":x:"  . _BaseKey . _BaseKey,                           func("DiacriticLetter").bind(_Diacritic, _Diacritic_SoundBeep_Frequency, _Diacritic_SoundBeep_Duration, _Tooltip))
    Hotstring(":x:"  . _BaseKey,                                      func("SingleLetter").bind(_BaseKey_SoundBeep_Frequency, _BaseKey_SoundBeep_Duration, _Tooltip))

    Hotstring(":zx:" . _ShiftBaseKey . _ShiftBaseKey . _ShiftBaseKey, func("DoubleLetter").bind(_ShiftBaseKey, _Double_SoundBeep_Frequency, _Double_SoundBeep_Duration))
    Hotstring(":x:"  . _ShiftBaseKey . _ShiftBaseKey,                 func("DiacriticLetter").bind(_ShiftDiacritic, _Diacritic_SoundBeep_Frequency, _Diacritic_SoundBeep_Duration, _Tooltip))
    Hotstring(":x:"  . _ShiftBaseKey,                                 func("SingleLetter").bind(_BaseKey_SoundBeep_Frequency, _BaseKey_SoundBeep_Duration, _Tooltip))
    }

~BackSpace:: ; this line prevent the following sequence from triggering: ao › aoo › aó › aó{Backspace} › a › ao › ó
    ;~ MsgBox, Backspace
    Hotstring("Reset")
return

 ;~ - - - - - - - - - - - - - - - - - - - - - - SECTION OF FUNCTIONS - - - - - - - - - - - - - - - - - - - - - - - - - - - 

DoubleLetter(_BaseKey, _Double_SoundBeep_Frequency, _Double_SoundBeep_Duration)
    {
    global _AllBeeps
    
    ;~ MsgBox, %_BaseKey%
    Send, {Raw}`b`b%_BaseKey%%_BaseKey%
    if (_AllBeeps = "on")
        SoundBeep, _Double_SoundBeep_Frequency, _Double_SoundBeep_Duration
    Tooltip,
    ;~ return
    }

;~ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

DiacriticLetter(_Diacritic, _Diacritic_SoundBeep_Frequency, _Diacritic_SoundBeep_Duration, _Tooltip)
    {
    global _AllBeeps, _AllTooltips, _DoubleWord
    
    ;~ MsgBox, % _Diacritic
    Send, {BackSpace 2}%_Diacritic%
    if (_AllBeeps = "on")
        SoundBeep, _Diacritic_SoundBeep_Frequency, _Diacritic_SoundBeep_Duration
    if ((_AllTooltips = "on") && (_Tooltip = "on") )
        {
        Tooltip, % _DoubleWord . "?", % A_CaretX,% A_CaretY-20
        }
    else
        {
        Tooltip,
        }
    ;~ return
    }
    
;~ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

SingleLetter(_BaseKey_SoundBeep_Frequency, _BaseKey_SoundBeep_Duration, _Tooltip)
    {
    global _AllBeeps, _AllTooltips, _DiacriticWord
    
    if (_AllBeeps = "on")
        SoundBeep, _BaseKey_SoundBeep_Frequency, _BaseKey_SoundBeep_Duration
    if ((_AllTooltips = "on") && (_Tooltip = "on") )
        {
        Tooltip, % _DiacriticWord . "?", % A_CaretX,% A_CaretY-20
        }
    else
        {
        Tooltip,
        }
    ;~ return
    }

;~ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

F_AllKeyboardKeys()
{
;~ row #1
Hotkey, ~Esc,       SwitchOffTooltip, On
Hotkey, ~F1,        SwitchOffTooltip, On
Hotkey, ~F2,        SwitchOffTooltip, On
Hotkey, ~F3,        SwitchOffTooltip, On
Hotkey, ~F4,        SwitchOffTooltip, On
Hotkey, ~F5,        SwitchOffTooltip, On
Hotkey, ~F6,        SwitchOffTooltip, On
Hotkey, ~F7,        SwitchOffTooltip, On
Hotkey, ~F8,        SwitchOffTooltip, On
Hotkey, ~F9,        SwitchOffTooltip, On
Hotkey, ~F10,       SwitchOffTooltip, On
Hotkey, ~F11,       SwitchOffTooltip, On
Hotkey, ~F12,       SwitchOffTooltip, On

;~ row #2:
Hotkey, ~``,        SwitchOffTooltip, On
Hotkey, ~1,         SwitchOffTooltip, On
Hotkey, ~2,         SwitchOffTooltip, On
Hotkey, ~3,         SwitchOffTooltip, On
Hotkey, ~4,         SwitchOffTooltip, On
Hotkey, ~5,         SwitchOffTooltip, On
Hotkey, ~6,         SwitchOffTooltip, On
Hotkey, ~7,         SwitchOffTooltip, On
Hotkey, ~8,         SwitchOffTooltip, On
Hotkey, ~9,         SwitchOffTooltip, On
Hotkey, ~0,         SwitchOffTooltip, On
Hotkey, ~-,         SwitchOffTooltip, On
Hotkey, ~=,         SwitchOffTooltip, On
Hotkey, ~BS,        SwitchOffTooltip, On

;~ row #3
Hotkey, ~Tab,       SwitchOffTooltip, On
Hotkey, ~q,         SwitchOffTooltip, On
Hotkey, ~w,         SwitchOffTooltip, On
Hotkey, ~e,         SwitchOffTooltip, On
Hotkey, ~r,         SwitchOffTooltip, On
Hotkey, ~t,         SwitchOffTooltip, On
Hotkey, ~y,         SwitchOffTooltip, On
Hotkey, ~u,         SwitchOffTooltip, On
Hotkey, ~i,         SwitchOffTooltip, On
Hotkey, ~o,         SwitchOffTooltip, On
Hotkey, ~[,         SwitchOffTooltip, On
Hotkey, ~],         SwitchOffTooltip, On
Hotkey, ~\,         SwitchOffTooltip, On

;~ row #4
Hotkey, ~CapsLock,  SwitchOffTooltip, On
Hotkey, ~a,         SwitchOffTooltip, On
Hotkey, ~s,         SwitchOffTooltip, On
Hotkey, ~d,         SwitchOffTooltip, On
Hotkey, ~f,         SwitchOffTooltip, On
Hotkey, ~g,         SwitchOffTooltip, On
Hotkey, ~h,         SwitchOffTooltip, On
Hotkey, ~j,         SwitchOffTooltip, On
Hotkey, ~k,         SwitchOffTooltip, On
Hotkey, ~l,         SwitchOffTooltip, On
Hotkey, ~;,         SwitchOffTooltip, On
Hotkey, ~',         SwitchOffTooltip, On
Hotkey, ~Enter,     SwitchOffTooltip, On

;~ row #5
Hotkey, ~Shift,     SwitchOffTooltip, On
Hotkey, ~z,         SwitchOffTooltip, On
Hotkey, ~x,         SwitchOffTooltip, On
Hotkey, ~c,         SwitchOffTooltip, On
Hotkey, ~v,         SwitchOffTooltip, On
Hotkey, ~b,         SwitchOffTooltip, On
Hotkey, ~n,         SwitchOffTooltip, On
Hotkey, ~m,         SwitchOffTooltip, On
Hotkey, ~`,,        SwitchOffTooltip, On
Hotkey, ~.,         SwitchOffTooltip, On
Hotkey, ~/,         SwitchOffTooltip, On

;~ row #6
Hotkey, ~Control,   SwitchOffTooltip, On
Hotkey, ~Lwin,      SwitchOffTooltip, On
Hotkey, ~Alt,       SwitchOffTooltip, On
Hotkey, ~Space,     SwitchOffTooltip, On
Hotkey, ~RWin,      SwitchOffTooltip, On
Hotkey, ~AppsKey,   SwitchOffTooltip, On
}

;~ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

ProcessInputArgs()
{
global A_Args, ApplicationName

if (A_Args.Length() = 0)
    {
    IfExist, *.ini
        {
        MsgBox, 16, %ApplicationName%.ahk, At least one *.ini file found in directory %A_WorkingDir%`n but current script (%ApplicationName%.ahk) was run without any arguments. One argument`, the name of .ini file`, is obligatory. Therefore script will now exit.
        ExitApp, 0
        }
    IfNotExist, *.ini
        MsgBox, 308, %ApplicationName%.ahk, No input arguments found and no *.ini files found in directory %A_WorkingDir%. Expected a single *.ini file. Do you want to create Default.ini configuration template? Script will exit after the default configuration file Default%ApplicationName%ConfigFile.ini is created.
    IfMsgBox, No
        ExitApp, 0
    IfMsgBox, Yes
        {
  ini=
(
[Global]
Language = NameOfYourLanguage
AmericanLayout = yes ; or no
AllTooltips = on ; or off
AllBeeps = on ; or off
DiacriticWord = Diacritic ; e.g. Diacritic, this parameter will appear in Tooltip, if Tooltips are enabled
DoubleWord = Double ; e.g. Double, this parameter will appear in Tooltip, if Tooltips are enabled

[Diacritic1] ; exapmple of single section; such a section have to be repeated for each Diacritic key
BaseKey = a ; name of a key which will activate a Diacritic key
Diacritic = {U+0105} ; definition of Diacritic key, the format {U+xyza} is obligatory
ShiftBaseKey = A ; as for basekey, but this time explicite specify which key will appear
ShiftDiacritic = {U+0104} ; definition of Diacritic key, the format {U+xyza} is obligatory
Tooltip = on ; or off
BaseKey_SoundBeep_Frequency = 1000 ; a number between 37 and 32767
BaseKey_SoundBeep_Duration = 150 ; The duration of the sound, in milliseconds
Diacritic_SoundBeep_Frequency = 1100 ; a number between 37 and 32767
Diacritic_SoundBeep_Duration = 150 ; The duration of the sound, in milliseconds
Double_SoundBeep_Frequency = 1200 ; a number between 37 and 32767
Double_SoundBeep_Duration = 150 ; The duration of the sound, in milliseconds
)
        FileAppend, %ini%, Default%ApplicationName%ConfigFile.ini
        ini = ""
        ExitApp, 0
        }
    }
else if (A_Args.Length() = 1)
    {
    IniRead, _Language,                         % A_ScriptDir . "\" . A_Args[1], Global, Language
    MsgBox, 64, Diacritic.ahk, % "Input argument: " . A_Args[1] . ". Found language: " . _Language . "."
    }
else if (A_Args.Length() > 1)
    {
    MsgBox, 48, Diacritic.ahk, % "Too many input arguments: " . A_Args.Length() . ". Expected just one, *.ini." 
    }
}    

;~ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;~ https://docs.microsoft.com/pl-pl/windows/win32/api/winuser/nf-winuser-systemparametersinfoa?redirectedfrom=MSDN
SetDefaultKeyboard(LocaleID)
{
	static SPI_SETDEFAULTINPUTLANG := 0x005A, SPIF_SENDWININICHANGE := 2
	WM_INPUTLANGCHANGEREQUEST := 0x50
	
	Language := DllCall("LoadKeyboardLayout", "Str", Format("{:08x}", LocaleID), "Int", 0)
	VarSetCapacity(binaryLocaleID, 4, 0)
	NumPut(LocaleID, binaryLocaleID)
	DllCall("SystemParametersInfo", UINT, SPI_SETDEFAULTINPUTLANG, UINT, 0, UPTR, &binaryLocaleID, UINT, SPIF_SENDWININICHANGE)
	
	WinGet, windows, List
	Loop % windows
		{
		PostMessage WM_INPUTLANGCHANGEREQUEST, 0, % Language, , % "ahk_id " windows%A_Index%
		}
}


 ;~ - - - - - - - - - - - - - - - - - - - - - - SECTION OF LABELS - - - - - - - - - - - - - - - - - - - - - - - - - - - 

SwitchOffTooltip:
    ;~ ToolTip, Carramba
    ToolTip,
return


TRAYMENU:
    Menu, Tray, Add, %ApplicationName%.ahk ABOUT, ABOUT
    Menu, Tray, Add, % ".ini file: " . A_Args[1], _iniFile
    ;~ Menu, Tray, Add, .ini file: %1%, _iniFile
    Menu, Tray, Default, %ApplicationName%.ahk ABOUT ; Default: Changes the menu's default item to be the specified menu item and makes its font bold.
    Menu, Tray, Add ; To add a menu separator line, omit all three parameters. To put your menu items on top of the standard menu items (after adding your own menu items) run Menu, Tray, NoStandard followed by Menu, Tray, Standard.
    Menu, Tray, NoStandard
    Menu, Tray, Standard
    Menu, Tray, Tip, %ApplicationName% ; Changes the tray icon's tooltip.
return

_iniFile:
return

ABOUT:
    Gui, MyAbout: Font, Bold
    Gui, MyAbout: Add, Text, , %ApplicationName% v.1.0 by mslonik
    Gui, MyAbout: Font
    Gui, MyAbout: Add, Text, xm, Simple script for configured set of diacritic marks (
    Gui, MyAbout: Font, CBlue Underline 
    Gui, MyAbout: Add, Text, x+1, https://en.wikipedia.org/wiki/Diacritic
    Gui, MyAbout: Font
    Gui, MyAbout: Add, Text, x+1, ) e.g.: ą, ć, ę, ł, ś, ź, ż, ó, ń etc.
    Gui, MyAbout: Add, Text, xm, Instead of using AltGr key (the right Alt`, see 
    Gui, MyAbout: Font, CBlue Underline 
    Gui, MyAbout: Add, Text, x+2, https://en.wikipedia.org/wiki/AltGr_key 
    Gui, MyAbout: Font
    Gui, MyAbout: Add, Text, x+2, for further details):
    Gui, MyAbout: Add, Text, xm+20, * double press a key corresponding to specific diacritic key`, e.g. ee converts into ę
    Gui, MyAbout: Add, Text, xm+20, * special sequence for double letters within words: <letter><letter><letter>`, e.g. zaaawansowany converts into zaawansowany

    Gui, MyAbout: Add, Button, Default Hidden w100 gMyOK Center vOkButtonVariabl hwndOkButtonHandle, &OK
    GuiControlGet, MyGuiControlGetVariable, MyAbout: Pos, %OkButtonHandle%
    Gui, MyAbout: Show, Center, %ApplicationName% About
    WinGetPos, , , MyAboutWindowWidth, , %ApplicationName% About
    NewButtonXPosition := (MyAboutWindowWidth / 2) - (MyGuiControlGetVariableW / 2)
    GuiControl, Move, %OkButtonHandle%, % "x" NewButtonXPosition
    GuiControl, Show, %OkButtonHandle%
return    
    
MyOK:
MyAboutGuiClose: ; Launched when the window is closed by pressing its X button in the title bar
    Gui, MyAbout: Destroy
return

Rationale / why:
Entering diacritric letters currently is solved by:
  • dedicated keyboard layout - new diactric letters are moved to locaction of other letters and a consequence letters are no longer directly available,
  • pressing modifier keys enable entering additional letters,
  • dead keys - after pressing of a dead key and certain next letter the diactric letter is produced,
  • combination of all above.
Picture below: Czech - Slovak keyboard layout example with plenty of diacritic keys / letters, some quite cryptic in my opinion.
Czech_Slovakian_layout_800x600.jpg
Czech_Slovakian_layout_800x600.jpg (96.57 KiB) Viewed 2950 times
Described above methods become apparently awkward for touch typists:
  • dedicated keyboard layout requires memorizing where diacritic keys are,
  • pressing modifier keys slows down and is cumbersome from ergonomic point of view (e.g. pressing AltGr by always right hand thumb),
  • pressing dead keys makes process of typing even slower then pressing additional modifier key.
So I started to think about at least compromise solution, which enable relatively easy entering diacritic keys without too much overhead and ergonomically feasible.

The proposed solution bases on idea of skrommel (AutoHotkey showcase) named Accents.ahk:

what if one just presses twice particular letter to get diacritic letter?
How brilliant and simple is that!

There is one more issue to be solved: words where agglutination of two letters exist and such a letter have associated diacritic letter. Example from Polish language: "zaawansowany". So if one just presses "zaawansowany" with above method, he (she / it) gets "ząwansowany" what is considered mispelling. To solve this issue one has to press base letter tripple: "zaaawansowany" -> "zaawansowany".


So for example diacritics in Polish language:

Code: Select all

 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ | No.  | Key  | Diactric | Unicode   | Description of diactric letter          |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   1  |  a   |    ą     | U+0105    |  Latin small letter a with ogonek       |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   2  |  c   |    ć     | U+0107    |  Latin small letter c with acute        |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   3  |  e   |    ę     | U+0119    |  Latin small letter e with ogonek       |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   4  |  l   |    ł     | U+0142    |  Latin small letter l with stroke       |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   5  |  n   |    ń     | U+0144    |  Latin small letter n with acute        |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   6  |  o   |    ó     | U+0144    |  Latin small letter o with acute        |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   7  |  s   |    ś     | U+0144    |  Latin small letter s with acute        |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   8  |  x   |    ź     | U+017A    |  Latin small letter z with acute        |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |   9  |  z   |    ż     | U+017C    |  Latin small letter z with dot above    |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  10  |  A   |    Ą     | U+0104    |  Latin capital letter a with ogonek     |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  11  |  C   |    Ć     | U+0106    |  Latin capital letter c with acute      |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  12  |  E   |    Ę     | U+0118    |  Latin capital letter a with ogonek     |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  13  |  L   |    Ł     | U+0141    |  Latin capital letter l with stroke     |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  14  |  N   |    Ń     | U+0143    |  Latin capital letter n with acute      |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  15  |  O   |    Ó     | U+00D3    |  Latin capital letter o with acute      |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  16  |  S   |    Ś     | U+015A    |  Latin capital letter s with acute      |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  17  |  X   |    Ź     | U+0179    |  Latin capital letter z with acute      |
 #~ +------+------+----------+-----------+-----------------------------------------+
 #~ |  18  |  Z   |    Ż     | U+017B    |  Latin capital letter z with dot above  |
 #~ +------+------+----------+-----------+-----------------------------------------+
The "Description of diactric letter" comes from this page.

If I want to get diacritic "ą" I have to press "aa". To get "aa" I have to press "aaa". As a consequence I get overhead ~50% to 75% but in my subjective opinion this method is still more ergonomic and faster (after some individual practice) than pressing AltGr or dead keys...


To make such a script more universal I provide .ini configuration files.

Input parameters (.ini file)

Code: Select all

[Global]
Language = Polish 						; optional language name displayed in some message windows
AmericanLayout = yes 					; or no, explained in details below
AllTooltips = off							; or on, global enabler / disabler of tooltips to be displayed if diacritic letter can be entered
AllBeeps = off							; sound on / off for all diacritic letters
DiacriticWord = Diacritic					; optional words to be displayed within tooltips
DoubleWord = Double						; optional words to be displayed within tooltips

[Diacritic1]							; section name; each diacritic letter, both small and capital, require such a section
BaseKey = a							; base key: which key have to be pressed to get diacritic letter
Diacritic = {U+0105}						; diacritic letter associated with double pressing of BaseKey
ShiftBaseKey = A						; capital letter: which capital key (with Shift modifier) have to be pressed to get diacritic letter
ShiftDiacritic = {U+0104}					; diacritic letter associated with double pressing of Shift modifier and BaseKey
Tooltip = on							; or off, if tooltip should be displayed for this particular diacritic letter?
BaseKey_SoundBeep_Frequency = 1000		; sound frequency associated with base key; it should be a number between 37 and 32767; if omitted, the frequency will be 523.
BaseKey_SoundBeep_Duration = 150			; sound duration of the sound produced upon base key was pressed, in milliseconds. 
Diacritic_SoundBeep_Frequency = 1100		; sound frequency associated with diacritic key; it should be a number between 37 and 32767; if omitted, the frequency will be 523.
Diacritic_SoundBeep_Duration = 150			; sound duration of the sound produced upon diacritic key was pressed, in milliseconds. 
Double_SoundBeep_Frequency = 1200			; sound frequency associated with double pressed base key; it should be a number between 37 and 32767; if omitted, the frequency will be 523.
Double_SoundBeep_Duration = 150			; sound duration of the sound produced upon base key was pressed twice, in milliseconds. 
Currently I've prepared dedicated .ini files for diacritic letters in Czech.ini, German1.ini, German2.ini, Norwegian.ini, Polish.ini and Slovakian.ini.

All the files are downloadable from Github.

Discussion
Personally I use American ANSI keyboard layout.
  • The American Windows Keyboard Layout is the only one (which I know) in Windows universe where Left Alt = Right Alt and there are no dead keys. Another words: you get what you press. Therefore I've added in configuration file feature of enabling / forcing of this layout.
  • ANSI hardware layout is used because... it perfectly fits to my (subjective) liking. Another words I don't like ISO or any other layout...
  • Touch typing with American ANSI in my opinion is the easiest way to harness this quite essential ability.
Now please have a look into so called "language" layout. For sake of example let's see the German one: here. What is apparent that Z letter is exchanged with Y and some letters / marks are relocatted to accumulate diacritic German letters: ß, ü, ö, ä. To mimic this behaviour I've prepared example configuration file German1.ini. So to get ß one have to press "-" key. The consequence of this choice is that "@" key... dissapears. T reach it one has to press... AltGr + q. Wait, what?!

But... why this way? Thanks to Diacritic.ahk one can 'design' its own layout. For somebody who is touch typist maybe much more intuitive way would be the following arrangement:
bb -> ß, BB -> ẞ, uu -> ü, UU -> Ü, oo -> ö, OO -> Ö, aa -> ä, AA -> Ä. Thanks to that "@" key may stay where it is in American ANSI keyboard layout (Shift + 2). So for sake of an example I've prepared German2.ini file for comparison to German1.ini.

Maybe there are some benefits to handicaped people as well, as my method of entering diacritic keys do not require of second key to be pressed (except capital letters). I've also added optional tooltips and optional sound emission to help recognize base keys / diacritic keys.

The .ini configuration file currently is weakly secured against human errors or intended errors, so beware and keep correct syntax.


Additional resources
  • Windows Keyboard Layouts web page contains sort of simulator enabling testing of various language layouts with modifiers and dead keys.
  • The real gem among pages describing keyboard layouts.
Acknowledgements
This is occasion to thank all people who helped me, patiantly pointing out my mistakes and sometimes clamsy questions. Personally I perceive this forum as a place gathering just wonderful, helpful, patient, encouraging people. Thank you again!

Kind regards, mslonik
Last edited by mslonik on 09 Mar 2020, 04:09, edited 1 time in total.

guest3456
Posts: 3463
Joined: 09 Oct 2013, 10:31

Re: Diacritic.ahk

Post by guest3456 » 05 Mar 2020, 23:09

good job, looks comprehensive


Janusz
Posts: 89
Joined: 18 Dec 2020, 17:47

Re: Diacritic letters (accents) with configuration file

Post by Janusz » 09 Apr 2021, 09:03

Yours Diacritic code is brilliant. BUt I can not understand how to type Diacritic letters. User must press for example cc to get č Czech character or for example, user must type tt to get ť letter?
I Am pressing keys very fast, but no diacritic characters are automatically added when I press some letter twice very fast. Or is it necessary to also click on some graphical area on The screen?
Very wll done. Yours code is also giving good programmers inspiration for working with timer to count The time interval between key presses. I Am using czech.ini ini file.

User avatar
mslonik
Posts: 144
Joined: 21 Feb 2019, 04:38
Location: Poland
Contact:

Re: Diacritic letters (accents) with configuration file

Post by mslonik » 09 Apr 2021, 13:58

Hi Janusz,

in case of Czech.ini I've prepared it only for "classic" Czech keyboard layout. Please open in any editor Czech.ini file. At its end you'll find table showing how to get diacritic keys. If you're Czech probably you're familiar with this leyout. So i.e. to get ě you need to double press 2.

If you want to get ě after pressing two times e you need to edit / prepare .ini file for yourself.

For 2x languages I've prepared double set of .ini files: German and Slovakian.

So German1.ini mimics "classic" German keyboard: e.g. to get ö you need to press two times ;.
German2.ini mimics "new" German keyboard: e.g. to get ö you need to press two times o, what is more natural to me as foreigner.

Unfortunately for Czech language I've prepared just one .ini, "classic". I encourage you to prepare the second one as well.

Hopefully it helps.

Kind regards, mslonik

My scripts on this forum: Hotstrings Diacritic O T A G L E
Please become my patreon: Patreon👍
Written in AutoHotkey text replacement tool: Hotstrings.technology
Courses on AutoHotkey :ugeek:

Janusz
Posts: 89
Joined: 18 Dec 2020, 17:47

Re: Diacritic letters (accents) with configuration file

Post by Janusz » 11 Apr 2021, 14:30

I have tried to go my own way. And if somebody of us would be a little kind to Me, it would be even finished. I have been stuck on The situation, when user press left Shift followed by key with The scan code SC00D folloed by some Czech letters which can get hook such as c, so Č, ď. HOw to detect The situation? Because in fact, user can press letter after many many seconds after user has pressed left Shift and key with scan code SC00D. Sure, my own way is not very smart. But it also work. I Am using special .ahk library from Evil focused on SAPi5 engines control. I AM using latest stable Espeak SAPI5 engine for WIndows, which uses very efficient memory allocations while speaking to it. So Autohotkey process do not allocate too much RAM. I AM learning Autohotkey so my code is not ellegant, not very smart, but it also partially work.

Code: Select all

#SingleInstance force
#persistent
SetBatchLines -1
SetKeyDelay -1
SendMode Input

s := new TTS()
return

~a::s.Speak("a")
~á::s.Speak("á")
~b::s.Speak("b")
~c::s.Speak("c")
~č::s.Speak("č")
~d::s.Speak("d")
~e::s.Speak("e")
~é::s.Speak("é")
~ě::s.Speak("ě")
~f::s.Speak("f")
~g::s.Speak("g")
~h::s.Speak("h")
~i::s.Speak("i")
~í::s.Speak("í")
~j::s.Speak("j")
~k::s.Speak("k")
~l::s.Speak("l")
~m::s.Speak("m")
~n::s.Speak("n")
o::s.Speak("o")
~p::s.Speak("p")
~q::s.Speak("q")
~r::s.Speak("r")
~ř::s.Speak("ř")
~s::s.Speak("s")
~š::s.Speak("š")
~t::s.speak("t")
~u::s.Speak("u")
~ů::s.Speak("ů")
~ú::s.Speak("ú")
~v::s.Speak("v")
~w::s.Speak("w")
~x::s.Speak("x")
~y::s.Speak("y")
~z::s.Speak("z")
~ž::s.Speak("ž")
~+a::s.Speak("vel a")
~+b::s.Speak("vel b")
~+c::s.Speak("vel c")
~+d::s.Speak("vel d")
~+e::s.Speak("vel e")
~+f::s.Speak("vel f")
~+g::s.Speak("vel g")
~+h::s.Speak("vel h")
~+i::s.Speak("vel i")
~+j::s.Speak("vel j")
~+k::s.Speak("vel k")
~+l::s.Speak("vel l")
~+m::s.Speak("vel m")
~+n::s.Speak("vel n")
~+o::s.Speak("vel o")
~+p::s.Speak("vel p")
~+q::s.Speak("vel q")
~+r::s.Speak("vel r")
~+s::s.Speak("vel s")
~+t::s.Speak("vel t")
~+u::s.Speak("vel u")
~+v::s.Speak("vel v")
~+w::s.Speak("vel w")
~+x::s.Speak("vel x")
~+y::s.Speak("vel y")
~+z::s.Speak("vel z")

~Space::s.Speak("mezera")
~1::s.Speak("1")
~2::s.Speak("2")
~3::s.Speak("3")
~4::s.Speak("4")
~5::s.Speak("5")
~6::s.Speak("6")
~7::s.Speak("7")
~8::s.Speak("8")
~9::s.Speak("9")
~0::s.Speak("0")
~/::s.Speak("lomeno")
~*::s.Speak("hvězdička")
~-::s.Speak("mínus")
~(::s.Speak("levá závorka")
~)::s.Speak("pravá závorka")
~_::s.Speak("podtržení")
~?::s.Speak("otazník")
~!::s.Speak("vykřičník")
~,::s.Speak("čárka")
~;::s.Speak("středník")
~SC034::s.Speak("tečka")
~+SC034::s.Speak("dvojtečka")
~+SC00D::s.speak("háček")
~LCTRL::s.ToggleSpeak("")
~^+Right::s.setrate(10) s.speak("nejrychleji")
~^F1::s.NextVoice() 

#Include sapi5.ahk
[Mod edit: [code][/code] tags added.]

Janusz
Posts: 89
Joined: 18 Dec 2020, 17:47

Re: Diacritic letters (accents) with configuration file

Post by Janusz » 11 Apr 2021, 15:58

Why I have decided to create this speaking keyboard? Because NVDA screen readen causes time delay between key press and leter spoken if I Am using Microsoft Word 2003 for students and Teachers. It is complex multitasking and multithreading related complex issue. The delay becomes when user typed more than 100 200 chars. Problem disappear, if user delete whole document. Very probably some issue related to intensive Word object model monitoring. It is sad, because NVDA developers are very advanced. They are always using latest Microsoft Visual studio and C++ compilers and C source code support remote process communication. So main communication between Python machine and remote process is made by using C++ source code. So my main goal is to create little speaking screen reader for Word, which will only support very basic navigation by using WOrd object model. No dialog windows monitoring in background, only navigation inside Word document. I want to try, if delay will also occur if I will type very fast and if I will type more than 200 300 chars continuously. FOrtunately for Me, Autohotkey also support multi threading while interpreting The .ahk sources, so may be, that I would have a little chance to success. can disable NVDA build in keyboard speaking in Word and I can even try to remove NVDA code to communicate with object model to give my experiment The chance to have some success while navigating in Word. To have A good success, I must use macro recorder and I must do my best to understand Word object model. FOrtunately for Me, Espeak for WIndows is made perfectly, and synthesizer do its best to prevent from memory leaks while using it.

Post Reply

Return to “Scripts and Functions (v1)”