/* * Copyright (c) 2002-2008 LWJGL Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of 'LWJGL' nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.lwjgl.opengl; /** * A native implementation of a LWJGL compatible Keyboard event queue. * @author elias_naur * @author mojang */ import java.awt.event.KeyEvent; import java.util.HashMap; import java.nio.ByteBuffer; import org.lwjgl.input.Keyboard; final class MacOSXNativeKeyboard extends EventQueue { private final byte[] key_states = new byte[Keyboard.KEYBOARD_SIZE]; /** Event scratch array */ private final ByteBuffer event = ByteBuffer.allocate(Keyboard.EVENT_SIZE); private ByteBuffer window_handle; private boolean has_deferred_event; private long deferred_nanos; private int deferred_key_code; private byte deferred_key_state; private int deferred_character; private HashMap<Short, Integer> nativeToLwjglMap; MacOSXNativeKeyboard(ByteBuffer window_handle) { super(Keyboard.EVENT_SIZE); nativeToLwjglMap = new HashMap<Short, Integer>(); initKeyboardMappings(); this.window_handle = window_handle; } private native void nRegisterKeyListener(ByteBuffer window_handle); private native void nUnregisterKeyListener(ByteBuffer window_handle); // These are from: <HIToolbox/Events.h> private void initKeyboardMappings() { nativeToLwjglMap.put((short)0x1D, Keyboard.KEY_0); nativeToLwjglMap.put((short)0x12, Keyboard.KEY_1); nativeToLwjglMap.put((short)0x13, Keyboard.KEY_2); nativeToLwjglMap.put((short)0x14, Keyboard.KEY_3); nativeToLwjglMap.put((short)0x15, Keyboard.KEY_4); nativeToLwjglMap.put((short)0x17, Keyboard.KEY_5); nativeToLwjglMap.put((short)0x16, Keyboard.KEY_6); nativeToLwjglMap.put((short)0x1A, Keyboard.KEY_7); nativeToLwjglMap.put((short)0x1C, Keyboard.KEY_8); nativeToLwjglMap.put((short)0x19, Keyboard.KEY_9); nativeToLwjglMap.put((short)0x00, Keyboard.KEY_A); nativeToLwjglMap.put((short)0x0B, Keyboard.KEY_B); nativeToLwjglMap.put((short)0x08, Keyboard.KEY_C); nativeToLwjglMap.put((short)0x02, Keyboard.KEY_D); nativeToLwjglMap.put((short)0x0E, Keyboard.KEY_E); nativeToLwjglMap.put((short)0x03, Keyboard.KEY_F); nativeToLwjglMap.put((short)0x05, Keyboard.KEY_G); nativeToLwjglMap.put((short)0x04, Keyboard.KEY_H); nativeToLwjglMap.put((short)0x22, Keyboard.KEY_I); nativeToLwjglMap.put((short)0x26, Keyboard.KEY_J); nativeToLwjglMap.put((short)0x28, Keyboard.KEY_K); nativeToLwjglMap.put((short)0x25, Keyboard.KEY_L); nativeToLwjglMap.put((short)0x2E, Keyboard.KEY_M); nativeToLwjglMap.put((short)0x2D, Keyboard.KEY_N); nativeToLwjglMap.put((short)0x1F, Keyboard.KEY_O); nativeToLwjglMap.put((short)0x23, Keyboard.KEY_P); nativeToLwjglMap.put((short)0x0C, Keyboard.KEY_Q); nativeToLwjglMap.put((short)0x0F, Keyboard.KEY_R); nativeToLwjglMap.put((short)0x01, Keyboard.KEY_S); nativeToLwjglMap.put((short)0x11, Keyboard.KEY_T); nativeToLwjglMap.put((short)0x20, Keyboard.KEY_U); nativeToLwjglMap.put((short)0x09, Keyboard.KEY_V); nativeToLwjglMap.put((short)0x0D, Keyboard.KEY_W); nativeToLwjglMap.put((short)0x07, Keyboard.KEY_X); nativeToLwjglMap.put((short)0x10, Keyboard.KEY_Y); nativeToLwjglMap.put((short)0x06, Keyboard.KEY_Z); nativeToLwjglMap.put((short)0x2A, Keyboard.KEY_BACKSLASH); nativeToLwjglMap.put((short)0x2B, Keyboard.KEY_COMMA); nativeToLwjglMap.put((short)0x18, Keyboard.KEY_EQUALS); nativeToLwjglMap.put((short)0x21, Keyboard.KEY_LBRACKET); nativeToLwjglMap.put((short)0x1B, Keyboard.KEY_MINUS); nativeToLwjglMap.put((short)0x27, Keyboard.KEY_APOSTROPHE); nativeToLwjglMap.put((short)0x1E, Keyboard.KEY_RBRACKET); nativeToLwjglMap.put((short)0x29, Keyboard.KEY_SEMICOLON); nativeToLwjglMap.put((short)0x2C, Keyboard.KEY_SLASH); nativeToLwjglMap.put((short)0x2F, Keyboard.KEY_PERIOD); nativeToLwjglMap.put((short)0x32, Keyboard.KEY_GRAVE); nativeToLwjglMap.put((short)0x41, Keyboard.KEY_DECIMAL); nativeToLwjglMap.put((short)0x43, Keyboard.KEY_MULTIPLY); nativeToLwjglMap.put((short)0x45, Keyboard.KEY_ADD); nativeToLwjglMap.put((short)0x47, Keyboard.KEY_CLEAR); nativeToLwjglMap.put((short)0x4B, Keyboard.KEY_DIVIDE); nativeToLwjglMap.put((short)0x4C, Keyboard.KEY_NUMPADENTER); nativeToLwjglMap.put((short)0x4E, Keyboard.KEY_SUBTRACT); nativeToLwjglMap.put((short)0x51, Keyboard.KEY_NUMPADEQUALS); nativeToLwjglMap.put((short)0x52, Keyboard.KEY_NUMPAD0); nativeToLwjglMap.put((short)0x53, Keyboard.KEY_NUMPAD1); nativeToLwjglMap.put((short)0x54, Keyboard.KEY_NUMPAD2); nativeToLwjglMap.put((short)0x55, Keyboard.KEY_NUMPAD3); nativeToLwjglMap.put((short)0x56, Keyboard.KEY_NUMPAD4); nativeToLwjglMap.put((short)0x57, Keyboard.KEY_NUMPAD5); nativeToLwjglMap.put((short)0x58, Keyboard.KEY_NUMPAD6); nativeToLwjglMap.put((short)0x59, Keyboard.KEY_NUMPAD7); nativeToLwjglMap.put((short)0x5B, Keyboard.KEY_NUMPAD8); nativeToLwjglMap.put((short)0x5C, Keyboard.KEY_NUMPAD9); nativeToLwjglMap.put((short)0x24, Keyboard.KEY_RETURN); nativeToLwjglMap.put((short)0x30, Keyboard.KEY_TAB); nativeToLwjglMap.put((short)0x31, Keyboard.KEY_SPACE); nativeToLwjglMap.put((short)0x33, Keyboard.KEY_BACK); nativeToLwjglMap.put((short)0x35, Keyboard.KEY_ESCAPE); nativeToLwjglMap.put((short)0x36, Keyboard.KEY_RMETA); // not in Events.h - works on MBP nativeToLwjglMap.put((short)0x37, Keyboard.KEY_LMETA); nativeToLwjglMap.put((short)0x38, Keyboard.KEY_LSHIFT); nativeToLwjglMap.put((short)0x39, Keyboard.KEY_CAPITAL); nativeToLwjglMap.put((short)0x3A, Keyboard.KEY_LMENU); nativeToLwjglMap.put((short)0x3B, Keyboard.KEY_LCONTROL); nativeToLwjglMap.put((short)0x3C, Keyboard.KEY_RSHIFT); nativeToLwjglMap.put((short)0x3D, Keyboard.KEY_RMENU); nativeToLwjglMap.put((short)0x3E, Keyboard.KEY_RCONTROL); nativeToLwjglMap.put((short)0x3F, Keyboard.KEY_FUNCTION); nativeToLwjglMap.put((short)0x77, Keyboard.KEY_END); nativeToLwjglMap.put((short)0x7A, Keyboard.KEY_F1); nativeToLwjglMap.put((short)0x78, Keyboard.KEY_F2); nativeToLwjglMap.put((short)0x63, Keyboard.KEY_F3); nativeToLwjglMap.put((short)0x76, Keyboard.KEY_F4); nativeToLwjglMap.put((short)0x60, Keyboard.KEY_F5); nativeToLwjglMap.put((short)0x61, Keyboard.KEY_F6); nativeToLwjglMap.put((short)0x62, Keyboard.KEY_F7); nativeToLwjglMap.put((short)0x64, Keyboard.KEY_F8); nativeToLwjglMap.put((short)0x65, Keyboard.KEY_F9); nativeToLwjglMap.put((short)0x6D, Keyboard.KEY_F10); nativeToLwjglMap.put((short)0x67, Keyboard.KEY_F11); nativeToLwjglMap.put((short)0x6F, Keyboard.KEY_F12); nativeToLwjglMap.put((short)0x69, Keyboard.KEY_F13); nativeToLwjglMap.put((short)0x6B, Keyboard.KEY_F14); nativeToLwjglMap.put((short)0x71, Keyboard.KEY_F15); nativeToLwjglMap.put((short)0x6A, Keyboard.KEY_F16); nativeToLwjglMap.put((short)0x40, Keyboard.KEY_F17); nativeToLwjglMap.put((short)0x4F, Keyboard.KEY_F18); nativeToLwjglMap.put((short)0x50, Keyboard.KEY_F19); // nativeToLwjglMap.put((short)0x5A, Keyboard.KEY_F20); nativeToLwjglMap.put((short)0x75, Keyboard.KEY_DELETE); nativeToLwjglMap.put((short)0x72, Keyboard.KEY_INSERT); // 'Help' in Events.h nativeToLwjglMap.put((short)0x73, Keyboard.KEY_HOME); // nativeToLwjglMap.put((short)0xA4, Keyboard.KEY_MUTE); nativeToLwjglMap.put((short)0x79, Keyboard.KEY_NEXT); nativeToLwjglMap.put((short)0x74, Keyboard.KEY_PRIOR); // nativeToLwjglMap.put((short)0x49, Keyboard.KEY_VOLUMEDOWN); // nativeToLwjglMap.put((short)0x48, Keyboard.KEY_VOLUMEUP); nativeToLwjglMap.put((short)0x7B, Keyboard.KEY_LEFT); nativeToLwjglMap.put((short)0x7C, Keyboard.KEY_RIGHT); nativeToLwjglMap.put((short)0x7D, Keyboard.KEY_DOWN); nativeToLwjglMap.put((short)0x7E, Keyboard.KEY_UP); nativeToLwjglMap.put((short)0x0A, Keyboard.KEY_SECTION); nativeToLwjglMap.put((short)0x6E, Keyboard.KEY_APPS); // not in Events.h nativeToLwjglMap.put((short)0x129, Keyboard.KEY_COLON); // not in Events.h -- do we need it? } public void register() { nRegisterKeyListener(window_handle); } public void unregister() { nUnregisterKeyListener(window_handle); } public void putKeyboardEvent(int key_code, byte state, int character, long nanos, boolean repeat) { event.clear(); event.putInt(key_code).put(state).putInt(character).putLong(nanos).put(repeat ? (byte)1 : (byte)0); event.flip(); putEvent(event); } public synchronized void poll(ByteBuffer key_down_buffer) { flushDeferredEvent(); int old_position = key_down_buffer.position(); key_down_buffer.put(key_states); key_down_buffer.position(old_position); } public synchronized void copyEvents(ByteBuffer dest) { flushDeferredEvent(); super.copyEvents(dest); } private synchronized void handleKey(int key_code, byte state, int character, long nanos) { if (character == KeyEvent.CHAR_UNDEFINED) character = Keyboard.CHAR_NONE; if (state == 1) { boolean repeat = false; if (has_deferred_event) { if ((nanos == deferred_nanos && deferred_key_code == key_code)) { has_deferred_event = false; repeat = true; // Repeat event } else flushDeferredEvent(); } putKeyEvent(key_code, state, character, nanos, repeat); } else { flushDeferredEvent(); has_deferred_event = true; deferred_nanos = nanos; deferred_key_code = key_code; deferred_key_state = state; deferred_character = character; } } private void flushDeferredEvent() { if (has_deferred_event) { putKeyEvent(deferred_key_code, deferred_key_state, deferred_character, deferred_nanos, false); has_deferred_event = false; } } public void putKeyEvent(int key_code, byte state, int character, long nanos, boolean repeat) { /* Ignore repeating presses */ int mapped_code = getMappedKeyCode((short)key_code); if (mapped_code < 0) { System.out.println("Unrecognized keycode: " + key_code); /* Unrecognized / unmapped code, do nothing */ return; } if ( key_states[mapped_code] == state ) repeat = true; key_states[mapped_code] = state; int key_int_char = character & 0xffff; putKeyboardEvent(mapped_code, state, key_int_char, nanos, repeat); } private int getMappedKeyCode(short key_code) { if (nativeToLwjglMap.containsKey(key_code)) { return nativeToLwjglMap.get(key_code); } return -1; } public void keyPressed(int key_code, String chars, long nanos) { // use only first character of chars returned for key press int character = (chars == null || chars.length() == 0) ? 0 : (int)chars.charAt(0); handleKey(key_code, (byte)1, character, nanos); } public void keyReleased(int key_code, String chars, long nanos) { // use only first character of chars returned for key release int character = (chars == null || chars.length() == 0) ? 0 : (int)chars.charAt(0); handleKey(key_code, (byte)0, character, nanos); } public void keyTyped(KeyEvent e) { } }