1. Einführung
Seit Windows 2000 Professional bzw. Windows 2000 Server zeigt Windows in der Grundeinstellung das Fokus-Rechteck sowie die Unterstriche unter Hotkeys nicht mehr an. Erst wenn der Anwender die Alt- oder Tab-Taste verwendet, wird diese Anzeige für das betreffende Programm wieder aktiviert.
Dieses Verhalten lässt sich (zumindest unter WinXP) an zwei verschiedenen Stellen abschalten, sodass Fokus-Rechteck und Hotkey-Unterstreichungen wieder ständig angezeigt werden:
- Systemsteuerung → Eingabehilfen → Reiter "Tastatur", dort einen Haken bei "Zusätzliche Tastaturhilfe in Programmen anzeigen" setzen.
- Systemsteuerung → Anzeige (oder Rechtsklick auf den Desktop und "Eigenschaften" im Kontextmenü auswählen), dort den Reiter "Darstellung" wählen. Auf den Button "Effekte" klicken und im dann erscheinenden Dialog den Haken bei "Unterstrichene Buchstaben für Tastaturnavigation ausblenden (mit Alt-Taste einblenden)" entfernen.
Passend zu dieser neuen Spielerei gibt es eine Reihe von Window-Messages, die im Folgenden beschrieben werden. Darüber hinaus bieten diese Messages auch die Möglichkeit, dieses Verhalten für ein Programm gezielt abzuschalten oder anderweitig zu beeinflussen, wenn einem das sinnvoll erscheint.
[Zurück zum Inhaltsverzeichnis]
2. Neue Windows-Messages
2.1. Vorbemerkung
Die Texte in diesem Kapitel sind größtenteils (sinngemäße) Übersetzungen der original Microsoft-Dokumentation und klingen von daher an der einen oder anderen Stelle womöglich ein wenig holperig.
2.2. Konstanten
Es gibt folgende Konstanten:
// Messages #define WM_CHANGEUISTATE 0x0127 // Benachrichtigung: UI state sollte geändert werden. #define WM_UPDATEUISTATE 0x0128 // Befehl: UI state ändern. #define WM_QUERYUISTATE 0x0129 // Aktuellen UI state abfragen. // Operations #define UIS_SET 1 // Angegebene(s) Element(e) einschalten. #define UIS_CLEAR 2 // Angegebene(s) Element(e) ausschalten. #define UIS_INITIALIZE 3 // Angegebene(s) Element(e) gemäß letztem // Eingabeereignis ändern (siehe Anmerkungen). // Elements #define UISF_HIDEFOCUS 0x1 // Fokus-Rechteck verbergen. #define UISF_HIDEACCEL 0x2 // Hotkey-Untersreichungen verbergen. #define UISF_ACTIVE 0x4 // Ein Control als aktives Control zeichnen.
Interessant ist dabei, dass die Logik hinter den Konstanten ein wenig negiert ist. Will man also z.B. das Fokus-Rechteck anzeigen, so muss man für das Element "UISF_HIDEFOCUS" ein "UIS_CLEAR" schicken (also das Verstecken des Fokus-Rechtecks ausschalten).
[Zurück zum Inhaltsverzeichnis]
2.3. WM_CHANGEUISTATE
Diese Nachricht wird gesendet um anzuzeigen, dass der UI state geändert werden soll.
wParam | – | Im unteren Wort wird die gewünschte Operation angegeben, im oberen Wort die Kombination der Elemente, für die die Operation gelten soll. |
lParam | – | Wird nicht verwendet und muss 0 sein. |
Anm.: | Ein Fenster sollte diese Nachricht an sich selbst oder sein Elternfenster schicken, wenn es den UI state aller Fenster in der gleichen Hierarchieebene ändern muss. Die Windows-Procedure muss DefWindowProc diese Nachricht behandeln lassen, um sicherzustellen, dass der gesamte Fensterbaum einen konsistenten UI-state hat. Wenn das Top-Level-Fenster eine WM_CHANGEUISTATE-Nachricht empfängt, sendet es eine WM_UPDATEUISTATE-Nachricht mit den gleichen Parametern an alle seine Kinderfenster. Wenn das System die WM_UPDATEUISTATE-Nachricht behandelt, führt es die entsprechenden Änderungen am UI state durch. |
Wenn das untere Wort von wParam UIS_INITIALIZE enthält, dann sendet das System die WM_UPDATEUISTATE-Nachricht mit einem UI state, der auf dem letzten Eingabeereignis basiert. Wenn die letzte Eingabe zum Beispiel von der Maus kam, versteckt das System die Tastaturhinweise. Wenn der UI state vom Behandeln der WM_CHANGEUISTATE-Nachricht der gleiche ist wie der vorherige, sendet DefWindowProc keine WM_UPDATEUISTATE-Nachricht. |
[Zurück zum Inhaltsverzeichnis]
2.4. WM_UPDATEUISTATE
Diese Nachricht wird von einer Anwendung gesendet, um den UI state eines Fensters und aller seiner Kinderfenster zu ändern.
wParam | – | Im unteren Wort wird die gewünschte Operation angegeben, im oberen Wort die Kombination der Elemente, für die die Operation gelten soll. |
lParam | – | Wird nicht verwendet und muss 0 sein. |
Anm.: | Ein Fenster sollte diese Nachricht senden, um den UI state aller seiner Kinderfenster zu ändern. Im Unterschied zur WM_CHANGEUISTATE-Nachricht, welche eine Benachrichtigung ist, führt DefWindowProc beim Behandeln dieser Nachricht die Änderungen am UI state durch und leitet die Änderungen an alle Kinderfenster weiter. |
Die Funktion DefWindowProc aktualisiert den UI state entsprechend dem Wert in wParam. Wenn der UI state angepasst wird, sendet die Funktion diese Nachricht an alle direten Kinderfenster. DefWindowProc sendet diese Nachricht auch, wenn es eine WM_CHANGEUISTATE-Nachricht erhält, die dem System anzeigt, dass ein Kindfenster seinen UI state ändern möchte. |
[Zurück zum Inhaltsverzeichnis]
2.5. WM_QUERYUISTATE
Diese Nachricht wird gesendet, um den UI state eines Fensters abzufragen.
wParam | – | Wird nicht verwendet und muss 0 sein. |
lParam | – | Wird nicht verwendet und muss 0 sein. |
Der Rückgabewert zeigt an, welche Elemente aktiv (gesetzt) sind. Ist kein Element gesetzt, d.h. das Folus-Rechteck ist sichtbar und die Hotkey-Unterstreichungen werden angezeigt, gibt der Aufruf NULL zurück.
[Zurück zum Inhaltsverzeichnis]
3. UI state für ein Fenster gezielt setzen
Um z.B. dafür zu sorgen, dass in einem Fenster das Fokus-Rechteck angezeigt wird, sendet man eine entsprechende WM_UPDATEUISTATE-Nachricht (nicht WM_CHANGEUISTATE!) an dieses Fenster:
myWnd.SendMessage( WM_UPDATEUISTATE, MAKELPARAM( UIS_CLEAR, UISF_HIDEFOCUS ) );
[Zurück zum Inhaltsverzeichnis]
4. Code-Snippets für .net
Da man in .net keinen "nativen" Zugriff auf die Methode SendMessage hat, muss ein wenig gebastelt werden. Wie so etwas in aussehen kann, zeigen die folgenden Beispiele.
4.1. C#
namespace myNamespace { public class Form1 : Form { class Win32 { // Messages public const int WM_UPDATEUISTATE = 0x0128; // UI state operations public const int UIS_SET = 1; public const int UIS_CLEAR = 2; // UI state elements public const int UISF_HIDEFOCUS = 0x1; // helpers public static int MakeLParam( int loWord, int hiWord ) { return (hiWord << 16) | (loWord & 0xffff); } // imported windows functions [DllImport("user32.dll")] public extern static int SendMessage( IntPtr hWnd , uint msg , int wParam , int lParam ); } // ... protected override void OnShown( EventArgs e ) { // display focus rectangle Win32.SendMessage( this.Handle , Win32.WM_UPDATEUISTATE , Win32.MakeLParam( Win32.UIS_CLEAR, Win32.UISF_HIDEFOCUS ) , 0 ); // call base class base.OnShown( e ); } // ... } // Form } // Namespace
[Zurück zum Inhaltsverzeichnis]
4.2. VB.net
Public Class Form1 Inherits Form Class Win32 ' messages Public Const WM_UPDATEUISTATE As Integer = 296 ' UI state options Public Const UIS_SET As Integer = 1 Public Const UIS_CLEAR As Integer = 2 ' UI state elements Public Const UISF_HIDEFOCUS As Integer = 1 ' helpers Public Shared Function MakeLParam( ByVal loWord As Integer _ , ByVal hiWord As Integer _ ) As Integer Return ( hiWord << 16 ) Or ( loWord And &Hffff ) End Function ' imported windows functions <DllImport( "user32.dll" )> _ Public Shared Function SendMessage( ByVal hWnd As IntPtr _ , ByVal msg As UInteger _ , ByVal wParam As Integer _ , ByVal lParam As Integer _ ) As Integer End Function End Class ' ... Protected Overloads Overrides Sub OnShown( ByVal e As EventArgs ) ' display focus rectangle Win32.SendMessage( Me.Handle _ , Win32.WM_UPDATEUISTATE _ , Win32.MakeLParam( Win32.UIS_CLEAR, Win32.UISF_HIDEFOCUS ) _ , 0 _ ) ' vall base class MyBase.OnShown( e ); End Sub ' ... End Class ' Form1