/* Scan the hardware keyboard and push any changes up through the input layer */ static void tosakbd_scankeyboard(struct platform_device *dev) { struct tosakbd *tosakbd = platform_get_drvdata(dev); unsigned int row, col, rowd; unsigned long flags; unsigned int num_pressed = 0; spin_lock_irqsave(&tosakbd->lock, flags); if (tosakbd->suspended) goto out; for (col = 0; col < TOSA_KEY_STROBE_NUM; col++) { /* * Discharge the output driver capacitatance * in the keyboard matrix. (Yes it is significant..) */ tosakbd_discharge_all(); udelay(KB_DISCHARGE_DELAY); tosakbd_activate_col(col); udelay(KB_ACTIVATE_DELAY); rowd = GET_ROWS_STATUS(col); for (row = 0; row < TOSA_KEY_SENSE_NUM; row++) { unsigned int scancode, pressed; scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); if (pressed && !tosakbd->keycode[scancode]) dev_warn(&dev->dev, "unhandled scancode: 0x%02x\n", scancode); input_report_key(tosakbd->input, tosakbd->keycode[scancode], pressed); if (pressed) num_pressed++; } tosakbd_reset_col(col); } tosakbd_activate_all(); input_sync(tosakbd->input); /* if any keys are pressed, enable the timer */ if (num_pressed) mod_timer(&tosakbd->timer, jiffies + SCAN_INTERVAL); out: spin_unlock_irqrestore(&tosakbd->lock, flags); }
/* Scan the hardware keyboard and push any changes up through the input layer */ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data) { unsigned int row, col, rowd; unsigned long flags; unsigned int num_pressed; if (corgikbd_data->suspended) return; spin_lock_irqsave(&corgikbd_data->lock, flags); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { /* * Discharge the output driver capacitatance * in the keyboard matrix. (Yes it is significant..) */ corgikbd_discharge_all(); udelay(KB_DISCHARGE_DELAY); corgikbd_activate_col(col); udelay(KB_ACTIVATE_DELAY); rowd = GET_ROWS_STATUS(col); for (row = 0; row < KB_ROWS; row++) { unsigned int scancode, pressed; scancode = SCANCODE(row, col); pressed = rowd & KB_ROWMASK(row); input_report_key(corgikbd_data->input, corgikbd_data->keycode[scancode], pressed); if (pressed) num_pressed++; if (pressed && (corgikbd_data->keycode[scancode] == CORGI_KEY_OFF) && time_after(jiffies, corgikbd_data->suspend_jiffies + HZ)) { input_event(corgikbd_data->input, EV_PWR, CORGI_KEY_OFF, 1); corgikbd_data->suspend_jiffies=jiffies; } } corgikbd_reset_col(col); } corgikbd_activate_all(); input_sync(corgikbd_data->input); /* if any keys are pressed, enable the timer */ if (num_pressed) mod_timer(&corgikbd_data->timer, jiffies + msecs_to_jiffies(SCAN_INTERVAL)); spin_unlock_irqrestore(&corgikbd_data->lock, flags); }
/**************************************************************************** * * This function creates the Keymap Array with scan code RC pointing to KeyCode * ***************************************************************************/ static int CreateKeyMap( struct CBLK *bcm_kp, struct BCM_GPIO_KEYMAP *keymap_p ) { int r,k, c=0; for(k=0;k<bcm_kp->key_count; k++) { r = elementExistInArray( keymap_p->gpio_row, bcm_kp->row_count, bcm_kp->keyRowArray ); c = elementExistInArray( keymap_p->gpio_col, bcm_kp->col_count, bcm_kp->keyColArray ); bcm_kp->keycode[SCANCODE(r,c)] = keymap_p->key_code; BCMKP_DBG(KERN_NOTICE "setting keymap r= %d, c=%d, code=%d\n", r,c,keymap_p->key_code); set_bit(keymap_p->key_code ,bcm_kp->input_dev->keybit); keymap_p++; } return(1); }
/****************************************************************************f * * Scan the matrix, and generate event for changes. * ***************************************************************************/ static void keypad_scan( int gpio_pin, struct CBLK *bcm_kp ) { unsigned int stat; int r, gpio_c, value; int c = 0; r = elementExistInArray( gpio_pin, bcm_kp->row_count , bcm_kp->keyRowArray ); stat = gpio_get_value(gpio_pin); if(stat) { /* At this point we know that the some key was released. So no point in scanning the Matrix. Just report the last pressed key on same GPIO as released. */ /* Handle if its a Direct key release*/ if(( bcm_kp->direct_key_col_index != -1 ) && ( bcm_kp->keycode[SCANCODE(r,bcm_kp->direct_key_col_index)] )) { input_report_key(bcm_kp->input_dev, bcm_kp->keycode[SCANCODE(r,bcm_kp->direct_key_col_index)], !stat); input_sync( bcm_kp->input_dev ); } /* Handle Matrix Key Release */ else { for(c=0;c< bcm_kp->col_count;c++) { if( test_bit( SCANCODE(r,c), bcm_kp->prevDown ) ) { input_report_key(bcm_kp->input_dev, bcm_kp->keycode[SCANCODE(r,c)], !stat); input_sync( bcm_kp->input_dev ); change_bit( SCANCODE(r,c), bcm_kp->prevDown ); BCMKP_DBG(KERN_DEBUG "Key released r=%d c=%d..\n", r, c); } } } } else { /* The Key is presses, so scan the Matrix */ //Now we have the GPIO row that cause the interrupt if(( bcm_kp->direct_key_col_index != -1 ) && ( bcm_kp->keycode[SCANCODE(r,bcm_kp->direct_key_col_index)] )) { /* The Key is a Direct Key */ input_report_key(bcm_kp->input_dev, bcm_kp->keycode[SCANCODE(r,bcm_kp->direct_key_col_index)], !stat); BCMKP_DBG(KERN_DEBUG "GPIO %d row press found Direct Key..\n", gpio_pin); } else{ //Now set all Col as High for(c=0;c< bcm_kp->col_count;c++) { gpio_c = bcm_kp->keyColArray[c]; if( gpio_c != BCM_NO_COLUMN ) gpio_set_value( gpio_c, 1 ); } for(c=0;c< bcm_kp->col_count;c++) { gpio_c = bcm_kp->keyColArray[c]; if( gpio_c == BCM_NO_COLUMN ) continue; gpio_set_value( gpio_c, 0 ); value = gpio_get_value(gpio_pin); gpio_set_value( gpio_c, 1 ); if( !value ) //Found the Key { if( bcm_kp->keycode[SCANCODE(r,c)] && !test_bit( SCANCODE(r,c), bcm_kp->prevDown ) ) { /* report status to input-subsystem */ input_report_key(bcm_kp->input_dev, bcm_kp->keycode[SCANCODE(r,c)], !value); input_sync( bcm_kp->input_dev ); change_bit( SCANCODE(r,c), bcm_kp->prevDown ); BCMKP_DBG(KERN_DEBUG "Key Pressed r=%d c=%d..\n", r, c); break; } } } //Now restore all the Col as Low for next interrupt for(c=0;c< bcm_kp->col_count;c++) { gpio_c = bcm_kp->keyColArray[c]; if( gpio_c != BCM_NO_COLUMN ) gpio_set_value( gpio_c, 0 ); } } } return; }
/* Scan the hardware keyboard and push any changes up through the input layer */ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) { unsigned int row, col, rowd; unsigned long flags; unsigned int num_pressed; unsigned long membase = locomokbd->base; spin_lock_irqsave(&locomokbd->lock, flags); locomokbd_charge_all(membase); num_pressed = 0; for (col = 0; col < KB_COLS; col++) { locomokbd_activate_col(membase, col); udelay(KB_DELAY); rowd = ~locomo_readl(membase + LOCOMO_KIB); for (row = 0; row < KB_ROWS; row++) { unsigned int scancode, pressed, key; scancode = SCANCODE(col, row); pressed = rowd & KB_ROWMASK(row); key = locomokbd->keycode[scancode]; input_report_key(locomokbd->input, key, pressed); if (likely(!pressed)) continue; num_pressed++; /* The "Cancel/ESC" key is labeled "On/Off" on * Collie and Poodle and should suspend the device * if it was pressed for more than a second. */ if (unlikely(key == KEY_ESC)) { if (!time_after(jiffies, locomokbd->suspend_jiffies + HZ)) continue; if (locomokbd->count_cancel++ != (HZ/SCAN_INTERVAL + 1)) continue; input_event(locomokbd->input, EV_PWR, KEY_SUSPEND, 1); locomokbd->suspend_jiffies = jiffies; } else locomokbd->count_cancel = 0; } locomokbd_reset_col(membase, col); } locomokbd_activate_all(membase); input_sync(locomokbd->input); /* if any keys are pressed, enable the timer */ if (num_pressed) mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL); else locomokbd->count_cancel = 0; spin_unlock_irqrestore(&locomokbd->lock, flags); }
namespace KKeyServer { struct TransKey { int qt_code; int mac_code; }; static TransKey qtKeyToChar[] = { {Qt::Key_Escape, kEscapeCharCode}, {Qt::Key_Tab, kTabCharCode}, {Qt::Key_Backtab, kTabCharCode}, // Backtab == tab with different modifiers {Qt::Key_Backspace, kBackspaceCharCode}, {Qt::Key_Return, kReturnCharCode}, {Qt::Key_Enter, kEnterCharCode}, // Insert {Qt::Key_Delete, kDeleteCharCode}, // Pause, Print, SysReq {Qt::Key_Clear, kClearCharCode}, {Qt::Key_Home, kHomeCharCode}, {Qt::Key_End, kEndCharCode}, {Qt::Key_Left, kLeftArrowCharCode}, {Qt::Key_Up, kUpArrowCharCode}, {Qt::Key_Right, kRightArrowCharCode}, {Qt::Key_Down, kDownArrowCharCode}, {Qt::Key_PageUp, kPageUpCharCode}, {Qt::Key_PageDown, kPageDownCharCode}, // Shift, Control, Meta, Alt, CapsLock, NumLock, ScrollLock // Super_L, Super_R, Menu, Hyper_L, Hyper_R {Qt::Key_Help, kHelpCharCode}, // Direction_L, Direction_R {Qt::Key_nobreakspace, kNonBreakingSpaceCharCode}, {0, 0} }; static QMultiMap<int, uint> scancodes; static long lastLayoutID = -1; #ifdef QT_MAC_USE_COCOA static TISInputSourceRef lastLayout = 0; #else static KeyboardLayoutRef lastLayout = NULL; #endif void updateScancodes() { #ifdef QT_MAC_USE_COCOA TISInputSourceRef layout = TISCopyCurrentKeyboardLayoutInputSource(); if (!layout) { qWarning() << "Error retrieving current layout"; return; } if (layout == lastLayout) { CFRelease(layout); } else { // keyboard layout changed #ifndef NDEBUG const void *name = TISGetInputSourceProperty(layout, kTISPropertyLocalizedName); qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0); #endif lastLayout = layout; scancodes.clear(); CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(layout, kTISPropertyUnicodeKeyLayoutData)); const UCKeyboardLayout *ucData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0; if (!ucData) { qWarning() << "Error retrieving current layout character data"; return; } for (int i = 0; i < 128; ++i) { UInt32 tmpState = 0; UniChar str[4]; UniCharCount actualLength = 0; OSStatus err = UCKeyTranslate(ucData, i, kUCKeyActionDown, 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, &tmpState, 4, &actualLength, str); if (err != noErr) { qWarning() << "Error translating unicode key" << err; } else { if (str[0] && str[0] != kFunctionKeyCharCode) { scancodes.insert(str[0], i); } } } } #else KeyboardLayoutRef layout; if (KLGetCurrentKeyboardLayout(&layout) != noErr) { qWarning() << "Error retrieving current layout"; } if (layout != lastLayout) { #ifndef NDEBUG void *name; KLGetKeyboardLayoutProperty(layout, kKLName, const_cast<const void **>(&name)); qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef) name, 0); #endif lastLayout = layout; scancodes.clear(); void *kchr; if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void **>(&kchr)) != noErr) { qWarning() << "Couldn't load active keyboard layout"; } else { for (int i = 0; i < 128; i++) { UInt32 tmpState = 0; UInt32 chr = KeyTranslate(kchr, i, &tmpState); if (chr && chr != kFunctionKeyCharCode) { scancodes.insert(chr, i); } } } } #endif } #define SCANCODE(name, value) { Qt::Key_ ## name, value } static TransKey functionKeys[] = { SCANCODE(F1, 122), SCANCODE(F2, 120), SCANCODE(F3, 99), SCANCODE(F4, 118), SCANCODE(F5, 96), SCANCODE(F6, 97), SCANCODE(F7, 98), SCANCODE(F8, 100), SCANCODE(F9, 101), SCANCODE(F10, 109), //TODO: figure out scancodes of other F* keys { 0, 0 } }; #undef SCANCODE bool keyQtToSymMac(int keyQt, int &sym) { // Printable ascii values, before A if (keyQt >= 0x20 && keyQt < Qt::Key_A) { sym = keyQt; return true; } // Letters, return lower-case equivalent if (keyQt >= Qt::Key_A && keyQt <= Qt::Key_Z) { sym = keyQt - Qt::Key_A + 'a'; return true; } // Printable ascii values up to lower-case a if (keyQt > Qt::Key_Z && keyQt <= 0x60) { sym = keyQt; return true; } // Remainder of printable ascii values if (keyQt >= 0x7B && keyQt < 0x7F) { sym = keyQt; return true; } // Function keys if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) { sym = kFunctionKeyCharCode; return true; } // Try to find in lookup table for (int i = 0; qtKeyToChar[i].qt_code; i++) { if (qtKeyToChar[i].qt_code == keyQt) { sym = qtKeyToChar[i].mac_code; return true; } } // Not found return false; } bool keyQtToCodeMac(int keyQt, QList<uint> &keyCodes) { updateScancodes(); keyCodes.clear(); keyQt &= ~Qt::KeyboardModifierMask; int chr; if (!keyQtToSymMac(keyQt, chr)) { return false; } if (chr == kFunctionKeyCharCode) { for (int i = 0; functionKeys[i].qt_code; i++) { if (functionKeys[i].qt_code == keyQt) { keyCodes.append(functionKeys[i].mac_code); } } } else { keyCodes += scancodes.values(chr); } return keyCodes.count() > 0; } bool keyQtToModMac(int keyQt, uint &mod) { mod = 0; if (keyQt & Qt::ShiftModifier) { mod |= shiftKey; } if (keyQt & Qt::ControlModifier) { mod |= cmdKey; } if (keyQt & Qt::AltModifier) { mod |= optionKey; } if (keyQt & Qt::MetaModifier) { mod |= controlKey; } if (keyQt & Qt::KeypadModifier) { mod |= kEventKeyModifierNumLockMask; } // Special case for Qt::Key_Backtab if ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Backtab) { mod |= shiftKey; } return true; } } // end of namespace KKeyServer