Key Kombination abfragen

  • C#

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Key Kombination abfragen

    Hallo zusammen,

    ich arbeite gerade an einem Programm mit dem ich Windows Fenster bewegen kann. Mein Ziel ist es ein beliebiges Windows Fenster zu verschieben während ich dabei eine Key Kombination drücke. Dies kann man sich etwa so vorstellen: Ich halte z.B. Strg + Alt + L gedrückt und kann mithilfe der (unbetätigten) Maus das Fenster verschieben. Was ich bereits schaffe ist die Abfrage des aktuellen Fensters MIttels GetForegroundWindow(), auch kann ich die Fenster Position setzen (das wird später aber durch die MoveWindow() Funktion ersetzt).

    Was mir noch Fehlt wäre eine Methode mit der ich die Möglichkeit habe die gedrückten Tasten zu ermitteln, sodass ich dann bei Strg + Alt + L das Fenster bewegen kann. Meine Frage richtet sich primär darauf, wie man diese Kombination ermitteln kann? Außerdem habe ich noch eine Subfrage, ich habe das Ganze zunächst in einem Windows Forms Projekt gestartet, ist das eine Gute Idee? Oder ginge auch eine Konsolen Applikation dafür?

    Der Code ist aktuell noch Quick&Dirty aber es ist zumindest ein Anfang mit dem sich arbeiten lässt :)

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Runtime.InteropServices;
    8. using System.Text;
    9. using System.Threading.Tasks;
    10. using System.Windows.Forms;
    11. namespace MoveActivatedWindow
    12. {
    13. public partial class Form1 : Form
    14. {
    15. int counter = 0;
    16. [DllImport("user32.dll")]
    17. private static extern IntPtr GetForegroundWindow();
    18. [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    19. public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int wFlags);
    20. [DllImport("user32.dll", SetLastError = true)]
    21. static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
    22. [StructLayout(LayoutKind.Sequential)]
    23. public struct RECT
    24. {
    25. public int Left; // x position of upper-left corner
    26. public int Top; // y position of upper-left corner
    27. public int Right; // x position of lower-right corner
    28. public int Bottom; // y position of lower-right corner
    29. }
    30. [DllImport("user32.dll", SetLastError = true)]
    31. internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    32. public Form1()
    33. {
    34. InitializeComponent();
    35. }
    36. private void button1_Click(object sender, EventArgs e)
    37. {
    38. counter = 0;
    39. timer1.Start();
    40. }
    41. private void timer1_Tick(object sender, EventArgs e)
    42. {
    43. if (counter >= 5) return;
    44. IntPtr selectedWindow = GetForegroundWindow();
    45. textBox1.AppendText(selectedWindow + "\n");
    46. const short SWP_NOSIZE = 0x0001; // Retains the current size (ignores the cx and cy parameters).
    47. const short SWP_NOZORDER = 0x0004; // Retains the current Z order (ignores the hWndInsertAfter parameter).
    48. const int SWP_SHOWWINDOW = 0x0040; // Displays the window
    49. SetWindowPos(selectedWindow, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
    50. RECT windowRect = new RECT();
    51. GetWindowRect(selectedWindow, out windowRect);
    52. textBox1.AppendText(windowRect.Right + " " + windowRect.Left + "\n");
    53. // TODO:
    54. // Berechnen der Breite & Höhe (verwende RECT dazu...)
    55. // Positioniere den Cursor auf die Mitte des akutellen Fensters (verwende zuvor berechnete Höhe/2 & Breite/2)
    56. // SetCursorPos() ...
    57. // GetCursorPos() ... Point(x,y)
    58. // Verwende dann MoveWindow ggf. noch ein Thread ...
    59. }
    60. }
    61. }
    @VB.neter0101 So was:

    VB.NET-Quellcode

    1. Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
    2. If e.Alt AndAlso e.Control AndAlso e.KeyCode = Keys.L Then
    3. Label1.Text = "Strg + Alt + L"
    4. Else
    5. Label1.Text = ""
    6. End If
    7. End Sub
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Gonger96 Jou.
    @VB.neter0101 Probierma
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Runtime.InteropServices;
    3. using System.Windows.Forms;
    4. namespace WindowsFormsApplication1
    5. {
    6. public partial class Form1 : Form
    7. {
    8. [DllImport("user32.dll")]
    9. internal static extern ushort GetAsyncKeyState(Keys key);
    10. public Form1()
    11. {
    12. this.InitializeComponent();
    13. }
    14. private void timer1_Tick(object sender, EventArgs e)
    15. {
    16. bool b1 = (Form1.GetAsyncKeyState(Keys.LMenu) == 0x8001);
    17. bool b2 = (Form1.GetAsyncKeyState(Keys.LControlKey) == 0x8001);
    18. bool b3 = (Form1.GetAsyncKeyState(Keys.L) == 0x8001);
    19. if (b1 && b2 && b3)
    20. {
    21. this.label1.Text = "Strg + Alt + L";
    22. }
    23. else
    24. {
    25. this.label1.Text = "";
    26. }
    27. }
    28. private void checkBox1_CheckedChanged(object sender, EventArgs e)
    29. {
    30. this.timer1.Enabled = this.checkBox1.Checked;
    31. }
    32. private void Form1_KeyDown(object sender, KeyEventArgs e)
    33. {
    34. this.label2.Text = e.KeyCode.ToString();
    35. }
    36. }
    37. }

    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @Gonger96, was heißt registrieren hier?
    @RodFromGermany danke das teste ich mal. Ich habe eher in diese Richtung gedacht: docs.microsoft.com/de-de/dotne…roc?view=netframework-4.8 bzw. https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-hotkey

    Edit: Ich habe es mal getestet, es scheint nicht richtig zu funktionieren, von diesem hier hätte ich erwartet, dass es anstandslos funktioniert label2.Text = e.KeyCode.ToString();, aber das tut es nicht. Kann das sein, dass die Keys nicht registriert werden wenn man VS in einer VM laufen hat?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VB.neter0101“ ()

    vbp-Suche "hotkey registrieren", dann kommst Du bei mikeb69s Thread raus
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Kommt da gar nichts raus? Oder was anderes als erwartet? Laut stackoverflow kann es sein, dass ein anderes Keyboard-Layout in der VM zu überraschenden Resultaten führt.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Bei dem Codeschnipsel label2.Text = e.KeyCode.ToString(); kommt nix heraus. Ich habe aber vor kurzem selbst genau das gleiche auf einem Dienstrechner ohne VM programmiert und da ging das ohne Probleme, daher schiebe ich das voll und ganz auf die VM, ich meine bei dem Teil mit this.label1.Text = "Strg + Alt + L"; einmal kurz erhascht zu haben, dass das Label so ausgesehen hat. Aber wie gesagt ich denke die VM ist schuld, was eigentlich sehr schade ist, das ich es nicht leiden kann eine Entwicklungsumgebung aktiv in mein System eingreifen zu lassen, bzw die dort entwickelten Programme (das kann mitunter sehr problematisch werden File.IO ) :)
    @VB.neter0101 Mit ner VM kann ich erst wieder auf Arbeit testen, muss ich mir auf einen Zettel schreiben.
    Was hast Du für ein Host-System?
    Bei mir läuft ein UBuntu.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @VB.neter0101 Ich hab mal noch ein wenig gespielt, das hier läuft sicherer:

    C#-Quellcode

    1. private void timer1_Tick(object sender, EventArgs e)
    2. {
    3. bool b1 = (Form1.GetAsyncKeyState(Keys.Menu) != 0);
    4. bool b2 = (Form1.GetAsyncKeyState(Keys.ControlKey) != 0);
    5. bool b3 = (Form1.GetAsyncKeyState(Keys.L) != 0);
    6. if (b1 && b2 && b3)
    7. {
    8. this.label1.Text = "Strg + Alt + L";
    9. }
    10. else
    11. {
    12. this.label1.Text = "";
    13. }
    14. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Es macht was es soll:

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Linq;
    7. using System.Runtime.InteropServices;
    8. using System.Text;
    9. using System.Threading;
    10. using System.Threading.Tasks;
    11. using System.Windows.Forms;
    12. namespace MoveWindowsWithHotkeys
    13. {
    14. public partial class Form1 : Form
    15. {
    16. [DllImport("user32.dll")]
    17. private static extern int RegisterHotKey(IntPtr hWnd, int id, int fsModifier, int vk);
    18. [DllImport("user32.dll")]
    19. private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    20. [DllImport("user32.dll")]
    21. private static extern IntPtr GetForegroundWindow();
    22. [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    23. public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int wFlags);
    24. [DllImport("user32.dll", SetLastError = true)]
    25. internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    26. [DllImport("user32.dll")]
    27. internal static extern ushort GetAsyncKeyState(Keys key);
    28. [DllImport("user32.dll")]
    29. static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint);
    30. [DllImport("user32.dll")]
    31. static extern bool SetCursorPos(int X, int Y);
    32. [DllImport("user32.dll", SetLastError = true)]
    33. static extern bool GetCursorPos(out Point lpPoint);
    34. [DllImport("user32.dll", SetLastError = true)]
    35. static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
    36. [StructLayout(LayoutKind.Sequential)]
    37. public struct RECT
    38. {
    39. public int Left; // x position of upper-left corner
    40. public int Top; // y position of upper-left corner
    41. public int Right; // x position of lower-right corner
    42. public int Bottom; // y position of lower-right corner
    43. }
    44. private const int Key_NONE = 0x0000;
    45. private const int WM_HOTKEY = 0x312; // 0x201 for left key from mouse
    46. public Form1()
    47. {
    48. InitializeComponent();
    49. }
    50. private void MoveTheSelectedWindow()
    51. {
    52. IntPtr selectedWindow = GetForegroundWindow();
    53. RECT windowRect = new RECT();
    54. GetWindowRect(selectedWindow, out windowRect);
    55. int selectedWindowWidth = windowRect.Right - windowRect.Left;
    56. int selectedWindowHeight = windowRect.Bottom - windowRect.Top;
    57. Point cursorPosition = new Point();
    58. GetCursorPos(out cursorPosition);
    59. int xOffset = cursorPosition.X - selectedWindowWidth / 2;
    60. int yOffset = cursorPosition.Y - selectedWindowHeight / 2;
    61. MoveWindow(selectedWindow, xOffset, yOffset, selectedWindowWidth, selectedWindowHeight, true);
    62. //const short SWP_NOSIZE = 0x0001; // Retains the current size (ignores the cx and cy parameters).
    63. //const short SWP_NOZORDER = 0x0004; // Retains the current Z order (ignores the hWndInsertAfter parameter).
    64. //const int SWP_SHOWWINDOW = 0x0040; // Displays the window
    65. //SetWindowPos(selectedWindow, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
    66. //GetWindowRect(selectedWindow, out windowRect);
    67. }
    68. private void timer1_Tick_1(object sender, EventArgs e)
    69. {
    70. bool b1 = (GetAsyncKeyState(Keys.Menu) != 0);
    71. bool b2 = (GetAsyncKeyState(Keys.ControlKey) != 0);
    72. bool b3 = (GetAsyncKeyState(Keys.Q) != 0);
    73. if (b1 && b2 && b3)
    74. {
    75. //this.label1.Text = "Strg + Alt + Q";
    76. MoveTheSelectedWindow();
    77. }
    78. else
    79. {
    80. //this.label1.Text = "";
    81. }
    82. }
    83. }
    84. }


    Damit kann ich bei gedrückter Tasten Kombi von Strg + Alt + Q ein ausgewähltes Fenster bewegen :)

    Das war mal wieder sehr aufschlussreich :)

    Mal angenommen ich möchte nicht immer die Tasten Kombi gedrückt halten, sondern einmal betätigen, um das Fenster zu bewegen und ein erneutes betätigen der Tasten Kombi führt dazu, dass das Fenster nicht mehr bewegt würde, wie könnte man das in den Timer einbauen?

    PS: Codekorrekturen sind gerne erwünscht!!!

    PPS: Außerdem habe ich ein interessantes Verhalten beobachtet, wenn ich z.B. Notepad++ verschiebe schreibt er mir die Qs ins Dokument :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „VB.neter0101“ ()

    Das geht über ein Flag (= Boolean Variable). Wenn die Tastenkombi gedrückt wird, wird das Flag zwischen True und False hin- und hergeschaltet. Und wenn es auf True ist, wird dies in Zeile #85 geprüft und der Fensterverschiebecode wird ausgeführt. Du solltest dies aber ggf. irgendwo anzeigen, ggf. als Symbol im Traybereich, Ob der Verschiebemodus aktiv oder inaktiv ist.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    VB.neter0101 schrieb:

    wenn ich z.B. Notepad++ verschiebe schreibt er mir die Qs ins Dokument
    GetAsyncKeyState() leert die Queue nicht.
    Wenn das Notepad den Folus hat, kommt da halt ein Q rein.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @VB.neter0101 Ich weiß nicht, wie die Fremd-Queue geleert werden kann.
    Da hat das System die Hand drauf, zumal Du das fremde ForegroundWindow bedienst, das das Ziel der Queue ist.
    Verhindern kannst Du das, wenn Dein Programm seine eigene Queue leert, und das passiert, wenn Dein Fenster selbst das ForegroundWindow ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Ich grabe hier mal wieder diesen Thread aus, da mich interessiert, wie man eine Key Kombination systemweit registriert, Bzw. wie man dies verallgemeinert mit weiteren Hotkeys.

    Wichtig wäre die Hotkeys als global zu setzen, dass sobald der Hotkey betätigt wird eine Subsequenz im Programm ausgeführt wird und das unabhängig davon ob meine Windows Form aktiv ist oder nicht.

    Hat hier schon mal Jemand erste Ergebnisse erzielt?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!