1/* fakekey.c 2 * Functions for simulating keypresses. 3 * 4 * Copyright (C) 2010 the Speakup Team 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16#include <linux/types.h> 17#include <linux/slab.h> 18#include <linux/preempt.h> 19#include <linux/percpu.h> 20#include <linux/input.h> 21 22#include "speakup.h" 23 24#define PRESSED 1 25#define RELEASED 0 26 27static DEFINE_PER_CPU(int, reporting_keystroke); 28 29static struct input_dev *virt_keyboard; 30 31int speakup_add_virtual_keyboard(void) 32{ 33 int err; 34 35 virt_keyboard = input_allocate_device(); 36 37 if (!virt_keyboard) 38 return -ENOMEM; 39 40 virt_keyboard->name = "Speakup"; 41 virt_keyboard->id.bustype = BUS_VIRTUAL; 42 virt_keyboard->phys = "speakup/input0"; 43 virt_keyboard->dev.parent = NULL; 44 45 __set_bit(EV_KEY, virt_keyboard->evbit); 46 __set_bit(KEY_DOWN, virt_keyboard->keybit); 47 48 err = input_register_device(virt_keyboard); 49 if (err) { 50 input_free_device(virt_keyboard); 51 virt_keyboard = NULL; 52 } 53 54 return err; 55} 56 57void speakup_remove_virtual_keyboard(void) 58{ 59 if (virt_keyboard != NULL) { 60 input_unregister_device(virt_keyboard); 61 virt_keyboard = NULL; 62 } 63} 64 65/* 66 * Send a simulated down-arrow to the application. 67 */ 68void speakup_fake_down_arrow(void) 69{ 70 unsigned long flags; 71 72 /* disable keyboard interrupts */ 73 local_irq_save(flags); 74 /* don't change CPU */ 75 preempt_disable(); 76 77 __this_cpu_write(reporting_keystroke, true); 78 input_report_key(virt_keyboard, KEY_DOWN, PRESSED); 79 input_report_key(virt_keyboard, KEY_DOWN, RELEASED); 80 input_sync(virt_keyboard); 81 __this_cpu_write(reporting_keystroke, false); 82 83 /* reenable preemption */ 84 preempt_enable(); 85 /* reenable keyboard interrupts */ 86 local_irq_restore(flags); 87} 88 89/* 90 * Are we handling a simulated keypress on the current CPU? 91 * Returns a boolean. 92 */ 93bool speakup_fake_key_pressed(void) 94{ 95 return this_cpu_read(reporting_keystroke); 96} 97