Jun 072016

You probably know about the Windows 7+ feature to snap a window to the left or right side of the monitor via Windows+Left / Windows+Right hotkey. You might even know that Windows 10 extended this to snap a window to the top or bottom and even to one of the quadrants of your monitor. (I for one had read about that Windows 10 feature but had already forgotten it, since I don’t plan to upgrade in the near future.)

But what if you don’t have Windows 10? Can this be done programmatically? Of course it can! Just add appropriate Actions, assign the shortcuts to your form and write the code. Or set the form’s KeyPreview property to true and put the code into the FormKeyDown event handler. Unfortunately this requires some rather tiresome copy and paste plus clicking on the object inspector for each of the forms. And, of course, copy and paste is evil, because it violates the DRY principle: If you make a mistake once, you will have to correct it in all the copies you have made in the meantime.

Enter TForm_ActivatePositoning: A utility function which I have added to dzLib today:

Just by calling


you can add this functionality to every form in every project you’ll ever write.

Ok, so what does it do?

It subclasses the window (that is: Replaces its WindowProc (Wow, I just learnt that there is a new approach to subclassing, must have missed that for a few years)) to intercept the CM_CHILDKEY message which is sent by the VCL whenever any child control of a form receives a WM_KEYDOWN message:

  TFormPositioningActivator = class(TWindowProcHook)
    FModifier: TShiftState;
    procedure CmChildKey(var _Msg: TMessage);
    function TheForm: TForm;
    procedure NewWindowProc(var _Msg: TMessage); override;
    constructor Create(_Form: TForm; _Modifier: TShiftState);

constructor TFormPositioningActivator.Create(_Form: TForm; _Modifier: TShiftState);
  inherited Create(_Form);
  FModifier := _Modifier;

procedure TFormPositioningActivator.CmChildKey(var _Msg: TMessage);
  Key: Word;
  Key := (_Msg.WParamLo and $FF);
  if GetModifierKeyState = FModifier then begin
    case Key of
      VK_LEFT, VK_NUMPAD4: TForm_MoveTo(TheForm, dwpLeft);
      VK_RIGHT, VK_NUMPAD6: TForm_MoveTo(TheForm, dwpRight);
      VK_UP, VK_NUMPAD8: TForm_MoveTo(TheForm, dwpTop);
      VK_DOWN, VK_NUMPAD2: TForm_MoveTo(TheForm, dwpBottom);
      VK_PRIOR, VK_NUMPAD9: TForm_MoveTo(TheForm, dwpTopRight);
      VK_NEXT, VK_NUMPAD3: TForm_MoveTo(TheForm, dwpBottomRight);
      VK_HOME, VK_NUMPAD7: TForm_MoveTo(TheForm, dwpTopLeft);
      VK_END, VK_NUMPAD1: TForm_MoveTo(TheForm, dwpBottomLeft);
      Exit; //==> exit, so Result doesn't get set to 1
    _Msg.Result := 1;

procedure TFormPositioningActivator.NewWindowProc(var _Msg: TMessage);
  if _Msg.Msg = CM_CHILDKEY then

  inherited NewWindowProc(_Msg);

function TFormPositioningActivator.TheForm: TForm;
  Result := TForm(FCtrl);

function TForm_ActivatePositioning(_Form: TForm; _Modifier: TShiftState = [ssCtrl, ssAlt]): TObject;
  Result := TFormPositioningActivator.Create(_Form, _Modifier);

It uses the existing TWindowProcHook class which is already used for drag&drop and autocomplete (wow, was that really two years ago?) so the actual code is quite simple, as you can see above.

I did not use the Windows key as modifier but rather Ctrl+Alt because Microsoft says we should not use the Windows key. But I’m not quite sure about this. Maybe I could instead check for the Windows version to see if those hotkeys are already available and only add those that aren’t, using the Windows key.

But for now, the following hotkeys are implemented:

  • Ctrl+Alt+Up – snap window to the top of the monitor, or if already there, to the bottom of the monitor above it
  • Ctrl+Alt+Down – same for the bottom of the monitor
  • Ctrl+Alt+Left – same for the left of the monitor
  • Ctrl+Alt+Right – same for the left of the monitor
  • Ctrl+Alt+Home – snap the window to the upper left quadrant of the monitor
  • Ctrl+Alt+End – same for the lower left quadrant
  • Ctrl+Alt+PgUp – same for the upper right quadrant
  • Ctrl+Alt+PgDown- same for the lower right quadrant

Those hotkeys also work for the keys on the numeric keypad, regardless whether NumLock is active or not. If you look at your keyboard you will notice why I choose these particular keys: The nicely correspond to the quadrants / halves of the monitor and should it easier to memorize them.

(Picture courtesy of Wikipedia.)

Sorry, the comment form is closed at this time.

%d bloggers like this: