Harmony
  1. Harmony
  2. HARMONY-4423

[classlib][awt][jedit] Toolkit.getLockingKeyState() is not implemented

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: None
    • Labels:
      None
    • Environment:
      Win32
    • Patch Info:
      Patch Available

      Description

      Method java.awt.Toolkit.getLockingKeyState(int) is not implemented and throws RuntimeException when called. This prevents some applications like jEdit automated GUI test scenario from running normally, see HARMONY-3633, it had to provide a special workaround patch to address this issue.

      Implementing this method may be tough as it requires writing native code, however a simple workaround patch may be created to improve compatibility while the real implementation is absent. Here I provide this patch (actually extracted from HARMONY-3633) and my suggestion is to apply it immediately.

      1. Harmony-4423-Workaround.patch
        0.8 kB
        Vasily Zakharov
      2. 4423_win.patch
        16 kB
        Ilya Berezhniuk
      3. 4423_win.patch
        16 kB
        Ilya Berezhniuk
      4. 4423_win.patch
        16 kB
        Ilya Berezhniuk
      5. 4423_win.patch
        16 kB
        Ilya Berezhniuk
      6. 4423_win.patch
        17 kB
        Ilya Berezhniuk
      7. 4423_win.patch
        10 kB
        Ilya Berezhniuk
      8. 4423_win_nosearch.patch
        15 kB
        Ilya Berezhniuk
      9. 4423_win_nosearch.patch
        15 kB
        Ilya Berezhniuk

        Issue Links

          Activity

          Hide
          Vasily Zakharov added a comment -

          The attached patch unconditionally returns false, instead of throwing exception.

          Show
          Vasily Zakharov added a comment - The attached patch unconditionally returns false, instead of throwing exception.
          Hide
          Vasily Zakharov added a comment -

          Here's the discussion on this topic in the mailing list:
          http://thread.gmane.org/gmane.comp.java.harmony.devel/28243

          Show
          Vasily Zakharov added a comment - Here's the discussion on this topic in the mailing list: http://thread.gmane.org/gmane.comp.java.harmony.devel/28243
          Hide
          Vasily Zakharov added a comment -

          I've checked the behavior of Toolkit.getLockingKeyState()/setLockingState() on Windows XP on RI and found that those methods work weirdly.

          Here's a simple test demonstrating RI behavior:

          import java.awt.Toolkit;
          import java.awt.event.KeyEvent;
          public class Test {
          public static void main(String[] args) {
          try

          { Toolkit toolkit = Toolkit.getDefaultToolkit(); System.out.println("" + toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) + " " + toolkit.getLockingKeyState(KeyEvent.VK_NUM_LOCK) + " " + toolkit.getLockingKeyState(KeyEvent.VK_SCROLL_LOCK) /*+ " " + toolkit.getLockingKeyState(KeyEvent.VK_KANA_LOCK)*/); // throws UnsupportedOperationException System.out.println("1. Turning CapsLock ON"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, true); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); System.out.println("2. Turning CapsLock OFF"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, false); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); System.out.println("3. Turning CapsLock ON"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, true); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); System.out.println("4. Turning CapsLock OFF"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, false); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); }

          catch (Throwable e)

          { e.printStackTrace(); }

          }
          }

          If CapsLock was OFF at the application start, the output is as follows (comments denote what happens at that point on the keyboard):

          false true false
          1. Turning CapsLock ON // Light goes ON
          false
          2. Turning CapsLock OFF
          false
          3. Turning CapsLock ON // Light goes OFF
          false
          4. Turning CapsLock OFF
          false

          If start CapsLock was ON at the application, the ouput is as follows:

          true true false
          1. Turning CapsLock ON // Light goes OFF
          true
          2. Turning CapsLock OFF
          true
          3. Turning CapsLock ON // Light goes ON
          true
          4. Turning CapsLock OFF
          true

          In other words, the following statements seem true about the RI operation:

          • getLockingKeyState() returns the state of the key at the application start, calls to setLockingKeyState() and pressing the key on the keyboard do not affect it.
          • If the key was OFF at the application start, setLockingKeyState(false) does nothing, and setLockingKeyState(true) toggles the actual state (light on the keyboard changes state and typing (in other window) indicates the state changes immediately).
          • If the key was ON at the application start, setLockingKeyState(true) does nothing, and setLockingKeyState(false) toggles the actual state.

          This behavior clearly contradicts the specification, but I suspect it's grounded by some Windows API peculiarities.

          I'm not sure if we should follow specification or RI behavior, but investigation of Windows API capabilities in this area is surely required before we could make the right decision.

          Show
          Vasily Zakharov added a comment - I've checked the behavior of Toolkit.getLockingKeyState()/setLockingState() on Windows XP on RI and found that those methods work weirdly. Here's a simple test demonstrating RI behavior: import java.awt.Toolkit; import java.awt.event.KeyEvent; public class Test { public static void main(String[] args) { try { Toolkit toolkit = Toolkit.getDefaultToolkit(); System.out.println("" + toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK) + " " + toolkit.getLockingKeyState(KeyEvent.VK_NUM_LOCK) + " " + toolkit.getLockingKeyState(KeyEvent.VK_SCROLL_LOCK) /*+ " " + toolkit.getLockingKeyState(KeyEvent.VK_KANA_LOCK)*/); // throws UnsupportedOperationException System.out.println("1. Turning CapsLock ON"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, true); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); System.out.println("2. Turning CapsLock OFF"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, false); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); System.out.println("3. Turning CapsLock ON"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, true); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); System.out.println("4. Turning CapsLock OFF"); toolkit.setLockingKeyState(KeyEvent.VK_CAPS_LOCK, false); Thread.sleep(1000); System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_CAPS_LOCK)); } catch (Throwable e) { e.printStackTrace(); } } } If CapsLock was OFF at the application start, the output is as follows (comments denote what happens at that point on the keyboard): false true false 1. Turning CapsLock ON // Light goes ON false 2. Turning CapsLock OFF false 3. Turning CapsLock ON // Light goes OFF false 4. Turning CapsLock OFF false If start CapsLock was ON at the application, the ouput is as follows: true true false 1. Turning CapsLock ON // Light goes OFF true 2. Turning CapsLock OFF true 3. Turning CapsLock ON // Light goes ON true 4. Turning CapsLock OFF true In other words, the following statements seem true about the RI operation: getLockingKeyState() returns the state of the key at the application start, calls to setLockingKeyState() and pressing the key on the keyboard do not affect it. If the key was OFF at the application start, setLockingKeyState(false) does nothing, and setLockingKeyState(true) toggles the actual state (light on the keyboard changes state and typing (in other window) indicates the state changes immediately). If the key was ON at the application start, setLockingKeyState(true) does nothing, and setLockingKeyState(false) toggles the actual state. This behavior clearly contradicts the specification, but I suspect it's grounded by some Windows API peculiarities. I'm not sure if we should follow specification or RI behavior, but investigation of Windows API capabilities in this area is surely required before we could make the right decision.
          Hide
          Alexey Petrenko added a comment -

          As far as I understood setLockingState works OK on RI but getLocking state returns the key state at the start up. Right?

          Show
          Alexey Petrenko added a comment - As far as I understood setLockingState works OK on RI but getLocking state returns the key state at the start up. Right?
          Hide
          Vasily Zakharov added a comment -

          I've tried the test on Linux, it seems to throw UnsupportedOperationException on any call to getLockingKeyState()/setLockingState() - in other words, it seems RI doesn't support this functionality on Linux.

          Show
          Vasily Zakharov added a comment - I've tried the test on Linux, it seems to throw UnsupportedOperationException on any call to getLockingKeyState()/setLockingState() - in other words, it seems RI doesn't support this functionality on Linux.
          Show
          Vasily Zakharov added a comment - In fact, the problem turns out to be much more complex. I searched the Java.Sun.Com site for related information and found a number of them that are useful. General idea is investigating the RI behavior to provide the proper compatibility in this area is a separate non-simple task. http://java.sun.com/developer/onlineTraining/new2java/supplements/solutions/Dec05.html http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4320043 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4414164 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4744373 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4834514 http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5100701 http://forum.java.sun.com/thread.jspa?forumID=54&threadID=627806 http://forum.java.sun.com/thread.jspa?forumID=57&threadID=628062 http://forum.java.sun.com/thread.jspa?forumID=57&threadID=751631 http://forum.java.sun.com/thread.jspa?forumID=257&threadID=321221
          Hide
          Alexey Petrenko added a comment -

          We can implement the spec. This is not complicated on Windows. I've not investigated the issue on Linux.

          Show
          Alexey Petrenko added a comment - We can implement the spec. This is not complicated on Windows. I've not investigated the issue on Linux.
          Hide
          Vasily Zakharov added a comment -

          It IS complicated. I mean, it's not a problem to provide SOME operational implementation, but it seems not possible to create an implementation that an average user would expect after reading the spec (see links above - RI still didn't do it). Choosing which RI-known problems we can tolerate and which not - is complicated.

          Show
          Vasily Zakharov added a comment - It IS complicated. I mean, it's not a problem to provide SOME operational implementation, but it seems not possible to create an implementation that an average user would expect after reading the spec (see links above - RI still didn't do it). Choosing which RI-known problems we can tolerate and which not - is complicated.
          Hide
          Alexey Petrenko added a comment -

          So what are the problems from Windows API and Linux API sides which are prevents us from getting the state of CAPS, NUM, SCROLL and KANA LOCK keys?

          Show
          Alexey Petrenko added a comment - So what are the problems from Windows API and Linux API sides which are prevents us from getting the state of CAPS, NUM, SCROLL and KANA LOCK keys?
          Hide
          Vasily Zakharov added a comment -

          It IS complicated. I mean, it's not a problem to provide SOME operational implementation, but it seems not possible to create an implementation that an average user would expect after reading the spec (see links above - RI still didn't do it). Choosing which RI-known problems we can tolerate and which not - is complicated.

          Show
          Vasily Zakharov added a comment - It IS complicated. I mean, it's not a problem to provide SOME operational implementation, but it seems not possible to create an implementation that an average user would expect after reading the spec (see links above - RI still didn't do it). Choosing which RI-known problems we can tolerate and which not - is complicated.
          Hide
          Ilya Berezhniuk added a comment -

          Here is Toolkit.getLockingKeyState/setLockingKeyState implementation for Windows.

          Toolkit class uses static LockingState.getInstance() method to get platform-specific successor of base class LockingState. Windows successor WinLockingState is implemented; LinuxLockingState is added also but its methods do nothing.

          Note: keybd_event function is used to generate keyboard events for toggling keys. MSDN says that SendInput should be used instead, but using SendInput involves raising minimal Windows version to 0x0500 and requires changes in build files.

          Show
          Ilya Berezhniuk added a comment - Here is Toolkit.getLockingKeyState/setLockingKeyState implementation for Windows. Toolkit class uses static LockingState.getInstance() method to get platform-specific successor of base class LockingState. Windows successor WinLockingState is implemented; LinuxLockingState is added also but its methods do nothing. Note: keybd_event function is used to generate keyboard events for toggling keys. MSDN says that SendInput should be used instead, but using SendInput involves raising minimal Windows version to 0x0500 and requires changes in build files.
          Hide
          Ilya Berezhniuk added a comment -

          Patch was updated: removed some copy-paste errors from LinuxLockingState class.

          Show
          Ilya Berezhniuk added a comment - Patch was updated: removed some copy-paste errors from LinuxLockingState class.
          Hide
          Ilya Berezhniuk added a comment -

          Some improvements were made in suggested patch.

          Show
          Ilya Berezhniuk added a comment - Some improvements were made in suggested patch.
          Hide
          Ilya Berezhniuk added a comment -

          Calls to keybd_event were replaces with calls to obtained pointers

          Show
          Ilya Berezhniuk added a comment - Calls to keybd_event were replaces with calls to obtained pointers
          Hide
          Ilya Berezhniuk added a comment -

          Attached 4423_win_nosearch.patch - it's another version of patch in which native code doesn't look for Win32 API functions through user32 library, but relies on natural dynamic linking.

          Show
          Ilya Berezhniuk added a comment - Attached 4423_win_nosearch.patch - it's another version of patch in which native code doesn't look for Win32 API functions through user32 library, but relies on natural dynamic linking.
          Hide
          Vasily Zakharov added a comment -

          Wow, Ilya, this patch is great! It seems to work even better than RI does! Thank you!

          Just a small note - when throwing UnsupportedOperationException (when Kana key is absent, for example), RI adds a detalization message, like this:

          java.lang.UnsupportedOperationException: Keyboard doesn't have requested key

          Probably we should do the same.

          Show
          Vasily Zakharov added a comment - Wow, Ilya, this patch is great! It seems to work even better than RI does! Thank you! Just a small note - when throwing UnsupportedOperationException (when Kana key is absent, for example), RI adds a detalization message, like this: java.lang.UnsupportedOperationException: Keyboard doesn't have requested key Probably we should do the same.
          Hide
          Ilya Berezhniuk added a comment -

          Vasily,
          I thought about it, but as far as I can see AWT usually uses strings like "Messages.getString("awt.XXX"))" for exceptions. Unfortunately, I don't know where to add appropriate string.
          If so, and if you know where to add string into string table, you can prepare additional patch for Toolkit.java, which will apply over both '4423_win.patch' and '4423_win_nosearch.patch'.

          If adding simple string right into java code is acceptable, I'll update patches.

          Show
          Ilya Berezhniuk added a comment - Vasily, I thought about it, but as far as I can see AWT usually uses strings like "Messages.getString("awt.XXX"))" for exceptions. Unfortunately, I don't know where to add appropriate string. If so, and if you know where to add string into string table, you can prepare additional patch for Toolkit.java, which will apply over both '4423_win.patch' and '4423_win_nosearch.patch'. If adding simple string right into java code is acceptable, I'll update patches.
          Hide
          Andrey Pavlenko added a comment -

          Ilya, Messages.getString("awt.XXX")) reads the messages from awt/src/main/java/common/org/apache/harmony/awt/internal/nls/messages.properties. You can put all messages you need to this file.

          Show
          Andrey Pavlenko added a comment - Ilya, Messages.getString("awt.XXX")) reads the messages from awt/src/main/java/common/org/apache/harmony/awt/internal/nls/messages.properties. You can put all messages you need to this file.
          Hide
          Ilya Berezhniuk added a comment -

          Attaching updated patches with added message in UnsupportedOperationException. The message added is awt.29A="Keyboard doesn't have KANA key", because this exception is thrown for KANA only.

          Show
          Ilya Berezhniuk added a comment - Attaching updated patches with added message in UnsupportedOperationException. The message added is awt.29A="Keyboard doesn't have KANA key", because this exception is thrown for KANA only.
          Hide
          Vasily Zakharov added a comment -

          Ilya, please note that UnsupportedOperationException is also thrown if totally wrong key number is provided or the code is run in Headless mode. Probably in these cases the diagnostics should be different.

          Show
          Vasily Zakharov added a comment - Ilya, please note that UnsupportedOperationException is also thrown if totally wrong key number is provided or the code is run in Headless mode. Probably in these cases the diagnostics should be different.
          Hide
          Ilya Berezhniuk added a comment -

          Vasily,

          thanks. I'm going to provide updated patch for Windows in next few hours, I'll take your note into account

          Show
          Ilya Berezhniuk added a comment - Vasily, thanks. I'm going to provide updated patch for Windows in next few hours, I'll take your note into account
          Hide
          Ilya Berezhniuk added a comment -

          With new improved implementation I've got wrong behavior
          So now I'm trying to locate an issue.

          Regarding exception throwing: by the spec, for wrong key these methods should throw IllegalArgumentException, and for headless mode they should throw HeadlessException. So I'll leave exception message as it, and I'll use string in code (not from table), because UnsupportedOperationException will be thrown from native code.

          Show
          Ilya Berezhniuk added a comment - With new improved implementation I've got wrong behavior So now I'm trying to locate an issue. Regarding exception throwing: by the spec, for wrong key these methods should throw IllegalArgumentException, and for headless mode they should throw HeadlessException. So I'll leave exception message as it, and I'll use string in code (not from table), because UnsupportedOperationException will be thrown from native code.
          Hide
          Vasily Zakharov added a comment -

          Oh, I see, then it's fine.

          The only thing, after the patch is complete, we should not forget to file any non-bug differences our implementation would have with RI.

          Show
          Vasily Zakharov added a comment - Oh, I see, then it's fine. The only thing, after the patch is complete, we should not forget to file any non-bug differences our implementation would have with RI.
          Hide
          Ilya Berezhniuk added a comment -

          Latest "4423_win.patch" is implementation for Windows with several performance and structure improvements.

          Show
          Ilya Berezhniuk added a comment - Latest "4423_win.patch" is implementation for Windows with several performance and structure improvements.
          Hide
          Alexey Petrenko added a comment -

          Ilya, thanks for the patch.
          I've slightly modified your patch... I've made WinWTK.getLockingState and WinWTK.setLockingState methods native.

          Vasily,
          please verify that the patch works as expected.

          Show
          Alexey Petrenko added a comment - Ilya, thanks for the patch. I've slightly modified your patch... I've made WinWTK.getLockingState and WinWTK.setLockingState methods native. Vasily, please verify that the patch works as expected.
          Hide
          Vasily Zakharov added a comment -

          Ilya, Alexey, thank you very much, the patch for Windows works ok and is applied fine.

          For Linux, the implementation is still a stub, so I think we should keep this issue open until we have an additional patch for Linux implementation ready. I'd also suggest to remove "Environment: Win32" flag, as this issue is not Windows-specific, but exists on all platforms.

          Show
          Vasily Zakharov added a comment - Ilya, Alexey, thank you very much, the patch for Windows works ok and is applied fine. For Linux, the implementation is still a stub, so I think we should keep this issue open until we have an additional patch for Linux implementation ready. I'd also suggest to remove "Environment: Win32" flag, as this issue is not Windows-specific, but exists on all platforms.
          Hide
          Vasily Zakharov added a comment -

          With the patch above applied, the additional workaround patch to java.awt.Toolkit that is used in jEdit automated GUI tests (see HARMONY-3633) becomes useless and may be removed.

          The attached Harmony-4423-jEdit.patch patch removes all extra stuff needed for that workaround from jEdit tests framework. The patch removes the bt-2/tests/jedit_test/src/patches/harmony directory and updates build.xml, build.properties and readme.txt accordingly.

          Show
          Vasily Zakharov added a comment - With the patch above applied, the additional workaround patch to java.awt.Toolkit that is used in jEdit automated GUI tests (see HARMONY-3633 ) becomes useless and may be removed. The attached Harmony-4423-jEdit.patch patch removes all extra stuff needed for that workaround from jEdit tests framework. The patch removes the bt-2/tests/jedit_test/src/patches/harmony directory and updates build.xml, build.properties and readme.txt accordingly.
          Hide
          Vasily Zakharov added a comment -

          Oh, I've found that similar issue for Linux is filed as HARMONY-4636.

          As of obsolete workaround in jEdit automated GUI tests, I've created a new JIRA, HARMONY-4659, and moved the patch there.

          Now this issue may be closed.

          Show
          Vasily Zakharov added a comment - Oh, I've found that similar issue for Linux is filed as HARMONY-4636 . As of obsolete workaround in jEdit automated GUI tests, I've created a new JIRA, HARMONY-4659 , and moved the patch there. Now this issue may be closed.

            People

            • Assignee:
              Alexey Petrenko
              Reporter:
              Vasily Zakharov
            • Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development