NumPred: Globaler Hook mit Nachrichten nach außen

Im Moment entwickle ich ein kleines Programm, mit dem es später möglich sein soll, das NumPad als eine Tastatur zu verwenden, die einerseits das Schreiben mit einer Hand ermöglicht und andererseits durch den Einsatz von "Predictive Text" eine annehmbare Schreibgeschwindigkeit ermöglicht. Das Projekt selber habe ich NumPred getauft - als eine Kombination aus "NumPad" und "Predictive Text". 😀

NumPred wird aus zwei Teilen bestehen: Zum einen aus der NumPred.dll, die einen sogenannten Systemhook enthält und der NumPred.exe, die das eigentliche Programm darstellen wird.
Der Hook wird alle Tastatureingaben, die getätigt werden, analysieren, Tasteneingaben auf dem NumPad herausfiltern und an das Programm weiterleiten. Das Programm wird sich dann um die eigentliche Funktionalität kümmern: Sich merken, in welcher Reihenfolge die Tasten gedrückt wurden, Wortvorschläge heraussuchen und nach einer Bestätigung an das aktive Programm schicken.

Dass so etwas garnicht ausarten muss, möchte ich euch anhand des Hook-Quelltextes zeigen. Dieser ist - wie gesagt - für das filtern und weiterschicken der Tastatureingaben zuständig:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
library NumPred;

uses
  Windows,
  SysUtils,
  Messages,
  Classes;

var
  VHookHandle   : HHook   = 0;
  VWindowHandle : THandle = 0;

const
  CHookMessage = WM_APP + 4665;
  CHookWindow  = 'NumPredKeyboardHookWindow';

function KeyboardHook(ACode : Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
const
  CPressedAfter  = 1 shl 31;
  CPressedBefore = 1 shl 30;
var
  LCallNext  : Boolean;
  LKeyStatus : Byte;
  LKBState   : TKeyboardState;
  LNumActive : Boolean;
begin
  LCallNext := true;
  if (ACode = HC_ACTION) then
  begin
    if (GetKeyboardState(LKBState)) then
    begin
      LNumActive := (LKBState[VK_NUMLOCK] = 1);
      if ((LNumActive) and (wParam in [VK_RETURN, VK_NUMPAD0..VK_DIVIDE])) then
      begin
        LKeyStatus := 0; // unknown key state
        if (((lParam and CPressedBefore) = 0) and ((lParam and CPressedAfter) = 0)) then
          LKeyStatus := 1; // key down state
        if (((lParam and CPressedBefore) <> 0) and ((lParam and CPressedAfter) <> 0)) then
          LKeyStatus := 2; // key up state

        if (LKeyStatus > 0) then
        begin
          if (VWindowHandle = 0) then
            VWindowHandle := FindWindow(nil, CHookWindow);

          if (VWindowHandle <> 0) then
            PostMessage(VWindowHandle, CHookMessage, wParam, LKeyStatus);
        end;

        // abort handling
        LCallNext := (VWindowHandle = 0);
      end;
    end;
  end;

  if LCallNext then
    Result := CallNextHookEx(VHookHandle, ACode, wParam, lParam)
  else
    Result := -1;
end;

function HookKeyboard : Boolean; stdcall;
begin
  Result := false;

  if (VHookHandle = 0) then
  begin
    VHookHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardHook, hInstance, 0);

    Result := (VHookHandle <> 0);
    if (Result) then
      VWindowHandle := 0;
  end;
end;

function UnhookKeyboard : Boolean; stdcall;
begin
  Result := false;

  if (VHookHandle <> 0) then
  begin
    Result := UnhookWindowsHookEx(VHookHandle);
    if (Result) then
    begin
      VHookHandle   := 0;
      VWindowHandle := 0;
    end;
  end;
end;

exports
  HookKeyboard,
  UnhookKeyboard;

begin
end.

Der Hook unterscheidet zwischen dem drücken einer Taste und dem wieder loslassen der Taste. Die Informationen werden an das Fenster mit dem Titel "NumPredKeyboardHookWindow" gesendet - ich hoffe, dass dieser Name systemweit eindeutig genug ist. 😉

Die Anwendung, die die Informationen erhalten will, muss ebenfalls garnicht so viel machen - spannend ist dann wirklich erst die eigentliche Ersetzungslogik, die mich noch ein paar Stunden Arbeit kosten wird. So sieht der einfache Zugriff auf die Daten aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// [...]

const
  CHookMessage = WM_APP + 4665;
  CHookWindow  = 'NumPredKeyboardHookWindow';

// [...]

function HookKeyboard : Boolean; stdcall; external 'NumPred.dll';
function UnhookKeyboard : Boolean; stdcall; external 'NumPred.dll';

// [...]

procedure TMainForm.FormCreate(Sender : TObject);
begin
  InitializeWindow;
end;

procedure TMainForm.FormDestroy(Sender : TObject);
begin
  DeinitializeWindow;
end;

function TMainForm.HandleMessages(var AMessage: TMessage) : Boolean;
begin
  Result := false;

  if (AMessage.Msg = CHookMessage) then
  begin
    // AMessage.LParam enthält KeyDown/KeyUp Status
    // AMessage.LParam enthält KeyCode

    // abort handling
    Result := true;
  end;
end;

procedure TMainForm.DeinitializeWindow;
begin
  // deinitialize hook
  if not(UnhookKeyboard) then
    ShowMessage('Unhooking did not work out!');

  // disable message receiving
  Application.UnhookMainWindow(HandleMessages);
  Application.Title := '';
end;

procedure TMainForm.InitializeWindow;
begin
  // hide taskbar entry
  ShowWindow(Application.Handle, SW_HIDE);
  SetWindowLong(Application.Handle, GWL_EXSTYLE, GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
  ShowWindow(Application.Handle, SW_SHOW);

  // enable message receiving
  Application.Title := CHookWindow;
  Application.HookMainWindow(HandleMessages);

  // initialize hook
  if not(HookKeyboard) then
    ShowMessage('Hooking did not work out!');
end;

// [...]

initialization
  // only allow one instance
  if (FindWindow(nil, CHookWindow) <> 0) then
    Halt;

// [...]

Wünscht mir Glück, dass ich es schaffe, das Programm so schnell wie möglich fertig zu stellen. Ich habe schon einige Vorstellungen, wie der Lernprozess der Anwendung ablaufen soll und wie der eingegebene Text schlussendlich im aktiven Fenster (z.B. Word oder Firefox) landen soll. Aber die genaue Implementierung muss ich erst noch erarbeiten. 😉
Captain-Hook-Grüße, Kenny

3D für den Heim-PC

Nachdem ich am Freitag eine Idee für ein neues Projekt hatte - von dem ich natürlich noch berichten werde - bin ich zu Saturn am Alexanderplatz gefahren, um mir USB-NumPads zu besorgen. Ich hatte zuerst bei MediaMarkt im Kaufpark Eiche danach gesucht: Dort gab es allerdings nur Bluetooth NumPads von Microsoft - das Stück für 40€ 🙁 ! Bei Saturn habe ich von SpeedLink einfache NumPads für 15€ das Stück bekommen... plus einen Blick in die Zukunft! 😀

nVidia 3D-Brille

An einem Stand konnte man die neue 3D-Brille von nVidia ausprobieren; als Testobjekte dienten Screenshots von Game-Größen wie Lara Croft!
Und in der Tat: Der 3D-Effekt ist atemberaubend! Man sieht z.B. ein umstürzendes Auto, bei dem man denkt, man könne es wieder zurechtrücken. Bei einer Kampfszene erkennt man, welcher Kämpfer welche Position im Raum einnimmt. Und das ganze natürlich gestochen scharf!

Man wird wirklich dazu verleitet, den Kopf zur Seite zu bewegen, weil man denkt, dass man dadurch vllt. in die Ecke des Raums gucken könnte. Stattdessen verzerrt sich jedoch die Anzeige - ein direkter Blick auf den Monitor ist also empfehlenswert.

200€ für die Brille (plus evtl. eine kompatible Grafikkarte) und nochmal ein wenig für ein 3D-Spiel wird sich wohl nicht jeder sofort leisten können oder wollen, aber ich denke, dass die Technik nun reif ist, den Consumermarkt zu erobern. Die Brille von nVidia machte auf mich jedenfalls einen sehr soliden Eindruck.

Zum Einsatz kam bei der Demo ein handelsüblicher Monitor. Es bleibt deshalb abzuwarten, ob sich solche generellen Lösungen nicht vielleicht auch gegen die kommende Generation von "3D-Fernsehern" durchsetzen können.
Update:
Ich habe gerade mal ein wenig gegooglet und bin dabei auf einen Artikel von Heise gestoßen. In diesem heißt es, dass für die Brille ein Monitor mit 120Hz-Technik benötigt wird, sodass jedes Auge mit 60Hz aufgelöst werden kann. Zudem heißt es in dem Artikel, dass der 3D-Effekt bei vielen bereits erhältlichen Spielen funktioniert. Na das denn ich doch mal genial! Dann fehlt ja nur noch eine neuere nVidia-Grafikkarte der 8er oder 9er Modellserie! 😀
3D-Grüße, Kenny

Appell für unabhängigen und günstigen Individualjournalismus

Der Journalismus hat es in der letzten Zeit wirklich nicht leicht: Auf der einen Seite wird der Platz der Auslandsreporter inzwischen von Twitterern eingenommen und auf der anderen Seite hat die Lokalpresse mit enthusiastischen Bloggern zu kämpfen. 😀

Am Mittwoch hat nur die Bundeszentrale für politische Bildung zu einem Kongress eingeladen, auf dem der Präsident der bpb - Thomas Krüger - einen Appell an die Verlage gerichtet hat, durch Sparmaßnahmen nicht die Qualität des Zeitungsjournalismus zu zerstören.

"Ohne professionellen, auch teuren Journalismus, also ohne Leitartikel und Lokalspitzen, Reportagen und Analysen löst sich die Presse in Nichts auf"
(Thomas Krüger, Präsident der bpb)

Da es hier um den Lokaljournalismus geht, möchte ich dazu mal meine eigene Meinung kundtun: Ja, wir brauchen professionellen Journalismus - die häufig angesprochenen Blabla-Blog (wie auch ich ihn teilweise betreibe) reichen nicht aus, um sich fundiert über örtliche Nachrichten zu informieren. Aber ich bin nicht der Meinung, dass dieser Journalismus teuer sein muss!

Es gibt so viele Leute, die in ihrer Freizeit irgendwelche Events besuchen, die auf dem Nach-Hause-Weg Unfälle beobachten oder die direkt mit irgendeinem Problem konfrontiert sind. Heutzutage ist es so einfach möglich, selber Informationen zu publizieren - auch die Möglichkeit, gemeinsam Informationen zusammen zu tragen, ist gegeben. Wieso müssen also Reporter bezahlt werden, die sich über solche Alltagsgeschehnisse informieren, wenn jeder einzelne Betroffene (einer reicht bereits aus) das gleiche tun kann? Natürlich sind solche Bericht meist subjektiv geprägt und enthalten nicht alle Fakten.
Aber wozu muss man wissen, wieviele Tote es bei einem Verkehrsunfall gab? Viel wichtiger ist doch zu wissen, weshalb der Ehemann an dem Abend 2 Stunden länger bis nach Hause gebraucht hat. Wozu muss man wissen, wie teuer ein Bauprojekt ist? Wichtig ist doch, zu wissen, was gebaut wird und für wen. Jedem, der mehr wissen möchte, steht es frei, sich weitergehend zu informieren und seine Erkenntnisse wiederum zu teilen.

Natürlich lässt sich damit kein Geld verdienen - oder zumindest nicht viel - aber welche Kosten entstehen denn im Vergleich dazu? Man meldet sich bei einem kostenlosen Dienst an, investiert ein wenig seiner Freizeit in das Verfassen eines Artikels und erhält als Dank Aufmerksamkeit und schriftliche Reaktionen der Leser.

Wenn sich solche Strukturen weltweit etablieren würden, könnten viele Journalisten "eingespart" - um nicht zu sagen "sinnvoller genutzt" - werden. Denn wenn man sich auf die gleiche, offene, private Weise auch über das Alltagsgeschehen in England, Japan, Russland, Australien, Afrika, etc. informieren könnte, würden auch Auslandsreporter zu einem bestimmten Teil überflüssig werden.

Ich denke, die Verlage müssen sich früher ode später damit abfinden, dass der kleine Blogger von nebenan, der aus Spaß an der Freude über lokale Events berichtet, seinem gut ausgebildeten Journalisten den Rang abläuft. In dem Bereich sitzen die Zeitungsverlage und andere Content-Anbieter im gleichen Boot: Das Internet ersetzt ihr teures Gewerbe durch ein günstigeres Verteilungsinstrument, das allen Bürgern zugänglich ist.
Bloggende Grüße, Kenny

Firefox: 4GB Plugin-Updates

Gerade hat sich Firefox bei mir gemeldet und mir verraten, dass es ein paar Plugin-Updates gibt. Updates gestartet... aber was ist das?! Jedes Plugin will plötzlich 4 Gigabyte an Daten herunterladen! 🙁

Firefox: 4GB Plugin-Updates

Glücklicherweise wurden schlussendlich doch nicht die vollen 4GB heruntergeladen - ein bisschen Angst hatte ich davor allerdings schon!

Wie kann so ein Fehler denn zustande kommen? Hat der Updater vielleicht einfach nur die Größe des Plugins nicht anfragen können und hat deswegen die 4GB angezeigt? Ist euch soetwas auch schon einmal aufgefallen?
Update:
@huxi hatte bereits nach ein paar Minuten eine mögliche Antwort für das Problem geliefert:

@weizenspreu Da wurde -1 als unsigned int angesehen => 4GB 😀
(@Huxi bei Twitter.com)

Aktuelle Grüße, Kenny

Naziaufmärsche und Parteigezanke

Eigentlich hatte ich mir ja vorgenommen, zu dem Thema meine Klappe zu halten, aber inzwischen gibt es so viele Meinungen dazu im Netz, dass ich auch meine mal kundtun möchte. Thema ist die Initiative "Dresden Nazifrei", die dazu aufruft, Europas größten Naziaufmarsch, der am 13.02.2010 in Dresden stattfinden soll, mit einer Sitzblockade zu vereiteln.

Dieser Aufruf ist in den letzten Tagen in die Schlagzeilen geraten, nachdem Razzien durchgeführt, Werbematerial beschlagnahmt und Plakatierer festgenommen wurden. Parallel dazu wurde die Webseite der Initiative Dresden-Nazifrei.de vom LKA Sachsen gesperrt, obwohl dieses Vorgehen von Juristen als unhaltbar angesehen wird (die Webseite ist inzwischen übrigens unter Dresden-Nazifrei.com erreichbar).

Ein ganz anderes Feuer brodelte - und brodelt immernoch - innerhalb der Piratenpartei. Dort ist man zwiegespalten über die Teilnahme an dieser Blockade. Die einen berufen sich auf § 1 Abs. 1 der Bundessatzung, der wie folgt lautet:

(1) Die Piratenpartei Deutschland (PIRATEN) ist eine Partei im Sinne des Grundgesetzes der Bundesrepublik Deutschland und des Parteiengesetzes. Sie vereinigt Piraten ohne Unterschied der Staatsangehörigkeit, des Standes, der Herkunft, der ethnischen Zugehörigkeit, des Geschlechts, der sexuellen Orientierung und des Bekenntnisses, die beim Aufbau und Ausbau eines demokratischen Rechtsstaates und einer modernen freiheitlichen Gesellschaftsordnung geprägt vom Geiste sozialer Gerechtigkeit mitwirken wollen. Totalitäre, diktatorische und faschistische Bestrebungen jeder Art lehnt die Piratenpartei Deutschland entschieden ab.
(Bundessatzung der Piratenpartei Deutschland, Hervorhebung durch mich)

So lehnt Sven Scholz zum Beispiel jegliche Meinungsfreiheit für Nazis ab es ab, dass die Ideologie der Nazis unter dem Deckmantel der Meinungsfreiheit geschützt wird, da er die Nazi-Ideologie nicht als Meinung sondern als Verbrechen ansieht:

Zur “Meinungsfreiheit” der Nazis: Ich sehe eine Ideologie, die Menschenrechte nicht nur missachtet sondern ihnen offen widerspricht nicht als “Meinung”, die durch Menschenrechte gedeckt ist. Naziideologie ist keine Meinung sondern ein Verbrechen.
(Artikel in Sven Scholz' Blog)

Die andere Seite widerum beruft sich ausschließlich auf § 5 Abs. 1 des Grundgesetzes, in dem es heißt:

(1) Jeder hat das Recht, seine Meinung in Wort, Schrift und Bild frei zu äußern und zu verbreiten und sich aus allgemein zugänglichen Quellen ungehindert zu unterrichten. Die Pressefreiheit und die Freiheit der Berichterstattung durch Rundfunk und Film werden gewährleistet. Eine Zensur findet nicht statt.
(§ 5 Abs. 1 GG)

Natürlich ist es edel, sich nur auf diesen Absatz zu stürzen, allerdings geht der § 5 noch weiter. Auch dieser sollte unbedingt Beachtung finden, bevor man für Menschenverächter in die Bresche springt:

(2) Diese Rechte finden ihre Schranken in den Vorschriften der allgemeinen Gesetze, den gesetzlichen Bestimmungen zum Schutze der Jugend und in dem Recht der persönlichen Ehre.
(§ 5 Abs. 2 GG)

In meinen Augen ist es nicht hinnehmbar, dass eine Gruppe die Rechte, die ihnen zustehen, missbrauchen, um damit die Rechte anderer Gruppen öffentlich zu unterminieren. In diesen Fällen muss der demokratische Staat - zu dem sich auch die Piratenpartei bekennt - aktiv werden und die Rechte und die Ehre der einzelnen Bürger schützen, die bei solchen Naziaufmärchen tangiert werden.

Das wird wahrscheinlich auch der Grund sein, weshalb der Landesverband Sachsen im Piratenpartei-Wiki seine Unterstützung bei der Teilname an "öffentlichen, friedlichen Aktionen und Demonstrationen" erklärt hat. Schön war auch zu sehen, dass der Bundesverband dies auch kurze Zeit später auf der offiziellen Webseite der Piratenpartei Deutschland nachgeholt hat. Man darf jedoch nicht vergessen, dass angemeldete Demonstrationen und Prosteste den besseren Weg zur friedlichen Bekämpfung von Verfassungsfeinden darstellen.
Genau diese Aussage bekräftigt auch noch einmal die Pressesprecherin des LV Berlin - Lena Rohrbach - in einem Kommentar im Spreeblick-Blog. Aktionen gegen Naziaufmärsche sind gerechtfertigt, solange probate, verfassungskonforme Mittel dafür eingesetzt werden.

Und für alle Gegner solcher Gegendemonstrationen, die ausschließlich auf den § 5 Abs 1. GG pochen, möchte ich abschließend gerne noch den Kommentar von Julian anführen, der das ganze in meinen Augen wunderbar zusammenfasst:

Jeder hat das recht zu demonstrieren, auch die Gegner einer anderen Demo. Meinungsfreiheit heisst nicht, seine Meinung unwidersprochen kundtun zu dürfen.
(Kommentar von "Julian" auf SvenScholz.de)

Diese Aussage trifft haargenau meinen Gedanken: Natürlich dürfen die Leute ihre Gedanken äußern, jedoch müssen sie damit rechnen, dass sie vom Staat dazu ermahnt werden, nicht die Rechte und die Ehre anderer zu verletzen und dass sich ihn andere Leute in den Weg stellen, die ihre Meinung nicht teilen und als Gegensprecher auftreten. So ist das nunmal in einer Demokratie: Es gibt immer mehr als nur eine Meinung. 😉
Update:
Im Zuge eines Kommentars von Sven Scholz habe ich den Absatz über seine Ansichten zur Meinungsfreiheit der Nazis abgeändert. Danke für die Korrektur! 😀
Demokratische Grüße, Kenny

Seite 58 von 87« Erste...575859...Letzte »