Comment #16 on issue 1064 by [email protected]: There are still problem with keyboard shortcuts in Windows
http://code.google.com/p/pharo/issues/detail?id=1064

'ctrl+.' doesn't also work. So I'm proposing a new solution.
The issue of shortcut key such as ctrl+i is solved by fixing VM, without repairing an image file of Pharo 1.1.1.
The workaround at Comment 11 is replaced to this solution.

(1)Problem
Thear are two problems.

First, key character event for Ctrl-key combination which can not encode to ASCII control character is not generated.
i.e. we can use only ASCII control character as Ctrl-key combo.
But some Ctrl-key combo which is not ASCII control character are used in Smalltalk. In current Windows VM implementation, a key character event on Smalltalk is created based on WM_CHAR Windows messege. Windos does not generate WM_CHAR message for Ctrl-key entry which can not encode to ASCII control character.

Second, when ctrl-key combo is pressed, ASCII control character is set to keyboard event imformation,
but the key's character code is not set.
Concretely, when '^A' is pressed, ASCII code '^A' is set to keyboard event, ASCII code 'A' is not set. The second problem is probably on only Windows VM, is not on other platforms.

(2)Solution
Create key character events for Ctrl-key combinations when WM_KEYCHAR is fetched, not when WM_CHAR is fetched. And then, by using ToAscii(or ToUnicode) Win32API function, convert virtual key code to ASCII code
 and set key's character to keyboard event object.
I think this approach is can be used to Squeak VM.

(3)Implementation
I corrected "sqWin32Window.c", please see also the attached file.

**** line 1060 in mapVirtualKey ****

    /* case VK_RETURN: return 13; */

**** line 1188 - 1236 new function ****

void recordCtrlKeyCharEvent(MSG* msg, sqKeyboardEvent* evt)
{
  BYTE keystate[256];
  WORD wd;
  WORD asciiKeyChar = 0;
  WORD asciiCtrlChar = 0xFFu;
  sqKeyboardEvent* extra;
  WPARAM virtualKeyCode = msg->wParam;

  assert(GetKeyState(VK_CONTROL) & 0x8000);

  /* Exit when only control key is pressed. */
  if(virtualKeyCode == VK_CONTROL) {
    return;
  }

  GetKeyboardState( keystate );

  /* get ASCII control character */
  switch(ToAscii( virtualKeyCode, HIWORD(msg->lParam), keystate, &wd, 0 )) {
  case 0:
    break;
  case 1:
    asciiCtrlChar = wd;
    break;
  default:
    return;
  }

  /* cancel ctrl key state */
  keystate[VK_CONTROL] = 0;

  /* get key character */
if (ToAscii( virtualKeyCode, HIWORD(msg->lParam), keystate, &asciiKeyChar, 0 ) != 1) {
    return;
  }

/* Exit when Ctrl + ENTER is pushed, because the combo is duplicate to ^N or ^M. */
  if (asciiKeyChar == 13) {
    return;
  }

  /* generate extra character event */
  extra = (sqKeyboardEvent*)sqNextEventPut();
  *extra = *evt;
  extra->pressCode = EventKeyChar;
extra->charCode = (asciiCtrlChar != 0xFFu ? asciiCtrlChar : asciiKeyChar) & 0xFF;
  extra->utf32Code = asciiKeyChar & 0xFF;
}

**** line 1276, 1304 - 1315 in recordKeyboardEvent ****

      /* if(keyCode == 13) return 1; */
...

  if(pressCode == EventKeyDown) {
    if (virtCode != 0) {
      /* generate extra character event */
      sqKeyboardEvent *extra = (sqKeyboardEvent*)sqNextEventPut();
      *extra = *evt;
      extra->pressCode = EventKeyChar;
    } else if (ctrl) {
/* note: when virtCode is not zero, ctrl+key combination (e.g. ctrl+arrow)
         are not created by recordCtrlKeyCharEvent. */
      recordCtrlKeyCharEvent(lastMessage, evt);
    }
  }

**** line 1586 - 1595 new function ****
BOOL notCtrlDown(MSG* msg) {
  switch(msg->message) {
  case WM_KEYDOWN:
  case WM_SYSKEYDOWN:
    if (GetKeyState(VK_CONTROL) & 0x8000) {
      return FALSE;
    }
  }
  return TRUE;
}

**** line 1615- 1620 in ioProcessEvents ****
/* Don't create WM_CHAR and WM_SYSCHAR message, when ctrl key is pressed. */
      if (notCtrlDown(&msg)) {
        TranslateMessage(&msg);
      }
      DispatchMessage(&msg);
    }


(4)Correct Pharo image file
To work some Ctrl+key combo whose key is non-alphabet, image file should be corrected.
e.g. below is a sample of correction for 'ctrl+.' on Pharo.

handleEvent: evt
    "Store the event in the queue if there's any"
    | type cmdBit ctrlBit | "# change #"
    type := evt at: 1.
    type = EventTypeKeyboard
        ifTrue: [
            cmdBit := 0. "# add #"
            ctrlBit := 0. "# add #"
            Preferences swapControlAndAltKeys
                    ifTrue: [ctrlBit := (evt at: 5) bitAnd: 2]
                    ifFalse:[cmdBit := (evt at: 5) bitAnd: 8]. "# add #"
            Preferences duplicateAllControlAndAltKeysSetting
                    ifTrue: [ctrlBit := (evt at: 5) bitAnd: 2]. "# add #"
cmdBit := (cmdBit bitShift:8) bitOr:(ctrlBit bitShift: 10). "# add #"

            "Check if the event is a user interrupt"
            ((evt at: 4) = 0
                and: [((evt at: 3)
                        bitOr: cmdBit) "# change #"
                            = interruptKey])
                    ifTrue: [
                        Display deferUpdates: false.
                        SoundService default shutDown.
                        self handleUserInterrupt].
            ^self ].

Thanks

tn

Attachments:
        sqWin32Window.c  100 KB


Reply via email to